@signe/room 2.9.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/chunk-EUXUH3YW.js +15 -0
  3. package/dist/chunk-EUXUH3YW.js.map +1 -0
  4. package/dist/cloudflare/index.d.ts +71 -0
  5. package/dist/cloudflare/index.js +320 -0
  6. package/dist/cloudflare/index.js.map +1 -0
  7. package/dist/index.d.ts +65 -188
  8. package/dist/index.js +742 -146
  9. package/dist/index.js.map +1 -1
  10. package/dist/node/index.d.ts +164 -0
  11. package/dist/node/index.js +786 -0
  12. package/dist/node/index.js.map +1 -0
  13. package/dist/party-dNs-hqkq.d.ts +175 -0
  14. package/examples/cloudflare/README.md +62 -0
  15. package/examples/cloudflare/node_modules/.bin/tsc +17 -0
  16. package/examples/cloudflare/node_modules/.bin/tsserver +17 -0
  17. package/examples/cloudflare/node_modules/.bin/wrangler +17 -0
  18. package/examples/cloudflare/node_modules/.bin/wrangler2 +17 -0
  19. package/examples/cloudflare/package.json +24 -0
  20. package/examples/cloudflare/public/index.html +443 -0
  21. package/examples/cloudflare/src/index.ts +28 -0
  22. package/examples/cloudflare/src/room.ts +44 -0
  23. package/examples/cloudflare/tsconfig.json +10 -0
  24. package/examples/cloudflare/wrangler.jsonc +25 -0
  25. package/examples/node/README.md +57 -0
  26. package/examples/node/node_modules/.bin/tsc +17 -0
  27. package/examples/node/node_modules/.bin/tsserver +17 -0
  28. package/examples/node/node_modules/.bin/tsx +17 -0
  29. package/examples/node/package.json +23 -0
  30. package/examples/node/public/index.html +443 -0
  31. package/examples/node/room.ts +44 -0
  32. package/examples/node/server.sqlite.ts +52 -0
  33. package/examples/node/server.ts +51 -0
  34. package/examples/node/tsconfig.json +10 -0
  35. package/examples/node-game/README.md +66 -0
  36. package/examples/node-game/package.json +23 -0
  37. package/examples/node-game/public/index.html +705 -0
  38. package/examples/node-game/room.ts +145 -0
  39. package/examples/node-game/server.sqlite.ts +54 -0
  40. package/examples/node-game/server.ts +53 -0
  41. package/examples/node-game/tsconfig.json +10 -0
  42. package/examples/node-shard/README.md +32 -0
  43. package/examples/node-shard/dev.ts +39 -0
  44. package/examples/node-shard/package.json +24 -0
  45. package/examples/node-shard/public/index.html +777 -0
  46. package/examples/node-shard/room-server.ts +68 -0
  47. package/examples/node-shard/room.ts +105 -0
  48. package/examples/node-shard/shared.ts +6 -0
  49. package/examples/node-shard/tsconfig.json +14 -0
  50. package/examples/node-shard/world-server.ts +169 -0
  51. package/package.json +14 -5
  52. package/readme.md +377 -11
  53. package/src/cloudflare/index.ts +474 -0
  54. package/src/mock.ts +29 -7
  55. package/src/node/index.ts +1112 -0
  56. package/src/server.ts +626 -90
  57. package/src/session.guard.ts +6 -2
  58. package/src/shard.ts +91 -23
  59. package/src/storage.ts +29 -5
  60. package/src/testing.ts +4 -3
  61. package/src/types/party.ts +4 -1
  62. package/src/world.guard.ts +23 -4
  63. package/src/world.ts +170 -79
  64. package/examples/game/.vscode/launch.json +0 -11
  65. package/examples/game/.vscode/settings.json +0 -11
  66. package/examples/game/README.md +0 -40
  67. package/examples/game/app/client.tsx +0 -15
  68. package/examples/game/app/components/Admin.tsx +0 -1089
  69. package/examples/game/app/components/Room.tsx +0 -162
  70. package/examples/game/app/styles.css +0 -31
  71. package/examples/game/package-lock.json +0 -225
  72. package/examples/game/package.json +0 -20
  73. package/examples/game/party/game.room.ts +0 -32
  74. package/examples/game/party/server.ts +0 -10
  75. package/examples/game/party/shard.ts +0 -5
  76. package/examples/game/partykit.json +0 -14
  77. package/examples/game/public/favicon.ico +0 -0
  78. package/examples/game/public/index.html +0 -27
  79. package/examples/game/public/normalize.css +0 -351
  80. package/examples/game/shared/room.schema.ts +0 -14
  81. package/examples/game/tsconfig.json +0 -109
package/dist/index.d.ts CHANGED
@@ -1,176 +1,7 @@
1
- import { Request as Request$2, DurableObjectStorage, WebSocket, DurableObjectState, AnalyticsEngineDataset, VectorizeIndex, R2Bucket, KVNamespace } from '@cloudflare/workers-types';
1
+ import { C as Connection, R as Request$1, a as Room$1, b as ConnectionContext, S as Server$1, c as Storage$1 } from './party-dNs-hqkq.js';
2
2
  import { z } from 'zod';
3
3
  import * as _signe_reactive from '@signe/reactive';
4
-
5
- type AssetFetcher = {
6
- fetch(path: string): Promise<Response | null>;
7
- };
8
- type StandardRequest = globalThis.Request;
9
- interface Request$1 extends Request$2 {
10
- }
11
- type ReturnRequest = StandardRequest | Request$2;
12
- /** Per-party key-value storage */
13
- interface Storage$1 extends DurableObjectStorage {
14
- }
15
- /** Connection metadata only available when the connection is made */
16
- type ConnectionContext = {
17
- request: Request$2;
18
- };
19
- type Stub = {
20
- /** @deprecated Use `await socket()` instead */
21
- connect: () => WebSocket;
22
- socket(pathOrInit?: string | RequestInit): Promise<WebSocket>;
23
- socket(path: string, init?: RequestInit): Promise<WebSocket>;
24
- fetch(pathOrInit?: string | RequestInit | ReturnRequest): Promise<Response>;
25
- fetch(path: string, init?: RequestInit | ReturnRequest): Promise<Response>;
26
- };
27
- /** Additional information about other resources in the current project */
28
- type Context = {
29
- /** Access other parties in this project */
30
- parties: Record<string, {
31
- get(id: string): Stub;
32
- }>;
33
- /**
34
- * A binding to the Cloudflare AI service.
35
- */
36
- ai: AI;
37
- /**
38
- * A binding to the Cloudflare Vectorize service.
39
- */
40
- vectorize: Record<string, VectorizeIndex>;
41
- /**
42
- * A binding to fetch static assets
43
- */
44
- assets: AssetFetcher;
45
- /**
46
- * Custom bindings
47
- */
48
- bindings: CustomBindings;
49
- };
50
- type AI = Record<string, never>;
51
- type ImmutablePrimitive = undefined | null | boolean | string | number;
52
- type Immutable<T> = T extends ImmutablePrimitive ? T : T extends Array<infer U> ? ImmutableArray<U> : T extends Map<infer K, infer V> ? ImmutableMap<K, V> : T extends Set<infer M> ? ImmutableSet<M> : ImmutableObject<T>;
53
- type ImmutableArray<T> = ReadonlyArray<Immutable<T>>;
54
- type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
55
- type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
56
- type ImmutableObject<T> = {
57
- readonly [K in keyof T]: Immutable<T[K]>;
58
- };
59
- type ConnectionState<T> = ImmutableObject<T> | null;
60
- type ConnectionSetStateFn<T> = (prevState: ConnectionState<T>) => T;
61
- /** A WebSocket connected to the Room */
62
- type Connection<TState = unknown> = WebSocket & {
63
- /** Connection identifier */
64
- id: string;
65
- /** @deprecated You can access the socket properties directly on the connection*/
66
- socket: WebSocket;
67
- uri: string;
68
- /**
69
- * Arbitrary state associated with this connection.
70
- * Read-only, use Connection.setState to update the state.
71
- */
72
- state: ConnectionState<TState>;
73
- setState(state: TState | ConnectionSetStateFn<TState> | null): ConnectionState<TState>;
74
- /** @deprecated use Connection.setState instead */
75
- serializeAttachment<T = unknown>(attachment: T): void;
76
- /** @deprecated use Connection.state instead */
77
- deserializeAttachment<T = unknown>(): T | null;
78
- };
79
- type CustomBindings = {
80
- r2: Record<string, R2Bucket>;
81
- kv: Record<string, KVNamespace>;
82
- };
83
- /** Room represents a single, self-contained, long-lived session. */
84
- type Room$1 = {
85
- /** Room ID defined in the Party URL, e.g. /parties/:name/:id */
86
- id: string;
87
- /** Internal ID assigned by the platform. Use Party.id instead. */
88
- internalID: string;
89
- /** Party name defined in the Party URL, e.g. /parties/:name/:id */
90
- name: string;
91
- /** Environment variables (--var, partykit.json#vars, or .env) */
92
- env: Record<string, unknown>;
93
- /** A per-room key-value storage */
94
- storage: Storage$1;
95
- /** `blockConcurrencyWhile()` ensures no requests are delivered until */
96
- blockConcurrencyWhile: DurableObjectState["blockConcurrencyWhile"];
97
- /** Additional information about other resources in the current project */
98
- context: Context;
99
- /** @deprecated Use `room.getConnections` instead */
100
- connections: Map<string, Connection>;
101
- /** @deprecated Use `room.context.parties` instead */
102
- parties: Context["parties"];
103
- /** Send a message to all connected clients, except connection ids listed `without` */
104
- broadcast: (msg: string | ArrayBuffer | ArrayBufferView, without?: string[] | undefined) => void;
105
- /** Get a connection by connection id */
106
- getConnection<TState = unknown>(id: string): Connection<TState> | undefined;
107
- /**
108
- * Get all connections. Optionally, you can provide a tag to filter returned connections.
109
- * Use `Party.Server#getConnectionTags` to tag the connection on connect.
110
- */
111
- getConnections<TState = unknown>(tag?: string): Iterable<Connection<TState>>;
112
- /**
113
- * Cloudflare Analytics Engine dataset. Use this to log custom events and metrics.
114
- */
115
- analytics: AnalyticsEngineDataset;
116
- };
117
- type Server$1 = {
118
- /**
119
- * You can define an `options` field to customise the Party.Server behaviour.
120
- */
121
- readonly options?: ServerOptions;
122
- /**
123
- * You can tag a connection to filter them in Party#getConnections.
124
- * Each connection supports up to 9 tags, each tag max length is 256 characters.
125
- */
126
- getConnectionTags?(connection: Connection, context: ConnectionContext): string[] | Promise<string[]>;
127
- /**
128
- * Called when the server is started, before first `onConnect` or `onRequest`.
129
- * Useful for loading data from storage.
130
- *
131
- * You can use this to load data from storage and perform other asynchronous
132
- * initialization, such as retrieving data or configuration from other
133
- * services or databases.
134
- */
135
- onStart?(): void | Promise<void>;
136
- /**
137
- * Called when a new incoming WebSocket connection is opened.
138
- */
139
- onConnect?(connection: Connection, ctx: ConnectionContext): void | Promise<void>;
140
- /**
141
- * Called when a WebSocket connection receives a message from a client, or another connected party.
142
- */
143
- onMessage?(message: string | ArrayBuffer | ArrayBufferView, sender: Connection): void | Promise<void>;
144
- /**
145
- * Called when a WebSocket connection is closed by the client.
146
- */
147
- onClose?(connection: Connection): void | Promise<void>;
148
- /**
149
- * Called when a WebSocket connection is closed due to a connection error.
150
- */
151
- onError?(connection: Connection, error: Error): void | Promise<void>;
152
- /**
153
- * Called when a HTTP request is made to the room URL.
154
- */
155
- onRequest?(req: Request$1): Response | Promise<Response>;
156
- /**
157
- * Called when an alarm is triggered. Use Party.storage.setAlarm to set an alarm.
158
- *
159
- * Alarms have access to most Party resources such as storage, but not Party.id
160
- * and Party.context.parties properties. Attempting to access them will result in a
161
- * runtime error.
162
- */
163
- onAlarm?(): void | Promise<void>;
164
- };
165
- type ServerOptions = {
166
- /**
167
- * Whether the PartyKit platform should remove the server from memory
168
- * between HTTP requests and WebSocket messages.
169
- *
170
- * The default value is `false`.
171
- */
172
- hibernate?: boolean;
173
- };
4
+ import '@cloudflare/workers-types';
174
5
 
175
6
  type GuardFn = (sender: Connection, value: any | Request$1, room: Room$1) => boolean | Promise<boolean | Response>;
176
7
  type RoomGuardFn = (conn: Connection, ctx: ConnectionContext, room: Room$1) => boolean | Promise<boolean | Response>;
@@ -211,6 +42,13 @@ declare function RoomGuard(guards: RoomGuardFn[]): (target: any) => void;
211
42
  */
212
43
  declare function Guard(guards: GuardFn[]): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
213
44
 
45
+ type SessionData = {
46
+ publicId: string;
47
+ state?: any;
48
+ created?: number;
49
+ connected?: boolean;
50
+ disconnectedAt?: number;
51
+ };
214
52
  /**
215
53
  * @class Server
216
54
  * @implements {Party.Server}
@@ -260,6 +98,21 @@ declare class Server implements Server$1 {
260
98
  */
261
99
  get isHibernate(): boolean;
262
100
  get roomStorage(): Storage$1;
101
+ private stateKey;
102
+ private sessionKey;
103
+ private sessionPublicKey;
104
+ private transferKey;
105
+ private isInternalStorageKey;
106
+ private listStorage;
107
+ private loadStatePath;
108
+ private saveStatePath;
109
+ private putStorageEntries;
110
+ private deleteStorageKeys;
111
+ private deleteStatePath;
112
+ private createStorageMetrics;
113
+ private getTransferExpiryTime;
114
+ private getPrivateId;
115
+ private hasActiveSessionConnection;
263
116
  send(conn: Connection, obj: any, subRoom: any): Promise<void>;
264
117
  broadcast(obj: any, subRoom: any): void;
265
118
  /**
@@ -279,6 +132,14 @@ declare class Server implements Server$1 {
279
132
  onStart(): Promise<void>;
280
133
  runGarbageCollector(): Promise<void>;
281
134
  private garbageCollector;
135
+ private scheduleSessionGarbageCollector;
136
+ private getSessionExpiryTime;
137
+ private shouldRunSessionGarbageCollector;
138
+ private shouldRunInterval;
139
+ private repairSessionPublicIndexes;
140
+ private isTransferExpired;
141
+ private cleanupExpiredTransfers;
142
+ private expireDisconnectedSession;
282
143
  /**
283
144
  * @method createRoom
284
145
  * @private
@@ -359,12 +220,12 @@ declare class Server implements Server$1 {
359
220
  * console.log(session);
360
221
  * ```
361
222
  */
362
- getSession(privateId: string): Promise<{
363
- publicId: string;
364
- state?: any;
365
- created?: number;
366
- connected?: boolean;
367
- } | null>;
223
+ getSession(privateId: string): Promise<SessionData | null>;
224
+ private getSessionPrivateIds;
225
+ private saveSessionPrivateIds;
226
+ private addSessionToPublicIndex;
227
+ private removeSessionFromPublicIndex;
228
+ private getSessionEntryByPublicId;
368
229
  private saveSession;
369
230
  private updateSessionConnection;
370
231
  /**
@@ -397,6 +258,7 @@ declare class Server implements Server$1 {
397
258
  * ```
398
259
  */
399
260
  onConnect(conn: Connection, ctx: ConnectionContext): Promise<void>;
261
+ private isAuthorizedShardRequest;
400
262
  /**
401
263
  * @method onConnectShard
402
264
  * @private
@@ -528,8 +390,6 @@ declare class Server implements Server$1 {
528
390
  * @returns {Object} An object containing the path parameters
529
391
  */
530
392
  private extractPathParams;
531
- private normalizeRequestPath;
532
- private pathPatternToRegex;
533
393
  /**
534
394
  * @method handleShardRequest
535
395
  * @private
@@ -553,10 +413,12 @@ declare class Server implements Server$1 {
553
413
 
554
414
  declare class Storage {
555
415
  private memory;
556
- put(key: any, value: any): Promise<void>;
416
+ put(key: any, value?: any): Promise<void>;
557
417
  get(key: any): Promise<any>;
558
- delete(key: any): Promise<void>;
559
- list(): Promise<Map<any, any>>;
418
+ delete(key: any): Promise<number | boolean>;
419
+ list(options?: {
420
+ prefix?: string;
421
+ }): Promise<Map<any, any>>;
560
422
  }
561
423
 
562
424
  declare class MockPartyClient {
@@ -564,7 +426,7 @@ declare class MockPartyClient {
564
426
  private events;
565
427
  id: string;
566
428
  conn: MockConnection;
567
- constructor(server: Server, id?: string);
429
+ constructor(server: Server, sessionId?: string);
568
430
  addEventListener(event: any, cb: any): void;
569
431
  removeEventListener(event: any, cb: any): void;
570
432
  _trigger(event: any, data: any): void;
@@ -593,15 +455,17 @@ declare class MockPartyRoom {
593
455
  headers?: Record<string, string>;
594
456
  }): Promise<MockPartyClient>;
595
457
  broadcast(data: any): void;
596
- getConnection(id: string): MockPartyClient;
458
+ getConnection(id: string): MockConnection;
597
459
  getConnections(): MockConnection[];
598
460
  clear(): void;
461
+ deleteConnection(id: string, connection?: MockConnection): void;
599
462
  }
600
463
  declare class MockConnection {
601
464
  client: MockPartyClient;
602
465
  server: Server;
603
466
  id: string;
604
- constructor(client: MockPartyClient);
467
+ sessionId: string;
468
+ constructor(client: MockPartyClient, sessionId: string);
605
469
  state: any;
606
470
  setState(value: any): void;
607
471
  send(data: any): void;
@@ -623,21 +487,25 @@ interface ShardOptions {
623
487
  declare class Shard {
624
488
  private room;
625
489
  ws: PartyWebSocket;
626
- connectionMap: Map<string, Connection<unknown>>;
490
+ connectionMap: Map<string, Set<Connection<unknown>>>;
627
491
  mainServerStub: any;
628
492
  worldUrl: string | null;
629
493
  worldId: string;
630
494
  lastReportedConnections: number;
631
495
  statsInterval: number;
632
496
  statsIntervalId: any;
633
- constructor(room: Room$1);
497
+ constructor(room: Room$1, options?: ShardOptions);
498
+ private getPrivateId;
499
+ private getEnvString;
500
+ private getRoomIdFromShardId;
501
+ private getWorldIdFromShardId;
634
502
  onStart(): Promise<void>;
635
503
  private startPeriodicStatsUpdates;
636
504
  private stopPeriodicStatsUpdates;
637
505
  onConnect(conn: Connection, ctx: ConnectionContext): void;
638
506
  onMessage(message: string | ArrayBuffer | ArrayBufferView, sender: Connection): void;
639
507
  onClose(conn: Connection): void;
640
- updateWorldStats(): Promise<boolean>;
508
+ updateWorldStats(force?: boolean): Promise<boolean>;
641
509
  /**
642
510
  * @method onRequest
643
511
  * @async
@@ -682,6 +550,7 @@ declare class Shard {
682
550
  declare function testRoom(Room: any, options?: {
683
551
  hibernate?: boolean;
684
552
  shard?: boolean;
553
+ id?: string;
685
554
  env?: Record<string, string>;
686
555
  parties?: Record<string, (io: any) => any>;
687
556
  partyFn?: (io: any) => any;
@@ -851,6 +720,7 @@ declare class RoomConfig {
851
720
  declare class ShardInfo {
852
721
  id: string;
853
722
  roomId: _signe_reactive.WritableSignal<string>;
723
+ worldId: _signe_reactive.WritableSignal<string>;
854
724
  url: _signe_reactive.WritableSignal<string>;
855
725
  currentConnections: _signe_reactive.WritableSignal<number>;
856
726
  maxConnections: _signe_reactive.WritableSignal<number>;
@@ -867,13 +737,20 @@ declare class WorldRoom implements RoomInterceptorPacket, RoomOnJoin {
867
737
  constructor(room: Room$1);
868
738
  onJoin(user: any, conn: Connection, ctx: ConnectionContext): Promise<void>;
869
739
  interceptorPacket(_: any, obj: any, conn: Connection): any;
740
+ private getWorldId;
741
+ private scheduleInactiveShardCleanup;
870
742
  private cleanupInactiveShards;
743
+ private removeShard;
744
+ private shouldCompleteDrain;
871
745
  registerRoom(req: Request$1, res?: ServerResponse): Promise<Response>;
872
746
  updateShardStats(req: Request$1, res: ServerResponse): Promise<Response>;
873
747
  scaleRoom(req: Request$1, res: ServerResponse): Promise<Response>;
874
748
  connect(req: Request$1, res: ServerResponse): Promise<Response>;
875
749
  private findOptimalShard;
750
+ private getAvailableShards;
751
+ private canCreateShard;
876
752
  private createShard;
753
+ private ensureMinShards;
877
754
  }
878
755
 
879
756
  /**