@sqlrooms/crdt 0.29.0-rc.2 → 0.29.0-rc.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/createCrdtSlice.d.ts.map +1 -1
- package/dist/createCrdtSlice.js +1 -0
- package/dist/createCrdtSlice.js.map +1 -1
- package/dist/sync/webSocketSyncConnector.d.ts.map +1 -1
- package/dist/sync/webSocketSyncConnector.js +7 -3
- package/dist/sync/webSocketSyncConnector.js.map +1 -1
- package/package.json +18 -18
- package/dist/sync/webSocketConnector.d.ts +0 -27
- package/dist/sync/webSocketConnector.d.ts.map +0 -1
- package/dist/sync/webSocketConnector.js +0 -390
- package/dist/sync/webSocketConnector.js.map +0 -1
- package/dist/types.d.ts +0 -28
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -10
- package/dist/types.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createCrdtSlice.d.ts","sourceRoot":"","sources":["../src/createCrdtSlice.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"createCrdtSlice.d.ts","sourceRoot":"","sources":["../src/createCrdtSlice.ts"],"names":[],"mappings":"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"}
|
package/dist/createCrdtSlice.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createCrdtSlice.js","sourceRoot":"","sources":["../src/createCrdtSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {setAutoFreeze} from 'immer';\nimport {LoroDoc} from 'loro-crdt';\nimport {InferInputType, Mirror, SchemaType, schema} from 'loro-mirror';\nimport {StateCreator} from 'zustand';\nimport {\n InferredState,\n MirrorSchema,\n StoreGet,\n StoreSet,\n StripCidDeep,\n createSlice,\n} from './type-helpers';\n\n// Mirror can’t stamp $cid on frozen objects, so disable auto-freeze.\nsetAutoFreeze(false);\n\nexport type CrdtMirrorValueSelector<S, TSchema extends SchemaType> = (\n state: S,\n) => StripCidDeep<InferredState<TSchema>>;\n\nexport type CrdtMirrorValueApplier<S, TSchema extends SchemaType> = (\n value: InferredState<TSchema>,\n set: StoreSet<S>,\n get: StoreGet<S>,\n) => void;\n\nexport type CrdtDocStorage = {\n load: () => Promise<Uint8Array | undefined>;\n save: (data: Uint8Array) => Promise<void>;\n};\n\nexport type CrdtConnectionStatus =\n | 'idle'\n | 'connecting'\n | 'open'\n | 'closed'\n | 'error';\n\nexport type CrdtSyncConnector = {\n connect: (doc: LoroDoc) => Promise<void>;\n disconnect?: () => Promise<void>;\n /**\n * Optional hook for connectors to report connection status into the CRDT slice.\n *\n * `createCrdtSlice` will wire this automatically to `crdt.setConnectionStatus`,\n * so consumer apps don't need to pass `onStatus` callbacks manually.\n */\n setStatusListener?: (\n listener: (status: CrdtConnectionStatus) => void,\n ) => void;\n};\n\nexport type CrdtMirror<S, TSchema extends SchemaType = SchemaType> = {\n /**\n * Schema for the value stored under this mirror's key in the Loro doc.\n *\n * Example: if the mirror key is `\"canvas\"`, this schema describes the value at\n * `doc.root.canvas` (not an extra `{canvas: ...}` wrapper).\n */\n schema: MirrorSchema<TSchema>;\n /**\n * Select the value to write under this mirror key.\n *\n * If omitted, the store field at the same key name will be mirrored.\n */\n select?: CrdtMirrorValueSelector<S, TSchema>;\n /**\n * Apply an incoming CRDT value under this mirror key back into the store.\n *\n * If omitted, the store field at the same key name will be replaced.\n */\n apply?: CrdtMirrorValueApplier<S, TSchema>;\n /**\n * Initial value written under this mirror key when creating the Mirror.\n */\n initialState?: Partial<InferInputType<TSchema>>;\n mirrorOptions?: Record<string, unknown>;\n};\n\nexport type CreateCrdtSliceOptions<S, TSchema extends SchemaType> = {\n /**\n * CRDT mirrors keyed by their root key in the Loro document.\n *\n * Each entry becomes one `loro-mirror` `Mirror` instance on a shared `LoroDoc`.\n */\n mirrors: Record<string, CrdtMirror<S, any>>;\n doc?: LoroDoc;\n createDoc?: () => LoroDoc;\n storage?: CrdtDocStorage;\n sync?: CrdtSyncConnector;\n mirrorOptions?: Record<string, unknown>;\n onError?: (error: unknown) => void;\n};\n\nexport type CrdtSliceState = {\n crdt: {\n status: 'idle' | 'ready' | 'error';\n error?: string;\n /**\n * Optional sync connection status for UIs.\n *\n * This is intentionally generic and primarily used by websocket-based sync\n * connectors via `onStatus`.\n */\n connectionStatus: CrdtConnectionStatus;\n /**\n * Update `connectionStatus` (typically wired to a sync connector `onStatus` callback).\n */\n setConnectionStatus: (status: CrdtConnectionStatus) => void;\n initialize: () => Promise<void>;\n destroy: () => Promise<void>;\n };\n};\n\n/**\n * Create a CRDT-backed slice that mirrors selected store fields into a Loro doc.\n *\n * The returned state creator is intended to be composed into a larger Zustand store.\n */\nexport function createCrdtSlice<\n S extends Record<string, any>,\n TSchema extends SchemaType = SchemaType,\n>(options: CreateCrdtSliceOptions<S, TSchema>): StateCreator<CrdtSliceState> {\n return createSlice<CrdtSliceState, S & CrdtSliceState>((set, get, store) => {\n let doc: LoroDoc | undefined;\n let mirrors: Mirror<any>[] = [];\n let mirrorKeys: string[] = [];\n let unsubStore: (() => void) | undefined;\n let unsubMirrors: Array<() => void> = [];\n let unsubDocLocal: (() => void) | undefined;\n let initializing: Promise<void> | undefined;\n let suppressStoreToMirror = false;\n const lastOutboundByKey = new Map<string, unknown>();\n\n const persistDoc = async () => {\n if (!options.storage || !doc) return;\n try {\n const snapshot = doc.export({mode: 'snapshot'});\n await options.storage.save(snapshot);\n } catch (error) {\n options.onError?.(error);\n }\n };\n\n const pushFromStore = (state: S) => {\n if (mirrors.length === 0 || suppressStoreToMirror) return;\n for (let i = 0; i < mirrors.length; i += 1) {\n const mirror = mirrors[i];\n const key = mirrorKeys[i];\n if (!mirror || !key) continue;\n const cfg = options.mirrors[key];\n if (!cfg) continue;\n\n const value = cfg.select ? cfg.select(state) : (state as any)[key];\n\n const lastOutbound = lastOutboundByKey.get(key);\n if (lastOutbound === value) continue;\n\n lastOutboundByKey.set(key, value);\n\n mirror.setState(\n (draft: any) => {\n draft[key] = value;\n },\n {tags: ['from-store']},\n );\n }\n void persistDoc();\n };\n\n const applyMirrorToStore = (\n key: string,\n cfg: CrdtMirror<S, any>,\n mirrorState: any,\n tags?: string[],\n ) => {\n if (tags?.includes('from-store')) return;\n suppressStoreToMirror = true;\n try {\n const value = mirrorState?.[key];\n if (cfg.apply) {\n cfg.apply(value, set, get);\n } else {\n set({[key]: value} as any);\n }\n } finally {\n suppressStoreToMirror = false;\n }\n void persistDoc();\n };\n\n const initialize = async () => {\n // Idempotency: room stores (and React StrictMode in dev) can call initialize()\n // more than once. A second initialization without a prior destroy() would leak\n // subscriptions and can desync the sync connector from the active doc.\n if (initializing) return initializing;\n if (get().crdt?.status === 'ready' && doc && mirrors.length > 0) return;\n\n initializing = (async () => {\n try {\n mirrorKeys = Object.keys(options.mirrors);\n if (mirrorKeys.length === 0) {\n throw new Error('[crdt] `mirrors` must have at least one entry.');\n }\n\n doc = options.doc ?? options.createDoc?.() ?? new LoroDoc();\n if (!doc) throw new Error('[crdt] Failed to create Loro doc');\n const activeDoc = doc;\n\n if (options.storage) {\n const snapshot = await options.storage.load();\n if (snapshot) {\n activeDoc.import(snapshot);\n }\n }\n\n mirrors = mirrorKeys.map((key) => {\n const cfg = options.mirrors[key];\n if (!cfg)\n throw new Error(`[crdt] Missing mirror config for \"${key}\".`);\n\n // Wrap per-mirror schema/value under its root key.\n const rootSchema = schema({[key]: cfg.schema as any} as any);\n const initialState = cfg.initialState\n ? ({[key]: cfg.initialState} as any)\n : undefined;\n\n return new Mirror<any>({\n doc: activeDoc,\n schema: rootSchema as any,\n initialState,\n ...(cfg.mirrorOptions ?? options.mirrorOptions ?? {}),\n });\n });\n // Debug local doc updates to verify mirror.setState is producing CRDT ops.\n unsubDocLocal = doc.subscribeLocalUpdates?.(\n (update: Uint8Array) => {},\n );\n\n // Subscribe mirror->store first so snapshot/imported state wins.\n unsubMirrors = mirrors.map((m, idx) => {\n const key = mirrorKeys[idx];\n if (!key) return () => {};\n const cfg = options.mirrors[key];\n if (!cfg) return () => {};\n return m.subscribe((state: any, meta: any) =>\n applyMirrorToStore(key, cfg, state, meta?.tags),\n );\n });\n\n // Wait a tick so mirrors can emit any imported state, then align store once.\n await Promise.resolve();\n for (let i = 0; i < mirrors.length; i += 1) {\n const m = mirrors[i];\n const key = mirrorKeys[i];\n if (!m || !key) continue;\n const cfg = options.mirrors[key];\n if (!cfg) continue;\n applyMirrorToStore(key, cfg, m.getState() as any, []);\n }\n // Now subscribe store->mirror for local changes.\n unsubStore = store.subscribe((state) => {\n pushFromStore(state);\n });\n\n if (options.sync) {\n options.sync.setStatusListener?.((status) => {\n get().crdt.setConnectionStatus(status);\n });\n await options.sync.connect(doc);\n }\n\n const prevCrdt = get().crdt;\n set({\n crdt: {\n ...(prevCrdt ?? {}),\n status: 'ready',\n error: undefined,\n initialize: prevCrdt?.initialize ?? initialize,\n destroy: prevCrdt?.destroy ?? destroy,\n },\n } as Partial<S & CrdtSliceState>);\n } catch (error: any) {\n options.onError?.(error);\n const prevCrdt = get().crdt;\n set({\n crdt: {\n ...(prevCrdt ?? {}),\n status: 'error',\n error: error?.message ?? 'Failed to initialize CRDT',\n initialize: prevCrdt?.initialize ?? initialize,\n destroy: prevCrdt?.destroy ?? destroy,\n },\n } as Partial<S & CrdtSliceState>);\n } finally {\n initializing = undefined;\n }\n })();\n\n return initializing;\n };\n\n const destroy = async () => {\n unsubStore?.();\n for (const unsub of unsubMirrors) unsub?.();\n unsubDocLocal?.();\n if (options.sync?.disconnect) {\n await options.sync.disconnect();\n }\n doc = undefined;\n mirrors = [];\n mirrorKeys = [];\n unsubMirrors = [];\n initializing = undefined;\n const prevCrdt = get().crdt;\n set({\n crdt: {\n ...(prevCrdt ?? {}),\n status: 'idle',\n error: undefined,\n connectionStatus: 'idle',\n initialize: prevCrdt?.initialize ?? initialize,\n destroy: prevCrdt?.destroy ?? destroy,\n },\n } as Partial<S & CrdtSliceState>);\n };\n\n return {\n crdt: {\n status: 'idle',\n connectionStatus: 'idle',\n setConnectionStatus: (status) => {\n const prev = get().crdt;\n set({\n crdt: {\n ...(prev ?? {}),\n connectionStatus: status,\n },\n } as Partial<S & CrdtSliceState>);\n },\n initialize,\n destroy,\n },\n };\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"createCrdtSlice.js","sourceRoot":"","sources":["../src/createCrdtSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {setAutoFreeze} from 'immer';\nimport {LoroDoc} from 'loro-crdt';\nimport {InferInputType, Mirror, SchemaType, schema} from 'loro-mirror';\nimport {StateCreator} from 'zustand';\nimport {\n InferredState,\n MirrorSchema,\n StoreGet,\n StoreSet,\n StripCidDeep,\n createSlice,\n} from './type-helpers';\n\n// Mirror can’t stamp $cid on frozen objects, so disable auto-freeze.\nsetAutoFreeze(false);\n\nexport type CrdtMirrorValueSelector<S, TSchema extends SchemaType> = (\n state: S,\n) => StripCidDeep<InferredState<TSchema>>;\n\nexport type CrdtMirrorValueApplier<S, TSchema extends SchemaType> = (\n value: InferredState<TSchema>,\n set: StoreSet<S>,\n get: StoreGet<S>,\n) => void;\n\nexport type CrdtDocStorage = {\n load: () => Promise<Uint8Array | undefined>;\n save: (data: Uint8Array) => Promise<void>;\n};\n\nexport type CrdtConnectionStatus =\n | 'idle'\n | 'connecting'\n | 'open'\n | 'closed'\n | 'error';\n\nexport type CrdtSyncConnector = {\n connect: (doc: LoroDoc) => Promise<void>;\n disconnect?: () => Promise<void>;\n /**\n * Optional hook for connectors to report connection status into the CRDT slice.\n *\n * `createCrdtSlice` will wire this automatically to `crdt.setConnectionStatus`,\n * so consumer apps don't need to pass `onStatus` callbacks manually.\n */\n setStatusListener?: (\n listener: (status: CrdtConnectionStatus) => void,\n ) => void;\n};\n\nexport type CrdtMirror<S, TSchema extends SchemaType = SchemaType> = {\n /**\n * Schema for the value stored under this mirror's key in the Loro doc.\n *\n * Example: if the mirror key is `\"canvas\"`, this schema describes the value at\n * `doc.root.canvas` (not an extra `{canvas: ...}` wrapper).\n */\n schema: MirrorSchema<TSchema>;\n /**\n * Select the value to write under this mirror key.\n *\n * If omitted, the store field at the same key name will be mirrored.\n */\n select?: CrdtMirrorValueSelector<S, TSchema>;\n /**\n * Apply an incoming CRDT value under this mirror key back into the store.\n *\n * If omitted, the store field at the same key name will be replaced.\n */\n apply?: CrdtMirrorValueApplier<S, TSchema>;\n /**\n * Initial value written under this mirror key when creating the Mirror.\n */\n initialState?: Partial<InferInputType<TSchema>>;\n mirrorOptions?: Record<string, unknown>;\n};\n\nexport type CreateCrdtSliceOptions<S, TSchema extends SchemaType> = {\n /**\n * CRDT mirrors keyed by their root key in the Loro document.\n *\n * Each entry becomes one `loro-mirror` `Mirror` instance on a shared `LoroDoc`.\n */\n mirrors: Record<string, CrdtMirror<S, any>>;\n doc?: LoroDoc;\n createDoc?: () => LoroDoc;\n storage?: CrdtDocStorage;\n sync?: CrdtSyncConnector;\n mirrorOptions?: Record<string, unknown>;\n onError?: (error: unknown) => void;\n};\n\nexport type CrdtSliceState = {\n crdt: {\n status: 'idle' | 'ready' | 'error';\n error?: string;\n /**\n * Optional sync connection status for UIs.\n *\n * This is intentionally generic and primarily used by websocket-based sync\n * connectors via `onStatus`.\n */\n connectionStatus: CrdtConnectionStatus;\n /**\n * Update `connectionStatus` (typically wired to a sync connector `onStatus` callback).\n */\n setConnectionStatus: (status: CrdtConnectionStatus) => void;\n initialize: () => Promise<void>;\n destroy: () => Promise<void>;\n };\n};\n\n/**\n * Create a CRDT-backed slice that mirrors selected store fields into a Loro doc.\n *\n * The returned state creator is intended to be composed into a larger Zustand store.\n */\nexport function createCrdtSlice<\n S extends Record<string, any>,\n TSchema extends SchemaType = SchemaType,\n>(options: CreateCrdtSliceOptions<S, TSchema>): StateCreator<CrdtSliceState> {\n return createSlice<CrdtSliceState, S & CrdtSliceState>((set, get, store) => {\n let doc: LoroDoc | undefined;\n let mirrors: Mirror<any>[] = [];\n let mirrorKeys: string[] = [];\n let unsubStore: (() => void) | undefined;\n let unsubMirrors: Array<() => void> = [];\n let unsubDocLocal: (() => void) | undefined;\n let initializing: Promise<void> | undefined;\n let suppressStoreToMirror = false;\n const lastOutboundByKey = new Map<string, unknown>();\n\n const persistDoc = async () => {\n if (!options.storage || !doc) return;\n try {\n const snapshot = doc.export({mode: 'snapshot'});\n await options.storage.save(snapshot);\n } catch (error) {\n options.onError?.(error);\n }\n };\n\n const pushFromStore = (state: S) => {\n if (mirrors.length === 0 || suppressStoreToMirror) return;\n for (let i = 0; i < mirrors.length; i += 1) {\n const mirror = mirrors[i];\n const key = mirrorKeys[i];\n if (!mirror || !key) continue;\n const cfg = options.mirrors[key];\n if (!cfg) continue;\n\n const value = cfg.select ? cfg.select(state) : (state as any)[key];\n\n const lastOutbound = lastOutboundByKey.get(key);\n if (lastOutbound === value) continue;\n\n lastOutboundByKey.set(key, value);\n\n mirror.setState(\n (draft: any) => {\n draft[key] = value;\n },\n {tags: ['from-store']},\n );\n }\n void persistDoc();\n };\n\n const applyMirrorToStore = (\n key: string,\n cfg: CrdtMirror<S, any>,\n mirrorState: any,\n tags?: string[],\n ) => {\n if (tags?.includes('from-store')) return;\n suppressStoreToMirror = true;\n try {\n const value = mirrorState?.[key];\n if (cfg.apply) {\n cfg.apply(value, set, get);\n } else {\n set({[key]: value} as any);\n }\n } finally {\n suppressStoreToMirror = false;\n }\n void persistDoc();\n };\n\n const initialize = async () => {\n // Idempotency: room stores (and React StrictMode in dev) can call initialize()\n // more than once. A second initialization without a prior destroy() would leak\n // subscriptions and can desync the sync connector from the active doc.\n if (initializing) return initializing;\n if (get().crdt?.status === 'ready' && doc && mirrors.length > 0) return;\n\n initializing = (async () => {\n try {\n mirrorKeys = Object.keys(options.mirrors);\n if (mirrorKeys.length === 0) {\n throw new Error('[crdt] `mirrors` must have at least one entry.');\n }\n\n doc = options.doc ?? options.createDoc?.() ?? new LoroDoc();\n if (!doc) throw new Error('[crdt] Failed to create Loro doc');\n const activeDoc = doc;\n\n if (options.storage) {\n const snapshot = await options.storage.load();\n if (snapshot) {\n activeDoc.import(snapshot);\n activeDoc.checkoutToLatest();\n }\n }\n\n mirrors = mirrorKeys.map((key) => {\n const cfg = options.mirrors[key];\n if (!cfg)\n throw new Error(`[crdt] Missing mirror config for \"${key}\".`);\n\n // Wrap per-mirror schema/value under its root key.\n const rootSchema = schema({[key]: cfg.schema as any} as any);\n const initialState = cfg.initialState\n ? ({[key]: cfg.initialState} as any)\n : undefined;\n\n return new Mirror<any>({\n doc: activeDoc,\n schema: rootSchema as any,\n initialState,\n ...(cfg.mirrorOptions ?? options.mirrorOptions ?? {}),\n });\n });\n // Debug local doc updates to verify mirror.setState is producing CRDT ops.\n unsubDocLocal = doc.subscribeLocalUpdates?.(\n (update: Uint8Array) => {},\n );\n\n // Subscribe mirror->store first so snapshot/imported state wins.\n unsubMirrors = mirrors.map((m, idx) => {\n const key = mirrorKeys[idx];\n if (!key) return () => {};\n const cfg = options.mirrors[key];\n if (!cfg) return () => {};\n return m.subscribe((state: any, meta: any) =>\n applyMirrorToStore(key, cfg, state, meta?.tags),\n );\n });\n\n // Wait a tick so mirrors can emit any imported state, then align store once.\n await Promise.resolve();\n for (let i = 0; i < mirrors.length; i += 1) {\n const m = mirrors[i];\n const key = mirrorKeys[i];\n if (!m || !key) continue;\n const cfg = options.mirrors[key];\n if (!cfg) continue;\n applyMirrorToStore(key, cfg, m.getState() as any, []);\n }\n // Now subscribe store->mirror for local changes.\n unsubStore = store.subscribe((state) => {\n pushFromStore(state);\n });\n\n if (options.sync) {\n options.sync.setStatusListener?.((status) => {\n get().crdt.setConnectionStatus(status);\n });\n await options.sync.connect(doc);\n }\n\n const prevCrdt = get().crdt;\n set({\n crdt: {\n ...(prevCrdt ?? {}),\n status: 'ready',\n error: undefined,\n initialize: prevCrdt?.initialize ?? initialize,\n destroy: prevCrdt?.destroy ?? destroy,\n },\n } as Partial<S & CrdtSliceState>);\n } catch (error: any) {\n options.onError?.(error);\n const prevCrdt = get().crdt;\n set({\n crdt: {\n ...(prevCrdt ?? {}),\n status: 'error',\n error: error?.message ?? 'Failed to initialize CRDT',\n initialize: prevCrdt?.initialize ?? initialize,\n destroy: prevCrdt?.destroy ?? destroy,\n },\n } as Partial<S & CrdtSliceState>);\n } finally {\n initializing = undefined;\n }\n })();\n\n return initializing;\n };\n\n const destroy = async () => {\n unsubStore?.();\n for (const unsub of unsubMirrors) unsub?.();\n unsubDocLocal?.();\n if (options.sync?.disconnect) {\n await options.sync.disconnect();\n }\n doc = undefined;\n mirrors = [];\n mirrorKeys = [];\n unsubMirrors = [];\n initializing = undefined;\n const prevCrdt = get().crdt;\n set({\n crdt: {\n ...(prevCrdt ?? {}),\n status: 'idle',\n error: undefined,\n connectionStatus: 'idle',\n initialize: prevCrdt?.initialize ?? initialize,\n destroy: prevCrdt?.destroy ?? destroy,\n },\n } as Partial<S & CrdtSliceState>);\n };\n\n return {\n crdt: {\n status: 'idle',\n connectionStatus: 'idle',\n setConnectionStatus: (status) => {\n const prev = get().crdt;\n set({\n crdt: {\n ...(prev ?? {}),\n connectionStatus: status,\n },\n } as Partial<S & CrdtSliceState>);\n },\n initialize,\n destroy,\n },\n };\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webSocketSyncConnector.d.ts","sourceRoot":"","sources":["../../src/sync/webSocketSyncConnector.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,oBAAoB,EAAE,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAE3E,KAAK,aAAa,GAAG;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,GAAG,eAAe,KAAK,IAAI,CAAC;IACxE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAAK,IAAI,CAAC;IAC7E,mBAAmB,EAAE,CACnB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAC/B,IAAI,CAAC;CACX,CAAC;
|
|
1
|
+
{"version":3,"file":"webSocketSyncConnector.d.ts","sourceRoot":"","sources":["../../src/sync/webSocketSyncConnector.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,oBAAoB,EAAE,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAE3E,KAAK,aAAa,GAAG;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,GAAG,eAAe,KAAK,IAAI,CAAC;IACxE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAAK,IAAI,CAAC;IAC7E,mBAAmB,EAAE,CACnB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAC/B,IAAI,CAAC;CACX,CAAC;AA2DF,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACnE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,aAAa,CAAC;IAC7E,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,oBAAoB,GAC5B,iBAAiB,CAqdnB"}
|
|
@@ -42,6 +42,10 @@ const fromBase64 = (value) => {
|
|
|
42
42
|
out[i] = binary.charCodeAt(i);
|
|
43
43
|
return out;
|
|
44
44
|
};
|
|
45
|
+
function importAndCheckoutLatest(doc, bytes) {
|
|
46
|
+
doc.import(bytes);
|
|
47
|
+
doc.checkoutToLatest();
|
|
48
|
+
}
|
|
45
49
|
/**
|
|
46
50
|
* Creates a CRDT sync connector that exchanges Loro updates over WebSocket.
|
|
47
51
|
*/
|
|
@@ -224,7 +228,7 @@ export function createWebSocketSyncConnector(options) {
|
|
|
224
228
|
const bytes = event.data instanceof ArrayBuffer
|
|
225
229
|
? new Uint8Array(event.data)
|
|
226
230
|
: new Uint8Array(event.data.buffer, event.data.byteOffset, event.data.byteLength);
|
|
227
|
-
activeDoc
|
|
231
|
+
importAndCheckoutLatest(activeDoc, bytes);
|
|
228
232
|
return;
|
|
229
233
|
}
|
|
230
234
|
if (typeof Blob !== 'undefined' && event.data instanceof Blob) {
|
|
@@ -232,7 +236,7 @@ export function createWebSocketSyncConnector(options) {
|
|
|
232
236
|
.arrayBuffer()
|
|
233
237
|
.then((buf) => {
|
|
234
238
|
const bytes = new Uint8Array(buf);
|
|
235
|
-
activeDoc
|
|
239
|
+
importAndCheckoutLatest(activeDoc, bytes);
|
|
236
240
|
})
|
|
237
241
|
.catch((error) => console.warn('Failed to decode CRDT binary message', error));
|
|
238
242
|
return;
|
|
@@ -294,7 +298,7 @@ export function createWebSocketSyncConnector(options) {
|
|
|
294
298
|
catch {
|
|
295
299
|
// ignore
|
|
296
300
|
}
|
|
297
|
-
activeDoc
|
|
301
|
+
importAndCheckoutLatest(activeDoc, bytes);
|
|
298
302
|
snapshotApplied = true;
|
|
299
303
|
if (snapshotWaitTimer) {
|
|
300
304
|
clearTimeout(snapshotWaitTimer);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webSocketSyncConnector.js","sourceRoot":"","sources":["../../src/sync/webSocketSyncConnector.ts"],"names":[],"mappings":"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","sourcesContent":["import {LoroDoc} from 'loro-crdt';\nimport {CrdtConnectionStatus, CrdtSyncConnector} from '../createCrdtSlice';\n\ntype WebSocketLike = {\n readyState: number;\n send: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void;\n close: () => void;\n addEventListener: (type: string, listener: (...args: any[]) => void) => void;\n removeEventListener: (\n type: string,\n listener: (...args: any[]) => void,\n ) => void;\n};\n\nconst WS_OPEN = 1;\nconst WS_CONNECTING = 0;\n\nconst getOrCreateClientId = (storageKey: string) => {\n try {\n const ss = (globalThis as any).sessionStorage as Storage | undefined;\n if (ss) {\n const existing = ss.getItem(storageKey);\n if (existing) return existing;\n const created = (globalThis as any).crypto?.randomUUID?.() as\n | string\n | undefined;\n const id = created ?? `client-${Math.random().toString(16).slice(2)}`;\n ss.setItem(storageKey, id);\n return id;\n }\n } catch {\n // ignore\n }\n const created = (globalThis as any).crypto?.randomUUID?.() as\n | string\n | undefined;\n return created ?? `client-${Math.random().toString(16).slice(2)}`;\n};\n\nconst toBase64 = (bytes: Uint8Array) => {\n const buf = (globalThis as any).Buffer as\n | {from: (input: Uint8Array) => {toString: (enc: string) => string}}\n | undefined;\n if (buf) {\n return buf.from(bytes).toString('base64');\n }\n let binary = '';\n bytes.forEach((b) => {\n binary += String.fromCharCode(b);\n });\n return btoa(binary);\n};\n\nconst fromBase64 = (value: string) => {\n const buf = (globalThis as any).Buffer as\n | {from: (input: string, encoding: string) => Uint8Array}\n | undefined;\n if (buf) {\n return Uint8Array.from(buf.from(value, 'base64'));\n }\n const binary = atob(value);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);\n return out;\n};\n\nexport type WebSocketSyncOptions = {\n url: string;\n roomId: string;\n token?: string;\n params?: Record<string, string>;\n protocols?: string | string[];\n onStatus?: (status: Exclude<CrdtConnectionStatus, 'idle'>) => void;\n createSocket?: (url: string, protocols?: string | string[]) => WebSocketLike;\n sendSnapshotOnConnect?: boolean;\n /**\n * Optional per-tab client identifier. If omitted, the connector generates one via\n * `crypto.randomUUID()` and persists it in `sessionStorage` (per-tab) by default.\n */\n clientId?: string;\n /**\n * Storage key used for persisting the generated clientId in `sessionStorage`.\n *\n * @defaultValue `\"sqlrooms-crdt-clientId\"`\n */\n clientIdStorageKey?: string;\n maxRetries?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n};\n\n/**\n * Creates a CRDT sync connector that exchanges Loro updates over WebSocket.\n */\nexport function createWebSocketSyncConnector(\n options: WebSocketSyncOptions,\n): CrdtSyncConnector {\n const sendSnapshotOnConnect = options.sendSnapshotOnConnect ?? true;\n const clientId =\n options.clientId ??\n getOrCreateClientId(\n options.clientIdStorageKey ?? `sqlrooms-crdt-clientId:${options.roomId}`,\n );\n let socket: WebSocketLike | undefined;\n let unsubscribeLocal: (() => void) | undefined;\n let subscribedDoc: LoroDoc | undefined;\n let attempt = 0;\n let stopped = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let joined = false;\n let snapshotApplied = false;\n let snapshotWaitTimer: ReturnType<typeof setTimeout> | undefined;\n let seededAfterEmptyServerSnapshot = false;\n let connecting = false;\n const pending: Uint8Array[] = [];\n let localSubscribed = false;\n let listeningSocket: WebSocketLike | undefined;\n let detachSocketListeners: (() => void) | undefined;\n let statusListener:\n | ((status: Exclude<CrdtConnectionStatus, 'idle'>) => void)\n | undefined;\n\n const maxRetries = options.maxRetries ?? Infinity;\n const initialDelay = options.initialDelayMs ?? 500;\n const maxDelay = options.maxDelayMs ?? 5000;\n\n const maybeSendUpdate = (update: Uint8Array) => {\n if (!socket || socket.readyState !== WS_OPEN) {\n pending.push(update);\n return;\n }\n if (!joined) {\n pending.push(update);\n return;\n }\n // IMPORTANT: don't send local updates until we've applied the server snapshot.\n // Otherwise, a refreshing client that starts with empty local state can emit delete ops\n // that wipe the room before the snapshot arrives.\n if (!snapshotApplied) {\n pending.push(update);\n return;\n }\n socket.send(update);\n };\n\n const attachLocalSubscription = (doc: LoroDoc) => {\n try {\n const unsub = doc.subscribeLocalUpdates((update: Uint8Array) => {\n // Pass through to shared handler so we keep centralized buffering/sending logic.\n maybeSendUpdate(update);\n });\n unsubscribeLocal = () => {\n try {\n unsub();\n } catch (error) {\n console.warn('[crdt] failed to unsubscribe local updates', error);\n }\n };\n localSubscribed = true;\n } catch (error) {\n console.warn('[crdt] failed to attach local subscription', error);\n localSubscribed = false;\n unsubscribeLocal = undefined;\n }\n };\n\n /**\n * Ensures we are subscribed to local updates on the *current* doc.\n *\n * This matters because this connector can be reused across reconnects and\n * `connect(doc)` calls; we must not keep a stale subscription to a prior doc.\n */\n const ensureLocalSubscription = (doc: LoroDoc) => {\n if (subscribedDoc && subscribedDoc !== doc) {\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n }\n if (!localSubscribed || !unsubscribeLocal || subscribedDoc !== doc) {\n attachLocalSubscription(doc);\n subscribedDoc = doc;\n }\n };\n\n const buildUrl = () => {\n const url = new URL(options.url);\n url.searchParams.set('roomId', options.roomId);\n if (options.token) url.searchParams.set('token', options.token);\n if (options.params) {\n Object.entries(options.params).forEach(([k, v]) =>\n url.searchParams.set(k, v),\n );\n }\n return url.toString();\n };\n\n const sendStatus = (status: Exclude<CrdtConnectionStatus, 'idle'>) => {\n options.onStatus?.(status);\n statusListener?.(status);\n };\n\n const sendJoin = () => {\n if (!socket || socket.readyState !== WS_OPEN) return;\n const payload = JSON.stringify({\n type: 'crdt-join',\n roomId: options.roomId,\n clientId,\n });\n socket.send(payload);\n };\n\n const sendSnapshot = (doc: LoroDoc) => {\n if (!socket || socket.readyState !== WS_OPEN) return;\n try {\n const snapshot = doc.export({mode: 'snapshot'});\n const payload = JSON.stringify({\n type: 'crdt-snapshot',\n roomId: options.roomId,\n data: toBase64(snapshot),\n });\n socket.send(payload);\n } catch (error) {\n console.warn('Failed to send CRDT snapshot', error);\n }\n };\n\n const scheduleReconnect = (doc: LoroDoc) => {\n if (stopped) return;\n if (reconnectTimer) return;\n if (connecting) return;\n if (attempt >= maxRetries) {\n sendStatus('closed');\n return;\n }\n const delay = Math.min(maxDelay, initialDelay * 2 ** attempt);\n attempt += 1;\n reconnectTimer = setTimeout(() => {\n reconnectTimer = undefined;\n void connect(doc);\n }, delay);\n // Avoid keeping the Node.js event loop alive in tests/SSR environments.\n // No-op in browsers.\n (reconnectTimer as any)?.unref?.();\n };\n\n const getEmptySnapshotLen = () => {\n try {\n return new LoroDoc().export({mode: 'snapshot'}).byteLength;\n } catch {\n return 0;\n }\n };\n\n const connect = async (doc: LoroDoc) => {\n if (stopped) return;\n if (connecting) return;\n // Always ensure we are subscribed to the *current* doc.\n ensureLocalSubscription(doc);\n\n const attachSocketListenersFor = (ws: WebSocketLike) => {\n // Ensure browser websockets deliver binary frames as ArrayBuffer (not Blob)\n if ('binaryType' in ws) {\n try {\n (ws as any).binaryType = 'arraybuffer';\n } catch (error) {\n console.warn('Failed to set binaryType on CRDT websocket', error);\n }\n }\n\n const handleMessage = (event: any) => {\n // Use the currently connected doc reference (not the doc that created the socket),\n // so a later connect(doc) call can rebind without needing a new WebSocket.\n const activeDoc = subscribedDoc ?? doc;\n if (!activeDoc) return;\n // Binary updates flow directly\n if (\n event.data instanceof ArrayBuffer ||\n ArrayBuffer.isView(event.data)\n ) {\n const bytes =\n event.data instanceof ArrayBuffer\n ? new Uint8Array(event.data)\n : new Uint8Array(\n event.data.buffer,\n event.data.byteOffset,\n event.data.byteLength,\n );\n activeDoc.import(bytes);\n return;\n }\n if (typeof Blob !== 'undefined' && event.data instanceof Blob) {\n void event.data\n .arrayBuffer()\n .then((buf: ArrayBuffer) => {\n const bytes = new Uint8Array(buf);\n activeDoc.import(bytes);\n })\n .catch((error: unknown) =>\n console.warn('Failed to decode CRDT binary message', error),\n );\n return;\n }\n\n if (typeof event.data === 'string') {\n try {\n const parsed = JSON.parse(event.data);\n if (parsed?.type === 'crdt-joined') {\n joined = true;\n snapshotApplied = false;\n // IMPORTANT: do not flush buffered local updates yet.\n // The server sends `crdt-joined` before `crdt-snapshot`; flushing here can\n // broadcast \"empty state\" ops from a refreshing client and wipe the room.\n if (snapshotWaitTimer) clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = setTimeout(() => {\n snapshotWaitTimer = undefined;\n if (!ws || ws.readyState !== WS_OPEN) return;\n // Fallback: if we never get a snapshot, avoid buffering forever.\n snapshotApplied = true;\n while (pending.length) {\n const update = pending.shift();\n if (update) ws.send(update);\n }\n }, 2000);\n (snapshotWaitTimer as any)?.unref?.();\n return;\n }\n if (parsed?.type === 'crdt-snapshot' && parsed.data) {\n const bytes = fromBase64(parsed.data);\n // If the server snapshot is empty, but we already have non-empty local state,\n // don't import the empty snapshot (it would wipe local state). Instead, seed\n // the server once with our snapshot.\n try {\n const emptyLen = getEmptySnapshotLen();\n const serverLooksEmpty = bytes.byteLength <= emptyLen + 32;\n const localSnapshotLen = activeDoc.export({\n mode: 'snapshot',\n }).byteLength;\n const localNonEmpty = localSnapshotLen > emptyLen + 32;\n if (\n serverLooksEmpty &&\n localNonEmpty &&\n !seededAfterEmptyServerSnapshot &&\n ws &&\n ws.readyState === WS_OPEN\n ) {\n seededAfterEmptyServerSnapshot = true;\n // Seed the server; server will accept snapshot only if the room is empty.\n sendSnapshot(activeDoc);\n snapshotApplied = true;\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n return;\n }\n } catch {\n // ignore\n }\n\n activeDoc.import(bytes);\n snapshotApplied = true;\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n // Now that we have base state, flush any local updates buffered during join.\n while (pending.length) {\n const update = pending.shift();\n if (update && ws && ws.readyState === WS_OPEN) {\n ws.send(update);\n }\n }\n }\n // Ignore other messages (errors, acks) for now\n } catch (error) {\n console.warn('Failed to parse CRDT message', error);\n }\n }\n };\n\n const handleOpen = () => {\n attempt = 0;\n joined = false;\n snapshotApplied = false;\n seededAfterEmptyServerSnapshot = false;\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n connecting = false;\n sendStatus('open');\n sendJoin();\n if (sendSnapshotOnConnect) {\n sendSnapshot(doc);\n }\n ensureLocalSubscription(doc);\n };\n\n const handleClose = (event: CloseEvent) => {\n console.warn('CRDT WS closed', {\n code: event.code,\n reason: event.reason,\n pending: pending.length,\n joined,\n });\n connecting = false;\n sendStatus('closed');\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n joined = false;\n pending.length = 0;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n scheduleReconnect(doc);\n };\n\n const handleError = (event: Event) => {\n console.warn('CRDT WS error', event);\n connecting = false;\n sendStatus('error');\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n joined = false;\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n scheduleReconnect(doc);\n };\n\n // Some WebSocket implementations expose either addEventListener or on*\n // handlers. Use one style only to avoid duplicate events.\n if (typeof ws.addEventListener === 'function') {\n ws.addEventListener('message', handleMessage);\n ws.addEventListener('open', handleOpen);\n ws.addEventListener('close', handleClose);\n ws.addEventListener('error', handleError);\n detachSocketListeners = () => {\n try {\n ws.removeEventListener('message', handleMessage);\n ws.removeEventListener('open', handleOpen);\n ws.removeEventListener('close', handleClose);\n ws.removeEventListener('error', handleError);\n } catch (error) {\n console.warn('[crdt] failed to detach socket listeners', error);\n }\n };\n } else {\n (ws as any).onmessage = handleMessage;\n (ws as any).onopen = handleOpen;\n (ws as any).onclose = handleClose;\n (ws as any).onerror = handleError;\n detachSocketListeners = () => {\n try {\n (ws as any).onmessage = null;\n (ws as any).onopen = null;\n (ws as any).onclose = null;\n (ws as any).onerror = null;\n } catch (error) {\n console.warn('[crdt] failed to clear socket handlers', error);\n }\n };\n }\n listeningSocket = ws;\n\n // If we stay in CONNECTING too long, force a reconnect to avoid being stuck.\n const connectingTimeout = setTimeout(() => {\n if (ws && ws.readyState === WS_CONNECTING && !joined) {\n console.warn('[crdt] ws still connecting after timeout; retrying');\n try {\n ws.close();\n } catch (error) {\n console.warn('[crdt] error closing stuck socket', error);\n }\n }\n }, 3000);\n // Avoid keeping the Node.js event loop alive in tests/SSR environments.\n // No-op in browsers.\n (connectingTimeout as any)?.unref?.();\n };\n\n if (\n socket &&\n (socket.readyState === WS_OPEN || socket.readyState === WS_CONNECTING)\n ) {\n if (listeningSocket !== socket) {\n console.warn('[crdt] existing socket had no listeners; attaching now');\n attachSocketListenersFor(socket);\n // If the socket is already open, we won't get an 'open' event, so act as if\n // we just opened: (re)join and optionally send snapshot.\n if (socket.readyState === WS_OPEN) {\n attempt = 0;\n joined = false;\n sendStatus('open');\n sendJoin();\n if (sendSnapshotOnConnect) sendSnapshot(doc);\n }\n }\n return;\n }\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n connecting = true;\n sendStatus('connecting');\n const wsCreator =\n options.createSocket ??\n ((url, protocols) => new WebSocket(url, protocols));\n const url = buildUrl();\n try {\n socket = wsCreator(url, options.protocols);\n } catch (error) {\n connecting = false;\n sendStatus('error');\n scheduleReconnect(doc);\n return;\n }\n attachSocketListenersFor(socket);\n };\n\n const disconnect = async () => {\n stopped = true;\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n if (socket) {\n try {\n socket.close();\n } catch (error) {\n console.warn('Error closing CRDT websocket', error);\n }\n }\n socket = undefined;\n sendStatus('closed');\n };\n\n return {\n connect,\n disconnect,\n setStatusListener: (listener) => {\n statusListener = listener as any;\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"webSocketSyncConnector.js","sourceRoot":"","sources":["../../src/sync/webSocketSyncConnector.ts"],"names":[],"mappings":"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","sourcesContent":["import {LoroDoc} from 'loro-crdt';\nimport {CrdtConnectionStatus, CrdtSyncConnector} from '../createCrdtSlice';\n\ntype WebSocketLike = {\n readyState: number;\n send: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void;\n close: () => void;\n addEventListener: (type: string, listener: (...args: any[]) => void) => void;\n removeEventListener: (\n type: string,\n listener: (...args: any[]) => void,\n ) => void;\n};\n\nconst WS_OPEN = 1;\nconst WS_CONNECTING = 0;\n\nconst getOrCreateClientId = (storageKey: string) => {\n try {\n const ss = (globalThis as any).sessionStorage as Storage | undefined;\n if (ss) {\n const existing = ss.getItem(storageKey);\n if (existing) return existing;\n const created = (globalThis as any).crypto?.randomUUID?.() as\n | string\n | undefined;\n const id = created ?? `client-${Math.random().toString(16).slice(2)}`;\n ss.setItem(storageKey, id);\n return id;\n }\n } catch {\n // ignore\n }\n const created = (globalThis as any).crypto?.randomUUID?.() as\n | string\n | undefined;\n return created ?? `client-${Math.random().toString(16).slice(2)}`;\n};\n\nconst toBase64 = (bytes: Uint8Array) => {\n const buf = (globalThis as any).Buffer as\n | {from: (input: Uint8Array) => {toString: (enc: string) => string}}\n | undefined;\n if (buf) {\n return buf.from(bytes).toString('base64');\n }\n let binary = '';\n bytes.forEach((b) => {\n binary += String.fromCharCode(b);\n });\n return btoa(binary);\n};\n\nconst fromBase64 = (value: string) => {\n const buf = (globalThis as any).Buffer as\n | {from: (input: string, encoding: string) => Uint8Array}\n | undefined;\n if (buf) {\n return Uint8Array.from(buf.from(value, 'base64'));\n }\n const binary = atob(value);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);\n return out;\n};\n\nfunction importAndCheckoutLatest(doc: LoroDoc, bytes: Uint8Array) {\n doc.import(bytes);\n doc.checkoutToLatest();\n}\n\nexport type WebSocketSyncOptions = {\n url: string;\n roomId: string;\n token?: string;\n params?: Record<string, string>;\n protocols?: string | string[];\n onStatus?: (status: Exclude<CrdtConnectionStatus, 'idle'>) => void;\n createSocket?: (url: string, protocols?: string | string[]) => WebSocketLike;\n sendSnapshotOnConnect?: boolean;\n /**\n * Optional per-tab client identifier. If omitted, the connector generates one via\n * `crypto.randomUUID()` and persists it in `sessionStorage` (per-tab) by default.\n */\n clientId?: string;\n /**\n * Storage key used for persisting the generated clientId in `sessionStorage`.\n *\n * @defaultValue `\"sqlrooms-crdt-clientId\"`\n */\n clientIdStorageKey?: string;\n maxRetries?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n};\n\n/**\n * Creates a CRDT sync connector that exchanges Loro updates over WebSocket.\n */\nexport function createWebSocketSyncConnector(\n options: WebSocketSyncOptions,\n): CrdtSyncConnector {\n const sendSnapshotOnConnect = options.sendSnapshotOnConnect ?? true;\n const clientId =\n options.clientId ??\n getOrCreateClientId(\n options.clientIdStorageKey ?? `sqlrooms-crdt-clientId:${options.roomId}`,\n );\n let socket: WebSocketLike | undefined;\n let unsubscribeLocal: (() => void) | undefined;\n let subscribedDoc: LoroDoc | undefined;\n let attempt = 0;\n let stopped = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let joined = false;\n let snapshotApplied = false;\n let snapshotWaitTimer: ReturnType<typeof setTimeout> | undefined;\n let seededAfterEmptyServerSnapshot = false;\n let connecting = false;\n const pending: Uint8Array[] = [];\n let localSubscribed = false;\n let listeningSocket: WebSocketLike | undefined;\n let detachSocketListeners: (() => void) | undefined;\n let statusListener:\n | ((status: Exclude<CrdtConnectionStatus, 'idle'>) => void)\n | undefined;\n\n const maxRetries = options.maxRetries ?? Infinity;\n const initialDelay = options.initialDelayMs ?? 500;\n const maxDelay = options.maxDelayMs ?? 5000;\n\n const maybeSendUpdate = (update: Uint8Array) => {\n if (!socket || socket.readyState !== WS_OPEN) {\n pending.push(update);\n return;\n }\n if (!joined) {\n pending.push(update);\n return;\n }\n // IMPORTANT: don't send local updates until we've applied the server snapshot.\n // Otherwise, a refreshing client that starts with empty local state can emit delete ops\n // that wipe the room before the snapshot arrives.\n if (!snapshotApplied) {\n pending.push(update);\n return;\n }\n socket.send(update);\n };\n\n const attachLocalSubscription = (doc: LoroDoc) => {\n try {\n const unsub = doc.subscribeLocalUpdates((update: Uint8Array) => {\n // Pass through to shared handler so we keep centralized buffering/sending logic.\n maybeSendUpdate(update);\n });\n unsubscribeLocal = () => {\n try {\n unsub();\n } catch (error) {\n console.warn('[crdt] failed to unsubscribe local updates', error);\n }\n };\n localSubscribed = true;\n } catch (error) {\n console.warn('[crdt] failed to attach local subscription', error);\n localSubscribed = false;\n unsubscribeLocal = undefined;\n }\n };\n\n /**\n * Ensures we are subscribed to local updates on the *current* doc.\n *\n * This matters because this connector can be reused across reconnects and\n * `connect(doc)` calls; we must not keep a stale subscription to a prior doc.\n */\n const ensureLocalSubscription = (doc: LoroDoc) => {\n if (subscribedDoc && subscribedDoc !== doc) {\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n }\n if (!localSubscribed || !unsubscribeLocal || subscribedDoc !== doc) {\n attachLocalSubscription(doc);\n subscribedDoc = doc;\n }\n };\n\n const buildUrl = () => {\n const url = new URL(options.url);\n url.searchParams.set('roomId', options.roomId);\n if (options.token) url.searchParams.set('token', options.token);\n if (options.params) {\n Object.entries(options.params).forEach(([k, v]) =>\n url.searchParams.set(k, v),\n );\n }\n return url.toString();\n };\n\n const sendStatus = (status: Exclude<CrdtConnectionStatus, 'idle'>) => {\n options.onStatus?.(status);\n statusListener?.(status);\n };\n\n const sendJoin = () => {\n if (!socket || socket.readyState !== WS_OPEN) return;\n const payload = JSON.stringify({\n type: 'crdt-join',\n roomId: options.roomId,\n clientId,\n });\n socket.send(payload);\n };\n\n const sendSnapshot = (doc: LoroDoc) => {\n if (!socket || socket.readyState !== WS_OPEN) return;\n try {\n const snapshot = doc.export({mode: 'snapshot'});\n const payload = JSON.stringify({\n type: 'crdt-snapshot',\n roomId: options.roomId,\n data: toBase64(snapshot),\n });\n socket.send(payload);\n } catch (error) {\n console.warn('Failed to send CRDT snapshot', error);\n }\n };\n\n const scheduleReconnect = (doc: LoroDoc) => {\n if (stopped) return;\n if (reconnectTimer) return;\n if (connecting) return;\n if (attempt >= maxRetries) {\n sendStatus('closed');\n return;\n }\n const delay = Math.min(maxDelay, initialDelay * 2 ** attempt);\n attempt += 1;\n reconnectTimer = setTimeout(() => {\n reconnectTimer = undefined;\n void connect(doc);\n }, delay);\n // Avoid keeping the Node.js event loop alive in tests/SSR environments.\n // No-op in browsers.\n (reconnectTimer as any)?.unref?.();\n };\n\n const getEmptySnapshotLen = () => {\n try {\n return new LoroDoc().export({mode: 'snapshot'}).byteLength;\n } catch {\n return 0;\n }\n };\n\n const connect = async (doc: LoroDoc) => {\n if (stopped) return;\n if (connecting) return;\n // Always ensure we are subscribed to the *current* doc.\n ensureLocalSubscription(doc);\n\n const attachSocketListenersFor = (ws: WebSocketLike) => {\n // Ensure browser websockets deliver binary frames as ArrayBuffer (not Blob)\n if ('binaryType' in ws) {\n try {\n (ws as any).binaryType = 'arraybuffer';\n } catch (error) {\n console.warn('Failed to set binaryType on CRDT websocket', error);\n }\n }\n\n const handleMessage = (event: any) => {\n // Use the currently connected doc reference (not the doc that created the socket),\n // so a later connect(doc) call can rebind without needing a new WebSocket.\n const activeDoc = subscribedDoc ?? doc;\n if (!activeDoc) return;\n // Binary updates flow directly\n if (\n event.data instanceof ArrayBuffer ||\n ArrayBuffer.isView(event.data)\n ) {\n const bytes =\n event.data instanceof ArrayBuffer\n ? new Uint8Array(event.data)\n : new Uint8Array(\n event.data.buffer,\n event.data.byteOffset,\n event.data.byteLength,\n );\n importAndCheckoutLatest(activeDoc, bytes);\n return;\n }\n if (typeof Blob !== 'undefined' && event.data instanceof Blob) {\n void event.data\n .arrayBuffer()\n .then((buf: ArrayBuffer) => {\n const bytes = new Uint8Array(buf);\n importAndCheckoutLatest(activeDoc, bytes);\n })\n .catch((error: unknown) =>\n console.warn('Failed to decode CRDT binary message', error),\n );\n return;\n }\n\n if (typeof event.data === 'string') {\n try {\n const parsed = JSON.parse(event.data);\n if (parsed?.type === 'crdt-joined') {\n joined = true;\n snapshotApplied = false;\n // IMPORTANT: do not flush buffered local updates yet.\n // The server sends `crdt-joined` before `crdt-snapshot`; flushing here can\n // broadcast \"empty state\" ops from a refreshing client and wipe the room.\n if (snapshotWaitTimer) clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = setTimeout(() => {\n snapshotWaitTimer = undefined;\n if (!ws || ws.readyState !== WS_OPEN) return;\n // Fallback: if we never get a snapshot, avoid buffering forever.\n snapshotApplied = true;\n while (pending.length) {\n const update = pending.shift();\n if (update) ws.send(update);\n }\n }, 2000);\n (snapshotWaitTimer as any)?.unref?.();\n return;\n }\n if (parsed?.type === 'crdt-snapshot' && parsed.data) {\n const bytes = fromBase64(parsed.data);\n // If the server snapshot is empty, but we already have non-empty local state,\n // don't import the empty snapshot (it would wipe local state). Instead, seed\n // the server once with our snapshot.\n try {\n const emptyLen = getEmptySnapshotLen();\n const serverLooksEmpty = bytes.byteLength <= emptyLen + 32;\n const localSnapshotLen = activeDoc.export({\n mode: 'snapshot',\n }).byteLength;\n const localNonEmpty = localSnapshotLen > emptyLen + 32;\n if (\n serverLooksEmpty &&\n localNonEmpty &&\n !seededAfterEmptyServerSnapshot &&\n ws &&\n ws.readyState === WS_OPEN\n ) {\n seededAfterEmptyServerSnapshot = true;\n // Seed the server; server will accept snapshot only if the room is empty.\n sendSnapshot(activeDoc);\n snapshotApplied = true;\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n return;\n }\n } catch {\n // ignore\n }\n\n importAndCheckoutLatest(activeDoc, bytes);\n snapshotApplied = true;\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n // Now that we have base state, flush any local updates buffered during join.\n while (pending.length) {\n const update = pending.shift();\n if (update && ws && ws.readyState === WS_OPEN) {\n ws.send(update);\n }\n }\n }\n // Ignore other messages (errors, acks) for now\n } catch (error) {\n console.warn('Failed to parse CRDT message', error);\n }\n }\n };\n\n const handleOpen = () => {\n attempt = 0;\n joined = false;\n snapshotApplied = false;\n seededAfterEmptyServerSnapshot = false;\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n connecting = false;\n sendStatus('open');\n sendJoin();\n if (sendSnapshotOnConnect) {\n sendSnapshot(doc);\n }\n ensureLocalSubscription(doc);\n };\n\n const handleClose = (event: CloseEvent) => {\n console.warn('CRDT WS closed', {\n code: event.code,\n reason: event.reason,\n pending: pending.length,\n joined,\n });\n connecting = false;\n sendStatus('closed');\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n joined = false;\n pending.length = 0;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n scheduleReconnect(doc);\n };\n\n const handleError = (event: Event) => {\n console.warn('CRDT WS error', event);\n connecting = false;\n sendStatus('error');\n if (snapshotWaitTimer) {\n clearTimeout(snapshotWaitTimer);\n snapshotWaitTimer = undefined;\n }\n joined = false;\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n scheduleReconnect(doc);\n };\n\n // Some WebSocket implementations expose either addEventListener or on*\n // handlers. Use one style only to avoid duplicate events.\n if (typeof ws.addEventListener === 'function') {\n ws.addEventListener('message', handleMessage);\n ws.addEventListener('open', handleOpen);\n ws.addEventListener('close', handleClose);\n ws.addEventListener('error', handleError);\n detachSocketListeners = () => {\n try {\n ws.removeEventListener('message', handleMessage);\n ws.removeEventListener('open', handleOpen);\n ws.removeEventListener('close', handleClose);\n ws.removeEventListener('error', handleError);\n } catch (error) {\n console.warn('[crdt] failed to detach socket listeners', error);\n }\n };\n } else {\n (ws as any).onmessage = handleMessage;\n (ws as any).onopen = handleOpen;\n (ws as any).onclose = handleClose;\n (ws as any).onerror = handleError;\n detachSocketListeners = () => {\n try {\n (ws as any).onmessage = null;\n (ws as any).onopen = null;\n (ws as any).onclose = null;\n (ws as any).onerror = null;\n } catch (error) {\n console.warn('[crdt] failed to clear socket handlers', error);\n }\n };\n }\n listeningSocket = ws;\n\n // If we stay in CONNECTING too long, force a reconnect to avoid being stuck.\n const connectingTimeout = setTimeout(() => {\n if (ws && ws.readyState === WS_CONNECTING && !joined) {\n console.warn('[crdt] ws still connecting after timeout; retrying');\n try {\n ws.close();\n } catch (error) {\n console.warn('[crdt] error closing stuck socket', error);\n }\n }\n }, 3000);\n // Avoid keeping the Node.js event loop alive in tests/SSR environments.\n // No-op in browsers.\n (connectingTimeout as any)?.unref?.();\n };\n\n if (\n socket &&\n (socket.readyState === WS_OPEN || socket.readyState === WS_CONNECTING)\n ) {\n if (listeningSocket !== socket) {\n console.warn('[crdt] existing socket had no listeners; attaching now');\n attachSocketListenersFor(socket);\n // If the socket is already open, we won't get an 'open' event, so act as if\n // we just opened: (re)join and optionally send snapshot.\n if (socket.readyState === WS_OPEN) {\n attempt = 0;\n joined = false;\n sendStatus('open');\n sendJoin();\n if (sendSnapshotOnConnect) sendSnapshot(doc);\n }\n }\n return;\n }\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n connecting = true;\n sendStatus('connecting');\n const wsCreator =\n options.createSocket ??\n ((url, protocols) => new WebSocket(url, protocols));\n const url = buildUrl();\n try {\n socket = wsCreator(url, options.protocols);\n } catch (error) {\n connecting = false;\n sendStatus('error');\n scheduleReconnect(doc);\n return;\n }\n attachSocketListenersFor(socket);\n };\n\n const disconnect = async () => {\n stopped = true;\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n if (socket) {\n try {\n socket.close();\n } catch (error) {\n console.warn('Error closing CRDT websocket', error);\n }\n }\n socket = undefined;\n sendStatus('closed');\n };\n\n return {\n connect,\n disconnect,\n setStatusListener: (listener) => {\n statusListener = listener as any;\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sqlrooms/crdt",
|
|
3
|
-
"version": "0.29.0-rc.
|
|
4
|
-
"main": "dist/index.js",
|
|
5
|
-
"types": "dist/index.d.ts",
|
|
6
|
-
"module": "dist/index.js",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"sideEffects": false,
|
|
9
|
-
"author": "SQLRooms Contributors",
|
|
10
|
-
"license": "MIT",
|
|
3
|
+
"version": "0.29.0-rc.4",
|
|
11
4
|
"repository": {
|
|
12
5
|
"type": "git",
|
|
13
6
|
"url": "git+https://github.com/sqlrooms/sqlrooms.git"
|
|
14
7
|
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "SQLRooms Contributors",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "dist/index.js",
|
|
13
|
+
"module": "dist/index.js",
|
|
14
|
+
"types": "dist/index.d.ts",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"dev": "tsc -w",
|
|
21
|
+
"lint": "eslint .",
|
|
22
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"typedoc": "typedoc"
|
|
20
25
|
},
|
|
21
26
|
"dependencies": {
|
|
22
27
|
"immer": "^11.0.1",
|
|
@@ -33,13 +38,8 @@
|
|
|
33
38
|
"peerDependencies": {
|
|
34
39
|
"react": ">=18"
|
|
35
40
|
},
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"build": "tsc",
|
|
39
|
-
"lint": "eslint .",
|
|
40
|
-
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
41
|
-
"typecheck": "tsc --noEmit",
|
|
42
|
-
"typedoc": "typedoc"
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "c815bf8b1a5bc3f51418e690ae2237e1f0861759"
|
|
45
45
|
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { CrdtSyncConnector } from '../createCrdtSlice';
|
|
2
|
-
type WebSocketLike = {
|
|
3
|
-
readyState: number;
|
|
4
|
-
send: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void;
|
|
5
|
-
close: () => void;
|
|
6
|
-
addEventListener: (type: string, listener: (...args: any[]) => void) => void;
|
|
7
|
-
removeEventListener: (type: string, listener: (...args: any[]) => void) => void;
|
|
8
|
-
};
|
|
9
|
-
export type WebSocketSyncOptions = {
|
|
10
|
-
url: string;
|
|
11
|
-
roomId: string;
|
|
12
|
-
token?: string;
|
|
13
|
-
params?: Record<string, string>;
|
|
14
|
-
protocols?: string | string[];
|
|
15
|
-
onStatus?: (status: 'connecting' | 'open' | 'closed' | 'error') => void;
|
|
16
|
-
createSocket?: (url: string, protocols?: string | string[]) => WebSocketLike;
|
|
17
|
-
sendSnapshotOnConnect?: boolean;
|
|
18
|
-
maxRetries?: number;
|
|
19
|
-
initialDelayMs?: number;
|
|
20
|
-
maxDelayMs?: number;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Creates a CRDT sync connector that exchanges Loro updates over WebSocket.
|
|
24
|
-
*/
|
|
25
|
-
export declare function createWebSocketSyncConnector(options: WebSocketSyncOptions): CrdtSyncConnector;
|
|
26
|
-
export {};
|
|
27
|
-
//# sourceMappingURL=webSocketConnector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webSocketConnector.d.ts","sourceRoot":"","sources":["../../src/sync/webSocketConnector.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAErD,KAAK,aAAa,GAAG;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,GAAG,eAAe,KAAK,IAAI,CAAC;IACxE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAAK,IAAI,CAAC;IAC7E,mBAAmB,EAAE,CACnB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAC/B,IAAI,CAAC;CACX,CAAC;AAgCF,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,KAAK,IAAI,CAAC;IACxE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,aAAa,CAAC;IAC7E,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,oBAAoB,GAC5B,iBAAiB,CAyYnB"}
|
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
const WS_OPEN = 1;
|
|
2
|
-
const WS_CONNECTING = 0;
|
|
3
|
-
const toBase64 = (bytes) => {
|
|
4
|
-
const buf = globalThis.Buffer;
|
|
5
|
-
if (buf) {
|
|
6
|
-
return buf.from(bytes).toString('base64');
|
|
7
|
-
}
|
|
8
|
-
let binary = '';
|
|
9
|
-
bytes.forEach((b) => {
|
|
10
|
-
binary += String.fromCharCode(b);
|
|
11
|
-
});
|
|
12
|
-
return btoa(binary);
|
|
13
|
-
};
|
|
14
|
-
const fromBase64 = (value) => {
|
|
15
|
-
const buf = globalThis.Buffer;
|
|
16
|
-
if (buf) {
|
|
17
|
-
return Uint8Array.from(buf.from(value, 'base64'));
|
|
18
|
-
}
|
|
19
|
-
const binary = atob(value);
|
|
20
|
-
const out = new Uint8Array(binary.length);
|
|
21
|
-
for (let i = 0; i < binary.length; i += 1)
|
|
22
|
-
out[i] = binary.charCodeAt(i);
|
|
23
|
-
return out;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Creates a CRDT sync connector that exchanges Loro updates over WebSocket.
|
|
27
|
-
*/
|
|
28
|
-
export function createWebSocketSyncConnector(options) {
|
|
29
|
-
let socket;
|
|
30
|
-
let unsubscribeLocal;
|
|
31
|
-
let subscribedDoc;
|
|
32
|
-
let attempt = 0;
|
|
33
|
-
let stopped = false;
|
|
34
|
-
let reconnectTimer;
|
|
35
|
-
let joined = false;
|
|
36
|
-
let connecting = false;
|
|
37
|
-
const pending = [];
|
|
38
|
-
let localSubscribed = false;
|
|
39
|
-
let listeningSocket;
|
|
40
|
-
let detachSocketListeners;
|
|
41
|
-
const maxRetries = options.maxRetries ?? Infinity;
|
|
42
|
-
const initialDelay = options.initialDelayMs ?? 500;
|
|
43
|
-
const maxDelay = options.maxDelayMs ?? 5000;
|
|
44
|
-
const maybeSendUpdate = (update) => {
|
|
45
|
-
console.debug('[crdt] local update observed', update.byteLength, 'bytes', {
|
|
46
|
-
joined,
|
|
47
|
-
readyState: socket?.readyState,
|
|
48
|
-
});
|
|
49
|
-
if (!socket || socket.readyState !== WS_OPEN) {
|
|
50
|
-
console.debug('[crdt] skip send: socket not open, buffering');
|
|
51
|
-
pending.push(update);
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
if (!joined) {
|
|
55
|
-
console.debug('[crdt] buffering local update before join', update.byteLength, 'bytes');
|
|
56
|
-
pending.push(update);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
console.debug('[crdt] sending local update', update.byteLength, 'bytes');
|
|
60
|
-
socket.send(update);
|
|
61
|
-
};
|
|
62
|
-
const attachLocalSubscription = (doc) => {
|
|
63
|
-
try {
|
|
64
|
-
const unsub = doc.subscribeLocalUpdates((update) => {
|
|
65
|
-
// Pass through to shared handler so we keep centralized buffering/sending logic.
|
|
66
|
-
maybeSendUpdate(update);
|
|
67
|
-
});
|
|
68
|
-
unsubscribeLocal = () => {
|
|
69
|
-
try {
|
|
70
|
-
unsub();
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
console.warn('[crdt] failed to unsubscribe local updates', error);
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
localSubscribed = true;
|
|
77
|
-
console.debug('[crdt] attached local update subscription');
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
console.warn('[crdt] failed to attach local subscription', error);
|
|
81
|
-
localSubscribed = false;
|
|
82
|
-
unsubscribeLocal = undefined;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
/**
|
|
86
|
-
* Ensures we are subscribed to local updates on the *current* doc.
|
|
87
|
-
*
|
|
88
|
-
* This matters because this connector can be reused across reconnects and
|
|
89
|
-
* `connect(doc)` calls; we must not keep a stale subscription to a prior doc.
|
|
90
|
-
*/
|
|
91
|
-
const ensureLocalSubscription = (doc) => {
|
|
92
|
-
if (subscribedDoc && subscribedDoc !== doc) {
|
|
93
|
-
console.info('[crdt] switching local update subscription to new doc');
|
|
94
|
-
unsubscribeLocal?.();
|
|
95
|
-
unsubscribeLocal = undefined;
|
|
96
|
-
localSubscribed = false;
|
|
97
|
-
subscribedDoc = undefined;
|
|
98
|
-
}
|
|
99
|
-
if (!localSubscribed || !unsubscribeLocal || subscribedDoc !== doc) {
|
|
100
|
-
attachLocalSubscription(doc);
|
|
101
|
-
subscribedDoc = doc;
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
const buildUrl = () => {
|
|
105
|
-
const url = new URL(options.url);
|
|
106
|
-
url.searchParams.set('roomId', options.roomId);
|
|
107
|
-
if (options.token)
|
|
108
|
-
url.searchParams.set('token', options.token);
|
|
109
|
-
if (options.params) {
|
|
110
|
-
Object.entries(options.params).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
111
|
-
}
|
|
112
|
-
return url.toString();
|
|
113
|
-
};
|
|
114
|
-
const sendStatus = (status) => {
|
|
115
|
-
console.info('[crdt] ws status ->', status);
|
|
116
|
-
options.onStatus?.(status);
|
|
117
|
-
};
|
|
118
|
-
const sendJoin = () => {
|
|
119
|
-
if (!socket || socket.readyState !== WS_OPEN)
|
|
120
|
-
return;
|
|
121
|
-
const payload = JSON.stringify({ type: 'crdt-join', roomId: options.roomId });
|
|
122
|
-
console.debug('[crdt] sending join', payload);
|
|
123
|
-
socket.send(payload);
|
|
124
|
-
};
|
|
125
|
-
const sendSnapshot = (doc) => {
|
|
126
|
-
if (!socket || socket.readyState !== WS_OPEN)
|
|
127
|
-
return;
|
|
128
|
-
try {
|
|
129
|
-
const snapshot = doc.export({ mode: 'snapshot' });
|
|
130
|
-
console.info('[crdt] sending snapshot bytes', snapshot?.byteLength ?? snapshot?.length ?? 0);
|
|
131
|
-
const payload = JSON.stringify({
|
|
132
|
-
type: 'crdt-snapshot',
|
|
133
|
-
roomId: options.roomId,
|
|
134
|
-
data: toBase64(snapshot),
|
|
135
|
-
});
|
|
136
|
-
socket.send(payload);
|
|
137
|
-
}
|
|
138
|
-
catch (error) {
|
|
139
|
-
console.warn('Failed to send CRDT snapshot', error);
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
const scheduleReconnect = (doc) => {
|
|
143
|
-
if (stopped)
|
|
144
|
-
return;
|
|
145
|
-
if (reconnectTimer)
|
|
146
|
-
return;
|
|
147
|
-
if (connecting)
|
|
148
|
-
return;
|
|
149
|
-
if (attempt >= maxRetries) {
|
|
150
|
-
sendStatus('closed');
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
const delay = Math.min(maxDelay, initialDelay * 2 ** attempt);
|
|
154
|
-
attempt += 1;
|
|
155
|
-
reconnectTimer = setTimeout(() => {
|
|
156
|
-
reconnectTimer = undefined;
|
|
157
|
-
void connect(doc);
|
|
158
|
-
}, delay);
|
|
159
|
-
};
|
|
160
|
-
const connect = async (doc) => {
|
|
161
|
-
if (stopped)
|
|
162
|
-
return;
|
|
163
|
-
if (connecting)
|
|
164
|
-
return;
|
|
165
|
-
// Always ensure we are subscribed to the *current* doc.
|
|
166
|
-
ensureLocalSubscription(doc);
|
|
167
|
-
console.info('[crdt] connect start');
|
|
168
|
-
const attachSocketListenersFor = (ws) => {
|
|
169
|
-
// Ensure browser websockets deliver binary frames as ArrayBuffer (not Blob)
|
|
170
|
-
if ('binaryType' in ws) {
|
|
171
|
-
try {
|
|
172
|
-
ws.binaryType = 'arraybuffer';
|
|
173
|
-
}
|
|
174
|
-
catch (error) {
|
|
175
|
-
console.warn('Failed to set binaryType on CRDT websocket', error);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
const handleMessage = (event) => {
|
|
179
|
-
// Use the currently connected doc reference (not the doc that created the socket),
|
|
180
|
-
// so a later connect(doc) call can rebind without needing a new WebSocket.
|
|
181
|
-
const activeDoc = subscribedDoc ?? doc;
|
|
182
|
-
if (!activeDoc)
|
|
183
|
-
return;
|
|
184
|
-
// Binary updates flow directly
|
|
185
|
-
if (event.data instanceof ArrayBuffer ||
|
|
186
|
-
ArrayBuffer.isView(event.data)) {
|
|
187
|
-
const bytes = event.data instanceof ArrayBuffer
|
|
188
|
-
? new Uint8Array(event.data)
|
|
189
|
-
: new Uint8Array(event.data.buffer, event.data.byteOffset, event.data.byteLength);
|
|
190
|
-
activeDoc.import(bytes);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
if (typeof Blob !== 'undefined' && event.data instanceof Blob) {
|
|
194
|
-
void event.data
|
|
195
|
-
.arrayBuffer()
|
|
196
|
-
.then((buf) => activeDoc.import(new Uint8Array(buf)))
|
|
197
|
-
.catch((error) => console.warn('Failed to decode CRDT binary message', error));
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (typeof event.data === 'string') {
|
|
201
|
-
try {
|
|
202
|
-
const parsed = JSON.parse(event.data);
|
|
203
|
-
console.debug('[crdt] ws message', parsed?.type);
|
|
204
|
-
if (parsed?.type === 'crdt-joined') {
|
|
205
|
-
joined = true;
|
|
206
|
-
console.debug('[crdt] joined room, flushing', pending.length, 'pending');
|
|
207
|
-
// flush pending updates
|
|
208
|
-
while (pending.length) {
|
|
209
|
-
const update = pending.shift();
|
|
210
|
-
if (update && ws && ws.readyState === WS_OPEN) {
|
|
211
|
-
// Debug visibility for diagnosing silent sync issues.
|
|
212
|
-
console.debug('[crdt] sending pending update after join', update.byteLength, 'bytes');
|
|
213
|
-
ws.send(update);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
if (parsed?.type === 'crdt-snapshot' && parsed.data) {
|
|
219
|
-
const bytes = fromBase64(parsed.data);
|
|
220
|
-
activeDoc.import(bytes);
|
|
221
|
-
}
|
|
222
|
-
// Ignore other messages (errors, acks) for now
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
console.warn('Failed to parse CRDT message', error);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
const handleOpen = () => {
|
|
230
|
-
attempt = 0;
|
|
231
|
-
joined = false;
|
|
232
|
-
connecting = false;
|
|
233
|
-
sendStatus('open');
|
|
234
|
-
sendJoin();
|
|
235
|
-
if (options.sendSnapshotOnConnect) {
|
|
236
|
-
sendSnapshot(doc);
|
|
237
|
-
}
|
|
238
|
-
ensureLocalSubscription(doc);
|
|
239
|
-
};
|
|
240
|
-
const handleClose = (event) => {
|
|
241
|
-
console.warn('CRDT WS closed', {
|
|
242
|
-
code: event.code,
|
|
243
|
-
reason: event.reason,
|
|
244
|
-
pending: pending.length,
|
|
245
|
-
joined,
|
|
246
|
-
});
|
|
247
|
-
connecting = false;
|
|
248
|
-
sendStatus('closed');
|
|
249
|
-
unsubscribeLocal?.();
|
|
250
|
-
unsubscribeLocal = undefined;
|
|
251
|
-
localSubscribed = false;
|
|
252
|
-
subscribedDoc = undefined;
|
|
253
|
-
joined = false;
|
|
254
|
-
pending.length = 0;
|
|
255
|
-
detachSocketListeners?.();
|
|
256
|
-
detachSocketListeners = undefined;
|
|
257
|
-
listeningSocket = undefined;
|
|
258
|
-
scheduleReconnect(doc);
|
|
259
|
-
};
|
|
260
|
-
const handleError = (event) => {
|
|
261
|
-
console.warn('CRDT WS error', event);
|
|
262
|
-
connecting = false;
|
|
263
|
-
sendStatus('error');
|
|
264
|
-
joined = false;
|
|
265
|
-
unsubscribeLocal?.();
|
|
266
|
-
unsubscribeLocal = undefined;
|
|
267
|
-
localSubscribed = false;
|
|
268
|
-
subscribedDoc = undefined;
|
|
269
|
-
detachSocketListeners?.();
|
|
270
|
-
detachSocketListeners = undefined;
|
|
271
|
-
listeningSocket = undefined;
|
|
272
|
-
scheduleReconnect(doc);
|
|
273
|
-
};
|
|
274
|
-
// Some WebSocket implementations expose either addEventListener or on*
|
|
275
|
-
// handlers. Use one style only to avoid duplicate events.
|
|
276
|
-
if (typeof ws.addEventListener === 'function') {
|
|
277
|
-
ws.addEventListener('message', handleMessage);
|
|
278
|
-
ws.addEventListener('open', handleOpen);
|
|
279
|
-
ws.addEventListener('close', handleClose);
|
|
280
|
-
ws.addEventListener('error', handleError);
|
|
281
|
-
detachSocketListeners = () => {
|
|
282
|
-
try {
|
|
283
|
-
ws.removeEventListener('message', handleMessage);
|
|
284
|
-
ws.removeEventListener('open', handleOpen);
|
|
285
|
-
ws.removeEventListener('close', handleClose);
|
|
286
|
-
ws.removeEventListener('error', handleError);
|
|
287
|
-
}
|
|
288
|
-
catch (error) {
|
|
289
|
-
console.warn('[crdt] failed to detach socket listeners', error);
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
ws.onmessage = handleMessage;
|
|
295
|
-
ws.onopen = handleOpen;
|
|
296
|
-
ws.onclose = handleClose;
|
|
297
|
-
ws.onerror = handleError;
|
|
298
|
-
detachSocketListeners = () => {
|
|
299
|
-
try {
|
|
300
|
-
ws.onmessage = null;
|
|
301
|
-
ws.onopen = null;
|
|
302
|
-
ws.onclose = null;
|
|
303
|
-
ws.onerror = null;
|
|
304
|
-
}
|
|
305
|
-
catch (error) {
|
|
306
|
-
console.warn('[crdt] failed to clear socket handlers', error);
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
listeningSocket = ws;
|
|
311
|
-
// If we stay in CONNECTING too long, force a reconnect to avoid being stuck.
|
|
312
|
-
setTimeout(() => {
|
|
313
|
-
if (ws && ws.readyState === WS_CONNECTING && !joined) {
|
|
314
|
-
console.warn('[crdt] ws still connecting after timeout; retrying');
|
|
315
|
-
try {
|
|
316
|
-
ws.close();
|
|
317
|
-
}
|
|
318
|
-
catch (error) {
|
|
319
|
-
console.warn('[crdt] error closing stuck socket', error);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}, 3000);
|
|
323
|
-
};
|
|
324
|
-
if (socket &&
|
|
325
|
-
(socket.readyState === WS_OPEN || socket.readyState === WS_CONNECTING)) {
|
|
326
|
-
console.info('[crdt] reuse existing socket, readyState:', socket.readyState);
|
|
327
|
-
if (listeningSocket !== socket) {
|
|
328
|
-
console.warn('[crdt] existing socket had no listeners; attaching now');
|
|
329
|
-
attachSocketListenersFor(socket);
|
|
330
|
-
// If the socket is already open, we won't get an 'open' event, so act as if
|
|
331
|
-
// we just opened: (re)join and optionally send snapshot.
|
|
332
|
-
if (socket.readyState === WS_OPEN) {
|
|
333
|
-
attempt = 0;
|
|
334
|
-
joined = false;
|
|
335
|
-
sendStatus('open');
|
|
336
|
-
sendJoin();
|
|
337
|
-
if (options.sendSnapshotOnConnect)
|
|
338
|
-
sendSnapshot(doc);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
if (reconnectTimer) {
|
|
344
|
-
clearTimeout(reconnectTimer);
|
|
345
|
-
reconnectTimer = undefined;
|
|
346
|
-
}
|
|
347
|
-
connecting = true;
|
|
348
|
-
sendStatus('connecting');
|
|
349
|
-
const wsCreator = options.createSocket ??
|
|
350
|
-
((url, protocols) => new WebSocket(url, protocols));
|
|
351
|
-
const url = buildUrl();
|
|
352
|
-
try {
|
|
353
|
-
socket = wsCreator(url, options.protocols);
|
|
354
|
-
console.info('[crdt] ws created', url);
|
|
355
|
-
}
|
|
356
|
-
catch (error) {
|
|
357
|
-
connecting = false;
|
|
358
|
-
sendStatus('error');
|
|
359
|
-
scheduleReconnect(doc);
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
attachSocketListenersFor(socket);
|
|
363
|
-
};
|
|
364
|
-
const disconnect = async () => {
|
|
365
|
-
stopped = true;
|
|
366
|
-
if (reconnectTimer) {
|
|
367
|
-
clearTimeout(reconnectTimer);
|
|
368
|
-
reconnectTimer = undefined;
|
|
369
|
-
}
|
|
370
|
-
unsubscribeLocal?.();
|
|
371
|
-
unsubscribeLocal = undefined;
|
|
372
|
-
localSubscribed = false;
|
|
373
|
-
subscribedDoc = undefined;
|
|
374
|
-
detachSocketListeners?.();
|
|
375
|
-
detachSocketListeners = undefined;
|
|
376
|
-
listeningSocket = undefined;
|
|
377
|
-
if (socket) {
|
|
378
|
-
try {
|
|
379
|
-
socket.close();
|
|
380
|
-
}
|
|
381
|
-
catch (error) {
|
|
382
|
-
console.warn('Error closing CRDT websocket', error);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
socket = undefined;
|
|
386
|
-
sendStatus('closed');
|
|
387
|
-
};
|
|
388
|
-
return { connect, disconnect };
|
|
389
|
-
}
|
|
390
|
-
//# sourceMappingURL=webSocketConnector.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webSocketConnector.js","sourceRoot":"","sources":["../../src/sync/webSocketConnector.ts"],"names":[],"mappings":"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","sourcesContent":["import {LoroDoc} from 'loro-crdt';\nimport {CrdtSyncConnector} from '../createCrdtSlice';\n\ntype WebSocketLike = {\n readyState: number;\n send: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void;\n close: () => void;\n addEventListener: (type: string, listener: (...args: any[]) => void) => void;\n removeEventListener: (\n type: string,\n listener: (...args: any[]) => void,\n ) => void;\n};\n\nconst WS_OPEN = 1;\nconst WS_CONNECTING = 0;\n\nconst toBase64 = (bytes: Uint8Array) => {\n const buf = (globalThis as any).Buffer as\n | {from: (input: Uint8Array) => {toString: (enc: string) => string}}\n | undefined;\n if (buf) {\n return buf.from(bytes).toString('base64');\n }\n let binary = '';\n bytes.forEach((b) => {\n binary += String.fromCharCode(b);\n });\n return btoa(binary);\n};\n\nconst fromBase64 = (value: string) => {\n const buf = (globalThis as any).Buffer as\n | {from: (input: string, encoding: string) => Uint8Array}\n | undefined;\n if (buf) {\n return Uint8Array.from(buf.from(value, 'base64'));\n }\n const binary = atob(value);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);\n return out;\n};\n\nexport type WebSocketSyncOptions = {\n url: string;\n roomId: string;\n token?: string;\n params?: Record<string, string>;\n protocols?: string | string[];\n onStatus?: (status: 'connecting' | 'open' | 'closed' | 'error') => void;\n createSocket?: (url: string, protocols?: string | string[]) => WebSocketLike;\n sendSnapshotOnConnect?: boolean;\n maxRetries?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n};\n\n/**\n * Creates a CRDT sync connector that exchanges Loro updates over WebSocket.\n */\nexport function createWebSocketSyncConnector(\n options: WebSocketSyncOptions,\n): CrdtSyncConnector {\n let socket: WebSocketLike | undefined;\n let unsubscribeLocal: (() => void) | undefined;\n let subscribedDoc: LoroDoc | undefined;\n let attempt = 0;\n let stopped = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let joined = false;\n let connecting = false;\n const pending: Uint8Array[] = [];\n let localSubscribed = false;\n let listeningSocket: WebSocketLike | undefined;\n let detachSocketListeners: (() => void) | undefined;\n\n const maxRetries = options.maxRetries ?? Infinity;\n const initialDelay = options.initialDelayMs ?? 500;\n const maxDelay = options.maxDelayMs ?? 5000;\n\n const maybeSendUpdate = (update: Uint8Array) => {\n console.debug('[crdt] local update observed', update.byteLength, 'bytes', {\n joined,\n readyState: socket?.readyState,\n });\n if (!socket || socket.readyState !== WS_OPEN) {\n console.debug('[crdt] skip send: socket not open, buffering');\n pending.push(update);\n return;\n }\n if (!joined) {\n console.debug(\n '[crdt] buffering local update before join',\n update.byteLength,\n 'bytes',\n );\n pending.push(update);\n return;\n }\n console.debug('[crdt] sending local update', update.byteLength, 'bytes');\n socket.send(update);\n };\n\n const attachLocalSubscription = (doc: LoroDoc) => {\n try {\n const unsub = doc.subscribeLocalUpdates((update: Uint8Array) => {\n // Pass through to shared handler so we keep centralized buffering/sending logic.\n maybeSendUpdate(update);\n });\n unsubscribeLocal = () => {\n try {\n unsub();\n } catch (error) {\n console.warn('[crdt] failed to unsubscribe local updates', error);\n }\n };\n localSubscribed = true;\n console.debug('[crdt] attached local update subscription');\n } catch (error) {\n console.warn('[crdt] failed to attach local subscription', error);\n localSubscribed = false;\n unsubscribeLocal = undefined;\n }\n };\n\n /**\n * Ensures we are subscribed to local updates on the *current* doc.\n *\n * This matters because this connector can be reused across reconnects and\n * `connect(doc)` calls; we must not keep a stale subscription to a prior doc.\n */\n const ensureLocalSubscription = (doc: LoroDoc) => {\n if (subscribedDoc && subscribedDoc !== doc) {\n console.info('[crdt] switching local update subscription to new doc');\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n }\n if (!localSubscribed || !unsubscribeLocal || subscribedDoc !== doc) {\n attachLocalSubscription(doc);\n subscribedDoc = doc;\n }\n };\n\n const buildUrl = () => {\n const url = new URL(options.url);\n url.searchParams.set('roomId', options.roomId);\n if (options.token) url.searchParams.set('token', options.token);\n if (options.params) {\n Object.entries(options.params).forEach(([k, v]) =>\n url.searchParams.set(k, v),\n );\n }\n return url.toString();\n };\n\n const sendStatus = (status: 'connecting' | 'open' | 'closed' | 'error') => {\n console.info('[crdt] ws status ->', status);\n options.onStatus?.(status);\n };\n\n const sendJoin = () => {\n if (!socket || socket.readyState !== WS_OPEN) return;\n const payload = JSON.stringify({type: 'crdt-join', roomId: options.roomId});\n console.debug('[crdt] sending join', payload);\n socket.send(payload);\n };\n\n const sendSnapshot = (doc: LoroDoc) => {\n if (!socket || socket.readyState !== WS_OPEN) return;\n try {\n const snapshot = doc.export({mode: 'snapshot'});\n console.info(\n '[crdt] sending snapshot bytes',\n snapshot?.byteLength ?? snapshot?.length ?? 0,\n );\n const payload = JSON.stringify({\n type: 'crdt-snapshot',\n roomId: options.roomId,\n data: toBase64(snapshot),\n });\n socket.send(payload);\n } catch (error) {\n console.warn('Failed to send CRDT snapshot', error);\n }\n };\n\n const scheduleReconnect = (doc: LoroDoc) => {\n if (stopped) return;\n if (reconnectTimer) return;\n if (connecting) return;\n if (attempt >= maxRetries) {\n sendStatus('closed');\n return;\n }\n const delay = Math.min(maxDelay, initialDelay * 2 ** attempt);\n attempt += 1;\n reconnectTimer = setTimeout(() => {\n reconnectTimer = undefined;\n void connect(doc);\n }, delay);\n };\n\n const connect = async (doc: LoroDoc) => {\n if (stopped) return;\n if (connecting) return;\n // Always ensure we are subscribed to the *current* doc.\n ensureLocalSubscription(doc);\n console.info('[crdt] connect start');\n\n const attachSocketListenersFor = (ws: WebSocketLike) => {\n // Ensure browser websockets deliver binary frames as ArrayBuffer (not Blob)\n if ('binaryType' in ws) {\n try {\n (ws as any).binaryType = 'arraybuffer';\n } catch (error) {\n console.warn('Failed to set binaryType on CRDT websocket', error);\n }\n }\n\n const handleMessage = (event: any) => {\n // Use the currently connected doc reference (not the doc that created the socket),\n // so a later connect(doc) call can rebind without needing a new WebSocket.\n const activeDoc = subscribedDoc ?? doc;\n if (!activeDoc) return;\n // Binary updates flow directly\n if (\n event.data instanceof ArrayBuffer ||\n ArrayBuffer.isView(event.data)\n ) {\n const bytes =\n event.data instanceof ArrayBuffer\n ? new Uint8Array(event.data)\n : new Uint8Array(\n event.data.buffer,\n event.data.byteOffset,\n event.data.byteLength,\n );\n activeDoc.import(bytes);\n return;\n }\n if (typeof Blob !== 'undefined' && event.data instanceof Blob) {\n void event.data\n .arrayBuffer()\n .then((buf: ArrayBuffer) => activeDoc.import(new Uint8Array(buf)))\n .catch((error: unknown) =>\n console.warn('Failed to decode CRDT binary message', error),\n );\n return;\n }\n\n if (typeof event.data === 'string') {\n try {\n const parsed = JSON.parse(event.data);\n console.debug('[crdt] ws message', parsed?.type);\n if (parsed?.type === 'crdt-joined') {\n joined = true;\n console.debug(\n '[crdt] joined room, flushing',\n pending.length,\n 'pending',\n );\n // flush pending updates\n while (pending.length) {\n const update = pending.shift();\n if (update && ws && ws.readyState === WS_OPEN) {\n // Debug visibility for diagnosing silent sync issues.\n console.debug(\n '[crdt] sending pending update after join',\n update.byteLength,\n 'bytes',\n );\n ws.send(update);\n }\n }\n return;\n }\n if (parsed?.type === 'crdt-snapshot' && parsed.data) {\n const bytes = fromBase64(parsed.data);\n activeDoc.import(bytes);\n }\n // Ignore other messages (errors, acks) for now\n } catch (error) {\n console.warn('Failed to parse CRDT message', error);\n }\n }\n };\n\n const handleOpen = () => {\n attempt = 0;\n joined = false;\n connecting = false;\n sendStatus('open');\n sendJoin();\n if (options.sendSnapshotOnConnect) {\n sendSnapshot(doc);\n }\n ensureLocalSubscription(doc);\n };\n\n const handleClose = (event: CloseEvent) => {\n console.warn('CRDT WS closed', {\n code: event.code,\n reason: event.reason,\n pending: pending.length,\n joined,\n });\n connecting = false;\n sendStatus('closed');\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n joined = false;\n pending.length = 0;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n scheduleReconnect(doc);\n };\n\n const handleError = (event: Event) => {\n console.warn('CRDT WS error', event);\n connecting = false;\n sendStatus('error');\n joined = false;\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n scheduleReconnect(doc);\n };\n\n // Some WebSocket implementations expose either addEventListener or on*\n // handlers. Use one style only to avoid duplicate events.\n if (typeof ws.addEventListener === 'function') {\n ws.addEventListener('message', handleMessage);\n ws.addEventListener('open', handleOpen);\n ws.addEventListener('close', handleClose);\n ws.addEventListener('error', handleError);\n detachSocketListeners = () => {\n try {\n ws.removeEventListener('message', handleMessage);\n ws.removeEventListener('open', handleOpen);\n ws.removeEventListener('close', handleClose);\n ws.removeEventListener('error', handleError);\n } catch (error) {\n console.warn('[crdt] failed to detach socket listeners', error);\n }\n };\n } else {\n (ws as any).onmessage = handleMessage;\n (ws as any).onopen = handleOpen;\n (ws as any).onclose = handleClose;\n (ws as any).onerror = handleError;\n detachSocketListeners = () => {\n try {\n (ws as any).onmessage = null;\n (ws as any).onopen = null;\n (ws as any).onclose = null;\n (ws as any).onerror = null;\n } catch (error) {\n console.warn('[crdt] failed to clear socket handlers', error);\n }\n };\n }\n listeningSocket = ws;\n\n // If we stay in CONNECTING too long, force a reconnect to avoid being stuck.\n setTimeout(() => {\n if (ws && ws.readyState === WS_CONNECTING && !joined) {\n console.warn('[crdt] ws still connecting after timeout; retrying');\n try {\n ws.close();\n } catch (error) {\n console.warn('[crdt] error closing stuck socket', error);\n }\n }\n }, 3000);\n };\n\n if (\n socket &&\n (socket.readyState === WS_OPEN || socket.readyState === WS_CONNECTING)\n ) {\n console.info(\n '[crdt] reuse existing socket, readyState:',\n socket.readyState,\n );\n if (listeningSocket !== socket) {\n console.warn('[crdt] existing socket had no listeners; attaching now');\n attachSocketListenersFor(socket);\n // If the socket is already open, we won't get an 'open' event, so act as if\n // we just opened: (re)join and optionally send snapshot.\n if (socket.readyState === WS_OPEN) {\n attempt = 0;\n joined = false;\n sendStatus('open');\n sendJoin();\n if (options.sendSnapshotOnConnect) sendSnapshot(doc);\n }\n }\n return;\n }\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n connecting = true;\n sendStatus('connecting');\n const wsCreator =\n options.createSocket ??\n ((url, protocols) => new WebSocket(url, protocols));\n const url = buildUrl();\n try {\n socket = wsCreator(url, options.protocols);\n console.info('[crdt] ws created', url);\n } catch (error) {\n connecting = false;\n sendStatus('error');\n scheduleReconnect(doc);\n return;\n }\n attachSocketListenersFor(socket);\n };\n\n const disconnect = async () => {\n stopped = true;\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n unsubscribeLocal?.();\n unsubscribeLocal = undefined;\n localSubscribed = false;\n subscribedDoc = undefined;\n detachSocketListeners?.();\n detachSocketListeners = undefined;\n listeningSocket = undefined;\n if (socket) {\n try {\n socket.close();\n } catch (error) {\n console.warn('Error closing CRDT websocket', error);\n }\n }\n socket = undefined;\n sendStatus('closed');\n };\n\n return {connect, disconnect};\n}\n"]}
|
package/dist/types.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { SchemaType, InferType } from 'loro-mirror';
|
|
2
|
-
import { StateCreator } from 'zustand';
|
|
3
|
-
export type StoreSet<S> = Parameters<StateCreator<S>>[0];
|
|
4
|
-
export type StoreGet<S> = Parameters<StateCreator<S>>[1];
|
|
5
|
-
export type MirrorSchema<T extends SchemaType = SchemaType> = T;
|
|
6
|
-
/**
|
|
7
|
-
* `loro-mirror` injects internal `$cid` metadata into mirrored map objects.
|
|
8
|
-
*
|
|
9
|
-
* Store state typically doesn't include `$cid`, so binding `select()` functions
|
|
10
|
-
* naturally return the same shape *minus* `$cid`. This helper strips `$cid`
|
|
11
|
-
* recursively so `select()` can be type-safe without forcing `any` casts.
|
|
12
|
-
*/
|
|
13
|
-
export type StripCidDeep<T> = T extends (infer U)[] ? StripCidDeep<U>[] : T extends Record<string, any> ? T extends {
|
|
14
|
-
$cid: any;
|
|
15
|
-
} ? Omit<{
|
|
16
|
-
[K in keyof T]: StripCidDeep<T[K]>;
|
|
17
|
-
}, '$cid'> : {
|
|
18
|
-
[K in keyof T]: StripCidDeep<T[K]>;
|
|
19
|
-
} : T;
|
|
20
|
-
export type InferredState<TSchema extends SchemaType> = InferType<TSchema> extends Record<string, any> ? InferType<TSchema> : Record<string, never>;
|
|
21
|
-
/**
|
|
22
|
-
* Local equivalent of `createSlice` from `@sqlrooms/room-store`.
|
|
23
|
-
*
|
|
24
|
-
* Kept inline so `@sqlrooms/crdt` stays dependency-light (no need to depend on
|
|
25
|
-
* `@sqlrooms/room-store` just for a typing helper).
|
|
26
|
-
*/
|
|
27
|
-
export declare function createSlice<SliceState, StoreState extends SliceState = SliceState>(sliceCreator: (...args: Parameters<StateCreator<StoreState>>) => SliceState): StateCreator<SliceState>;
|
|
28
|
-
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,aAAa,CAAC;AAClD,OAAO,EAAC,YAAY,EAAW,MAAM,SAAS,CAAC;AAE/C,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzD,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,IAAI,CAAC,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAC/C,YAAY,CAAC,CAAC,CAAC,EAAE,GACjB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC3B,CAAC,SAAS;IAAC,IAAI,EAAE,GAAG,CAAA;CAAC,GACnB,IAAI,CAAC;KAAE,CAAC,IAAI,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAC,EAAE,MAAM,CAAC,GAClD;KAAE,CAAC,IAAI,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAC,GACtC,CAAC,CAAC;AAER,MAAM,MAAM,aAAa,CAAC,OAAO,SAAS,UAAU,IAClD,SAAS,CAAC,OAAO,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1C,SAAS,CAAC,OAAO,CAAC,GAClB,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE5B;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,UAAU,EACV,UAAU,SAAS,UAAU,GAAG,UAAU,EAE1C,YAAY,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,KAAK,UAAU,GAC1E,YAAY,CAAC,UAAU,CAAC,CAG1B"}
|
package/dist/types.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Local equivalent of `createSlice` from `@sqlrooms/room-store`.
|
|
3
|
-
*
|
|
4
|
-
* Kept inline so `@sqlrooms/crdt` stays dependency-light (no need to depend on
|
|
5
|
-
* `@sqlrooms/room-store` just for a typing helper).
|
|
6
|
-
*/
|
|
7
|
-
export function createSlice(sliceCreator) {
|
|
8
|
-
return (set, get, store) => sliceCreator(set, get, store);
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA4BA;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAIzB,YAA2E;IAE3E,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CACzB,YAAY,CAAC,GAAG,EAAE,GAAuB,EAAE,KAA6B,CAAC,CAAC;AAC9E,CAAC","sourcesContent":["import {SchemaType, InferType} from 'loro-mirror';\nimport {StateCreator, StoreApi} from 'zustand';\n\nexport type StoreSet<S> = Parameters<StateCreator<S>>[0];\nexport type StoreGet<S> = Parameters<StateCreator<S>>[1];\n\nexport type MirrorSchema<T extends SchemaType = SchemaType> = T;\n\n/**\n * `loro-mirror` injects internal `$cid` metadata into mirrored map objects.\n *\n * Store state typically doesn't include `$cid`, so binding `select()` functions\n * naturally return the same shape *minus* `$cid`. This helper strips `$cid`\n * recursively so `select()` can be type-safe without forcing `any` casts.\n */\nexport type StripCidDeep<T> = T extends (infer U)[]\n ? StripCidDeep<U>[]\n : T extends Record<string, any>\n ? T extends {$cid: any}\n ? Omit<{[K in keyof T]: StripCidDeep<T[K]>}, '$cid'>\n : {[K in keyof T]: StripCidDeep<T[K]>}\n : T;\n\nexport type InferredState<TSchema extends SchemaType> =\n InferType<TSchema> extends Record<string, any>\n ? InferType<TSchema>\n : Record<string, never>;\n\n/**\n * Local equivalent of `createSlice` from `@sqlrooms/room-store`.\n *\n * Kept inline so `@sqlrooms/crdt` stays dependency-light (no need to depend on\n * `@sqlrooms/room-store` just for a typing helper).\n */\nexport function createSlice<\n SliceState,\n StoreState extends SliceState = SliceState,\n>(\n sliceCreator: (...args: Parameters<StateCreator<StoreState>>) => SliceState,\n): StateCreator<SliceState> {\n return (set, get, store) =>\n sliceCreator(set, get as () => StoreState, store as StoreApi<StoreState>);\n}\n"]}
|