@abraca/dabra 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hocuspocus-provider.cjs +3237 -0
- package/dist/hocuspocus-provider.cjs.map +1 -0
- package/dist/hocuspocus-provider.esm.js +3199 -0
- package/dist/hocuspocus-provider.esm.js.map +1 -0
- package/dist/index.d.ts +784 -0
- package/package.json +42 -0
- package/src/AbracadabraProvider.ts +381 -0
- package/src/CryptoIdentityKeystore.ts +294 -0
- package/src/EventEmitter.ts +44 -0
- package/src/HocuspocusProvider.ts +603 -0
- package/src/HocuspocusProviderWebsocket.ts +533 -0
- package/src/IncomingMessage.ts +63 -0
- package/src/MessageReceiver.ts +139 -0
- package/src/MessageSender.ts +22 -0
- package/src/OfflineStore.ts +185 -0
- package/src/OutgoingMessage.ts +25 -0
- package/src/OutgoingMessages/AuthenticationMessage.ts +25 -0
- package/src/OutgoingMessages/AwarenessMessage.ts +41 -0
- package/src/OutgoingMessages/CloseMessage.ts +17 -0
- package/src/OutgoingMessages/QueryAwarenessMessage.ts +17 -0
- package/src/OutgoingMessages/StatelessMessage.ts +18 -0
- package/src/OutgoingMessages/SubdocMessage.ts +35 -0
- package/src/OutgoingMessages/SyncStepOneMessage.ts +25 -0
- package/src/OutgoingMessages/SyncStepTwoMessage.ts +25 -0
- package/src/OutgoingMessages/UpdateMessage.ts +20 -0
- package/src/index.ts +7 -0
- package/src/types.ts +144 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
import { Event, MessageEvent } from "ws";
|
|
2
|
+
import * as Y from "yjs";
|
|
3
|
+
|
|
4
|
+
//#region node_modules/lib0/observable.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Handles named events.
|
|
7
|
+
*
|
|
8
|
+
* @deprecated
|
|
9
|
+
* @template N
|
|
10
|
+
*/
|
|
11
|
+
declare class Observable<N> {
|
|
12
|
+
/**
|
|
13
|
+
* Some desc.
|
|
14
|
+
* @type {Map<N, any>}
|
|
15
|
+
*/
|
|
16
|
+
_observers: Map<N, any>;
|
|
17
|
+
/**
|
|
18
|
+
* @param {N} name
|
|
19
|
+
* @param {function} f
|
|
20
|
+
*/
|
|
21
|
+
on(name: N, f: Function): void;
|
|
22
|
+
/**
|
|
23
|
+
* @param {N} name
|
|
24
|
+
* @param {function} f
|
|
25
|
+
*/
|
|
26
|
+
once(name: N, f: Function): void;
|
|
27
|
+
/**
|
|
28
|
+
* @param {N} name
|
|
29
|
+
* @param {function} f
|
|
30
|
+
*/
|
|
31
|
+
off(name: N, f: Function): void;
|
|
32
|
+
/**
|
|
33
|
+
* Emit a named event. All registered event listeners that listen to the
|
|
34
|
+
* specified name will receive the event.
|
|
35
|
+
*
|
|
36
|
+
* @todo This should catch exceptions
|
|
37
|
+
*
|
|
38
|
+
* @param {N} name The event name.
|
|
39
|
+
* @param {Array<any>} args The arguments that are applied to the event listener.
|
|
40
|
+
*/
|
|
41
|
+
emit(name: N, args: Array<any>): void;
|
|
42
|
+
destroy(): void;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region node_modules/y-protocols/awareness.d.ts
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {Object} MetaClientState
|
|
48
|
+
* @property {number} MetaClientState.clock
|
|
49
|
+
* @property {number} MetaClientState.lastUpdated unix timestamp
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information
|
|
53
|
+
* (cursor, username, status, ..). Each client can update its own local state and listen to state changes of
|
|
54
|
+
* remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline.
|
|
55
|
+
*
|
|
56
|
+
* Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override
|
|
57
|
+
* its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is
|
|
58
|
+
* applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that
|
|
59
|
+
* a remote client is offline, it may propagate a message with
|
|
60
|
+
* `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a
|
|
61
|
+
* message is received, and the known clock of that client equals the received clock, it will override the state with `null`.
|
|
62
|
+
*
|
|
63
|
+
* Before a client disconnects, it should propagate a `null` state with an updated clock.
|
|
64
|
+
*
|
|
65
|
+
* Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state.
|
|
66
|
+
*
|
|
67
|
+
* @extends {Observable<string>}
|
|
68
|
+
*/
|
|
69
|
+
declare class Awareness extends Observable<string> {
|
|
70
|
+
/**
|
|
71
|
+
* @param {Y.Doc} doc
|
|
72
|
+
*/
|
|
73
|
+
constructor(doc: Y.Doc);
|
|
74
|
+
doc: Y.Doc;
|
|
75
|
+
/**
|
|
76
|
+
* @type {number}
|
|
77
|
+
*/
|
|
78
|
+
clientID: number;
|
|
79
|
+
/**
|
|
80
|
+
* Maps from client id to client state
|
|
81
|
+
* @type {Map<number, Object<string, any>>}
|
|
82
|
+
*/
|
|
83
|
+
states: Map<number, {
|
|
84
|
+
[x: string]: any;
|
|
85
|
+
}>;
|
|
86
|
+
/**
|
|
87
|
+
* @type {Map<number, MetaClientState>}
|
|
88
|
+
*/
|
|
89
|
+
meta: Map<number, MetaClientState>;
|
|
90
|
+
_checkInterval: any;
|
|
91
|
+
/**
|
|
92
|
+
* @return {Object<string,any>|null}
|
|
93
|
+
*/
|
|
94
|
+
getLocalState(): {
|
|
95
|
+
[x: string]: any;
|
|
96
|
+
} | null;
|
|
97
|
+
/**
|
|
98
|
+
* @param {Object<string,any>|null} state
|
|
99
|
+
*/
|
|
100
|
+
setLocalState(state: {
|
|
101
|
+
[x: string]: any;
|
|
102
|
+
} | null): void;
|
|
103
|
+
/**
|
|
104
|
+
* @param {string} field
|
|
105
|
+
* @param {any} value
|
|
106
|
+
*/
|
|
107
|
+
setLocalStateField(field: string, value: any): void;
|
|
108
|
+
/**
|
|
109
|
+
* @return {Map<number,Object<string,any>>}
|
|
110
|
+
*/
|
|
111
|
+
getStates(): Map<number, {
|
|
112
|
+
[x: string]: any;
|
|
113
|
+
}>;
|
|
114
|
+
}
|
|
115
|
+
type MetaClientState = {
|
|
116
|
+
clock: number;
|
|
117
|
+
/**
|
|
118
|
+
* unix timestamp
|
|
119
|
+
*/
|
|
120
|
+
lastUpdated: number;
|
|
121
|
+
};
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region packages/provider/src/EventEmitter.d.ts
|
|
124
|
+
declare class EventEmitter {
|
|
125
|
+
callbacks: {
|
|
126
|
+
[key: string]: Function[];
|
|
127
|
+
};
|
|
128
|
+
on(event: string, fn: Function): this;
|
|
129
|
+
protected emit(event: string, ...args: any): this;
|
|
130
|
+
off(event: string, fn?: Function): this;
|
|
131
|
+
removeAllListeners(): void;
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region packages/provider/src/AbracadabraProvider.d.ts
|
|
135
|
+
interface AbracadabraProviderConfiguration extends HocuspocusProviderConfiguration {
|
|
136
|
+
/**
|
|
137
|
+
* Subdocument loading strategy.
|
|
138
|
+
* - "lazy" (default) – child providers are created only when explicitly requested.
|
|
139
|
+
* - "eager" – all children returned by the server on connect are loaded automatically.
|
|
140
|
+
*/
|
|
141
|
+
subdocLoading?: "lazy" | "eager";
|
|
142
|
+
/** Called when the server confirms a subdoc registration. */
|
|
143
|
+
onSubdocRegistered?: (data: onSubdocRegisteredParameters) => void;
|
|
144
|
+
/** Called when a child AbracadabraProvider has been created and attached. */
|
|
145
|
+
onSubdocLoaded?: (data: onSubdocLoadedParameters) => void;
|
|
146
|
+
/**
|
|
147
|
+
* Disable the IndexedDB offline store. Useful for server-side rendering
|
|
148
|
+
* or testing environments that lack IndexedDB.
|
|
149
|
+
*/
|
|
150
|
+
disableOfflineStore?: boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Identity for passwordless crypto auth (Model B multi-key).
|
|
153
|
+
* Mutually exclusive with token.
|
|
154
|
+
*/
|
|
155
|
+
cryptoIdentity?: CryptoIdentity | (() => Promise<CryptoIdentity>);
|
|
156
|
+
/**
|
|
157
|
+
* Signs a base64url challenge and returns a base64url signature.
|
|
158
|
+
* Required when cryptoIdentity is set.
|
|
159
|
+
*/
|
|
160
|
+
signChallenge?: (challenge: string) => Promise<string>;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* AbracadabraProvider extends HocuspocusProvider with:
|
|
164
|
+
*
|
|
165
|
+
* 1. Subdocument lifecycle – intercepts Y.Doc subdoc events and syncs them
|
|
166
|
+
* with the server via MSG_SUBDOC (4) frames. Child documents get their
|
|
167
|
+
* own AbracadabraProvider instances sharing the same WebSocket connection.
|
|
168
|
+
*
|
|
169
|
+
* 2. Offline-first – persists CRDT updates to IndexedDB so they survive
|
|
170
|
+
* page reloads and network outages. On reconnect, pending updates are
|
|
171
|
+
* flushed before resuming normal sync.
|
|
172
|
+
*
|
|
173
|
+
* 3. Permission snapshotting – stores the resolved role locally so the UI
|
|
174
|
+
* can gate write operations without a network round-trip. Role is
|
|
175
|
+
* refreshed from the server on every reconnect.
|
|
176
|
+
*/
|
|
177
|
+
declare class AbracadabraProvider extends HocuspocusProvider {
|
|
178
|
+
effectiveRole: EffectiveRole;
|
|
179
|
+
private offlineStore;
|
|
180
|
+
private childProviders;
|
|
181
|
+
private subdocLoading;
|
|
182
|
+
private abracadabraConfig;
|
|
183
|
+
private readonly boundHandleYSubdocsChange;
|
|
184
|
+
constructor(configuration: AbracadabraProviderConfiguration);
|
|
185
|
+
authenticatedHandler(scope: string): void;
|
|
186
|
+
/**
|
|
187
|
+
* Override sendToken to send an identity declaration instead of a JWT
|
|
188
|
+
* when cryptoIdentity is configured.
|
|
189
|
+
*/
|
|
190
|
+
sendToken(): Promise<void>;
|
|
191
|
+
/** Handle an auth_challenge message from the server. */
|
|
192
|
+
private handleAuthChallenge;
|
|
193
|
+
private restorePermissionSnapshot;
|
|
194
|
+
get canWrite(): boolean;
|
|
195
|
+
/**
|
|
196
|
+
* Called when a MSG_STATELESS frame arrives from the server.
|
|
197
|
+
* Abracadabra uses stateless frames to deliver subdoc confirmations
|
|
198
|
+
* ({ type: "subdoc_registered", child_id, parent_id }).
|
|
199
|
+
*/
|
|
200
|
+
receiveStateless(payload: string): void;
|
|
201
|
+
/**
|
|
202
|
+
* Y.Doc emits 'subdocs' whenever subdocuments are added, removed, or loaded.
|
|
203
|
+
* We intercept additions to register them with the Abracadabra server.
|
|
204
|
+
*/
|
|
205
|
+
private handleYSubdocsChange;
|
|
206
|
+
/**
|
|
207
|
+
* Send a subdoc registration frame to the server.
|
|
208
|
+
* If offline the event is queued in IndexedDB and replayed on reconnect.
|
|
209
|
+
*/
|
|
210
|
+
private registerSubdoc;
|
|
211
|
+
/**
|
|
212
|
+
* Create (or return cached) a child AbracadabraProvider for a given
|
|
213
|
+
* child document id. The child shares the parent's WebSocket connection.
|
|
214
|
+
*/
|
|
215
|
+
loadChild(childId: string): Promise<AbracadabraProvider>;
|
|
216
|
+
private unloadChild;
|
|
217
|
+
/** Return all currently-loaded child providers. */
|
|
218
|
+
get children(): Map<string, AbracadabraProvider>;
|
|
219
|
+
/**
|
|
220
|
+
* Override to persist every local update to IndexedDB before sending it
|
|
221
|
+
* over the wire, ensuring no work is lost during connection outages.
|
|
222
|
+
*/
|
|
223
|
+
documentUpdateHandler(update: Uint8Array, origin: unknown): void;
|
|
224
|
+
/**
|
|
225
|
+
* After reconnect + sync, flush any updates that were generated while
|
|
226
|
+
* offline, then flush any queued subdoc registrations.
|
|
227
|
+
*/
|
|
228
|
+
private flushPendingUpdates;
|
|
229
|
+
get isConnected(): boolean;
|
|
230
|
+
destroy(): void;
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region node_modules/lib0/encoding.d.ts
|
|
234
|
+
/**
|
|
235
|
+
* A BinaryEncoder handles the encoding to an Uint8Array.
|
|
236
|
+
*/
|
|
237
|
+
declare class Encoder {
|
|
238
|
+
cpos: number;
|
|
239
|
+
cbuf: Uint8Array<ArrayBuffer>;
|
|
240
|
+
/**
|
|
241
|
+
* @type {Array<Uint8Array>}
|
|
242
|
+
*/
|
|
243
|
+
bufs: Array<Uint8Array>;
|
|
244
|
+
}
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region node_modules/lib0/decoding.d.ts
|
|
247
|
+
/**
|
|
248
|
+
* A Decoder handles the decoding of an Uint8Array.
|
|
249
|
+
* @template {ArrayBufferLike} [Buf=ArrayBufferLike]
|
|
250
|
+
*/
|
|
251
|
+
declare class Decoder<Buf extends ArrayBufferLike = ArrayBufferLike> {
|
|
252
|
+
/**
|
|
253
|
+
* @param {Uint8Array<Buf>} uint8Array Binary data to decode
|
|
254
|
+
*/
|
|
255
|
+
constructor(uint8Array: Uint8Array<Buf>);
|
|
256
|
+
/**
|
|
257
|
+
* Decoding target.
|
|
258
|
+
*
|
|
259
|
+
* @type {Uint8Array<Buf>}
|
|
260
|
+
*/
|
|
261
|
+
arr: Uint8Array<Buf>;
|
|
262
|
+
/**
|
|
263
|
+
* Current decoding position.
|
|
264
|
+
*
|
|
265
|
+
* @type {number}
|
|
266
|
+
*/
|
|
267
|
+
pos: number;
|
|
268
|
+
}
|
|
269
|
+
//#endregion
|
|
270
|
+
//#region packages/common/src/CloseEvents.d.ts
|
|
271
|
+
interface CloseEvent {
|
|
272
|
+
code: number;
|
|
273
|
+
reason: string;
|
|
274
|
+
}
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region packages/provider/src/IncomingMessage.d.ts
|
|
277
|
+
declare class IncomingMessage {
|
|
278
|
+
data: any;
|
|
279
|
+
encoder: Encoder;
|
|
280
|
+
decoder: Decoder;
|
|
281
|
+
constructor(data: any);
|
|
282
|
+
peekVarString(): string;
|
|
283
|
+
readVarUint(): MessageType;
|
|
284
|
+
readVarString(): string;
|
|
285
|
+
readVarUint8Array(): Uint8Array<ArrayBufferLike>;
|
|
286
|
+
writeVarUint(type: MessageType): void;
|
|
287
|
+
writeVarString(string: string): void;
|
|
288
|
+
writeVarUint8Array(data: Uint8Array): void;
|
|
289
|
+
length(): number;
|
|
290
|
+
}
|
|
291
|
+
//#endregion
|
|
292
|
+
//#region packages/provider/src/OutgoingMessage.d.ts
|
|
293
|
+
declare class OutgoingMessage implements OutgoingMessageInterface {
|
|
294
|
+
encoder: Encoder;
|
|
295
|
+
type?: MessageType;
|
|
296
|
+
constructor();
|
|
297
|
+
get(args: Partial<OutgoingMessageArguments>): Encoder | undefined;
|
|
298
|
+
toUint8Array(): Uint8Array<ArrayBuffer>;
|
|
299
|
+
}
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region packages/provider/src/OutgoingMessages/AuthenticationMessage.d.ts
|
|
302
|
+
declare class AuthenticationMessage extends OutgoingMessage {
|
|
303
|
+
type: MessageType;
|
|
304
|
+
description: string;
|
|
305
|
+
get(args: Partial<OutgoingMessageArguments>): Encoder;
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region packages/provider/src/OutgoingMessages/AwarenessMessage.d.ts
|
|
309
|
+
declare class AwarenessMessage extends OutgoingMessage {
|
|
310
|
+
type: MessageType;
|
|
311
|
+
description: string;
|
|
312
|
+
get(args: Partial<OutgoingMessageArguments>): Encoder;
|
|
313
|
+
}
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region packages/provider/src/OutgoingMessages/QueryAwarenessMessage.d.ts
|
|
316
|
+
declare class QueryAwarenessMessage extends OutgoingMessage {
|
|
317
|
+
type: MessageType;
|
|
318
|
+
description: string;
|
|
319
|
+
get(args: Partial<OutgoingMessageArguments>): Encoder;
|
|
320
|
+
}
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region packages/provider/src/OutgoingMessages/SyncStepOneMessage.d.ts
|
|
323
|
+
declare class SyncStepOneMessage extends OutgoingMessage {
|
|
324
|
+
type: MessageType;
|
|
325
|
+
description: string;
|
|
326
|
+
get(args: Partial<OutgoingMessageArguments>): Encoder;
|
|
327
|
+
}
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region packages/provider/src/OutgoingMessages/SyncStepTwoMessage.d.ts
|
|
330
|
+
declare class SyncStepTwoMessage extends OutgoingMessage {
|
|
331
|
+
type: MessageType;
|
|
332
|
+
description: string;
|
|
333
|
+
get(args: Partial<OutgoingMessageArguments>): Encoder;
|
|
334
|
+
}
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region packages/provider/src/OutgoingMessages/UpdateMessage.d.ts
|
|
337
|
+
declare class UpdateMessage extends OutgoingMessage {
|
|
338
|
+
type: MessageType;
|
|
339
|
+
description: string;
|
|
340
|
+
get(args: Partial<OutgoingMessageArguments>): Encoder;
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region packages/provider/src/types.d.ts
|
|
344
|
+
declare enum MessageType {
|
|
345
|
+
Sync = 0,
|
|
346
|
+
Awareness = 1,
|
|
347
|
+
Auth = 2,
|
|
348
|
+
QueryAwareness = 3,
|
|
349
|
+
Subdoc = 4,
|
|
350
|
+
Stateless = 5,
|
|
351
|
+
CLOSE = 7,
|
|
352
|
+
SyncStatus = 8
|
|
353
|
+
}
|
|
354
|
+
declare enum WebSocketStatus {
|
|
355
|
+
Connecting = "connecting",
|
|
356
|
+
Connected = "connected",
|
|
357
|
+
Disconnected = "disconnected"
|
|
358
|
+
}
|
|
359
|
+
type AuthorizedScope = "read-write" | "readonly";
|
|
360
|
+
interface OutgoingMessageInterface {
|
|
361
|
+
encoder: Encoder;
|
|
362
|
+
type?: MessageType;
|
|
363
|
+
}
|
|
364
|
+
interface OutgoingMessageArguments {
|
|
365
|
+
documentName: string;
|
|
366
|
+
token: string;
|
|
367
|
+
document: Y.Doc;
|
|
368
|
+
awareness: Awareness;
|
|
369
|
+
clients: number[];
|
|
370
|
+
states: Map<number, {
|
|
371
|
+
[key: string]: any;
|
|
372
|
+
}>;
|
|
373
|
+
update: any;
|
|
374
|
+
payload: string;
|
|
375
|
+
encoder: Encoder;
|
|
376
|
+
}
|
|
377
|
+
interface Constructable<T> {
|
|
378
|
+
new (...args: any): T;
|
|
379
|
+
}
|
|
380
|
+
type ConstructableOutgoingMessage = Constructable<AuthenticationMessage> | Constructable<AwarenessMessage> | Constructable<QueryAwarenessMessage> | Constructable<SyncStepOneMessage> | Constructable<SyncStepTwoMessage> | Constructable<UpdateMessage>;
|
|
381
|
+
type onAuthenticationFailedParameters = {
|
|
382
|
+
reason: string;
|
|
383
|
+
};
|
|
384
|
+
type onAuthenticatedParameters = {
|
|
385
|
+
scope: AuthorizedScope;
|
|
386
|
+
};
|
|
387
|
+
type onOpenParameters = {
|
|
388
|
+
event: Event;
|
|
389
|
+
};
|
|
390
|
+
type onMessageParameters = {
|
|
391
|
+
event: MessageEvent;
|
|
392
|
+
message: IncomingMessage;
|
|
393
|
+
};
|
|
394
|
+
type onOutgoingMessageParameters = {
|
|
395
|
+
message: OutgoingMessage;
|
|
396
|
+
};
|
|
397
|
+
type onStatusParameters = {
|
|
398
|
+
status: WebSocketStatus;
|
|
399
|
+
};
|
|
400
|
+
type onSyncedParameters = {
|
|
401
|
+
state: boolean;
|
|
402
|
+
};
|
|
403
|
+
type onUnsyncedChangesParameters = {
|
|
404
|
+
number: number;
|
|
405
|
+
};
|
|
406
|
+
type onDisconnectParameters = {
|
|
407
|
+
event: CloseEvent;
|
|
408
|
+
};
|
|
409
|
+
type onCloseParameters = {
|
|
410
|
+
event: CloseEvent;
|
|
411
|
+
};
|
|
412
|
+
type onAwarenessUpdateParameters = {
|
|
413
|
+
states: StatesArray;
|
|
414
|
+
};
|
|
415
|
+
type onAwarenessChangeParameters = {
|
|
416
|
+
states: StatesArray;
|
|
417
|
+
};
|
|
418
|
+
type onStatelessParameters = {
|
|
419
|
+
payload: string;
|
|
420
|
+
};
|
|
421
|
+
type StatesArray = {
|
|
422
|
+
clientId: number;
|
|
423
|
+
[key: string | number]: any;
|
|
424
|
+
}[];
|
|
425
|
+
type EffectiveRole = "owner" | "editor" | "viewer" | null;
|
|
426
|
+
/** Ed25519 identity for passwordless crypto auth (Model B multi-key). */
|
|
427
|
+
interface CryptoIdentity {
|
|
428
|
+
username: string;
|
|
429
|
+
/** base64url-encoded Ed25519 public key (32 bytes) */
|
|
430
|
+
publicKey: string;
|
|
431
|
+
}
|
|
432
|
+
interface SubdocRegisteredEvent {
|
|
433
|
+
childId: string;
|
|
434
|
+
parentId: string;
|
|
435
|
+
}
|
|
436
|
+
type onSubdocRegisteredParameters = SubdocRegisteredEvent;
|
|
437
|
+
type onSubdocLoadedParameters = {
|
|
438
|
+
childId: string;
|
|
439
|
+
provider: AbracadabraProvider;
|
|
440
|
+
};
|
|
441
|
+
interface AbracadabraOutgoingMessageArguments extends OutgoingMessageArguments {
|
|
442
|
+
childDocumentName: string;
|
|
443
|
+
}
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region packages/provider/src/HocuspocusProviderWebsocket.d.ts
|
|
446
|
+
type HocuspocusWebSocket = WebSocket & {
|
|
447
|
+
identifier: string;
|
|
448
|
+
};
|
|
449
|
+
type HocusPocusWebSocket = HocuspocusWebSocket;
|
|
450
|
+
type HocuspocusProviderWebsocketConfiguration = Required<Pick<CompleteHocuspocusProviderWebsocketConfiguration, "url">> & Partial<CompleteHocuspocusProviderWebsocketConfiguration>;
|
|
451
|
+
interface CompleteHocuspocusProviderWebsocketConfiguration {
|
|
452
|
+
/**
|
|
453
|
+
* Whether to connect automatically when creating the provider instance. Default=true
|
|
454
|
+
*/
|
|
455
|
+
autoConnect: boolean;
|
|
456
|
+
/**
|
|
457
|
+
* URL of your @hocuspocus/server instance
|
|
458
|
+
*/
|
|
459
|
+
url: string;
|
|
460
|
+
/**
|
|
461
|
+
* By default, trailing slashes are removed from the URL. Set this to true
|
|
462
|
+
* to preserve trailing slashes if your server configuration requires them.
|
|
463
|
+
*/
|
|
464
|
+
preserveTrailingSlash: boolean;
|
|
465
|
+
/**
|
|
466
|
+
* An optional WebSocket polyfill, for example for Node.js
|
|
467
|
+
*/
|
|
468
|
+
WebSocketPolyfill: any;
|
|
469
|
+
/**
|
|
470
|
+
* Disconnect when no message is received for the defined amount of milliseconds.
|
|
471
|
+
*/
|
|
472
|
+
messageReconnectTimeout: number;
|
|
473
|
+
/**
|
|
474
|
+
* The delay between each attempt in milliseconds. You can provide a factor to have the delay grow exponentially.
|
|
475
|
+
*/
|
|
476
|
+
delay: number;
|
|
477
|
+
/**
|
|
478
|
+
* The initialDelay is the amount of time to wait before making the first attempt. This option should typically be 0 since you typically want the first attempt to happen immediately.
|
|
479
|
+
*/
|
|
480
|
+
initialDelay: number;
|
|
481
|
+
/**
|
|
482
|
+
* The factor option is used to grow the delay exponentially.
|
|
483
|
+
*/
|
|
484
|
+
factor: number;
|
|
485
|
+
/**
|
|
486
|
+
* The maximum number of attempts or 0 if there is no limit on number of attempts.
|
|
487
|
+
*/
|
|
488
|
+
maxAttempts: number;
|
|
489
|
+
/**
|
|
490
|
+
* minDelay is used to set a lower bound of delay when jitter is enabled. This property has no effect if jitter is disabled.
|
|
491
|
+
*/
|
|
492
|
+
minDelay: number;
|
|
493
|
+
/**
|
|
494
|
+
* The maxDelay option is used to set an upper bound for the delay when factor is enabled. A value of 0 can be provided if there should be no upper bound when calculating delay.
|
|
495
|
+
*/
|
|
496
|
+
maxDelay: number;
|
|
497
|
+
/**
|
|
498
|
+
* If jitter is true then the calculated delay will be a random integer value between minDelay and the calculated delay for the current iteration.
|
|
499
|
+
*/
|
|
500
|
+
jitter: boolean;
|
|
501
|
+
/**
|
|
502
|
+
* A timeout in milliseconds. If timeout is non-zero then a timer is set using setTimeout. If the timeout is triggered then future attempts will be aborted.
|
|
503
|
+
*/
|
|
504
|
+
timeout: number;
|
|
505
|
+
handleTimeout: (() => Promise<unknown>) | null;
|
|
506
|
+
onOpen: (data: onOpenParameters) => void;
|
|
507
|
+
onConnect: () => void;
|
|
508
|
+
onMessage: (data: onMessageParameters) => void;
|
|
509
|
+
onOutgoingMessage: (data: onOutgoingMessageParameters) => void;
|
|
510
|
+
onStatus: (data: onStatusParameters) => void;
|
|
511
|
+
onDisconnect: (data: onDisconnectParameters) => void;
|
|
512
|
+
onClose: (data: onCloseParameters) => void;
|
|
513
|
+
onDestroy: () => void;
|
|
514
|
+
onAwarenessUpdate: (data: onAwarenessUpdateParameters) => void;
|
|
515
|
+
onAwarenessChange: (data: onAwarenessChangeParameters) => void;
|
|
516
|
+
/**
|
|
517
|
+
* Map of attached providers keyed by documentName.
|
|
518
|
+
*/
|
|
519
|
+
providerMap: Map<string, HocuspocusProvider>;
|
|
520
|
+
}
|
|
521
|
+
declare class HocuspocusProviderWebsocket extends EventEmitter {
|
|
522
|
+
private messageQueue;
|
|
523
|
+
configuration: CompleteHocuspocusProviderWebsocketConfiguration;
|
|
524
|
+
webSocket: HocusPocusWebSocket | null;
|
|
525
|
+
webSocketHandlers: {
|
|
526
|
+
[key: string]: any;
|
|
527
|
+
};
|
|
528
|
+
shouldConnect: boolean;
|
|
529
|
+
status: WebSocketStatus;
|
|
530
|
+
lastMessageReceived: number;
|
|
531
|
+
identifier: number;
|
|
532
|
+
intervals: any;
|
|
533
|
+
connectionAttempt: {
|
|
534
|
+
resolve: (value?: any) => void;
|
|
535
|
+
reject: (reason?: any) => void;
|
|
536
|
+
} | null;
|
|
537
|
+
constructor(configuration: HocuspocusProviderWebsocketConfiguration);
|
|
538
|
+
receivedOnOpenPayload?: Event | undefined;
|
|
539
|
+
onOpen(event: Event): Promise<void>;
|
|
540
|
+
attach(provider: HocuspocusProvider): void;
|
|
541
|
+
detach(provider: HocuspocusProvider): void;
|
|
542
|
+
setConfiguration(configuration?: Partial<HocuspocusProviderWebsocketConfiguration>): void;
|
|
543
|
+
cancelWebsocketRetry?: () => void;
|
|
544
|
+
connect(): Promise<unknown>;
|
|
545
|
+
attachWebSocketListeners(ws: HocusPocusWebSocket, reject: Function): void;
|
|
546
|
+
cleanupWebSocket(): void;
|
|
547
|
+
createWebSocketConnection(): Promise<unknown>;
|
|
548
|
+
onMessage(event: MessageEvent): void;
|
|
549
|
+
resolveConnectionAttempt(): void;
|
|
550
|
+
stopConnectionAttempt(): void;
|
|
551
|
+
rejectConnectionAttempt(): void;
|
|
552
|
+
closeTries: number;
|
|
553
|
+
checkConnection(): void;
|
|
554
|
+
get serverUrl(): string;
|
|
555
|
+
get url(): string;
|
|
556
|
+
disconnect(): void;
|
|
557
|
+
send(message: any): void;
|
|
558
|
+
onClose({
|
|
559
|
+
event
|
|
560
|
+
}: onCloseParameters): void;
|
|
561
|
+
destroy(): void;
|
|
562
|
+
}
|
|
563
|
+
//#endregion
|
|
564
|
+
//#region packages/provider/src/HocuspocusProvider.d.ts
|
|
565
|
+
type HocuspocusProviderConfiguration = Required<Pick<CompleteHocuspocusProviderConfiguration, "name">> & Partial<CompleteHocuspocusProviderConfiguration> & ((Required<Pick<CompleteHocuspocusProviderWebsocketConfiguration, "url">> & Partial<Pick<CompleteHocuspocusProviderWebsocketConfiguration, "preserveTrailingSlash">>) | Required<Pick<CompleteHocuspocusProviderConfiguration, "websocketProvider">>);
|
|
566
|
+
interface CompleteHocuspocusProviderConfiguration {
|
|
567
|
+
/**
|
|
568
|
+
* The identifier/name of your document
|
|
569
|
+
*/
|
|
570
|
+
name: string;
|
|
571
|
+
/**
|
|
572
|
+
* The actual Y.js document
|
|
573
|
+
*/
|
|
574
|
+
document: Y.Doc;
|
|
575
|
+
/**
|
|
576
|
+
* An Awareness instance to keep the presence state of all clients.
|
|
577
|
+
*
|
|
578
|
+
* You can disable sharing awareness information by passing `null`.
|
|
579
|
+
* Note that having no awareness information shared across all connections will break our ping checks
|
|
580
|
+
* and thus trigger reconnects. You should always have at least one Provider with enabled awareness per
|
|
581
|
+
* socket connection, or ensure that the Provider receives messages before running into `HocuspocusProviderWebsocket.messageReconnectTimeout`.
|
|
582
|
+
*/
|
|
583
|
+
awareness: Awareness | null;
|
|
584
|
+
/**
|
|
585
|
+
* A token that’s sent to the backend for authentication purposes.
|
|
586
|
+
*/
|
|
587
|
+
token: string | (() => string) | (() => Promise<string>) | null;
|
|
588
|
+
/**
|
|
589
|
+
* Hocuspocus websocket provider
|
|
590
|
+
*/
|
|
591
|
+
websocketProvider: HocuspocusProviderWebsocket;
|
|
592
|
+
/**
|
|
593
|
+
* Force syncing the document in the defined interval.
|
|
594
|
+
*/
|
|
595
|
+
forceSyncInterval: false | number;
|
|
596
|
+
onAuthenticated: (data: onAuthenticatedParameters) => void;
|
|
597
|
+
onAuthenticationFailed: (data: onAuthenticationFailedParameters) => void;
|
|
598
|
+
onOpen: (data: onOpenParameters) => void;
|
|
599
|
+
onConnect: () => void;
|
|
600
|
+
onStatus: (data: onStatusParameters) => void;
|
|
601
|
+
onMessage: (data: onMessageParameters) => void;
|
|
602
|
+
onOutgoingMessage: (data: onOutgoingMessageParameters) => void;
|
|
603
|
+
onSynced: (data: onSyncedParameters) => void;
|
|
604
|
+
onDisconnect: (data: onDisconnectParameters) => void;
|
|
605
|
+
onClose: (data: onCloseParameters) => void;
|
|
606
|
+
onDestroy: () => void;
|
|
607
|
+
onAwarenessUpdate: (data: onAwarenessUpdateParameters) => void;
|
|
608
|
+
onAwarenessChange: (data: onAwarenessChangeParameters) => void;
|
|
609
|
+
onStateless: (data: onStatelessParameters) => void;
|
|
610
|
+
onUnsyncedChanges: (data: onUnsyncedChangesParameters) => void;
|
|
611
|
+
}
|
|
612
|
+
declare class AwarenessError extends Error {
|
|
613
|
+
code: number;
|
|
614
|
+
}
|
|
615
|
+
declare class HocuspocusProvider extends EventEmitter {
|
|
616
|
+
configuration: CompleteHocuspocusProviderConfiguration;
|
|
617
|
+
isSynced: boolean;
|
|
618
|
+
unsyncedChanges: number;
|
|
619
|
+
isAuthenticated: boolean;
|
|
620
|
+
authorizedScope: AuthorizedScope | undefined;
|
|
621
|
+
manageSocket: boolean;
|
|
622
|
+
private _isAttached;
|
|
623
|
+
intervals: any;
|
|
624
|
+
constructor(configuration: HocuspocusProviderConfiguration);
|
|
625
|
+
boundDocumentUpdateHandler: (update: Uint8Array, origin: any) => void;
|
|
626
|
+
boundAwarenessUpdateHandler: ({
|
|
627
|
+
added,
|
|
628
|
+
updated,
|
|
629
|
+
removed
|
|
630
|
+
}: any, origin: any) => void;
|
|
631
|
+
boundPageHide: () => void;
|
|
632
|
+
boundOnOpen: (event: Event) => Promise<void>;
|
|
633
|
+
boundOnClose: () => void;
|
|
634
|
+
forwardConnect: () => this;
|
|
635
|
+
forwardStatus: (e: onStatusParameters) => this;
|
|
636
|
+
forwardClose: (e: onCloseParameters) => this;
|
|
637
|
+
forwardDisconnect: (e: onDisconnectParameters) => this;
|
|
638
|
+
forwardDestroy: () => this;
|
|
639
|
+
setConfiguration(configuration?: Partial<HocuspocusProviderConfiguration>): void;
|
|
640
|
+
get document(): Y.Doc;
|
|
641
|
+
get isAttached(): boolean;
|
|
642
|
+
get awareness(): Awareness | null;
|
|
643
|
+
get hasUnsyncedChanges(): boolean;
|
|
644
|
+
private resetUnsyncedChanges;
|
|
645
|
+
incrementUnsyncedChanges(): void;
|
|
646
|
+
decrementUnsyncedChanges(): void;
|
|
647
|
+
forceSync(): void;
|
|
648
|
+
pageHide(): void;
|
|
649
|
+
registerEventListeners(): void;
|
|
650
|
+
sendStateless(payload: string): void;
|
|
651
|
+
sendToken(): Promise<void>;
|
|
652
|
+
documentUpdateHandler(update: Uint8Array, origin: any): void;
|
|
653
|
+
awarenessUpdateHandler({
|
|
654
|
+
added,
|
|
655
|
+
updated,
|
|
656
|
+
removed
|
|
657
|
+
}: any, origin: any): void;
|
|
658
|
+
/**
|
|
659
|
+
* Indicates whether a first handshake with the server has been established
|
|
660
|
+
*
|
|
661
|
+
* Note: this does not mean all updates from the client have been persisted to the backend. For this,
|
|
662
|
+
* use `hasUnsyncedChanges`.
|
|
663
|
+
*/
|
|
664
|
+
get synced(): boolean;
|
|
665
|
+
set synced(state: boolean);
|
|
666
|
+
receiveStateless(payload: string): void;
|
|
667
|
+
connect(): Promise<unknown>;
|
|
668
|
+
disconnect(): void;
|
|
669
|
+
onOpen(event: Event): Promise<void>;
|
|
670
|
+
getToken(): Promise<string | null>;
|
|
671
|
+
startSync(): void;
|
|
672
|
+
send(message: ConstructableOutgoingMessage, args: any): void;
|
|
673
|
+
onMessage(event: MessageEvent): void;
|
|
674
|
+
onClose(): void;
|
|
675
|
+
destroy(): void;
|
|
676
|
+
detach(): void;
|
|
677
|
+
attach(): void;
|
|
678
|
+
permissionDeniedHandler(reason: string): void;
|
|
679
|
+
authenticatedHandler(scope: string): void;
|
|
680
|
+
setAwarenessField(key: string, value: any): void;
|
|
681
|
+
}
|
|
682
|
+
//#endregion
|
|
683
|
+
//#region packages/provider/src/OfflineStore.d.ts
|
|
684
|
+
/**
|
|
685
|
+
* IndexedDB-backed offline store for a single Abracadabra document.
|
|
686
|
+
*
|
|
687
|
+
* Responsibilities:
|
|
688
|
+
* - Persist CRDT updates locally so they survive page refreshes / network loss.
|
|
689
|
+
* - Store the last-known state vector for fast reconnect diffs.
|
|
690
|
+
* - Store a permission snapshot so the UI can gate writes without a network round-trip.
|
|
691
|
+
* - Queue subdoc registration events created while offline.
|
|
692
|
+
*
|
|
693
|
+
* Falls back to a silent no-op when IndexedDB is unavailable (e.g. SSR / Node.js).
|
|
694
|
+
*/
|
|
695
|
+
interface PendingSubdoc {
|
|
696
|
+
childId: string;
|
|
697
|
+
parentId: string;
|
|
698
|
+
createdAt: number;
|
|
699
|
+
}
|
|
700
|
+
declare class OfflineStore {
|
|
701
|
+
private docId;
|
|
702
|
+
private db;
|
|
703
|
+
constructor(docId: string);
|
|
704
|
+
private getDb;
|
|
705
|
+
persistUpdate(update: Uint8Array): Promise<void>;
|
|
706
|
+
getPendingUpdates(): Promise<Uint8Array[]>;
|
|
707
|
+
clearPendingUpdates(): Promise<void>;
|
|
708
|
+
getStateVector(): Promise<Uint8Array | null>;
|
|
709
|
+
saveStateVector(sv: Uint8Array): Promise<void>;
|
|
710
|
+
getPermissionSnapshot(): Promise<string | null>;
|
|
711
|
+
savePermissionSnapshot(role: string): Promise<void>;
|
|
712
|
+
queueSubdoc(entry: PendingSubdoc): Promise<void>;
|
|
713
|
+
getPendingSubdocs(): Promise<PendingSubdoc[]>;
|
|
714
|
+
removeSubdocFromQueue(childId: string): Promise<void>;
|
|
715
|
+
destroy(): void;
|
|
716
|
+
}
|
|
717
|
+
//#endregion
|
|
718
|
+
//#region packages/provider/src/OutgoingMessages/SubdocMessage.d.ts
|
|
719
|
+
/**
|
|
720
|
+
* Registers a new subdocument with the Abracadabra server.
|
|
721
|
+
*
|
|
722
|
+
* Wire format (consumed by handle_subdoc in sync.rs):
|
|
723
|
+
* [ParentDocName: VarString] [MSG_SUBDOC(4): VarUint] [childDocumentName: VarString]
|
|
724
|
+
*
|
|
725
|
+
* The server responds with a MSG_STATELESS JSON frame:
|
|
726
|
+
* { type: "subdoc_registered", child_id, parent_id }
|
|
727
|
+
* which AbracadabraProvider intercepts in receiveStateless().
|
|
728
|
+
*/
|
|
729
|
+
declare class SubdocMessage extends OutgoingMessage {
|
|
730
|
+
type: MessageType;
|
|
731
|
+
description: string;
|
|
732
|
+
get(args: Partial<OutgoingMessageArguments>): Encoder;
|
|
733
|
+
}
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region packages/provider/src/CryptoIdentityKeystore.d.ts
|
|
736
|
+
/**
|
|
737
|
+
* CryptoIdentityKeystore
|
|
738
|
+
*
|
|
739
|
+
* Per-device Ed25519 keypair, private key protected by WebAuthn PRF + AES-256-GCM.
|
|
740
|
+
* Stored in IndexedDB under "abracadabra:identity" / "identity" / key "current".
|
|
741
|
+
*
|
|
742
|
+
* No private key is ever shared between devices. Each device generates its own
|
|
743
|
+
* keypair, encrypts the private key with the PRF output from its own WebAuthn
|
|
744
|
+
* credential, and stores the ciphertext in IndexedDB.
|
|
745
|
+
*
|
|
746
|
+
* Dependencies: @noble/ed25519, @noble/hashes (for HKDF)
|
|
747
|
+
*/
|
|
748
|
+
declare class CryptoIdentityKeystore {
|
|
749
|
+
/**
|
|
750
|
+
* One-time setup for a device: generates an Ed25519 keypair, creates a
|
|
751
|
+
* WebAuthn credential with PRF extension, encrypts the private key, and
|
|
752
|
+
* stores everything in IndexedDB.
|
|
753
|
+
*
|
|
754
|
+
* Returns the base64url-encoded public key. The caller must register this
|
|
755
|
+
* key with the server via POST /auth/register (first device) or
|
|
756
|
+
* POST /auth/keys (additional device).
|
|
757
|
+
*
|
|
758
|
+
* @param username - The user's account name.
|
|
759
|
+
* @param rpId - WebAuthn relying party ID (e.g. "example.com").
|
|
760
|
+
* @param rpName - Human-readable relying party name.
|
|
761
|
+
*/
|
|
762
|
+
register(username: string, rpId: string, rpName: string): Promise<string>;
|
|
763
|
+
/**
|
|
764
|
+
* Sign a base64url-encoded challenge using the stored Ed25519 private key.
|
|
765
|
+
*
|
|
766
|
+
* This triggers a WebAuthn assertion (biometric / PIN prompt) to unlock the
|
|
767
|
+
* private key via PRF → HKDF → AES-GCM decryption. The private key is
|
|
768
|
+
* wiped from memory after signing.
|
|
769
|
+
*
|
|
770
|
+
* @param challengeB64 - base64url-encoded challenge bytes from the server.
|
|
771
|
+
* @returns base64url-encoded Ed25519 signature (64 bytes).
|
|
772
|
+
*/
|
|
773
|
+
sign(challengeB64: string): Promise<string>;
|
|
774
|
+
/** Returns the stored base64url public key, or null if no identity exists. */
|
|
775
|
+
getPublicKey(): Promise<string | null>;
|
|
776
|
+
/** Returns the stored username, or null if no identity exists. */
|
|
777
|
+
getUsername(): Promise<string | null>;
|
|
778
|
+
/** Returns true if an identity is stored in IndexedDB. */
|
|
779
|
+
hasIdentity(): Promise<boolean>;
|
|
780
|
+
/** Remove the stored identity from IndexedDB. */
|
|
781
|
+
clear(): Promise<void>;
|
|
782
|
+
}
|
|
783
|
+
//#endregion
|
|
784
|
+
export { AbracadabraOutgoingMessageArguments, AbracadabraProvider, AbracadabraProviderConfiguration, AuthorizedScope, AwarenessError, CompleteHocuspocusProviderConfiguration, CompleteHocuspocusProviderWebsocketConfiguration, Constructable, ConstructableOutgoingMessage, CryptoIdentity, CryptoIdentityKeystore, EffectiveRole, HocusPocusWebSocket, HocuspocusProvider, HocuspocusProviderConfiguration, HocuspocusProviderWebsocket, HocuspocusProviderWebsocketConfiguration, HocuspocusWebSocket, MessageType, OfflineStore, OutgoingMessageArguments, OutgoingMessageInterface, PendingSubdoc, StatesArray, SubdocMessage, SubdocRegisteredEvent, WebSocketStatus, onAuthenticatedParameters, onAuthenticationFailedParameters, onAwarenessChangeParameters, onAwarenessUpdateParameters, onCloseParameters, onDisconnectParameters, onMessageParameters, onOpenParameters, onOutgoingMessageParameters, onStatelessParameters, onStatusParameters, onSubdocLoadedParameters, onSubdocRegisteredParameters, onSyncedParameters, onUnsyncedChangesParameters };
|