@pluv/io 3.1.7 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
 
2
- > @pluv/io@3.1.7 build /home/runner/work/pluv/pluv/packages/io
2
+ > @pluv/io@3.2.0 build /home/runner/work/pluv/pluv/packages/io
3
3
  > pnpm run version && tsup src/index.ts --format esm,cjs --dts
4
4
 
5
5
 
6
- > @pluv/io@3.1.7 version /home/runner/work/pluv/pluv/packages/io
6
+ > @pluv/io@3.2.0 version /home/runner/work/pluv/pluv/packages/io
7
7
  > genversion ./src/version.generated.ts --esm
8
8
 
9
9
  CLI Building entry: src/index.ts
@@ -12,11 +12,11 @@
12
12
  CLI Target: es6
13
13
  ESM Build start
14
14
  CJS Build start
15
- CJS dist/index.js 55.74 KB
16
- CJS ⚡️ Build success in 106ms
17
- ESM dist/index.mjs 53.56 KB
18
- ESM ⚡️ Build success in 110ms
15
+ CJS dist/index.js 55.81 KB
16
+ CJS ⚡️ Build success in 118ms
17
+ ESM dist/index.mjs 53.63 KB
18
+ ESM ⚡️ Build success in 123ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 4281ms
21
- DTS dist/index.d.mts 34.07 KB
22
- DTS dist/index.d.ts 34.07 KB
20
+ DTS ⚡️ Build success in 4090ms
21
+ DTS dist/index.d.mts 34.23 KB
22
+ DTS dist/index.d.ts 34.23 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @pluv/io
2
2
 
3
+ ## 3.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6d2b257: Support async `context` parameter in `createIO`.
8
+
9
+ ### Patch Changes
10
+
11
+ - @pluv/crdt@3.2.0
12
+ - @pluv/types@3.2.0
13
+
3
14
  ## 3.1.7
4
15
 
5
16
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -121,7 +121,7 @@ declare class PluvRouter<TPlatform extends AbstractPlatform<any> = AbstractPlatf
121
121
  private _isValidEventName;
122
122
  }
123
123
 
124
- type PluvContext<TPlatform extends AbstractPlatform, TContext extends Record<string, any>> = TContext | ((params: InferRoomContextType<TPlatform>) => TContext);
124
+ type PluvContext<TPlatform extends AbstractPlatform, TContext extends Record<string, any>> = MaybePromise<TContext> | ((params: InferRoomContextType<TPlatform>) => MaybePromise<TContext>);
125
125
  type EventResolverKind = "broadcast" | "self" | "sync";
126
126
  type EventResolver<TKind extends EventResolverKind = EventResolverKind, TPlatform extends AbstractPlatform = AbstractPlatform, TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null = null, TContext extends Record<string, any> = {}, TInput extends JsonObject = {}, TOutput extends EventRecord<string, any> = {}> = (data: TInput, context: EventResolverContext<TKind, TPlatform, TAuthorize, TContext>) => MaybePromise<TOutput | void>;
127
127
  interface EventResolverContext<TKind extends EventResolverKind = EventResolverKind, TPlatform extends AbstractPlatform = AbstractPlatform, TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null = null, TContext extends Record<string, any> = {}> {
@@ -339,7 +339,7 @@ type BroadcastProxy<TIO extends IORoom<any, any, any, any, any>> = (<TEvent exte
339
339
  };
340
340
  type IORoomConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null = any, TContext extends Record<string, any> = {}, TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {}> = Partial<IORoomListeners<TPlatform, TAuthorize, TContext, TEvents>> & {
341
341
  authorize?: TAuthorize;
342
- context: TContext;
342
+ context: PluvContext<TPlatform, TContext>;
343
343
  crdt?: {
344
344
  doc: (value: any) => AbstractCrdtDocFactory<any, any>;
345
345
  };
@@ -365,6 +365,7 @@ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
365
365
  private readonly _getInitialStorage;
366
366
  private readonly _listeners;
367
367
  private readonly _platform;
368
+ private readonly _roomContext;
368
369
  private readonly _router;
369
370
  private readonly _sessions;
370
371
  private readonly _userSessionss;
@@ -414,6 +415,7 @@ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
414
415
  private _ensureDetached;
415
416
  private _getAbstractWs;
416
417
  private _getAuthorizedUser;
418
+ private _getContext;
417
419
  private _getInitialDoc;
418
420
  private _getIOAuthorize;
419
421
  private _getLatestPresence;
@@ -460,6 +462,7 @@ type CreateRoomOptions<TPlatform extends AbstractPlatform<any, any>, TAuthorize
460
462
  declare class PluvServer<TPlatform extends AbstractPlatform<any, any> = AbstractPlatform<any, any>, TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null = any, TContext extends Record<string, any> = {}, TCrdt extends CrdtLibraryType$1<any> = CrdtLibraryType$1<any>, TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {}> implements IOLike<TAuthorize, TCrdt, TEvents> {
461
463
  readonly version: string;
462
464
  private readonly _config;
465
+ private readonly _docFactory;
463
466
  get fetch(): (...args: any[]) => Promise<any>;
464
467
  /**
465
468
  * @ignore
@@ -468,7 +471,7 @@ declare class PluvServer<TPlatform extends AbstractPlatform<any, any> = Abstract
468
471
  */
469
472
  get _defs(): {
470
473
  authorize: TAuthorize;
471
- context: TContext;
474
+ context: PluvContext<TPlatform, TContext>;
472
475
  crdt: TCrdt;
473
476
  events: TEvents;
474
477
  platform: TPlatform;
package/dist/index.d.ts CHANGED
@@ -121,7 +121,7 @@ declare class PluvRouter<TPlatform extends AbstractPlatform<any> = AbstractPlatf
121
121
  private _isValidEventName;
122
122
  }
123
123
 
124
- type PluvContext<TPlatform extends AbstractPlatform, TContext extends Record<string, any>> = TContext | ((params: InferRoomContextType<TPlatform>) => TContext);
124
+ type PluvContext<TPlatform extends AbstractPlatform, TContext extends Record<string, any>> = MaybePromise<TContext> | ((params: InferRoomContextType<TPlatform>) => MaybePromise<TContext>);
125
125
  type EventResolverKind = "broadcast" | "self" | "sync";
126
126
  type EventResolver<TKind extends EventResolverKind = EventResolverKind, TPlatform extends AbstractPlatform = AbstractPlatform, TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null = null, TContext extends Record<string, any> = {}, TInput extends JsonObject = {}, TOutput extends EventRecord<string, any> = {}> = (data: TInput, context: EventResolverContext<TKind, TPlatform, TAuthorize, TContext>) => MaybePromise<TOutput | void>;
127
127
  interface EventResolverContext<TKind extends EventResolverKind = EventResolverKind, TPlatform extends AbstractPlatform = AbstractPlatform, TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null = null, TContext extends Record<string, any> = {}> {
@@ -339,7 +339,7 @@ type BroadcastProxy<TIO extends IORoom<any, any, any, any, any>> = (<TEvent exte
339
339
  };
340
340
  type IORoomConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null = any, TContext extends Record<string, any> = {}, TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {}> = Partial<IORoomListeners<TPlatform, TAuthorize, TContext, TEvents>> & {
341
341
  authorize?: TAuthorize;
342
- context: TContext;
342
+ context: PluvContext<TPlatform, TContext>;
343
343
  crdt?: {
344
344
  doc: (value: any) => AbstractCrdtDocFactory<any, any>;
345
345
  };
@@ -365,6 +365,7 @@ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
365
365
  private readonly _getInitialStorage;
366
366
  private readonly _listeners;
367
367
  private readonly _platform;
368
+ private readonly _roomContext;
368
369
  private readonly _router;
369
370
  private readonly _sessions;
370
371
  private readonly _userSessionss;
@@ -414,6 +415,7 @@ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
414
415
  private _ensureDetached;
415
416
  private _getAbstractWs;
416
417
  private _getAuthorizedUser;
418
+ private _getContext;
417
419
  private _getInitialDoc;
418
420
  private _getIOAuthorize;
419
421
  private _getLatestPresence;
@@ -460,6 +462,7 @@ type CreateRoomOptions<TPlatform extends AbstractPlatform<any, any>, TAuthorize
460
462
  declare class PluvServer<TPlatform extends AbstractPlatform<any, any> = AbstractPlatform<any, any>, TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null = any, TContext extends Record<string, any> = {}, TCrdt extends CrdtLibraryType$1<any> = CrdtLibraryType$1<any>, TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {}> implements IOLike<TAuthorize, TCrdt, TEvents> {
461
463
  readonly version: string;
462
464
  private readonly _config;
465
+ private readonly _docFactory;
463
466
  get fetch(): (...args: any[]) => Promise<any>;
464
467
  /**
465
468
  * @ignore
@@ -468,7 +471,7 @@ declare class PluvServer<TPlatform extends AbstractPlatform<any, any> = Abstract
468
471
  */
469
472
  get _defs(): {
470
473
  authorize: TAuthorize;
471
- context: TContext;
474
+ context: PluvContext<TPlatform, TContext>;
472
475
  crdt: TCrdt;
473
476
  events: TEvents;
474
477
  platform: TPlatform;
package/dist/index.js CHANGED
@@ -455,6 +455,7 @@ var IORoom = class {
455
455
  this._debug = debug;
456
456
  this._docFactory = crdt.doc(() => ({}));
457
457
  this._getInitialStorage = getInitialStorage;
458
+ this._roomContext = roomContext;
458
459
  this._router = router;
459
460
  this._platform = platform.initialize(__spreadProps(__spreadValues({}, !!_meta ? { _meta } : {}), { roomContext }));
460
461
  this._listeners = {
@@ -671,11 +672,11 @@ var IORoom = class {
671
672
  const user = session.user;
672
673
  if (!!user) this._removeUserSession(user.id, sessionId);
673
674
  try {
674
- const doc = yield this._doc;
675
+ const [doc, context] = yield Promise.all([this._doc, this._getContext()]);
675
676
  const encodedState = doc.getEncodedState();
676
677
  yield Promise.resolve(
677
678
  this._listeners.onUserDisconnected({
678
- context: this._context,
679
+ context,
679
680
  encodedState,
680
681
  platform: this._platform,
681
682
  room: this.id,
@@ -716,7 +717,7 @@ var IORoom = class {
716
717
  const sessionId = session.id;
717
718
  const presence = session.presence;
718
719
  const user = session.user;
719
- const doc = yield this._doc;
720
+ const [doc, context] = yield Promise.all([this._doc, this._getContext()]);
720
721
  const encodedState = doc.isEmpty() ? null : doc.getEncodedState();
721
722
  yield this._sendSelfMessage(
722
723
  {
@@ -733,7 +734,7 @@ var IORoom = class {
733
734
  try {
734
735
  yield Promise.resolve(
735
736
  this._listeners.onUserConnected({
736
- context: this._context,
737
+ context,
737
738
  encodedState,
738
739
  platform: this._platform,
739
740
  room: this.id,
@@ -803,20 +804,25 @@ var IORoom = class {
803
804
  }
804
805
  });
805
806
  }
807
+ _getContext() {
808
+ return __async(this, null, function* () {
809
+ return typeof this._context === "function" ? yield Promise.resolve(this._context(this._roomContext)) : yield Promise.resolve(this._context);
810
+ });
811
+ }
806
812
  _getInitialDoc() {
807
813
  return __async(this, null, function* () {
808
814
  const doc = this._docFactory.getEmpty();
809
- const encodedState = yield this._platform.persistence.getStorageState(this.id);
815
+ const [encodedState, context] = yield Promise.all([
816
+ this._platform.persistence.getStorageState(this.id),
817
+ this._getContext()
818
+ ]);
810
819
  if (!encodedState) {
811
820
  const loadedState = yield this._getInitialStorage({
812
- context: this._context,
821
+ context,
813
822
  room: this.id
814
823
  });
815
- const checkDoc = this._crdt.doc(() => ({})).getEmpty().applyEncodedState({ update: loadedState });
816
- const isEmpty = checkDoc.isEmpty();
817
- checkDoc.destroy();
818
- if (!!loadedState && !isEmpty) {
819
- doc.applyEncodedState({ update: loadedState }).getEncodedState();
824
+ if (!!loadedState && !this._docFactory.isEmpty(loadedState)) {
825
+ doc.applyEncodedState({ update: loadedState });
820
826
  }
821
827
  }
822
828
  if (typeof encodedState === "string") doc.applyEncodedState({ update: encodedState });
@@ -903,13 +909,13 @@ var IORoom = class {
903
909
  const doc = yield this._getInitialDoc();
904
910
  const uninitialize = () => __async(this, null, function* () {
905
911
  this._platform.pubSub.unsubscribe(pubSubId);
906
- const doc2 = yield this._doc;
912
+ const [doc2, context] = yield Promise.all([this._doc, this._getContext()]);
907
913
  const encodedState = doc2.getEncodedState();
908
914
  doc2.destroy();
909
915
  this._doc = Promise.resolve(this._docFactory.getEmpty());
910
916
  yield Promise.resolve(
911
917
  this._listeners.onDestroy(__spreadProps(__spreadValues({}, "_meta" in this._platform && !!this._platform._meta ? { _meta: this._platform._meta } : {}), {
912
- context: this._context,
918
+ context,
913
919
  encodedState,
914
920
  platform: this._platform,
915
921
  room: this.id
@@ -943,9 +949,9 @@ var IORoom = class {
943
949
  const setPresence = (params) => {
944
950
  this._setPresence.bind(this)(params);
945
951
  };
946
- const doc = yield this._doc;
952
+ const [doc, context] = yield Promise.all([this._doc, this._getContext()]);
947
953
  const eventContext = {
948
- context: this._context,
954
+ context,
949
955
  doc,
950
956
  garbageCollect: () => __async(this, null, function* () {
951
957
  yield this.garbageCollect();
@@ -974,7 +980,7 @@ var IORoom = class {
974
980
  if (!message) return;
975
981
  const procedure = this._getProcedure(message);
976
982
  this._listeners.onMessage(__spreadProps(__spreadValues({}, "_meta" in this._platform && !!this._platform._meta ? { _meta: this._platform._meta } : {}), {
977
- context: this._context,
983
+ context,
978
984
  encodedState: doc.getEncodedState(),
979
985
  message,
980
986
  platform: this._platform,
@@ -1137,9 +1143,9 @@ var IORoom = class {
1137
1143
  if (!sender) return;
1138
1144
  const connectionId = sender.sessionId;
1139
1145
  if (typeof connectionId !== "string") return;
1140
- const doc = yield this._doc;
1141
- const context = {
1142
- context: this._context,
1146
+ const [doc, context] = yield Promise.all([this._doc, this._getContext()]);
1147
+ const resolverCtx = {
1148
+ context,
1143
1149
  doc,
1144
1150
  garbageCollect: () => __async(this, null, function* () {
1145
1151
  yield this.garbageCollect();
@@ -1164,7 +1170,7 @@ var IORoom = class {
1164
1170
  } catch (e) {
1165
1171
  return;
1166
1172
  }
1167
- Promise.resolve(resolver(inputs, context)).then((output) => {
1173
+ Promise.resolve(resolver(inputs, resolverCtx)).then((output) => {
1168
1174
  if (!output) return;
1169
1175
  Object.keys(output).forEach((type) => {
1170
1176
  var _a2, _b;
@@ -1184,7 +1190,7 @@ var IORoom = class {
1184
1190
  };
1185
1191
 
1186
1192
  // src/version.generated.ts
1187
- var version = "3.1.7";
1193
+ var version = "3.2.0";
1188
1194
 
1189
1195
  // src/PluvServer.ts
1190
1196
  var PluvServer = class {
@@ -1207,6 +1213,7 @@ var PluvServer = class {
1207
1213
  onUserConnected,
1208
1214
  onUserDisconnected
1209
1215
  } = options;
1216
+ this._docFactory = this._config.crdt.doc(() => ({}));
1210
1217
  this._listeners = {
1211
1218
  onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
1212
1219
  onRoomMessage: (event) => onRoomMessage == null ? void 0 : onRoomMessage(event),
@@ -1281,11 +1288,8 @@ var PluvServer = class {
1281
1288
  const update = data == null ? void 0 : data.update;
1282
1289
  if (!oldState) {
1283
1290
  const loadedState = yield this._getInitialStorage({ context, room });
1284
- const checkDoc = this._config.crdt.doc(() => ({})).getEmpty().applyEncodedState({ update: loadedState });
1285
- const isEmpty = checkDoc.isEmpty();
1286
- checkDoc.destroy();
1287
- if (!!loadedState && !isEmpty) {
1288
- doc.applyEncodedState({ update: loadedState }).getEncodedState();
1291
+ if (!!loadedState && !this._docFactory.isEmpty(loadedState)) {
1292
+ doc.applyEncodedState({ update: loadedState });
1289
1293
  }
1290
1294
  }
1291
1295
  if (!doc.isEmpty()) {
@@ -1398,12 +1402,11 @@ var PluvServer = class {
1398
1402
  if (!/^[a-z0-9](?:[a-z0-9-_]*[a-z0-9])?$/i.test(room))
1399
1403
  throw new Error("Unsupported room name");
1400
1404
  const roomContext = platformRoomContext;
1401
- const context = typeof this._config.context === "function" ? this._config.context(roomContext) : this._config.context;
1402
1405
  const listeners = this._getListeners();
1403
1406
  const logDebug = this._logDebug.bind(this);
1404
1407
  const newRoom = new IORoom(room, __spreadProps(__spreadValues({}, !!_meta ? { _meta } : {}), {
1405
1408
  authorize: (_c = this._config.authorize) != null ? _c : void 0,
1406
- context,
1409
+ context: this._config.context,
1407
1410
  crdt: this._config.crdt,
1408
1411
  debug: debug != null ? debug : this._config.debug,
1409
1412
  getInitialStorage: this._getInitialStorage,
package/dist/index.mjs CHANGED
@@ -413,6 +413,7 @@ var IORoom = class {
413
413
  this._debug = debug;
414
414
  this._docFactory = crdt.doc(() => ({}));
415
415
  this._getInitialStorage = getInitialStorage;
416
+ this._roomContext = roomContext;
416
417
  this._router = router;
417
418
  this._platform = platform.initialize(__spreadProps(__spreadValues({}, !!_meta ? { _meta } : {}), { roomContext }));
418
419
  this._listeners = {
@@ -629,11 +630,11 @@ var IORoom = class {
629
630
  const user = session.user;
630
631
  if (!!user) this._removeUserSession(user.id, sessionId);
631
632
  try {
632
- const doc = yield this._doc;
633
+ const [doc, context] = yield Promise.all([this._doc, this._getContext()]);
633
634
  const encodedState = doc.getEncodedState();
634
635
  yield Promise.resolve(
635
636
  this._listeners.onUserDisconnected({
636
- context: this._context,
637
+ context,
637
638
  encodedState,
638
639
  platform: this._platform,
639
640
  room: this.id,
@@ -674,7 +675,7 @@ var IORoom = class {
674
675
  const sessionId = session.id;
675
676
  const presence = session.presence;
676
677
  const user = session.user;
677
- const doc = yield this._doc;
678
+ const [doc, context] = yield Promise.all([this._doc, this._getContext()]);
678
679
  const encodedState = doc.isEmpty() ? null : doc.getEncodedState();
679
680
  yield this._sendSelfMessage(
680
681
  {
@@ -691,7 +692,7 @@ var IORoom = class {
691
692
  try {
692
693
  yield Promise.resolve(
693
694
  this._listeners.onUserConnected({
694
- context: this._context,
695
+ context,
695
696
  encodedState,
696
697
  platform: this._platform,
697
698
  room: this.id,
@@ -761,20 +762,25 @@ var IORoom = class {
761
762
  }
762
763
  });
763
764
  }
765
+ _getContext() {
766
+ return __async(this, null, function* () {
767
+ return typeof this._context === "function" ? yield Promise.resolve(this._context(this._roomContext)) : yield Promise.resolve(this._context);
768
+ });
769
+ }
764
770
  _getInitialDoc() {
765
771
  return __async(this, null, function* () {
766
772
  const doc = this._docFactory.getEmpty();
767
- const encodedState = yield this._platform.persistence.getStorageState(this.id);
773
+ const [encodedState, context] = yield Promise.all([
774
+ this._platform.persistence.getStorageState(this.id),
775
+ this._getContext()
776
+ ]);
768
777
  if (!encodedState) {
769
778
  const loadedState = yield this._getInitialStorage({
770
- context: this._context,
779
+ context,
771
780
  room: this.id
772
781
  });
773
- const checkDoc = this._crdt.doc(() => ({})).getEmpty().applyEncodedState({ update: loadedState });
774
- const isEmpty = checkDoc.isEmpty();
775
- checkDoc.destroy();
776
- if (!!loadedState && !isEmpty) {
777
- doc.applyEncodedState({ update: loadedState }).getEncodedState();
782
+ if (!!loadedState && !this._docFactory.isEmpty(loadedState)) {
783
+ doc.applyEncodedState({ update: loadedState });
778
784
  }
779
785
  }
780
786
  if (typeof encodedState === "string") doc.applyEncodedState({ update: encodedState });
@@ -861,13 +867,13 @@ var IORoom = class {
861
867
  const doc = yield this._getInitialDoc();
862
868
  const uninitialize = () => __async(this, null, function* () {
863
869
  this._platform.pubSub.unsubscribe(pubSubId);
864
- const doc2 = yield this._doc;
870
+ const [doc2, context] = yield Promise.all([this._doc, this._getContext()]);
865
871
  const encodedState = doc2.getEncodedState();
866
872
  doc2.destroy();
867
873
  this._doc = Promise.resolve(this._docFactory.getEmpty());
868
874
  yield Promise.resolve(
869
875
  this._listeners.onDestroy(__spreadProps(__spreadValues({}, "_meta" in this._platform && !!this._platform._meta ? { _meta: this._platform._meta } : {}), {
870
- context: this._context,
876
+ context,
871
877
  encodedState,
872
878
  platform: this._platform,
873
879
  room: this.id
@@ -901,9 +907,9 @@ var IORoom = class {
901
907
  const setPresence = (params) => {
902
908
  this._setPresence.bind(this)(params);
903
909
  };
904
- const doc = yield this._doc;
910
+ const [doc, context] = yield Promise.all([this._doc, this._getContext()]);
905
911
  const eventContext = {
906
- context: this._context,
912
+ context,
907
913
  doc,
908
914
  garbageCollect: () => __async(this, null, function* () {
909
915
  yield this.garbageCollect();
@@ -932,7 +938,7 @@ var IORoom = class {
932
938
  if (!message) return;
933
939
  const procedure = this._getProcedure(message);
934
940
  this._listeners.onMessage(__spreadProps(__spreadValues({}, "_meta" in this._platform && !!this._platform._meta ? { _meta: this._platform._meta } : {}), {
935
- context: this._context,
941
+ context,
936
942
  encodedState: doc.getEncodedState(),
937
943
  message,
938
944
  platform: this._platform,
@@ -1095,9 +1101,9 @@ var IORoom = class {
1095
1101
  if (!sender) return;
1096
1102
  const connectionId = sender.sessionId;
1097
1103
  if (typeof connectionId !== "string") return;
1098
- const doc = yield this._doc;
1099
- const context = {
1100
- context: this._context,
1104
+ const [doc, context] = yield Promise.all([this._doc, this._getContext()]);
1105
+ const resolverCtx = {
1106
+ context,
1101
1107
  doc,
1102
1108
  garbageCollect: () => __async(this, null, function* () {
1103
1109
  yield this.garbageCollect();
@@ -1122,7 +1128,7 @@ var IORoom = class {
1122
1128
  } catch (e) {
1123
1129
  return;
1124
1130
  }
1125
- Promise.resolve(resolver(inputs, context)).then((output) => {
1131
+ Promise.resolve(resolver(inputs, resolverCtx)).then((output) => {
1126
1132
  if (!output) return;
1127
1133
  Object.keys(output).forEach((type) => {
1128
1134
  var _a2, _b;
@@ -1142,7 +1148,7 @@ var IORoom = class {
1142
1148
  };
1143
1149
 
1144
1150
  // src/version.generated.ts
1145
- var version = "3.1.7";
1151
+ var version = "3.2.0";
1146
1152
 
1147
1153
  // src/PluvServer.ts
1148
1154
  var PluvServer = class {
@@ -1165,6 +1171,7 @@ var PluvServer = class {
1165
1171
  onUserConnected,
1166
1172
  onUserDisconnected
1167
1173
  } = options;
1174
+ this._docFactory = this._config.crdt.doc(() => ({}));
1168
1175
  this._listeners = {
1169
1176
  onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
1170
1177
  onRoomMessage: (event) => onRoomMessage == null ? void 0 : onRoomMessage(event),
@@ -1239,11 +1246,8 @@ var PluvServer = class {
1239
1246
  const update = data == null ? void 0 : data.update;
1240
1247
  if (!oldState) {
1241
1248
  const loadedState = yield this._getInitialStorage({ context, room });
1242
- const checkDoc = this._config.crdt.doc(() => ({})).getEmpty().applyEncodedState({ update: loadedState });
1243
- const isEmpty = checkDoc.isEmpty();
1244
- checkDoc.destroy();
1245
- if (!!loadedState && !isEmpty) {
1246
- doc.applyEncodedState({ update: loadedState }).getEncodedState();
1249
+ if (!!loadedState && !this._docFactory.isEmpty(loadedState)) {
1250
+ doc.applyEncodedState({ update: loadedState });
1247
1251
  }
1248
1252
  }
1249
1253
  if (!doc.isEmpty()) {
@@ -1356,12 +1360,11 @@ var PluvServer = class {
1356
1360
  if (!/^[a-z0-9](?:[a-z0-9-_]*[a-z0-9])?$/i.test(room))
1357
1361
  throw new Error("Unsupported room name");
1358
1362
  const roomContext = platformRoomContext;
1359
- const context = typeof this._config.context === "function" ? this._config.context(roomContext) : this._config.context;
1360
1363
  const listeners = this._getListeners();
1361
1364
  const logDebug = this._logDebug.bind(this);
1362
1365
  const newRoom = new IORoom(room, __spreadProps(__spreadValues({}, !!_meta ? { _meta } : {}), {
1363
1366
  authorize: (_c = this._config.authorize) != null ? _c : void 0,
1364
- context,
1367
+ context: this._config.context,
1365
1368
  crdt: this._config.crdt,
1366
1369
  debug: debug != null ? debug : this._config.debug,
1367
1370
  getInitialStorage: this._getInitialStorage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/io",
3
- "version": "3.1.7",
3
+ "version": "3.2.0",
4
4
  "description": "@pluv/io server-side websocket manager",
5
5
  "author": "leedavidcs",
6
6
  "license": "MIT",
@@ -21,16 +21,16 @@
21
21
  "jose": "^5.10.0",
22
22
  "kleur": "^4.1.5",
23
23
  "wonka": "^6.3.5",
24
- "@pluv/crdt": "^3.1.7",
25
- "@pluv/types": "^3.1.7"
24
+ "@pluv/crdt": "^3.2.0",
25
+ "@pluv/types": "^3.2.0"
26
26
  },
27
27
  "devDependencies": {
28
- "eslint": "^9.27.0",
28
+ "eslint": "^9.28.0",
29
29
  "genversion": "^3.2.0",
30
30
  "tsup": "^8.5.0",
31
31
  "typescript": "^5.8.3",
32
- "@pluv/tsconfig": "^3.1.7",
33
- "eslint-config-pluv": "^3.1.7"
32
+ "@pluv/tsconfig": "^3.2.0",
33
+ "eslint-config-pluv": "^3.2.0"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "pnpm run version && tsup src/index.ts --format esm,cjs --dts",
package/src/IORoom.ts CHANGED
@@ -41,6 +41,7 @@ import type {
41
41
  IORoomMessageEvent,
42
42
  IOUserConnectedEvent,
43
43
  IOUserDisconnectedEvent,
44
+ PluvContext,
44
45
  PluvIOAuthorize,
45
46
  ResolvedPluvIOAuthorize,
46
47
  WebSocketSession,
@@ -89,7 +90,7 @@ export type IORoomConfig<
89
90
  TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {},
90
91
  > = Partial<IORoomListeners<TPlatform, TAuthorize, TContext, TEvents>> & {
91
92
  authorize?: TAuthorize;
92
- context: TContext;
93
+ context: PluvContext<TPlatform, TContext>;
93
94
  crdt?: { doc: (value: any) => AbstractCrdtDocFactory<any, any> };
94
95
  debug: boolean;
95
96
  getInitialStorage: GetInitialStorageFn<TContext>;
@@ -134,13 +135,14 @@ export class IORoom<
134
135
  private _uninitialize: Promise<() => Promise<void>> | null = null;
135
136
 
136
137
  private readonly _authorize: TAuthorize = null as TAuthorize;
137
- private readonly _context: TContext;
138
+ private readonly _context: PluvContext<TPlatform, TContext>;
138
139
  private readonly _crdt: TCrdt;
139
140
  private readonly _debug: boolean;
140
141
  private readonly _docFactory: AbstractCrdtDocFactory<any, any>;
141
142
  private readonly _getInitialStorage: GetInitialStorageFn<TContext>;
142
143
  private readonly _listeners: IORoomListeners<TPlatform, TAuthorize, TContext, TEvents>;
143
144
  private readonly _platform: TPlatform;
145
+ private readonly _roomContext: InferRoomContextType<TPlatform>;
144
146
  private readonly _router: PluvRouter<TPlatform, TAuthorize, TContext, TEvents>;
145
147
  private readonly _sessions = new Map<
146
148
  [sessionId: string][0],
@@ -214,6 +216,7 @@ export class IORoom<
214
216
  this._debug = debug;
215
217
  this._docFactory = crdt.doc(() => ({}));
216
218
  this._getInitialStorage = getInitialStorage;
219
+ this._roomContext = roomContext;
217
220
  this._router = router;
218
221
  this._platform = platform.initialize({ ...(!!_meta ? { _meta } : {}), roomContext });
219
222
 
@@ -478,12 +481,12 @@ export class IORoom<
478
481
  if (!!user) this._removeUserSession(user.id, sessionId);
479
482
 
480
483
  try {
481
- const doc = await this._doc;
484
+ const [doc, context] = await Promise.all([this._doc, this._getContext()]);
482
485
  const encodedState = doc.getEncodedState();
483
486
 
484
487
  await Promise.resolve(
485
488
  this._listeners.onUserDisconnected({
486
- context: this._context,
489
+ context,
487
490
  encodedState,
488
491
  platform: this._platform,
489
492
  room: this.id,
@@ -531,7 +534,7 @@ export class IORoom<
531
534
  const presence = session.presence;
532
535
  const user = session.user;
533
536
 
534
- const doc = await this._doc;
537
+ const [doc, context] = await Promise.all([this._doc, this._getContext()]);
535
538
  const encodedState = doc.isEmpty() ? null : doc.getEncodedState();
536
539
 
537
540
  await this._sendSelfMessage(
@@ -550,7 +553,7 @@ export class IORoom<
550
553
  try {
551
554
  await Promise.resolve(
552
555
  this._listeners.onUserConnected({
553
- context: this._context,
556
+ context,
554
557
  encodedState,
555
558
  platform: this._platform,
556
559
  room: this.id,
@@ -641,25 +644,28 @@ export class IORoom<
641
644
  }
642
645
  }
643
646
 
647
+ private async _getContext(): Promise<TContext> {
648
+ return typeof this._context === "function"
649
+ ? await Promise.resolve(this._context(this._roomContext))
650
+ : await Promise.resolve(this._context);
651
+ }
652
+
644
653
  private async _getInitialDoc(): Promise<CrdtDocLike<any, any>> {
645
654
  const doc = this._docFactory.getEmpty();
646
- const encodedState = await this._platform.persistence.getStorageState(this.id);
655
+
656
+ const [encodedState, context] = await Promise.all([
657
+ this._platform.persistence.getStorageState(this.id),
658
+ this._getContext(),
659
+ ]);
647
660
 
648
661
  if (!encodedState) {
649
662
  const loadedState = await this._getInitialStorage({
650
- context: this._context,
663
+ context,
651
664
  room: this.id,
652
665
  });
653
666
 
654
- const checkDoc = this._crdt
655
- .doc(() => ({}))
656
- .getEmpty()
657
- .applyEncodedState({ update: loadedState });
658
- const isEmpty = checkDoc.isEmpty();
659
- checkDoc.destroy();
660
-
661
- if (!!loadedState && !isEmpty) {
662
- doc.applyEncodedState({ update: loadedState }).getEncodedState();
667
+ if (!!loadedState && !this._docFactory.isEmpty(loadedState)) {
668
+ doc.applyEncodedState({ update: loadedState });
663
669
  }
664
670
  }
665
671
 
@@ -789,7 +795,7 @@ export class IORoom<
789
795
  const uninitialize = async () => {
790
796
  this._platform.pubSub.unsubscribe(pubSubId);
791
797
 
792
- const doc = await this._doc;
798
+ const [doc, context] = await Promise.all([this._doc, this._getContext()]);
793
799
  const encodedState = doc.getEncodedState();
794
800
 
795
801
  doc.destroy();
@@ -800,7 +806,7 @@ export class IORoom<
800
806
  ...("_meta" in this._platform && !!this._platform._meta
801
807
  ? { _meta: this._platform._meta }
802
808
  : {}),
803
- context: this._context,
809
+ context,
804
810
  encodedState,
805
811
  platform: this._platform,
806
812
  room: this.id,
@@ -847,14 +853,14 @@ export class IORoom<
847
853
  this._setPresence.bind(this)(params);
848
854
  };
849
855
 
850
- const doc = await this._doc;
856
+ const [doc, context] = await Promise.all([this._doc, this._getContext()]);
851
857
  const eventContext: EventResolverContext<
852
858
  EventResolverKind,
853
859
  TPlatform,
854
860
  TAuthorize,
855
861
  TContext
856
862
  > = {
857
- context: this._context,
863
+ context,
858
864
  doc,
859
865
  garbageCollect: async () => {
860
866
  await this.garbageCollect();
@@ -893,7 +899,7 @@ export class IORoom<
893
899
  ...("_meta" in this._platform && !!this._platform._meta
894
900
  ? { _meta: this._platform._meta }
895
901
  : {}),
896
- context: this._context,
902
+ context,
897
903
  encodedState: doc.getEncodedState(),
898
904
  message: message as InferEventMessage<
899
905
  InferEventsOutput<TEvents>,
@@ -1134,9 +1140,9 @@ export class IORoom<
1134
1140
 
1135
1141
  if (typeof connectionId !== "string") return;
1136
1142
 
1137
- const doc = await this._doc;
1138
- const context: EventResolverContext<"sync", TPlatform, TAuthorize, TContext> = {
1139
- context: this._context,
1143
+ const [doc, context] = await Promise.all([this._doc, this._getContext()]);
1144
+ const resolverCtx: EventResolverContext<"sync", TPlatform, TAuthorize, TContext> = {
1145
+ context,
1140
1146
  doc,
1141
1147
  garbageCollect: async () => {
1142
1148
  await this.garbageCollect();
@@ -1166,7 +1172,7 @@ export class IORoom<
1166
1172
  return;
1167
1173
  }
1168
1174
 
1169
- Promise.resolve(resolver(inputs, context)).then((output) => {
1175
+ Promise.resolve(resolver(inputs, resolverCtx)).then((output) => {
1170
1176
  if (!output) return;
1171
1177
 
1172
1178
  Object.keys(output).forEach((type: string) => {
package/src/PluvServer.ts CHANGED
@@ -108,6 +108,7 @@ export class PluvServer<
108
108
  private readonly _config: NonNilProps<
109
109
  PluvServerConfig<TPlatform, TAuthorize, TContext, TCrdt, TEvents>
110
110
  >;
111
+ private readonly _docFactory: AbstractCrdtDocFactory<any, any>;
111
112
 
112
113
  public get fetch(): (...args: any[]) => Promise<any> {
113
114
  return (...args: any[]): Promise<any> => {
@@ -136,7 +137,7 @@ export class PluvServer<
136
137
  platform: this._config.platform(),
137
138
  } as {
138
139
  authorize: TAuthorize;
139
- context: TContext;
140
+ context: PluvContext<TPlatform, TContext>;
140
141
  crdt: TCrdt;
141
142
  events: TEvents;
142
143
  platform: TPlatform;
@@ -211,15 +212,8 @@ export class PluvServer<
211
212
  if (!oldState) {
212
213
  const loadedState = await this._getInitialStorage({ context, room });
213
214
 
214
- const checkDoc = this._config.crdt
215
- .doc(() => ({}))
216
- .getEmpty()
217
- .applyEncodedState({ update: loadedState });
218
- const isEmpty = checkDoc.isEmpty();
219
- checkDoc.destroy();
220
-
221
- if (!!loadedState && !isEmpty) {
222
- doc.applyEncodedState({ update: loadedState }).getEncodedState();
215
+ if (!!loadedState && !this._docFactory.isEmpty(loadedState)) {
216
+ doc.applyEncodedState({ update: loadedState });
223
217
  }
224
218
  }
225
219
 
@@ -390,6 +384,7 @@ export class PluvServer<
390
384
  onUserDisconnected,
391
385
  } = options as Partial<BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>>;
392
386
 
387
+ this._docFactory = this._config.crdt.doc(() => ({}));
393
388
  (this as any)._listeners = {
394
389
  onRoomDeleted: (event) => onRoomDeleted?.(event),
395
390
  onRoomMessage: (event) => onRoomMessage?.(event),
@@ -418,17 +413,13 @@ export class PluvServer<
418
413
  throw new Error("Unsupported room name");
419
414
 
420
415
  const roomContext = platformRoomContext as InferRoomContextType<TPlatform>;
421
- const context: TContext =
422
- typeof this._config.context === "function"
423
- ? this._config.context(roomContext)
424
- : this._config.context;
425
416
  const listeners = this._getListeners();
426
417
  const logDebug = this._logDebug.bind(this);
427
418
 
428
419
  const newRoom = new IORoom<TPlatform, TAuthorize, TContext, TCrdt, TEvents>(room, {
429
420
  ...(!!_meta ? { _meta } : {}),
430
421
  authorize: this._config.authorize ?? undefined,
431
- context,
422
+ context: this._config.context,
432
423
  crdt: this._config.crdt,
433
424
  debug: debug ?? this._config.debug,
434
425
  getInitialStorage: this._getInitialStorage,
package/src/types.ts CHANGED
@@ -25,8 +25,8 @@ import type { AbstractWebSocket } from "./AbstractWebSocket";
25
25
  import type { PluvRouter, PluvRouterEventConfig } from "./PluvRouter";
26
26
 
27
27
  export type PluvContext<TPlatform extends AbstractPlatform, TContext extends Record<string, any>> =
28
- | TContext
29
- | ((params: InferRoomContextType<TPlatform>) => TContext);
28
+ | MaybePromise<TContext>
29
+ | ((params: InferRoomContextType<TPlatform>) => MaybePromise<TContext>);
30
30
 
31
31
  export type EventResolverKind = "broadcast" | "self" | "sync";
32
32
 
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '3.1.7'
2
+ export const version = '3.2.0'