@pluv/platform-cloudflare 3.2.1 → 4.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.
@@ -1,15 +1,16 @@
1
1
 
2
- > @pluv/platform-cloudflare@3.2.1 build /home/runner/work/pluv/pluv/packages/platform-cloudflare
3
- > tsup src/index.ts
2
+ > @pluv/platform-cloudflare@4.0.0 build /home/runner/work/pluv/pluv/packages/platform-cloudflare
3
+ > tsdown
4
4
 
5
- CLI Building entry: src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.5.0
8
- CLI Using tsup config: /home/runner/work/pluv/pluv/packages/platform-cloudflare/tsup.config.ts
9
- CLI Target: es6
10
- ESM Build start
11
- ESM dist/index.mjs 8.92 KB
12
- ESM ⚡️ Build success in 21ms
13
- DTS Build start
14
- DTS ⚡️ Build success in 913ms
15
- DTS dist/index.d.mts 5.50 KB
5
+ ℹ tsdown v0.20.0-beta.4 powered by rolldown v1.0.0-beta.60
6
+ ℹ config file: /home/runner/work/pluv/pluv/packages/platform-cloudflare/tsdown.config.ts
7
+ ℹ entry: src/index.ts
8
+ ℹ target: esnext
9
+ ℹ tsconfig: tsconfig.json
10
+ ℹ Build start
11
+ ℹ dist/index.mjs  6.30 kB │ gzip: 1.81 kB
12
+ ℹ dist/index.mjs.map 18.41 kB │ gzip: 4.57 kB
13
+ ℹ dist/index.d.mts.map  3.10 kB │ gzip: 0.99 kB
14
+ ℹ dist/index.d.mts  5.79 kB │ gzip: 1.47 kB
15
+ ℹ 4 files, total: 33.60 kB
16
+ ✔ Build complete in 672ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,107 @@
1
1
  # @pluv/platform-cloudflare
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - df5c39c: Update all packages to be ESM only.
8
+ - 07e2a1e: ### Breaking Changes
9
+
10
+ This release includes the following breaking changes:
11
+ 1. **Removed `onDestroy` handler** (room-level only) - replaced with `onRoomDestroyed` and `onStorageDestroyed`
12
+ 2. **Removed `onRoomDeleted` handler** (server-level) - replaced with `onRoomDestroyed` and `onStorageDestroyed`
13
+ 3. **Listeners can no longer be configured at room-level** - all listeners must be configured at server-level via `io.server()`
14
+ 4. **Event type changes** - `IORoomDestroyedEvent` no longer includes `encodedState`
15
+
16
+ #### Remove `onDestroy` and `onRoomDeleted` in favor of `onRoomDestroyed` and `onStorageDestroyed`
17
+
18
+ **BREAKING**: Two event handlers have been **removed** in favor of two separate handlers that provide better control over when storage is saved. This is a breaking change that requires code updates.
19
+
20
+ **New Handlers:**
21
+ - **`onRoomDestroyed`**: Fires whenever a room is destroyed. This event does NOT include `encodedState` to prevent accidentally saving empty or uninitialized storage data. **Available only at server-level** via `io.server()`.
22
+ - **`onStorageDestroyed`**: Only fires when the storage document is about to be destroyed after it has been initialized via `initializeSession`. This event includes `encodedState` and should be used for saving storage to your database. **Available only at server-level** via `io.server()`.
23
+
24
+ **Removed Handlers:**
25
+ - **`onDestroy`** (room-level only, via `createRoom`): **REMOVED**. Use `onRoomDestroyed` and `onStorageDestroyed` instead.
26
+ - **`onRoomDeleted`** (server-level): **REMOVED**. Use `onRoomDestroyed` and `onStorageDestroyed` instead.
27
+
28
+ **Migration Guide:**
29
+
30
+ **Old (no longer works):**
31
+
32
+ ```typescript
33
+ // Room-level onDestroy (removed)
34
+ const room = io.createRoom("room-id", {
35
+ onDestroy: async ({ encodedState, room }) => {
36
+ // This no longer works
37
+ await saveToDatabase(room, encodedState);
38
+ },
39
+ });
40
+
41
+ // Server-level onRoomDeleted (removed)
42
+ io.server({
43
+ onRoomDeleted: async ({ encodedState, room }) => {
44
+ // This no longer works
45
+ await saveToDatabase(room, encodedState);
46
+ },
47
+ });
48
+ ```
49
+
50
+ **New (recommended approach):**
51
+
52
+ ```typescript
53
+ // Server-level handlers (recommended - all listeners are now server-level)
54
+ io.server({
55
+ onRoomDestroyed: async ({ room }) => {
56
+ // Room destroyed - use for cleanup if needed
57
+ await cleanupRoom(room);
58
+ },
59
+ onStorageDestroyed: async ({ encodedState, room }) => {
60
+ // Only fires when storage was initialized via initializeSession
61
+ // Safe to save to database
62
+ await saveToDatabase(room, encodedState);
63
+ },
64
+ });
65
+
66
+ // Rooms are created without listener options
67
+ const room = io.createRoom("room-id");
68
+ ```
69
+
70
+ #### Type Changes
71
+
72
+ **BREAKING**: The following type changes may require TypeScript code updates:
73
+ - **`IORoomDestroyedEvent`** no longer includes `encodedState` (breaking change if you were accessing `encodedState` from this event)
74
+ - **`IORoomListenerEvent`** includes `encodedState: string | null` (used by `onStorageDestroyed`)
75
+ - **All listeners must be configured at the server level** via `io.server()`, not at the room level via `createRoom()` (breaking change - room-level listener configuration is no longer supported)
76
+ - **`CreateRoomOptions`** now correctly requires platform-specific room context properties (e.g., `env` and `state` for Cloudflare) when they are required by the platform, while properly handling optional properties like `meta` (breaking change - TypeScript will now correctly enforce required properties)
77
+
78
+ ### Minor Changes
79
+
80
+ - 037074e: Migrated build process from tsup to tsdown.
81
+
82
+ ### Patch Changes
83
+
84
+ - 2eb5def: Bumped dependencies.
85
+ - Updated dependencies [2eb5def]
86
+ - Updated dependencies [df5c39c]
87
+ - Updated dependencies [c142910]
88
+ - Updated dependencies [037074e]
89
+ - Updated dependencies [07e2a1e]
90
+ - @pluv/persistence-cloudflare-transactional-storage@4.0.0
91
+ - @pluv/types@4.0.0
92
+ - @pluv/crdt@4.0.0
93
+ - @pluv/io@4.0.0
94
+
95
+ ## 3.2.2
96
+
97
+ ### Patch Changes
98
+
99
+ - Updated dependencies [8665dbe]
100
+ - @pluv/types@3.2.2
101
+ - @pluv/crdt@3.2.2
102
+ - @pluv/io@3.2.2
103
+ - @pluv/persistence-cloudflare-transactional-storage@3.2.2
104
+
3
105
  ## 3.2.1
4
106
 
5
107
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1,98 +1,106 @@
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';
3
- import { CrdtLibraryType, NoopCrdtDocFactory } from '@pluv/crdt';
1
+ import { AbstractEventMap, AbstractListener, AbstractPlatform, AbstractPlatformConfig, AbstractWebSocket, AbstractWebSocketConfig, ConvertWebSocketConfig, CreateIOParams, InferInitContextType, PluvContext, PluvIOAuthorize, WebSocketRegistrationMode, WebSocketSerializedState, WebSocketSession } from "@pluv/io";
2
+ import { BaseUser, IOAuthorize, Id, InferIOAuthorizeUser, Json, JsonObject } from "@pluv/types";
3
+ import { CrdtLibraryType, NoopCrdtDocFactory } from "@pluv/crdt";
4
4
 
5
+ //#region src/CloudflareWebSocket.d.ts
5
6
  type CloudflareWebSocketConfig = AbstractWebSocketConfig;
6
7
  declare class CloudflareWebSocket<TAuthorize extends IOAuthorize<any, any> | null = null> extends AbstractWebSocket<WebSocket, TAuthorize> {
7
- set presence(presence: JsonObject | null);
8
- get readyState(): 0 | 1 | 2 | 3;
9
- get session(): WebSocketSession<TAuthorize>;
10
- get sessionId(): string;
11
- get state(): WebSocketSerializedState;
12
- set state(state: WebSocketSerializedState);
13
- set user(user: InferIOAuthorizeUser<TAuthorize>);
14
- constructor(webSocket: WebSocket, config: CloudflareWebSocketConfig);
15
- addEventListener<TType extends keyof AbstractEventMap>(type: TType, handler: AbstractListener<TType>): void;
16
- close(code?: number | undefined, reason?: string | undefined): void;
17
- send(message: string | ArrayBuffer | ArrayBufferView): void;
18
- terminate(code?: number): void;
8
+ set presence(presence: JsonObject | null);
9
+ get readyState(): 0 | 1 | 2 | 3;
10
+ get session(): WebSocketSession<TAuthorize>;
11
+ get sessionId(): string;
12
+ get state(): WebSocketSerializedState;
13
+ set state(state: WebSocketSerializedState);
14
+ set user(user: InferIOAuthorizeUser<TAuthorize>);
15
+ constructor(webSocket: WebSocket, config: CloudflareWebSocketConfig);
16
+ addEventListener<TType extends keyof AbstractEventMap>(type: TType, handler: AbstractListener<TType>): void;
17
+ close(code?: number | undefined, reason?: string | undefined): void;
18
+ send(message: string | ArrayBuffer | ArrayBufferView): void;
19
+ terminate(code?: number): void;
19
20
  }
20
-
21
+ //#endregion
22
+ //#region src/CloudflarePlatform.d.ts
21
23
  type CloudflarePlatformRoomContext<TEnv extends Record<string, any>, TMeta extends Record<string, Json>> = {
22
- env: TEnv;
23
- state: DurableObjectState;
24
+ env: TEnv;
25
+ state: DurableObjectState;
24
26
  } & (keyof TMeta extends never ? {
25
- meta?: undefined;
27
+ meta?: undefined;
26
28
  } : {
27
- meta: TMeta;
29
+ meta: TMeta;
28
30
  });
29
31
  type CloudflarePlatformConfig<TEnv extends Record<string, any> = {}, TMeta extends Record<string, Json> = {}> = AbstractPlatformConfig<CloudflarePlatformRoomContext<TEnv, TMeta>> & {
30
- mode?: WebSocketRegistrationMode;
32
+ mode?: WebSocketRegistrationMode;
31
33
  };
32
34
  declare class CloudflarePlatform<TAuthorize extends IOAuthorize<any, any> | null = null, TEnv extends Record<string, any> = {}, TMeta extends Record<string, Json> = {}> extends AbstractPlatform<CloudflareWebSocket<TAuthorize>, {
33
- env: TEnv;
34
- request: Request;
35
+ env: TEnv;
36
+ request: Request;
35
37
  }, CloudflarePlatformRoomContext<TEnv, TMeta>, {
38
+ authorize: {
39
+ secret: true;
40
+ };
41
+ handleMode: "io";
42
+ requireAuth: false;
43
+ registrationMode: WebSocketRegistrationMode;
44
+ listeners: {
45
+ onRoomDestroyed: true;
46
+ onRoomMessage: true;
47
+ onStorageDestroyed: true;
48
+ onStorageUpdated: true;
49
+ onUserConnected: true;
50
+ onUserDisconnected: true;
51
+ };
52
+ router: true;
53
+ }> {
54
+ readonly id: string;
55
+ readonly _config: {
36
56
  authorize: {
37
- secret: true;
57
+ secret: true;
38
58
  };
39
59
  handleMode: "io";
40
- requireAuth: false;
41
60
  registrationMode: WebSocketRegistrationMode;
61
+ requireAuth: false;
42
62
  listeners: {
43
- onRoomDeleted: true;
44
- onRoomMessage: true;
45
- onStorageUpdated: true;
46
- onUserConnected: true;
47
- onUserDisconnected: true;
63
+ onRoomDestroyed: true;
64
+ onRoomMessage: true;
65
+ onStorageDestroyed: true;
66
+ onStorageUpdated: true;
67
+ onUserConnected: true;
68
+ onUserDisconnected: true;
48
69
  };
49
70
  router: true;
50
- }> {
51
- readonly id: string;
52
- readonly _config: {
53
- authorize: {
54
- secret: true;
55
- };
56
- handleMode: "io";
57
- registrationMode: WebSocketRegistrationMode;
58
- requireAuth: false;
59
- listeners: {
60
- onRoomDeleted: true;
61
- onRoomMessage: true;
62
- onStorageUpdated: true;
63
- onUserConnected: true;
64
- onUserDisconnected: true;
65
- };
66
- router: true;
67
- };
68
- readonly _name = "platformCloudflare";
69
- constructor(config: CloudflarePlatformConfig<TEnv, TMeta>);
70
- acceptWebSocket(webSocket: CloudflareWebSocket<TAuthorize>): Promise<void>;
71
- convertWebSocket(webSocket: WebSocket, config: ConvertWebSocketConfig): CloudflareWebSocket<TAuthorize>;
72
- getLastPing(webSocket: CloudflareWebSocket<TAuthorize>): number | null;
73
- getSerializedState(webSocket: WebSocket): WebSocketSerializedState | null;
74
- getSessionId(webSocket: WebSocket): string | null;
75
- getWebSockets(): readonly WebSocket[];
76
- initialize(config: AbstractPlatformConfig<CloudflarePlatformRoomContext<TEnv, TMeta>>): this;
77
- parseData(data: string | ArrayBuffer): Record<string, any>;
78
- randomUUID(): string;
79
- setSerializedState(webSocket: CloudflareWebSocket<TAuthorize>, state: WebSocketSerializedState): WebSocketSerializedState;
80
- private _getDetachedState;
71
+ };
72
+ readonly _name = "platformCloudflare";
73
+ constructor(config: CloudflarePlatformConfig<TEnv, TMeta>);
74
+ acceptWebSocket(webSocket: CloudflareWebSocket<TAuthorize>): Promise<void>;
75
+ convertWebSocket(webSocket: WebSocket, config: ConvertWebSocketConfig): CloudflareWebSocket<TAuthorize>;
76
+ getLastPing(webSocket: CloudflareWebSocket<TAuthorize>): number | null;
77
+ getSerializedState(webSocket: WebSocket): WebSocketSerializedState | null;
78
+ getSessionId(webSocket: WebSocket): string | null;
79
+ getWebSockets(): readonly WebSocket[];
80
+ initialize(config: AbstractPlatformConfig<CloudflarePlatformRoomContext<TEnv, TMeta>>): this;
81
+ parseData(data: string | ArrayBuffer): Record<string, any>;
82
+ randomUUID(): string;
83
+ setSerializedState(webSocket: CloudflareWebSocket<TAuthorize>, state: WebSocketSerializedState): WebSocketSerializedState;
84
+ private _getDetachedState;
81
85
  }
82
-
86
+ //#endregion
87
+ //#region src/utils/identity.d.ts
83
88
  declare const identity: <T extends unknown>(x: T) => T;
84
-
89
+ //#endregion
90
+ //#region src/infer.d.ts
85
91
  type InferCallback<TEnv extends Record<string, any> = {}, TMeta extends Record<string, Json> = {}> = (i: typeof identity) => {
86
- env?: (io: TEnv) => TEnv;
87
- meta?: (io: TMeta) => TMeta;
92
+ env?: (io: TEnv) => TEnv;
93
+ meta?: (io: TMeta) => TMeta;
88
94
  };
89
95
  declare const infer: <TEnv extends Record<string, any> = {}, TMeta extends Record<string, Json> = {}>(callback: InferCallback<TEnv, TMeta>) => InferCallback<TEnv, TMeta>;
90
-
96
+ //#endregion
97
+ //#region src/platformCloudflare.d.ts
91
98
  type PlatformCloudflareCreateIOParams<TEnv extends Record<string, any> = {}, TMeta extends Record<string, Json> = {}, TContext extends Record<string, any> = {}, TUser extends BaseUser | null = null, TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>> = Id<CloudflarePlatformConfig<TEnv, TMeta> & Omit<CreateIOParams<CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>, TContext, TUser, TCrdt>, "authorize" | "context" | "platform"> & {
92
- authorize?: PluvIOAuthorize<CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>, TUser, InferInitContextType<CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>>>;
93
- context?: PluvContext<CloudflarePlatform<IOAuthorize<TUser, any>, TEnv, TMeta>, TContext>;
94
- types?: InferCallback<TEnv, TMeta>;
99
+ authorize?: PluvIOAuthorize<CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>, TUser, InferInitContextType<CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>>>;
100
+ context?: PluvContext<CloudflarePlatform<IOAuthorize<TUser, any>, TEnv, TMeta>, TContext>;
101
+ types?: InferCallback<TEnv, TMeta>;
95
102
  }>;
96
103
  declare const platformCloudflare: <TEnv extends Record<string, any> = {}, TMeta extends Record<string, Json> = {}, TContext extends Record<string, any> = {}, TUser extends BaseUser | null = null, TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>>(config?: PlatformCloudflareCreateIOParams<TEnv, TMeta, TContext, TUser, TCrdt>) => CreateIOParams<CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>, TContext, TUser, TCrdt>;
97
-
98
- export { CloudflarePlatform, type CloudflarePlatformConfig, type InferCallback, type PlatformCloudflareCreateIOParams, infer, platformCloudflare };
104
+ //#endregion
105
+ export { type CloudflarePlatform, type CloudflarePlatformConfig, type InferCallback, type PlatformCloudflareCreateIOParams, infer, platformCloudflare };
106
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/CloudflareWebSocket.ts","../src/CloudflarePlatform.ts","../src/utils/identity.ts","../src/infer.ts","../src/platformCloudflare.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,273 +1,231 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
- var __async = (__this, __arguments, generator) => {
21
- return new Promise((resolve, reject) => {
22
- var fulfilled = (value) => {
23
- try {
24
- step(generator.next(value));
25
- } catch (e) {
26
- reject(e);
27
- }
28
- };
29
- var rejected = (value) => {
30
- try {
31
- step(generator.throw(value));
32
- } catch (e) {
33
- reject(e);
34
- }
35
- };
36
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
37
- step((generator = generator.apply(__this, __arguments)).next());
38
- });
39
- };
40
-
41
- // src/infer.ts
42
- var infer = (callback) => callback;
43
-
44
- // src/CloudflarePlatform.ts
45
- import { AbstractPlatform } from "@pluv/io";
1
+ import { AbstractPlatform, AbstractWebSocket } from "@pluv/io";
46
2
  import { PersistenceCloudflareTransactionalStorage } from "@pluv/persistence-cloudflare-transactional-storage";
47
3
 
48
- // src/CloudflareWebSocket.ts
49
- import { AbstractWebSocket } from "@pluv/io";
4
+ //#region src/infer.ts
5
+ const infer = (callback) => callback;
6
+
7
+ //#endregion
8
+ //#region src/CloudflareWebSocket.ts
50
9
  var CloudflareWebSocket = class extends AbstractWebSocket {
51
- set presence(presence) {
52
- const deserialized = this.webSocket.deserializeAttachment();
53
- const state = deserialized.state;
54
- this.webSocket.serializeAttachment(__spreadProps(__spreadValues({}, this.webSocket.deserializeAttachment()), {
55
- state: __spreadProps(__spreadValues({}, state), { presence })
56
- }));
57
- }
58
- get readyState() {
59
- return this.webSocket.readyState;
60
- }
61
- get session() {
62
- var _a;
63
- const deserialized = this.webSocket.deserializeAttachment();
64
- const sessionId = deserialized.sessionId;
65
- const state = this.state;
66
- const user = (_a = deserialized.user) != null ? _a : null;
67
- return __spreadProps(__spreadValues({}, state), {
68
- id: sessionId,
69
- user,
70
- webSocket: this
71
- });
72
- }
73
- get sessionId() {
74
- var _a, _b;
75
- const deserialized = (_a = this.webSocket.deserializeAttachment()) != null ? _a : {};
76
- const sessionId = (_b = deserialized.sessionId) != null ? _b : `p_${crypto.randomUUID()}`;
77
- if (typeof deserialized.sessionId !== "string") {
78
- this.webSocket.serializeAttachment(__spreadProps(__spreadValues({}, deserialized), { sessionId }));
79
- }
80
- return sessionId;
81
- }
82
- get state() {
83
- var _a;
84
- const deserialized = this.webSocket.deserializeAttachment();
85
- const state = (_a = deserialized == null ? void 0 : deserialized.state) != null ? _a : null;
86
- if (!state) throw new Error("Could not get websocket state");
87
- const currentPing = state.timers.ping;
88
- const lastPing = this._platform.getLastPing(this);
89
- if (!lastPing) return state;
90
- if (currentPing >= lastPing) return state;
91
- const newState = __spreadProps(__spreadValues({}, state), {
92
- timers: __spreadProps(__spreadValues({}, state.timers), { ping: lastPing })
93
- });
94
- return this._platform.setSerializedState(this, newState);
95
- }
96
- set state(state) {
97
- const deserialized = this.webSocket.deserializeAttachment();
98
- this.webSocket.serializeAttachment(__spreadProps(__spreadValues({}, deserialized), { state }));
99
- }
100
- set user(user) {
101
- const deserialized = this.webSocket.deserializeAttachment();
102
- this.webSocket.serializeAttachment(__spreadProps(__spreadValues({}, deserialized), { user }));
103
- }
104
- constructor(webSocket, config) {
105
- const { room } = config;
106
- super(webSocket, config);
107
- const state = {
108
- presence: null,
109
- quit: false,
110
- room,
111
- timers: {
112
- ping: (/* @__PURE__ */ new Date()).getTime(),
113
- presence: null
114
- }
115
- };
116
- webSocket.serializeAttachment(__spreadValues({
117
- state
118
- }, webSocket.deserializeAttachment()));
119
- }
120
- addEventListener(type, handler) {
121
- this.webSocket.addEventListener(type, handler);
122
- }
123
- close(code, reason) {
124
- const canClose = [this.CONNECTING, this.OPEN].some(
125
- (readyState) => readyState === this.readyState
126
- );
127
- if (!canClose) return;
128
- this.webSocket.close(code, reason);
129
- }
130
- send(message) {
131
- if (this.readyState !== this.OPEN) return;
132
- this.webSocket.send(message);
133
- }
134
- terminate(code = 1011) {
135
- return this.webSocket.close(code, "Terminated");
136
- }
10
+ set presence(presence) {
11
+ const state = this.webSocket.deserializeAttachment().state;
12
+ this.webSocket.serializeAttachment({
13
+ ...this.webSocket.deserializeAttachment(),
14
+ state: {
15
+ ...state,
16
+ presence
17
+ }
18
+ });
19
+ }
20
+ get readyState() {
21
+ return this.webSocket.readyState;
22
+ }
23
+ get session() {
24
+ const deserialized = this.webSocket.deserializeAttachment();
25
+ const sessionId = deserialized.sessionId;
26
+ const state = this.state;
27
+ const user = deserialized.user ?? null;
28
+ return {
29
+ ...state,
30
+ id: sessionId,
31
+ user,
32
+ webSocket: this
33
+ };
34
+ }
35
+ get sessionId() {
36
+ const deserialized = this.webSocket.deserializeAttachment() ?? {};
37
+ const sessionId = deserialized.sessionId ?? `p_${crypto.randomUUID()}`;
38
+ if (typeof deserialized.sessionId !== "string") this.webSocket.serializeAttachment({
39
+ ...deserialized,
40
+ sessionId
41
+ });
42
+ return sessionId;
43
+ }
44
+ get state() {
45
+ const state = this.webSocket.deserializeAttachment()?.state ?? null;
46
+ if (!state) throw new Error("Could not get websocket state");
47
+ const currentPing = state.timers.ping;
48
+ const lastPing = this._platform.getLastPing(this);
49
+ if (!lastPing) return state;
50
+ if (currentPing >= lastPing) return state;
51
+ const newState = {
52
+ ...state,
53
+ timers: {
54
+ ...state.timers,
55
+ ping: lastPing
56
+ }
57
+ };
58
+ return this._platform.setSerializedState(this, newState);
59
+ }
60
+ set state(state) {
61
+ const deserialized = this.webSocket.deserializeAttachment();
62
+ this.webSocket.serializeAttachment({
63
+ ...deserialized,
64
+ state
65
+ });
66
+ }
67
+ set user(user) {
68
+ const deserialized = this.webSocket.deserializeAttachment();
69
+ this.webSocket.serializeAttachment({
70
+ ...deserialized,
71
+ user
72
+ });
73
+ }
74
+ constructor(webSocket, config) {
75
+ const { room } = config;
76
+ super(webSocket, config);
77
+ const state = {
78
+ presence: null,
79
+ quit: false,
80
+ room,
81
+ timers: {
82
+ ping: (/* @__PURE__ */ new Date()).getTime(),
83
+ presence: null
84
+ }
85
+ };
86
+ webSocket.serializeAttachment({
87
+ state,
88
+ ...webSocket.deserializeAttachment()
89
+ });
90
+ }
91
+ addEventListener(type, handler) {
92
+ this.webSocket.addEventListener(type, handler);
93
+ }
94
+ close(code, reason) {
95
+ if (![this.CONNECTING, this.OPEN].some((readyState) => readyState === this.readyState)) return;
96
+ this.webSocket.close(code, reason);
97
+ }
98
+ send(message) {
99
+ if (this.readyState !== this.OPEN) return;
100
+ this.webSocket.send(message);
101
+ }
102
+ terminate(code = 1011) {
103
+ return this.webSocket.close(code, "Terminated");
104
+ }
137
105
  };
138
106
 
139
- // src/constants.ts
140
- var DEFAULT_REGISTRATION_MODE = "detached";
107
+ //#endregion
108
+ //#region src/constants.ts
109
+ const DEFAULT_REGISTRATION_MODE = "detached";
141
110
 
142
- // src/CloudflarePlatform.ts
143
- var CloudflarePlatform = class _CloudflarePlatform extends AbstractPlatform {
144
- constructor(config) {
145
- var _a, _b;
146
- super(__spreadValues(__spreadValues({}, config), config.roomContext && config.mode === "detached" ? {
147
- persistence: (_a = config.persistence) != null ? _a : new PersistenceCloudflareTransactionalStorage({ mode: "sqlite" })
148
- } : {}));
149
- this.id = crypto.randomUUID();
150
- this._name = "platformCloudflare";
151
- this._config = {
152
- authorize: {
153
- secret: true
154
- },
155
- handleMode: "io",
156
- registrationMode: (_b = config.mode) != null ? _b : DEFAULT_REGISTRATION_MODE,
157
- requireAuth: false,
158
- listeners: {
159
- onRoomDeleted: true,
160
- onRoomMessage: true,
161
- onStorageUpdated: true,
162
- onUserConnected: true,
163
- onUserDisconnected: true
164
- },
165
- router: true
166
- };
167
- const detachedState = this._getDetachedState();
168
- if (!detachedState) return;
169
- detachedState.setWebSocketAutoResponse(
170
- new WebSocketRequestResponsePair(
171
- '{"type":"$ping","data":{}}',
172
- JSON.stringify({ type: "$pong", data: {} })
173
- )
174
- );
175
- }
176
- acceptWebSocket(webSocket) {
177
- return __async(this, null, function* () {
178
- const detachedState = this._getDetachedState();
179
- if (!detachedState) {
180
- webSocket.webSocket.accept();
181
- return;
182
- }
183
- detachedState.acceptWebSocket(webSocket.webSocket);
184
- });
185
- }
186
- convertWebSocket(webSocket, config) {
187
- const { room } = config;
188
- return new CloudflareWebSocket(webSocket, {
189
- persistence: this.persistence,
190
- platform: this,
191
- room
192
- });
193
- }
194
- getLastPing(webSocket) {
195
- var _a;
196
- const detachedState = this._getDetachedState();
197
- if (!detachedState) return null;
198
- const timestamp = detachedState.getWebSocketAutoResponseTimestamp(webSocket.webSocket);
199
- return (_a = timestamp == null ? void 0 : timestamp.getTime()) != null ? _a : null;
200
- }
201
- getSerializedState(webSocket) {
202
- var _a;
203
- const deserialized = webSocket.deserializeAttachment();
204
- return (_a = deserialized == null ? void 0 : deserialized.state) != null ? _a : null;
205
- }
206
- getSessionId(webSocket) {
207
- var _a;
208
- const deserialized = (_a = webSocket.deserializeAttachment()) != null ? _a : {};
209
- const sessionId = deserialized.sessionId;
210
- if (typeof sessionId !== "string") return null;
211
- return sessionId;
212
- }
213
- getWebSockets() {
214
- var _a;
215
- const detachedState = this._getDetachedState();
216
- if (!detachedState) return [];
217
- const webSockets = (_a = detachedState.getWebSockets()) != null ? _a : [];
218
- return webSockets;
219
- }
220
- initialize(config) {
221
- var _a;
222
- const ctx = (_a = config.roomContext) != null ? _a : __spreadValues({}, this._roomContext);
223
- if (!ctx.env || !ctx.state) throw new Error("Could not derive platform roomContext");
224
- const roomContext = {
225
- env: ctx.env,
226
- meta: ctx.meta,
227
- state: ctx.state
228
- };
229
- return new _CloudflarePlatform({
230
- roomContext,
231
- mode: this._config.registrationMode,
232
- persistence: this.persistence.initialize(roomContext),
233
- pubSub: this.pubSub
234
- })._initialize();
235
- }
236
- parseData(data) {
237
- if (typeof data === "string") return JSON.parse(data);
238
- const decoder = new TextDecoder("utf8");
239
- return JSON.parse(decoder.decode(data));
240
- }
241
- randomUUID() {
242
- return crypto.randomUUID();
243
- }
244
- setSerializedState(webSocket, state) {
245
- var _a;
246
- const deserialized = (_a = webSocket.webSocket.deserializeAttachment()) != null ? _a : {};
247
- webSocket.webSocket.serializeAttachment(__spreadProps(__spreadValues({}, deserialized), { state }));
248
- return state;
249
- }
250
- _getDetachedState() {
251
- var _a, _b;
252
- if (this._config.registrationMode !== "detached") return null;
253
- const detachedState = (_b = (_a = this._roomContext) == null ? void 0 : _a.state) != null ? _b : null;
254
- return detachedState;
255
- }
111
+ //#endregion
112
+ //#region src/CloudflarePlatform.ts
113
+ var CloudflarePlatform = class CloudflarePlatform extends AbstractPlatform {
114
+ id = crypto.randomUUID();
115
+ _config;
116
+ _name = "platformCloudflare";
117
+ constructor(config) {
118
+ super({
119
+ ...config,
120
+ ...config.roomContext && config.mode === "detached" ? { persistence: config.persistence ?? new PersistenceCloudflareTransactionalStorage({ mode: "sqlite" }) } : {}
121
+ });
122
+ this._config = {
123
+ authorize: { secret: true },
124
+ handleMode: "io",
125
+ registrationMode: config.mode ?? DEFAULT_REGISTRATION_MODE,
126
+ requireAuth: false,
127
+ listeners: {
128
+ onRoomDestroyed: true,
129
+ onRoomMessage: true,
130
+ onStorageDestroyed: true,
131
+ onStorageUpdated: true,
132
+ onUserConnected: true,
133
+ onUserDisconnected: true
134
+ },
135
+ router: true
136
+ };
137
+ const detachedState = this._getDetachedState();
138
+ if (!detachedState) return;
139
+ detachedState.setWebSocketAutoResponse(new WebSocketRequestResponsePair("{\"type\":\"$ping\",\"data\":{}}", JSON.stringify({
140
+ type: "$pong",
141
+ data: {}
142
+ })));
143
+ }
144
+ async acceptWebSocket(webSocket) {
145
+ const detachedState = this._getDetachedState();
146
+ if (!detachedState) {
147
+ webSocket.webSocket.accept();
148
+ return;
149
+ }
150
+ detachedState.acceptWebSocket(webSocket.webSocket);
151
+ }
152
+ convertWebSocket(webSocket, config) {
153
+ const { room } = config;
154
+ return new CloudflareWebSocket(webSocket, {
155
+ persistence: this.persistence,
156
+ platform: this,
157
+ room
158
+ });
159
+ }
160
+ getLastPing(webSocket) {
161
+ const detachedState = this._getDetachedState();
162
+ if (!detachedState) return null;
163
+ return detachedState.getWebSocketAutoResponseTimestamp(webSocket.webSocket)?.getTime() ?? null;
164
+ }
165
+ getSerializedState(webSocket) {
166
+ return webSocket.deserializeAttachment()?.state ?? null;
167
+ }
168
+ getSessionId(webSocket) {
169
+ const sessionId = (webSocket.deserializeAttachment() ?? {}).sessionId;
170
+ if (typeof sessionId !== "string") return null;
171
+ return sessionId;
172
+ }
173
+ getWebSockets() {
174
+ const detachedState = this._getDetachedState();
175
+ if (!detachedState) return [];
176
+ return detachedState.getWebSockets() ?? [];
177
+ }
178
+ initialize(config) {
179
+ const ctx = config.roomContext ?? { ...this._roomContext };
180
+ if (!ctx.env || !ctx.state) throw new Error("Could not derive platform roomContext");
181
+ const roomContext = {
182
+ env: ctx.env,
183
+ meta: ctx.meta,
184
+ state: ctx.state
185
+ };
186
+ return new CloudflarePlatform({
187
+ roomContext,
188
+ mode: this._config.registrationMode,
189
+ persistence: this.persistence.initialize(roomContext),
190
+ pubSub: this.pubSub
191
+ })._initialize();
192
+ }
193
+ parseData(data) {
194
+ if (typeof data === "string") return JSON.parse(data);
195
+ const decoder = new TextDecoder("utf8");
196
+ return JSON.parse(decoder.decode(data));
197
+ }
198
+ randomUUID() {
199
+ return crypto.randomUUID();
200
+ }
201
+ setSerializedState(webSocket, state) {
202
+ const deserialized = webSocket.webSocket.deserializeAttachment() ?? {};
203
+ webSocket.webSocket.serializeAttachment({
204
+ ...deserialized,
205
+ state
206
+ });
207
+ return state;
208
+ }
209
+ _getDetachedState() {
210
+ if (this._config.registrationMode !== "detached") return null;
211
+ return this._roomContext?.state ?? null;
212
+ }
256
213
  };
257
214
 
258
- // src/platformCloudflare.ts
259
- var platformCloudflare = (config = {}) => {
260
- const { authorize, context, crdt, debug, limits } = config;
261
- return {
262
- authorize,
263
- context,
264
- crdt,
265
- debug,
266
- limits,
267
- platform: () => new CloudflarePlatform(config)
268
- };
269
- };
270
- export {
271
- infer,
272
- platformCloudflare
215
+ //#endregion
216
+ //#region src/platformCloudflare.ts
217
+ const platformCloudflare = (config = {}) => {
218
+ const { authorize, context, crdt, debug, limits } = config;
219
+ return {
220
+ authorize,
221
+ context,
222
+ crdt,
223
+ debug,
224
+ limits,
225
+ platform: () => new CloudflarePlatform(config)
226
+ };
273
227
  };
228
+
229
+ //#endregion
230
+ export { infer, platformCloudflare };
231
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/infer.ts","../src/CloudflareWebSocket.ts","../src/constants.ts","../src/CloudflarePlatform.ts","../src/platformCloudflare.ts"],"sourcesContent":["import type { Json } from \"@pluv/types\";\nimport type { identity } from \"./utils\";\n\nexport type InferCallback<\n TEnv extends Record<string, any> = {},\n TMeta extends Record<string, Json> = {},\n> = (i: typeof identity) => {\n env?: (io: TEnv) => TEnv;\n meta?: (io: TMeta) => TMeta;\n};\n\nexport const infer = <\n TEnv extends Record<string, any> = {},\n TMeta extends Record<string, Json> = {},\n>(\n callback: InferCallback<TEnv, TMeta>,\n) => callback;\n","import type {\n AbstractEventMap,\n AbstractListener,\n AbstractWebSocketConfig,\n WebSocketSerializedState,\n WebSocketSession,\n} from \"@pluv/io\";\nimport { AbstractWebSocket } from \"@pluv/io\";\nimport type { InferIOAuthorizeUser, IOAuthorize, JsonObject } from \"@pluv/types\";\n\nexport interface CloudflareWebSocketEventMap {\n close: CloseEvent;\n message: MessageEvent;\n open: Event;\n error: ErrorEvent;\n}\n\nexport type CloudflareWebSocketConfig = AbstractWebSocketConfig;\n\nexport class CloudflareWebSocket<\n TAuthorize extends IOAuthorize<any, any> | null = null,\n> extends AbstractWebSocket<WebSocket, TAuthorize> {\n public set presence(presence: JsonObject | null) {\n const deserialized = this.webSocket.deserializeAttachment();\n const state = deserialized.state;\n\n this.webSocket.serializeAttachment({\n ...this.webSocket.deserializeAttachment(),\n state: { ...state, presence },\n });\n }\n\n public get readyState(): 0 | 1 | 2 | 3 {\n return this.webSocket.readyState as 0 | 1 | 2 | 3;\n }\n\n public get session(): WebSocketSession<TAuthorize> {\n const deserialized = this.webSocket.deserializeAttachment();\n const sessionId = deserialized.sessionId as string;\n const state = this.state;\n const user = (deserialized.user ?? null) as InferIOAuthorizeUser<TAuthorize>;\n\n return {\n ...state,\n id: sessionId,\n user,\n webSocket: this,\n };\n }\n\n public get sessionId(): string {\n const deserialized = this.webSocket.deserializeAttachment() ?? {};\n const sessionId = deserialized.sessionId ?? `p_${crypto.randomUUID()}`;\n\n if (typeof deserialized.sessionId !== \"string\") {\n this.webSocket.serializeAttachment({ ...deserialized, sessionId });\n }\n\n return sessionId;\n }\n\n public get state(): WebSocketSerializedState {\n const deserialized = this.webSocket.deserializeAttachment();\n const state = deserialized?.state ?? null;\n\n if (!state) throw new Error(\"Could not get websocket state\");\n\n const currentPing = state.timers.ping;\n const lastPing = this._platform.getLastPing(this);\n\n if (!lastPing) return state;\n if (currentPing >= lastPing) return state;\n\n const newState: WebSocketSerializedState = {\n ...state,\n timers: { ...state.timers, ping: lastPing },\n };\n\n return this._platform.setSerializedState(this, newState);\n }\n\n public set state(state: WebSocketSerializedState) {\n const deserialized = this.webSocket.deserializeAttachment();\n\n this.webSocket.serializeAttachment({ ...deserialized, state });\n }\n\n public set user(user: InferIOAuthorizeUser<TAuthorize>) {\n const deserialized = this.webSocket.deserializeAttachment();\n\n this.webSocket.serializeAttachment({ ...deserialized, user });\n }\n\n constructor(webSocket: WebSocket, config: CloudflareWebSocketConfig) {\n const { room } = config;\n\n super(webSocket, config);\n\n const state: WebSocketSerializedState = {\n presence: null,\n quit: false,\n room,\n timers: {\n ping: new Date().getTime(),\n presence: null,\n },\n };\n\n webSocket.serializeAttachment({\n state,\n ...webSocket.deserializeAttachment(),\n });\n }\n\n public addEventListener<TType extends keyof AbstractEventMap>(\n type: TType,\n handler: AbstractListener<TType>,\n ) {\n this.webSocket.addEventListener(type, handler as any);\n }\n\n public close(code?: number | undefined, reason?: string | undefined): void {\n const canClose = [this.CONNECTING, this.OPEN].some(\n (readyState) => readyState === this.readyState,\n );\n\n if (!canClose) return;\n\n this.webSocket.close(code, reason);\n }\n\n public send(message: string | ArrayBuffer | ArrayBufferView): void {\n if (this.readyState !== this.OPEN) return;\n\n this.webSocket.send(message);\n }\n\n public terminate(code: number = 1011): void {\n return this.webSocket.close(code, \"Terminated\");\n }\n}\n","import type { WebSocketRegistrationMode } from \"@pluv/io\";\n\nexport const DEFAULT_REGISTRATION_MODE: WebSocketRegistrationMode = \"detached\";\nexport const GARBAGE_COLLECT_INTERVAL_MS = 60_000;\n","import type {\n AbstractPlatformConfig,\n ConvertWebSocketConfig,\n WebSocketRegistrationMode,\n WebSocketSerializedState,\n} from \"@pluv/io\";\nimport { AbstractPlatform } from \"@pluv/io\";\nimport { PersistenceCloudflareTransactionalStorage } from \"@pluv/persistence-cloudflare-transactional-storage\";\nimport type { IOAuthorize, Json } from \"@pluv/types\";\nimport { CloudflareWebSocket } from \"./CloudflareWebSocket\";\nimport { DEFAULT_REGISTRATION_MODE } from \"./constants\";\n\nexport type CloudflarePlatformRoomContext<\n TEnv extends Record<string, any>,\n TMeta extends Record<string, Json>,\n> = {\n env: TEnv;\n state: DurableObjectState;\n} & (keyof TMeta extends never ? { meta?: undefined } : { meta: TMeta });\n\nexport type CloudflarePlatformConfig<\n TEnv extends Record<string, any> = {},\n TMeta extends Record<string, Json> = {},\n> = AbstractPlatformConfig<CloudflarePlatformRoomContext<TEnv, TMeta>> & {\n mode?: WebSocketRegistrationMode;\n};\n\nexport class CloudflarePlatform<\n TAuthorize extends IOAuthorize<any, any> | null = null,\n TEnv extends Record<string, any> = {},\n TMeta extends Record<string, Json> = {},\n> extends AbstractPlatform<\n CloudflareWebSocket<TAuthorize>,\n { env: TEnv; request: Request },\n CloudflarePlatformRoomContext<TEnv, TMeta>,\n {\n authorize: {\n secret: true;\n };\n handleMode: \"io\";\n requireAuth: false;\n registrationMode: WebSocketRegistrationMode;\n listeners: {\n onRoomDestroyed: true;\n onRoomMessage: true;\n onStorageDestroyed: true;\n onStorageUpdated: true;\n onUserConnected: true;\n onUserDisconnected: true;\n };\n router: true;\n }\n> {\n public readonly id = crypto.randomUUID();\n public readonly _config;\n public readonly _name = \"platformCloudflare\";\n\n constructor(config: CloudflarePlatformConfig<TEnv, TMeta>) {\n super({\n ...config,\n ...(config.roomContext && config.mode === \"detached\"\n ? {\n persistence:\n config.persistence ??\n new PersistenceCloudflareTransactionalStorage({ mode: \"sqlite\" }),\n }\n : {}),\n });\n\n this._config = {\n authorize: {\n secret: true as const,\n },\n handleMode: \"io\" as const,\n registrationMode: config.mode ?? DEFAULT_REGISTRATION_MODE,\n requireAuth: false as const,\n listeners: {\n onRoomDestroyed: true as const,\n onRoomMessage: true as const,\n onStorageDestroyed: true as const,\n onStorageUpdated: true as const,\n onUserConnected: true as const,\n onUserDisconnected: true as const,\n },\n router: true as const,\n };\n\n const detachedState = this._getDetachedState();\n\n if (!detachedState) return;\n\n detachedState.setWebSocketAutoResponse(\n new WebSocketRequestResponsePair(\n '{\"type\":\"$ping\",\"data\":{}}',\n JSON.stringify({ type: \"$pong\", data: {} }),\n ),\n );\n }\n\n public async acceptWebSocket(webSocket: CloudflareWebSocket<TAuthorize>): Promise<void> {\n const detachedState = this._getDetachedState();\n\n if (!detachedState) {\n webSocket.webSocket.accept();\n\n return;\n }\n\n detachedState.acceptWebSocket(webSocket.webSocket);\n }\n\n public convertWebSocket(\n webSocket: WebSocket,\n config: ConvertWebSocketConfig,\n ): CloudflareWebSocket<TAuthorize> {\n const { room } = config;\n\n return new CloudflareWebSocket<TAuthorize>(webSocket, {\n persistence: this.persistence,\n platform: this,\n room,\n });\n }\n\n public getLastPing(webSocket: CloudflareWebSocket<TAuthorize>): number | null {\n const detachedState = this._getDetachedState();\n\n if (!detachedState) return null;\n\n const timestamp = detachedState.getWebSocketAutoResponseTimestamp(webSocket.webSocket);\n\n return timestamp?.getTime() ?? null;\n }\n\n public getSerializedState(webSocket: WebSocket): WebSocketSerializedState | null {\n const deserialized = webSocket.deserializeAttachment();\n\n return deserialized?.state ?? null;\n }\n\n public getSessionId(webSocket: WebSocket): string | null {\n const deserialized = webSocket.deserializeAttachment() ?? {};\n const sessionId = deserialized.sessionId;\n\n if (typeof sessionId !== \"string\") return null;\n\n return sessionId;\n }\n\n public getWebSockets(): readonly WebSocket[] {\n const detachedState = this._getDetachedState();\n\n if (!detachedState) return [];\n\n const webSockets = detachedState.getWebSockets() ?? [];\n\n return webSockets;\n }\n\n public initialize(\n config: AbstractPlatformConfig<CloudflarePlatformRoomContext<TEnv, TMeta>>,\n ): this {\n const ctx = config.roomContext ?? { ...this._roomContext };\n\n if (!ctx.env || !ctx.state) throw new Error(\"Could not derive platform roomContext\");\n\n const roomContext = {\n env: ctx.env,\n meta: ctx.meta,\n state: ctx.state,\n } as CloudflarePlatformRoomContext<TEnv, TMeta>;\n\n return new CloudflarePlatform<TAuthorize, TEnv, TMeta>({\n roomContext,\n mode: this._config.registrationMode,\n persistence: this.persistence.initialize(roomContext),\n pubSub: this.pubSub,\n })._initialize() as this;\n }\n\n public parseData(data: string | ArrayBuffer): Record<string, any> {\n if (typeof data === \"string\") return JSON.parse(data);\n\n const decoder = new TextDecoder(\"utf8\");\n\n return JSON.parse(decoder.decode(data));\n }\n\n public randomUUID(): string {\n return crypto.randomUUID();\n }\n\n public setSerializedState(\n webSocket: CloudflareWebSocket<TAuthorize>,\n state: WebSocketSerializedState,\n ): WebSocketSerializedState {\n const deserialized = webSocket.webSocket.deserializeAttachment() ?? {};\n\n webSocket.webSocket.serializeAttachment({ ...deserialized, state });\n\n return state;\n }\n\n private _getDetachedState(): DurableObjectState | null {\n if (this._config.registrationMode !== \"detached\") return null;\n\n const detachedState = this._roomContext?.state ?? null;\n\n return detachedState;\n }\n}\n","import type { CrdtLibraryType, NoopCrdtDocFactory } from \"@pluv/crdt\";\nimport type { CreateIOParams, InferInitContextType, PluvContext, PluvIOAuthorize } from \"@pluv/io\";\nimport type { BaseUser, Id, IOAuthorize, Json } from \"@pluv/types\";\nimport type { CloudflarePlatformConfig } from \"./CloudflarePlatform\";\nimport { CloudflarePlatform } from \"./CloudflarePlatform\";\nimport type { InferCallback } from \"./infer\";\n\nexport type PlatformCloudflareCreateIOParams<\n TEnv extends Record<string, any> = {},\n TMeta extends Record<string, Json> = {},\n TContext extends Record<string, any> = {},\n TUser extends BaseUser | null = null,\n TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>,\n> = Id<\n CloudflarePlatformConfig<TEnv, TMeta> &\n Omit<\n CreateIOParams<\n CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>,\n TContext,\n TUser,\n TCrdt\n >,\n \"authorize\" | \"context\" | \"platform\"\n > & {\n authorize?: PluvIOAuthorize<\n CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>,\n TUser,\n InferInitContextType<CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>>\n >;\n context?: PluvContext<\n CloudflarePlatform<IOAuthorize<TUser, any>, TEnv, TMeta>,\n TContext\n >;\n types?: InferCallback<TEnv, TMeta>;\n }\n>;\n\nexport const platformCloudflare = <\n TEnv extends Record<string, any> = {},\n TMeta extends Record<string, Json> = {},\n TContext extends Record<string, any> = {},\n TUser extends BaseUser | null = null,\n TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>,\n>(\n config: PlatformCloudflareCreateIOParams<TEnv, TMeta, TContext, TUser, TCrdt> = {},\n): CreateIOParams<\n CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>,\n TContext,\n TUser,\n TCrdt\n> => {\n const { authorize, context, crdt, debug, limits } = config;\n\n return {\n authorize,\n context,\n crdt,\n debug,\n limits,\n platform: () => new CloudflarePlatform<IOAuthorize<TUser, TContext>, TEnv, TMeta>(config),\n };\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/platform-cloudflare",
3
- "version": "3.2.1",
3
+ "version": "4.0.0",
4
4
  "description": "@pluv/io adapter for cloudflare workers",
5
5
  "author": {
6
6
  "email": "david@pluv.io",
@@ -14,30 +14,35 @@
14
14
  "url": "git+https://github.com/pluv-io/pluv.git",
15
15
  "directory": "packages/platform-cloudflare"
16
16
  },
17
- "module": "./dist/index.mjs",
17
+ "type": "module",
18
18
  "types": "./dist/index.d.mts",
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
22
  "dependencies": {
23
- "path-to-regexp": "^8.2.0",
24
- "@pluv/crdt": "^3.2.1",
25
- "@pluv/io": "^3.2.1",
26
- "@pluv/persistence-cloudflare-transactional-storage": "^3.2.1",
27
- "@pluv/types": "^3.2.1"
23
+ "path-to-regexp": "^8.3.0",
24
+ "@pluv/crdt": "^4.0.0",
25
+ "@pluv/io": "^4.0.0",
26
+ "@pluv/persistence-cloudflare-transactional-storage": "^4.0.0",
27
+ "@pluv/types": "^4.0.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@cloudflare/workers-types": "^4.20250715.0",
31
- "eslint": "^9.31.0",
32
- "tsup": "^8.5.0",
33
- "typescript": "^5.8.3",
34
- "@pluv/tsconfig": "^3.2.1",
35
- "eslint-config-pluv": "^3.2.1"
30
+ "@cloudflare/workers-types": "^4.20260120.0",
31
+ "eslint": "^9.39.2",
32
+ "tsdown": "0.20.0-beta.4",
33
+ "typescript": "^5.9.3",
34
+ "@pluv/tsconfig": "^4.0.0",
35
+ "eslint-config-pluv": "^4.0.0"
36
+ },
37
+ "exports": {
38
+ ".": "./dist/index.mjs",
39
+ "./*": "./*"
36
40
  },
37
41
  "scripts": {
38
- "build": "tsup src/index.ts",
39
- "dev": "tsup src/index.ts --format esm,cjs --watch --dts",
42
+ "build": "tsdown",
43
+ "dev": "tsdown --watch",
40
44
  "lint": "eslint \"src/**/*.ts*\" --fix --max-warnings 0",
45
+ "typecheck": "tsc --noEmit",
41
46
  "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
42
47
  }
43
48
  }
@@ -41,8 +41,9 @@ export class CloudflarePlatform<
41
41
  requireAuth: false;
42
42
  registrationMode: WebSocketRegistrationMode;
43
43
  listeners: {
44
- onRoomDeleted: true;
44
+ onRoomDestroyed: true;
45
45
  onRoomMessage: true;
46
+ onStorageDestroyed: true;
46
47
  onStorageUpdated: true;
47
48
  onUserConnected: true;
48
49
  onUserDisconnected: true;
@@ -74,8 +75,9 @@ export class CloudflarePlatform<
74
75
  registrationMode: config.mode ?? DEFAULT_REGISTRATION_MODE,
75
76
  requireAuth: false as const,
76
77
  listeners: {
77
- onRoomDeleted: true as const,
78
+ onRoomDestroyed: true as const,
78
79
  onRoomMessage: true as const,
80
+ onStorageDestroyed: true as const,
79
81
  onStorageUpdated: true as const,
80
82
  onUserConnected: true as const,
81
83
  onUserDisconnected: true as const,
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from "tsdown";
2
+
3
+ export default defineConfig({
4
+ format: ["esm"],
5
+ dts: true,
6
+ outDir: "dist",
7
+ entry: "src/index.ts",
8
+ target: "esnext",
9
+ sourcemap: true,
10
+ clean: true,
11
+ external: ["cloudflare:workers"],
12
+ exports: {
13
+ all: true,
14
+ },
15
+ });
package/tsup.config.ts DELETED
@@ -1,8 +0,0 @@
1
- import { defineConfig } from "tsup";
2
-
3
- export default defineConfig({
4
- dts: true,
5
- entry: ["src/index.ts"],
6
- external: ["cloudflare:workers"],
7
- format: ["esm"],
8
- });