@pluv/platform-cloudflare 0.24.0 → 0.25.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 +6 -6
- package/CHANGELOG.md +51 -0
- package/dist/index.js +9 -102
- package/dist/index.mjs +7 -100
- package/package.json +7 -6
- package/src/CloudflarePlatform.ts +4 -4
- package/src/createPluvHandler.ts +3 -3
- package/src/PersistanceCloudflare.ts +0 -100
- package/src/utils/index.ts +0 -1
- package/src/utils/partitionByLength.ts +0 -8
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/platform-cloudflare@0.
|
|
2
|
+
> @pluv/platform-cloudflare@0.25.0 build /home/runner/work/pluv/pluv/packages/platform-cloudflare
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --dts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
[34mCLI[39m Target: es6
|
|
9
9
|
[34mESM[39m Build start
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m12.78 KB[39m
|
|
12
|
+
[32mCJS[39m ⚡️ Build success in 38ms
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m11.68 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 53ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 705ms
|
|
17
17
|
[32mDTS[39m [1mdist/index.d.mts [22m[32m4.15 KB[39m
|
|
18
18
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m4.15 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
# @pluv/platform-cloudflare
|
|
2
2
|
|
|
3
|
+
## 0.25.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9db06ba: **BREAKING **
|
|
8
|
+
|
|
9
|
+
Fixed typos `persistance` to `persistence`.
|
|
10
|
+
|
|
11
|
+
This does mean that all properties referencing `persistance` will need to be fixed. Examples below:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Re-install @pluv/persistence-redis
|
|
15
|
+
pnpm uninstall @pluv/persistance-redis
|
|
16
|
+
pnpm install @pluv/persistence-redis
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// Before
|
|
21
|
+
createIO({
|
|
22
|
+
platform: platformNode({
|
|
23
|
+
persistance: new PersistanceRedis(/* ... */),
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// After
|
|
28
|
+
createIO({
|
|
29
|
+
platform: platformNode({
|
|
30
|
+
persistence: new PersistenceRedis(/* ... */),
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`@pluv/persistance-redis` has been deprecated for `@pluv/persistence-redis`.
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [9db06ba]
|
|
40
|
+
- Updated dependencies [4e078ca]
|
|
41
|
+
- Updated dependencies [f556d30]
|
|
42
|
+
- Updated dependencies [9db06ba]
|
|
43
|
+
- @pluv/persistence-cloudflare-transactional-storage@0.25.0
|
|
44
|
+
- @pluv/io@0.25.0
|
|
45
|
+
- @pluv/types@0.25.0
|
|
46
|
+
|
|
47
|
+
## 0.24.1
|
|
48
|
+
|
|
49
|
+
### Patch Changes
|
|
50
|
+
|
|
51
|
+
- @pluv/io@0.24.1
|
|
52
|
+
- @pluv/types@0.24.1
|
|
53
|
+
|
|
3
54
|
## 0.24.0
|
|
4
55
|
|
|
5
56
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -72,14 +72,14 @@ var createPluvHandler = (config) => {
|
|
|
72
72
|
}
|
|
73
73
|
webSocketClose(ws, code, reason, wasClean) {
|
|
74
74
|
return __async(this, null, function* () {
|
|
75
|
-
if (io._registrationMode !== "detached") return;
|
|
75
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
76
76
|
const handler2 = this._room.onClose(ws);
|
|
77
77
|
yield handler2({ code, reason });
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
webSocketError(ws, error) {
|
|
81
81
|
return __async(this, null, function* () {
|
|
82
|
-
if (io._registrationMode !== "detached") return;
|
|
82
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
83
83
|
const handler2 = this._room.onError(ws);
|
|
84
84
|
const eventError = error instanceof Error ? error : new Error("Internal Error");
|
|
85
85
|
yield handler2({ error: eventError, message: eventError.message });
|
|
@@ -87,7 +87,7 @@ var createPluvHandler = (config) => {
|
|
|
87
87
|
}
|
|
88
88
|
webSocketMessage(ws, message) {
|
|
89
89
|
return __async(this, null, function* () {
|
|
90
|
-
if (io._registrationMode !== "detached") return;
|
|
90
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
91
91
|
const handler2 = this._room.onMessage(ws);
|
|
92
92
|
yield handler2({ data: message });
|
|
93
93
|
});
|
|
@@ -184,7 +184,8 @@ var createPluvHandler = (config) => {
|
|
|
184
184
|
};
|
|
185
185
|
|
|
186
186
|
// src/CloudflarePlatform.ts
|
|
187
|
-
var
|
|
187
|
+
var import_io2 = require("@pluv/io");
|
|
188
|
+
var import_persistence_cloudflare_transactional_storage = require("@pluv/persistence-cloudflare-transactional-storage");
|
|
188
189
|
|
|
189
190
|
// src/CloudflareWebSocket.ts
|
|
190
191
|
var import_io = require("@pluv/io");
|
|
@@ -250,108 +251,14 @@ var CloudflareWebSocket = class extends import_io.AbstractWebSocket {
|
|
|
250
251
|
}
|
|
251
252
|
};
|
|
252
253
|
|
|
253
|
-
// src/PersistanceCloudflare.ts
|
|
254
|
-
var import_io2 = require("@pluv/io");
|
|
255
|
-
|
|
256
|
-
// src/utils/partitionByLength.ts
|
|
257
|
-
var partitionByLength = (arr, length) => {
|
|
258
|
-
if (!arr.length) return [];
|
|
259
|
-
const head = arr.slice(0, length);
|
|
260
|
-
const tail = arr.slice(length);
|
|
261
|
-
return [head, ...partitionByLength(tail, length)];
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
// src/PersistanceCloudflare.ts
|
|
265
|
-
var CLOUDFLARE_DELETE_BATCH_LIMIT = 128;
|
|
266
|
-
var STORAGE_PREFIX = "$PLUV_STORAGE;";
|
|
267
|
-
var USER_PREFIX = "$PLUV_USER";
|
|
268
|
-
var PersistanceCloudflare = class extends import_io2.AbstractPersistance {
|
|
269
|
-
constructor(config) {
|
|
270
|
-
super();
|
|
271
|
-
const { state } = config;
|
|
272
|
-
this._state = state;
|
|
273
|
-
}
|
|
274
|
-
addUser(room, connectionId, user) {
|
|
275
|
-
return __async(this, null, function* () {
|
|
276
|
-
yield this._state.storage.put(this._getUserKey(room, connectionId), user);
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
deleteStorageState(room) {
|
|
280
|
-
return __async(this, null, function* () {
|
|
281
|
-
yield this._state.storage.delete(this._getStorageKey(room));
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
deleteUser(room, connectionId) {
|
|
285
|
-
return __async(this, null, function* () {
|
|
286
|
-
yield this._state.storage.delete(this._getUserKey(room, connectionId));
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
deleteUsers(room) {
|
|
290
|
-
return __async(this, null, function* () {
|
|
291
|
-
const map = yield this._state.storage.list({
|
|
292
|
-
allowConcurrency: true,
|
|
293
|
-
noCache: true,
|
|
294
|
-
prefix: USER_PREFIX
|
|
295
|
-
});
|
|
296
|
-
const partitions = partitionByLength(Array.from(map.keys()), CLOUDFLARE_DELETE_BATCH_LIMIT);
|
|
297
|
-
yield this._state.storage.transaction((tx) => __async(this, null, function* () {
|
|
298
|
-
yield partitions.reduce((promise, partition) => __async(this, null, function* () {
|
|
299
|
-
return yield promise.then(() => __async(this, null, function* () {
|
|
300
|
-
yield tx.delete(partition);
|
|
301
|
-
}));
|
|
302
|
-
}), Promise.resolve());
|
|
303
|
-
}));
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
getSize(room) {
|
|
307
|
-
return __async(this, null, function* () {
|
|
308
|
-
const storage = yield this._state.storage.list({ prefix: USER_PREFIX });
|
|
309
|
-
return storage.size;
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
getStorageState(room) {
|
|
313
|
-
return __async(this, null, function* () {
|
|
314
|
-
const storage = yield this._state.storage.get(this._getStorageKey(room));
|
|
315
|
-
return storage != null ? storage : null;
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
getUser(room, connectionId) {
|
|
319
|
-
return __async(this, null, function* () {
|
|
320
|
-
const user = yield this._state.storage.get(this._getUserKey(room, connectionId));
|
|
321
|
-
return user != null ? user : null;
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
getUsers(room) {
|
|
325
|
-
return __async(this, null, function* () {
|
|
326
|
-
const storage = yield this._state.storage.list({
|
|
327
|
-
prefix: USER_PREFIX
|
|
328
|
-
});
|
|
329
|
-
return Array.from(storage.values());
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
setStorageState(room, state) {
|
|
333
|
-
return __async(this, null, function* () {
|
|
334
|
-
yield this._state.storage.put(this._getStorageKey(room), state, {
|
|
335
|
-
allowConcurrency: true
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
_getStorageKey(room) {
|
|
340
|
-
return `${STORAGE_PREFIX}::${room}`;
|
|
341
|
-
}
|
|
342
|
-
_getUserKey(room, connectionId) {
|
|
343
|
-
return `${USER_PREFIX}::${room}::${connectionId}`;
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
254
|
// src/constants.ts
|
|
348
255
|
var DEFAULT_REGISTRATION_MODE = "detached";
|
|
349
256
|
|
|
350
257
|
// src/CloudflarePlatform.ts
|
|
351
|
-
var CloudflarePlatform = class _CloudflarePlatform extends
|
|
258
|
+
var CloudflarePlatform = class _CloudflarePlatform extends import_io2.AbstractPlatform {
|
|
352
259
|
constructor(config = {}) {
|
|
353
260
|
var _a;
|
|
354
|
-
super(__spreadValues(__spreadValues({}, config), config.context && config.mode === "detached" ? {
|
|
261
|
+
super(__spreadValues(__spreadValues({}, config), config.context && config.mode === "detached" ? { persistence: new import_persistence_cloudflare_transactional_storage.PersistenceCloudflareTransactionalStorage(config.context) } : {}));
|
|
355
262
|
this._registrationMode = (_a = config.mode) != null ? _a : DEFAULT_REGISTRATION_MODE;
|
|
356
263
|
const detachedState = this._getDetachedState();
|
|
357
264
|
if (!detachedState) return;
|
|
@@ -371,7 +278,7 @@ var CloudflarePlatform = class _CloudflarePlatform extends import_io3.AbstractPl
|
|
|
371
278
|
}
|
|
372
279
|
convertWebSocket(webSocket, config) {
|
|
373
280
|
const { room } = config;
|
|
374
|
-
return new CloudflareWebSocket(webSocket, {
|
|
281
|
+
return new CloudflareWebSocket(webSocket, { persistence: this.persistence, room });
|
|
375
282
|
}
|
|
376
283
|
getLastPing(webSocket) {
|
|
377
284
|
var _a;
|
|
@@ -406,7 +313,7 @@ var CloudflarePlatform = class _CloudflarePlatform extends import_io3.AbstractPl
|
|
|
406
313
|
}
|
|
407
314
|
return new _CloudflarePlatform(__spreadProps(__spreadValues({
|
|
408
315
|
mode: this._registrationMode,
|
|
409
|
-
|
|
316
|
+
persistence: this.persistence,
|
|
410
317
|
pubSub: this.pubSub
|
|
411
318
|
}, config), {
|
|
412
319
|
context: { env: context.env, state: context.state }
|
package/dist/index.mjs
CHANGED
|
@@ -48,14 +48,14 @@ var createPluvHandler = (config) => {
|
|
|
48
48
|
}
|
|
49
49
|
webSocketClose(ws, code, reason, wasClean) {
|
|
50
50
|
return __async(this, null, function* () {
|
|
51
|
-
if (io._registrationMode !== "detached") return;
|
|
51
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
52
52
|
const handler2 = this._room.onClose(ws);
|
|
53
53
|
yield handler2({ code, reason });
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
webSocketError(ws, error) {
|
|
57
57
|
return __async(this, null, function* () {
|
|
58
|
-
if (io._registrationMode !== "detached") return;
|
|
58
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
59
59
|
const handler2 = this._room.onError(ws);
|
|
60
60
|
const eventError = error instanceof Error ? error : new Error("Internal Error");
|
|
61
61
|
yield handler2({ error: eventError, message: eventError.message });
|
|
@@ -63,7 +63,7 @@ var createPluvHandler = (config) => {
|
|
|
63
63
|
}
|
|
64
64
|
webSocketMessage(ws, message) {
|
|
65
65
|
return __async(this, null, function* () {
|
|
66
|
-
if (io._registrationMode !== "detached") return;
|
|
66
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
67
67
|
const handler2 = this._room.onMessage(ws);
|
|
68
68
|
yield handler2({ data: message });
|
|
69
69
|
});
|
|
@@ -161,6 +161,7 @@ var createPluvHandler = (config) => {
|
|
|
161
161
|
|
|
162
162
|
// src/CloudflarePlatform.ts
|
|
163
163
|
import { AbstractPlatform } from "@pluv/io";
|
|
164
|
+
import { PersistenceCloudflareTransactionalStorage } from "@pluv/persistence-cloudflare-transactional-storage";
|
|
164
165
|
|
|
165
166
|
// src/CloudflareWebSocket.ts
|
|
166
167
|
import { AbstractWebSocket } from "@pluv/io";
|
|
@@ -226,100 +227,6 @@ var CloudflareWebSocket = class extends AbstractWebSocket {
|
|
|
226
227
|
}
|
|
227
228
|
};
|
|
228
229
|
|
|
229
|
-
// src/PersistanceCloudflare.ts
|
|
230
|
-
import { AbstractPersistance } from "@pluv/io";
|
|
231
|
-
|
|
232
|
-
// src/utils/partitionByLength.ts
|
|
233
|
-
var partitionByLength = (arr, length) => {
|
|
234
|
-
if (!arr.length) return [];
|
|
235
|
-
const head = arr.slice(0, length);
|
|
236
|
-
const tail = arr.slice(length);
|
|
237
|
-
return [head, ...partitionByLength(tail, length)];
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
// src/PersistanceCloudflare.ts
|
|
241
|
-
var CLOUDFLARE_DELETE_BATCH_LIMIT = 128;
|
|
242
|
-
var STORAGE_PREFIX = "$PLUV_STORAGE;";
|
|
243
|
-
var USER_PREFIX = "$PLUV_USER";
|
|
244
|
-
var PersistanceCloudflare = class extends AbstractPersistance {
|
|
245
|
-
constructor(config) {
|
|
246
|
-
super();
|
|
247
|
-
const { state } = config;
|
|
248
|
-
this._state = state;
|
|
249
|
-
}
|
|
250
|
-
addUser(room, connectionId, user) {
|
|
251
|
-
return __async(this, null, function* () {
|
|
252
|
-
yield this._state.storage.put(this._getUserKey(room, connectionId), user);
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
deleteStorageState(room) {
|
|
256
|
-
return __async(this, null, function* () {
|
|
257
|
-
yield this._state.storage.delete(this._getStorageKey(room));
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
deleteUser(room, connectionId) {
|
|
261
|
-
return __async(this, null, function* () {
|
|
262
|
-
yield this._state.storage.delete(this._getUserKey(room, connectionId));
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
deleteUsers(room) {
|
|
266
|
-
return __async(this, null, function* () {
|
|
267
|
-
const map = yield this._state.storage.list({
|
|
268
|
-
allowConcurrency: true,
|
|
269
|
-
noCache: true,
|
|
270
|
-
prefix: USER_PREFIX
|
|
271
|
-
});
|
|
272
|
-
const partitions = partitionByLength(Array.from(map.keys()), CLOUDFLARE_DELETE_BATCH_LIMIT);
|
|
273
|
-
yield this._state.storage.transaction((tx) => __async(this, null, function* () {
|
|
274
|
-
yield partitions.reduce((promise, partition) => __async(this, null, function* () {
|
|
275
|
-
return yield promise.then(() => __async(this, null, function* () {
|
|
276
|
-
yield tx.delete(partition);
|
|
277
|
-
}));
|
|
278
|
-
}), Promise.resolve());
|
|
279
|
-
}));
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
getSize(room) {
|
|
283
|
-
return __async(this, null, function* () {
|
|
284
|
-
const storage = yield this._state.storage.list({ prefix: USER_PREFIX });
|
|
285
|
-
return storage.size;
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
getStorageState(room) {
|
|
289
|
-
return __async(this, null, function* () {
|
|
290
|
-
const storage = yield this._state.storage.get(this._getStorageKey(room));
|
|
291
|
-
return storage != null ? storage : null;
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
getUser(room, connectionId) {
|
|
295
|
-
return __async(this, null, function* () {
|
|
296
|
-
const user = yield this._state.storage.get(this._getUserKey(room, connectionId));
|
|
297
|
-
return user != null ? user : null;
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
getUsers(room) {
|
|
301
|
-
return __async(this, null, function* () {
|
|
302
|
-
const storage = yield this._state.storage.list({
|
|
303
|
-
prefix: USER_PREFIX
|
|
304
|
-
});
|
|
305
|
-
return Array.from(storage.values());
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
setStorageState(room, state) {
|
|
309
|
-
return __async(this, null, function* () {
|
|
310
|
-
yield this._state.storage.put(this._getStorageKey(room), state, {
|
|
311
|
-
allowConcurrency: true
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
_getStorageKey(room) {
|
|
316
|
-
return `${STORAGE_PREFIX}::${room}`;
|
|
317
|
-
}
|
|
318
|
-
_getUserKey(room, connectionId) {
|
|
319
|
-
return `${USER_PREFIX}::${room}::${connectionId}`;
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
|
|
323
230
|
// src/constants.ts
|
|
324
231
|
var DEFAULT_REGISTRATION_MODE = "detached";
|
|
325
232
|
|
|
@@ -327,7 +234,7 @@ var DEFAULT_REGISTRATION_MODE = "detached";
|
|
|
327
234
|
var CloudflarePlatform = class _CloudflarePlatform extends AbstractPlatform {
|
|
328
235
|
constructor(config = {}) {
|
|
329
236
|
var _a;
|
|
330
|
-
super(__spreadValues(__spreadValues({}, config), config.context && config.mode === "detached" ? {
|
|
237
|
+
super(__spreadValues(__spreadValues({}, config), config.context && config.mode === "detached" ? { persistence: new PersistenceCloudflareTransactionalStorage(config.context) } : {}));
|
|
331
238
|
this._registrationMode = (_a = config.mode) != null ? _a : DEFAULT_REGISTRATION_MODE;
|
|
332
239
|
const detachedState = this._getDetachedState();
|
|
333
240
|
if (!detachedState) return;
|
|
@@ -347,7 +254,7 @@ var CloudflarePlatform = class _CloudflarePlatform extends AbstractPlatform {
|
|
|
347
254
|
}
|
|
348
255
|
convertWebSocket(webSocket, config) {
|
|
349
256
|
const { room } = config;
|
|
350
|
-
return new CloudflareWebSocket(webSocket, {
|
|
257
|
+
return new CloudflareWebSocket(webSocket, { persistence: this.persistence, room });
|
|
351
258
|
}
|
|
352
259
|
getLastPing(webSocket) {
|
|
353
260
|
var _a;
|
|
@@ -382,7 +289,7 @@ var CloudflarePlatform = class _CloudflarePlatform extends AbstractPlatform {
|
|
|
382
289
|
}
|
|
383
290
|
return new _CloudflarePlatform(__spreadProps(__spreadValues({
|
|
384
291
|
mode: this._registrationMode,
|
|
385
|
-
|
|
292
|
+
persistence: this.persistence,
|
|
386
293
|
pubSub: this.pubSub
|
|
387
294
|
}, config), {
|
|
388
295
|
context: { env: context.env, state: context.state }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/platform-cloudflare",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "@pluv/io adapter for cloudflare workers",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,16 +18,17 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"path-to-regexp": "^7.1.0",
|
|
21
|
-
"@pluv/io": "^0.
|
|
22
|
-
"@pluv/
|
|
21
|
+
"@pluv/io": "^0.25.0",
|
|
22
|
+
"@pluv/persistence-cloudflare-transactional-storage": "^0.25.0",
|
|
23
|
+
"@pluv/types": "^0.25.0"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
|
-
"@cloudflare/workers-types": "^4.
|
|
26
|
+
"@cloudflare/workers-types": "^4.20240821.1",
|
|
26
27
|
"eslint": "^8.57.0",
|
|
27
28
|
"tsup": "^8.2.4",
|
|
28
29
|
"typescript": "^5.5.4",
|
|
29
|
-
"@pluv/tsconfig": "^0.
|
|
30
|
-
"eslint-config-pluv": "^0.
|
|
30
|
+
"@pluv/tsconfig": "^0.25.0",
|
|
31
|
+
"eslint-config-pluv": "^0.25.0"
|
|
31
32
|
},
|
|
32
33
|
"scripts": {
|
|
33
34
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
@@ -5,8 +5,8 @@ import type {
|
|
|
5
5
|
WebSocketSerializedState,
|
|
6
6
|
} from "@pluv/io";
|
|
7
7
|
import { AbstractPlatform } from "@pluv/io";
|
|
8
|
+
import { PersistenceCloudflareTransactionalStorage } from "@pluv/persistence-cloudflare-transactional-storage";
|
|
8
9
|
import { CloudflareWebSocket } from "./CloudflareWebSocket";
|
|
9
|
-
import { PersistanceCloudflare } from "./PersistanceCloudflare";
|
|
10
10
|
import { DEFAULT_REGISTRATION_MODE } from "./constants";
|
|
11
11
|
|
|
12
12
|
export type CloudflarePlatformConfig<TEnv extends Record<string, any> = {}> = AbstractPlatformConfig<
|
|
@@ -25,7 +25,7 @@ export class CloudflarePlatform<TEnv extends Record<string, any> = {}> extends A
|
|
|
25
25
|
super({
|
|
26
26
|
...config,
|
|
27
27
|
...(config.context && config.mode === "detached"
|
|
28
|
-
? {
|
|
28
|
+
? { persistence: new PersistenceCloudflareTransactionalStorage(config.context) }
|
|
29
29
|
: {}),
|
|
30
30
|
});
|
|
31
31
|
|
|
@@ -55,7 +55,7 @@ export class CloudflarePlatform<TEnv extends Record<string, any> = {}> extends A
|
|
|
55
55
|
public convertWebSocket(webSocket: WebSocket, config: ConvertWebSocketConfig): CloudflareWebSocket {
|
|
56
56
|
const { room } = config;
|
|
57
57
|
|
|
58
|
-
return new CloudflareWebSocket(webSocket, {
|
|
58
|
+
return new CloudflareWebSocket(webSocket, { persistence: this.persistence, room });
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
public getLastPing(webSocket: CloudflareWebSocket): number | null {
|
|
@@ -100,7 +100,7 @@ export class CloudflarePlatform<TEnv extends Record<string, any> = {}> extends A
|
|
|
100
100
|
|
|
101
101
|
return new CloudflarePlatform<TEnv>({
|
|
102
102
|
mode: this._registrationMode,
|
|
103
|
-
|
|
103
|
+
persistence: this.persistence,
|
|
104
104
|
pubSub: this.pubSub,
|
|
105
105
|
...config,
|
|
106
106
|
context: { env: context.env, state: context.state },
|
package/src/createPluvHandler.ts
CHANGED
|
@@ -59,7 +59,7 @@ export const createPluvHandler = <TPluvServer extends PluvServer<CloudflarePlatf
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
public async webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean): Promise<void> {
|
|
62
|
-
if (io._registrationMode !== "detached") return;
|
|
62
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
63
63
|
|
|
64
64
|
const handler = this._room.onClose(ws);
|
|
65
65
|
|
|
@@ -67,7 +67,7 @@ export const createPluvHandler = <TPluvServer extends PluvServer<CloudflarePlatf
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
public async webSocketError(ws: WebSocket, error: unknown): Promise<void> {
|
|
70
|
-
if (io._registrationMode !== "detached") return;
|
|
70
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
71
71
|
|
|
72
72
|
const handler = this._room.onError(ws);
|
|
73
73
|
const eventError = error instanceof Error ? error : new Error("Internal Error");
|
|
@@ -76,7 +76,7 @@ export const createPluvHandler = <TPluvServer extends PluvServer<CloudflarePlatf
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
public async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void> {
|
|
79
|
-
if (io._registrationMode !== "detached") return;
|
|
79
|
+
if (io._defs.platform._registrationMode !== "detached") return;
|
|
80
80
|
|
|
81
81
|
const handler = this._room.onMessage(ws);
|
|
82
82
|
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { AbstractPersistance } from "@pluv/io";
|
|
2
|
-
import type { JsonObject } from "@pluv/types";
|
|
3
|
-
import { partitionByLength } from "./utils";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* !HACK
|
|
7
|
-
* @description The max amount of keys a Cloudflare transactional storage may delete at once
|
|
8
|
-
* @see https://developers.cloudflare.com/durable-objects/api/transactional-storage-api/#delete
|
|
9
|
-
* @date July 8, 2024
|
|
10
|
-
*/
|
|
11
|
-
const CLOUDFLARE_DELETE_BATCH_LIMIT = 128;
|
|
12
|
-
const STORAGE_PREFIX = "$PLUV_STORAGE;";
|
|
13
|
-
const USER_PREFIX = "$PLUV_USER";
|
|
14
|
-
|
|
15
|
-
export interface PersistanceCloudflareConfig<TEnv extends Record<string, any> = {}> {
|
|
16
|
-
env: TEnv;
|
|
17
|
-
state: DurableObjectState;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class PersistanceCloudflare<TEnv extends Record<string, any> = {}> extends AbstractPersistance {
|
|
21
|
-
private _state: DurableObjectState;
|
|
22
|
-
|
|
23
|
-
constructor(config: PersistanceCloudflareConfig<TEnv>) {
|
|
24
|
-
super();
|
|
25
|
-
|
|
26
|
-
const { state } = config;
|
|
27
|
-
|
|
28
|
-
this._state = state;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public async addUser(room: string, connectionId: string, user: JsonObject | null): Promise<void> {
|
|
32
|
-
await this._state.storage.put(this._getUserKey(room, connectionId), user);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public async deleteStorageState(room: string): Promise<void> {
|
|
36
|
-
await this._state.storage.delete(this._getStorageKey(room));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
public async deleteUser(room: string, connectionId: string): Promise<void> {
|
|
40
|
-
await this._state.storage.delete(this._getUserKey(room, connectionId));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public async deleteUsers(room: string): Promise<void> {
|
|
44
|
-
const map = await this._state.storage.list({
|
|
45
|
-
allowConcurrency: true,
|
|
46
|
-
noCache: true,
|
|
47
|
-
prefix: USER_PREFIX,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const partitions = partitionByLength(Array.from(map.keys()), CLOUDFLARE_DELETE_BATCH_LIMIT);
|
|
51
|
-
|
|
52
|
-
await this._state.storage.transaction(async (tx) => {
|
|
53
|
-
await partitions.reduce(async (promise, partition) => {
|
|
54
|
-
return await promise.then(async () => {
|
|
55
|
-
await tx.delete(partition as string[]);
|
|
56
|
-
});
|
|
57
|
-
}, Promise.resolve());
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
public async getSize(room: string): Promise<number> {
|
|
62
|
-
const storage = await this._state.storage.list({ prefix: USER_PREFIX });
|
|
63
|
-
|
|
64
|
-
return storage.size;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public async getStorageState(room: string): Promise<string | null> {
|
|
68
|
-
const storage = await this._state.storage.get<string>(this._getStorageKey(room));
|
|
69
|
-
|
|
70
|
-
return storage ?? null;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public async getUser(room: string, connectionId: string): Promise<JsonObject | null> {
|
|
74
|
-
const user = await this._state.storage.get<JsonObject | null>(this._getUserKey(room, connectionId));
|
|
75
|
-
|
|
76
|
-
return user ?? null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public async getUsers(room: string): Promise<readonly (JsonObject | null)[]> {
|
|
80
|
-
const storage = await this._state.storage.list({
|
|
81
|
-
prefix: USER_PREFIX,
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
return Array.from(storage.values()) as (JsonObject | null)[];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
public async setStorageState(room: string, state: string): Promise<void> {
|
|
88
|
-
await this._state.storage.put(this._getStorageKey(room), state, {
|
|
89
|
-
allowConcurrency: true,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private _getStorageKey(room: string): string {
|
|
94
|
-
return `${STORAGE_PREFIX}::${room}`;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private _getUserKey(room: string, connectionId: string): string {
|
|
98
|
-
return `${USER_PREFIX}::${room}::${connectionId}`;
|
|
99
|
-
}
|
|
100
|
-
}
|
package/src/utils/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { partitionByLength } from "./partitionByLength";
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export const partitionByLength = <T>(arr: readonly T[] | T[], length: number): readonly (readonly T[])[] => {
|
|
2
|
-
if (!arr.length) return [];
|
|
3
|
-
|
|
4
|
-
const head = arr.slice(0, length);
|
|
5
|
-
const tail = arr.slice(length);
|
|
6
|
-
|
|
7
|
-
return [head, ...partitionByLength(tail, length)];
|
|
8
|
-
};
|