@pluv/platform-cloudflare 2.3.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +3 -33
- package/dist/index.mjs +3 -142
- package/package.json +6 -6
- package/src/index.ts +0 -8
- package/src/createPluvHandler.ts +0 -244
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/platform-cloudflare@
|
|
2
|
+
> @pluv/platform-cloudflare@3.0.0 build /home/runner/work/pluv/pluv/packages/platform-cloudflare
|
|
3
3
|
> tsup src/index.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
[34mCLI[39m Using tsup config: /home/runner/work/pluv/pluv/packages/platform-cloudflare/tsup.config.ts
|
|
9
9
|
[34mCLI[39m Target: es6
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
-
[32mESM[39m [1mdist/index.mjs [22m[
|
|
12
|
-
[32mESM[39m ⚡️ Build success in
|
|
11
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m8.92 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 53ms
|
|
13
13
|
[34mDTS[39m Build start
|
|
14
|
-
[32mDTS[39m ⚡️ Build success in
|
|
15
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
14
|
+
[32mDTS[39m ⚡️ Build success in 1244ms
|
|
15
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m5.28 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @pluv/platform-cloudflare
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- bc1ae91: **BREAKING** Removed deprecated `createPluvHandler`.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- @pluv/io@3.0.0
|
|
12
|
+
- @pluv/persistence-cloudflare-transactional-storage@3.0.0
|
|
13
|
+
- @pluv/types@3.0.0
|
|
14
|
+
|
|
3
15
|
## 2.3.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { AbstractWebSocket, WebSocketSession, WebSocketSerializedState, AbstractWebSocketConfig, AbstractEventMap, AbstractListener, AbstractPlatform, WebSocketRegistrationMode, AbstractPlatformConfig, ConvertWebSocketConfig,
|
|
2
|
-
import { IOAuthorize, JsonObject, InferIOAuthorizeUser, Json,
|
|
3
|
-
import { DurableObject } from 'cloudflare:workers';
|
|
1
|
+
import { AbstractWebSocket, WebSocketSession, WebSocketSerializedState, AbstractWebSocketConfig, AbstractEventMap, AbstractListener, AbstractPlatform, WebSocketRegistrationMode, AbstractPlatformConfig, ConvertWebSocketConfig, CreateIOParams, PluvIOAuthorize, InferInitContextType, PluvContext } from '@pluv/io';
|
|
2
|
+
import { IOAuthorize, JsonObject, InferIOAuthorizeUser, Json, BaseUser, Id } from '@pluv/types';
|
|
4
3
|
|
|
5
4
|
type CloudflareWebSocketConfig = AbstractWebSocketConfig;
|
|
6
5
|
declare class CloudflareWebSocket<TAuthorize extends IOAuthorize<any, any> | null = null> extends AbstractWebSocket<WebSocket, TAuthorize> {
|
|
@@ -80,35 +79,6 @@ declare class CloudflarePlatform<TAuthorize extends IOAuthorize<any, any> | null
|
|
|
80
79
|
private _getDetachedState;
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
type AuthorizeFunctionContext<TPluvServer extends PluvServer<any, any, any, any>> = {
|
|
84
|
-
room: string;
|
|
85
|
-
} & InferInitContextType<TPluvServer extends PluvServer<infer IPlatform, any, any, any> ? IPlatform : never>;
|
|
86
|
-
type AuthorizeFunction<TPluvServer extends PluvServer<any, any, any, any>> = (ctx: AuthorizeFunctionContext<TPluvServer>) => MaybePromise<Maybe<InferIOAuthorizeUser<InferIOAuthorize<TPluvServer>>>>;
|
|
87
|
-
type CreatePluvHandlerConfig<TPluvServer extends PluvServer<any, any, any, any>, TEnv extends Record<string, any>> = {
|
|
88
|
-
binding: string;
|
|
89
|
-
endpoint?: string;
|
|
90
|
-
modify?: (request: Request, response: Response, env: TEnv) => MaybePromise<Response>;
|
|
91
|
-
io: TPluvServer;
|
|
92
|
-
} & (InferIOAuthorizeUser<InferIOAuthorize<TPluvServer>> extends BaseUser ? {
|
|
93
|
-
authorize: AuthorizeFunction<TPluvServer>;
|
|
94
|
-
} : {
|
|
95
|
-
authorize?: undefined;
|
|
96
|
-
});
|
|
97
|
-
type PluvHandlerFetch<TEnv extends Record<string, any> = {}> = (request: Request, env: TEnv) => Promise<Response | null>;
|
|
98
|
-
interface CreatePluvHandlerResult<TEnv extends Record<string, any> = {}> {
|
|
99
|
-
DurableObject: {
|
|
100
|
-
new (state: DurableObjectState, env: TEnv): DurableObject<TEnv>;
|
|
101
|
-
};
|
|
102
|
-
fetch: PluvHandlerFetch<TEnv>;
|
|
103
|
-
handler: ExportedHandler<TEnv>;
|
|
104
|
-
}
|
|
105
|
-
type InferCloudflarePluvHandlerEnv<TPluvServer extends PluvServer<CloudflarePlatform<any, any>, any, any, any>> = TPluvServer extends PluvServer<CloudflarePlatform<any, infer IEnv>, any, any, any> ? IEnv : {};
|
|
106
|
-
/**
|
|
107
|
-
* @deprecated Instructions will be provided on https://pluv.io on how to host this yourself instead.
|
|
108
|
-
* @date April 27, 2025
|
|
109
|
-
*/
|
|
110
|
-
declare const createPluvHandler: <TPluvServer extends PluvServer<CloudflarePlatform<any, any>, any, any, any>>(config: CreatePluvHandlerConfig<TPluvServer, Id<InferCloudflarePluvHandlerEnv<TPluvServer>>>) => CreatePluvHandlerResult<Id<InferCloudflarePluvHandlerEnv<TPluvServer>>>;
|
|
111
|
-
|
|
112
82
|
declare const identity: <T extends unknown>(x: T) => T;
|
|
113
83
|
|
|
114
84
|
type InferCallback<TEnv extends Record<string, any> = {}, TMeta extends Record<string, Json> = {}> = (i: typeof identity) => {
|
|
@@ -124,4 +94,4 @@ type PlatformCloudflareCreateIOParams<TEnv extends Record<string, any> = {}, TMe
|
|
|
124
94
|
}>;
|
|
125
95
|
declare const platformCloudflare: <TEnv extends Record<string, any> = {}, TMeta extends Record<string, Json> = {}, TContext extends Record<string, any> = {}, TUser extends BaseUser | null = null>(config?: PlatformCloudflareCreateIOParams<TEnv, TMeta, TContext, TUser>) => CreateIOParams<CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>, TContext, TUser>;
|
|
126
96
|
|
|
127
|
-
export {
|
|
97
|
+
export { CloudflarePlatform, type CloudflarePlatformConfig, type InferCallback, type PlatformCloudflareCreateIOParams, infer, platformCloudflare };
|
package/dist/index.mjs
CHANGED
|
@@ -38,147 +38,6 @@ var __async = (__this, __arguments, generator) => {
|
|
|
38
38
|
});
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
// src/createPluvHandler.ts
|
|
42
|
-
import { DurableObject as BaseDurableObject } from "cloudflare:workers";
|
|
43
|
-
import { match } from "path-to-regexp";
|
|
44
|
-
|
|
45
|
-
// src/constants.ts
|
|
46
|
-
var DEFAULT_REGISTRATION_MODE = "detached";
|
|
47
|
-
var GARBAGE_COLLECT_INTERVAL_MS = 6e4;
|
|
48
|
-
|
|
49
|
-
// src/createPluvHandler.ts
|
|
50
|
-
var createPluvHandler = (config) => {
|
|
51
|
-
const { authorize, binding, endpoint = "/api/pluv", modify, io } = config;
|
|
52
|
-
const DurableObject = class extends BaseDurableObject {
|
|
53
|
-
constructor(state, env) {
|
|
54
|
-
super(state, env);
|
|
55
|
-
this._room = io.createRoom(state.id.toString(), { env, state });
|
|
56
|
-
}
|
|
57
|
-
webSocketClose(ws, code, reason, wasClean) {
|
|
58
|
-
return __async(this, null, function* () {
|
|
59
|
-
if (io._defs.platform._config.registrationMode !== "detached") return;
|
|
60
|
-
const onCloseHandler = this._room.onClose(ws);
|
|
61
|
-
yield onCloseHandler({ code, reason });
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
webSocketError(ws, error) {
|
|
65
|
-
return __async(this, null, function* () {
|
|
66
|
-
if (io._defs.platform._config.registrationMode !== "detached") return;
|
|
67
|
-
const onErrorHandler = this._room.onError(ws);
|
|
68
|
-
const eventError = error instanceof Error ? error : new Error("Internal Error");
|
|
69
|
-
yield onErrorHandler({ error: eventError, message: eventError.message });
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
webSocketMessage(ws, message) {
|
|
73
|
-
return __async(this, null, function* () {
|
|
74
|
-
if (io._defs.platform._config.registrationMode !== "detached") return;
|
|
75
|
-
const onMessageHandler = this._room.onMessage(ws);
|
|
76
|
-
yield onMessageHandler({ data: message });
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
fetch(request) {
|
|
80
|
-
return __async(this, null, function* () {
|
|
81
|
-
const isWSRequest = request.headers.get("Upgrade") === "websocket";
|
|
82
|
-
if (!isWSRequest) return new Response("Expected websocket", { status: 400 });
|
|
83
|
-
const { 0: client, 1: server } = new WebSocketPair();
|
|
84
|
-
const token = new URL(request.url).searchParams.get("token");
|
|
85
|
-
const alarm = yield this.ctx.storage.getAlarm();
|
|
86
|
-
if (alarm !== null)
|
|
87
|
-
yield this.ctx.storage.setAlarm(Date.now() + GARBAGE_COLLECT_INTERVAL_MS);
|
|
88
|
-
yield this._room.register(server, { env: this.env, request, token });
|
|
89
|
-
return new Response(null, { status: 101, webSocket: client });
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
alarm(alarmInfo) {
|
|
93
|
-
return __async(this, null, function* () {
|
|
94
|
-
yield this._room.garbageCollect();
|
|
95
|
-
yield this.ctx.storage.setAlarm(Date.now() + GARBAGE_COLLECT_INTERVAL_MS);
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
const getDurableObjectNamespace = (env) => {
|
|
100
|
-
const namespace = env[binding];
|
|
101
|
-
if (!namespace) {
|
|
102
|
-
throw new Error(`Could not find DurableObject binding: ${binding}`);
|
|
103
|
-
}
|
|
104
|
-
return namespace;
|
|
105
|
-
};
|
|
106
|
-
const authHandler = (request, env) => __async(null, null, function* () {
|
|
107
|
-
if (!authorize) return null;
|
|
108
|
-
const { pathname, searchParams } = new URL(request.url);
|
|
109
|
-
const matcher = match(`${endpoint}/authorize`);
|
|
110
|
-
const matched = matcher(pathname);
|
|
111
|
-
if (!matched) return null;
|
|
112
|
-
const room = searchParams.get("room");
|
|
113
|
-
if (!room) {
|
|
114
|
-
return new Response("Not found", {
|
|
115
|
-
headers: { "Content-Type": "text/plain" },
|
|
116
|
-
status: 404
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
try {
|
|
120
|
-
const user = yield authorize({
|
|
121
|
-
env,
|
|
122
|
-
request,
|
|
123
|
-
room
|
|
124
|
-
});
|
|
125
|
-
if (!user) throw new Error();
|
|
126
|
-
const namespace = getDurableObjectNamespace(env);
|
|
127
|
-
const durableObjectId = namespace.idFromName(room);
|
|
128
|
-
const token = yield io.createToken({
|
|
129
|
-
env,
|
|
130
|
-
room: durableObjectId.toString(),
|
|
131
|
-
user,
|
|
132
|
-
request
|
|
133
|
-
});
|
|
134
|
-
return new Response(token, {
|
|
135
|
-
headers: { "Content-Type": "text/plain" },
|
|
136
|
-
status: 200
|
|
137
|
-
});
|
|
138
|
-
} catch (err) {
|
|
139
|
-
return new Response(err instanceof Error ? err.message : "Unauthorized", {
|
|
140
|
-
headers: { "Content-Type": "text/plain" },
|
|
141
|
-
status: 403
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
const roomHandler = (request, env) => __async(null, null, function* () {
|
|
146
|
-
const { pathname } = new URL(request.url);
|
|
147
|
-
const matcher = match(`${endpoint}/room/:roomId`);
|
|
148
|
-
const matched = matcher(pathname);
|
|
149
|
-
if (!matched) return null;
|
|
150
|
-
const { roomId } = matched.params;
|
|
151
|
-
if (!roomId) {
|
|
152
|
-
return new Response("Not found", {
|
|
153
|
-
headers: { "Content-Type": "text/plain" },
|
|
154
|
-
status: 404
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
const namespace = getDurableObjectNamespace(env);
|
|
158
|
-
const durableObjectId = namespace.idFromName(roomId);
|
|
159
|
-
const room = namespace.get(durableObjectId);
|
|
160
|
-
return room.fetch(request);
|
|
161
|
-
});
|
|
162
|
-
const handlerFetch = (request, env) => __async(null, null, function* () {
|
|
163
|
-
return [authHandler, roomHandler].reduce((promise, current) => __async(null, null, function* () {
|
|
164
|
-
return yield promise.then((value) => __async(null, null, function* () {
|
|
165
|
-
return value != null ? value : yield current(request, env);
|
|
166
|
-
}));
|
|
167
|
-
}), Promise.resolve(null));
|
|
168
|
-
});
|
|
169
|
-
const handler = {
|
|
170
|
-
fetch: (request, env) => __async(null, null, function* () {
|
|
171
|
-
var _a, _b;
|
|
172
|
-
const response = (_a = yield handlerFetch(request, env)) != null ? _a : new Response("Not Found", {
|
|
173
|
-
headers: { "Content-Type": "text/plain" },
|
|
174
|
-
status: 404
|
|
175
|
-
});
|
|
176
|
-
return (_b = modify == null ? void 0 : modify(request, response, env)) != null ? _b : response;
|
|
177
|
-
})
|
|
178
|
-
};
|
|
179
|
-
return { fetch: handlerFetch, DurableObject, handler };
|
|
180
|
-
};
|
|
181
|
-
|
|
182
41
|
// src/infer.ts
|
|
183
42
|
var infer = (callback) => callback;
|
|
184
43
|
|
|
@@ -277,6 +136,9 @@ var CloudflareWebSocket = class extends AbstractWebSocket {
|
|
|
277
136
|
}
|
|
278
137
|
};
|
|
279
138
|
|
|
139
|
+
// src/constants.ts
|
|
140
|
+
var DEFAULT_REGISTRATION_MODE = "detached";
|
|
141
|
+
|
|
280
142
|
// src/CloudflarePlatform.ts
|
|
281
143
|
var CloudflarePlatform = class _CloudflarePlatform extends AbstractPlatform {
|
|
282
144
|
constructor(config) {
|
|
@@ -406,7 +268,6 @@ var platformCloudflare = (config = {}) => {
|
|
|
406
268
|
};
|
|
407
269
|
};
|
|
408
270
|
export {
|
|
409
|
-
createPluvHandler,
|
|
410
271
|
infer,
|
|
411
272
|
platformCloudflare
|
|
412
273
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/platform-cloudflare",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "@pluv/io adapter for cloudflare workers",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,17 +17,17 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"path-to-regexp": "^8.2.0",
|
|
20
|
-
"@pluv/io": "^
|
|
21
|
-
"@pluv/persistence-cloudflare-transactional-storage": "^
|
|
22
|
-
"@pluv/types": "^
|
|
20
|
+
"@pluv/io": "^3.0.0",
|
|
21
|
+
"@pluv/persistence-cloudflare-transactional-storage": "^3.0.0",
|
|
22
|
+
"@pluv/types": "^3.0.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@cloudflare/workers-types": "^4.20250521.0",
|
|
26
26
|
"eslint": "^9.27.0",
|
|
27
27
|
"tsup": "^8.5.0",
|
|
28
28
|
"typescript": "^5.8.3",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
29
|
+
"eslint-config-pluv": "^3.0.0",
|
|
30
|
+
"@pluv/tsconfig": "^3.0.0"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "tsup src/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
export type { CloudflarePlatform, CloudflarePlatformConfig } from "./CloudflarePlatform";
|
|
2
|
-
export { createPluvHandler } from "./createPluvHandler";
|
|
3
|
-
export type {
|
|
4
|
-
AuthorizeFunction,
|
|
5
|
-
AuthorizeFunctionContext,
|
|
6
|
-
CreatePluvHandlerConfig,
|
|
7
|
-
CreatePluvHandlerResult,
|
|
8
|
-
PluvHandlerFetch,
|
|
9
|
-
} from "./createPluvHandler";
|
|
10
2
|
export { infer } from "./infer";
|
|
11
3
|
export type { InferCallback } from "./infer";
|
|
12
4
|
export { platformCloudflare } from "./platformCloudflare";
|
package/src/createPluvHandler.ts
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import type { InferInitContextType, IORoom, PluvServer } from "@pluv/io";
|
|
2
|
-
import type {
|
|
3
|
-
BaseUser,
|
|
4
|
-
Id,
|
|
5
|
-
InferIOAuthorize,
|
|
6
|
-
InferIOAuthorizeUser,
|
|
7
|
-
Maybe,
|
|
8
|
-
MaybePromise,
|
|
9
|
-
} from "@pluv/types";
|
|
10
|
-
import { DurableObject as BaseDurableObject } from "cloudflare:workers";
|
|
11
|
-
import { match } from "path-to-regexp";
|
|
12
|
-
import { CloudflarePlatform } from "./CloudflarePlatform";
|
|
13
|
-
import { GARBAGE_COLLECT_INTERVAL_MS } from "./constants";
|
|
14
|
-
|
|
15
|
-
export type AuthorizeFunctionContext<TPluvServer extends PluvServer<any, any, any, any>> = {
|
|
16
|
-
room: string;
|
|
17
|
-
} & InferInitContextType<
|
|
18
|
-
TPluvServer extends PluvServer<infer IPlatform, any, any, any> ? IPlatform : never
|
|
19
|
-
>;
|
|
20
|
-
export type AuthorizeFunction<TPluvServer extends PluvServer<any, any, any, any>> = (
|
|
21
|
-
ctx: AuthorizeFunctionContext<TPluvServer>,
|
|
22
|
-
) => MaybePromise<Maybe<InferIOAuthorizeUser<InferIOAuthorize<TPluvServer>>>>;
|
|
23
|
-
|
|
24
|
-
export type CreatePluvHandlerConfig<
|
|
25
|
-
TPluvServer extends PluvServer<any, any, any, any>,
|
|
26
|
-
TEnv extends Record<string, any>,
|
|
27
|
-
> = {
|
|
28
|
-
binding: string;
|
|
29
|
-
endpoint?: string;
|
|
30
|
-
modify?: (request: Request, response: Response, env: TEnv) => MaybePromise<Response>;
|
|
31
|
-
io: TPluvServer;
|
|
32
|
-
} & (InferIOAuthorizeUser<InferIOAuthorize<TPluvServer>> extends BaseUser
|
|
33
|
-
? { authorize: AuthorizeFunction<TPluvServer> }
|
|
34
|
-
: { authorize?: undefined });
|
|
35
|
-
|
|
36
|
-
export type PluvHandlerFetch<TEnv extends Record<string, any> = {}> = (
|
|
37
|
-
request: Request,
|
|
38
|
-
env: TEnv,
|
|
39
|
-
) => Promise<Response | null>;
|
|
40
|
-
|
|
41
|
-
export interface CreatePluvHandlerResult<TEnv extends Record<string, any> = {}> {
|
|
42
|
-
DurableObject: {
|
|
43
|
-
new (state: DurableObjectState, env: TEnv): BaseDurableObject<TEnv>;
|
|
44
|
-
};
|
|
45
|
-
fetch: PluvHandlerFetch<TEnv>;
|
|
46
|
-
handler: ExportedHandler<TEnv>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
type InferCloudflarePluvHandlerEnv<
|
|
50
|
-
TPluvServer extends PluvServer<CloudflarePlatform<any, any>, any, any, any>,
|
|
51
|
-
> = TPluvServer extends PluvServer<CloudflarePlatform<any, infer IEnv>, any, any, any> ? IEnv : {};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @deprecated Instructions will be provided on https://pluv.io on how to host this yourself instead.
|
|
55
|
-
* @date April 27, 2025
|
|
56
|
-
*/
|
|
57
|
-
export const createPluvHandler = <
|
|
58
|
-
TPluvServer extends PluvServer<CloudflarePlatform<any, any>, any, any, any>,
|
|
59
|
-
>(
|
|
60
|
-
config: CreatePluvHandlerConfig<TPluvServer, Id<InferCloudflarePluvHandlerEnv<TPluvServer>>>,
|
|
61
|
-
): CreatePluvHandlerResult<Id<InferCloudflarePluvHandlerEnv<TPluvServer>>> => {
|
|
62
|
-
const { authorize, binding, endpoint = "/api/pluv", modify, io } = config;
|
|
63
|
-
|
|
64
|
-
const DurableObject = class extends BaseDurableObject<
|
|
65
|
-
Id<InferCloudflarePluvHandlerEnv<TPluvServer>>
|
|
66
|
-
> {
|
|
67
|
-
private _room: IORoom<CloudflarePlatform<any, any>>;
|
|
68
|
-
|
|
69
|
-
constructor(
|
|
70
|
-
state: DurableObjectState,
|
|
71
|
-
env: Id<InferCloudflarePluvHandlerEnv<TPluvServer>>,
|
|
72
|
-
) {
|
|
73
|
-
super(state, env);
|
|
74
|
-
|
|
75
|
-
this._room = io.createRoom(state.id.toString(), { env, state });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public async webSocketClose(
|
|
79
|
-
ws: WebSocket,
|
|
80
|
-
code: number,
|
|
81
|
-
reason: string,
|
|
82
|
-
wasClean: boolean,
|
|
83
|
-
): Promise<void> {
|
|
84
|
-
if (io._defs.platform._config.registrationMode !== "detached") return;
|
|
85
|
-
|
|
86
|
-
const onCloseHandler = this._room.onClose(ws);
|
|
87
|
-
|
|
88
|
-
await onCloseHandler({ code, reason });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
public async webSocketError(ws: WebSocket, error: unknown): Promise<void> {
|
|
92
|
-
if (io._defs.platform._config.registrationMode !== "detached") return;
|
|
93
|
-
|
|
94
|
-
const onErrorHandler = this._room.onError(ws);
|
|
95
|
-
const eventError = error instanceof Error ? error : new Error("Internal Error");
|
|
96
|
-
|
|
97
|
-
await onErrorHandler({ error: eventError, message: eventError.message });
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void> {
|
|
101
|
-
if (io._defs.platform._config.registrationMode !== "detached") return;
|
|
102
|
-
|
|
103
|
-
const onMessageHandler = this._room.onMessage(ws);
|
|
104
|
-
|
|
105
|
-
await onMessageHandler({ data: message });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async fetch(request: Request<any, CfProperties<any>>): Promise<Response> {
|
|
109
|
-
const isWSRequest = request.headers.get("Upgrade") === "websocket";
|
|
110
|
-
|
|
111
|
-
if (!isWSRequest) return new Response("Expected websocket", { status: 400 });
|
|
112
|
-
|
|
113
|
-
const { 0: client, 1: server } = new WebSocketPair();
|
|
114
|
-
const token = new URL(request.url).searchParams.get("token");
|
|
115
|
-
|
|
116
|
-
const alarm = await this.ctx.storage.getAlarm();
|
|
117
|
-
if (alarm !== null)
|
|
118
|
-
await this.ctx.storage.setAlarm(Date.now() + GARBAGE_COLLECT_INTERVAL_MS);
|
|
119
|
-
|
|
120
|
-
await this._room.register(server, { env: this.env, request, token });
|
|
121
|
-
|
|
122
|
-
return new Response(null, { status: 101, webSocket: client });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public async alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> {
|
|
126
|
-
await this._room.garbageCollect();
|
|
127
|
-
await this.ctx.storage.setAlarm(Date.now() + GARBAGE_COLLECT_INTERVAL_MS);
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const getDurableObjectNamespace = (
|
|
132
|
-
env: Id<InferCloudflarePluvHandlerEnv<TPluvServer>>,
|
|
133
|
-
): DurableObjectNamespace => {
|
|
134
|
-
const namespace = env[binding as keyof typeof env] as DurableObjectNamespace;
|
|
135
|
-
|
|
136
|
-
if (!namespace) {
|
|
137
|
-
throw new Error(`Could not find DurableObject binding: ${binding}`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return namespace;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const authHandler: PluvHandlerFetch<Id<InferCloudflarePluvHandlerEnv<TPluvServer>>> = async (
|
|
144
|
-
request,
|
|
145
|
-
env,
|
|
146
|
-
) => {
|
|
147
|
-
if (!authorize) return null;
|
|
148
|
-
|
|
149
|
-
const { pathname, searchParams } = new URL(request.url);
|
|
150
|
-
const matcher = match<{}>(`${endpoint}/authorize`);
|
|
151
|
-
const matched = matcher(pathname);
|
|
152
|
-
|
|
153
|
-
if (!matched) return null;
|
|
154
|
-
|
|
155
|
-
const room = searchParams.get("room");
|
|
156
|
-
|
|
157
|
-
if (!room) {
|
|
158
|
-
return new Response("Not found", {
|
|
159
|
-
headers: { "Content-Type": "text/plain" },
|
|
160
|
-
status: 404,
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
const user = await authorize({
|
|
166
|
-
env,
|
|
167
|
-
request,
|
|
168
|
-
room,
|
|
169
|
-
} as AuthorizeFunctionContext<TPluvServer>);
|
|
170
|
-
|
|
171
|
-
if (!user) throw new Error();
|
|
172
|
-
|
|
173
|
-
const namespace = getDurableObjectNamespace(env);
|
|
174
|
-
const durableObjectId = namespace.idFromName(room);
|
|
175
|
-
|
|
176
|
-
const token = await io.createToken({
|
|
177
|
-
env,
|
|
178
|
-
room: durableObjectId.toString(),
|
|
179
|
-
user: user as any,
|
|
180
|
-
request,
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
return new Response(token, {
|
|
184
|
-
headers: { "Content-Type": "text/plain" },
|
|
185
|
-
status: 200,
|
|
186
|
-
});
|
|
187
|
-
} catch (err) {
|
|
188
|
-
return new Response(err instanceof Error ? err.message : "Unauthorized", {
|
|
189
|
-
headers: { "Content-Type": "text/plain" },
|
|
190
|
-
status: 403,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const roomHandler: PluvHandlerFetch<Id<InferCloudflarePluvHandlerEnv<TPluvServer>>> = async (
|
|
196
|
-
request,
|
|
197
|
-
env,
|
|
198
|
-
) => {
|
|
199
|
-
const { pathname } = new URL(request.url);
|
|
200
|
-
const matcher = match<{ roomId: string }>(`${endpoint}/room/:roomId`);
|
|
201
|
-
const matched = matcher(pathname);
|
|
202
|
-
|
|
203
|
-
if (!matched) return null;
|
|
204
|
-
|
|
205
|
-
const { roomId } = matched.params;
|
|
206
|
-
|
|
207
|
-
if (!roomId) {
|
|
208
|
-
return new Response("Not found", {
|
|
209
|
-
headers: { "Content-Type": "text/plain" },
|
|
210
|
-
status: 404,
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const namespace = getDurableObjectNamespace(env);
|
|
215
|
-
const durableObjectId = namespace.idFromName(roomId);
|
|
216
|
-
const room = namespace.get(durableObjectId);
|
|
217
|
-
|
|
218
|
-
return room.fetch(request);
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
const handlerFetch: PluvHandlerFetch<Id<InferCloudflarePluvHandlerEnv<TPluvServer>>> = async (
|
|
222
|
-
request,
|
|
223
|
-
env,
|
|
224
|
-
) => {
|
|
225
|
-
return [authHandler, roomHandler].reduce(async (promise, current) => {
|
|
226
|
-
return await promise.then(async (value) => value ?? (await current(request, env)));
|
|
227
|
-
}, Promise.resolve<Response | null>(null));
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
const handler: ExportedHandler<Id<InferCloudflarePluvHandlerEnv<TPluvServer>>> = {
|
|
231
|
-
fetch: async (request, env) => {
|
|
232
|
-
const response =
|
|
233
|
-
(await handlerFetch(request, env)) ??
|
|
234
|
-
new Response("Not Found", {
|
|
235
|
-
headers: { "Content-Type": "text/plain" },
|
|
236
|
-
status: 404,
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
return modify?.(request, response, env) ?? response;
|
|
240
|
-
},
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
return { fetch: handlerFetch, DurableObject, handler };
|
|
244
|
-
};
|