@abraca/dabra 1.0.2 → 1.0.3

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
@@ -415,6 +415,12 @@ declare class AbracadabraClient {
415
415
  * No auth required.
416
416
  */
417
417
  serverInfo(): Promise<ServerInfo>;
418
+ /**
419
+ * Fetch ICE server configuration for WebRTC peer connections.
420
+ * Falls back to default Google STUN server if the endpoint is unavailable.
421
+ * No auth required.
422
+ */
423
+ getIceServers(): Promise<RTCIceServer[]>;
418
424
  private request;
419
425
  private toError;
420
426
  private loadPersistedToken;
@@ -1591,4 +1597,358 @@ declare class BackgroundSyncManager extends EventEmitter {
1591
1597
  private _walkXml;
1592
1598
  }
1593
1599
  //#endregion
1594
- export { AbracadabraBaseProvider, AbracadabraBaseProviderConfiguration, AbracadabraClient, AbracadabraClientConfig, AbracadabraOutgoingMessageArguments, AbracadabraProvider, AbracadabraProviderConfiguration, AbracadabraWS, AbracadabraWSConfiguration, AbracadabraWebSocketConn, AuthMessageType, AuthorizedScope, AwarenessError, BackgroundSyncManager, type BackgroundSyncManagerOptions, BackgroundSyncPersistence, CloseEvent, CompleteAbracadabraBaseProviderConfiguration, CompleteAbracadabraWSConfiguration, CompleteHocuspocusProviderConfiguration, CompleteHocuspocusProviderWebsocketConfiguration, ConnectionTimeout, Constructable, ConstructableOutgoingMessage, CryptoIdentity, CryptoIdentityKeystore, type DocEncryptionInfo, DocKeyManager, type DocSyncState, DocumentCache, type DocumentCacheOptions, DocumentMeta, E2EAbracadabraProvider, E2EOfflineStore, EffectiveRole, EncryptedYMap, EncryptedYText, FileBlobStore, Forbidden, HealthStatus, HocusPocusWebSocket, HocuspocusProvider, HocuspocusProviderConfiguration, HocuspocusProviderWebsocket, HocuspocusProviderWebsocketConfiguration, HocuspocusWebSocket, InviteRow, MessageTooBig, MessageType, OfflineStore, OutgoingMessageArguments, OutgoingMessageInterface, PendingSubdoc, PermissionEntry, PublicKeyInfo, ResetConnection, SearchIndex, SearchResult, ServerInfo, SpaceMeta, StatesArray, SubdocMessage, SubdocRegisteredEvent, Unauthorized, UploadInfo, UploadMeta, UploadQueueEntry, UploadQueueStatus, UserProfile, WebSocketStatus, WsReadyStates, 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 };
1600
+ //#region packages/provider/src/webrtc/DataChannelRouter.d.ts
1601
+ declare class DataChannelRouter extends EventEmitter {
1602
+ private connection;
1603
+ private channels;
1604
+ constructor(connection: RTCPeerConnection);
1605
+ /** Create a named data channel (initiator side). */
1606
+ createChannel(name: string, options?: RTCDataChannelInit): RTCDataChannel;
1607
+ /** Create the standard set of channels for Abracadabra WebRTC. */
1608
+ createDefaultChannels(opts: {
1609
+ enableDocSync: boolean;
1610
+ enableAwareness: boolean;
1611
+ enableFileTransfer: boolean;
1612
+ }): void;
1613
+ getChannel(name: string): RTCDataChannel | null;
1614
+ isOpen(name: string): boolean;
1615
+ private registerChannel;
1616
+ close(): void;
1617
+ destroy(): void;
1618
+ }
1619
+ //#endregion
1620
+ //#region packages/provider/src/webrtc/types.d.ts
1621
+ type SignalingIncoming = {
1622
+ type: "join";
1623
+ } | {
1624
+ type: "leave";
1625
+ } | {
1626
+ type: "offer";
1627
+ to: string;
1628
+ sdp: string;
1629
+ } | {
1630
+ type: "answer";
1631
+ to: string;
1632
+ sdp: string;
1633
+ } | {
1634
+ type: "ice";
1635
+ to: string;
1636
+ candidate: string;
1637
+ } | {
1638
+ type: "mute";
1639
+ muted: boolean;
1640
+ } | {
1641
+ type: "media-state";
1642
+ video: boolean;
1643
+ screen: boolean;
1644
+ } | {
1645
+ type: "profile";
1646
+ name: string;
1647
+ color: string;
1648
+ } | {
1649
+ type: "pong";
1650
+ };
1651
+ type SignalingOutgoing = {
1652
+ type: "welcome";
1653
+ peer_id: string;
1654
+ peers: PeerInfo[];
1655
+ } | {
1656
+ type: "joined";
1657
+ peer_id: string;
1658
+ user_id: string;
1659
+ muted: boolean;
1660
+ video: boolean;
1661
+ screen: boolean;
1662
+ name: string | null;
1663
+ color: string | null;
1664
+ } | {
1665
+ type: "left";
1666
+ peer_id: string;
1667
+ } | {
1668
+ type: "offer";
1669
+ from: string;
1670
+ sdp: string;
1671
+ } | {
1672
+ type: "answer";
1673
+ from: string;
1674
+ sdp: string;
1675
+ } | {
1676
+ type: "ice";
1677
+ from: string;
1678
+ candidate: string;
1679
+ } | {
1680
+ type: "mute";
1681
+ peer_id: string;
1682
+ muted: boolean;
1683
+ } | {
1684
+ type: "media-state";
1685
+ peer_id: string;
1686
+ video: boolean;
1687
+ screen: boolean;
1688
+ } | {
1689
+ type: "profile";
1690
+ peer_id: string;
1691
+ name: string;
1692
+ color: string;
1693
+ } | {
1694
+ type: "ping";
1695
+ } | {
1696
+ type: "error";
1697
+ code: string;
1698
+ message: string;
1699
+ };
1700
+ interface PeerInfo {
1701
+ peer_id: string;
1702
+ user_id: string;
1703
+ muted: boolean;
1704
+ video: boolean;
1705
+ screen: boolean;
1706
+ name: string | null;
1707
+ color: string | null;
1708
+ }
1709
+ interface PeerState extends PeerInfo {
1710
+ connectionState: RTCPeerConnectionState | "new";
1711
+ }
1712
+ interface FileTransferMeta {
1713
+ transferId: string;
1714
+ filename: string;
1715
+ mimeType: string;
1716
+ totalSize: number;
1717
+ chunkSize: number;
1718
+ totalChunks: number;
1719
+ }
1720
+ type FileTransferStatus = "pending" | "sending" | "receiving" | "complete" | "cancelled" | "error";
1721
+ declare const CHANNEL_NAMES: {
1722
+ readonly YJS_SYNC: "yjs-sync";
1723
+ readonly AWARENESS: "awareness";
1724
+ readonly FILE_TRANSFER: "file-transfer";
1725
+ readonly CUSTOM: "custom";
1726
+ };
1727
+ interface AbracadabraWebRTCConfiguration {
1728
+ /** Document ID for the signaling room. */
1729
+ docId: string;
1730
+ /** Server base URL (http/https). Signaling URL derived automatically. */
1731
+ url: string;
1732
+ /** JWT token or async token factory. */
1733
+ token: string | (() => string) | (() => Promise<string>);
1734
+ /** Optional Y.Doc to sync over data channels (hybrid mode). */
1735
+ document?: InstanceType<typeof Y.Doc> | null;
1736
+ /** Optional Awareness instance for presence sync over data channels. */
1737
+ awareness?: InstanceType<typeof Awareness> | null;
1738
+ /** ICE server configuration. Defaults to Google STUN. */
1739
+ iceServers?: RTCIceServer[];
1740
+ /** Display name for this peer. */
1741
+ displayName?: string;
1742
+ /** Color identifier for this peer. */
1743
+ color?: string;
1744
+ /** Enable Y.js document sync over data channels. Default: true when document is provided. */
1745
+ enableDocSync?: boolean;
1746
+ /** Enable awareness sync over data channels. Default: true when awareness is provided. */
1747
+ enableAwarenessSync?: boolean;
1748
+ /** Enable file transfer channel. Default: false. */
1749
+ enableFileTransfer?: boolean;
1750
+ /** Max file chunk size in bytes. Default: 16384 (16KB). */
1751
+ fileChunkSize?: number;
1752
+ /** Auto-connect on construction. Default: true. */
1753
+ autoConnect?: boolean;
1754
+ /** WebSocket polyfill for signaling (e.g. for Node.js). */
1755
+ WebSocketPolyfill?: any;
1756
+ }
1757
+ declare const DEFAULT_ICE_SERVERS: RTCIceServer[];
1758
+ declare const DEFAULT_FILE_CHUNK_SIZE = 16384;
1759
+ //#endregion
1760
+ //#region packages/provider/src/webrtc/FileTransferChannel.d.ts
1761
+ /**
1762
+ * Handle for tracking a file transfer in progress.
1763
+ */
1764
+ declare class FileTransferHandle extends EventEmitter {
1765
+ readonly transferId: string;
1766
+ progress: number;
1767
+ status: FileTransferStatus;
1768
+ private abortController;
1769
+ constructor(transferId: string);
1770
+ cancel(): void;
1771
+ get signal(): AbortSignal;
1772
+ /** @internal */
1773
+ _setProgress(p: number): void;
1774
+ /** @internal */
1775
+ _setStatus(s: FileTransferStatus): void;
1776
+ }
1777
+ /**
1778
+ * Chunked binary file transfer over a dedicated WebRTC data channel.
1779
+ */
1780
+ declare class FileTransferChannel extends EventEmitter {
1781
+ private readonly router;
1782
+ private receives;
1783
+ private chunkSize;
1784
+ private channelMessageHandler;
1785
+ constructor(router: DataChannelRouter, chunkSize?: number);
1786
+ /** Send a file to a peer. Returns a handle for tracking progress. */
1787
+ send(file: File | Blob, filename: string): Promise<FileTransferHandle>;
1788
+ private handleMessage;
1789
+ private handleStart;
1790
+ private handleChunk;
1791
+ private handleComplete;
1792
+ private handleCancel;
1793
+ destroy(): void;
1794
+ }
1795
+ //#endregion
1796
+ //#region packages/provider/src/webrtc/AbracadabraWebRTC.d.ts
1797
+ /**
1798
+ * Optional WebRTC provider for peer-to-peer Y.js sync, awareness, and file transfer.
1799
+ *
1800
+ * Uses the server's signaling endpoint (`/ws/:doc_id/signaling`) for connection
1801
+ * negotiation, then establishes direct data channels between peers. Designed to
1802
+ * work alongside `AbracadabraProvider` — the server remains the persistence layer,
1803
+ * while WebRTC provides low-latency P2P sync.
1804
+ *
1805
+ * Falls back to a no-op when `RTCPeerConnection` is unavailable (e.g. Node.js).
1806
+ */
1807
+ declare class AbracadabraWebRTC extends EventEmitter {
1808
+ private signaling;
1809
+ private peerConnections;
1810
+ private yjsChannels;
1811
+ private fileChannels;
1812
+ private readonly config;
1813
+ readonly peers: Map<string, PeerState>;
1814
+ localPeerId: string | null;
1815
+ isConnected: boolean;
1816
+ constructor(configuration: AbracadabraWebRTCConfiguration);
1817
+ /**
1818
+ * Create an AbracadabraWebRTC instance from an existing provider,
1819
+ * reusing its document, awareness, URL, and token.
1820
+ */
1821
+ static fromProvider(provider: AbracadabraProvider, options?: Partial<AbracadabraWebRTCConfiguration>): AbracadabraWebRTC;
1822
+ connect(): Promise<void>;
1823
+ disconnect(): void;
1824
+ destroy(): void;
1825
+ setMuted(muted: boolean): void;
1826
+ setMediaState(video: boolean, screen: boolean): void;
1827
+ setProfile(name: string, color: string): void;
1828
+ /**
1829
+ * Send a file to a specific peer. Returns a handle for tracking progress.
1830
+ */
1831
+ sendFile(peerId: string, file: File | Blob, filename: string): Promise<FileTransferHandle | null>;
1832
+ /**
1833
+ * Send a file to all connected peers. Returns an array of handles.
1834
+ */
1835
+ broadcastFile(file: File | Blob, filename: string): Promise<FileTransferHandle[]>;
1836
+ /**
1837
+ * Send a custom string message to a specific peer via a data channel.
1838
+ */
1839
+ sendCustomMessage(peerId: string, payload: string): void;
1840
+ /**
1841
+ * Send a custom string message to all connected peers.
1842
+ */
1843
+ broadcastCustomMessage(payload: string): void;
1844
+ private addPeer;
1845
+ private removePeer;
1846
+ private removeAllPeers;
1847
+ private createPeerConnection;
1848
+ private attachDataHandlers;
1849
+ private initiateConnection;
1850
+ private handleOffer;
1851
+ private buildSignalingUrl;
1852
+ }
1853
+ //#endregion
1854
+ //#region packages/provider/src/webrtc/SignalingSocket.d.ts
1855
+ interface SignalingSocketConfiguration {
1856
+ /** WebSocket URL for the signaling endpoint. */
1857
+ url: string;
1858
+ /** JWT token or async token factory for auth. */
1859
+ token: string | (() => string) | (() => Promise<string>);
1860
+ /** Auto-connect on construction. Default: true. */
1861
+ autoConnect?: boolean;
1862
+ /** WebSocket polyfill (e.g. for Node.js). */
1863
+ WebSocketPolyfill?: any;
1864
+ /** Retry delay in ms. Default: 1000. */
1865
+ delay?: number;
1866
+ /** Retry factor. Default: 2. */
1867
+ factor?: number;
1868
+ /** Min retry delay. Default: 1000. */
1869
+ minDelay?: number;
1870
+ /** Max retry delay. Default: 30000. */
1871
+ maxDelay?: number;
1872
+ /** Randomize delay. Default: true. */
1873
+ jitter?: boolean;
1874
+ /** Max retry attempts (0 = unlimited). Default: 0. */
1875
+ maxAttempts?: number;
1876
+ }
1877
+ declare class SignalingSocket extends EventEmitter {
1878
+ private ws;
1879
+ private wsHandlers;
1880
+ private shouldConnect;
1881
+ private cancelRetry?;
1882
+ private connectionAttempt;
1883
+ private readonly config;
1884
+ localPeerId: string | null;
1885
+ isConnected: boolean;
1886
+ constructor(configuration: SignalingSocketConfiguration);
1887
+ private getToken;
1888
+ connect(): Promise<void>;
1889
+ private createConnection;
1890
+ private handleMessage;
1891
+ private sendRaw;
1892
+ sendOffer(to: string, sdp: string): void;
1893
+ sendAnswer(to: string, sdp: string): void;
1894
+ sendIce(to: string, candidate: string): void;
1895
+ sendMute(muted: boolean): void;
1896
+ sendMediaState(video: boolean, screen: boolean): void;
1897
+ sendProfile(name: string, color: string): void;
1898
+ sendLeave(): void;
1899
+ disconnect(): void;
1900
+ destroy(): void;
1901
+ private cleanup;
1902
+ }
1903
+ //#endregion
1904
+ //#region packages/provider/src/webrtc/PeerConnection.d.ts
1905
+ declare class PeerConnection extends EventEmitter {
1906
+ readonly connection: RTCPeerConnection;
1907
+ readonly router: DataChannelRouter;
1908
+ readonly peerId: string;
1909
+ private pendingCandidates;
1910
+ private hasRemoteDescription;
1911
+ constructor(peerId: string, iceServers: RTCIceServer[]);
1912
+ get connectionState(): RTCPeerConnectionState;
1913
+ get iceConnectionState(): RTCIceConnectionState;
1914
+ /** Create an SDP offer (initiator side). */
1915
+ createOffer(iceRestart?: boolean): Promise<string>;
1916
+ /** Set a remote offer and create an answer (receiver side). Returns the SDP answer. */
1917
+ setRemoteOffer(sdp: string): Promise<string>;
1918
+ /** Set the remote answer (initiator side). */
1919
+ setRemoteAnswer(sdp: string): Promise<void>;
1920
+ /** Add a remote ICE candidate. Queues if remote description not yet set. */
1921
+ addIceCandidate(candidateJson: string): Promise<void>;
1922
+ private flushPendingCandidates;
1923
+ close(): void;
1924
+ destroy(): void;
1925
+ }
1926
+ //#endregion
1927
+ //#region packages/provider/src/webrtc/YjsDataChannel.d.ts
1928
+ /**
1929
+ * Handles Y.js document sync and awareness over WebRTC data channels.
1930
+ *
1931
+ * Uses the same y-protocols/sync encoding as the WebSocket provider but
1932
+ * transported over RTCDataChannel instead. A unique origin is used to
1933
+ * prevent echo loops with the server-based provider.
1934
+ */
1935
+ declare class YjsDataChannel {
1936
+ private readonly document;
1937
+ private readonly awareness;
1938
+ private readonly router;
1939
+ private docUpdateHandler;
1940
+ private awarenessUpdateHandler;
1941
+ private channelOpenHandler;
1942
+ private channelMessageHandler;
1943
+ constructor(document: Y.Doc, awareness: Awareness | null, router: DataChannelRouter);
1944
+ /** Start listening for Y.js updates and data channel messages. */
1945
+ attach(): void;
1946
+ /** Stop listening and clean up handlers. */
1947
+ detach(): void;
1948
+ destroy(): void;
1949
+ private sendSyncStep1;
1950
+ private handleSyncMessage;
1951
+ private handleAwarenessMessage;
1952
+ }
1953
+ //#endregion
1954
+ export { AbracadabraBaseProvider, AbracadabraBaseProviderConfiguration, AbracadabraClient, AbracadabraClientConfig, AbracadabraOutgoingMessageArguments, AbracadabraProvider, AbracadabraProviderConfiguration, AbracadabraWS, AbracadabraWSConfiguration, AbracadabraWebRTC, type AbracadabraWebRTCConfiguration, AbracadabraWebSocketConn, AuthMessageType, AuthorizedScope, AwarenessError, BackgroundSyncManager, type BackgroundSyncManagerOptions, BackgroundSyncPersistence, CHANNEL_NAMES, CloseEvent, CompleteAbracadabraBaseProviderConfiguration, CompleteAbracadabraWSConfiguration, CompleteHocuspocusProviderConfiguration, CompleteHocuspocusProviderWebsocketConfiguration, ConnectionTimeout, Constructable, ConstructableOutgoingMessage, CryptoIdentity, CryptoIdentityKeystore, DEFAULT_FILE_CHUNK_SIZE, DEFAULT_ICE_SERVERS, DataChannelRouter, type DocEncryptionInfo, DocKeyManager, type DocSyncState, DocumentCache, type DocumentCacheOptions, DocumentMeta, E2EAbracadabraProvider, E2EOfflineStore, EffectiveRole, EncryptedYMap, EncryptedYText, FileBlobStore, FileTransferChannel, FileTransferHandle, type FileTransferMeta, type FileTransferStatus, Forbidden, HealthStatus, HocusPocusWebSocket, HocuspocusProvider, HocuspocusProviderConfiguration, HocuspocusProviderWebsocket, HocuspocusProviderWebsocketConfiguration, HocuspocusWebSocket, InviteRow, MessageTooBig, MessageType, OfflineStore, OutgoingMessageArguments, OutgoingMessageInterface, 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abraca/dabra",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "abracadabra provider",
5
5
  "keywords": [
6
6
  "abracadabra",
@@ -536,6 +536,24 @@ export class AbracadabraClient {
536
536
  return this.request<ServerInfo>("GET", "/info", { auth: false });
537
537
  }
538
538
 
539
+ /**
540
+ * Fetch ICE server configuration for WebRTC peer connections.
541
+ * Falls back to default Google STUN server if the endpoint is unavailable.
542
+ * No auth required.
543
+ */
544
+ async getIceServers(): Promise<RTCIceServer[]> {
545
+ try {
546
+ const res = await this.request<{ iceServers: RTCIceServer[] }>(
547
+ "GET",
548
+ "/ice-servers",
549
+ { auth: false },
550
+ );
551
+ return res.iceServers;
552
+ } catch {
553
+ return [{ urls: "stun:stun.l.google.com:19302" }];
554
+ }
555
+ }
556
+
539
557
  // ── Internals ────────────────────────────────────────────────────────────
540
558
 
541
559
  private async request<T = void>(
@@ -511,7 +511,9 @@ export class AbracadabraWS extends EventEmitter {
511
511
  this.emit("status", { status: WebSocketStatus.Disconnected });
512
512
 
513
513
  // Detect server-side rate-limit close (code 4429).
514
- const isRateLimited = (event as any)?.code === 4429;
514
+ // `event` may be a CloseEvent (browser) with `.code`, or a raw number (ws/Node.js).
515
+ console.log('[DEBUG] onClose event:', typeof event, JSON.stringify(event), 'code:', (event as any)?.code);
516
+ const isRateLimited = (event as any)?.code === 4429 || event === 4429;
515
517
  this.emit("disconnect", { event });
516
518
  if (isRateLimited) {
517
519
  this.emit("rateLimited");
package/src/index.ts CHANGED
@@ -23,3 +23,4 @@ export { BackgroundSyncManager } from "./BackgroundSyncManager.ts";
23
23
  export type { BackgroundSyncManagerOptions } from "./BackgroundSyncManager.ts";
24
24
  export { BackgroundSyncPersistence } from "./BackgroundSyncPersistence.ts";
25
25
  export type { DocSyncState } from "./BackgroundSyncPersistence.ts";
26
+ export * from "./webrtc/index.ts";