@abraca/dabra 1.0.21 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -340,6 +340,11 @@ declare class AbracadabraClient {
340
340
  publicKey: string;
341
341
  };
342
342
  }>;
343
+ /**
344
+ * Fetch a short-lived anonymous pairing token for WebRTC signaling.
345
+ * No authentication required. The token only grants access to `__pairing_*` rooms.
346
+ */
347
+ static getPairingToken(serverUrl: string): Promise<string>;
343
348
  /** Get encryption info for a document. */
344
349
  getDocEncryption(docId: string): Promise<DocEncryptionInfo>;
345
350
  /** Set the encryption mode for a document (no downgrade). */
@@ -621,6 +626,12 @@ interface AbracadabraProviderConfiguration extends Omit<AbracadabraBaseProviderC
621
626
  keystore?: CryptoIdentityKeystore;
622
627
  /** Shared WebSocket connection (use when multiplexing multiple root documents). */
623
628
  websocketProvider?: AbracadabraWS;
629
+ /**
630
+ * When true, the IndexedDB offline store is NOT scoped by server origin.
631
+ * This allows a single document to be synced across multiple servers while
632
+ * sharing one local store. Used for the identity doc.
633
+ */
634
+ serverAgnostic?: boolean;
624
635
  }
625
636
  /**
626
637
  * AbracadabraProvider extends AbracadabraBaseProvider with:
@@ -2242,12 +2253,22 @@ declare class ManualSignaling extends EventEmitter {
2242
2253
  interface DevicePairingConfig {
2243
2254
  /** Server base URL (http/https). */
2244
2255
  serverUrl: string;
2245
- /** JWT token or async token factory for signaling auth. */
2246
- token: string | (() => string) | (() => Promise<string>);
2256
+ /**
2257
+ * JWT token or async token factory for signaling auth.
2258
+ * When omitted, a short-lived anonymous pairing token is fetched automatically
2259
+ * from `POST /auth/pairing-token`.
2260
+ */
2261
+ token?: string | (() => string) | (() => Promise<string>);
2247
2262
  /** E2EE identity (Ed25519 public key + X25519 private key). */
2248
2263
  e2ee: E2EEIdentity;
2249
2264
  /** ICE servers. Defaults to Google STUN. */
2250
2265
  iceServers?: RTCIceServer[];
2266
+ /**
2267
+ * Fallback signaling server URL. If the primary server is unreachable,
2268
+ * signaling will retry through this server. The actual pairing data is
2269
+ * E2EE-encrypted, so the relay server cannot read it.
2270
+ */
2271
+ fallbackSignalingUrl?: string;
2251
2272
  /** WebSocket polyfill (for Node.js). */
2252
2273
  WebSocketPolyfill?: any;
2253
2274
  }
@@ -2271,6 +2292,8 @@ declare class DevicePairingChannel extends EventEmitter {
2271
2292
  private _destroyed;
2272
2293
  private _pendingRequest;
2273
2294
  private _connectedPeerId;
2295
+ private _usingFallback;
2296
+ private _resolvedIceServers;
2274
2297
  readonly role: PairingRole;
2275
2298
  readonly pairingCode: string;
2276
2299
  private constructor();
@@ -2309,7 +2332,11 @@ declare class DevicePairingChannel extends EventEmitter {
2309
2332
  requestPairing(request: PairingRequest): void;
2310
2333
  get isDestroyed(): boolean;
2311
2334
  destroy(): void;
2335
+ private resolveToken;
2312
2336
  private start;
2337
+ private connectToServer;
2338
+ /** Whether the connection fell back to the fallback signaling server. */
2339
+ get usingFallback(): boolean;
2313
2340
  private sendMessage;
2314
2341
  private handleMessage;
2315
2342
  }
@@ -2342,4 +2369,155 @@ declare class BroadcastChannelSync extends EventEmitter {
2342
2369
  private handleAwarenessMessage;
2343
2370
  }
2344
2371
  //#endregion
2345
- export { AbracadabraBaseProvider, AbracadabraBaseProviderConfiguration, AbracadabraClient, AbracadabraClientConfig, AbracadabraOutgoingMessageArguments, AbracadabraProvider, AbracadabraProviderConfiguration, AbracadabraWS, AbracadabraWSConfiguration, AbracadabraWebRTC, type AbracadabraWebRTCConfiguration, AbracadabraWebSocketConn, AuthMessageType, AuthorizedScope, AwarenessError, BackgroundSyncManager, type BackgroundSyncManagerOptions, BackgroundSyncPersistence, BroadcastChannelSync, CHANNEL_NAMES, CloseEvent, CompleteAbracadabraBaseProviderConfiguration, CompleteAbracadabraWSConfiguration, CompleteHocuspocusProviderConfiguration, CompleteHocuspocusProviderWebsocketConfiguration, ConnectionTimeout, Constructable, ConstructableOutgoingMessage, CryptoIdentity, CryptoIdentityKeystore, DEFAULT_FILE_CHUNK_SIZE, DEFAULT_ICE_SERVERS, DataChannelRouter, DevicePairingChannel, type DevicePairingConfig, type DocEncryptionInfo, DocKeyManager, type DocSyncState, DocumentCache, type DocumentCacheOptions, DocumentMeta, E2EAbracadabraProvider, E2EEChannel, type E2EEIdentity, E2EOfflineStore, EffectivePermissionEntry, EffectivePermissionsResponse, EffectiveRole, EncryptedYMap, EncryptedYText, FileBlobStore, FileTransferChannel, FileTransferHandle, type FileTransferMeta, type FileTransferStatus, Forbidden, HealthStatus, HocusPocusWebSocket, HocuspocusProvider, HocuspocusProviderConfiguration, HocuspocusProviderWebsocket, HocuspocusProviderWebsocketConfiguration, HocuspocusWebSocket, InviteRow, KEY_EXCHANGE_CHANNEL, ManualSignaling, type ManualSignalingBlob, MessageTooBig, MessageType, OfflineStore, OutgoingMessageArguments, OutgoingMessageInterface, type PairingRequest, type PairingResult, PeerConnection, type PeerInfo, type PeerState, PendingSubdoc, PermissionEntry, PublicKeyInfo, ResetConnection, SearchIndex, SearchResult, ServerInfo, type SignalingIncoming, type SignalingOutgoing, SignalingSocket, SpaceMeta, StatesArray, SubdocMessage, SubdocRegisteredEvent, Unauthorized, UploadInfo, UploadMeta, UploadQueueEntry, UploadQueueStatus, UserProfile, WebSocketStatus, WsReadyStates, YjsDataChannel, attachUpdatedAtObserver, awarenessStatesToArray, decryptField, encryptField, makeEncryptedYMap, makeEncryptedYText, onAuthenticatedParameters, onAuthenticationFailedParameters, onAwarenessChangeParameters, onAwarenessUpdateParameters, onCloseParameters, onDisconnectParameters, onMessageParameters, onOpenParameters, onOutgoingMessageParameters, onStatelessParameters, onStatusParameters, onSubdocLoadedParameters, onSubdocRegisteredParameters, onSyncedParameters, onUnsyncedChangesParameters, readAuthMessage, writeAuthenticated, writeAuthentication, writePermissionDenied, writeTokenSyncRequest };
2372
+ //#region packages/provider/src/IdentityDoc.d.ts
2373
+ /**
2374
+ * Derives a deterministic UUID from an Ed25519 account-level public key.
2375
+ *
2376
+ * The result is a valid UUID v5-style string that any device sharing the
2377
+ * same identity can independently compute. The `abracadabra:identity:`
2378
+ * prefix prevents collisions with randomly generated doc UUIDs.
2379
+ *
2380
+ * @param publicKeyB64 Base64url-encoded Ed25519 public key (32 bytes).
2381
+ */
2382
+ declare function deriveIdentityDocId(publicKeyB64: string): string;
2383
+ interface IdentityProfile {
2384
+ username?: string;
2385
+ displayName?: string;
2386
+ colorName?: string;
2387
+ neutralColorName?: string;
2388
+ locale?: string;
2389
+ avatarUrl?: string;
2390
+ }
2391
+ interface IdentityServerEntry {
2392
+ label: string;
2393
+ hubDocId?: string;
2394
+ entryDocId?: string;
2395
+ defaultRole?: string;
2396
+ spacesEnabled?: boolean;
2397
+ addedAt: number;
2398
+ }
2399
+ interface IdentitySpaceEntry {
2400
+ id: string;
2401
+ name: string;
2402
+ type: "local" | "remote";
2403
+ serverUrl: string | null;
2404
+ docId: string;
2405
+ remoteSpaceId?: string;
2406
+ visibility: "public" | "private" | "invite";
2407
+ isHub: boolean;
2408
+ order: number;
2409
+ lastSyncedAt?: number;
2410
+ createdAt: number;
2411
+ }
2412
+ interface IdentityDocConfiguration {
2413
+ /** Base64url-encoded Ed25519 account public key. */
2414
+ publicKey: string;
2415
+ /**
2416
+ * Trusted server URL for identity doc sync.
2417
+ * Only this server (plus the local server) will receive the identity doc.
2418
+ */
2419
+ syncServerUrl?: string;
2420
+ /** Local Tauri server URL for on-device persistence. */
2421
+ localServerUrl?: string;
2422
+ /**
2423
+ * JWT token or async factory for authenticating with sync servers.
2424
+ * When using multiple servers, provide a factory that returns the correct
2425
+ * token for each.
2426
+ */
2427
+ token?: string | (() => string) | (() => Promise<string>);
2428
+ /** Per-server token factories keyed by base URL. */
2429
+ tokens?: Record<string, string | (() => string) | (() => Promise<string>)>;
2430
+ /**
2431
+ * Crypto identity for Ed25519 challenge-response auth.
2432
+ * When provided, used instead of JWT tokens for authenticating with servers.
2433
+ */
2434
+ cryptoIdentity?: CryptoIdentity | (() => Promise<CryptoIdentity>);
2435
+ /**
2436
+ * Signs a base64url challenge and returns a base64url signature.
2437
+ * Required when cryptoIdentity is set.
2438
+ */
2439
+ signChallenge?: (challenge: string) => Promise<string>;
2440
+ /**
2441
+ * WebRTC configuration for P2P identity sync.
2442
+ * When provided, enables E2EE peer-to-peer sync using signaling from
2443
+ * any connected server.
2444
+ */
2445
+ webrtc?: {
2446
+ /** Server URL to use for signaling (any connected server works). */signalingServerUrl: string; /** Token for the signaling server. */
2447
+ token: string | (() => string) | (() => Promise<string>); /** E2EE identity for the data channel. */
2448
+ e2ee?: E2EEIdentity; /** ICE servers. */
2449
+ iceServers?: RTCIceServer[];
2450
+ };
2451
+ /** Disable IndexedDB offline store. */
2452
+ disableOfflineStore?: boolean;
2453
+ /** Auto-connect on construction. Default: true. */
2454
+ autoConnect?: boolean;
2455
+ /** Additional provider config passed through to each AbracadabraProvider. */
2456
+ providerDefaults?: Partial<AbracadabraProviderConfiguration>;
2457
+ }
2458
+ /**
2459
+ * Manages a Y.Doc dedicated to user identity that syncs across trusted
2460
+ * targets only: a designated sync server, a local Tauri server, and/or
2461
+ * WebRTC P2P.
2462
+ *
2463
+ * The Y.Doc contains cross-device settings (profile, servers, spaces,
2464
+ * plugins, preferences). Each sync target gets its own
2465
+ * AbracadabraProvider sharing the same Y.Doc, with `serverAgnostic: true`
2466
+ * so they all use one IndexedDB store.
2467
+ */
2468
+ declare class IdentityDocProvider extends EventEmitter {
2469
+ readonly docId: string;
2470
+ readonly document: Y.Doc;
2471
+ private providers;
2472
+ private websockets;
2473
+ private webrtc;
2474
+ private config;
2475
+ private _destroyed;
2476
+ constructor(configuration: IdentityDocConfiguration);
2477
+ connect(): void;
2478
+ connectToServer(key: string, serverUrl: string): void;
2479
+ private _connectWebRTC;
2480
+ get profileMap(): Y.Map<string>;
2481
+ get serversMap(): Y.Map<Y.Map<any>>;
2482
+ get spacesArray(): Y.Array<Y.Map<any>>;
2483
+ get pluginsMap(): Y.Map<any>;
2484
+ get preferencesMap(): Y.Map<any>;
2485
+ getProfile(): IdentityProfile;
2486
+ setProfile(profile: Partial<IdentityProfile>): void;
2487
+ getServer(url: string): IdentityServerEntry | undefined;
2488
+ setServer(url: string, entry: IdentityServerEntry): void;
2489
+ removeServer(url: string): void;
2490
+ getServers(): Map<string, IdentityServerEntry>;
2491
+ getSpaces(): IdentitySpaceEntry[];
2492
+ addSpace(space: IdentitySpaceEntry): void;
2493
+ removeSpace(spaceId: string): void;
2494
+ updateSpace(spaceId: string, updates: Partial<IdentitySpaceEntry>): void;
2495
+ getExternalPlugins(): Y.Array<Y.Map<any>>;
2496
+ getDisabledBuiltins(): Y.Array<string>;
2497
+ getPreference<T = any>(key: string): T | undefined;
2498
+ setPreference(key: string, value: any): void;
2499
+ /**
2500
+ * Observe deep changes on a specific top-level map.
2501
+ * Returns an unsubscribe function.
2502
+ */
2503
+ observe(mapName: "profile" | "servers" | "plugins" | "preferences", callback: (events: Y.YEvent<any>[], transaction: Y.Transaction) => void): () => void;
2504
+ /**
2505
+ * Observe changes to the spaces array.
2506
+ * Returns an unsubscribe function.
2507
+ */
2508
+ observeSpaces(callback: (event: Y.YArrayEvent<Y.Map<any>>, transaction: Y.Transaction) => void): () => void;
2509
+ /**
2510
+ * Returns true if the identity doc has no profile data yet (first use).
2511
+ * Call this to decide whether to run migration from localStorage.
2512
+ */
2513
+ isEmpty(): boolean;
2514
+ /**
2515
+ * Update the sync server URL at runtime (e.g. when user changes their
2516
+ * designated sync server in settings).
2517
+ */
2518
+ setSyncServer(url: string | null): void;
2519
+ getProvider(key: string): AbracadabraProvider | undefined;
2520
+ destroy(): void;
2521
+ }
2522
+ //#endregion
2523
+ export { AbracadabraBaseProvider, AbracadabraBaseProviderConfiguration, AbracadabraClient, AbracadabraClientConfig, AbracadabraOutgoingMessageArguments, AbracadabraProvider, AbracadabraProviderConfiguration, AbracadabraWS, AbracadabraWSConfiguration, AbracadabraWebRTC, type AbracadabraWebRTCConfiguration, AbracadabraWebSocketConn, AuthMessageType, AuthorizedScope, AwarenessError, BackgroundSyncManager, type BackgroundSyncManagerOptions, BackgroundSyncPersistence, BroadcastChannelSync, CHANNEL_NAMES, CloseEvent, CompleteAbracadabraBaseProviderConfiguration, CompleteAbracadabraWSConfiguration, CompleteHocuspocusProviderConfiguration, CompleteHocuspocusProviderWebsocketConfiguration, ConnectionTimeout, Constructable, ConstructableOutgoingMessage, CryptoIdentity, CryptoIdentityKeystore, DEFAULT_FILE_CHUNK_SIZE, DEFAULT_ICE_SERVERS, DataChannelRouter, DevicePairingChannel, type DevicePairingConfig, type DocEncryptionInfo, DocKeyManager, type DocSyncState, DocumentCache, type DocumentCacheOptions, DocumentMeta, E2EAbracadabraProvider, E2EEChannel, type E2EEIdentity, E2EOfflineStore, EffectivePermissionEntry, EffectivePermissionsResponse, EffectiveRole, EncryptedYMap, EncryptedYText, FileBlobStore, FileTransferChannel, FileTransferHandle, type FileTransferMeta, type FileTransferStatus, Forbidden, HealthStatus, HocusPocusWebSocket, HocuspocusProvider, HocuspocusProviderConfiguration, HocuspocusProviderWebsocket, HocuspocusProviderWebsocketConfiguration, HocuspocusWebSocket, type IdentityDocConfiguration, IdentityDocProvider, type IdentityProfile, type IdentityServerEntry, type IdentitySpaceEntry, InviteRow, KEY_EXCHANGE_CHANNEL, ManualSignaling, type ManualSignalingBlob, MessageTooBig, MessageType, OfflineStore, OutgoingMessageArguments, OutgoingMessageInterface, type PairingRequest, type PairingResult, PeerConnection, type PeerInfo, type PeerState, PendingSubdoc, PermissionEntry, PublicKeyInfo, ResetConnection, SearchIndex, SearchResult, ServerInfo, type SignalingIncoming, type SignalingOutgoing, SignalingSocket, SpaceMeta, StatesArray, SubdocMessage, SubdocRegisteredEvent, Unauthorized, UploadInfo, UploadMeta, UploadQueueEntry, UploadQueueStatus, UserProfile, WebSocketStatus, WsReadyStates, YjsDataChannel, attachUpdatedAtObserver, awarenessStatesToArray, decryptField, deriveIdentityDocId, encryptField, makeEncryptedYMap, makeEncryptedYText, onAuthenticatedParameters, onAuthenticationFailedParameters, onAwarenessChangeParameters, onAwarenessUpdateParameters, onCloseParameters, onDisconnectParameters, onMessageParameters, onOpenParameters, onOutgoingMessageParameters, onStatelessParameters, onStatusParameters, onSubdocLoadedParameters, onSubdocRegisteredParameters, onSyncedParameters, onUnsyncedChangesParameters, readAuthMessage, writeAuthenticated, writeAuthentication, writePermissionDenied, writeTokenSyncRequest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abraca/dabra",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "abracadabra provider",
5
5
  "keywords": [
6
6
  "abracadabra",
@@ -227,6 +227,23 @@ export class AbracadabraClient {
227
227
  });
228
228
  }
229
229
 
230
+ // ── Pairing ─────────────────────────────────────────────────────────────
231
+
232
+ /**
233
+ * Fetch a short-lived anonymous pairing token for WebRTC signaling.
234
+ * No authentication required. The token only grants access to `__pairing_*` rooms.
235
+ */
236
+ static async getPairingToken(serverUrl: string): Promise<string> {
237
+ let base = serverUrl;
238
+ while (base.endsWith("/")) base = base.slice(0, -1);
239
+ const resp = await fetch(`${base}/auth/pairing-token`, { method: "POST" });
240
+ if (!resp.ok) {
241
+ throw new Error(`Failed to fetch pairing token: ${resp.status}`);
242
+ }
243
+ const { token } = (await resp.json()) as { token: string };
244
+ return token;
245
+ }
246
+
230
247
  // ── Encryption ───────────────────────────────────────────────────────────
231
248
 
232
249
  /** Get encryption info for a document. */
@@ -66,6 +66,13 @@ export interface AbracadabraProviderConfiguration
66
66
 
67
67
  /** Shared WebSocket connection (use when multiplexing multiple root documents). */
68
68
  websocketProvider?: AbracadabraWS;
69
+
70
+ /**
71
+ * When true, the IndexedDB offline store is NOT scoped by server origin.
72
+ * This allows a single document to be synced across multiple servers while
73
+ * sharing one local store. Used for the identity doc.
74
+ */
75
+ serverAgnostic?: boolean;
69
76
  }
70
77
 
71
78
  /** Validate that a string is a UUID acceptable by the server's DocId parser. */
@@ -134,7 +141,9 @@ export class AbracadabraProvider extends AbracadabraBaseProvider {
134
141
  this.abracadabraConfig = configuration;
135
142
  this.subdocLoading = configuration.subdocLoading ?? "lazy";
136
143
 
137
- const serverOrigin = AbracadabraProvider.deriveServerOrigin(configuration, client);
144
+ const serverOrigin = configuration.serverAgnostic
145
+ ? undefined
146
+ : AbracadabraProvider.deriveServerOrigin(configuration, client);
138
147
  this.offlineStore = configuration.disableOfflineStore
139
148
  ? null
140
149
  : new OfflineStore(configuration.name, serverOrigin);