@pluv/client 0.25.4 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +9 -9
- package/CHANGELOG.md +179 -0
- package/dist/index.d.mts +163 -77
- package/dist/index.d.ts +163 -77
- package/dist/index.js +318 -189
- package/dist/index.mjs +318 -189
- package/package.json +7 -7
- package/src/AbstractRoom.ts +6 -4
- package/src/MockedRoom.ts +115 -27
- package/src/PluvClient.ts +80 -28
- package/src/PluvProcedure.ts +81 -0
- package/src/PluvRoom.ts +113 -45
- package/src/PluvRouter.ts +70 -0
- package/src/createClient.ts +11 -3
- package/src/enums.ts +7 -0
- package/src/index.ts +5 -3
- package/src/types.ts +43 -7
- package/src/utils/identity.ts +1 -0
- package/src/utils/index.ts +1 -0
package/dist/index.mjs
CHANGED
|
@@ -52,6 +52,41 @@ var AbstractStorageStore = class {
|
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
// src/PluvProcedure.ts
|
|
56
|
+
var PluvProcedure = class _PluvProcedure {
|
|
57
|
+
constructor(config = {}) {
|
|
58
|
+
this._broadcast = null;
|
|
59
|
+
this._input = null;
|
|
60
|
+
const { broadcast, input } = config;
|
|
61
|
+
this._broadcast = broadcast != null ? broadcast : null;
|
|
62
|
+
this._input = input != null ? input : null;
|
|
63
|
+
}
|
|
64
|
+
get config() {
|
|
65
|
+
var _a, _b, _c;
|
|
66
|
+
return {
|
|
67
|
+
broadcast: (_b = (_a = this._broadcast) == null ? void 0 : _a.bind(this)) != null ? _b : null,
|
|
68
|
+
input: (_c = this._input) != null ? _c : null,
|
|
69
|
+
resolver: this._resolver()
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
broadcast(resolver) {
|
|
73
|
+
const { broadcast } = this.config;
|
|
74
|
+
if (!!broadcast) throw new Error("Broadcast was already defined for this procedure");
|
|
75
|
+
return new _PluvProcedure(__spreadProps(__spreadValues({}, this.config), {
|
|
76
|
+
broadcast: resolver
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
input(input) {
|
|
80
|
+
return new _PluvProcedure({ input });
|
|
81
|
+
}
|
|
82
|
+
_resolver() {
|
|
83
|
+
return (data, context) => {
|
|
84
|
+
var _a;
|
|
85
|
+
return (_a = this._broadcast) == null ? void 0 : _a.call(this, data, context);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
55
90
|
// src/CrdtManager.ts
|
|
56
91
|
import { noop } from "@pluv/crdt";
|
|
57
92
|
var CrdtManager = class {
|
|
@@ -179,6 +214,21 @@ var OtherNotifier = class {
|
|
|
179
214
|
}
|
|
180
215
|
};
|
|
181
216
|
|
|
217
|
+
// src/PluvRouter.ts
|
|
218
|
+
var PluvRouter = class _PluvRouter {
|
|
219
|
+
constructor(events) {
|
|
220
|
+
this._defs = { events: {} };
|
|
221
|
+
this._defs = { events };
|
|
222
|
+
}
|
|
223
|
+
static merge(...routers) {
|
|
224
|
+
const events = Object.assign(/* @__PURE__ */ Object.create(null), ...routers.map((router) => router._defs.events));
|
|
225
|
+
if (Object.keys(events).some((key) => key.startsWith("$"))) {
|
|
226
|
+
throw new Error('Procedures may not start with "$"');
|
|
227
|
+
}
|
|
228
|
+
return new _PluvRouter(events);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
182
232
|
// src/StateNotifier.ts
|
|
183
233
|
import { makeSubject as makeSubject4, subscribe as subscribe4 } from "wonka";
|
|
184
234
|
var StateNotifier = class {
|
|
@@ -199,6 +249,31 @@ var StateNotifier = class {
|
|
|
199
249
|
}
|
|
200
250
|
};
|
|
201
251
|
|
|
252
|
+
// src/StorageStore.ts
|
|
253
|
+
var StorageStore = class extends AbstractStorageStore {
|
|
254
|
+
addUpdate() {
|
|
255
|
+
return Promise.resolve();
|
|
256
|
+
}
|
|
257
|
+
applyUpdates() {
|
|
258
|
+
return Promise.resolve();
|
|
259
|
+
}
|
|
260
|
+
destroy() {
|
|
261
|
+
return Promise.resolve();
|
|
262
|
+
}
|
|
263
|
+
flatten() {
|
|
264
|
+
return Promise.resolve();
|
|
265
|
+
}
|
|
266
|
+
getShouldFlatten() {
|
|
267
|
+
return Promise.resolve(false);
|
|
268
|
+
}
|
|
269
|
+
getUpdates() {
|
|
270
|
+
return Promise.resolve([]);
|
|
271
|
+
}
|
|
272
|
+
initialize() {
|
|
273
|
+
return Promise.resolve();
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
202
277
|
// src/UsersManager.ts
|
|
203
278
|
var UsersManager = class {
|
|
204
279
|
constructor(config) {
|
|
@@ -292,7 +367,7 @@ var UsersManager = class {
|
|
|
292
367
|
}
|
|
293
368
|
};
|
|
294
369
|
|
|
295
|
-
// src/
|
|
370
|
+
// src/enums.ts
|
|
296
371
|
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
297
372
|
ConnectionState2["Closed"] = "Closed";
|
|
298
373
|
ConnectionState2["Connecting"] = "Connecting";
|
|
@@ -302,179 +377,6 @@ var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
|
302
377
|
return ConnectionState2;
|
|
303
378
|
})(ConnectionState || {});
|
|
304
379
|
|
|
305
|
-
// src/MockedRoom.ts
|
|
306
|
-
var MockedRoom = class extends AbstractRoom {
|
|
307
|
-
constructor(room, options) {
|
|
308
|
-
const { events, initialPresence, initialStorage, presence } = options;
|
|
309
|
-
super(room);
|
|
310
|
-
this._crdtNotifier = new CrdtNotifier();
|
|
311
|
-
this._eventNotifier = new EventNotifier();
|
|
312
|
-
this._otherNotifier = new OtherNotifier();
|
|
313
|
-
this._state = {
|
|
314
|
-
authorization: {
|
|
315
|
-
token: null,
|
|
316
|
-
user: null
|
|
317
|
-
},
|
|
318
|
-
connection: {
|
|
319
|
-
count: 1,
|
|
320
|
-
id: null,
|
|
321
|
-
state: "Untouched" /* Untouched */
|
|
322
|
-
},
|
|
323
|
-
webSocket: null
|
|
324
|
-
};
|
|
325
|
-
this._stateNotifier = new StateNotifier();
|
|
326
|
-
this._subscriptions = {
|
|
327
|
-
observeCrdt: null
|
|
328
|
-
};
|
|
329
|
-
this.canRedo = () => {
|
|
330
|
-
return !!this._crdtManager.doc.canRedo();
|
|
331
|
-
};
|
|
332
|
-
this.canUndo = () => {
|
|
333
|
-
return !!this._crdtManager.doc.canUndo();
|
|
334
|
-
};
|
|
335
|
-
this.event = (event, callback) => {
|
|
336
|
-
return this._eventNotifier.subscribe(event, callback);
|
|
337
|
-
};
|
|
338
|
-
this.getConnection = () => {
|
|
339
|
-
return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));
|
|
340
|
-
};
|
|
341
|
-
this.getMyPresence = () => {
|
|
342
|
-
return this._usersManager.myPresence;
|
|
343
|
-
};
|
|
344
|
-
this.getMyself = () => {
|
|
345
|
-
return this._usersManager.myself;
|
|
346
|
-
};
|
|
347
|
-
this.getOther = (connectionId) => {
|
|
348
|
-
return this._usersManager.getOther(connectionId);
|
|
349
|
-
};
|
|
350
|
-
this.getOthers = () => {
|
|
351
|
-
return this._usersManager.getOthers();
|
|
352
|
-
};
|
|
353
|
-
this.getStorage = (type) => {
|
|
354
|
-
const sharedType = this._crdtManager.get(type);
|
|
355
|
-
if (typeof sharedType === "undefined") return null;
|
|
356
|
-
return sharedType;
|
|
357
|
-
};
|
|
358
|
-
this.other = (connectionId, callback) => {
|
|
359
|
-
return this._otherNotifier.subscribe(connectionId, callback);
|
|
360
|
-
};
|
|
361
|
-
this.redo = () => {
|
|
362
|
-
this._crdtManager.doc.redo();
|
|
363
|
-
};
|
|
364
|
-
this.storage = (key, fn) => {
|
|
365
|
-
return this._crdtNotifier.subscribe(key, fn);
|
|
366
|
-
};
|
|
367
|
-
this.storageRoot = (fn) => {
|
|
368
|
-
return this._crdtNotifier.subcribeRoot(fn);
|
|
369
|
-
};
|
|
370
|
-
this.subscribe = (name, callback) => {
|
|
371
|
-
return this._stateNotifier.subscribe(name, callback);
|
|
372
|
-
};
|
|
373
|
-
this.transact = (fn, origin) => {
|
|
374
|
-
const _origin = origin != null ? origin : this._state.connection.id;
|
|
375
|
-
const crdtManager = this._crdtManager;
|
|
376
|
-
if (typeof _origin !== "string") return;
|
|
377
|
-
if (!crdtManager) return;
|
|
378
|
-
crdtManager.doc.transact(() => {
|
|
379
|
-
const storage = crdtManager.doc.get();
|
|
380
|
-
fn(storage);
|
|
381
|
-
}, _origin);
|
|
382
|
-
};
|
|
383
|
-
this.undo = () => {
|
|
384
|
-
this._crdtManager.doc.undo();
|
|
385
|
-
};
|
|
386
|
-
this.updateMyPresence = (presence) => {
|
|
387
|
-
var _a;
|
|
388
|
-
const newPresence = typeof presence === "function" ? presence(this.getMyPresence()) : presence;
|
|
389
|
-
this._usersManager.updateMyPresence(newPresence);
|
|
390
|
-
const myPresence = this._usersManager.myPresence;
|
|
391
|
-
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
392
|
-
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
393
|
-
!!myself && this._stateNotifier.subjects["myself"].next(myself);
|
|
394
|
-
};
|
|
395
|
-
this._events = events;
|
|
396
|
-
this._usersManager = new UsersManager({
|
|
397
|
-
initialPresence,
|
|
398
|
-
presence
|
|
399
|
-
});
|
|
400
|
-
this._crdtManager = new CrdtManager({
|
|
401
|
-
initialStorage
|
|
402
|
-
});
|
|
403
|
-
this._observeCrdt();
|
|
404
|
-
}
|
|
405
|
-
get storageLoaded() {
|
|
406
|
-
return true;
|
|
407
|
-
}
|
|
408
|
-
broadcast(event, data) {
|
|
409
|
-
if (!this._events) return;
|
|
410
|
-
const resolver = this._events[event];
|
|
411
|
-
if (!resolver) return;
|
|
412
|
-
const result = resolver(data);
|
|
413
|
-
Object.keys(result).forEach((type) => {
|
|
414
|
-
const _type = type.toString();
|
|
415
|
-
const data2 = result[_type];
|
|
416
|
-
if (!data2) return;
|
|
417
|
-
this._eventNotifier.subject(_type).next(data2);
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
getDoc() {
|
|
421
|
-
return this._crdtManager.doc;
|
|
422
|
-
}
|
|
423
|
-
getStorageJson(type) {
|
|
424
|
-
if (this._state.connection.id === null) return null;
|
|
425
|
-
if (typeof type === "undefined") return this._crdtManager.doc.toJson();
|
|
426
|
-
return this._crdtManager.doc.toJson(type);
|
|
427
|
-
}
|
|
428
|
-
_observeCrdt() {
|
|
429
|
-
var _a, _b;
|
|
430
|
-
(_b = (_a = this._subscriptions).observeCrdt) == null ? void 0 : _b.call(_a);
|
|
431
|
-
if (!this._crdtManager) return;
|
|
432
|
-
const unsubscribe = this._crdtManager.doc.subscribe((event) => {
|
|
433
|
-
var _a2;
|
|
434
|
-
const origin = (_a2 = event.origin) != null ? _a2 : null;
|
|
435
|
-
if (!this._crdtManager) return;
|
|
436
|
-
if (origin === "$STORAGE_UPDATED") return;
|
|
437
|
-
const sharedTypes = this._crdtManager.doc.get();
|
|
438
|
-
const storageRoot = Object.keys(sharedTypes).reduce(
|
|
439
|
-
(acc, prop) => {
|
|
440
|
-
if (!this._crdtManager) return acc;
|
|
441
|
-
const serialized = this._crdtManager.doc.toJson(prop);
|
|
442
|
-
this._crdtNotifier.subject(prop).next(serialized);
|
|
443
|
-
return __spreadProps(__spreadValues({}, acc), { [prop]: serialized });
|
|
444
|
-
},
|
|
445
|
-
{}
|
|
446
|
-
);
|
|
447
|
-
this._crdtNotifier.rootSubject.next(storageRoot);
|
|
448
|
-
});
|
|
449
|
-
this._subscriptions.observeCrdt = unsubscribe;
|
|
450
|
-
}
|
|
451
|
-
};
|
|
452
|
-
|
|
453
|
-
// src/StorageStore.ts
|
|
454
|
-
var StorageStore = class extends AbstractStorageStore {
|
|
455
|
-
addUpdate() {
|
|
456
|
-
return Promise.resolve();
|
|
457
|
-
}
|
|
458
|
-
applyUpdates() {
|
|
459
|
-
return Promise.resolve();
|
|
460
|
-
}
|
|
461
|
-
destroy() {
|
|
462
|
-
return Promise.resolve();
|
|
463
|
-
}
|
|
464
|
-
flatten() {
|
|
465
|
-
return Promise.resolve();
|
|
466
|
-
}
|
|
467
|
-
getShouldFlatten() {
|
|
468
|
-
return Promise.resolve(false);
|
|
469
|
-
}
|
|
470
|
-
getUpdates() {
|
|
471
|
-
return Promise.resolve([]);
|
|
472
|
-
}
|
|
473
|
-
initialize() {
|
|
474
|
-
return Promise.resolve();
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
|
|
478
380
|
// src/utils/debounce.ts
|
|
479
381
|
var debounce = (fn, options) => {
|
|
480
382
|
const { wait, immediate = false } = options != null ? options : {};
|
|
@@ -512,8 +414,10 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
512
414
|
debug = false,
|
|
513
415
|
initialPresence,
|
|
514
416
|
initialStorage,
|
|
417
|
+
metadata,
|
|
515
418
|
onAuthorizationFail,
|
|
516
419
|
presence,
|
|
420
|
+
router,
|
|
517
421
|
wsEndpoint
|
|
518
422
|
} = options;
|
|
519
423
|
super(room);
|
|
@@ -522,6 +426,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
522
426
|
this._intervals = {
|
|
523
427
|
heartbeat: null
|
|
524
428
|
};
|
|
429
|
+
this._metadata = {};
|
|
525
430
|
this._otherNotifier = new OtherNotifier();
|
|
526
431
|
this._state = {
|
|
527
432
|
authorization: {
|
|
@@ -546,17 +451,37 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
546
451
|
this._windowListeners = null;
|
|
547
452
|
this._wsListeners = null;
|
|
548
453
|
this.broadcast = new Proxy(
|
|
549
|
-
(event, data) => {
|
|
454
|
+
(event, data) => __async(this, null, function* () {
|
|
550
455
|
if (!this._state.webSocket) return;
|
|
551
456
|
if (this._state.connection.state !== "Open" /* Open */) return;
|
|
552
457
|
const type = event.toString();
|
|
553
|
-
this.
|
|
554
|
-
|
|
458
|
+
const procedure = this._router._defs.events[type];
|
|
459
|
+
if (!(procedure == null ? void 0 : procedure.config.broadcast)) {
|
|
460
|
+
this._sendMessage({ data, type });
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const myself = this._usersManager.myself;
|
|
464
|
+
if (!myself) return;
|
|
465
|
+
const parsed = procedure.config.input ? procedure.config.input.parse(data) : data;
|
|
466
|
+
const context = {
|
|
467
|
+
doc: this._crdtManager.doc,
|
|
468
|
+
others: this._usersManager.getOthers(),
|
|
469
|
+
room: this.id,
|
|
470
|
+
user: myself
|
|
471
|
+
};
|
|
472
|
+
const output = yield procedure.config.broadcast(
|
|
473
|
+
parsed,
|
|
474
|
+
context
|
|
475
|
+
);
|
|
476
|
+
Object.entries(output).forEach(([_type, _data]) => {
|
|
477
|
+
this._sendMessage({ data: _data, type: _type });
|
|
478
|
+
});
|
|
479
|
+
}),
|
|
555
480
|
{
|
|
556
481
|
get(fn, prop) {
|
|
557
|
-
return (data) => {
|
|
558
|
-
return fn(prop, data);
|
|
559
|
-
};
|
|
482
|
+
return (data) => __async(this, null, function* () {
|
|
483
|
+
return yield fn(prop, data);
|
|
484
|
+
});
|
|
560
485
|
}
|
|
561
486
|
}
|
|
562
487
|
);
|
|
@@ -631,7 +556,10 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
631
556
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
632
557
|
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
633
558
|
!!myself && this._stateNotifier.subjects["myself"].next(myself);
|
|
634
|
-
this.broadcast(
|
|
559
|
+
this.broadcast(
|
|
560
|
+
"$UPDATE_PRESENCE",
|
|
561
|
+
{ presence: newPresence }
|
|
562
|
+
);
|
|
635
563
|
};
|
|
636
564
|
this._flattenStorageStore = debounce(
|
|
637
565
|
() => __async(this, null, function* () {
|
|
@@ -652,9 +580,10 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
652
580
|
};
|
|
653
581
|
const addon = this._getAddon(addons);
|
|
654
582
|
const { storage } = __spreadValues(__spreadValues({}, DEFAULT_PLUV_CLIENT_ADDON({ room: this })), addon({ room: this }));
|
|
655
|
-
this._storageStore = storage;
|
|
656
583
|
this._debug = debug;
|
|
657
584
|
this._endpoints = { authEndpoint, wsEndpoint };
|
|
585
|
+
this._storageStore = storage;
|
|
586
|
+
if (!!metadata) this._metadata = metadata;
|
|
658
587
|
this._listeners = {
|
|
659
588
|
onAuthorizationFail: (error) => {
|
|
660
589
|
this._clearTimeout(this._timeouts.reconnect);
|
|
@@ -662,6 +591,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
662
591
|
onAuthorizationFail == null ? void 0 : onAuthorizationFail(error);
|
|
663
592
|
}
|
|
664
593
|
};
|
|
594
|
+
this._router = router != null ? router : new PluvRouter({});
|
|
665
595
|
this._usersManager = new UsersManager({ initialPresence, presence });
|
|
666
596
|
this._crdtManager = new CrdtManager({ initialStorage });
|
|
667
597
|
}
|
|
@@ -846,7 +776,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
846
776
|
options: {}
|
|
847
777
|
};
|
|
848
778
|
}
|
|
849
|
-
const result = this._endpoints.authEndpoint(room);
|
|
779
|
+
const result = this._endpoints.authEndpoint({ metadata: this._metadata, room });
|
|
850
780
|
return typeof result === "string" ? { url: result, options: {} } : result;
|
|
851
781
|
}
|
|
852
782
|
_getAuthorization(room) {
|
|
@@ -872,7 +802,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
872
802
|
case "string":
|
|
873
803
|
return this._endpoints.wsEndpoint;
|
|
874
804
|
default:
|
|
875
|
-
return this._endpoints.wsEndpoint(room);
|
|
805
|
+
return this._endpoints.wsEndpoint({ metadata: this._metadata, room });
|
|
876
806
|
}
|
|
877
807
|
}
|
|
878
808
|
_handleExit(message) {
|
|
@@ -1230,8 +1160,11 @@ var PluvClient = class {
|
|
|
1230
1160
|
authEndpoint: this._authEndpoint,
|
|
1231
1161
|
debug: options.debug,
|
|
1232
1162
|
initialPresence: options.initialPresence,
|
|
1233
|
-
initialStorage:
|
|
1163
|
+
initialStorage: this._initialStorage,
|
|
1164
|
+
metadata: options.metadata,
|
|
1234
1165
|
onAuthorizationFail: options.onAuthorizationFail,
|
|
1166
|
+
presence: this._presence,
|
|
1167
|
+
router: options.router,
|
|
1235
1168
|
wsEndpoint: this._wsEndpoint
|
|
1236
1169
|
});
|
|
1237
1170
|
this._rooms.set(room, newRoom);
|
|
@@ -1240,9 +1173,7 @@ var PluvClient = class {
|
|
|
1240
1173
|
};
|
|
1241
1174
|
this.enter = (room) => __async(this, null, function* () {
|
|
1242
1175
|
const toEnter = typeof room === "string" ? this.getRoom(room) : room;
|
|
1243
|
-
if (!toEnter) {
|
|
1244
|
-
throw new Error(`Could not find room: ${room}.`);
|
|
1245
|
-
}
|
|
1176
|
+
if (!toEnter) throw new Error(`Could not find room: ${room}.`);
|
|
1246
1177
|
this._rooms.set(toEnter.id, toEnter);
|
|
1247
1178
|
yield toEnter.connect();
|
|
1248
1179
|
this._logDebug(`Entered room: ${room}`);
|
|
@@ -1262,11 +1193,19 @@ var PluvClient = class {
|
|
|
1262
1193
|
this._rooms.delete(toLeave.id);
|
|
1263
1194
|
this._logDebug(`Left and deleted room: ${room}`);
|
|
1264
1195
|
});
|
|
1265
|
-
const { authEndpoint, debug = false, wsEndpoint } = options;
|
|
1196
|
+
const { authEndpoint, debug = false, initialStorage, presence, wsEndpoint } = options;
|
|
1266
1197
|
this._authEndpoint = authEndpoint;
|
|
1267
1198
|
this._debug = debug;
|
|
1199
|
+
this._initialStorage = initialStorage;
|
|
1200
|
+
this._presence = presence;
|
|
1268
1201
|
this._wsEndpoint = wsEndpoint;
|
|
1269
1202
|
}
|
|
1203
|
+
get procedure() {
|
|
1204
|
+
return new PluvProcedure();
|
|
1205
|
+
}
|
|
1206
|
+
router(events) {
|
|
1207
|
+
return new PluvRouter(events);
|
|
1208
|
+
}
|
|
1270
1209
|
_logDebug(...data) {
|
|
1271
1210
|
var _a;
|
|
1272
1211
|
if (((_a = process == null ? void 0 : process.env) == null ? void 0 : _a.NODE_ENV) === "production") return;
|
|
@@ -1278,6 +1217,196 @@ var PluvClient = class {
|
|
|
1278
1217
|
var createClient = (options) => {
|
|
1279
1218
|
return new PluvClient(options);
|
|
1280
1219
|
};
|
|
1220
|
+
|
|
1221
|
+
// src/MockedRoom.ts
|
|
1222
|
+
var MockedRoom = class extends AbstractRoom {
|
|
1223
|
+
constructor(room, options) {
|
|
1224
|
+
const { events, initialPresence, initialStorage, presence, router } = options;
|
|
1225
|
+
super(room);
|
|
1226
|
+
this._crdtNotifier = new CrdtNotifier();
|
|
1227
|
+
this._eventNotifier = new EventNotifier();
|
|
1228
|
+
this._otherNotifier = new OtherNotifier();
|
|
1229
|
+
this._state = {
|
|
1230
|
+
authorization: {
|
|
1231
|
+
token: null,
|
|
1232
|
+
user: null
|
|
1233
|
+
},
|
|
1234
|
+
connection: {
|
|
1235
|
+
count: 1,
|
|
1236
|
+
id: null,
|
|
1237
|
+
state: "Untouched" /* Untouched */
|
|
1238
|
+
},
|
|
1239
|
+
webSocket: null
|
|
1240
|
+
};
|
|
1241
|
+
this._stateNotifier = new StateNotifier();
|
|
1242
|
+
this._subscriptions = {
|
|
1243
|
+
observeCrdt: null
|
|
1244
|
+
};
|
|
1245
|
+
this.broadcast = new Proxy(
|
|
1246
|
+
(event, data) => __async(this, null, function* () {
|
|
1247
|
+
if (!this._state.webSocket) return;
|
|
1248
|
+
if (this._state.connection.state !== "Open" /* Open */) return;
|
|
1249
|
+
const type = event.toString();
|
|
1250
|
+
const procedure = this._router._defs.events[type];
|
|
1251
|
+
if (!(procedure == null ? void 0 : procedure.config.broadcast)) {
|
|
1252
|
+
this._simulateEvent(type, data);
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
const myself = this._usersManager.myself;
|
|
1256
|
+
if (!myself) return;
|
|
1257
|
+
const parsed = procedure.config.input ? procedure.config.input.parse(data) : data;
|
|
1258
|
+
const context = {
|
|
1259
|
+
doc: this._crdtManager.doc,
|
|
1260
|
+
others: this._usersManager.getOthers(),
|
|
1261
|
+
room: this.id,
|
|
1262
|
+
user: myself
|
|
1263
|
+
};
|
|
1264
|
+
const output = yield procedure.config.broadcast(
|
|
1265
|
+
parsed,
|
|
1266
|
+
context
|
|
1267
|
+
);
|
|
1268
|
+
Object.entries(output).forEach(([_type, _data]) => {
|
|
1269
|
+
this._simulateEvent(_type, _data);
|
|
1270
|
+
});
|
|
1271
|
+
}),
|
|
1272
|
+
{
|
|
1273
|
+
get(fn, prop) {
|
|
1274
|
+
return (data) => __async(this, null, function* () {
|
|
1275
|
+
return yield fn(prop, data);
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
);
|
|
1280
|
+
this.canRedo = () => {
|
|
1281
|
+
return !!this._crdtManager.doc.canRedo();
|
|
1282
|
+
};
|
|
1283
|
+
this.canUndo = () => {
|
|
1284
|
+
return !!this._crdtManager.doc.canUndo();
|
|
1285
|
+
};
|
|
1286
|
+
this.event = new Proxy(
|
|
1287
|
+
(event, callback) => this._eventNotifier.subscribe(event, callback),
|
|
1288
|
+
{
|
|
1289
|
+
get(fn, prop) {
|
|
1290
|
+
return (callback) => fn(prop, callback);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
);
|
|
1294
|
+
this.getConnection = () => {
|
|
1295
|
+
return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));
|
|
1296
|
+
};
|
|
1297
|
+
this.getMyPresence = () => {
|
|
1298
|
+
return this._usersManager.myPresence;
|
|
1299
|
+
};
|
|
1300
|
+
this.getMyself = () => {
|
|
1301
|
+
return this._usersManager.myself;
|
|
1302
|
+
};
|
|
1303
|
+
this.getOther = (connectionId) => {
|
|
1304
|
+
return this._usersManager.getOther(connectionId);
|
|
1305
|
+
};
|
|
1306
|
+
this.getOthers = () => {
|
|
1307
|
+
return this._usersManager.getOthers();
|
|
1308
|
+
};
|
|
1309
|
+
this.getStorage = (type) => {
|
|
1310
|
+
const sharedType = this._crdtManager.get(type);
|
|
1311
|
+
if (typeof sharedType === "undefined") return null;
|
|
1312
|
+
return sharedType;
|
|
1313
|
+
};
|
|
1314
|
+
this.other = (connectionId, callback) => {
|
|
1315
|
+
return this._otherNotifier.subscribe(connectionId, callback);
|
|
1316
|
+
};
|
|
1317
|
+
this.redo = () => {
|
|
1318
|
+
this._crdtManager.doc.redo();
|
|
1319
|
+
};
|
|
1320
|
+
this.storage = (key, fn) => {
|
|
1321
|
+
return this._crdtNotifier.subscribe(key, fn);
|
|
1322
|
+
};
|
|
1323
|
+
this.storageRoot = (fn) => {
|
|
1324
|
+
return this._crdtNotifier.subcribeRoot(fn);
|
|
1325
|
+
};
|
|
1326
|
+
this.subscribe = (name, callback) => {
|
|
1327
|
+
return this._stateNotifier.subscribe(name, callback);
|
|
1328
|
+
};
|
|
1329
|
+
this.transact = (fn, origin) => {
|
|
1330
|
+
const _origin = origin != null ? origin : this._state.connection.id;
|
|
1331
|
+
const crdtManager = this._crdtManager;
|
|
1332
|
+
if (typeof _origin !== "string") return;
|
|
1333
|
+
if (!crdtManager) return;
|
|
1334
|
+
crdtManager.doc.transact(() => {
|
|
1335
|
+
const storage = crdtManager.doc.get();
|
|
1336
|
+
fn(storage);
|
|
1337
|
+
}, _origin);
|
|
1338
|
+
};
|
|
1339
|
+
this.undo = () => {
|
|
1340
|
+
this._crdtManager.doc.undo();
|
|
1341
|
+
};
|
|
1342
|
+
this.updateMyPresence = (presence) => {
|
|
1343
|
+
var _a;
|
|
1344
|
+
const newPresence = typeof presence === "function" ? presence(this.getMyPresence()) : presence;
|
|
1345
|
+
this._usersManager.updateMyPresence(newPresence);
|
|
1346
|
+
const myPresence = this._usersManager.myPresence;
|
|
1347
|
+
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
1348
|
+
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
1349
|
+
!!myself && this._stateNotifier.subjects["myself"].next(myself);
|
|
1350
|
+
};
|
|
1351
|
+
this._events = events;
|
|
1352
|
+
this._router = router != null ? router : new PluvRouter({});
|
|
1353
|
+
this._usersManager = new UsersManager({
|
|
1354
|
+
initialPresence,
|
|
1355
|
+
presence
|
|
1356
|
+
});
|
|
1357
|
+
this._crdtManager = new CrdtManager({
|
|
1358
|
+
initialStorage
|
|
1359
|
+
});
|
|
1360
|
+
this._observeCrdt();
|
|
1361
|
+
}
|
|
1362
|
+
get storageLoaded() {
|
|
1363
|
+
return true;
|
|
1364
|
+
}
|
|
1365
|
+
getDoc() {
|
|
1366
|
+
return this._crdtManager.doc;
|
|
1367
|
+
}
|
|
1368
|
+
getStorageJson(type) {
|
|
1369
|
+
if (this._state.connection.id === null) return null;
|
|
1370
|
+
if (typeof type === "undefined") return this._crdtManager.doc.toJson();
|
|
1371
|
+
return this._crdtManager.doc.toJson(type);
|
|
1372
|
+
}
|
|
1373
|
+
_observeCrdt() {
|
|
1374
|
+
var _a, _b;
|
|
1375
|
+
(_b = (_a = this._subscriptions).observeCrdt) == null ? void 0 : _b.call(_a);
|
|
1376
|
+
if (!this._crdtManager) return;
|
|
1377
|
+
const unsubscribe = this._crdtManager.doc.subscribe((event) => {
|
|
1378
|
+
var _a2;
|
|
1379
|
+
const origin = (_a2 = event.origin) != null ? _a2 : null;
|
|
1380
|
+
if (!this._crdtManager) return;
|
|
1381
|
+
if (origin === "$STORAGE_UPDATED") return;
|
|
1382
|
+
const sharedTypes = this._crdtManager.doc.get();
|
|
1383
|
+
const storageRoot = Object.keys(sharedTypes).reduce(
|
|
1384
|
+
(acc, prop) => {
|
|
1385
|
+
if (!this._crdtManager) return acc;
|
|
1386
|
+
const serialized = this._crdtManager.doc.toJson(prop);
|
|
1387
|
+
this._crdtNotifier.subject(prop).next(serialized);
|
|
1388
|
+
return __spreadProps(__spreadValues({}, acc), { [prop]: serialized });
|
|
1389
|
+
},
|
|
1390
|
+
{}
|
|
1391
|
+
);
|
|
1392
|
+
this._crdtNotifier.rootSubject.next(storageRoot);
|
|
1393
|
+
});
|
|
1394
|
+
this._subscriptions.observeCrdt = unsubscribe;
|
|
1395
|
+
}
|
|
1396
|
+
_simulateEvent(event, data) {
|
|
1397
|
+
if (!this._events) return;
|
|
1398
|
+
const type = event.toString();
|
|
1399
|
+
const resolver = this._events[type];
|
|
1400
|
+
if (!resolver) return;
|
|
1401
|
+
const result = resolver(data);
|
|
1402
|
+
Object.keys(result).forEach((type2) => {
|
|
1403
|
+
const _type = type2.toString();
|
|
1404
|
+
const data2 = result[_type];
|
|
1405
|
+
if (!data2) return;
|
|
1406
|
+
this._eventNotifier.subject(_type).next(data2);
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
};
|
|
1281
1410
|
export {
|
|
1282
1411
|
AbstractRoom,
|
|
1283
1412
|
AbstractStorageStore,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "@pluv/io frontend client",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"wonka": "^6.3.4",
|
|
21
|
-
"@pluv/crdt": "^0.
|
|
22
|
-
"@pluv/types": "^0.
|
|
21
|
+
"@pluv/crdt": "^0.27.0",
|
|
22
|
+
"@pluv/types": "^0.27.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"eslint": "^8.57.0",
|
|
26
|
-
"tsup": "^8.
|
|
27
|
-
"typescript": "^5.
|
|
28
|
-
"@pluv/tsconfig": "^0.
|
|
29
|
-
"eslint-config-pluv": "^0.
|
|
26
|
+
"tsup": "^8.3.0",
|
|
27
|
+
"typescript": "^5.6.2",
|
|
28
|
+
"@pluv/tsconfig": "^0.27.0",
|
|
29
|
+
"eslint-config-pluv": "^0.27.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
package/src/AbstractRoom.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { AbstractCrdtDoc, CrdtType, InferCrdtJson } from "@pluv/crdt";
|
|
|
2
2
|
import type { IOLike, Id, InferIOInput, InferIOOutput, JsonObject } from "@pluv/types";
|
|
3
3
|
import type { EventNotifierSubscriptionCallback } from "./EventNotifier";
|
|
4
4
|
import type { OtherNotifierSubscriptionCallback } from "./OtherNotifier";
|
|
5
|
+
import type { MergeEvents, PluvRouterEventConfig } from "./PluvRouter";
|
|
5
6
|
import type { StateNotifierSubjects, SubscriptionCallback } from "./StateNotifier";
|
|
6
7
|
import type { UpdateMyPresenceAction, UserInfo, WebSocketConnection } from "./types";
|
|
7
8
|
|
|
@@ -9,6 +10,7 @@ export abstract class AbstractRoom<
|
|
|
9
10
|
TIO extends IOLike,
|
|
10
11
|
TPresence extends JsonObject = {},
|
|
11
12
|
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
13
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
12
14
|
> {
|
|
13
15
|
public readonly id: string;
|
|
14
16
|
|
|
@@ -18,9 +20,9 @@ export abstract class AbstractRoom<
|
|
|
18
20
|
|
|
19
21
|
public abstract storageLoaded: boolean;
|
|
20
22
|
|
|
21
|
-
public abstract broadcast<TEvent extends keyof InferIOInput<TIO
|
|
23
|
+
public abstract broadcast<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(
|
|
22
24
|
event: TEvent,
|
|
23
|
-
data: Id<InferIOInput<TIO
|
|
25
|
+
data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>,
|
|
24
26
|
): void;
|
|
25
27
|
|
|
26
28
|
public abstract canRedo(): boolean;
|
|
@@ -29,9 +31,9 @@ export abstract class AbstractRoom<
|
|
|
29
31
|
|
|
30
32
|
public abstract getDoc(): AbstractCrdtDoc<TStorage>;
|
|
31
33
|
|
|
32
|
-
public abstract event<TEvent extends keyof InferIOOutput<TIO
|
|
34
|
+
public abstract event<TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(
|
|
33
35
|
event: TEvent,
|
|
34
|
-
callback: EventNotifierSubscriptionCallback<
|
|
36
|
+
callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, TEvent>,
|
|
35
37
|
): () => void;
|
|
36
38
|
|
|
37
39
|
public abstract getConnection(): WebSocketConnection;
|