@pluv/client 0.38.14 → 0.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +75 -0
- package/dist/index.d.mts +132 -115
- package/dist/index.d.ts +132 -115
- package/dist/index.js +97 -69
- package/dist/index.mjs +97 -69
- package/eslint.config.mjs +4 -0
- package/package.json +7 -7
- package/src/MockedRoom.ts +1 -0
- package/src/PluvClient.ts +25 -11
- package/src/PluvRoom.ts +133 -76
- package/src/index.ts +10 -3
- package/src/types.ts +21 -0
- package/.eslintrc.js +0 -4
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/client@0.
|
|
2
|
+
> @pluv/client@0.39.1 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[32m49.44 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 100ms
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m50.76 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 123ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 3307ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m24.50 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m24.50 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,80 @@
|
|
|
1
1
|
# @pluv/client
|
|
2
2
|
|
|
3
|
+
## 0.39.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @pluv/crdt@0.39.1
|
|
8
|
+
- @pluv/types@0.39.1
|
|
9
|
+
|
|
10
|
+
## 0.39.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- e6ddddc: **BREAKING** Moved the `metadata` parameter from the constructor of `PluvRoom` to `PluvClient.connect`. The `metadata` parameter from the constructor of `PluvRoom` is now the validation schema for `metadata` passed through from `PluvClient`.
|
|
15
|
+
|
|
16
|
+
This should not be breaking for most users, as the recommended way to enter a room has always been via `PluvClient.enter(room)` (i.e. these are mostly internal-only changes).
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// Before
|
|
20
|
+
const room = new Room("my-room", { metadata: { hello: "world" } });
|
|
21
|
+
|
|
22
|
+
await room.connect();
|
|
23
|
+
|
|
24
|
+
// After
|
|
25
|
+
const room = new Room("my-room", {
|
|
26
|
+
metadata: z.object({ hello: z.string() }),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await room.connect({ metadata: { hello: "world" } });
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- e6ddddc: **BREAKING** Moved the `metadata` parameter from `PluvClient.createRoom` to `PluvClient.enter`.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// Before
|
|
36
|
+
const room = client.createRoom({
|
|
37
|
+
// ...
|
|
38
|
+
metadata: { hello: "world" },
|
|
39
|
+
// ...
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
client.enter(room);
|
|
43
|
+
|
|
44
|
+
// After
|
|
45
|
+
const room = client.createRoom({
|
|
46
|
+
// ...
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
client.enter(room, { metadata });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Patch Changes
|
|
53
|
+
|
|
54
|
+
- e6ddddc: Improved handling of polling-reconnects to `PluvRoom` after the websocket closes (depending on the close event's code).
|
|
55
|
+
- 2cfb68d: Add the ability to configure the reconnect timeout (in milliseconds) for a `PluvRoom`, and lowered the default reconnect timeout from 30s to 5s. Values will be automatically clamped to between 1s and 60s.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// Both of these are valid
|
|
59
|
+
const room = client.createRoom("my-room", {
|
|
60
|
+
// Set timeout to a fixed 10s
|
|
61
|
+
reconnectTimeoutMs: 10_000,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const room = client.createRoom("my-room", {
|
|
65
|
+
/**
|
|
66
|
+
* `attempts` is the count of failed reconnect attempts, starting from 0 on the first attempt.
|
|
67
|
+
* The returned value will be how long until the next attempt.
|
|
68
|
+
*/
|
|
69
|
+
reconnectTimeoutMs: ({ attempts }) => {
|
|
70
|
+
return 10_000 + 1_000 * Math.pow(2, attempts);
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- @pluv/crdt@0.39.0
|
|
76
|
+
- @pluv/types@0.39.0
|
|
77
|
+
|
|
3
78
|
## 0.38.14
|
|
4
79
|
|
|
5
80
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CrdtType, AbstractCrdtDoc, InferCrdtJson
|
|
1
|
+
import { CrdtType, AbstractCrdtDocFactory, AbstractCrdtDoc, InferCrdtJson } from '@pluv/crdt';
|
|
2
2
|
export { CrdtType, InferCrdtJson } from '@pluv/crdt';
|
|
3
|
-
import { IOLike, InferIOOutput, Id, IOEventMessage, JsonObject, EventRecord,
|
|
3
|
+
import { IOLike, InferIOOutput, Id, IOEventMessage, JsonObject, EventRecord, ProcedureLike, InputZodLike, IORouterLike, InferIOAuthorizeUser, InferIOAuthorize, BaseUser, InferIOInput, MaybePromise } from '@pluv/types';
|
|
4
4
|
export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types';
|
|
5
5
|
import { Subject } from 'wonka';
|
|
6
6
|
|
|
@@ -14,45 +14,12 @@ declare enum ConnectionState {
|
|
|
14
14
|
Untouched = "Untouched"
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
token: string | null;
|
|
19
|
-
user: InferIOAuthorizeUser<InferIOAuthorize<TIO>> | null;
|
|
20
|
-
}
|
|
21
|
-
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>;
|
|
22
|
-
interface EventResolverContext<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
23
|
-
doc: AbstractCrdtDoc<TStorage>;
|
|
24
|
-
others: readonly UserInfo<TIO, TPresence>[];
|
|
25
|
-
room: string;
|
|
26
|
-
user: UserInfo<TIO, TPresence>;
|
|
27
|
-
}
|
|
28
|
-
type MergeEventRecords<TEventRecords extends EventRecord<string, any>[], TRoot extends EventRecord<string, any> = {}> = TEventRecords extends [
|
|
29
|
-
infer IHead extends EventRecord<string, any>,
|
|
30
|
-
...infer ITail extends EventRecord<string, any>[]
|
|
31
|
-
] ? MergeEventRecords<ITail, Omit<TRoot, keyof IHead> & {
|
|
32
|
-
[P in keyof IHead]: TRoot extends Record<P, any> ? TRoot[P] | IHead[P] : IHead[P];
|
|
33
|
-
}> : Id<TRoot>;
|
|
34
|
-
interface PublicKeyParams<TMetadata extends JsonObject> {
|
|
35
|
-
metadata: TMetadata;
|
|
36
|
-
}
|
|
37
|
-
type PublicKey<TMetadata extends JsonObject> = string | ((params: PublicKeyParams<TMetadata>) => string);
|
|
38
|
-
type UpdateMyPresenceAction<TPresence extends JsonObject> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
|
|
39
|
-
interface UserInfo<TIO extends IOLike, TPresence extends JsonObject = {}> {
|
|
40
|
-
connectionId: string;
|
|
41
|
-
presence: TPresence;
|
|
42
|
-
user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;
|
|
43
|
-
}
|
|
44
|
-
interface WebSocketConnection {
|
|
45
|
-
count: number;
|
|
46
|
-
id: string | null;
|
|
47
|
-
state: ConnectionState;
|
|
48
|
-
}
|
|
49
|
-
interface WebSocketState<TIO extends IOLike> {
|
|
50
|
-
authorization: AuthorizationState<TIO>;
|
|
51
|
-
connection: WebSocketConnection;
|
|
52
|
-
webSocket: WebSocket | null;
|
|
53
|
-
}
|
|
17
|
+
declare const identity: <T extends unknown>(x: T) => T;
|
|
54
18
|
|
|
55
|
-
type
|
|
19
|
+
type InferCallback<TIO extends IOLike<any, any>> = (i: typeof identity) => {
|
|
20
|
+
io: (io: TIO) => TIO;
|
|
21
|
+
};
|
|
22
|
+
declare const infer: <TIO extends IOLike<any, any>>(callback: InferCallback<TIO>) => InferCallback<TIO>;
|
|
56
23
|
|
|
57
24
|
interface PluvProcedureConfig<TIO extends IOLike = IOLike, TInput extends JsonObject = {}, TOutput extends EventRecord<string, any> = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
58
25
|
broadcast?: EventResolver<TIO, TInput, TOutput, TPresence, TStorage> | null;
|
|
@@ -68,6 +35,22 @@ declare class PluvProcedure<TIO extends IOLike = IOLike, TInput extends JsonObje
|
|
|
68
35
|
private _resolver;
|
|
69
36
|
}
|
|
70
37
|
|
|
38
|
+
declare abstract class AbstractStorageStore {
|
|
39
|
+
room: string;
|
|
40
|
+
constructor(room: string);
|
|
41
|
+
abstract addUpdate(update: string): Promise<void>;
|
|
42
|
+
abstract destroy(): Promise<void>;
|
|
43
|
+
abstract flatten(encodedState: string): Promise<void>;
|
|
44
|
+
abstract getShouldFlatten(): Promise<boolean>;
|
|
45
|
+
abstract getUpdates(start?: number): Promise<readonly string[]>;
|
|
46
|
+
abstract initialize(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type CrdtManagerOptions<TStorage extends Record<string, CrdtType<any, any>> = {}> = {
|
|
50
|
+
encodedState?: string | Uint8Array | null;
|
|
51
|
+
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
52
|
+
};
|
|
53
|
+
|
|
71
54
|
type PluvRouterEventConfig<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
|
|
72
55
|
[P: string]: Pick<PluvProcedure<TIO, any, any, TPresence, TStorage>, "config">;
|
|
73
56
|
};
|
|
@@ -99,58 +82,6 @@ interface StateNotifierSubjects<TIO extends IOLike, TPresence extends JsonObject
|
|
|
99
82
|
type InferSubjectValue<TIO extends IOLike, TPresence extends JsonObject, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue> ? Id<IValue> : never;
|
|
100
83
|
type SubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
|
|
101
84
|
|
|
102
|
-
declare abstract class AbstractRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> {
|
|
103
|
-
readonly id: string;
|
|
104
|
-
constructor(room: string);
|
|
105
|
-
abstract storageLoaded: boolean;
|
|
106
|
-
abstract broadcast<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(event: TEvent, data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>): void;
|
|
107
|
-
abstract canRedo(): boolean;
|
|
108
|
-
abstract canUndo(): boolean;
|
|
109
|
-
abstract getDoc(): AbstractCrdtDoc<TStorage>;
|
|
110
|
-
abstract event<TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(event: TEvent, callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, TEvent>): () => void;
|
|
111
|
-
abstract getConnection(): WebSocketConnection;
|
|
112
|
-
abstract getMyPresence(): TPresence;
|
|
113
|
-
abstract getMyself(): Id<UserInfo<TIO, TPresence>> | null;
|
|
114
|
-
abstract getOther(connectionId: string): Id<UserInfo<TIO, TPresence>> | null;
|
|
115
|
-
abstract getOthers(): readonly Id<UserInfo<TIO, TPresence>>[];
|
|
116
|
-
abstract getStorage<TKey extends keyof TStorage>(type: TKey): TStorage[TKey] | null;
|
|
117
|
-
abstract getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
118
|
-
abstract getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
119
|
-
abstract other(connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>): () => void;
|
|
120
|
-
abstract redo(): void;
|
|
121
|
-
abstract storage<TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void): () => void;
|
|
122
|
-
abstract storageRoot(fn: (value: {
|
|
123
|
-
[P in keyof TStorage]: InferCrdtJson<TStorage[P]>;
|
|
124
|
-
}) => void): () => void;
|
|
125
|
-
abstract subscribe<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(name: TSubject, callback: SubscriptionCallback<TIO, TPresence, TSubject>): () => void;
|
|
126
|
-
abstract transact(fn: (storage: TStorage) => void, origin?: string): void;
|
|
127
|
-
abstract undo(): void;
|
|
128
|
-
abstract updateMyPresence(presence: UpdateMyPresenceAction<TPresence>): void;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
declare abstract class AbstractStorageStore {
|
|
132
|
-
room: string;
|
|
133
|
-
constructor(room: string);
|
|
134
|
-
abstract addUpdate(update: string): Promise<void>;
|
|
135
|
-
abstract destroy(): Promise<void>;
|
|
136
|
-
abstract flatten(encodedState: string): Promise<void>;
|
|
137
|
-
abstract getShouldFlatten(): Promise<boolean>;
|
|
138
|
-
abstract getUpdates(start?: number): Promise<readonly string[]>;
|
|
139
|
-
abstract initialize(): Promise<void>;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
declare const identity: <T extends unknown>(x: T) => T;
|
|
143
|
-
|
|
144
|
-
type InferCallback<TIO extends IOLike<any, any>> = (i: typeof identity) => {
|
|
145
|
-
io: (io: TIO) => TIO;
|
|
146
|
-
};
|
|
147
|
-
declare const infer: <TIO extends IOLike<any, any>>(callback: InferCallback<TIO>) => InferCallback<TIO>;
|
|
148
|
-
|
|
149
|
-
type CrdtManagerOptions<TStorage extends Record<string, CrdtType<any, any>> = {}> = {
|
|
150
|
-
encodedState?: string | Uint8Array | null;
|
|
151
|
-
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
152
|
-
};
|
|
153
|
-
|
|
154
85
|
type UsersManagerConfig<TPresence extends JsonObject = {}> = {
|
|
155
86
|
initialPresence?: TPresence;
|
|
156
87
|
presence?: InputZodLike<TPresence>;
|
|
@@ -191,34 +122,39 @@ type PluvRoomDebug<TIO extends IOLike> = Id<{
|
|
|
191
122
|
output: readonly (keyof InferIOOutput<TIO>)[];
|
|
192
123
|
input: readonly (keyof InferIOInput<TIO>)[];
|
|
193
124
|
}>;
|
|
125
|
+
type RoomConnectParams<TMetadata extends JsonObject = {}> = keyof TMetadata extends never ? [] : [WithMetadata<TMetadata>];
|
|
126
|
+
interface ReconnectTimeoutMsParams {
|
|
127
|
+
attempts: number;
|
|
128
|
+
}
|
|
129
|
+
type ReconnectTimeoutMs = number | ((params: ReconnectTimeoutMsParams) => number);
|
|
194
130
|
type RoomConfig<TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = Id<{
|
|
195
131
|
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
196
132
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
197
133
|
onAuthorizationFail?: (error: Error) => void;
|
|
134
|
+
metadata?: InputZodLike<TMetadata>;
|
|
198
135
|
publicKey?: PublicKey<TMetadata>;
|
|
136
|
+
reconnectTimeoutMs?: ReconnectTimeoutMs;
|
|
199
137
|
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
200
|
-
} & RoomEndpoints<TIO, TMetadata> & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & UsersManagerConfig<TPresence
|
|
201
|
-
metadata?: undefined;
|
|
202
|
-
} : {
|
|
203
|
-
metadata: TMetadata;
|
|
204
|
-
})>;
|
|
138
|
+
} & RoomEndpoints<TIO, TMetadata> & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & UsersManagerConfig<TPresence>>;
|
|
205
139
|
declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> extends AbstractRoom<TIO, TPresence, TStorage> {
|
|
206
140
|
readonly _endpoints: RoomEndpoints<TIO, TMetadata>;
|
|
141
|
+
readonly metadata?: InputZodLike<TMetadata>;
|
|
207
142
|
private readonly _crdtManager;
|
|
208
143
|
private readonly _crdtNotifier;
|
|
209
144
|
private readonly _debug;
|
|
210
145
|
private readonly _eventNotifier;
|
|
211
146
|
private readonly _intervals;
|
|
212
147
|
private readonly _listeners;
|
|
213
|
-
private readonly _metadata;
|
|
214
148
|
private readonly _otherNotifier;
|
|
215
149
|
private readonly _publicKey;
|
|
150
|
+
private readonly _reconnectTimeoutMs;
|
|
216
151
|
private readonly _router;
|
|
217
152
|
private readonly _stateNotifier;
|
|
218
153
|
private readonly _storageStore;
|
|
219
154
|
private readonly _subscriptions;
|
|
220
155
|
private readonly _timeouts;
|
|
221
156
|
private readonly _usersManager;
|
|
157
|
+
private _lastMetadata;
|
|
222
158
|
private _state;
|
|
223
159
|
private _windowListeners;
|
|
224
160
|
private _wsListeners;
|
|
@@ -228,7 +164,7 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
228
164
|
broadcast: (<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(event: TEvent, data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>) => Promise<void>) & { [PEvent in keyof InferIOInput<MergeEvents<TEvents, TIO>>]: (data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[PEvent]>) => Promise<void>; };
|
|
229
165
|
canRedo: () => boolean;
|
|
230
166
|
canUndo: () => boolean;
|
|
231
|
-
connect(): Promise<void>;
|
|
167
|
+
connect(...args: RoomConnectParams<TMetadata>): Promise<void>;
|
|
232
168
|
disconnect(): Promise<void>;
|
|
233
169
|
event: (<TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(event: TEvent, callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, TEvent>) => () => void) & { [PEvent in keyof InferIOOutput<MergeEvents<TEvents, TIO>>]: (callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, PEvent>) => () => void; };
|
|
234
170
|
getConnection: () => WebSocketConnection;
|
|
@@ -275,28 +211,23 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
275
211
|
private _logDebug;
|
|
276
212
|
private _observeCrdt;
|
|
277
213
|
private _onAuthorizationFail;
|
|
278
|
-
/**
|
|
279
|
-
* TODO
|
|
280
|
-
* @description Determine if ws was closed with a code for closing without retries.
|
|
281
|
-
* Otherwise, attempt to retry again with incremental backoff
|
|
282
|
-
* @author leedavidcs
|
|
283
|
-
* @date August 19, 2022
|
|
284
|
-
*/
|
|
285
214
|
private _onClose;
|
|
286
215
|
/**
|
|
287
216
|
* TODO
|
|
288
217
|
* @description Handle websocket errors in a meaningful way, should they occur
|
|
289
|
-
* @author leedavidcs
|
|
290
218
|
* @date August 19, 2022
|
|
291
219
|
*/
|
|
292
220
|
private _onError;
|
|
293
221
|
private _onMessage;
|
|
294
222
|
private _onOpen;
|
|
223
|
+
private _onNavigatorOffline;
|
|
295
224
|
private _onNavigatorOnline;
|
|
296
225
|
private _onVisibilityChange;
|
|
297
226
|
private _parseMessage;
|
|
227
|
+
private _pollReconnect;
|
|
298
228
|
private _reconnect;
|
|
299
229
|
private _sendMessage;
|
|
230
|
+
private _setMetadata;
|
|
300
231
|
private _updateState;
|
|
301
232
|
}
|
|
302
233
|
|
|
@@ -314,17 +245,15 @@ type CreateRoomOptions<TIO extends IOLike<any, any>, TPresence extends JsonObjec
|
|
|
314
245
|
initialPresence?: TPresence;
|
|
315
246
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
316
247
|
onAuthorizationFail?: (error: Error) => void;
|
|
248
|
+
reconnectTimeoutMs?: ReconnectTimeoutMs;
|
|
317
249
|
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
} : {
|
|
321
|
-
metadata: TMetadata;
|
|
322
|
-
});
|
|
250
|
+
};
|
|
251
|
+
type EnterRoomParams<TMetadata extends JsonObject = {}> = keyof TMetadata extends never ? [] : [WithMetadata<TMetadata>];
|
|
323
252
|
declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TMetadata extends JsonObject = {}> {
|
|
253
|
+
readonly metadata?: InputZodLike<TMetadata>;
|
|
324
254
|
private readonly _authEndpoint;
|
|
325
255
|
private readonly _debug;
|
|
326
256
|
private readonly _initialStorage?;
|
|
327
|
-
private readonly _metadata?;
|
|
328
257
|
private readonly _presence?;
|
|
329
258
|
private readonly _publicKey;
|
|
330
259
|
private readonly _rooms;
|
|
@@ -335,7 +264,7 @@ declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObj
|
|
|
335
264
|
get procedure(): PluvProcedure<TIO, {}, {}, TPresence, TStorage>;
|
|
336
265
|
constructor(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>);
|
|
337
266
|
createRoom: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(room: string, options: CreateRoomOptions<TIO, TPresence, TStorage, TMetadata, TEvents>) => PluvRoom<TIO, TMetadata, TPresence, TStorage, TEvents>;
|
|
338
|
-
enter: (room: string | PluvRoom<TIO, any, any, any>) => Promise<PluvRoom<TIO, TMetadata, TPresence, TStorage, any>>;
|
|
267
|
+
enter: (room: string | PluvRoom<TIO, TMetadata, any, any, any>, ...args: EnterRoomParams<TMetadata>) => Promise<PluvRoom<TIO, TMetadata, TPresence, TStorage, any>>;
|
|
339
268
|
getRoom: (room: string) => PluvRoom<TIO, TMetadata, TPresence, TStorage, any> | null;
|
|
340
269
|
getRooms: () => readonly PluvRoom<TIO, TMetadata, TPresence, TStorage, any>[];
|
|
341
270
|
leave: (room: string | PluvRoom<TIO, any, any, any>) => Promise<void>;
|
|
@@ -343,6 +272,94 @@ declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObj
|
|
|
343
272
|
private _logDebug;
|
|
344
273
|
}
|
|
345
274
|
|
|
275
|
+
interface AuthorizationState<TIO extends IOLike> {
|
|
276
|
+
token: string | null;
|
|
277
|
+
user: InferIOAuthorizeUser<InferIOAuthorize<TIO>> | null;
|
|
278
|
+
}
|
|
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
|
+
interface EventResolverContext<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
281
|
+
doc: AbstractCrdtDoc<TStorage>;
|
|
282
|
+
others: readonly UserInfo<TIO, TPresence>[];
|
|
283
|
+
room: string;
|
|
284
|
+
user: UserInfo<TIO, TPresence>;
|
|
285
|
+
}
|
|
286
|
+
type InferMetadata<TClient extends PluvClient<any, any, any, any>> = TClient extends PluvClient<any, any, any, infer IMetadata> ? IMetadata : never;
|
|
287
|
+
type MergeEventRecords<TEventRecords extends EventRecord<string, any>[], TRoot extends EventRecord<string, any> = {}> = TEventRecords extends [
|
|
288
|
+
infer IHead extends EventRecord<string, any>,
|
|
289
|
+
...infer ITail extends EventRecord<string, any>[]
|
|
290
|
+
] ? MergeEventRecords<ITail, Omit<TRoot, keyof IHead> & {
|
|
291
|
+
[P in keyof IHead]: TRoot extends Record<P, any> ? TRoot[P] | IHead[P] : IHead[P];
|
|
292
|
+
}> : Id<TRoot>;
|
|
293
|
+
interface PublicKeyParams<TMetadata extends JsonObject> {
|
|
294
|
+
metadata: TMetadata;
|
|
295
|
+
}
|
|
296
|
+
type PublicKey<TMetadata extends JsonObject> = string | ((params: PublicKeyParams<TMetadata>) => string);
|
|
297
|
+
type UpdateMyPresenceAction<TPresence extends JsonObject> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
|
|
298
|
+
interface UserInfo<TIO extends IOLike, TPresence extends JsonObject = {}> {
|
|
299
|
+
connectionId: string;
|
|
300
|
+
presence: TPresence;
|
|
301
|
+
user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;
|
|
302
|
+
}
|
|
303
|
+
interface WebSocketConnection {
|
|
304
|
+
/**
|
|
305
|
+
* @description How many times a connection attempt was made. This will increment upon each
|
|
306
|
+
* unsuccessful attempt, and will reset upon a successful connection.
|
|
307
|
+
* @date April 13, 2025
|
|
308
|
+
*/
|
|
309
|
+
attempts: number;
|
|
310
|
+
/**
|
|
311
|
+
* @description How many times the user has connected to the room. This can be more than 1 in
|
|
312
|
+
* the case of reconnects. This is tracked because on the very first connection (i.e. when
|
|
313
|
+
* count is 0) we don't want to send the storage state as an update to the room and overwrite
|
|
314
|
+
* the upstream state.
|
|
315
|
+
* @date April 13, 2025
|
|
316
|
+
*/
|
|
317
|
+
count: number;
|
|
318
|
+
id: string | null;
|
|
319
|
+
state: ConnectionState;
|
|
320
|
+
}
|
|
321
|
+
interface WebSocketState<TIO extends IOLike> {
|
|
322
|
+
authorization: AuthorizationState<TIO>;
|
|
323
|
+
connection: WebSocketConnection;
|
|
324
|
+
webSocket: WebSocket | null;
|
|
325
|
+
}
|
|
326
|
+
type WithMetadata<TMetadata extends JsonObject = {}> = keyof TMetadata extends never ? {
|
|
327
|
+
metadata?: undefined;
|
|
328
|
+
} : {
|
|
329
|
+
metadata: TMetadata;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
type OtherNotifierSubscriptionCallback<TIO extends IOLike> = (value: Id<UserInfo<TIO>> | null) => void;
|
|
333
|
+
|
|
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
|
+
readonly id: string;
|
|
336
|
+
constructor(room: string);
|
|
337
|
+
abstract storageLoaded: boolean;
|
|
338
|
+
abstract broadcast<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(event: TEvent, data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>): void;
|
|
339
|
+
abstract canRedo(): boolean;
|
|
340
|
+
abstract canUndo(): boolean;
|
|
341
|
+
abstract getDoc(): AbstractCrdtDoc<TStorage>;
|
|
342
|
+
abstract event<TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(event: TEvent, callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, TEvent>): () => void;
|
|
343
|
+
abstract getConnection(): WebSocketConnection;
|
|
344
|
+
abstract getMyPresence(): TPresence;
|
|
345
|
+
abstract getMyself(): Id<UserInfo<TIO, TPresence>> | null;
|
|
346
|
+
abstract getOther(connectionId: string): Id<UserInfo<TIO, TPresence>> | null;
|
|
347
|
+
abstract getOthers(): readonly Id<UserInfo<TIO, TPresence>>[];
|
|
348
|
+
abstract getStorage<TKey extends keyof TStorage>(type: TKey): TStorage[TKey] | null;
|
|
349
|
+
abstract getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
350
|
+
abstract getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
351
|
+
abstract other(connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>): () => void;
|
|
352
|
+
abstract redo(): void;
|
|
353
|
+
abstract storage<TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void): () => void;
|
|
354
|
+
abstract storageRoot(fn: (value: {
|
|
355
|
+
[P in keyof TStorage]: InferCrdtJson<TStorage[P]>;
|
|
356
|
+
}) => void): () => void;
|
|
357
|
+
abstract subscribe<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(name: TSubject, callback: SubscriptionCallback<TIO, TPresence, TSubject>): () => void;
|
|
358
|
+
abstract transact(fn: (storage: TStorage) => void, origin?: string): void;
|
|
359
|
+
abstract undo(): void;
|
|
360
|
+
abstract updateMyPresence(presence: UpdateMyPresenceAction<TPresence>): void;
|
|
361
|
+
}
|
|
362
|
+
|
|
346
363
|
declare const createClient: <TIO extends IOLike<any, any>, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TMetadata extends JsonObject = {}>(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>) => PluvClient<TIO, TPresence, TStorage, TMetadata>;
|
|
347
364
|
|
|
348
365
|
type MockedRoomEvents<TIO extends IOLike> = Partial<{
|
|
@@ -400,4 +417,4 @@ declare const register: <TMetadata extends JsonObject>(params: RegisterParams<TM
|
|
|
400
417
|
wsEndpoint: (params: EndpointParams<TMetadata>) => string;
|
|
401
418
|
};
|
|
402
419
|
|
|
403
|
-
export { AbstractRoom, AbstractStorageStore, ConnectionState, type CreateRoomOptions, type InferCallback, type MergeEvents, MockedRoom, type MockedRoomConfig, type MockedRoomEvents, PluvClient, type PluvClientOptions, type PluvProcedureConfig, PluvRoom, type PluvRoomAddon, type PluvRoomAddonInput, type PluvRoomAddonResult, type PluvRoomDebug, PluvRouter, type PluvRouterEventConfig, type PublicKey, type PublicKeyParams, type RegisterParams, type RoomEndpoints, type UserInfo, type WebSocketConnection, type WebSocketState, createClient, infer, register };
|
|
420
|
+
export { AbstractRoom, AbstractStorageStore, ConnectionState, type CreateRoomOptions, type EnterRoomParams, type InferCallback, type InferMetadata, type MergeEvents, MockedRoom, type MockedRoomConfig, type MockedRoomEvents, PluvClient, type PluvClientOptions, type PluvProcedureConfig, PluvRoom, type PluvRoomAddon, type PluvRoomAddonInput, type PluvRoomAddonResult, type PluvRoomDebug, PluvRouter, type PluvRouterEventConfig, type PublicKey, type PublicKeyParams, type RegisterParams, type RoomConnectParams, type RoomEndpoints, type UserInfo, type WebSocketConnection, type WebSocketState, createClient, infer, register };
|