@pluv/io 0.3.9 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -224,6 +224,10 @@ var AbstractWebSocket = class {
224
224
  // src/PluvIO.ts
225
225
  import colors2 from "kleur";
226
226
 
227
+ // src/IORoom.ts
228
+ import { doc } from "@pluv/crdt-yjs";
229
+ import colors from "kleur";
230
+
227
231
  // src/authorize.ts
228
232
  import hkdf from "@panva/hkdf";
229
233
  import { EncryptJWT, jwtDecrypt } from "jose";
@@ -261,8 +265,6 @@ var authorize = (params) => {
261
265
  };
262
266
 
263
267
  // src/IORoom.ts
264
- import { doc } from "@pluv/crdt-yjs";
265
- import colors from "kleur";
266
268
  var PING_TIMEOUT_MS = 3e4;
267
269
  var IORoom = class {
268
270
  constructor(id, config) {
@@ -359,101 +361,12 @@ var IORoom = class {
359
361
  sessionId,
360
362
  user != null ? user : {}
361
363
  );
364
+ const onClose = this._onClose(session, uninitializeWs).bind(this);
365
+ const onMessage = this._onMessage(session).bind(this);
366
+ pluvWs.addEventListener("close", onClose);
367
+ pluvWs.addEventListener("error", onClose);
368
+ pluvWs.addEventListener("message", onMessage);
362
369
  this._emitRegistered(session);
363
- this._emitStorageReceived(session);
364
- this._emitUserJoined(session);
365
- const context = {
366
- context: this._context,
367
- doc: this._doc,
368
- room: this.id,
369
- session,
370
- sessions: this._sessions
371
- };
372
- pluvWs.addEventListener("message", (event) => {
373
- if (!this._uninitialize)
374
- return;
375
- if (session.quit) {
376
- session.webSocket.close(1011, "WebSocket broken.");
377
- return;
378
- }
379
- const message = this._parseMessage(event);
380
- if (!message)
381
- return;
382
- const eventConfig = this._getEventConfig(message);
383
- if (!eventConfig)
384
- return;
385
- this._resolveMessage(message, context).then((output) => {
386
- var _a2, _b;
387
- if (!output)
388
- return;
389
- const eventType = (_b = (_a2 = eventConfig.options) == null ? void 0 : _a2.type) != null ? _b : "broadcast";
390
- switch (eventType) {
391
- case "self": {
392
- Object.entries(output).forEach(([type, data]) => {
393
- this._sendSelfMessage({ data, type }, session);
394
- });
395
- return;
396
- }
397
- case "sync": {
398
- this._platform.pubSub.publish(this.id, __spreadValues({
399
- connectionId: session.id,
400
- options: eventConfig.options,
401
- room: this.id,
402
- user: session.user
403
- }, message));
404
- Object.entries(output).forEach(([type, data]) => {
405
- this._sendSelfMessage({ data, type }, session);
406
- });
407
- return;
408
- }
409
- case "broadcast":
410
- default: {
411
- Object.entries(output).forEach(([type, data]) => {
412
- this._broadcast({
413
- message: { data, type },
414
- senderId: session.id
415
- });
416
- });
417
- }
418
- }
419
- });
420
- });
421
- const closeHandler = () => {
422
- if (!this._uninitialize)
423
- return;
424
- session.quit = true;
425
- this._logDebug(
426
- `${colors.blue(
427
- `(Unregistering connection for room ${this.id}:`
428
- )} ${sessionId}`
429
- );
430
- this._sessions.delete(session.id);
431
- this._platform.persistance.deleteUser(this.id, session.id).finally(() => {
432
- var _a2;
433
- this._broadcast({
434
- message: {
435
- type: "$EXIT",
436
- data: { sessionId: session.id }
437
- },
438
- senderId: session.id
439
- });
440
- uninitializeWs();
441
- const size2 = this.getSize();
442
- this._logDebug(
443
- `${colors.blue(
444
- `Unregistered connection for room ${this.id}:`
445
- )} ${sessionId}`
446
- );
447
- this._logDebug(
448
- `${colors.blue(`Room ${this.id} size:`)} ${size2}`
449
- );
450
- if (size2)
451
- return;
452
- (_a2 = this._uninitialize) == null ? void 0 : _a2.call(this);
453
- });
454
- };
455
- pluvWs.addEventListener("close", closeHandler);
456
- pluvWs.addEventListener("error", closeHandler);
457
370
  this._logDebug(
458
371
  `${colors.blue(
459
372
  `Registered connection for room ${this.id}:`
@@ -501,34 +414,6 @@ var IORoom = class {
501
414
  session
502
415
  );
503
416
  }
504
- _emitStorageReceived(session) {
505
- this._platform.persistance.getStorageState(this.id).then((_state) => __async(this, null, function* () {
506
- var _a, _b;
507
- const state = (_b = _state != null ? _state : yield (_a = this._initialStorage) == null ? void 0 : _a.call(this)) != null ? _b : this._doc.encodeStateAsUpdate();
508
- this._sendSelfMessage(
509
- {
510
- type: "$STORAGE_RECEIVED",
511
- data: { state }
512
- },
513
- session
514
- );
515
- }));
516
- }
517
- _emitUserJoined(session) {
518
- const user = session.user;
519
- if (!user)
520
- return;
521
- this._broadcast({
522
- message: {
523
- type: "$USER_JOINED",
524
- data: {
525
- connectionId: session.id,
526
- user
527
- }
528
- },
529
- senderId: session.id
530
- });
531
- }
532
417
  _getAuthorizedUser(token) {
533
418
  return __async(this, null, function* () {
534
419
  var _a;
@@ -567,6 +452,19 @@ var IORoom = class {
567
452
  var _a;
568
453
  return (_a = this._events[message.type]) != null ? _a : null;
569
454
  }
455
+ _getEventInputs(message) {
456
+ const eventConfig = this._getEventConfig(message);
457
+ if (!eventConfig)
458
+ return message.data;
459
+ return eventConfig.input ? eventConfig.input.parse(message.data) : message.data;
460
+ }
461
+ _getEventResolverObject(message) {
462
+ const eventConfig = this._getEventConfig(message);
463
+ if (!eventConfig)
464
+ return {};
465
+ const resolver = eventConfig.resolver;
466
+ return typeof resolver === "function" ? { broadcast: resolver } : __spreadValues({}, resolver);
467
+ }
570
468
  _initialize() {
571
469
  return __async(this, null, function* () {
572
470
  this._logDebug(`${colors.blue(`Initializing room ${this.id}:`)}`);
@@ -598,6 +496,105 @@ var IORoom = class {
598
496
  _logDebug(...data) {
599
497
  this._debug && console.log(...data);
600
498
  }
499
+ _onClose(session, callback) {
500
+ return () => {
501
+ if (!this._uninitialize)
502
+ return;
503
+ session.quit = true;
504
+ this._logDebug(
505
+ `${colors.blue(
506
+ `(Unregistering connection for room ${this.id}:`
507
+ )} ${session.id}`
508
+ );
509
+ this._sessions.delete(session.id);
510
+ this._platform.persistance.deleteUser(this.id, session.id).finally(() => {
511
+ var _a;
512
+ this._broadcast({
513
+ message: {
514
+ type: "$EXIT",
515
+ data: { sessionId: session.id }
516
+ },
517
+ senderId: session.id
518
+ });
519
+ callback == null ? void 0 : callback();
520
+ const size = this.getSize();
521
+ this._logDebug(
522
+ `${colors.blue(
523
+ `Unregistered connection for room ${this.id}:`
524
+ )} ${session.id}`
525
+ );
526
+ this._logDebug(
527
+ `${colors.blue(`Room ${this.id} size:`)} ${size}`
528
+ );
529
+ if (size)
530
+ return;
531
+ (_a = this._uninitialize) == null ? void 0 : _a.call(this);
532
+ });
533
+ };
534
+ }
535
+ _onMessage(session) {
536
+ return (event) => {
537
+ var _a, _b, _c;
538
+ const context = {
539
+ context: this._context,
540
+ doc: this._doc,
541
+ room: this.id,
542
+ session,
543
+ sessions: this._sessions
544
+ };
545
+ if (!this._uninitialize)
546
+ return;
547
+ if (session.quit) {
548
+ session.webSocket.close(1011, "WebSocket broken.");
549
+ return;
550
+ }
551
+ const message = this._parseMessage(event);
552
+ if (!message)
553
+ return;
554
+ const resolver = this._getEventResolverObject(message);
555
+ let inputs;
556
+ try {
557
+ inputs = this._getEventInputs(message);
558
+ } catch (error) {
559
+ session == null ? void 0 : session.webSocket.handleError({
560
+ error,
561
+ message: "Invalid input",
562
+ session
563
+ });
564
+ return;
565
+ }
566
+ Promise.all([
567
+ (_a = resolver.broadcast) == null ? void 0 : _a.call(resolver, inputs, context),
568
+ (_b = resolver.self) == null ? void 0 : _b.call(resolver, inputs, context),
569
+ (_c = resolver.sync) == null ? void 0 : _c.call(resolver, inputs, context)
570
+ ]).then(([broadcast, self, sync]) => {
571
+ if (broadcast) {
572
+ Object.entries(broadcast).forEach(([type, data]) => {
573
+ this._broadcast({
574
+ message: { data, type },
575
+ senderId: session.id
576
+ });
577
+ });
578
+ }
579
+ if (self) {
580
+ Object.entries(self).forEach(([type, data]) => {
581
+ this._sendSelfMessage({ data, type }, session);
582
+ });
583
+ }
584
+ if (sync) {
585
+ this._platform.pubSub.publish(this.id, __spreadValues({
586
+ connectionId: session.id,
587
+ options: { type: "sync" },
588
+ room: this.id,
589
+ user: session.user
590
+ }, message));
591
+ Object.entries(sync).forEach(([type, data]) => {
592
+ this._sendSelfMessage({ data, type }, session);
593
+ });
594
+ }
595
+ });
596
+ };
597
+ }
601
598
  _parseMessage(message) {
602
599
  const parsed = this._platform.parseData(message.data);
603
600
  try {
@@ -612,29 +609,6 @@ var IORoom = class {
612
609
  return null;
613
610
  }
614
611
  }
615
- _resolveMessage(message, context) {
616
- return __async(this, null, function* () {
617
- const { session } = context;
618
- const eventConfig = this._getEventConfig(message);
619
- if (!eventConfig)
620
- return null;
621
- let input;
622
- try {
623
- input = eventConfig.input ? eventConfig.input.parse(message.data) : message.data;
624
- } catch (error) {
625
- session == null ? void 0 : session.webSocket.handleError({
626
- error,
627
- message: "Invalid input",
628
- session
629
- });
630
- return null;
631
- }
632
- const output = yield eventConfig.resolver(input, context);
633
- if (!output)
634
- return null;
635
- return output;
636
- });
637
- }
638
612
  _sendMessage(message, sender, options = {}) {
639
613
  switch (options.type) {
640
614
  case "self": {
@@ -684,13 +658,23 @@ var IORoom = class {
684
658
  const senderId = sender == null ? void 0 : sender.id;
685
659
  if (!senderId)
686
660
  return;
687
- this._resolveMessage(message, {
661
+ const context = {
688
662
  context: this._context,
689
663
  doc: this._doc,
690
664
  room: this.id,
691
665
  session: null,
692
666
  sessions: this._sessions
693
- }).then((output) => {
667
+ };
668
+ const resolver = this._getEventResolverObject(message).sync;
669
+ if (!resolver)
670
+ return;
671
+ let inputs;
672
+ try {
673
+ inputs = this._getEventInputs(message);
674
+ } catch (e) {
675
+ return;
676
+ }
677
+ Promise.resolve(resolver(inputs, context)).then((output) => {
694
678
  if (!output)
695
679
  return;
696
680
  Object.keys(output).forEach((type) => {
@@ -717,32 +701,70 @@ var PluvIO = class {
717
701
  this._rooms = /* @__PURE__ */ new Map();
718
702
  this._authorize = null;
719
703
  this._events = {
720
- $PING: {
721
- resolver: (data, { session }) => {
722
- if (!session)
723
- return {};
724
- const currentTime = (/* @__PURE__ */ new Date()).getTime();
725
- session.timers.ping = currentTime;
726
- return { $PONG: {} };
727
- },
728
- options: { type: "self" }
729
- },
730
704
  $GET_OTHERS: {
731
- resolver: (data, { room, session, sessions }) => {
732
- const others = Array.from(sessions.entries()).filter(([, wsSession]) => wsSession.id !== (session == null ? void 0 : session.id)).reduce(
733
- (acc, [connectionId, { presence, user }]) => __spreadProps(__spreadValues({}, acc), {
734
- [connectionId]: {
735
- connectionId,
736
- presence,
737
- room,
738
- user
705
+ resolver: {
706
+ sync: (data, { room, session, sessions }) => {
707
+ const others = Array.from(sessions.entries()).filter(([, wsSession]) => wsSession.id !== (session == null ? void 0 : session.id)).reduce(
708
+ (acc, [connectionId, { presence, user }]) => __spreadProps(__spreadValues({}, acc), {
709
+ [connectionId]: {
710
+ connectionId,
711
+ presence,
712
+ room,
713
+ user
714
+ }
715
+ }),
716
+ {}
717
+ );
718
+ return { $OTHERS_RECEIVED: { others } };
719
+ }
720
+ }
721
+ },
722
+ $INITIALIZE_SESSION: {
723
+ resolver: {
724
+ broadcast: ({ presence }, { session }) => {
725
+ if (!session)
726
+ return {};
727
+ session.presence = presence;
728
+ return {
729
+ $USER_JOINED: {
730
+ connectionId: session.id,
731
+ user: session.user,
732
+ presence
739
733
  }
740
- }),
741
- {}
742
- );
743
- return { $OTHERS_RECEIVED: { others } };
744
- },
745
- options: { type: "sync" }
734
+ };
735
+ },
736
+ self: (_0, _1) => __async(this, [_0, _1], function* ({ update }, { doc: doc2, room }) {
737
+ var _a, _b;
738
+ const oldState = yield this._platform.persistance.getStorageState(room);
739
+ const updates = [
740
+ oldState ? null : yield (_a = this._initialStorage) == null ? void 0 : _a.call(this, room),
741
+ update
742
+ ];
743
+ if (updates.some((_update) => !!_update)) {
744
+ const state2 = updates.reduce((_doc, _up) => _doc.applyUpdate(_up), doc2).encodeStateAsUpdate();
745
+ yield this._platform.persistance.setStorageState(
746
+ room,
747
+ state2
748
+ );
749
+ this._listeners.onStorageUpdated(room, state2);
750
+ }
751
+ const state = (_b = yield this._platform.persistance.getStorageState(
752
+ room
753
+ )) != null ? _b : doc2.encodeStateAsUpdate();
754
+ return { $STORAGE_RECEIVED: { state } };
755
+ })
756
+ }
757
+ },
758
+ $PING: {
759
+ resolver: {
760
+ self: (data, { session }) => {
761
+ if (!session)
762
+ return {};
763
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
764
+ session.timers.ping = currentTime;
765
+ return { $PONG: {} };
766
+ }
767
+ }
746
768
  },
747
769
  $UPDATE_PRESENCE: {
748
770
  resolver: ({ presence }, { session }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/io",
3
- "version": "0.3.9",
3
+ "version": "0.4.0",
4
4
  "description": "@pluv/io server-side websocket manager",
5
5
  "author": "leedavidcs",
6
6
  "license": "MIT",
@@ -17,12 +17,12 @@
17
17
  "access": "public"
18
18
  },
19
19
  "dependencies": {
20
- "@panva/hkdf": "^1.0.4",
21
- "jose": "^4.13.1",
20
+ "@panva/hkdf": "^1.1.1",
21
+ "jose": "^4.14.4",
22
22
  "kleur": "^4.1.5",
23
- "wonka": "^6.3.1",
24
- "@pluv/crdt-yjs": "^0.3.6",
25
- "@pluv/types": "^0.1.6"
23
+ "wonka": "^6.3.2",
24
+ "@pluv/crdt-yjs": "^0.3.7",
25
+ "@pluv/types": "^0.2.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "yjs": "^13.0.0"
@@ -30,9 +30,9 @@
30
30
  "devDependencies": {
31
31
  "tsup": "^6.7.0",
32
32
  "typescript": "^5.0.4",
33
- "yjs": "^13.5.52",
34
- "@pluv/tsconfig": "^0.1.5",
35
- "eslint-config-pluv": "^0.1.10"
33
+ "yjs": "^13.6.0",
34
+ "@pluv/tsconfig": "^0.1.6",
35
+ "eslint-config-pluv": "^0.1.11"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsup src/index.ts --format esm,cjs --dts",