@pluv/platform-cloudflare 0.19.0 → 0.21.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 +15 -15
- package/CHANGELOG.md +85 -0
- package/README.md +0 -50
- package/dist/index.d.mts +32 -10
- package/dist/index.d.ts +32 -10
- package/dist/index.js +238 -19
- package/dist/index.mjs +239 -18
- package/package.json +9 -9
- package/src/CloudflarePlatform.ts +114 -4
- package/src/CloudflareWebSocket.ts +48 -13
- package/src/PersistanceCloudflare.ts +100 -0
- package/src/constants.ts +3 -0
- package/src/createPluvHandler.ts +26 -12
- package/src/index.ts +2 -1
- package/src/platformCloudflare.ts +3 -2
- package/src/utils/index.ts +1 -0
- package/src/utils/partitionByLength.ts +8 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/platform-cloudflare@0.
|
|
2
|
+
> @pluv/platform-cloudflare@0.21.0 build /home/runner/work/pluv/pluv/packages/platform-cloudflare
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --dts
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
6
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
+
[34mCLI[39m tsup v8.2.4
|
|
8
|
+
[34mCLI[39m Target: es6
|
|
9
|
+
[34mESM[39m Build start
|
|
10
|
+
[34mCJS[39m Build start
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m15.00 KB[39m
|
|
12
|
+
[32mCJS[39m ⚡️ Build success in 80ms
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m13.96 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 85ms
|
|
15
|
+
[34mDTS[39m Build start
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 2845ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m4.11 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m4.11 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,90 @@
|
|
|
1
1
|
# @pluv/platform-cloudflare
|
|
2
2
|
|
|
3
|
+
## 0.21.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 307bd44: `@pluv/platform-cloudflare` now supports Cloudflare Worker's WebSocket Hibernation API, and usees it by default.
|
|
8
|
+
|
|
9
|
+
To switch back to not using the WebSocket Hibernation API, specify a `mode` of `attached`.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// With event-listeners directly attached to the websocket on registration (i.e. non-hibernation)
|
|
13
|
+
createIO({
|
|
14
|
+
platform: platformCloudflare({
|
|
15
|
+
mode: "attached",
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// With event listeners unattached to the websocket during registration (i.e. hibernation)
|
|
20
|
+
createIO({
|
|
21
|
+
platform: platformCloudflare({
|
|
22
|
+
mode: "detached",
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- 41b15e4: **BREAKING** - Updated `sessions` type in the procedure context from `Map<string, WebSocketSession>` to `readonly WebSocketSession[]`.
|
|
28
|
+
- f570c8a: **BREAKING**: The original request object is no longer available in the context of any event resolvers.
|
|
29
|
+
|
|
30
|
+
Previously, the request object that was passed into `PluvServer.getRoom` would be made available on the context object of each of the resolvers. This is no-longer a part of the event context, and therefore needs to be omitted from calls to `PluvServer.getRoom`.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// Before
|
|
34
|
+
|
|
35
|
+
// With platform-node
|
|
36
|
+
ioServer.getRoom(websocket, { req, token });
|
|
37
|
+
|
|
38
|
+
// With platform-cloudflare
|
|
39
|
+
ioServer.getRoom(websocket, { env, req, token });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// Now
|
|
44
|
+
|
|
45
|
+
// With platform-node
|
|
46
|
+
ioServer.getRoom(websocket, { req });
|
|
47
|
+
|
|
48
|
+
// With platform-cloudflare
|
|
49
|
+
ioServer.getRoom(websocket, { env, req });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- b98ab6b: Internal updates to platforms (i.e. `@pluv/platform-cloudflare` and `@pluv/platform-node`) to be able to support Cloudflare Worker Websocket Hibernation APIs.
|
|
53
|
+
- 4c2228d: **BREAKING**: Require `DurableObjectState` in `ioServer.getRoom`.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
// Before
|
|
57
|
+
|
|
58
|
+
// With platform-cloudflare
|
|
59
|
+
ioServer.getRoom(websocket, { env, req });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
// Now
|
|
64
|
+
|
|
65
|
+
// With platform-cloudflare
|
|
66
|
+
ioServer.getRoom(websocket, { env, req, state });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Patch Changes
|
|
70
|
+
|
|
71
|
+
- cc2613e: Moved `sessionId` from being derived in `IORoom` to being derived as a getter in `AbstractWebsocket`.
|
|
72
|
+
- Updated dependencies [307bd44]
|
|
73
|
+
- Updated dependencies [41b15e4]
|
|
74
|
+
- Updated dependencies [f570c8a]
|
|
75
|
+
- Updated dependencies [b98ab6b]
|
|
76
|
+
- Updated dependencies [4c2228d]
|
|
77
|
+
- Updated dependencies [cc2613e]
|
|
78
|
+
- @pluv/io@0.21.0
|
|
79
|
+
- @pluv/types@0.21.0
|
|
80
|
+
|
|
81
|
+
## 0.20.0
|
|
82
|
+
|
|
83
|
+
### Patch Changes
|
|
84
|
+
|
|
85
|
+
- @pluv/io@0.20.0
|
|
86
|
+
- @pluv/types@0.20.0
|
|
87
|
+
|
|
3
88
|
## 0.19.0
|
|
4
89
|
|
|
5
90
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,30 +1,3 @@
|
|
|
1
|
-
> **Disclaimer:**
|
|
2
|
-
> This package is currently in preview and may have breaking changes between versions. Please wait for a `v1.0.0` stable release before using this in production.
|
|
3
|
-
|
|
4
|
-
<h1 align="center">
|
|
5
|
-
<br />
|
|
6
|
-
<img src="https://github.com/pluv-io/pluv/blob/master/assets/pluv-icon-192x192.png?raw=true" alt="Pluv.IO" width="180" style="border-radius:16px" />
|
|
7
|
-
<br />
|
|
8
|
-
<a href="https://pluv.io/docs/introduction">Pluv.IO (preview)</a>
|
|
9
|
-
<br />
|
|
10
|
-
</h1>
|
|
11
|
-
|
|
12
|
-
<h3 align="center">Multi-platform, E2E type-safe realtime packages</h3>
|
|
13
|
-
<h4 align="center">💕 Inspired by <a href="https://trpc.io">trpc</a> 💕 <a href="https://docs.yjs.dev/">yjs</a> 💕 and <a href="https://developers.cloudflare.com/">Cloudflare</a> 💕 </h4>
|
|
14
|
-
|
|
15
|
-
<p align="center">
|
|
16
|
-
<a href="https://www.npmjs.com/package/@pluv/platform-cloudflare">
|
|
17
|
-
<img src="https://img.shields.io/npm/v/@pluv/platform-cloudflare" alt="npm @pluv/platform-cloudflare" />
|
|
18
|
-
</a>
|
|
19
|
-
<a href="https://github.com/pluv-io/pluv/blob/master/LICENSE">
|
|
20
|
-
<img alt="GitHub" src="https://img.shields.io/github/license/pluv-io/pluv" alt="License MIT" />
|
|
21
|
-
</a>
|
|
22
|
-
<a href="https://commitizen.github.io/cz-cli/">
|
|
23
|
-
<img src="https://img.shields.io/badge/commitizen-friendly-brightgreen.svg" alt="Commitizen friendly" />
|
|
24
|
-
</a>
|
|
25
|
-
<img src="https://badgen.net/badge/-/TypeScript?icon=typescript&label&labelColor=blue&color=555555" alt="TypeScript" />
|
|
26
|
-
</p>
|
|
27
|
-
|
|
28
1
|
## `@pluv/platform-cloudflare`
|
|
29
2
|
|
|
30
3
|
> Enables [@pluv/io](https://www.npmjs.com/package/@pluv/io) to run on [Cloudflare Workers](https://workers.cloudflare.com/).
|
|
@@ -43,26 +16,3 @@ yarn add @pluv/platform-cloudflare
|
|
|
43
16
|
# pnpm
|
|
44
17
|
pnpm add @pluv/platform-cloudflare
|
|
45
18
|
```
|
|
46
|
-
|
|
47
|
-
## Basic Example
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
import { createIO } from "@pluv/io";
|
|
51
|
-
import { platformCloudflare } from "@pluv/platform-cloudflare";
|
|
52
|
-
|
|
53
|
-
export const io = createIO({ platform: platformCloudflare() });
|
|
54
|
-
export const ioServer = io.server();
|
|
55
|
-
|
|
56
|
-
/* Somewhere in a Cloudflare worker durable object */
|
|
57
|
-
const { 0: client, 1: server } = new WebSocketPair();
|
|
58
|
-
|
|
59
|
-
const room = ioServer.getRoom(state.id.toString(), { env });
|
|
60
|
-
|
|
61
|
-
await room.register(server);
|
|
62
|
-
|
|
63
|
-
return new Response(null, { status: 101, webSocket: client });
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Reference
|
|
67
|
-
|
|
68
|
-
Check us out on [GitHub](https://github.com/pluv-io/pluv) for more information on how to use `@pluv/io`.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,26 +1,48 @@
|
|
|
1
|
-
import { AbstractWebSocket, AbstractEventMap, AbstractListener, AbstractWebSocketConfig, AbstractPlatform, ConvertWebSocketConfig, PluvServer } from '@pluv/io';
|
|
2
|
-
import { MaybePromise, Maybe, InferIOAuthorizeUser, InferIOAuthorize, InferIOAuthorizeRequired, Id } from '@pluv/types';
|
|
1
|
+
import { AbstractWebSocket, WebSocketSerializedState, AbstractEventMap, AbstractListener, AbstractWebSocketConfig, AbstractPlatformConfig, WebSocketRegistrationMode, AbstractPlatform, ConvertWebSocketConfig, PluvServer } from '@pluv/io';
|
|
2
|
+
import { JsonObject, MaybePromise, Maybe, InferIOAuthorizeUser, InferIOAuthorize, InferIOAuthorizeRequired, Id } from '@pluv/types';
|
|
3
3
|
|
|
4
4
|
type CloudflareWebSocketConfig = AbstractWebSocketConfig;
|
|
5
|
-
declare class CloudflareWebSocket extends AbstractWebSocket {
|
|
6
|
-
|
|
5
|
+
declare class CloudflareWebSocket extends AbstractWebSocket<WebSocket> {
|
|
6
|
+
set presence(presence: JsonObject | null);
|
|
7
7
|
get readyState(): 0 | 1 | 2 | 3;
|
|
8
|
+
get sessionId(): string;
|
|
9
|
+
get state(): WebSocketSerializedState;
|
|
8
10
|
constructor(webSocket: WebSocket, config: CloudflareWebSocketConfig);
|
|
9
11
|
addEventListener<TType extends keyof AbstractEventMap>(type: TType, handler: AbstractListener<TType>): void;
|
|
10
12
|
close(code?: number | undefined, reason?: string | undefined): void;
|
|
11
|
-
initialize(): Promise<() => undefined>;
|
|
12
13
|
send(message: string | ArrayBuffer | ArrayBufferView): void;
|
|
13
14
|
terminate(): void;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
type CloudflarePlatformConfig<TEnv extends Record<string, any> = {}> = AbstractPlatformConfig<{
|
|
17
18
|
env: TEnv;
|
|
18
19
|
}, {
|
|
19
|
-
|
|
20
|
+
state: DurableObjectState;
|
|
21
|
+
}> & {
|
|
22
|
+
mode?: WebSocketRegistrationMode;
|
|
23
|
+
};
|
|
24
|
+
declare class CloudflarePlatform<TEnv extends Record<string, any> = {}> extends AbstractPlatform<CloudflareWebSocket, {
|
|
25
|
+
env: TEnv;
|
|
26
|
+
}, {
|
|
27
|
+
state: DurableObjectState;
|
|
20
28
|
}> {
|
|
29
|
+
readonly _registrationMode: WebSocketRegistrationMode;
|
|
30
|
+
constructor(config?: CloudflarePlatformConfig<TEnv>);
|
|
31
|
+
acceptWebSocket(webSocket: CloudflareWebSocket): Promise<void>;
|
|
21
32
|
convertWebSocket(webSocket: WebSocket, config: ConvertWebSocketConfig): CloudflareWebSocket;
|
|
33
|
+
getLastPing(webSocket: CloudflareWebSocket): number | null;
|
|
34
|
+
getSerializedState(webSocket: CloudflareWebSocket): WebSocketSerializedState | null;
|
|
35
|
+
getSessionId(webSocket: WebSocket): string | null;
|
|
36
|
+
getWebSockets(): readonly WebSocket[];
|
|
37
|
+
initialize(config: AbstractPlatformConfig<{
|
|
38
|
+
env: TEnv;
|
|
39
|
+
}, {
|
|
40
|
+
state: DurableObjectState;
|
|
41
|
+
}>): this;
|
|
22
42
|
parseData(data: string | ArrayBuffer): Record<string, any>;
|
|
23
43
|
randomUUID(): string;
|
|
44
|
+
setSerializedState(webSocket: CloudflareWebSocket, state: WebSocketSerializedState): void;
|
|
45
|
+
private _getDetachedState;
|
|
24
46
|
}
|
|
25
47
|
|
|
26
48
|
interface AuthorizeFunctionContext {
|
|
@@ -47,8 +69,8 @@ interface CreatePluvHandlerResult<TEnv extends Record<string, any> = {}> {
|
|
|
47
69
|
handler: ExportedHandler<TEnv>;
|
|
48
70
|
}
|
|
49
71
|
type InferCloudflarePluvHandlerEnv<TPluvServer extends PluvServer<CloudflarePlatform, any, any, any>> = TPluvServer extends PluvServer<CloudflarePlatform<infer IEnv>, any, any, any> ? IEnv : {};
|
|
50
|
-
declare const createPluvHandler: <TPluvServer extends PluvServer<CloudflarePlatform
|
|
72
|
+
declare const createPluvHandler: <TPluvServer extends PluvServer<CloudflarePlatform, any, any, any>>(config: CreatePluvHandlerConfig<TPluvServer, Id<InferCloudflarePluvHandlerEnv<TPluvServer>>>) => CreatePluvHandlerResult<Id<InferCloudflarePluvHandlerEnv<TPluvServer>>>;
|
|
51
73
|
|
|
52
|
-
declare const platformCloudflare: <TEnv extends Record<string, any> = {}>() => CloudflarePlatform<TEnv>;
|
|
74
|
+
declare const platformCloudflare: <TEnv extends Record<string, any> = {}>(config?: CloudflarePlatformConfig<TEnv>) => CloudflarePlatform<TEnv>;
|
|
53
75
|
|
|
54
|
-
export { type AuthorizeFunction, type AuthorizeFunctionContext, type CreatePluvHandlerConfig, type CreatePluvHandlerResult, type PluvHandlerFetch, createPluvHandler, platformCloudflare };
|
|
76
|
+
export { type AuthorizeFunction, type AuthorizeFunctionContext, type CloudflarePlatformConfig, type CreatePluvHandlerConfig, type CreatePluvHandlerResult, type PluvHandlerFetch, createPluvHandler, platformCloudflare };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,26 +1,48 @@
|
|
|
1
|
-
import { AbstractWebSocket, AbstractEventMap, AbstractListener, AbstractWebSocketConfig, AbstractPlatform, ConvertWebSocketConfig, PluvServer } from '@pluv/io';
|
|
2
|
-
import { MaybePromise, Maybe, InferIOAuthorizeUser, InferIOAuthorize, InferIOAuthorizeRequired, Id } from '@pluv/types';
|
|
1
|
+
import { AbstractWebSocket, WebSocketSerializedState, AbstractEventMap, AbstractListener, AbstractWebSocketConfig, AbstractPlatformConfig, WebSocketRegistrationMode, AbstractPlatform, ConvertWebSocketConfig, PluvServer } from '@pluv/io';
|
|
2
|
+
import { JsonObject, MaybePromise, Maybe, InferIOAuthorizeUser, InferIOAuthorize, InferIOAuthorizeRequired, Id } from '@pluv/types';
|
|
3
3
|
|
|
4
4
|
type CloudflareWebSocketConfig = AbstractWebSocketConfig;
|
|
5
|
-
declare class CloudflareWebSocket extends AbstractWebSocket {
|
|
6
|
-
|
|
5
|
+
declare class CloudflareWebSocket extends AbstractWebSocket<WebSocket> {
|
|
6
|
+
set presence(presence: JsonObject | null);
|
|
7
7
|
get readyState(): 0 | 1 | 2 | 3;
|
|
8
|
+
get sessionId(): string;
|
|
9
|
+
get state(): WebSocketSerializedState;
|
|
8
10
|
constructor(webSocket: WebSocket, config: CloudflareWebSocketConfig);
|
|
9
11
|
addEventListener<TType extends keyof AbstractEventMap>(type: TType, handler: AbstractListener<TType>): void;
|
|
10
12
|
close(code?: number | undefined, reason?: string | undefined): void;
|
|
11
|
-
initialize(): Promise<() => undefined>;
|
|
12
13
|
send(message: string | ArrayBuffer | ArrayBufferView): void;
|
|
13
14
|
terminate(): void;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
type CloudflarePlatformConfig<TEnv extends Record<string, any> = {}> = AbstractPlatformConfig<{
|
|
17
18
|
env: TEnv;
|
|
18
19
|
}, {
|
|
19
|
-
|
|
20
|
+
state: DurableObjectState;
|
|
21
|
+
}> & {
|
|
22
|
+
mode?: WebSocketRegistrationMode;
|
|
23
|
+
};
|
|
24
|
+
declare class CloudflarePlatform<TEnv extends Record<string, any> = {}> extends AbstractPlatform<CloudflareWebSocket, {
|
|
25
|
+
env: TEnv;
|
|
26
|
+
}, {
|
|
27
|
+
state: DurableObjectState;
|
|
20
28
|
}> {
|
|
29
|
+
readonly _registrationMode: WebSocketRegistrationMode;
|
|
30
|
+
constructor(config?: CloudflarePlatformConfig<TEnv>);
|
|
31
|
+
acceptWebSocket(webSocket: CloudflareWebSocket): Promise<void>;
|
|
21
32
|
convertWebSocket(webSocket: WebSocket, config: ConvertWebSocketConfig): CloudflareWebSocket;
|
|
33
|
+
getLastPing(webSocket: CloudflareWebSocket): number | null;
|
|
34
|
+
getSerializedState(webSocket: CloudflareWebSocket): WebSocketSerializedState | null;
|
|
35
|
+
getSessionId(webSocket: WebSocket): string | null;
|
|
36
|
+
getWebSockets(): readonly WebSocket[];
|
|
37
|
+
initialize(config: AbstractPlatformConfig<{
|
|
38
|
+
env: TEnv;
|
|
39
|
+
}, {
|
|
40
|
+
state: DurableObjectState;
|
|
41
|
+
}>): this;
|
|
22
42
|
parseData(data: string | ArrayBuffer): Record<string, any>;
|
|
23
43
|
randomUUID(): string;
|
|
44
|
+
setSerializedState(webSocket: CloudflareWebSocket, state: WebSocketSerializedState): void;
|
|
45
|
+
private _getDetachedState;
|
|
24
46
|
}
|
|
25
47
|
|
|
26
48
|
interface AuthorizeFunctionContext {
|
|
@@ -47,8 +69,8 @@ interface CreatePluvHandlerResult<TEnv extends Record<string, any> = {}> {
|
|
|
47
69
|
handler: ExportedHandler<TEnv>;
|
|
48
70
|
}
|
|
49
71
|
type InferCloudflarePluvHandlerEnv<TPluvServer extends PluvServer<CloudflarePlatform, any, any, any>> = TPluvServer extends PluvServer<CloudflarePlatform<infer IEnv>, any, any, any> ? IEnv : {};
|
|
50
|
-
declare const createPluvHandler: <TPluvServer extends PluvServer<CloudflarePlatform
|
|
72
|
+
declare const createPluvHandler: <TPluvServer extends PluvServer<CloudflarePlatform, any, any, any>>(config: CreatePluvHandlerConfig<TPluvServer, Id<InferCloudflarePluvHandlerEnv<TPluvServer>>>) => CreatePluvHandlerResult<Id<InferCloudflarePluvHandlerEnv<TPluvServer>>>;
|
|
51
73
|
|
|
52
|
-
declare const platformCloudflare: <TEnv extends Record<string, any> = {}>() => CloudflarePlatform<TEnv>;
|
|
74
|
+
declare const platformCloudflare: <TEnv extends Record<string, any> = {}>(config?: CloudflarePlatformConfig<TEnv>) => CloudflarePlatform<TEnv>;
|
|
53
75
|
|
|
54
|
-
export { type AuthorizeFunction, type AuthorizeFunctionContext, type CreatePluvHandlerConfig, type CreatePluvHandlerResult, type PluvHandlerFetch, createPluvHandler, platformCloudflare };
|
|
76
|
+
export { type AuthorizeFunction, type AuthorizeFunctionContext, type CloudflarePlatformConfig, type CreatePluvHandlerConfig, type CreatePluvHandlerResult, type PluvHandlerFetch, createPluvHandler, platformCloudflare };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
10
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
+
var __spreadValues = (a, b) => {
|
|
12
|
+
for (var prop in b || (b = {}))
|
|
13
|
+
if (__hasOwnProp.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
if (__getOwnPropSymbols)
|
|
16
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
17
|
+
if (__propIsEnum.call(b, prop))
|
|
18
|
+
__defNormalProp(a, prop, b[prop]);
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
21
|
+
};
|
|
22
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
6
23
|
var __export = (target, all) => {
|
|
7
24
|
for (var name in all)
|
|
8
25
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -51,14 +68,23 @@ var createPluvHandler = (config) => {
|
|
|
51
68
|
const { authorize, binding, endpoint = "/api/pluv", modify, io } = config;
|
|
52
69
|
const DurableObject = class {
|
|
53
70
|
constructor(state, env) {
|
|
54
|
-
this.
|
|
55
|
-
this._io = io.getRoom(state.id.toString(), { env });
|
|
71
|
+
this._room = io.getRoom(state.id.toString(), { env, state });
|
|
56
72
|
}
|
|
57
73
|
webSocketClose(ws, code, reason, wasClean) {
|
|
74
|
+
if (io._registrationMode !== "detached") return;
|
|
75
|
+
const handler2 = this._room.onClose(ws);
|
|
76
|
+
handler2({ code, reason });
|
|
58
77
|
}
|
|
59
78
|
webSocketError(ws, error) {
|
|
79
|
+
if (io._registrationMode !== "detached") return;
|
|
80
|
+
const handler2 = this._room.onError(ws);
|
|
81
|
+
const eventError = error instanceof Error ? error : new Error("Internal Error");
|
|
82
|
+
handler2({ error: eventError, message: eventError.message });
|
|
60
83
|
}
|
|
61
84
|
webSocketMessage(ws, message) {
|
|
85
|
+
if (io._registrationMode !== "detached") return;
|
|
86
|
+
const handler2 = this._room.onMessage(ws);
|
|
87
|
+
handler2({ data: message });
|
|
62
88
|
}
|
|
63
89
|
fetch(request) {
|
|
64
90
|
return __async(this, null, function* () {
|
|
@@ -68,11 +94,7 @@ var createPluvHandler = (config) => {
|
|
|
68
94
|
}
|
|
69
95
|
const { 0: client, 1: server } = new WebSocketPair();
|
|
70
96
|
const token = new URL(request.url).searchParams.get("token");
|
|
71
|
-
yield this.
|
|
72
|
-
env: this._env,
|
|
73
|
-
request,
|
|
74
|
-
token
|
|
75
|
-
});
|
|
97
|
+
yield this._room.register(server, { token });
|
|
76
98
|
return new Response(null, { status: 101, webSocket: client });
|
|
77
99
|
});
|
|
78
100
|
}
|
|
@@ -154,18 +176,50 @@ var createPluvHandler = (config) => {
|
|
|
154
176
|
};
|
|
155
177
|
|
|
156
178
|
// src/CloudflarePlatform.ts
|
|
157
|
-
var
|
|
179
|
+
var import_io3 = require("@pluv/io");
|
|
158
180
|
|
|
159
181
|
// src/CloudflareWebSocket.ts
|
|
160
182
|
var import_io = require("@pluv/io");
|
|
161
183
|
var CloudflareWebSocket = class extends import_io.AbstractWebSocket {
|
|
184
|
+
set presence(presence) {
|
|
185
|
+
const deserialized = this.webSocket.deserializeAttachment();
|
|
186
|
+
const state = deserialized.state;
|
|
187
|
+
this.webSocket.serializeAttachment(__spreadProps(__spreadValues({}, this.webSocket.deserializeAttachment()), {
|
|
188
|
+
state: __spreadProps(__spreadValues({}, state), { presence })
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
162
191
|
get readyState() {
|
|
163
192
|
return this.webSocket.readyState;
|
|
164
193
|
}
|
|
194
|
+
get sessionId() {
|
|
195
|
+
var _a, _b;
|
|
196
|
+
const deserialized = (_a = this.webSocket.deserializeAttachment()) != null ? _a : {};
|
|
197
|
+
const sessionId = (_b = deserialized.sessionId) != null ? _b : crypto.randomUUID();
|
|
198
|
+
if (typeof deserialized.sessionId !== "string") {
|
|
199
|
+
this.webSocket.serializeAttachment(__spreadProps(__spreadValues({}, deserialized), { sessionId }));
|
|
200
|
+
}
|
|
201
|
+
return sessionId;
|
|
202
|
+
}
|
|
203
|
+
get state() {
|
|
204
|
+
var _a;
|
|
205
|
+
const deserialized = this.webSocket.deserializeAttachment();
|
|
206
|
+
const state = (_a = deserialized.state) != null ? _a : null;
|
|
207
|
+
if (!state) throw new Error("Could not get websocket state");
|
|
208
|
+
return state;
|
|
209
|
+
}
|
|
165
210
|
constructor(webSocket, config) {
|
|
166
|
-
const { room
|
|
167
|
-
super(
|
|
168
|
-
|
|
211
|
+
const { room } = config;
|
|
212
|
+
super(webSocket, config);
|
|
213
|
+
const state = {
|
|
214
|
+
presence: null,
|
|
215
|
+
quit: false,
|
|
216
|
+
room,
|
|
217
|
+
timers: { ping: (/* @__PURE__ */ new Date()).getTime() }
|
|
218
|
+
};
|
|
219
|
+
webSocket.serializeAttachment(__spreadValues({
|
|
220
|
+
sessionId: this.sessionId,
|
|
221
|
+
state
|
|
222
|
+
}, webSocket.deserializeAttachment()));
|
|
169
223
|
}
|
|
170
224
|
addEventListener(type, handler) {
|
|
171
225
|
this.webSocket.addEventListener(type, handler);
|
|
@@ -175,10 +229,6 @@ var CloudflareWebSocket = class extends import_io.AbstractWebSocket {
|
|
|
175
229
|
if (!canClose) return;
|
|
176
230
|
this.webSocket.close(code, reason);
|
|
177
231
|
}
|
|
178
|
-
initialize() {
|
|
179
|
-
this.webSocket.accept();
|
|
180
|
-
return Promise.resolve(() => void 0);
|
|
181
|
-
}
|
|
182
232
|
send(message) {
|
|
183
233
|
if (this.readyState !== this.OPEN) return;
|
|
184
234
|
this.webSocket.send(message);
|
|
@@ -188,10 +238,169 @@ var CloudflareWebSocket = class extends import_io.AbstractWebSocket {
|
|
|
188
238
|
}
|
|
189
239
|
};
|
|
190
240
|
|
|
241
|
+
// src/PersistanceCloudflare.ts
|
|
242
|
+
var import_io2 = require("@pluv/io");
|
|
243
|
+
|
|
244
|
+
// src/utils/partitionByLength.ts
|
|
245
|
+
var partitionByLength = (arr, length) => {
|
|
246
|
+
if (!arr.length) return [];
|
|
247
|
+
const head = arr.slice(0, length);
|
|
248
|
+
const tail = arr.slice(length);
|
|
249
|
+
return [head, ...partitionByLength(tail, length)];
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// src/PersistanceCloudflare.ts
|
|
253
|
+
var CLOUDFLARE_DELETE_BATCH_LIMIT = 128;
|
|
254
|
+
var STORAGE_PREFIX = "$PLUV_STORAGE;";
|
|
255
|
+
var USER_PREFIX = "$PLUV_USER";
|
|
256
|
+
var PersistanceCloudflare = class extends import_io2.AbstractPersistance {
|
|
257
|
+
constructor(config) {
|
|
258
|
+
super();
|
|
259
|
+
const { state } = config;
|
|
260
|
+
this._state = state;
|
|
261
|
+
}
|
|
262
|
+
addUser(room, connectionId, user) {
|
|
263
|
+
return __async(this, null, function* () {
|
|
264
|
+
yield this._state.storage.put(this._getUserKey(room, connectionId), user);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
deleteStorageState(room) {
|
|
268
|
+
return __async(this, null, function* () {
|
|
269
|
+
yield this._state.storage.delete(this._getStorageKey(room));
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
deleteUser(room, connectionId) {
|
|
273
|
+
return __async(this, null, function* () {
|
|
274
|
+
yield this._state.storage.delete(this._getUserKey(room, connectionId));
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
deleteUsers(room) {
|
|
278
|
+
return __async(this, null, function* () {
|
|
279
|
+
const map = yield this._state.storage.list({
|
|
280
|
+
allowConcurrency: true,
|
|
281
|
+
noCache: true,
|
|
282
|
+
prefix: USER_PREFIX
|
|
283
|
+
});
|
|
284
|
+
const partitions = partitionByLength(Array.from(map.keys()), CLOUDFLARE_DELETE_BATCH_LIMIT);
|
|
285
|
+
yield this._state.storage.transaction((tx) => __async(this, null, function* () {
|
|
286
|
+
yield partitions.reduce((promise, partition) => __async(this, null, function* () {
|
|
287
|
+
return yield promise.then(() => __async(this, null, function* () {
|
|
288
|
+
yield tx.delete(partition);
|
|
289
|
+
}));
|
|
290
|
+
}), Promise.resolve());
|
|
291
|
+
}));
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
getSize(room) {
|
|
295
|
+
return __async(this, null, function* () {
|
|
296
|
+
const storage = yield this._state.storage.list({ prefix: USER_PREFIX });
|
|
297
|
+
return storage.size;
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
getStorageState(room) {
|
|
301
|
+
return __async(this, null, function* () {
|
|
302
|
+
const storage = yield this._state.storage.get(this._getStorageKey(room));
|
|
303
|
+
return storage != null ? storage : null;
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
getUser(room, connectionId) {
|
|
307
|
+
return __async(this, null, function* () {
|
|
308
|
+
const user = yield this._state.storage.get(this._getUserKey(room, connectionId));
|
|
309
|
+
return user != null ? user : null;
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
getUsers(room) {
|
|
313
|
+
return __async(this, null, function* () {
|
|
314
|
+
const storage = yield this._state.storage.list({
|
|
315
|
+
prefix: USER_PREFIX
|
|
316
|
+
});
|
|
317
|
+
return Array.from(storage.values());
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
setStorageState(room, state) {
|
|
321
|
+
return __async(this, null, function* () {
|
|
322
|
+
yield this._state.storage.put(this._getStorageKey(room), state, {
|
|
323
|
+
allowConcurrency: true
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
_getStorageKey(room) {
|
|
328
|
+
return `${STORAGE_PREFIX}::${room}`;
|
|
329
|
+
}
|
|
330
|
+
_getUserKey(room, connectionId) {
|
|
331
|
+
return `${USER_PREFIX}::${room}::${connectionId}`;
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// src/constants.ts
|
|
336
|
+
var DEFAULT_REGISTRATION_MODE = "detached";
|
|
337
|
+
|
|
191
338
|
// src/CloudflarePlatform.ts
|
|
192
|
-
var CloudflarePlatform = class extends
|
|
339
|
+
var CloudflarePlatform = class _CloudflarePlatform extends import_io3.AbstractPlatform {
|
|
340
|
+
constructor(config = {}) {
|
|
341
|
+
var _a;
|
|
342
|
+
super(__spreadValues(__spreadValues({}, config), config.context && config.mode === "detached" ? { persistance: new PersistanceCloudflare(config.context) } : {}));
|
|
343
|
+
this._registrationMode = (_a = config.mode) != null ? _a : DEFAULT_REGISTRATION_MODE;
|
|
344
|
+
const detachedState = this._getDetachedState();
|
|
345
|
+
if (!detachedState) return;
|
|
346
|
+
detachedState.setWebSocketAutoResponse(
|
|
347
|
+
new WebSocketRequestResponsePair('{"type":"$PING","data":{}}', JSON.stringify({ type: "$PONG", data: {} }))
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
acceptWebSocket(webSocket) {
|
|
351
|
+
return __async(this, null, function* () {
|
|
352
|
+
const detachedState = this._getDetachedState();
|
|
353
|
+
if (!detachedState) {
|
|
354
|
+
webSocket.webSocket.accept();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
detachedState.acceptWebSocket(webSocket.webSocket);
|
|
358
|
+
});
|
|
359
|
+
}
|
|
193
360
|
convertWebSocket(webSocket, config) {
|
|
194
|
-
|
|
361
|
+
const { room } = config;
|
|
362
|
+
return new CloudflareWebSocket(webSocket, { persistance: this.persistance, room });
|
|
363
|
+
}
|
|
364
|
+
getLastPing(webSocket) {
|
|
365
|
+
var _a;
|
|
366
|
+
const detachedState = this._getDetachedState();
|
|
367
|
+
if (!detachedState) return null;
|
|
368
|
+
const timestamp = detachedState.getWebSocketAutoResponseTimestamp(webSocket.webSocket);
|
|
369
|
+
return (_a = timestamp == null ? void 0 : timestamp.getTime()) != null ? _a : null;
|
|
370
|
+
}
|
|
371
|
+
getSerializedState(webSocket) {
|
|
372
|
+
var _a;
|
|
373
|
+
const deserialized = webSocket.webSocket.deserializeAttachment();
|
|
374
|
+
return (_a = deserialized == null ? void 0 : deserialized.state) != null ? _a : null;
|
|
375
|
+
}
|
|
376
|
+
getSessionId(webSocket) {
|
|
377
|
+
var _a;
|
|
378
|
+
const deserialized = (_a = webSocket.deserializeAttachment()) != null ? _a : {};
|
|
379
|
+
const sessionId = deserialized.sessionId;
|
|
380
|
+
if (typeof sessionId !== "string") {
|
|
381
|
+
throw new Error("This websocket was not registered");
|
|
382
|
+
}
|
|
383
|
+
return sessionId;
|
|
384
|
+
}
|
|
385
|
+
getWebSockets() {
|
|
386
|
+
var _a;
|
|
387
|
+
const detachedState = this._getDetachedState();
|
|
388
|
+
if (!detachedState) return [];
|
|
389
|
+
return (_a = detachedState.getWebSockets()) != null ? _a : [];
|
|
390
|
+
}
|
|
391
|
+
initialize(config) {
|
|
392
|
+
var _a;
|
|
393
|
+
const context = (_a = config.context) != null ? _a : __spreadValues(__spreadValues({}, this._ioContext), this._roomContext);
|
|
394
|
+
if (!context.env || !context.state) {
|
|
395
|
+
throw new Error("Could not derive platform context");
|
|
396
|
+
}
|
|
397
|
+
return new _CloudflarePlatform(__spreadProps(__spreadValues({
|
|
398
|
+
mode: this._registrationMode,
|
|
399
|
+
persistance: this.persistance,
|
|
400
|
+
pubSub: this.pubSub
|
|
401
|
+
}, config), {
|
|
402
|
+
context: { env: context.env, state: context.state }
|
|
403
|
+
}))._initialize();
|
|
195
404
|
}
|
|
196
405
|
parseData(data) {
|
|
197
406
|
if (typeof data === "string") return JSON.parse(data);
|
|
@@ -201,11 +410,21 @@ var CloudflarePlatform = class extends import_io2.AbstractPlatform {
|
|
|
201
410
|
randomUUID() {
|
|
202
411
|
return crypto.randomUUID();
|
|
203
412
|
}
|
|
413
|
+
setSerializedState(webSocket, state) {
|
|
414
|
+
var _a;
|
|
415
|
+
const deserialized = (_a = webSocket.webSocket.deserializeAttachment()) != null ? _a : {};
|
|
416
|
+
webSocket.webSocket.serializeAttachment(__spreadProps(__spreadValues({}, deserialized), { state }));
|
|
417
|
+
}
|
|
418
|
+
_getDetachedState() {
|
|
419
|
+
var _a, _b;
|
|
420
|
+
if (this._registrationMode !== "detached") return null;
|
|
421
|
+
return (_b = (_a = this._roomContext) == null ? void 0 : _a.state) != null ? _b : null;
|
|
422
|
+
}
|
|
204
423
|
};
|
|
205
424
|
|
|
206
425
|
// src/platformCloudflare.ts
|
|
207
|
-
var platformCloudflare = () => {
|
|
208
|
-
return new CloudflarePlatform();
|
|
426
|
+
var platformCloudflare = (config = {}) => {
|
|
427
|
+
return new CloudflarePlatform(config);
|
|
209
428
|
};
|
|
210
429
|
// Annotate the CommonJS export names for ESM import in node:
|
|
211
430
|
0 && (module.exports = {
|