@abraca/dabra 1.0.2 → 1.0.4
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/abracadabra-provider.cjs +1196 -10
- package/dist/abracadabra-provider.cjs.map +1 -1
- package/dist/abracadabra-provider.esm.js +1187 -11
- package/dist/abracadabra-provider.esm.js.map +1 -1
- package/dist/index.d.ts +363 -1
- package/package.json +1 -1
- package/src/AbracadabraClient.ts +18 -0
- package/src/AbracadabraWS.ts +3 -1
- package/src/index.ts +1 -0
- package/src/types.ts +2 -0
- package/src/webrtc/AbracadabraWebRTC.ts +540 -0
- package/src/webrtc/DataChannelRouter.ts +110 -0
- package/src/webrtc/FileTransferChannel.ts +359 -0
- package/src/webrtc/PeerConnection.ts +133 -0
- package/src/webrtc/SignalingSocket.ts +366 -0
- package/src/webrtc/YjsDataChannel.ts +195 -0
- package/src/webrtc/index.ts +20 -0
- package/src/webrtc/types.ts +159 -0
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;
|
|
@@ -935,6 +941,8 @@ interface UserProfile {
|
|
|
935
941
|
email: string | null;
|
|
936
942
|
displayName: string | null;
|
|
937
943
|
role: string;
|
|
944
|
+
/** Account-level Ed25519 public key (base64url). Canonical user identity. */
|
|
945
|
+
publicKey: string | null;
|
|
938
946
|
}
|
|
939
947
|
interface DocumentMeta {
|
|
940
948
|
id: string;
|
|
@@ -1591,4 +1599,358 @@ declare class BackgroundSyncManager extends EventEmitter {
|
|
|
1591
1599
|
private _walkXml;
|
|
1592
1600
|
}
|
|
1593
1601
|
//#endregion
|
|
1594
|
-
|
|
1602
|
+
//#region packages/provider/src/webrtc/DataChannelRouter.d.ts
|
|
1603
|
+
declare class DataChannelRouter extends EventEmitter {
|
|
1604
|
+
private connection;
|
|
1605
|
+
private channels;
|
|
1606
|
+
constructor(connection: RTCPeerConnection);
|
|
1607
|
+
/** Create a named data channel (initiator side). */
|
|
1608
|
+
createChannel(name: string, options?: RTCDataChannelInit): RTCDataChannel;
|
|
1609
|
+
/** Create the standard set of channels for Abracadabra WebRTC. */
|
|
1610
|
+
createDefaultChannels(opts: {
|
|
1611
|
+
enableDocSync: boolean;
|
|
1612
|
+
enableAwareness: boolean;
|
|
1613
|
+
enableFileTransfer: boolean;
|
|
1614
|
+
}): void;
|
|
1615
|
+
getChannel(name: string): RTCDataChannel | null;
|
|
1616
|
+
isOpen(name: string): boolean;
|
|
1617
|
+
private registerChannel;
|
|
1618
|
+
close(): void;
|
|
1619
|
+
destroy(): void;
|
|
1620
|
+
}
|
|
1621
|
+
//#endregion
|
|
1622
|
+
//#region packages/provider/src/webrtc/types.d.ts
|
|
1623
|
+
type SignalingIncoming = {
|
|
1624
|
+
type: "join";
|
|
1625
|
+
} | {
|
|
1626
|
+
type: "leave";
|
|
1627
|
+
} | {
|
|
1628
|
+
type: "offer";
|
|
1629
|
+
to: string;
|
|
1630
|
+
sdp: string;
|
|
1631
|
+
} | {
|
|
1632
|
+
type: "answer";
|
|
1633
|
+
to: string;
|
|
1634
|
+
sdp: string;
|
|
1635
|
+
} | {
|
|
1636
|
+
type: "ice";
|
|
1637
|
+
to: string;
|
|
1638
|
+
candidate: string;
|
|
1639
|
+
} | {
|
|
1640
|
+
type: "mute";
|
|
1641
|
+
muted: boolean;
|
|
1642
|
+
} | {
|
|
1643
|
+
type: "media-state";
|
|
1644
|
+
video: boolean;
|
|
1645
|
+
screen: boolean;
|
|
1646
|
+
} | {
|
|
1647
|
+
type: "profile";
|
|
1648
|
+
name: string;
|
|
1649
|
+
color: string;
|
|
1650
|
+
} | {
|
|
1651
|
+
type: "pong";
|
|
1652
|
+
};
|
|
1653
|
+
type SignalingOutgoing = {
|
|
1654
|
+
type: "welcome";
|
|
1655
|
+
peer_id: string;
|
|
1656
|
+
peers: PeerInfo[];
|
|
1657
|
+
} | {
|
|
1658
|
+
type: "joined";
|
|
1659
|
+
peer_id: string;
|
|
1660
|
+
user_id: string;
|
|
1661
|
+
muted: boolean;
|
|
1662
|
+
video: boolean;
|
|
1663
|
+
screen: boolean;
|
|
1664
|
+
name: string | null;
|
|
1665
|
+
color: string | null;
|
|
1666
|
+
} | {
|
|
1667
|
+
type: "left";
|
|
1668
|
+
peer_id: string;
|
|
1669
|
+
} | {
|
|
1670
|
+
type: "offer";
|
|
1671
|
+
from: string;
|
|
1672
|
+
sdp: string;
|
|
1673
|
+
} | {
|
|
1674
|
+
type: "answer";
|
|
1675
|
+
from: string;
|
|
1676
|
+
sdp: string;
|
|
1677
|
+
} | {
|
|
1678
|
+
type: "ice";
|
|
1679
|
+
from: string;
|
|
1680
|
+
candidate: string;
|
|
1681
|
+
} | {
|
|
1682
|
+
type: "mute";
|
|
1683
|
+
peer_id: string;
|
|
1684
|
+
muted: boolean;
|
|
1685
|
+
} | {
|
|
1686
|
+
type: "media-state";
|
|
1687
|
+
peer_id: string;
|
|
1688
|
+
video: boolean;
|
|
1689
|
+
screen: boolean;
|
|
1690
|
+
} | {
|
|
1691
|
+
type: "profile";
|
|
1692
|
+
peer_id: string;
|
|
1693
|
+
name: string;
|
|
1694
|
+
color: string;
|
|
1695
|
+
} | {
|
|
1696
|
+
type: "ping";
|
|
1697
|
+
} | {
|
|
1698
|
+
type: "error";
|
|
1699
|
+
code: string;
|
|
1700
|
+
message: string;
|
|
1701
|
+
};
|
|
1702
|
+
interface PeerInfo {
|
|
1703
|
+
peer_id: string;
|
|
1704
|
+
user_id: string;
|
|
1705
|
+
muted: boolean;
|
|
1706
|
+
video: boolean;
|
|
1707
|
+
screen: boolean;
|
|
1708
|
+
name: string | null;
|
|
1709
|
+
color: string | null;
|
|
1710
|
+
}
|
|
1711
|
+
interface PeerState extends PeerInfo {
|
|
1712
|
+
connectionState: RTCPeerConnectionState | "new";
|
|
1713
|
+
}
|
|
1714
|
+
interface FileTransferMeta {
|
|
1715
|
+
transferId: string;
|
|
1716
|
+
filename: string;
|
|
1717
|
+
mimeType: string;
|
|
1718
|
+
totalSize: number;
|
|
1719
|
+
chunkSize: number;
|
|
1720
|
+
totalChunks: number;
|
|
1721
|
+
}
|
|
1722
|
+
type FileTransferStatus = "pending" | "sending" | "receiving" | "complete" | "cancelled" | "error";
|
|
1723
|
+
declare const CHANNEL_NAMES: {
|
|
1724
|
+
readonly YJS_SYNC: "yjs-sync";
|
|
1725
|
+
readonly AWARENESS: "awareness";
|
|
1726
|
+
readonly FILE_TRANSFER: "file-transfer";
|
|
1727
|
+
readonly CUSTOM: "custom";
|
|
1728
|
+
};
|
|
1729
|
+
interface AbracadabraWebRTCConfiguration {
|
|
1730
|
+
/** Document ID for the signaling room. */
|
|
1731
|
+
docId: string;
|
|
1732
|
+
/** Server base URL (http/https). Signaling URL derived automatically. */
|
|
1733
|
+
url: string;
|
|
1734
|
+
/** JWT token or async token factory. */
|
|
1735
|
+
token: string | (() => string) | (() => Promise<string>);
|
|
1736
|
+
/** Optional Y.Doc to sync over data channels (hybrid mode). */
|
|
1737
|
+
document?: InstanceType<typeof Y.Doc> | null;
|
|
1738
|
+
/** Optional Awareness instance for presence sync over data channels. */
|
|
1739
|
+
awareness?: InstanceType<typeof Awareness> | null;
|
|
1740
|
+
/** ICE server configuration. Defaults to Google STUN. */
|
|
1741
|
+
iceServers?: RTCIceServer[];
|
|
1742
|
+
/** Display name for this peer. */
|
|
1743
|
+
displayName?: string;
|
|
1744
|
+
/** Color identifier for this peer. */
|
|
1745
|
+
color?: string;
|
|
1746
|
+
/** Enable Y.js document sync over data channels. Default: true when document is provided. */
|
|
1747
|
+
enableDocSync?: boolean;
|
|
1748
|
+
/** Enable awareness sync over data channels. Default: true when awareness is provided. */
|
|
1749
|
+
enableAwarenessSync?: boolean;
|
|
1750
|
+
/** Enable file transfer channel. Default: false. */
|
|
1751
|
+
enableFileTransfer?: boolean;
|
|
1752
|
+
/** Max file chunk size in bytes. Default: 16384 (16KB). */
|
|
1753
|
+
fileChunkSize?: number;
|
|
1754
|
+
/** Auto-connect on construction. Default: true. */
|
|
1755
|
+
autoConnect?: boolean;
|
|
1756
|
+
/** WebSocket polyfill for signaling (e.g. for Node.js). */
|
|
1757
|
+
WebSocketPolyfill?: any;
|
|
1758
|
+
}
|
|
1759
|
+
declare const DEFAULT_ICE_SERVERS: RTCIceServer[];
|
|
1760
|
+
declare const DEFAULT_FILE_CHUNK_SIZE = 16384;
|
|
1761
|
+
//#endregion
|
|
1762
|
+
//#region packages/provider/src/webrtc/FileTransferChannel.d.ts
|
|
1763
|
+
/**
|
|
1764
|
+
* Handle for tracking a file transfer in progress.
|
|
1765
|
+
*/
|
|
1766
|
+
declare class FileTransferHandle extends EventEmitter {
|
|
1767
|
+
readonly transferId: string;
|
|
1768
|
+
progress: number;
|
|
1769
|
+
status: FileTransferStatus;
|
|
1770
|
+
private abortController;
|
|
1771
|
+
constructor(transferId: string);
|
|
1772
|
+
cancel(): void;
|
|
1773
|
+
get signal(): AbortSignal;
|
|
1774
|
+
/** @internal */
|
|
1775
|
+
_setProgress(p: number): void;
|
|
1776
|
+
/** @internal */
|
|
1777
|
+
_setStatus(s: FileTransferStatus): void;
|
|
1778
|
+
}
|
|
1779
|
+
/**
|
|
1780
|
+
* Chunked binary file transfer over a dedicated WebRTC data channel.
|
|
1781
|
+
*/
|
|
1782
|
+
declare class FileTransferChannel extends EventEmitter {
|
|
1783
|
+
private readonly router;
|
|
1784
|
+
private receives;
|
|
1785
|
+
private chunkSize;
|
|
1786
|
+
private channelMessageHandler;
|
|
1787
|
+
constructor(router: DataChannelRouter, chunkSize?: number);
|
|
1788
|
+
/** Send a file to a peer. Returns a handle for tracking progress. */
|
|
1789
|
+
send(file: File | Blob, filename: string): Promise<FileTransferHandle>;
|
|
1790
|
+
private handleMessage;
|
|
1791
|
+
private handleStart;
|
|
1792
|
+
private handleChunk;
|
|
1793
|
+
private handleComplete;
|
|
1794
|
+
private handleCancel;
|
|
1795
|
+
destroy(): void;
|
|
1796
|
+
}
|
|
1797
|
+
//#endregion
|
|
1798
|
+
//#region packages/provider/src/webrtc/AbracadabraWebRTC.d.ts
|
|
1799
|
+
/**
|
|
1800
|
+
* Optional WebRTC provider for peer-to-peer Y.js sync, awareness, and file transfer.
|
|
1801
|
+
*
|
|
1802
|
+
* Uses the server's signaling endpoint (`/ws/:doc_id/signaling`) for connection
|
|
1803
|
+
* negotiation, then establishes direct data channels between peers. Designed to
|
|
1804
|
+
* work alongside `AbracadabraProvider` — the server remains the persistence layer,
|
|
1805
|
+
* while WebRTC provides low-latency P2P sync.
|
|
1806
|
+
*
|
|
1807
|
+
* Falls back to a no-op when `RTCPeerConnection` is unavailable (e.g. Node.js).
|
|
1808
|
+
*/
|
|
1809
|
+
declare class AbracadabraWebRTC extends EventEmitter {
|
|
1810
|
+
private signaling;
|
|
1811
|
+
private peerConnections;
|
|
1812
|
+
private yjsChannels;
|
|
1813
|
+
private fileChannels;
|
|
1814
|
+
private readonly config;
|
|
1815
|
+
readonly peers: Map<string, PeerState>;
|
|
1816
|
+
localPeerId: string | null;
|
|
1817
|
+
isConnected: boolean;
|
|
1818
|
+
constructor(configuration: AbracadabraWebRTCConfiguration);
|
|
1819
|
+
/**
|
|
1820
|
+
* Create an AbracadabraWebRTC instance from an existing provider,
|
|
1821
|
+
* reusing its document, awareness, URL, and token.
|
|
1822
|
+
*/
|
|
1823
|
+
static fromProvider(provider: AbracadabraProvider, options?: Partial<AbracadabraWebRTCConfiguration>): AbracadabraWebRTC;
|
|
1824
|
+
connect(): Promise<void>;
|
|
1825
|
+
disconnect(): void;
|
|
1826
|
+
destroy(): void;
|
|
1827
|
+
setMuted(muted: boolean): void;
|
|
1828
|
+
setMediaState(video: boolean, screen: boolean): void;
|
|
1829
|
+
setProfile(name: string, color: string): void;
|
|
1830
|
+
/**
|
|
1831
|
+
* Send a file to a specific peer. Returns a handle for tracking progress.
|
|
1832
|
+
*/
|
|
1833
|
+
sendFile(peerId: string, file: File | Blob, filename: string): Promise<FileTransferHandle | null>;
|
|
1834
|
+
/**
|
|
1835
|
+
* Send a file to all connected peers. Returns an array of handles.
|
|
1836
|
+
*/
|
|
1837
|
+
broadcastFile(file: File | Blob, filename: string): Promise<FileTransferHandle[]>;
|
|
1838
|
+
/**
|
|
1839
|
+
* Send a custom string message to a specific peer via a data channel.
|
|
1840
|
+
*/
|
|
1841
|
+
sendCustomMessage(peerId: string, payload: string): void;
|
|
1842
|
+
/**
|
|
1843
|
+
* Send a custom string message to all connected peers.
|
|
1844
|
+
*/
|
|
1845
|
+
broadcastCustomMessage(payload: string): void;
|
|
1846
|
+
private addPeer;
|
|
1847
|
+
private removePeer;
|
|
1848
|
+
private removeAllPeers;
|
|
1849
|
+
private createPeerConnection;
|
|
1850
|
+
private attachDataHandlers;
|
|
1851
|
+
private initiateConnection;
|
|
1852
|
+
private handleOffer;
|
|
1853
|
+
private buildSignalingUrl;
|
|
1854
|
+
}
|
|
1855
|
+
//#endregion
|
|
1856
|
+
//#region packages/provider/src/webrtc/SignalingSocket.d.ts
|
|
1857
|
+
interface SignalingSocketConfiguration {
|
|
1858
|
+
/** WebSocket URL for the signaling endpoint. */
|
|
1859
|
+
url: string;
|
|
1860
|
+
/** JWT token or async token factory for auth. */
|
|
1861
|
+
token: string | (() => string) | (() => Promise<string>);
|
|
1862
|
+
/** Auto-connect on construction. Default: true. */
|
|
1863
|
+
autoConnect?: boolean;
|
|
1864
|
+
/** WebSocket polyfill (e.g. for Node.js). */
|
|
1865
|
+
WebSocketPolyfill?: any;
|
|
1866
|
+
/** Retry delay in ms. Default: 1000. */
|
|
1867
|
+
delay?: number;
|
|
1868
|
+
/** Retry factor. Default: 2. */
|
|
1869
|
+
factor?: number;
|
|
1870
|
+
/** Min retry delay. Default: 1000. */
|
|
1871
|
+
minDelay?: number;
|
|
1872
|
+
/** Max retry delay. Default: 30000. */
|
|
1873
|
+
maxDelay?: number;
|
|
1874
|
+
/** Randomize delay. Default: true. */
|
|
1875
|
+
jitter?: boolean;
|
|
1876
|
+
/** Max retry attempts (0 = unlimited). Default: 0. */
|
|
1877
|
+
maxAttempts?: number;
|
|
1878
|
+
}
|
|
1879
|
+
declare class SignalingSocket extends EventEmitter {
|
|
1880
|
+
private ws;
|
|
1881
|
+
private wsHandlers;
|
|
1882
|
+
private shouldConnect;
|
|
1883
|
+
private cancelRetry?;
|
|
1884
|
+
private connectionAttempt;
|
|
1885
|
+
private readonly config;
|
|
1886
|
+
localPeerId: string | null;
|
|
1887
|
+
isConnected: boolean;
|
|
1888
|
+
constructor(configuration: SignalingSocketConfiguration);
|
|
1889
|
+
private getToken;
|
|
1890
|
+
connect(): Promise<void>;
|
|
1891
|
+
private createConnection;
|
|
1892
|
+
private handleMessage;
|
|
1893
|
+
private sendRaw;
|
|
1894
|
+
sendOffer(to: string, sdp: string): void;
|
|
1895
|
+
sendAnswer(to: string, sdp: string): void;
|
|
1896
|
+
sendIce(to: string, candidate: string): void;
|
|
1897
|
+
sendMute(muted: boolean): void;
|
|
1898
|
+
sendMediaState(video: boolean, screen: boolean): void;
|
|
1899
|
+
sendProfile(name: string, color: string): void;
|
|
1900
|
+
sendLeave(): void;
|
|
1901
|
+
disconnect(): void;
|
|
1902
|
+
destroy(): void;
|
|
1903
|
+
private cleanup;
|
|
1904
|
+
}
|
|
1905
|
+
//#endregion
|
|
1906
|
+
//#region packages/provider/src/webrtc/PeerConnection.d.ts
|
|
1907
|
+
declare class PeerConnection extends EventEmitter {
|
|
1908
|
+
readonly connection: RTCPeerConnection;
|
|
1909
|
+
readonly router: DataChannelRouter;
|
|
1910
|
+
readonly peerId: string;
|
|
1911
|
+
private pendingCandidates;
|
|
1912
|
+
private hasRemoteDescription;
|
|
1913
|
+
constructor(peerId: string, iceServers: RTCIceServer[]);
|
|
1914
|
+
get connectionState(): RTCPeerConnectionState;
|
|
1915
|
+
get iceConnectionState(): RTCIceConnectionState;
|
|
1916
|
+
/** Create an SDP offer (initiator side). */
|
|
1917
|
+
createOffer(iceRestart?: boolean): Promise<string>;
|
|
1918
|
+
/** Set a remote offer and create an answer (receiver side). Returns the SDP answer. */
|
|
1919
|
+
setRemoteOffer(sdp: string): Promise<string>;
|
|
1920
|
+
/** Set the remote answer (initiator side). */
|
|
1921
|
+
setRemoteAnswer(sdp: string): Promise<void>;
|
|
1922
|
+
/** Add a remote ICE candidate. Queues if remote description not yet set. */
|
|
1923
|
+
addIceCandidate(candidateJson: string): Promise<void>;
|
|
1924
|
+
private flushPendingCandidates;
|
|
1925
|
+
close(): void;
|
|
1926
|
+
destroy(): void;
|
|
1927
|
+
}
|
|
1928
|
+
//#endregion
|
|
1929
|
+
//#region packages/provider/src/webrtc/YjsDataChannel.d.ts
|
|
1930
|
+
/**
|
|
1931
|
+
* Handles Y.js document sync and awareness over WebRTC data channels.
|
|
1932
|
+
*
|
|
1933
|
+
* Uses the same y-protocols/sync encoding as the WebSocket provider but
|
|
1934
|
+
* transported over RTCDataChannel instead. A unique origin is used to
|
|
1935
|
+
* prevent echo loops with the server-based provider.
|
|
1936
|
+
*/
|
|
1937
|
+
declare class YjsDataChannel {
|
|
1938
|
+
private readonly document;
|
|
1939
|
+
private readonly awareness;
|
|
1940
|
+
private readonly router;
|
|
1941
|
+
private docUpdateHandler;
|
|
1942
|
+
private awarenessUpdateHandler;
|
|
1943
|
+
private channelOpenHandler;
|
|
1944
|
+
private channelMessageHandler;
|
|
1945
|
+
constructor(document: Y.Doc, awareness: Awareness | null, router: DataChannelRouter);
|
|
1946
|
+
/** Start listening for Y.js updates and data channel messages. */
|
|
1947
|
+
attach(): void;
|
|
1948
|
+
/** Stop listening and clean up handlers. */
|
|
1949
|
+
detach(): void;
|
|
1950
|
+
destroy(): void;
|
|
1951
|
+
private sendSyncStep1;
|
|
1952
|
+
private handleSyncMessage;
|
|
1953
|
+
private handleAwarenessMessage;
|
|
1954
|
+
}
|
|
1955
|
+
//#endregion
|
|
1956
|
+
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
package/src/AbracadabraClient.ts
CHANGED
|
@@ -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>(
|
package/src/AbracadabraWS.ts
CHANGED
|
@@ -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
|
-
|
|
514
|
+
// `event` may be a CloseEvent (browser) with `.code`, or a raw number (ws/Node.js).
|
|
515
|
+
// `event` may be a CloseEvent (browser) with `.code`, or a raw number (ws/Node.js).
|
|
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";
|
package/src/types.ts
CHANGED
|
@@ -166,6 +166,8 @@ export interface UserProfile {
|
|
|
166
166
|
email: string | null;
|
|
167
167
|
displayName: string | null;
|
|
168
168
|
role: string;
|
|
169
|
+
/** Account-level Ed25519 public key (base64url). Canonical user identity. */
|
|
170
|
+
publicKey: string | null;
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
export interface DocumentMeta {
|