@pluv/client 0.40.1 → 0.41.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 +8 -8
- package/CHANGELOG.md +24 -0
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +209 -85
- package/dist/index.mjs +209 -85
- package/package.json +7 -7
- package/src/AbstractRoom.ts +4 -1
- package/src/MockedRoom.ts +11 -4
- package/src/OtherNotifier.ts +21 -18
- package/src/PluvClient.ts +2 -3
- package/src/PluvRoom.ts +83 -36
- package/src/UsersManager.ts +209 -53
- package/src/constants.ts +1 -0
- package/src/types.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/client@0.
|
|
2
|
+
> @pluv/client@0.41.0 build /home/runner/work/pluv/pluv/packages/client
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --dts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
[34mCLI[39m Target: es6
|
|
9
9
|
[34mESM[39m Build start
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
11
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m54.19 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 130ms
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m55.51 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 131ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m24.
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m24.
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 3289ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m24.58 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m24.58 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @pluv/client
|
|
2
2
|
|
|
3
|
+
## 0.41.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 41aa439: **BREAKING** User's presence is now limited to be at most 512 bytes. If the presence is any larger, the `PluvRoom` will now throw an error.
|
|
8
|
+
- 555b88d: Users can now have multiple simultaneous connections. Previously, if a user tried to open a connection to a room while already being connected to the room, the new connection would be blocked. Now, when the user opens another connection, the new connection will be opened and initialized with their latest presence.
|
|
9
|
+
|
|
10
|
+
Users can only have 1 identity and 1 presence, which means that all presence updates will sync across all of that user's connections. This means that even when a user opens multiple connections, they will only appear once in `others`.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- eb2d903: `PluvRoom` attempts to reconnect immediately after receiving a `close` event, instead of waiting for the reconnect timer. After failing the initial reconnect will the reconnects poll on the timer.
|
|
15
|
+
- 555b88d: Fixed the `presence` type of `other` and `others` to equal the inferred presence type.
|
|
16
|
+
- @pluv/crdt@0.41.0
|
|
17
|
+
- @pluv/types@0.41.0
|
|
18
|
+
|
|
19
|
+
## 0.40.2
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- 6fbc2fe: Update `PluvClient.createRoom` so that the 2nd parameter is optional.
|
|
24
|
+
- @pluv/crdt@0.40.2
|
|
25
|
+
- @pluv/types@0.40.2
|
|
26
|
+
|
|
3
27
|
## 0.40.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -176,7 +176,7 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
176
176
|
getStorage: <TKey extends keyof TStorage>(type: TKey) => TStorage[TKey] | null;
|
|
177
177
|
getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
178
178
|
getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
179
|
-
other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>) => (() => void);
|
|
179
|
+
other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO, TPresence>) => (() => void);
|
|
180
180
|
redo: () => void;
|
|
181
181
|
storage: <TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void) => (() => void);
|
|
182
182
|
storageRoot: (fn: (value: { [P in keyof TStorage]: InferCrdtJson<TStorage[P]>; }) => void) => (() => void);
|
|
@@ -263,7 +263,7 @@ declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObj
|
|
|
263
263
|
};
|
|
264
264
|
get procedure(): PluvProcedure<TIO, {}, {}, TPresence, TStorage>;
|
|
265
265
|
constructor(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>);
|
|
266
|
-
createRoom: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(room: string, options
|
|
266
|
+
createRoom: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(room: string, options?: CreateRoomOptions<TIO, TPresence, TStorage, TMetadata, TEvents>) => PluvRoom<TIO, TMetadata, TPresence, TStorage, TEvents>;
|
|
267
267
|
enter: (room: string | PluvRoom<TIO, TMetadata, any, any, any>, ...args: EnterRoomParams<TMetadata>) => Promise<PluvRoom<TIO, TMetadata, TPresence, TStorage, any>>;
|
|
268
268
|
getRoom: (room: string) => PluvRoom<TIO, TMetadata, TPresence, TStorage, any> | null;
|
|
269
269
|
getRooms: () => readonly PluvRoom<TIO, TMetadata, TPresence, TStorage, any>[];
|
|
@@ -274,7 +274,7 @@ declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObj
|
|
|
274
274
|
|
|
275
275
|
interface AuthorizationState<TIO extends IOLike> {
|
|
276
276
|
token: string | null;
|
|
277
|
-
user: InferIOAuthorizeUser<InferIOAuthorize<TIO
|
|
277
|
+
user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>> | null;
|
|
278
278
|
}
|
|
279
279
|
type EventResolver<TIO extends IOLike = IOLike, TInput extends JsonObject = {}, TOutput extends EventRecord<string, any> = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = (data: TInput, context: EventResolverContext<TIO, TPresence, TStorage>) => MaybePromise<TOutput | void>;
|
|
280
280
|
interface EventResolverContext<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
@@ -329,7 +329,7 @@ type WithMetadata<TMetadata extends JsonObject = {}> = keyof TMetadata extends n
|
|
|
329
329
|
metadata: TMetadata;
|
|
330
330
|
};
|
|
331
331
|
|
|
332
|
-
type OtherNotifierSubscriptionCallback<TIO extends IOLike> = (value: Id<UserInfo<TIO>> | null) => void;
|
|
332
|
+
type OtherNotifierSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (value: Id<UserInfo<TIO, TPresence>> | null) => void;
|
|
333
333
|
|
|
334
334
|
declare abstract class AbstractRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> {
|
|
335
335
|
readonly id: string;
|
|
@@ -348,7 +348,7 @@ declare abstract class AbstractRoom<TIO extends IOLike, TPresence extends JsonOb
|
|
|
348
348
|
abstract getStorage<TKey extends keyof TStorage>(type: TKey): TStorage[TKey] | null;
|
|
349
349
|
abstract getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
350
350
|
abstract getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
351
|
-
abstract other(connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>): () => void;
|
|
351
|
+
abstract other(connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO, TPresence>): () => void;
|
|
352
352
|
abstract redo(): void;
|
|
353
353
|
abstract storage<TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void): () => void;
|
|
354
354
|
abstract storageRoot(fn: (value: {
|
|
@@ -395,7 +395,7 @@ declare class MockedRoom<TIO extends IOLike, TPresence extends JsonObject = {},
|
|
|
395
395
|
getStorage: <TKey extends keyof TStorage>(type: TKey) => TStorage[TKey] | null;
|
|
396
396
|
getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
397
397
|
getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
398
|
-
other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>) => (() => void);
|
|
398
|
+
other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO, TPresence>) => (() => void);
|
|
399
399
|
redo: () => void;
|
|
400
400
|
storage: <TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void) => (() => void);
|
|
401
401
|
storageRoot: (fn: (value: { [P in keyof TStorage]: InferCrdtJson<TStorage[P]>; }) => void) => (() => void);
|
package/dist/index.d.ts
CHANGED
|
@@ -176,7 +176,7 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
176
176
|
getStorage: <TKey extends keyof TStorage>(type: TKey) => TStorage[TKey] | null;
|
|
177
177
|
getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
178
178
|
getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
179
|
-
other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>) => (() => void);
|
|
179
|
+
other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO, TPresence>) => (() => void);
|
|
180
180
|
redo: () => void;
|
|
181
181
|
storage: <TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void) => (() => void);
|
|
182
182
|
storageRoot: (fn: (value: { [P in keyof TStorage]: InferCrdtJson<TStorage[P]>; }) => void) => (() => void);
|
|
@@ -263,7 +263,7 @@ declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObj
|
|
|
263
263
|
};
|
|
264
264
|
get procedure(): PluvProcedure<TIO, {}, {}, TPresence, TStorage>;
|
|
265
265
|
constructor(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>);
|
|
266
|
-
createRoom: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(room: string, options
|
|
266
|
+
createRoom: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(room: string, options?: CreateRoomOptions<TIO, TPresence, TStorage, TMetadata, TEvents>) => PluvRoom<TIO, TMetadata, TPresence, TStorage, TEvents>;
|
|
267
267
|
enter: (room: string | PluvRoom<TIO, TMetadata, any, any, any>, ...args: EnterRoomParams<TMetadata>) => Promise<PluvRoom<TIO, TMetadata, TPresence, TStorage, any>>;
|
|
268
268
|
getRoom: (room: string) => PluvRoom<TIO, TMetadata, TPresence, TStorage, any> | null;
|
|
269
269
|
getRooms: () => readonly PluvRoom<TIO, TMetadata, TPresence, TStorage, any>[];
|
|
@@ -274,7 +274,7 @@ declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObj
|
|
|
274
274
|
|
|
275
275
|
interface AuthorizationState<TIO extends IOLike> {
|
|
276
276
|
token: string | null;
|
|
277
|
-
user: InferIOAuthorizeUser<InferIOAuthorize<TIO
|
|
277
|
+
user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>> | null;
|
|
278
278
|
}
|
|
279
279
|
type EventResolver<TIO extends IOLike = IOLike, TInput extends JsonObject = {}, TOutput extends EventRecord<string, any> = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = (data: TInput, context: EventResolverContext<TIO, TPresence, TStorage>) => MaybePromise<TOutput | void>;
|
|
280
280
|
interface EventResolverContext<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
@@ -329,7 +329,7 @@ type WithMetadata<TMetadata extends JsonObject = {}> = keyof TMetadata extends n
|
|
|
329
329
|
metadata: TMetadata;
|
|
330
330
|
};
|
|
331
331
|
|
|
332
|
-
type OtherNotifierSubscriptionCallback<TIO extends IOLike> = (value: Id<UserInfo<TIO>> | null) => void;
|
|
332
|
+
type OtherNotifierSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (value: Id<UserInfo<TIO, TPresence>> | null) => void;
|
|
333
333
|
|
|
334
334
|
declare abstract class AbstractRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> {
|
|
335
335
|
readonly id: string;
|
|
@@ -348,7 +348,7 @@ declare abstract class AbstractRoom<TIO extends IOLike, TPresence extends JsonOb
|
|
|
348
348
|
abstract getStorage<TKey extends keyof TStorage>(type: TKey): TStorage[TKey] | null;
|
|
349
349
|
abstract getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
350
350
|
abstract getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
351
|
-
abstract other(connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>): () => void;
|
|
351
|
+
abstract other(connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO, TPresence>): () => void;
|
|
352
352
|
abstract redo(): void;
|
|
353
353
|
abstract storage<TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void): () => void;
|
|
354
354
|
abstract storageRoot(fn: (value: {
|
|
@@ -395,7 +395,7 @@ declare class MockedRoom<TIO extends IOLike, TPresence extends JsonObject = {},
|
|
|
395
395
|
getStorage: <TKey extends keyof TStorage>(type: TKey) => TStorage[TKey] | null;
|
|
396
396
|
getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
397
397
|
getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
398
|
-
other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>) => (() => void);
|
|
398
|
+
other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO, TPresence>) => (() => void);
|
|
399
399
|
redo: () => void;
|
|
400
400
|
storage: <TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void) => (() => void);
|
|
401
401
|
storageRoot: (fn: (value: { [P in keyof TStorage]: InferCrdtJson<TStorage[P]>; }) => void) => (() => void);
|
package/dist/index.js
CHANGED
|
@@ -223,24 +223,27 @@ var EventNotifier = class {
|
|
|
223
223
|
var import_wonka3 = require("wonka");
|
|
224
224
|
var OtherNotifier = class {
|
|
225
225
|
constructor() {
|
|
226
|
-
this.
|
|
226
|
+
this._subjects = /* @__PURE__ */ new Map();
|
|
227
227
|
}
|
|
228
228
|
clear() {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
this.subject(connectionId).next(null);
|
|
232
|
-
this.subjects.delete(connectionId);
|
|
229
|
+
this._subjects.forEach((subject) => {
|
|
230
|
+
subject.next(null);
|
|
233
231
|
});
|
|
232
|
+
this._subjects.clear();
|
|
234
233
|
}
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
delete(clientId) {
|
|
235
|
+
this.subject(clientId).next(null);
|
|
236
|
+
this._subjects.delete(clientId);
|
|
237
|
+
}
|
|
238
|
+
subject(clientId) {
|
|
239
|
+
const subject = this._subjects.get(clientId);
|
|
237
240
|
if (subject) return subject;
|
|
238
241
|
const newSubject = (0, import_wonka3.makeSubject)();
|
|
239
|
-
this.
|
|
242
|
+
this._subjects.set(clientId, newSubject);
|
|
240
243
|
return newSubject;
|
|
241
244
|
}
|
|
242
|
-
subscribe(
|
|
243
|
-
const source = this.subject(
|
|
245
|
+
subscribe(clientId, callback) {
|
|
246
|
+
const source = this.subject(clientId).source;
|
|
244
247
|
return (0, import_wonka3.subscribe)(callback)(source).unsubscribe;
|
|
245
248
|
}
|
|
246
249
|
};
|
|
@@ -314,9 +317,16 @@ var StorageStore = class extends AbstractStorageStore {
|
|
|
314
317
|
}
|
|
315
318
|
};
|
|
316
319
|
|
|
320
|
+
// src/constants.ts
|
|
321
|
+
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
322
|
+
|
|
317
323
|
// src/UsersManager.ts
|
|
318
324
|
var UsersManager = class {
|
|
319
325
|
constructor(config) {
|
|
326
|
+
this._idMap = {
|
|
327
|
+
fromConnectionId: /* @__PURE__ */ new Map(),
|
|
328
|
+
fromClientId: /* @__PURE__ */ new Map()
|
|
329
|
+
};
|
|
320
330
|
/**
|
|
321
331
|
* @description This is only set when the user is connected.
|
|
322
332
|
*/
|
|
@@ -334,74 +344,154 @@ var UsersManager = class {
|
|
|
334
344
|
get myself() {
|
|
335
345
|
return this._myself;
|
|
336
346
|
}
|
|
337
|
-
|
|
347
|
+
addConnection(userInfo) {
|
|
348
|
+
var _a;
|
|
349
|
+
const data = __spreadProps(__spreadValues({}, userInfo), {
|
|
350
|
+
presence: (_a = userInfo.presence) != null ? _a : this._initialPresence
|
|
351
|
+
});
|
|
352
|
+
const myClientId = !!this._myself ? this.getClientId(this._myself) : null;
|
|
353
|
+
const clientId = this.getClientId(data);
|
|
354
|
+
const remaining = this._setConnectionId(userInfo.connectionId, clientId).size;
|
|
355
|
+
if (myClientId === clientId) {
|
|
356
|
+
const result2 = {
|
|
357
|
+
clientId,
|
|
358
|
+
data,
|
|
359
|
+
isMyself: true,
|
|
360
|
+
remaining
|
|
361
|
+
};
|
|
362
|
+
return result2;
|
|
363
|
+
}
|
|
364
|
+
const other = this._others.get(clientId);
|
|
365
|
+
if (!other) this._others.set(clientId, data);
|
|
366
|
+
const result = {
|
|
367
|
+
clientId,
|
|
368
|
+
data,
|
|
369
|
+
isMyself: false,
|
|
370
|
+
remaining
|
|
371
|
+
};
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
clearConnections() {
|
|
375
|
+
this.removeMyself();
|
|
338
376
|
this._others.clear();
|
|
377
|
+
this._idMap.fromClientId.clear();
|
|
378
|
+
this._idMap.fromConnectionId.clear();
|
|
379
|
+
}
|
|
380
|
+
deleteConnection(connectionId) {
|
|
381
|
+
var _a, _b, _c;
|
|
382
|
+
const clientId = this.getClientId(connectionId);
|
|
383
|
+
this._deleteConnectionId(connectionId);
|
|
384
|
+
if (!clientId) return null;
|
|
385
|
+
const userInfo = (_a = this._others.get(clientId)) != null ? _a : null;
|
|
386
|
+
if (!userInfo) return null;
|
|
387
|
+
const remaining = (_c = (_b = this._getConnectionIds(clientId)) == null ? void 0 : _b.size) != null ? _c : 0;
|
|
388
|
+
const result = { clientId, remaining, data: userInfo };
|
|
389
|
+
if (!remaining) this._others.delete(clientId);
|
|
390
|
+
return result;
|
|
391
|
+
}
|
|
392
|
+
getClientId(input) {
|
|
393
|
+
var _a, _b, _c, _d;
|
|
394
|
+
if (typeof input !== "string") {
|
|
395
|
+
const userInfo = input;
|
|
396
|
+
const connectionId2 = userInfo.connectionId;
|
|
397
|
+
const userId = (_b = (_a = userInfo.user) == null ? void 0 : _a.id) != null ? _b : null;
|
|
398
|
+
return userId != null ? userId : connectionId2;
|
|
399
|
+
}
|
|
400
|
+
const connectionId = input;
|
|
401
|
+
if (((_c = this._myself) == null ? void 0 : _c.connectionId) === connectionId) {
|
|
402
|
+
return this.getClientId(this._myself);
|
|
403
|
+
}
|
|
404
|
+
const clientId = (_d = this._idMap.fromConnectionId.get(connectionId)) != null ? _d : null;
|
|
405
|
+
return clientId;
|
|
339
406
|
}
|
|
340
407
|
getOther(connectionId) {
|
|
341
408
|
var _a;
|
|
342
|
-
|
|
409
|
+
const clientId = this.getClientId(connectionId);
|
|
410
|
+
if (!clientId) return null;
|
|
411
|
+
return (_a = this._others.get(clientId)) != null ? _a : null;
|
|
343
412
|
}
|
|
344
413
|
getOthers() {
|
|
345
414
|
return Array.from(this._others.values());
|
|
346
415
|
}
|
|
347
416
|
patchPresence(connectionId, patch) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (!other) return;
|
|
417
|
+
const clientId = this.getClientId(connectionId);
|
|
418
|
+
const myClientId = !!this._myself ? this.getClientId(this._myself) : null;
|
|
419
|
+
if (!clientId) return null;
|
|
420
|
+
if (myClientId === clientId) return this.updateMyPresence(patch);
|
|
421
|
+
const other = this._others.get(clientId);
|
|
422
|
+
if (!other) return null;
|
|
355
423
|
const presence = __spreadValues(__spreadValues({}, other.presence), patch);
|
|
356
|
-
|
|
357
|
-
this._others.set(
|
|
424
|
+
const validated = this._presence ? this._presence.parse(presence) : presence;
|
|
425
|
+
this._others.set(clientId, __spreadProps(__spreadValues({}, other), { presence: validated }));
|
|
426
|
+
return validated;
|
|
358
427
|
}
|
|
359
428
|
removeMyself() {
|
|
429
|
+
if (!this._myself) return;
|
|
430
|
+
const connectionId = this._myself.connectionId;
|
|
431
|
+
this._deleteConnectionId(connectionId);
|
|
360
432
|
this._myself = null;
|
|
361
433
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
this.
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
this.
|
|
370
|
-
connectionId,
|
|
371
|
-
presence: this._initialPresence,
|
|
372
|
-
user
|
|
373
|
-
};
|
|
374
|
-
this._myPresence = this._initialPresence;
|
|
434
|
+
setMyself(userInfo) {
|
|
435
|
+
var _a;
|
|
436
|
+
const connectionId = userInfo.connectionId;
|
|
437
|
+
const presence = (_a = userInfo.presence) != null ? _a : this._initialPresence;
|
|
438
|
+
this._myself = __spreadProps(__spreadValues({}, userInfo), { presence });
|
|
439
|
+
this._myPresence = presence;
|
|
440
|
+
const clientId = this.getClientId(this._myself);
|
|
441
|
+
this._setConnectionId(connectionId, clientId);
|
|
375
442
|
}
|
|
376
443
|
setPresence(connectionId, presence) {
|
|
377
|
-
|
|
378
|
-
|
|
444
|
+
const clientId = this.getClientId(connectionId);
|
|
445
|
+
const myClientId = !!this._myself ? this.getClientId(this._myself) : null;
|
|
446
|
+
if (!clientId) return;
|
|
447
|
+
if (myClientId === clientId) {
|
|
448
|
+
if (!this._myself) return;
|
|
379
449
|
this._myself.presence = presence;
|
|
380
450
|
this._myPresence = presence;
|
|
381
451
|
return;
|
|
382
452
|
}
|
|
383
|
-
const other = this._others.get(
|
|
453
|
+
const other = this._others.get(clientId);
|
|
384
454
|
if (!other) return;
|
|
385
|
-
this._others.set(
|
|
386
|
-
}
|
|
387
|
-
setUser(connectionId, user, presence) {
|
|
388
|
-
var _a;
|
|
389
|
-
if (((_a = this._myself) == null ? void 0 : _a.connectionId) === connectionId) return;
|
|
390
|
-
const other = this._others.get(connectionId);
|
|
391
|
-
if (other) return;
|
|
392
|
-
this._others.set(connectionId, {
|
|
393
|
-
connectionId,
|
|
394
|
-
presence: presence != null ? presence : this._initialPresence,
|
|
395
|
-
user
|
|
396
|
-
});
|
|
455
|
+
this._others.set(clientId, __spreadProps(__spreadValues({}, other), { presence }));
|
|
397
456
|
}
|
|
398
457
|
/**
|
|
399
458
|
* @description This method need not care about being connected.
|
|
400
459
|
*/
|
|
401
460
|
updateMyPresence(patch) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
461
|
+
const updated = __spreadValues(__spreadValues({}, this._myPresence), patch);
|
|
462
|
+
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
463
|
+
if (bytes > MAX_PRESENCE_SIZE_BYTES) {
|
|
464
|
+
throw new Error(
|
|
465
|
+
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
this._myPresence = updated;
|
|
469
|
+
if (!this._myself) return updated;
|
|
470
|
+
this._myself.presence = updated;
|
|
471
|
+
return updated;
|
|
472
|
+
}
|
|
473
|
+
_deleteConnectionId(connectionId) {
|
|
474
|
+
var _a;
|
|
475
|
+
const clientId = this.getClientId(connectionId);
|
|
476
|
+
this._idMap.fromConnectionId.delete(connectionId);
|
|
477
|
+
if (!clientId) return;
|
|
478
|
+
const set = (_a = this._idMap.fromClientId.get(clientId)) != null ? _a : null;
|
|
479
|
+
if (!set) return;
|
|
480
|
+
set.delete(connectionId);
|
|
481
|
+
if (!!set.size) return;
|
|
482
|
+
this._idMap.fromClientId.delete(clientId);
|
|
483
|
+
}
|
|
484
|
+
_getConnectionIds(clientId) {
|
|
485
|
+
const set = this._idMap.fromClientId.get(clientId);
|
|
486
|
+
return set != null ? set : null;
|
|
487
|
+
}
|
|
488
|
+
_setConnectionId(connectionId, clientId) {
|
|
489
|
+
var _a;
|
|
490
|
+
const set = (_a = this._idMap.fromClientId.get(clientId)) != null ? _a : /* @__PURE__ */ new Set();
|
|
491
|
+
const updated = set.add(connectionId);
|
|
492
|
+
this._idMap.fromConnectionId.set(connectionId, clientId);
|
|
493
|
+
this._idMap.fromClientId.set(clientId, updated);
|
|
494
|
+
return updated;
|
|
405
495
|
}
|
|
406
496
|
};
|
|
407
497
|
|
|
@@ -567,7 +657,9 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
567
657
|
return sharedType;
|
|
568
658
|
};
|
|
569
659
|
this.other = (connectionId, callback) => {
|
|
570
|
-
|
|
660
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
661
|
+
if (!clientId) return () => void 0;
|
|
662
|
+
return this._otherNotifier.subscribe(clientId, callback);
|
|
571
663
|
};
|
|
572
664
|
this.redo = () => {
|
|
573
665
|
this._crdtManager.doc.redo();
|
|
@@ -599,7 +691,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
599
691
|
const myPresence = this._usersManager.myPresence;
|
|
600
692
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
601
693
|
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
602
|
-
!!myself
|
|
694
|
+
if (!!myself) this._stateNotifier.subjects.myself.next(myself);
|
|
603
695
|
this.broadcast(
|
|
604
696
|
"$updatePresence",
|
|
605
697
|
{ presence: newPresence }
|
|
@@ -669,8 +761,8 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
669
761
|
try {
|
|
670
762
|
const publicKey = this._getPublicKey(params);
|
|
671
763
|
authToken = yield this._getAuthorization(this.id, params);
|
|
672
|
-
authToken
|
|
673
|
-
publicKey
|
|
764
|
+
if (authToken) url.searchParams.set("token", encodeURIComponent(authToken));
|
|
765
|
+
if (publicKey) url.searchParams.set("public_key", encodeURIComponent(publicKey));
|
|
674
766
|
webSocket = new WebSocket(url.toString());
|
|
675
767
|
} catch (err) {
|
|
676
768
|
this._updateState((oldState) => {
|
|
@@ -781,7 +873,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
781
873
|
this._clearTimeout(this._timeouts.pong);
|
|
782
874
|
this._detachWindowListeners();
|
|
783
875
|
this._usersManager.removeMyself();
|
|
784
|
-
this._usersManager.
|
|
876
|
+
this._usersManager.clearConnections();
|
|
785
877
|
this._otherNotifier.clear();
|
|
786
878
|
this._stateNotifier.subjects.myself.next(null);
|
|
787
879
|
this._stateNotifier.subjects.others.next([]);
|
|
@@ -869,11 +961,11 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
869
961
|
const { connectionId } = message;
|
|
870
962
|
if (!connectionId) return;
|
|
871
963
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
872
|
-
this._usersManager.
|
|
964
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
965
|
+
const deleted = this._usersManager.deleteConnection(connectionId);
|
|
873
966
|
const others = this._usersManager.getOthers();
|
|
874
967
|
this._stateNotifier.subjects.others.next(others);
|
|
875
|
-
this._otherNotifier.
|
|
876
|
-
this._otherNotifier.subjects.delete(connectionId);
|
|
968
|
+
if (!(deleted == null ? void 0 : deleted.remaining) && !!clientId) this._otherNotifier.delete(clientId);
|
|
877
969
|
}
|
|
878
970
|
_handlePresenceUpdatedMessage(message) {
|
|
879
971
|
var _a;
|
|
@@ -883,11 +975,18 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
883
975
|
const data = message.data;
|
|
884
976
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
885
977
|
if ((myself == null ? void 0 : myself.connectionId) === connectionId) return;
|
|
886
|
-
this._usersManager.patchPresence(connectionId, data.presence);
|
|
978
|
+
const updated = this._usersManager.patchPresence(connectionId, data.presence);
|
|
979
|
+
const myClientId = !!myself ? this._usersManager.getClientId(myself) : null;
|
|
980
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
981
|
+
if (!!clientId && myClientId === clientId) {
|
|
982
|
+
this._stateNotifier.subjects["my-presence"].next(updated);
|
|
983
|
+
this._stateNotifier.subjects.myself.next(this._usersManager.myself);
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
887
986
|
const other = this._usersManager.getOther(connectionId);
|
|
888
987
|
const others = this._usersManager.getOthers();
|
|
889
|
-
this._otherNotifier.subject(
|
|
890
|
-
this._stateNotifier.subjects
|
|
988
|
+
if (!!clientId) this._otherNotifier.subject(clientId).next(other);
|
|
989
|
+
this._stateNotifier.subjects.others.next(others);
|
|
891
990
|
}
|
|
892
991
|
_handleReceiveOthers(message) {
|
|
893
992
|
if (!message.connectionId) return;
|
|
@@ -895,31 +994,44 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
895
994
|
const data = message.data;
|
|
896
995
|
Object.keys(data.others).forEach((connectionId) => {
|
|
897
996
|
const { presence, user } = data.others[connectionId];
|
|
898
|
-
this._usersManager.
|
|
997
|
+
const result = this._usersManager.addConnection({
|
|
998
|
+
connectionId,
|
|
999
|
+
presence: presence != null ? presence : void 0,
|
|
1000
|
+
user
|
|
1001
|
+
});
|
|
1002
|
+
if (!!presence) this._usersManager.patchPresence(connectionId, presence);
|
|
1003
|
+
if (result.isMyself) return;
|
|
1004
|
+
const clientId = result.clientId;
|
|
899
1005
|
const other = this._usersManager.getOther(connectionId);
|
|
900
|
-
|
|
901
|
-
this._otherNotifier.subject(connectionId).next(other);
|
|
1006
|
+
this._otherNotifier.subject(clientId).next(other);
|
|
902
1007
|
});
|
|
903
1008
|
const others = this._usersManager.getOthers();
|
|
904
|
-
this._stateNotifier.subjects
|
|
1009
|
+
this._stateNotifier.subjects.others.next(others);
|
|
905
1010
|
}
|
|
906
1011
|
_handleRegisteredMessage(message) {
|
|
907
|
-
var _a, _b;
|
|
908
|
-
const { connectionId
|
|
1012
|
+
var _a, _b, _c;
|
|
1013
|
+
const { connectionId } = message;
|
|
1014
|
+
const user = message.user;
|
|
909
1015
|
if (!connectionId) return;
|
|
910
1016
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
1017
|
+
const data = message.data;
|
|
911
1018
|
this._updateState((oldState) => {
|
|
912
1019
|
oldState.connection.count += 1;
|
|
913
1020
|
oldState.connection.id = connectionId;
|
|
914
1021
|
oldState.authorization.user = user != null ? user : null;
|
|
915
1022
|
return oldState;
|
|
916
1023
|
});
|
|
917
|
-
|
|
1024
|
+
const userInfo = {
|
|
1025
|
+
connectionId,
|
|
1026
|
+
presence: (_a = data.presence) != null ? _a : void 0,
|
|
1027
|
+
user
|
|
1028
|
+
};
|
|
1029
|
+
this._usersManager.setMyself(userInfo);
|
|
918
1030
|
const presence = this._usersManager.myPresence;
|
|
919
|
-
const myself = (
|
|
1031
|
+
const myself = (_b = this._usersManager.myself) != null ? _b : null;
|
|
920
1032
|
this._stateNotifier.subjects["my-presence"].next(presence);
|
|
921
|
-
this._stateNotifier.subjects
|
|
922
|
-
const update = this._state.connection.count > 1 ? (
|
|
1033
|
+
this._stateNotifier.subjects.myself.next(myself);
|
|
1034
|
+
const update = this._state.connection.count > 1 ? (_c = this._crdtManager.doc.getEncodedState()) != null ? _c : null : null;
|
|
923
1035
|
this._sendMessage({
|
|
924
1036
|
type: "$initializeSession",
|
|
925
1037
|
data: { presence, update }
|
|
@@ -974,6 +1086,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
974
1086
|
this._crdtNotifier.rootSubject.next(storageRoot);
|
|
975
1087
|
}
|
|
976
1088
|
_handleUserJoinedMessage(message) {
|
|
1089
|
+
var _a;
|
|
977
1090
|
const { connectionId } = message;
|
|
978
1091
|
if (!connectionId) return;
|
|
979
1092
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
@@ -982,12 +1095,18 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
982
1095
|
const myself = this._usersManager.myself;
|
|
983
1096
|
if (myself.connectionId === connectionId) {
|
|
984
1097
|
this._sendMessage({ type: "$getOthers", data: {} });
|
|
1098
|
+
return;
|
|
985
1099
|
}
|
|
986
|
-
this._usersManager.
|
|
1100
|
+
const result = this._usersManager.addConnection({
|
|
1101
|
+
connectionId,
|
|
1102
|
+
presence: data.presence,
|
|
1103
|
+
user: data.user
|
|
1104
|
+
});
|
|
1105
|
+
const clientId = (_a = result == null ? void 0 : result.clientId) != null ? _a : null;
|
|
987
1106
|
const other = this._usersManager.getOther(connectionId);
|
|
988
1107
|
const others = this._usersManager.getOthers();
|
|
989
|
-
this._otherNotifier.subject(
|
|
990
|
-
this._stateNotifier.subjects
|
|
1108
|
+
if (!!clientId) this._otherNotifier.subject(clientId).next(other);
|
|
1109
|
+
this._stateNotifier.subjects.others.next(others);
|
|
991
1110
|
}
|
|
992
1111
|
_heartbeat() {
|
|
993
1112
|
this._clearTimeout(this._timeouts.pong);
|
|
@@ -997,7 +1116,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
997
1116
|
_logDebug(...data) {
|
|
998
1117
|
var _a;
|
|
999
1118
|
if (((_a = process == null ? void 0 : process.env) == null ? void 0 : _a.NODE_ENV) === "production") return;
|
|
1000
|
-
this._debug
|
|
1119
|
+
if (this._debug) console.log(...data);
|
|
1001
1120
|
}
|
|
1002
1121
|
_observeCrdt() {
|
|
1003
1122
|
var _a, _b;
|
|
@@ -1032,7 +1151,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1032
1151
|
_onClose(event) {
|
|
1033
1152
|
return __async(this, null, function* () {
|
|
1034
1153
|
this._logDebug("WebSocket closed");
|
|
1035
|
-
!!event.reason
|
|
1154
|
+
if (!!event.reason) this._logDebug(event.reason);
|
|
1036
1155
|
const shouldRetry = [
|
|
1037
1156
|
// Going away: Client/server is shutting down or navigating
|
|
1038
1157
|
1001,
|
|
@@ -1047,15 +1166,18 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1047
1166
|
// Bad gateway
|
|
1048
1167
|
1014
|
|
1049
1168
|
].some((okToRetryCode) => event.code === okToRetryCode);
|
|
1050
|
-
this._closeWs();
|
|
1051
|
-
if (!shouldRetry) this._clearTimeout(this._timeouts.reconnect);
|
|
1052
|
-
else this._pollReconnect();
|
|
1053
1169
|
this._updateState((oldState) => {
|
|
1054
1170
|
oldState.authorization.token = null;
|
|
1055
1171
|
oldState.connection.state = shouldRetry ? "Unavailable" /* Unavailable */ : "Closed" /* Closed */;
|
|
1056
1172
|
oldState.webSocket = null;
|
|
1057
1173
|
return oldState;
|
|
1058
1174
|
});
|
|
1175
|
+
if (shouldRetry) {
|
|
1176
|
+
yield this._reconnect();
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
this._closeWs();
|
|
1180
|
+
this._clearTimeout(this._timeouts.reconnect);
|
|
1059
1181
|
});
|
|
1060
1182
|
}
|
|
1061
1183
|
/**
|
|
@@ -1226,7 +1348,7 @@ var PluvClient = class {
|
|
|
1226
1348
|
constructor(options) {
|
|
1227
1349
|
this._publicKey = null;
|
|
1228
1350
|
this._rooms = /* @__PURE__ */ new Map();
|
|
1229
|
-
this.createRoom = (room, options) => {
|
|
1351
|
+
this.createRoom = (room, options = {}) => {
|
|
1230
1352
|
var _a;
|
|
1231
1353
|
const oldRoom = this.getRoom(room);
|
|
1232
1354
|
if (oldRoom) return oldRoom;
|
|
@@ -1297,7 +1419,7 @@ var PluvClient = class {
|
|
|
1297
1419
|
_logDebug(...data) {
|
|
1298
1420
|
var _a;
|
|
1299
1421
|
if (((_a = process == null ? void 0 : process.env) == null ? void 0 : _a.NODE_ENV) === "production") return;
|
|
1300
|
-
this._debug
|
|
1422
|
+
if (this._debug) console.log(...data);
|
|
1301
1423
|
}
|
|
1302
1424
|
};
|
|
1303
1425
|
|
|
@@ -1404,7 +1526,9 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1404
1526
|
return sharedType;
|
|
1405
1527
|
};
|
|
1406
1528
|
this.other = (connectionId, callback) => {
|
|
1407
|
-
|
|
1529
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
1530
|
+
if (!clientId) return () => void 0;
|
|
1531
|
+
return this._otherNotifier.subscribe(clientId, callback);
|
|
1408
1532
|
};
|
|
1409
1533
|
this.redo = () => {
|
|
1410
1534
|
this._crdtManager.doc.redo();
|
|
@@ -1438,7 +1562,7 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1438
1562
|
const myPresence = this._usersManager.myPresence;
|
|
1439
1563
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
1440
1564
|
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
1441
|
-
!!myself
|
|
1565
|
+
if (!!myself) this._stateNotifier.subjects["myself"].next(myself);
|
|
1442
1566
|
};
|
|
1443
1567
|
this._events = events;
|
|
1444
1568
|
this._router = router != null ? router : new PluvRouter({});
|