@edryslabs/genericprovider 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +660 -0
  3. package/dist/index.d.ts +323 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +1001 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib.d.ts +36 -0
  8. package/dist/lib.d.ts.map +1 -0
  9. package/dist/lib.js +37 -0
  10. package/dist/lib.js.map +1 -0
  11. package/dist/providers/dummy/index.d.ts +226 -0
  12. package/dist/providers/dummy/index.d.ts.map +1 -0
  13. package/dist/providers/dummy/index.js +326 -0
  14. package/dist/providers/dummy/index.js.map +1 -0
  15. package/dist/providers/gun/index.d.ts +269 -0
  16. package/dist/providers/gun/index.d.ts.map +1 -0
  17. package/dist/providers/gun/index.js +683 -0
  18. package/dist/providers/gun/index.js.map +1 -0
  19. package/dist/providers/indexeddb/index.d.ts +161 -0
  20. package/dist/providers/indexeddb/index.d.ts.map +1 -0
  21. package/dist/providers/indexeddb/index.js +369 -0
  22. package/dist/providers/indexeddb/index.js.map +1 -0
  23. package/dist/providers/matrix/index.d.ts +109 -0
  24. package/dist/providers/matrix/index.d.ts.map +1 -0
  25. package/dist/providers/matrix/index.js +329 -0
  26. package/dist/providers/matrix/index.js.map +1 -0
  27. package/dist/providers/nostr/index.d.ts +172 -0
  28. package/dist/providers/nostr/index.d.ts.map +1 -0
  29. package/dist/providers/nostr/index.js +280 -0
  30. package/dist/providers/nostr/index.js.map +1 -0
  31. package/dist/providers/peerjs/index.d.ts +231 -0
  32. package/dist/providers/peerjs/index.d.ts.map +1 -0
  33. package/dist/providers/peerjs/index.js +1038 -0
  34. package/dist/providers/peerjs/index.js.map +1 -0
  35. package/dist/providers/pubnub/index.d.ts +106 -0
  36. package/dist/providers/pubnub/index.d.ts.map +1 -0
  37. package/dist/providers/pubnub/index.js +357 -0
  38. package/dist/providers/pubnub/index.js.map +1 -0
  39. package/dist/providers/simple-peer/index.d.ts +253 -0
  40. package/dist/providers/simple-peer/index.d.ts.map +1 -0
  41. package/dist/providers/simple-peer/index.js +783 -0
  42. package/dist/providers/simple-peer/index.js.map +1 -0
  43. package/dist/providers/supabase/index.d.ts +80 -0
  44. package/dist/providers/supabase/index.d.ts.map +1 -0
  45. package/dist/providers/supabase/index.js +202 -0
  46. package/dist/providers/supabase/index.js.map +1 -0
  47. package/dist/providers/trystero/index.d.ts +181 -0
  48. package/dist/providers/trystero/index.d.ts.map +1 -0
  49. package/dist/providers/trystero/index.js +187 -0
  50. package/dist/providers/trystero/index.js.map +1 -0
  51. package/dist/providers/websocket/index.d.ts +92 -0
  52. package/dist/providers/websocket/index.d.ts.map +1 -0
  53. package/dist/providers/websocket/index.js +272 -0
  54. package/dist/providers/websocket/index.js.map +1 -0
  55. package/dist/sync-monitor.d.ts +90 -0
  56. package/dist/sync-monitor.d.ts.map +1 -0
  57. package/dist/sync-monitor.js +149 -0
  58. package/dist/sync-monitor.js.map +1 -0
  59. package/dist/transport.d.ts +116 -0
  60. package/dist/transport.d.ts.map +1 -0
  61. package/dist/transport.js +2 -0
  62. package/dist/transport.js.map +1 -0
  63. package/package.json +137 -0
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Nostr Transport Provider
3
+ *
4
+ * Serverless, decentralised synchronisation using the Nostr protocol.
5
+ * Binary Yjs updates are base64-encoded and published as signed Nostr events
6
+ * to one or more relays. Every connected client subscribes to the same room tag,
7
+ * so updates fan out through all configured relays automatically.
8
+ *
9
+ * Features:
10
+ * - No server setup required (uses public relays or your own)
11
+ * - Multi-relay fan-out for redundancy
12
+ * - Ephemeral or persistent identity (bring-your-own key pair)
13
+ * - Optional password to obfuscate the room tag (SHA-256)
14
+ * - Configurable history window to catch up on missed updates
15
+ * - Automatic deduplication (events from self are ignored)
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import * as Y from 'yjs'
20
+ * import { GenericProvider } from 'y-generic'
21
+ * import { NostrTransport } from 'y-generic/providers/nostr'
22
+ * import { finalizeEvent, getPublicKey, SimplePool } from 'nostr-tools'
23
+ *
24
+ * const doc = new Y.Doc()
25
+ * const transport = new NostrTransport({ finalizeEvent, getPublicKey, SimplePool })
26
+ *
27
+ * const provider = new GenericProvider(doc, transport)
28
+ * await provider.connect({
29
+ * room: 'my-doc',
30
+ * relays: ['wss://relay.damus.io', 'wss://nos.lol'],
31
+ * })
32
+ * ```
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * // With a persistent identity and password-protected room
37
+ * import { generateSecretKey } from 'nostr-tools/pure'
38
+ *
39
+ * const secretKey = generateSecretKey() // persist this to keep identity
40
+ * const transport = new NostrTransport({ finalizeEvent, getPublicKey, SimplePool, secretKey })
41
+ *
42
+ * await provider.connect({
43
+ * room: 'my-doc',
44
+ * password: 'secret',
45
+ * relays: ['wss://relay.damus.io'],
46
+ * historyWindowSecs: 3600, // fetch last hour of updates on connect
47
+ * })
48
+ * ```
49
+ */
50
+ // ---------------------------------------------------------------------------
51
+ // CRC32 translation helpers
52
+ //
53
+ // GenericProvider wraps every outgoing message as [CRC32 (4 bytes)][payload].
54
+ // Nostr event content is plain text (base64), so we strip the CRC32 header
55
+ // before encoding and re-add it after decoding so GenericProvider accepts the
56
+ // incoming message.
57
+ // ---------------------------------------------------------------------------
58
+ const _CRC32_TABLE = (() => {
59
+ const table = new Uint32Array(256);
60
+ for (let i = 0; i < 256; i++) {
61
+ let c = i;
62
+ for (let j = 0; j < 8; j++)
63
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
64
+ table[i] = c;
65
+ }
66
+ return table;
67
+ })();
68
+ function _crc32(data) {
69
+ let crc = 0xffffffff;
70
+ for (let i = 0; i < data.length; i++)
71
+ crc = (crc >>> 8) ^ _CRC32_TABLE[(crc ^ data[i]) & 0xff];
72
+ return (crc ^ 0xffffffff) >>> 0;
73
+ }
74
+ /** Strip the 4-byte CRC32 header that GenericProvider prepends. */
75
+ function stripCRC32Header(data) {
76
+ return data.length >= 4 ? data.subarray(4) : data;
77
+ }
78
+ /** Add a valid CRC32 header so GenericProvider accepts the message. */
79
+ function addCRC32Header(data) {
80
+ const crc = _crc32(data);
81
+ const wrapped = new Uint8Array(4 + data.length);
82
+ wrapped[0] = (crc >>> 24) & 0xff;
83
+ wrapped[1] = (crc >>> 16) & 0xff;
84
+ wrapped[2] = (crc >>> 8) & 0xff;
85
+ wrapped[3] = crc & 0xff;
86
+ wrapped.set(data, 4);
87
+ return wrapped;
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // Base64 helpers (no Buffer/Node dependency)
91
+ // ---------------------------------------------------------------------------
92
+ function uint8ArrayToBase64(data) {
93
+ let binary = '';
94
+ for (let i = 0; i < data.length; i++) {
95
+ binary += String.fromCharCode(data[i]);
96
+ }
97
+ return btoa(binary);
98
+ }
99
+ function base64ToUint8Array(base64) {
100
+ const binary = atob(base64);
101
+ const bytes = new Uint8Array(binary.length);
102
+ for (let i = 0; i < binary.length; i++) {
103
+ bytes[i] = binary.charCodeAt(i);
104
+ }
105
+ return bytes;
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // Password hashing (obfuscates room tag — not encryption)
109
+ // ---------------------------------------------------------------------------
110
+ async function hashPassword(password) {
111
+ const encoded = new TextEncoder().encode(password);
112
+ const hashBuffer = await crypto.subtle.digest('SHA-256', encoded);
113
+ return Array.from(new Uint8Array(hashBuffer))
114
+ .map((b) => b.toString(16).padStart(2, '0'))
115
+ .join('')
116
+ .substring(0, 16);
117
+ }
118
+ // ---------------------------------------------------------------------------
119
+ // Nostr event kind for Yjs collaboration events.
120
+ //
121
+ // Kind 27370 is an application-specific kind chosen to avoid collisions with
122
+ // any well-known NIPs. Relays treat it as a regular (stored) event so that
123
+ // peers joining later can catch up on missed updates.
124
+ // ---------------------------------------------------------------------------
125
+ const DEFAULT_KIND = 27370;
126
+ // Default public relays used when no `relays` list is provided in config.
127
+ const DEFAULT_RELAYS = [
128
+ 'wss://relay.damus.io',
129
+ 'wss://nos.lol',
130
+ 'wss://relay.nostr.band',
131
+ ];
132
+ // ---------------------------------------------------------------------------
133
+ // NostrTransport
134
+ // ---------------------------------------------------------------------------
135
+ /**
136
+ * Nostr transport for y-generic.
137
+ *
138
+ * Publishes Yjs binary updates as base64-encoded Nostr events and subscribes
139
+ * to matching events from peers. Works in both browser and Node.js environments.
140
+ */
141
+ export class NostrTransport {
142
+ constructor(opts) {
143
+ this._connected = false;
144
+ this._buffer = [];
145
+ this.pool = null;
146
+ this.sub = null;
147
+ this.relays = [];
148
+ this.pubkey = '';
149
+ this.roomTag = '';
150
+ this.opts = opts;
151
+ this.eventKind = opts.eventKind ?? DEFAULT_KIND;
152
+ // Use provided key or an initial placeholder; real key resolved on connect.
153
+ this.secretKey = opts.secretKey ?? new Uint8Array(32);
154
+ }
155
+ get isConnected() {
156
+ return this._connected;
157
+ }
158
+ // ---------------------------------------------------------------------------
159
+ // Transport interface
160
+ // ---------------------------------------------------------------------------
161
+ async connect(config) {
162
+ if (this._connected) {
163
+ throw new Error('NostrTransport: already connected');
164
+ }
165
+ const debug = config.debug ?? this.opts.debug ?? false;
166
+ this.relays =
167
+ config.relays && config.relays.length > 0 ? config.relays : DEFAULT_RELAYS;
168
+ // Resolve signing key
169
+ if (this.opts.secretKey) {
170
+ this.secretKey = this.opts.secretKey;
171
+ }
172
+ else {
173
+ // Ephemeral key — unique per transport instance lifetime
174
+ this.secretKey = crypto.getRandomValues(new Uint8Array(32));
175
+ }
176
+ this.pubkey = this.opts.getPublicKey(this.secretKey);
177
+ // Compute room tag (optionally obfuscated by password)
178
+ this.roomTag = config.password
179
+ ? `${config.room}-${await hashPassword(config.password)}`
180
+ : config.room;
181
+ const historyWindowSecs = config.historyWindowSecs ?? 86400;
182
+ const since = historyWindowSecs > 0
183
+ ? Math.floor(Date.now() / 1000) - historyWindowSecs
184
+ : Math.floor(Date.now() / 1000); // real-time only
185
+ const filter = {
186
+ kinds: [this.eventKind],
187
+ '#r': [this.roomTag],
188
+ since,
189
+ };
190
+ this.pool = new this.opts.SimplePool();
191
+ if (debug) {
192
+ console.log('[NostrTransport] Connecting. relays:', this.relays, 'room:', this.roomTag, 'kind:', this.eventKind, 'filter.since:', since);
193
+ }
194
+ // Subscribe to events matching our room. The subscription delivers both
195
+ // stored (historical) events first, then real-time new events.
196
+ this.sub = this.pool.subscribeMany(this.relays, [filter], {
197
+ onevent: (event) => {
198
+ // Ignore events published by this client to avoid echo
199
+ if (event.pubkey === this.pubkey)
200
+ return;
201
+ if (debug) {
202
+ console.log('[NostrTransport] Received event', event.id.substring(0, 8), 'from', event.pubkey.substring(0, 8));
203
+ }
204
+ try {
205
+ const raw = base64ToUint8Array(event.content);
206
+ const withHeader = addCRC32Header(raw);
207
+ this._deliver(withHeader);
208
+ }
209
+ catch (err) {
210
+ console.warn('[NostrTransport] Failed to decode event content:', err);
211
+ }
212
+ },
213
+ oneose: () => {
214
+ if (debug) {
215
+ console.log('[NostrTransport] EOSE — stored events delivered');
216
+ }
217
+ },
218
+ });
219
+ this._connected = true;
220
+ if (debug) {
221
+ console.log('[NostrTransport] Connected, pubkey:', this.pubkey);
222
+ }
223
+ }
224
+ disconnect() {
225
+ if (this.sub) {
226
+ this.sub.close();
227
+ this.sub = null;
228
+ }
229
+ if (this.pool) {
230
+ this.pool.close(this.relays);
231
+ this.pool = null;
232
+ }
233
+ this._connected = false;
234
+ this._buffer = [];
235
+ }
236
+ async send(data) {
237
+ if (!this._connected || !this.pool) {
238
+ console.warn('[NostrTransport] Cannot send: not connected');
239
+ return;
240
+ }
241
+ // Strip the 4-byte CRC32 header added by GenericProvider before encoding
242
+ const raw = stripCRC32Header(data);
243
+ const content = uint8ArrayToBase64(raw);
244
+ const event = this.opts.finalizeEvent({
245
+ kind: this.eventKind,
246
+ created_at: Math.floor(Date.now() / 1000),
247
+ // Tag `r` is used as the room/document identifier for filtering
248
+ tags: [['r', this.roomTag]],
249
+ content,
250
+ }, this.secretKey);
251
+ // Publish to all relays; ignore individual relay errors
252
+ await Promise.allSettled(this.pool.publish(this.relays, event));
253
+ }
254
+ onMessage(callback) {
255
+ this._callback = callback;
256
+ // Flush buffered messages that arrived before this registration
257
+ if (this._buffer.length > 0) {
258
+ for (const msg of this._buffer) {
259
+ callback(msg);
260
+ }
261
+ this._buffer = [];
262
+ }
263
+ return () => {
264
+ this._callback = undefined;
265
+ };
266
+ }
267
+ // ---------------------------------------------------------------------------
268
+ // Private helpers
269
+ // ---------------------------------------------------------------------------
270
+ _deliver(data) {
271
+ if (this._callback) {
272
+ this._callback(data);
273
+ }
274
+ else {
275
+ // Buffer messages that arrive before onMessage() is registered
276
+ this._buffer.push(data);
277
+ }
278
+ }
279
+ }
280
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/nostr/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * PeerJS Transport Provider
3
+ *
4
+ * Peer-to-peer transport using WebRTC data channels with PeerJS library.
5
+ * PeerJS provides a simpler API and built-in signaling infrastructure.
6
+ *
7
+ * Features:
8
+ * - Direct peer-to-peer connections
9
+ * - Built-in signaling servers (PeerJS Cloud)
10
+ * - Automatic peer ID management
11
+ * - Simple connection API
12
+ * - Optional encryption
13
+ * - Automatic reconnection
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { GenericProvider } from 'y-generic'
18
+ * import { PeerJSTransport } from 'y-generic/providers/peerjs'
19
+ * import Peer from 'peerjs'
20
+ *
21
+ * const doc = new Y.Doc()
22
+ * const transport = new PeerJSTransport({
23
+ * peer: Peer, // Pass the PeerJS constructor
24
+ * password: 'optional-encryption-key'
25
+ * })
26
+ * const provider = new GenericProvider(doc, transport)
27
+ * await provider.connect({ room: 'my-room' })
28
+ * ```
29
+ */
30
+ import type { Transport, ConnectionConfig } from '../../transport';
31
+ /**
32
+ * PeerJS constructor type (from peerjs library).
33
+ */
34
+ export type PeerJSConstructor = any;
35
+ /**
36
+ * Configuration options for PeerJS transport.
37
+ */
38
+ export interface PeerJSTransportOptions {
39
+ /**
40
+ * The PeerJS library constructor.
41
+ * Users must provide this to avoid bundling the library.
42
+ * @example
43
+ * ```typescript
44
+ * import Peer from 'peerjs'
45
+ * const transport = new PeerJSTransport({ peer: Peer })
46
+ * ```
47
+ */
48
+ peer: PeerJSConstructor;
49
+ /**
50
+ * PeerJS server configuration.
51
+ * @default Uses PeerJS Cloud (cloud.peerjs.com)
52
+ */
53
+ peerOptions?: {
54
+ host?: string;
55
+ port?: number;
56
+ path?: string;
57
+ key?: string;
58
+ secure?: boolean;
59
+ config?: any;
60
+ debug?: number;
61
+ };
62
+ /**
63
+ * Optional password for encrypting messages.
64
+ * When provided, all messages are encrypted before sending.
65
+ * @default undefined
66
+ */
67
+ password?: string;
68
+ /**
69
+ * Maximum number of peer connections.
70
+ * @default 20 + random(0-15)
71
+ */
72
+ maxConns?: number;
73
+ /**
74
+ * Enable debug logging.
75
+ * @default false
76
+ */
77
+ debug?: boolean;
78
+ }
79
+ /**
80
+ * PeerJS transport implementation.
81
+ * Creates direct peer-to-peer connections using PeerJS library.
82
+ */
83
+ export declare class PeerJSTransport implements Transport {
84
+ private options;
85
+ private _connected;
86
+ private _room;
87
+ private _callback?;
88
+ private _peerConnectCallback?;
89
+ private peer;
90
+ private peerId;
91
+ private peers;
92
+ private knownPeers;
93
+ private broadcastChannel?;
94
+ private discoveryInterval?;
95
+ private isCoordinator;
96
+ private coordinatorPeerId;
97
+ private coordinatorConn?;
98
+ private roomPeers;
99
+ private reElectionInProgress;
100
+ private _destroying;
101
+ /**
102
+ * Create a new PeerJS transport.
103
+ *
104
+ * @param options - Configuration options (must include peer constructor)
105
+ */
106
+ constructor(options: PeerJSTransportOptions);
107
+ /**
108
+ * Connect to the room and start discovering peers.
109
+ */
110
+ connect(config: ConnectionConfig): Promise<void>;
111
+ /**
112
+ * Create a regular (non-coordinator) peer and connect to coordinator.
113
+ */
114
+ private createRegularPeer;
115
+ /**
116
+ * Disconnect from all peers and cleanup.
117
+ */
118
+ disconnect(): void;
119
+ /**
120
+ * Handle unexpected disconnect from the PeerJS signaling server.
121
+ * Happens on network changes (WiFi ↔ mobile), server restarts, etc.
122
+ * PeerJS keeps the same Peer ID — we call reconnect() then re-open
123
+ * DataConnections to all peers we already knew about.
124
+ */
125
+ private _handlePeerServerDisconnect;
126
+ /**
127
+ * Register callback for new peer data-channel connections.
128
+ */
129
+ onPeerConnect(callback: (peerId: string) => void): () => void;
130
+ /**
131
+ * Send data to all connected peers.
132
+ */
133
+ send(data: Uint8Array): void;
134
+ /**
135
+ * Register callback for incoming messages.
136
+ */
137
+ onMessage(callback: (data: Uint8Array) => void): () => void;
138
+ /**
139
+ * Check if connected.
140
+ */
141
+ get isConnected(): boolean;
142
+ /**
143
+ * Get number of connected peers (for debugging).
144
+ */
145
+ get connectedPeers(): number;
146
+ /**
147
+ * Setup peer discovery using BroadcastChannel for same-browser tabs.
148
+ */
149
+ private setupPeerDiscovery;
150
+ /**
151
+ * Announce presence to other peers.
152
+ */
153
+ private announcePeer;
154
+ /**
155
+ * Setup cross-browser peer discovery by connecting to the coordinator.
156
+ *
157
+ * Note: This method is only called for regular (non-coordinator) peers.
158
+ * The coordinator already exists because we failed to claim its ID.
159
+ */
160
+ private setupCrossBrowserDiscovery;
161
+ /**
162
+ * Become the coordinator for this room.
163
+ */
164
+ private becomeCoordinator;
165
+ /**
166
+ * Handle messages from coordinator (when we're a regular peer).
167
+ */
168
+ private handleCoordinatorMessage;
169
+ /**
170
+ * Handle coordinator disconnect - start re-election.
171
+ */
172
+ private handleCoordinatorDisconnect;
173
+ /**
174
+ * Attempt to connect to the coordinator.
175
+ * If coordinator doesn't exist yet, retry a few times.
176
+ */
177
+ private attemptCoordinatorConnection;
178
+ /**
179
+ * Transition from regular peer to coordinator by reconnecting with coordinator ID.
180
+ */
181
+ private transitionToCoordinator;
182
+ /**
183
+ * Recreate the local peer with a fresh random ID and reconnect to the
184
+ * coordinator (whoever won the election while we were transitioning).
185
+ * Called when transitionToCoordinator() fails.
186
+ */
187
+ private reestablishAsRegularPeer;
188
+ /**
189
+ * Connect to a peer by ID.
190
+ * To avoid race conditions, only the peer with the lower ID initiates the connection.
191
+ */
192
+ private connectToPeer;
193
+ /**
194
+ * Handle incoming connection from another peer.
195
+ */
196
+ private handleIncomingConnection;
197
+ /**
198
+ * Setup a peer connection with event handlers.
199
+ */
200
+ private setupConnection;
201
+ /**
202
+ * Remove and cleanup a peer connection.
203
+ */
204
+ private removePeer;
205
+ /**
206
+ * Send a coordination message (JSON encoded as binary).
207
+ */
208
+ private sendCoordinationMessage;
209
+ /**
210
+ * Try to decode data as a coordination message.
211
+ * Returns the parsed message if successful, null otherwise.
212
+ */
213
+ private tryDecodeCoordinationMessage;
214
+ /**
215
+ * Simple XOR encryption (not cryptographically secure, just obfuscation).
216
+ */
217
+ private encrypt;
218
+ /**
219
+ * Simple XOR decryption.
220
+ */
221
+ private decrypt;
222
+ /**
223
+ * Hash password to key.
224
+ */
225
+ private hashPassword;
226
+ /**
227
+ * Log debug messages if enabled.
228
+ */
229
+ private log;
230
+ }
231
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/peerjs/index.ts"],"names":[],"mappings":"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"}