@pluv/types 2.1.0 → 2.2.1

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,5 +1,5 @@
1
1
 
2
- > @pluv/types@2.1.0 build /home/runner/work/pluv/pluv/packages/types
2
+ > @pluv/types@2.2.1 build /home/runner/work/pluv/pluv/packages/types
3
3
  > tsup src/index.ts --format esm,cjs --dts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -8,11 +8,11 @@
8
8
  CLI Target: es6
9
9
  ESM Build start
10
10
  CJS Build start
11
- ESM dist/index.mjs 197.00 B
12
- ESM ⚡️ Build success in 34ms
13
- CJS dist/index.js 1.21 KB
14
- CJS ⚡️ Build success in 35ms
11
+ CJS dist/index.js 1.37 KB
12
+ CJS ⚡️ Build success in 37ms
13
+ ESM dist/index.mjs 330.00 B
14
+ ESM ⚡️ Build success in 38ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 1274ms
17
- DTS dist/index.d.mts 18.11 KB
18
- DTS dist/index.d.ts 18.11 KB
16
+ DTS ⚡️ Build success in 1276ms
17
+ DTS dist/index.d.mts 18.73 KB
18
+ DTS dist/index.d.ts 18.73 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @pluv/types
2
2
 
3
+ ## 2.2.1
4
+
5
+ ## 2.2.0
6
+
3
7
  ## 2.1.0
4
8
 
5
9
  ## 2.0.2
package/dist/index.d.mts CHANGED
@@ -56,13 +56,14 @@ interface DocBatchApplyEncodedStateParams {
56
56
  origin?: string;
57
57
  updates?: Maybe<readonly Maybe<string | Uint8Array>[]>;
58
58
  }
59
- interface DocSubscribeCallbackParams<TStorage extends Record<string, CrdtType<any, any>>> {
60
- doc: CrdtDocLike<TStorage>;
59
+ interface DocSubscribeCallbackParams<TDoc extends any, TStorage extends Record<string, CrdtType<any, any>>> {
60
+ doc: CrdtDocLike<TDoc, TStorage>;
61
61
  local: boolean;
62
62
  origin?: string | null;
63
63
  update: string;
64
64
  }
65
- interface CrdtDocLike<TStorage extends Record<string, CrdtType<any, any>>> {
65
+ interface CrdtDocLike<TDoc extends any, TStorage extends Record<string, CrdtType<any, any>>> {
66
+ value: TDoc;
66
67
  applyEncodedState(params: DocApplyEncodedStateParams): this;
67
68
  batchApplyEncodedState(params: DocBatchApplyEncodedStateParams): this;
68
69
  canRedo(): boolean;
@@ -74,7 +75,7 @@ interface CrdtDocLike<TStorage extends Record<string, CrdtType<any, any>>> {
74
75
  isEmpty(): boolean;
75
76
  rebuildStorage(reference: TStorage): this;
76
77
  redo(): this;
77
- subscribe(listener: (params: DocSubscribeCallbackParams<TStorage>) => void): () => void;
78
+ subscribe(listener: (params: DocSubscribeCallbackParams<TDoc, TStorage>) => void): () => void;
78
79
  toJson(): InferCrdtJson<TStorage>;
79
80
  toJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]>;
80
81
  track(): this;
@@ -83,13 +84,20 @@ interface CrdtDocLike<TStorage extends Record<string, CrdtType<any, any>>> {
83
84
  }
84
85
 
85
86
  declare const ConnectionState: {
86
- readonly Closed: "Closed";
87
- readonly Connecting: "Connecting";
88
- readonly Open: "Open";
89
- readonly Unavailable: "Unavailable";
90
- readonly Untouched: "Untouched";
87
+ readonly Closed: "closed";
88
+ readonly Connecting: "connecting";
89
+ readonly Open: "open";
90
+ readonly Unavailable: "unavailable";
91
+ readonly Untouched: "untouched";
91
92
  };
92
93
  type ConnectionState = (typeof ConnectionState)[keyof typeof ConnectionState];
94
+ declare const StorageState: {
95
+ Loading: string;
96
+ Offline: string;
97
+ Synced: string;
98
+ Unavailable: string;
99
+ };
100
+ type StorageState = (typeof StorageState)[keyof typeof StorageState];
93
101
 
94
102
  type BaseUser = {
95
103
  id: string;
@@ -242,9 +250,9 @@ interface AuthorizationState<TIO extends IOLike> {
242
250
  token: string | null;
243
251
  user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>> | null;
244
252
  }
245
- type OtherSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (value: Id<UserInfo<TIO, TPresence>> | null) => void;
246
- type OtherSubscriptionFn<TIO extends IOLike, TPresence extends JsonObject> = (connectionId: string, callback: OtherSubscriptionCallback<TIO, TPresence>) => () => void;
247
- type OthersSubscriptionEvent<TIO extends IOLike, TPresence extends JsonObject> = {
253
+ type OtherSubscriptionCallback<TIO extends IOLike, TPresence extends Record<string, any>> = (value: Id<UserInfo<TIO, TPresence>> | null) => void;
254
+ type OtherSubscriptionFn<TIO extends IOLike, TPresence extends Record<string, any>> = (connectionId: string, callback: OtherSubscriptionCallback<TIO, TPresence>) => () => void;
255
+ type OthersSubscriptionEvent<TIO extends IOLike, TPresence extends Record<string, any>> = {
248
256
  kind: "clear";
249
257
  } | {
250
258
  kind: "enter";
@@ -259,19 +267,19 @@ type OthersSubscriptionEvent<TIO extends IOLike, TPresence extends JsonObject> =
259
267
  kind: "update";
260
268
  user: Id<UserInfo<TIO, TPresence>>;
261
269
  };
262
- type OthersSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (value: readonly Id<UserInfo<TIO, TPresence>>[], event: OthersSubscriptionEvent<TIO, TPresence>) => void;
263
- type OthersSubscriptionFn<TIO extends IOLike, TPresence extends JsonObject> = (callback: OthersSubscriptionCallback<TIO, TPresence>) => () => void;
264
- interface StateNotifierSubjects<TIO extends IOLike, TPresence extends JsonObject> {
270
+ type OthersSubscriptionCallback<TIO extends IOLike, TPresence extends Record<string, any>> = (value: readonly Id<UserInfo<TIO, TPresence>>[], event: OthersSubscriptionEvent<TIO, TPresence>) => void;
271
+ type OthersSubscriptionFn<TIO extends IOLike, TPresence extends Record<string, any>> = (callback: OthersSubscriptionCallback<TIO, TPresence>) => () => void;
272
+ interface StateNotifierSubjects<TIO extends IOLike, TPresence extends Record<string, any>> {
265
273
  connection: Subject<Id<WebSocketState<TIO>>>;
266
274
  "my-presence": Subject<TPresence | null>;
267
275
  myself: Subject<Readonly<Id<UserInfo<TIO, TPresence>>> | null>;
268
276
  others: Subject<readonly Id<UserInfo<TIO, TPresence>>[]>;
269
277
  "storage-loaded": Subject<boolean>;
270
278
  }
271
- type InferSubjectValue<TIO extends IOLike, TPresence extends JsonObject, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue> ? Id<IValue> : never;
272
- type SubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
273
- type UpdateMyPresenceAction<TPresence extends JsonObject> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
274
- interface UserInfo<TIO extends IOLike, TPresence extends JsonObject = {}> {
279
+ type InferSubjectValue<TIO extends IOLike, TPresence extends Record<string, any>, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue> ? Id<IValue> : never;
280
+ type SubscriptionCallback<TIO extends IOLike, TPresence extends Record<string, any>, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
281
+ type UpdateMyPresenceAction<TPresence extends Record<string, any>> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
282
+ interface UserInfo<TIO extends IOLike, TPresence extends Record<string, any> = {}> {
275
283
  connectionId: string;
276
284
  presence: TPresence;
277
285
  user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;
@@ -283,20 +291,16 @@ interface WebSocketConnection {
283
291
  * @date April 13, 2025
284
292
  */
285
293
  attempts: number;
286
- /**
287
- * @description How many times the user has connected to the room. This can be more than 1 in
288
- * the case of reconnects. This is tracked because on the very first connection (i.e. when
289
- * count is 0) we don't want to send the storage state as an update to the room and overwrite
290
- * the upstream state.
291
- * @date April 13, 2025
292
- */
293
- count: number;
294
294
  id: string | null;
295
295
  state: ConnectionState;
296
296
  }
297
+ interface StorageInfo {
298
+ state: StorageState;
299
+ }
297
300
  interface WebSocketState<TIO extends IOLike> {
298
301
  authorization: AuthorizationState<TIO>;
299
302
  connection: WebSocketConnection;
303
+ storage: StorageInfo;
300
304
  webSocket: WebSocket | null;
301
305
  }
302
306
  type BroadcastProxy<TIO extends IOLike, TEvents extends PluvRouterEventConfig> = (<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(event: TEvent, data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>) => Promise<void>) & {
@@ -317,7 +321,7 @@ type StorageProxy<TStorage extends Record<string, CrdtType<any, any>>> = Storage
317
321
  [PKey in keyof TStorage]: (callback: StorageSubscriptionCallback<TStorage, PKey>) => () => void;
318
322
  };
319
323
  type SubscribeFn<TValue extends unknown> = (callback: (value: TValue) => void) => () => void;
320
- type SubscribeProxy<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig> = (<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(name: TSubject, callback: SubscriptionCallback<TIO, TPresence, TSubject>) => () => void) & {
324
+ type SubscribeProxy<TIO extends IOLike, TPresence extends Record<string, any>, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig> = (<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(name: TSubject, callback: SubscriptionCallback<TIO, TPresence, TSubject>) => () => void) & {
321
325
  connection: SubscribeFn<Id<WebSocketState<TIO>>>;
322
326
  event: EventProxy<TIO, TEvents>;
323
327
  myPresence: SubscribeFn<TPresence | null>;
@@ -327,13 +331,23 @@ type SubscribeProxy<TIO extends IOLike, TPresence extends JsonObject, TStorage e
327
331
  storage: StorageProxy<TStorage>;
328
332
  storageLoaded: SubscribeFn<boolean>;
329
333
  };
330
- interface RoomLike<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig = {}> {
334
+ interface RoomEventListenerMap {
335
+ close: (event: CloseEvent | null) => void;
336
+ error: (event: Event) => void;
337
+ message: (event: MessageEvent<any>) => void;
338
+ open: (event: Event) => void;
339
+ }
340
+ interface RoomLike<TIO extends IOLike, TDoc extends any, TPresence extends Record<string, any> = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig = {}> {
331
341
  id: string;
332
- storageLoaded: boolean;
333
342
  broadcast: BroadcastProxy<TIO, TEvents>;
343
+ /**
344
+ * @deprecated To be removed in v3. Use getStorageLoaded instead.
345
+ */
346
+ storageLoaded: boolean;
347
+ addEventListener<TKind extends keyof RoomEventListenerMap>(kind: TKind, handler: RoomEventListenerMap[TKind]): () => void;
334
348
  canRedo(): boolean;
335
349
  canUndo(): boolean;
336
- getDoc(): CrdtDocLike<TStorage>;
350
+ getDoc(): CrdtDocLike<TDoc, TStorage>;
337
351
  event: EventProxy<TIO, TEvents>;
338
352
  getConnection(): WebSocketConnection;
339
353
  getMyPresence(): TPresence;
@@ -343,6 +357,7 @@ interface RoomLike<TIO extends IOLike, TPresence extends JsonObject = {}, TStora
343
357
  getStorage<TKey extends keyof TStorage>(type: TKey): TStorage[TKey] | null;
344
358
  getStorageJson(): InferCrdtJson<TStorage> | null;
345
359
  getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
360
+ getStorageLoaded: () => boolean;
346
361
  other(connectionId: string, callback: OtherSubscriptionCallback<TIO, TPresence>): () => void;
347
362
  redo(): void;
348
363
  storage: StorageProxy<TStorage>;
@@ -355,4 +370,4 @@ interface RoomLike<TIO extends IOLike, TPresence extends JsonObject = {}, TStora
355
370
  updateMyPresence(presence: UpdateMyPresenceAction<TPresence>): void;
356
371
  }
357
372
 
358
- export { type BaseClientEventRecord, type BaseClientMessage, type BaseIOEventRecord, type BaseUser, type BroadcastProxy, ConnectionState, type Constructable, type CrdtDocLike, type CrdtType, type DeepPartial, type DeepWriteable, type DocApplyEncodedStateParams, type DocBatchApplyEncodedStateParams, type DocSubscribeCallbackParams, type EventMessage, type EventNotifierSubscriptionCallback, type EventProxy, type EventRecord, type GetEventMessage, type IOAuthorize, type IOAuthorizeEventMessage, type IOEventMessage, type IOLike, type IORouterLike, type Id, type InferEventMessage, type InferEventsInput, type InferEventsOutput, type InferIOAuthorize, type InferIOAuthorizeUser, type InferIOInput, type InferIOOutput, type InputZodLike, type Json, type JsonObject, type JsonPrimitive, type Maybe, type MaybePromise, type MaybeReadonlyArray, type MergeEvents, type NonNilProps, type OptionalProps, type OtherSubscriptionCallback, type OtherSubscriptionFn, type OthersSubscriptionCallback, type OthersSubscriptionEvent, type OthersSubscriptionFn, type ProcedureLike, type RoomLike, type Spread, type SpreadProperties, type StateNotifierSubjects, type StorageProxy, type StorageRootSubscriptionCallback, type StorageRootSubscriptionFn, type StorageSubscriptionCallback, type StorageSubscriptionFn, type SubscribeFn, type SubscribeProxy, type SubscriptionCallback, type UndefinedProps, type UpdateMyPresenceAction, type UserInfo, type WebSocketConnection, type WebSocketState };
373
+ export { type BaseClientEventRecord, type BaseClientMessage, type BaseIOEventRecord, type BaseUser, type BroadcastProxy, ConnectionState, type Constructable, type CrdtDocLike, type CrdtType, type DeepPartial, type DeepWriteable, type DocApplyEncodedStateParams, type DocBatchApplyEncodedStateParams, type DocSubscribeCallbackParams, type EventMessage, type EventNotifierSubscriptionCallback, type EventProxy, type EventRecord, type GetEventMessage, type IOAuthorize, type IOAuthorizeEventMessage, type IOEventMessage, type IOLike, type IORouterLike, type Id, type InferCrdtJson, type InferEventMessage, type InferEventsInput, type InferEventsOutput, type InferIOAuthorize, type InferIOAuthorizeUser, type InferIOInput, type InferIOOutput, type InputZodLike, type Json, type JsonObject, type JsonPrimitive, type Maybe, type MaybePromise, type MaybeReadonlyArray, type MergeEvents, type NonNilProps, type OptionalProps, type OtherSubscriptionCallback, type OtherSubscriptionFn, type OthersSubscriptionCallback, type OthersSubscriptionEvent, type OthersSubscriptionFn, type PluvRouterEventConfig, type ProcedureLike, type RoomEventListenerMap, type RoomLike, type Spread, type SpreadProperties, type StateNotifierSubjects, type StorageInfo, type StorageProxy, type StorageRootSubscriptionCallback, type StorageRootSubscriptionFn, StorageState, type StorageSubscriptionCallback, type StorageSubscriptionFn, type SubscribeFn, type SubscribeProxy, type SubscriptionCallback, type UndefinedProps, type UpdateMyPresenceAction, type UserInfo, type WebSocketConnection, type WebSocketState };
package/dist/index.d.ts CHANGED
@@ -56,13 +56,14 @@ interface DocBatchApplyEncodedStateParams {
56
56
  origin?: string;
57
57
  updates?: Maybe<readonly Maybe<string | Uint8Array>[]>;
58
58
  }
59
- interface DocSubscribeCallbackParams<TStorage extends Record<string, CrdtType<any, any>>> {
60
- doc: CrdtDocLike<TStorage>;
59
+ interface DocSubscribeCallbackParams<TDoc extends any, TStorage extends Record<string, CrdtType<any, any>>> {
60
+ doc: CrdtDocLike<TDoc, TStorage>;
61
61
  local: boolean;
62
62
  origin?: string | null;
63
63
  update: string;
64
64
  }
65
- interface CrdtDocLike<TStorage extends Record<string, CrdtType<any, any>>> {
65
+ interface CrdtDocLike<TDoc extends any, TStorage extends Record<string, CrdtType<any, any>>> {
66
+ value: TDoc;
66
67
  applyEncodedState(params: DocApplyEncodedStateParams): this;
67
68
  batchApplyEncodedState(params: DocBatchApplyEncodedStateParams): this;
68
69
  canRedo(): boolean;
@@ -74,7 +75,7 @@ interface CrdtDocLike<TStorage extends Record<string, CrdtType<any, any>>> {
74
75
  isEmpty(): boolean;
75
76
  rebuildStorage(reference: TStorage): this;
76
77
  redo(): this;
77
- subscribe(listener: (params: DocSubscribeCallbackParams<TStorage>) => void): () => void;
78
+ subscribe(listener: (params: DocSubscribeCallbackParams<TDoc, TStorage>) => void): () => void;
78
79
  toJson(): InferCrdtJson<TStorage>;
79
80
  toJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]>;
80
81
  track(): this;
@@ -83,13 +84,20 @@ interface CrdtDocLike<TStorage extends Record<string, CrdtType<any, any>>> {
83
84
  }
84
85
 
85
86
  declare const ConnectionState: {
86
- readonly Closed: "Closed";
87
- readonly Connecting: "Connecting";
88
- readonly Open: "Open";
89
- readonly Unavailable: "Unavailable";
90
- readonly Untouched: "Untouched";
87
+ readonly Closed: "closed";
88
+ readonly Connecting: "connecting";
89
+ readonly Open: "open";
90
+ readonly Unavailable: "unavailable";
91
+ readonly Untouched: "untouched";
91
92
  };
92
93
  type ConnectionState = (typeof ConnectionState)[keyof typeof ConnectionState];
94
+ declare const StorageState: {
95
+ Loading: string;
96
+ Offline: string;
97
+ Synced: string;
98
+ Unavailable: string;
99
+ };
100
+ type StorageState = (typeof StorageState)[keyof typeof StorageState];
93
101
 
94
102
  type BaseUser = {
95
103
  id: string;
@@ -242,9 +250,9 @@ interface AuthorizationState<TIO extends IOLike> {
242
250
  token: string | null;
243
251
  user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>> | null;
244
252
  }
245
- type OtherSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (value: Id<UserInfo<TIO, TPresence>> | null) => void;
246
- type OtherSubscriptionFn<TIO extends IOLike, TPresence extends JsonObject> = (connectionId: string, callback: OtherSubscriptionCallback<TIO, TPresence>) => () => void;
247
- type OthersSubscriptionEvent<TIO extends IOLike, TPresence extends JsonObject> = {
253
+ type OtherSubscriptionCallback<TIO extends IOLike, TPresence extends Record<string, any>> = (value: Id<UserInfo<TIO, TPresence>> | null) => void;
254
+ type OtherSubscriptionFn<TIO extends IOLike, TPresence extends Record<string, any>> = (connectionId: string, callback: OtherSubscriptionCallback<TIO, TPresence>) => () => void;
255
+ type OthersSubscriptionEvent<TIO extends IOLike, TPresence extends Record<string, any>> = {
248
256
  kind: "clear";
249
257
  } | {
250
258
  kind: "enter";
@@ -259,19 +267,19 @@ type OthersSubscriptionEvent<TIO extends IOLike, TPresence extends JsonObject> =
259
267
  kind: "update";
260
268
  user: Id<UserInfo<TIO, TPresence>>;
261
269
  };
262
- type OthersSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (value: readonly Id<UserInfo<TIO, TPresence>>[], event: OthersSubscriptionEvent<TIO, TPresence>) => void;
263
- type OthersSubscriptionFn<TIO extends IOLike, TPresence extends JsonObject> = (callback: OthersSubscriptionCallback<TIO, TPresence>) => () => void;
264
- interface StateNotifierSubjects<TIO extends IOLike, TPresence extends JsonObject> {
270
+ type OthersSubscriptionCallback<TIO extends IOLike, TPresence extends Record<string, any>> = (value: readonly Id<UserInfo<TIO, TPresence>>[], event: OthersSubscriptionEvent<TIO, TPresence>) => void;
271
+ type OthersSubscriptionFn<TIO extends IOLike, TPresence extends Record<string, any>> = (callback: OthersSubscriptionCallback<TIO, TPresence>) => () => void;
272
+ interface StateNotifierSubjects<TIO extends IOLike, TPresence extends Record<string, any>> {
265
273
  connection: Subject<Id<WebSocketState<TIO>>>;
266
274
  "my-presence": Subject<TPresence | null>;
267
275
  myself: Subject<Readonly<Id<UserInfo<TIO, TPresence>>> | null>;
268
276
  others: Subject<readonly Id<UserInfo<TIO, TPresence>>[]>;
269
277
  "storage-loaded": Subject<boolean>;
270
278
  }
271
- type InferSubjectValue<TIO extends IOLike, TPresence extends JsonObject, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue> ? Id<IValue> : never;
272
- type SubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
273
- type UpdateMyPresenceAction<TPresence extends JsonObject> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
274
- interface UserInfo<TIO extends IOLike, TPresence extends JsonObject = {}> {
279
+ type InferSubjectValue<TIO extends IOLike, TPresence extends Record<string, any>, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue> ? Id<IValue> : never;
280
+ type SubscriptionCallback<TIO extends IOLike, TPresence extends Record<string, any>, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
281
+ type UpdateMyPresenceAction<TPresence extends Record<string, any>> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
282
+ interface UserInfo<TIO extends IOLike, TPresence extends Record<string, any> = {}> {
275
283
  connectionId: string;
276
284
  presence: TPresence;
277
285
  user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;
@@ -283,20 +291,16 @@ interface WebSocketConnection {
283
291
  * @date April 13, 2025
284
292
  */
285
293
  attempts: number;
286
- /**
287
- * @description How many times the user has connected to the room. This can be more than 1 in
288
- * the case of reconnects. This is tracked because on the very first connection (i.e. when
289
- * count is 0) we don't want to send the storage state as an update to the room and overwrite
290
- * the upstream state.
291
- * @date April 13, 2025
292
- */
293
- count: number;
294
294
  id: string | null;
295
295
  state: ConnectionState;
296
296
  }
297
+ interface StorageInfo {
298
+ state: StorageState;
299
+ }
297
300
  interface WebSocketState<TIO extends IOLike> {
298
301
  authorization: AuthorizationState<TIO>;
299
302
  connection: WebSocketConnection;
303
+ storage: StorageInfo;
300
304
  webSocket: WebSocket | null;
301
305
  }
302
306
  type BroadcastProxy<TIO extends IOLike, TEvents extends PluvRouterEventConfig> = (<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(event: TEvent, data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>) => Promise<void>) & {
@@ -317,7 +321,7 @@ type StorageProxy<TStorage extends Record<string, CrdtType<any, any>>> = Storage
317
321
  [PKey in keyof TStorage]: (callback: StorageSubscriptionCallback<TStorage, PKey>) => () => void;
318
322
  };
319
323
  type SubscribeFn<TValue extends unknown> = (callback: (value: TValue) => void) => () => void;
320
- type SubscribeProxy<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig> = (<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(name: TSubject, callback: SubscriptionCallback<TIO, TPresence, TSubject>) => () => void) & {
324
+ type SubscribeProxy<TIO extends IOLike, TPresence extends Record<string, any>, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig> = (<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(name: TSubject, callback: SubscriptionCallback<TIO, TPresence, TSubject>) => () => void) & {
321
325
  connection: SubscribeFn<Id<WebSocketState<TIO>>>;
322
326
  event: EventProxy<TIO, TEvents>;
323
327
  myPresence: SubscribeFn<TPresence | null>;
@@ -327,13 +331,23 @@ type SubscribeProxy<TIO extends IOLike, TPresence extends JsonObject, TStorage e
327
331
  storage: StorageProxy<TStorage>;
328
332
  storageLoaded: SubscribeFn<boolean>;
329
333
  };
330
- interface RoomLike<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig = {}> {
334
+ interface RoomEventListenerMap {
335
+ close: (event: CloseEvent | null) => void;
336
+ error: (event: Event) => void;
337
+ message: (event: MessageEvent<any>) => void;
338
+ open: (event: Event) => void;
339
+ }
340
+ interface RoomLike<TIO extends IOLike, TDoc extends any, TPresence extends Record<string, any> = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig = {}> {
331
341
  id: string;
332
- storageLoaded: boolean;
333
342
  broadcast: BroadcastProxy<TIO, TEvents>;
343
+ /**
344
+ * @deprecated To be removed in v3. Use getStorageLoaded instead.
345
+ */
346
+ storageLoaded: boolean;
347
+ addEventListener<TKind extends keyof RoomEventListenerMap>(kind: TKind, handler: RoomEventListenerMap[TKind]): () => void;
334
348
  canRedo(): boolean;
335
349
  canUndo(): boolean;
336
- getDoc(): CrdtDocLike<TStorage>;
350
+ getDoc(): CrdtDocLike<TDoc, TStorage>;
337
351
  event: EventProxy<TIO, TEvents>;
338
352
  getConnection(): WebSocketConnection;
339
353
  getMyPresence(): TPresence;
@@ -343,6 +357,7 @@ interface RoomLike<TIO extends IOLike, TPresence extends JsonObject = {}, TStora
343
357
  getStorage<TKey extends keyof TStorage>(type: TKey): TStorage[TKey] | null;
344
358
  getStorageJson(): InferCrdtJson<TStorage> | null;
345
359
  getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
360
+ getStorageLoaded: () => boolean;
346
361
  other(connectionId: string, callback: OtherSubscriptionCallback<TIO, TPresence>): () => void;
347
362
  redo(): void;
348
363
  storage: StorageProxy<TStorage>;
@@ -355,4 +370,4 @@ interface RoomLike<TIO extends IOLike, TPresence extends JsonObject = {}, TStora
355
370
  updateMyPresence(presence: UpdateMyPresenceAction<TPresence>): void;
356
371
  }
357
372
 
358
- export { type BaseClientEventRecord, type BaseClientMessage, type BaseIOEventRecord, type BaseUser, type BroadcastProxy, ConnectionState, type Constructable, type CrdtDocLike, type CrdtType, type DeepPartial, type DeepWriteable, type DocApplyEncodedStateParams, type DocBatchApplyEncodedStateParams, type DocSubscribeCallbackParams, type EventMessage, type EventNotifierSubscriptionCallback, type EventProxy, type EventRecord, type GetEventMessage, type IOAuthorize, type IOAuthorizeEventMessage, type IOEventMessage, type IOLike, type IORouterLike, type Id, type InferEventMessage, type InferEventsInput, type InferEventsOutput, type InferIOAuthorize, type InferIOAuthorizeUser, type InferIOInput, type InferIOOutput, type InputZodLike, type Json, type JsonObject, type JsonPrimitive, type Maybe, type MaybePromise, type MaybeReadonlyArray, type MergeEvents, type NonNilProps, type OptionalProps, type OtherSubscriptionCallback, type OtherSubscriptionFn, type OthersSubscriptionCallback, type OthersSubscriptionEvent, type OthersSubscriptionFn, type ProcedureLike, type RoomLike, type Spread, type SpreadProperties, type StateNotifierSubjects, type StorageProxy, type StorageRootSubscriptionCallback, type StorageRootSubscriptionFn, type StorageSubscriptionCallback, type StorageSubscriptionFn, type SubscribeFn, type SubscribeProxy, type SubscriptionCallback, type UndefinedProps, type UpdateMyPresenceAction, type UserInfo, type WebSocketConnection, type WebSocketState };
373
+ export { type BaseClientEventRecord, type BaseClientMessage, type BaseIOEventRecord, type BaseUser, type BroadcastProxy, ConnectionState, type Constructable, type CrdtDocLike, type CrdtType, type DeepPartial, type DeepWriteable, type DocApplyEncodedStateParams, type DocBatchApplyEncodedStateParams, type DocSubscribeCallbackParams, type EventMessage, type EventNotifierSubscriptionCallback, type EventProxy, type EventRecord, type GetEventMessage, type IOAuthorize, type IOAuthorizeEventMessage, type IOEventMessage, type IOLike, type IORouterLike, type Id, type InferCrdtJson, type InferEventMessage, type InferEventsInput, type InferEventsOutput, type InferIOAuthorize, type InferIOAuthorizeUser, type InferIOInput, type InferIOOutput, type InputZodLike, type Json, type JsonObject, type JsonPrimitive, type Maybe, type MaybePromise, type MaybeReadonlyArray, type MergeEvents, type NonNilProps, type OptionalProps, type OtherSubscriptionCallback, type OtherSubscriptionFn, type OthersSubscriptionCallback, type OthersSubscriptionEvent, type OthersSubscriptionFn, type PluvRouterEventConfig, type ProcedureLike, type RoomEventListenerMap, type RoomLike, type Spread, type SpreadProperties, type StateNotifierSubjects, type StorageInfo, type StorageProxy, type StorageRootSubscriptionCallback, type StorageRootSubscriptionFn, StorageState, type StorageSubscriptionCallback, type StorageSubscriptionFn, type SubscribeFn, type SubscribeProxy, type SubscriptionCallback, type UndefinedProps, type UpdateMyPresenceAction, type UserInfo, type WebSocketConnection, type WebSocketState };
package/dist/index.js CHANGED
@@ -20,19 +20,27 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- ConnectionState: () => ConnectionState
23
+ ConnectionState: () => ConnectionState,
24
+ StorageState: () => StorageState
24
25
  });
25
26
  module.exports = __toCommonJS(index_exports);
26
27
 
27
28
  // src/pluv/enums.ts
28
29
  var ConnectionState = {
29
- Closed: "Closed",
30
- Connecting: "Connecting",
31
- Open: "Open",
32
- Unavailable: "Unavailable",
33
- Untouched: "Untouched"
30
+ Closed: "closed",
31
+ Connecting: "connecting",
32
+ Open: "open",
33
+ Unavailable: "unavailable",
34
+ Untouched: "untouched"
35
+ };
36
+ var StorageState = {
37
+ Loading: "loading",
38
+ Offline: "offline",
39
+ Synced: "synced",
40
+ Unavailable: "unavailable"
34
41
  };
35
42
  // Annotate the CommonJS export names for ESM import in node:
36
43
  0 && (module.exports = {
37
- ConnectionState
44
+ ConnectionState,
45
+ StorageState
38
46
  });
package/dist/index.mjs CHANGED
@@ -1,11 +1,18 @@
1
1
  // src/pluv/enums.ts
2
2
  var ConnectionState = {
3
- Closed: "Closed",
4
- Connecting: "Connecting",
5
- Open: "Open",
6
- Unavailable: "Unavailable",
7
- Untouched: "Untouched"
3
+ Closed: "closed",
4
+ Connecting: "connecting",
5
+ Open: "open",
6
+ Unavailable: "unavailable",
7
+ Untouched: "untouched"
8
+ };
9
+ var StorageState = {
10
+ Loading: "loading",
11
+ Offline: "offline",
12
+ Synced: "synced",
13
+ Unavailable: "unavailable"
8
14
  };
9
15
  export {
10
- ConnectionState
16
+ ConnectionState,
17
+ StorageState
11
18
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/types",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "description": "@pluv/io shared types",
5
5
  "author": "leedavidcs",
6
6
  "license": "MIT",
@@ -19,8 +19,8 @@
19
19
  "eslint": "^9.26.0",
20
20
  "tsup": "^8.4.0",
21
21
  "typescript": "^5.8.3",
22
- "@pluv/tsconfig": "^2.1.0",
23
- "eslint-config-pluv": "^2.1.0"
22
+ "@pluv/tsconfig": "^2.2.1",
23
+ "eslint-config-pluv": "^2.2.1"
24
24
  },
25
25
  "dependencies": {
26
26
  "wonka": "^6.3.5"
package/src/index.ts CHANGED
@@ -15,7 +15,7 @@ export type {
15
15
  SpreadProperties,
16
16
  UndefinedProps,
17
17
  } from "./general";
18
- export { ConnectionState } from "./pluv";
18
+ export { ConnectionState, StorageState } from "./pluv";
19
19
  export type {
20
20
  BaseClientEventRecord,
21
21
  BaseClientMessage,
@@ -32,6 +32,7 @@ export type {
32
32
  EventProxy,
33
33
  EventRecord,
34
34
  GetEventMessage,
35
+ InferCrdtJson,
35
36
  InferEventMessage,
36
37
  InferEventsInput,
37
38
  InferEventsOutput,
@@ -51,9 +52,12 @@ export type {
51
52
  OthersSubscriptionFn,
52
53
  OtherSubscriptionCallback,
53
54
  OtherSubscriptionFn,
55
+ PluvRouterEventConfig,
54
56
  ProcedureLike,
57
+ RoomEventListenerMap,
55
58
  RoomLike,
56
59
  StateNotifierSubjects,
60
+ StorageInfo,
57
61
  StorageProxy,
58
62
  StorageRootSubscriptionCallback,
59
63
  StorageRootSubscriptionFn,
package/src/pluv/crdt.ts CHANGED
@@ -30,14 +30,22 @@ export interface DocBatchApplyEncodedStateParams {
30
30
  updates?: Maybe<readonly Maybe<string | Uint8Array>[]>;
31
31
  }
32
32
 
33
- export interface DocSubscribeCallbackParams<TStorage extends Record<string, CrdtType<any, any>>> {
34
- doc: CrdtDocLike<TStorage>;
33
+ export interface DocSubscribeCallbackParams<
34
+ TDoc extends any,
35
+ TStorage extends Record<string, CrdtType<any, any>>,
36
+ > {
37
+ doc: CrdtDocLike<TDoc, TStorage>;
35
38
  local: boolean;
36
39
  origin?: string | null;
37
40
  update: string;
38
41
  }
39
42
 
40
- export interface CrdtDocLike<TStorage extends Record<string, CrdtType<any, any>>> {
43
+ export interface CrdtDocLike<
44
+ TDoc extends any,
45
+ TStorage extends Record<string, CrdtType<any, any>>,
46
+ > {
47
+ value: TDoc;
48
+
41
49
  applyEncodedState(params: DocApplyEncodedStateParams): this;
42
50
  batchApplyEncodedState(params: DocBatchApplyEncodedStateParams): this;
43
51
  canRedo(): boolean;
@@ -49,7 +57,7 @@ export interface CrdtDocLike<TStorage extends Record<string, CrdtType<any, any>>
49
57
  isEmpty(): boolean;
50
58
  rebuildStorage(reference: TStorage): this;
51
59
  redo(): this;
52
- subscribe(listener: (params: DocSubscribeCallbackParams<TStorage>) => void): () => void;
60
+ subscribe(listener: (params: DocSubscribeCallbackParams<TDoc, TStorage>) => void): () => void;
53
61
  toJson(): InferCrdtJson<TStorage>;
54
62
  toJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]>;
55
63
  track(): this;
package/src/pluv/enums.ts CHANGED
@@ -1,9 +1,18 @@
1
1
  export const ConnectionState = {
2
- Closed: "Closed",
3
- Connecting: "Connecting",
4
- Open: "Open",
5
- Unavailable: "Unavailable",
6
- Untouched: "Untouched",
2
+ Closed: "closed",
3
+ Connecting: "connecting",
4
+ Open: "open",
5
+ Unavailable: "unavailable",
6
+ Untouched: "untouched",
7
7
  } as const;
8
8
 
9
9
  export type ConnectionState = (typeof ConnectionState)[keyof typeof ConnectionState];
10
+
11
+ export const StorageState = {
12
+ Loading: "loading",
13
+ Offline: "offline",
14
+ Synced: "synced",
15
+ Unavailable: "unavailable",
16
+ };
17
+
18
+ export type StorageState = (typeof StorageState)[keyof typeof StorageState];
package/src/pluv/room.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Subject } from "wonka";
2
2
  import type { Id, JsonObject } from "../general";
3
3
  import type { CrdtDocLike, CrdtType, InferCrdtJson } from "./crdt";
4
- import type { ConnectionState } from "./enums";
4
+ import type { ConnectionState, StorageState } from "./enums";
5
5
  import type {
6
6
  InferIOAuthorize,
7
7
  InferIOAuthorizeUser,
@@ -18,32 +18,35 @@ export interface AuthorizationState<TIO extends IOLike> {
18
18
  user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>> | null;
19
19
  }
20
20
 
21
- export type OtherSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (
21
+ export type OtherSubscriptionCallback<TIO extends IOLike, TPresence extends Record<string, any>> = (
22
22
  value: Id<UserInfo<TIO, TPresence>> | null,
23
23
  ) => void;
24
24
 
25
- export type OtherSubscriptionFn<TIO extends IOLike, TPresence extends JsonObject> = (
25
+ export type OtherSubscriptionFn<TIO extends IOLike, TPresence extends Record<string, any>> = (
26
26
  connectionId: string,
27
27
  callback: OtherSubscriptionCallback<TIO, TPresence>,
28
28
  ) => () => void;
29
29
 
30
- export type OthersSubscriptionEvent<TIO extends IOLike, TPresence extends JsonObject> =
30
+ export type OthersSubscriptionEvent<TIO extends IOLike, TPresence extends Record<string, any>> =
31
31
  | { kind: "clear" }
32
32
  | { kind: "enter"; user: Id<UserInfo<TIO, TPresence>> }
33
33
  | { kind: "leave"; user: Id<UserInfo<TIO, TPresence>> }
34
34
  | { kind: "sync"; users: readonly Id<UserInfo<TIO, TPresence>>[] }
35
35
  | { kind: "update"; user: Id<UserInfo<TIO, TPresence>> };
36
36
 
37
- export type OthersSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (
37
+ export type OthersSubscriptionCallback<
38
+ TIO extends IOLike,
39
+ TPresence extends Record<string, any>,
40
+ > = (
38
41
  value: readonly Id<UserInfo<TIO, TPresence>>[],
39
42
  event: OthersSubscriptionEvent<TIO, TPresence>,
40
43
  ) => void;
41
44
 
42
- export type OthersSubscriptionFn<TIO extends IOLike, TPresence extends JsonObject> = (
45
+ export type OthersSubscriptionFn<TIO extends IOLike, TPresence extends Record<string, any>> = (
43
46
  callback: OthersSubscriptionCallback<TIO, TPresence>,
44
47
  ) => () => void;
45
48
 
46
- export interface StateNotifierSubjects<TIO extends IOLike, TPresence extends JsonObject> {
49
+ export interface StateNotifierSubjects<TIO extends IOLike, TPresence extends Record<string, any>> {
47
50
  connection: Subject<Id<WebSocketState<TIO>>>;
48
51
  "my-presence": Subject<TPresence | null>;
49
52
  myself: Subject<Readonly<Id<UserInfo<TIO, TPresence>>> | null>;
@@ -53,7 +56,7 @@ export interface StateNotifierSubjects<TIO extends IOLike, TPresence extends Jso
53
56
 
54
57
  type InferSubjectValue<
55
58
  TIO extends IOLike,
56
- TPresence extends JsonObject,
59
+ TPresence extends Record<string, any>,
57
60
  TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
58
61
  > =
59
62
  StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue>
@@ -62,15 +65,15 @@ type InferSubjectValue<
62
65
 
63
66
  export type SubscriptionCallback<
64
67
  TIO extends IOLike,
65
- TPresence extends JsonObject,
68
+ TPresence extends Record<string, any>,
66
69
  TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
67
70
  > = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
68
71
 
69
- export type UpdateMyPresenceAction<TPresence extends JsonObject> =
72
+ export type UpdateMyPresenceAction<TPresence extends Record<string, any>> =
70
73
  | Partial<TPresence>
71
74
  | ((oldPresence: TPresence | null) => Partial<TPresence>);
72
75
 
73
- export interface UserInfo<TIO extends IOLike, TPresence extends JsonObject = {}> {
76
+ export interface UserInfo<TIO extends IOLike, TPresence extends Record<string, any> = {}> {
74
77
  connectionId: string;
75
78
  presence: TPresence;
76
79
  user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;
@@ -83,21 +86,18 @@ export interface WebSocketConnection {
83
86
  * @date April 13, 2025
84
87
  */
85
88
  attempts: number;
86
- /**
87
- * @description How many times the user has connected to the room. This can be more than 1 in
88
- * the case of reconnects. This is tracked because on the very first connection (i.e. when
89
- * count is 0) we don't want to send the storage state as an update to the room and overwrite
90
- * the upstream state.
91
- * @date April 13, 2025
92
- */
93
- count: number;
94
89
  id: string | null;
95
90
  state: ConnectionState;
96
91
  }
97
92
 
93
+ export interface StorageInfo {
94
+ state: StorageState;
95
+ }
96
+
98
97
  export interface WebSocketState<TIO extends IOLike> {
99
98
  authorization: AuthorizationState<TIO>;
100
99
  connection: WebSocketConnection;
100
+ storage: StorageInfo;
101
101
  webSocket: WebSocket | null;
102
102
  }
103
103
 
@@ -164,7 +164,7 @@ export type SubscribeFn<TValue extends unknown> = (callback: (value: TValue) =>
164
164
 
165
165
  export type SubscribeProxy<
166
166
  TIO extends IOLike,
167
- TPresence extends JsonObject,
167
+ TPresence extends Record<string, any>,
168
168
  TStorage extends Record<string, CrdtType<any, any>>,
169
169
  TEvents extends PluvRouterEventConfig,
170
170
  > = (<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(
@@ -181,22 +181,37 @@ export type SubscribeProxy<
181
181
  storageLoaded: SubscribeFn<boolean>;
182
182
  };
183
183
 
184
+ export interface RoomEventListenerMap {
185
+ close: (event: CloseEvent | null) => void;
186
+ error: (event: Event) => void;
187
+ message: (event: MessageEvent<any>) => void;
188
+ open: (event: Event) => void;
189
+ }
190
+
184
191
  export interface RoomLike<
185
192
  TIO extends IOLike,
186
- TPresence extends JsonObject = {},
193
+ TDoc extends any,
194
+ TPresence extends Record<string, any> = {},
187
195
  TStorage extends Record<string, CrdtType<any, any>> = {},
188
196
  TEvents extends PluvRouterEventConfig = {},
189
197
  > {
190
198
  id: string;
199
+ broadcast: BroadcastProxy<TIO, TEvents>;
200
+ /**
201
+ * @deprecated To be removed in v3. Use getStorageLoaded instead.
202
+ */
191
203
  storageLoaded: boolean;
192
204
 
193
- broadcast: BroadcastProxy<TIO, TEvents>;
205
+ addEventListener<TKind extends keyof RoomEventListenerMap>(
206
+ kind: TKind,
207
+ handler: RoomEventListenerMap[TKind],
208
+ ): () => void;
194
209
 
195
210
  canRedo(): boolean;
196
211
 
197
212
  canUndo(): boolean;
198
213
 
199
- getDoc(): CrdtDocLike<TStorage>;
214
+ getDoc(): CrdtDocLike<TDoc, TStorage>;
200
215
 
201
216
  event: EventProxy<TIO, TEvents>;
202
217
 
@@ -215,6 +230,8 @@ export interface RoomLike<
215
230
  getStorageJson(): InferCrdtJson<TStorage> | null;
216
231
  getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
217
232
 
233
+ getStorageLoaded: () => boolean;
234
+
218
235
  other(connectionId: string, callback: OtherSubscriptionCallback<TIO, TPresence>): () => void;
219
236
 
220
237
  redo(): void;