forked from nitrojs/nitro
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcloudflare-durable.ts
More file actions
113 lines (97 loc) · 3.01 KB
/
Copy pathcloudflare-durable.ts
File metadata and controls
113 lines (97 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import "#nitro/virtual/polyfills";
import type * as CF from "@cloudflare/workers-types";
import { DurableObject } from "cloudflare:workers";
import wsAdapter from "crossws/adapters/cloudflare";
import { createHandler, augmentReq } from "./_module-handler.ts";
import { useNitroApp, useNitroHooks } from "nitro/app";
import { isPublicAssetURL } from "#nitro/virtual/public-assets";
import { resolveWebsocketHooks } from "#nitro/runtime/app";
import { hasWebSocket } from "#nitro/virtual/feature-flags";
const DURABLE_BINDING = "$DurableObject";
const DURABLE_INSTANCE = "server";
interface Env {
ASSETS?: { fetch: typeof CF.fetch };
[DURABLE_BINDING]?: CF.DurableObjectNamespace;
}
const nitroApp = useNitroApp();
const nitroHooks = useNitroHooks();
const getDurableStub = (env: Env) => {
const binding = env[DURABLE_BINDING];
if (!binding) {
throw new Error(
`Durable Object binding "${DURABLE_BINDING}" not available.`
);
}
const id = binding.idFromName(DURABLE_INSTANCE);
return binding.get(id);
};
const ws = hasWebSocket
? wsAdapter({
resolve: resolveWebsocketHooks,
instanceName: DURABLE_INSTANCE,
bindingName: DURABLE_BINDING,
})
: undefined;
export default createHandler<Env>({
fetch(request, env, context, url, ctxExt) {
// Static assets fallback (optional binding)
if (env.ASSETS && isPublicAssetURL(url.pathname)) {
return env.ASSETS.fetch(request as any);
}
// Expose stub fetch to the context
ctxExt.durableFetch = (req = request) =>
getDurableStub(env).fetch(req as any);
// Websocket upgrade
// https://crossws.unjs.io/adapters/cloudflare#durable-objects
if (hasWebSocket && request.headers.get("upgrade") === "websocket") {
return ws!.handleUpgrade(request, env, context);
}
},
});
export class $DurableObject extends DurableObject {
constructor(state: DurableObjectState, env: Record<string, any>) {
super(state, env);
state.waitUntil(
nitroHooks.callHook("cloudflare:durable:init", this, {
state,
env,
}) || Promise.resolve()
);
if (hasWebSocket) {
ws!.handleDurableInit(this, state, env);
}
}
override fetch(request: Request) {
augmentReq(request, {
env: this.env,
context: this.ctx as any,
});
if (hasWebSocket && request.headers.get("upgrade") === "websocket") {
return ws!.handleDurableUpgrade(this, request);
}
return nitroApp.fetch(request);
}
override alarm(): void | Promise<void> {
this.ctx.waitUntil(
nitroHooks.callHook("cloudflare:durable:alarm", this) || Promise.resolve()
);
}
override async webSocketMessage(
client: WebSocket,
message: ArrayBuffer | string
) {
if (hasWebSocket) {
return ws!.handleDurableMessage(this, client, message);
}
}
override async webSocketClose(
client: WebSocket,
code: number,
reason: string,
wasClean: boolean
) {
if (hasWebSocket) {
return ws!.handleDurableClose(this, client, code, reason, wasClean);
}
}
}