@absolutejs/sync 1.15.0 → 1.16.0
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/adapters/tanstack-db/index.js +45 -5
- package/dist/adapters/tanstack-db/index.js.map +5 -4
- package/dist/angular/index.js +45 -5
- package/dist/angular/index.js.map +5 -4
- package/dist/client/index.js +75 -17
- package/dist/client/index.js.map +8 -7
- package/dist/client/presence.d.ts +6 -0
- package/dist/client/syncClient.d.ts +8 -0
- package/dist/client/syncCollection.d.ts +6 -0
- package/dist/client/syncStore.d.ts +6 -0
- package/dist/engine/connection.d.ts +46 -3
- package/dist/engine/index.js +103 -21
- package/dist/engine/index.js.map +6 -5
- package/dist/engine/socket.d.ts +61 -7
- package/dist/engine/syncEngine.d.ts +30 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +165 -33
- package/dist/index.js.map +7 -6
- package/dist/react/index.js +45 -5
- package/dist/react/index.js.map +5 -4
- package/dist/serializer.d.ts +36 -0
- package/dist/svelte/index.js +45 -5
- package/dist/svelte/index.js.map +5 -4
- package/dist/testing.js +47 -11
- package/dist/testing.js.map +3 -3
- package/dist/vue/index.js +45 -5
- package/dist/vue/index.js.map +5 -4
- package/package.json +1 -1
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/crdt/orSet.ts", "../src/crdt/lwwMap.ts", "../src/crdt/list.ts", "../src/crdt/index.ts", "../src/angular/sync-collection.service.ts", "../src/client/syncCollection.ts", "../src/client/collaborativeText.ts"],
|
|
3
|
+
"sources": ["../src/crdt/orSet.ts", "../src/crdt/lwwMap.ts", "../src/crdt/list.ts", "../src/crdt/index.ts", "../src/angular/sync-collection.service.ts", "../src/serializer.ts", "../src/client/syncCollection.ts", "../src/client/collaborativeText.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * An observed-remove set (OR-Set) — a CRDT set where concurrent add/remove of an\n * element resolves **add-wins**: each `add` tags the element with a unique tag,\n * and `remove` only retracts the tags it has observed, so a concurrent add (a new\n * tag) survives. State-based: `merge` is union of tags minus removed tags.\n */\n\nconst newTag = (): string => globalThis.crypto.randomUUID();\nconst defaultEquals = <T>(a: T, b: T): boolean => Object.is(a, b);\n\nexport type OrSetState<T> = {\n\t/** Each add: the value plus the unique tag that observed it. */\n\tadds: { value: T; tag: string }[];\n\t/** Tags retracted by `remove`. */\n\tremoved: string[];\n};\n\nexport const orSet = {\n\tcreate: <T>(): OrSetState<T> => ({ adds: [], removed: [] }),\n\n\tadd: <T>(\n\t\tstate: OrSetState<T>,\n\t\tvalue: T,\n\t\ttag = newTag()\n\t): OrSetState<T> => ({\n\t\tadds: [...state.adds, { value, tag }],\n\t\tremoved: state.removed\n\t}),\n\n\t/** Retract every tag currently observed for `value` (add-wins on re-add). */\n\tremove: <T>(\n\t\tstate: OrSetState<T>,\n\t\tvalue: T,\n\t\tequals: (a: T, b: T) => boolean = defaultEquals\n\t): OrSetState<T> => {\n\t\tconst tags = state.adds\n\t\t\t.filter((entry) => equals(entry.value, value))\n\t\t\t.map((entry) => entry.tag);\n\n\t\treturn {\n\t\t\tadds: state.adds,\n\t\t\tremoved: [...new Set([...state.removed, ...tags])]\n\t\t};\n\t},\n\n\thas: <T>(\n\t\tstate: OrSetState<T>,\n\t\tvalue: T,\n\t\tequals: (a: T, b: T) => boolean = defaultEquals\n\t): boolean => {\n\t\tconst removed = new Set(state.removed);\n\n\t\treturn state.adds.some(\n\t\t\t(entry) => equals(entry.value, value) && !removed.has(entry.tag)\n\t\t);\n\t},\n\n\t/** The live, de-duplicated members. */\n\tvalues: <T>(\n\t\tstate: OrSetState<T>,\n\t\tequals: (a: T, b: T) => boolean = defaultEquals\n\t): T[] => {\n\t\tconst removed = new Set(state.removed);\n\t\tconst out: T[] = [];\n\t\tfor (const entry of state.adds) {\n\t\t\tif (\n\t\t\t\t!removed.has(entry.tag) &&\n\t\t\t\t!out.some((value) => equals(value, entry.value))\n\t\t\t) {\n\t\t\t\tout.push(entry.value);\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t},\n\n\t/** Union the observed tags and the removed tags (commutative/idempotent). */\n\tmerge: <T>(a: OrSetState<T>, b: OrSetState<T>): OrSetState<T> => {\n\t\tconst byTag = new Map<string, { value: T; tag: string }>();\n\t\tfor (const entry of [...a.adds, ...b.adds]) {\n\t\t\tbyTag.set(entry.tag, entry);\n\t\t}\n\n\t\treturn {\n\t\t\tadds: [...byTag.values()],\n\t\t\tremoved: [...new Set([...a.removed, ...b.removed])]\n\t\t};\n\t}\n};\n",
|
|
6
6
|
"/**\n * A last-write-wins map (LWW-Map) — a CRDT key→value map. Each key is an\n * independent LWW register: the write (set or delete) with the highest timestamp\n * wins, ties broken by replica id. `delete` is a tombstone so it can lose to a\n * later concurrent `set`. State-based: `merge` is per-key LWW.\n */\n\nexport type LwwMapEntry<V> = {\n\tvalue?: V;\n\tdeleted: boolean;\n\ttimestamp: number;\n\treplica: string;\n};\n\nexport type LwwMapState<V> = Record<string, LwwMapEntry<V>>;\n\nconst pick = <V>(a: LwwMapEntry<V>, b: LwwMapEntry<V>): LwwMapEntry<V> => {\n\tif (b.timestamp > a.timestamp) {\n\t\treturn b;\n\t}\n\tif (b.timestamp < a.timestamp) {\n\t\treturn a;\n\t}\n\treturn b.replica > a.replica ? b : a;\n};\n\nexport const lwwMap = {\n\tcreate: <V>(): LwwMapState<V> => ({}),\n\n\tset: <V>(\n\t\tstate: LwwMapState<V>,\n\t\tkey: string,\n\t\tvalue: V,\n\t\treplica: string,\n\t\ttimestamp = Date.now()\n\t): LwwMapState<V> => ({\n\t\t...state,\n\t\t[key]: { value, deleted: false, timestamp, replica }\n\t}),\n\n\tdelete: <V>(\n\t\tstate: LwwMapState<V>,\n\t\tkey: string,\n\t\treplica: string,\n\t\ttimestamp = Date.now()\n\t): LwwMapState<V> => ({\n\t\t...state,\n\t\t[key]: { value: state[key]?.value, deleted: true, timestamp, replica }\n\t}),\n\n\tget: <V>(state: LwwMapState<V>, key: string): V | undefined => {\n\t\tconst entry = state[key];\n\n\t\treturn entry !== undefined && !entry.deleted ? entry.value : undefined;\n\t},\n\n\thas: <V>(state: LwwMapState<V>, key: string): boolean => {\n\t\tconst entry = state[key];\n\n\t\treturn entry !== undefined && !entry.deleted;\n\t},\n\n\tkeys: <V>(state: LwwMapState<V>): string[] =>\n\t\tObject.keys(state).filter((key) => !state[key]?.deleted),\n\n\tentries: <V>(state: LwwMapState<V>): [string, V][] => {\n\t\tconst out: [string, V][] = [];\n\t\tfor (const [key, entry] of Object.entries(state)) {\n\t\t\tif (!entry.deleted && entry.value !== undefined) {\n\t\t\t\tout.push([key, entry.value]);\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t},\n\n\t/** Per-key last-write-wins (commutative/idempotent). */\n\tmerge: <V>(a: LwwMapState<V>, b: LwwMapState<V>): LwwMapState<V> => {\n\t\tconst out: LwwMapState<V> = { ...a };\n\t\tfor (const [key, entry] of Object.entries(b)) {\n\t\t\tconst existing = out[key];\n\t\t\tout[key] = existing === undefined ? entry : pick(existing, entry);\n\t\t}\n\n\t\treturn out;\n\t}\n};\n",
|
|
7
7
|
"/**\n * An ordered list CRDT — the same RGA sequence type as the collaborative text,\n * but over arbitrary items instead of characters. Concurrent inserts and deletes\n * at any position merge without conflict and converge. State-based, with delta\n * support (`takeDelta`) so a client uploads only its new ops.\n */\n\nexport type ListElement<T> = {\n\tid: string;\n\treplica: string;\n\tclock: number;\n\tafter: string | null;\n\tvalue: T;\n\tdeleted: boolean;\n};\n\nexport type ListState<T> = { elements: ListElement<T>[] };\n\nconst order = <T>(a: ListElement<T>, b: ListElement<T>) => {\n\tif (a.clock !== b.clock) {\n\t\treturn b.clock - a.clock;\n\t}\n\tif (a.replica === b.replica) {\n\t\treturn 0;\n\t}\n\treturn a.replica > b.replica ? -1 : 1;\n};\n\nconst linearize = <T>(elements: ListElement<T>[]): ListElement<T>[] => {\n\tconst present = new Set(elements.map((element) => element.id));\n\tconst children = new Map<string | null, ListElement<T>[]>();\n\tfor (const element of elements) {\n\t\tconst anchor =\n\t\t\telement.after !== null && !present.has(element.after)\n\t\t\t\t? null\n\t\t\t\t: element.after;\n\t\tconst list = children.get(anchor);\n\t\tif (list === undefined) {\n\t\t\tchildren.set(anchor, [element]);\n\t\t} else {\n\t\t\tlist.push(element);\n\t\t}\n\t}\n\tfor (const list of children.values()) {\n\t\tlist.sort(order);\n\t}\n\tconst ordered: ListElement<T>[] = [];\n\tconst stack = [...(children.get(null) ?? [])].reverse();\n\twhile (stack.length > 0) {\n\t\tconst element = stack.pop()!;\n\t\tordered.push(element);\n\t\tconst kids = children.get(element.id);\n\t\tif (kids !== undefined) {\n\t\t\tfor (let index = kids.length - 1; index >= 0; index -= 1) {\n\t\t\t\tstack.push(kids[index]!);\n\t\t\t}\n\t\t}\n\t}\n\treturn ordered;\n};\n\n/** The visible items of a list-CRDT state. Pure. */\nexport const listOf = <T>(state: ListState<T>): T[] =>\n\tlinearize(state.elements)\n\t\t.filter((element) => !element.deleted)\n\t\t.map((element) => element.value);\n\n/** Merge two list-CRDT states (commutative/idempotent). Pure. */\nexport const mergeListState = <T>(\n\ta: ListState<T>,\n\tb: ListState<T>\n): ListState<T> => {\n\tconst byId = new Map<string, ListElement<T>>();\n\tfor (const element of [...a.elements, ...b.elements]) {\n\t\tconst existing = byId.get(element.id);\n\t\tbyId.set(\n\t\t\telement.id,\n\t\t\texisting === undefined\n\t\t\t\t? element\n\t\t\t\t: { ...existing, deleted: existing.deleted || element.deleted }\n\t\t);\n\t}\n\treturn { elements: [...byId.values()] };\n};\n\nexport type ListCrdt<T> = {\n\t/** The current visible items. */\n\tlist: () => T[];\n\t/** Insert `items` at visible `index`. */\n\tinsert: (index: number, items: T[]) => void;\n\t/** Tombstone `count` visible items from `index`. */\n\tdelete: (index: number, count: number) => void;\n\t/** Merge another replica's state in. */\n\tmerge: (state: ListState<T>) => void;\n\t/** The full serializable state (for hydration). */\n\tstate: () => ListState<T>;\n\t/** The locally-authored ops since the last call, then clears the buffer. */\n\ttakeDelta: () => ListState<T>;\n};\n\n/** Create a live ordered-list CRDT for `replica`. */\nexport const createList = <T>(\n\treplica: string,\n\tinitial?: ListState<T>\n): ListCrdt<T> => {\n\tconst elements = new Map<string, ListElement<T>>();\n\tconst pending = new Map<string, ListElement<T>>();\n\tlet clock = 0;\n\tif (initial !== undefined) {\n\t\tfor (const element of initial.elements) {\n\t\t\telements.set(element.id, element);\n\t\t\tclock = Math.max(clock, element.clock);\n\t\t}\n\t}\n\n\tconst visible = () =>\n\t\tlinearize([...elements.values()]).filter((element) => !element.deleted);\n\n\treturn {\n\t\tlist: () => listOf({ elements: [...elements.values()] }),\n\t\tinsert: (index, items) => {\n\t\t\tconst seen = visible();\n\t\t\tlet after = index <= 0 ? null : (seen[index - 1]?.id ?? null);\n\t\t\tfor (const value of items) {\n\t\t\t\tclock += 1;\n\t\t\t\tconst element: ListElement<T> = {\n\t\t\t\t\tid: `${replica}:${clock}`,\n\t\t\t\t\treplica,\n\t\t\t\t\tclock,\n\t\t\t\t\tafter,\n\t\t\t\t\tvalue,\n\t\t\t\t\tdeleted: false\n\t\t\t\t};\n\t\t\t\telements.set(element.id, element);\n\t\t\t\tpending.set(element.id, element);\n\t\t\t\tafter = element.id;\n\t\t\t}\n\t\t},\n\t\tdelete: (index, count) => {\n\t\t\tconst seen = visible();\n\t\t\tfor (let offset = 0; offset < count; offset += 1) {\n\t\t\t\tconst target = seen[index + offset];\n\t\t\t\tif (target !== undefined) {\n\t\t\t\t\tconst tombstoned = { ...target, deleted: true };\n\t\t\t\t\telements.set(target.id, tombstoned);\n\t\t\t\t\tpending.set(target.id, tombstoned);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tmerge: (state) => {\n\t\t\tfor (const element of state.elements) {\n\t\t\t\tconst existing = elements.get(element.id);\n\t\t\t\telements.set(\n\t\t\t\t\telement.id,\n\t\t\t\t\texisting === undefined\n\t\t\t\t\t\t? element\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t...existing,\n\t\t\t\t\t\t\t\tdeleted: existing.deleted || element.deleted\n\t\t\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tclock = Math.max(clock, element.clock);\n\t\t\t}\n\t\t},\n\t\tstate: () => ({ elements: [...elements.values()] }),\n\t\ttakeDelta: () => {\n\t\t\tconst delta = { elements: [...pending.values()] };\n\t\t\tpending.clear();\n\n\t\t\treturn delta;\n\t\t}\n\t};\n};\n",
|
|
8
8
|
"/**\n * Conflict-free replicated data types (CRDTs) for multiplayer/offline editing —\n * pure, dependency-free, and isomorphic (use the same code client and server).\n *\n * These are *state-based* CRDTs (CvRDTs): every `merge` is commutative,\n * associative, and idempotent, so replicas that exchange state in any order\n * converge to the same value. That fits the sync engine without engine changes:\n * store the CRDT state as a row field, have a mutation `merge` the incoming\n * state into the stored one (concurrent writes combine instead of clobbering),\n * and have each client merge the broadcast state into its local edits.\n */\n\nexport { orSet } from './orSet';\nexport type { OrSetState } from './orSet';\nexport { lwwMap } from './lwwMap';\nexport type { LwwMapEntry, LwwMapState } from './lwwMap';\nexport { createList, listOf, mergeListState } from './list';\nexport type { ListCrdt, ListElement, ListState } from './list';\n\nconst sumValues = (counts: Record<string, number>) =>\n\tObject.values(counts).reduce((total, value) => total + value, 0);\n\nconst mergeMax = (\n\ta: Record<string, number>,\n\tb: Record<string, number>\n): Record<string, number> => {\n\tconst merged: Record<string, number> = { ...a };\n\tfor (const [replica, value] of Object.entries(b)) {\n\t\tmerged[replica] = Math.max(merged[replica] ?? 0, value);\n\t}\n\treturn merged;\n};\n\n/* ─── PN-counter ─── */\n\n/** A counter that survives concurrent increments/decrements across replicas. */\nexport type CounterState = {\n\tincrements: Record<string, number>;\n\tdecrements: Record<string, number>;\n};\n\nexport const counter = {\n\tcreate: (): CounterState => ({ increments: {}, decrements: {} }),\n\t/** Current value: total increments minus total decrements. */\n\tvalue: (state: CounterState) =>\n\t\tsumValues(state.increments) - sumValues(state.decrements),\n\tincrement: (\n\t\tstate: CounterState,\n\t\treplica: string,\n\t\tby = 1\n\t): CounterState => ({\n\t\tincrements: {\n\t\t\t...state.increments,\n\t\t\t[replica]: (state.increments[replica] ?? 0) + by\n\t\t},\n\t\tdecrements: state.decrements\n\t}),\n\tdecrement: (\n\t\tstate: CounterState,\n\t\treplica: string,\n\t\tby = 1\n\t): CounterState => ({\n\t\tincrements: state.increments,\n\t\tdecrements: {\n\t\t\t...state.decrements,\n\t\t\t[replica]: (state.decrements[replica] ?? 0) + by\n\t\t}\n\t}),\n\t/** Merge by taking the max count seen per replica (monotonic). */\n\tmerge: (a: CounterState, b: CounterState): CounterState => ({\n\t\tincrements: mergeMax(a.increments, b.increments),\n\t\tdecrements: mergeMax(a.decrements, b.decrements)\n\t})\n};\n\n/* ─── LWW register ─── */\n\n/** A single value where the latest write wins (ties broken by replica id). */\nexport type LwwState<T> = { value: T; timestamp: number; replica: string };\n\nexport const lww = {\n\tcreate: <T>(\n\t\tvalue: T,\n\t\treplica: string,\n\t\ttimestamp = Date.now()\n\t): LwwState<T> => ({ value, timestamp, replica }),\n\tset: <T>(\n\t\tvalue: T,\n\t\treplica: string,\n\t\ttimestamp = Date.now()\n\t): LwwState<T> => ({\n\t\tvalue,\n\t\ttimestamp,\n\t\treplica\n\t}),\n\t/** Keep the entry with the higher timestamp (replica id breaks ties). */\n\tmerge: <T>(a: LwwState<T>, b: LwwState<T>): LwwState<T> => {\n\t\tif (b.timestamp > a.timestamp) {\n\t\t\treturn b;\n\t\t}\n\t\tif (b.timestamp < a.timestamp) {\n\t\t\treturn a;\n\t\t}\n\t\treturn b.replica > a.replica ? b : a;\n\t}\n};\n\n/* ─── Collaborative text ─── */\n\n/**\n * The contract a collaborative-text CRDT exposes, independent of the algorithm\n * behind it. Implemented first-party by the RGA below ({@link createTextCrdt})\n * and by third-party backends in the `sync-adapters` repo (e.g.\n * `@absolutejs/sync-yjs`). `State` is whatever that backend persists and\n * broadcasts — JSON ({@link TextState}) for the RGA, a base64 update for Yjs.\n */\nexport type CrdtText<State> = {\n\t/** The current visible text. */\n\ttext: () => string;\n\t/** Reconcile the local text to `next` (the backend computes the edit). */\n\tsetText: (next: string) => void;\n\t/** Merge another replica's state in (e.g. a broadcast from the server). */\n\tmerge: (state: State) => void;\n\t/** The full serializable state to persist/broadcast (for hydration). */\n\tstate: () => State;\n\t/**\n\t * The locally-authored changes since the last call (a delta-state), then clears\n\t * the buffer. A delta merges exactly like a full state (union), so a client can\n\t * upload just its new ops — O(edit) instead of O(doc) — while the server keeps\n\t * full state. Optional: backends without delta support fall back to `state()`.\n\t */\n\ttakeDelta?: () => State;\n\t/**\n\t * The stable anchor for a caret at visible `index` — the id of the element the\n\t * caret sits after (`null` = document start). Broadcast this instead of a raw\n\t * index so a caret survives concurrent edits. Optional (text backends provide it).\n\t */\n\tanchorAt?: (index: number) => string | null;\n\t/** The current visible index of a caret anchored after `anchor` (see {@link anchorAt}). */\n\tindexOfAnchor?: (anchor: string | null) => number;\n};\n\n/**\n * The minimal server-side surface the engine needs to auto-merge a CRDT field on\n * write (see `engine.registerCrdt`): combine two states and produce an empty one.\n * Both the first-party {@link rgaText} and `@absolutejs/sync-yjs`'s `yjsText`\n * satisfy it, as does any {@link TextCrdtAdapter}.\n */\nexport type CrdtMergeable<State> = {\n\tempty: () => State;\n\tmerge: (a: State, b: State) => State;\n};\n\n/**\n * A pluggable collaborative-text backend. `create` mints a live doc for a\n * replica; `merge` combines two persisted states server-side (no live instance\n * needed — for the merge-on-write mutation); `empty`/`textOf` are conveniences.\n * Swap the first-party {@link rgaText} for an adapter to get a different engine\n * (e.g. Yjs) behind the exact same call sites.\n */\nexport type TextCrdtAdapter<State> = CrdtMergeable<State> & {\n\tcreate: (replica: string, initial?: State) => CrdtText<State>;\n\ttextOf: (state: State) => string;\n\t/** Optionally bound state growth (e.g. drop unreferenced tombstones). */\n\tcompact?: (state: State) => State;\n};\n\n/* ─── Collaborative text (RGA) — the first-party backend ─── */\n\n/** One inserted character in the replicated sequence (kept as a tombstone if deleted). */\nexport type TextElement = {\n\tid: string;\n\treplica: string;\n\tclock: number;\n\t/** Id of the element this was inserted after (`null` = start of document). */\n\tafter: string | null;\n\tvalue: string;\n\tdeleted: boolean;\n};\n\n/** Serializable state of a {@link TextCrdt} — safe to store as a row field. */\nexport type TextState = { elements: TextElement[] };\n\n// Sibling order (same `after`): higher clock first, then higher replica id.\nconst compare = (a: TextElement, b: TextElement) => {\n\tif (a.clock !== b.clock) {\n\t\treturn b.clock - a.clock;\n\t}\n\tif (a.replica === b.replica) {\n\t\treturn 0;\n\t}\n\treturn a.replica > b.replica ? -1 : 1;\n};\n\n/** Flatten the sequence into document order (an iterative RGA pre-order walk). */\nconst linearize = (elements: TextElement[]): TextElement[] => {\n\tconst present = new Set(elements.map((element) => element.id));\n\tconst children = new Map<string | null, TextElement[]>();\n\tfor (const element of elements) {\n\t\t// An element whose anchor was compacted/GC'd away (or never seen) is an\n\t\t// orphan — re-root it deterministically instead of dropping its content.\n\t\tconst anchor =\n\t\t\telement.after !== null && !present.has(element.after)\n\t\t\t\t? null\n\t\t\t\t: element.after;\n\t\tconst list = children.get(anchor);\n\t\tif (list === undefined) {\n\t\t\tchildren.set(anchor, [element]);\n\t\t} else {\n\t\t\tlist.push(element);\n\t\t}\n\t}\n\tfor (const list of children.values()) {\n\t\tlist.sort(compare);\n\t}\n\tconst ordered: TextElement[] = [];\n\tconst stack = [...(children.get(null) ?? [])].reverse();\n\twhile (stack.length > 0) {\n\t\tconst element = stack.pop()!;\n\t\tordered.push(element);\n\t\tconst kids = children.get(element.id);\n\t\tif (kids !== undefined) {\n\t\t\tfor (let index = kids.length - 1; index >= 0; index -= 1) {\n\t\t\t\tstack.push(kids[index]!);\n\t\t\t}\n\t\t}\n\t}\n\treturn ordered;\n};\n\n/** The visible string of a text-CRDT state. Pure — use it server-side too. */\nexport const textOf = (state: TextState): string =>\n\tlinearize(state.elements)\n\t\t.filter((element) => !element.deleted)\n\t\t.map((element) => element.value)\n\t\t.join('');\n\n/** Merge two text-CRDT states (commutative/idempotent). Pure — for server mutations. */\nexport const mergeTextState = (a: TextState, b: TextState): TextState => {\n\tconst byId = new Map<string, TextElement>();\n\tfor (const element of [...a.elements, ...b.elements]) {\n\t\tconst existing = byId.get(element.id);\n\t\tbyId.set(\n\t\t\telement.id,\n\t\t\texisting === undefined\n\t\t\t\t? element\n\t\t\t\t: { ...existing, deleted: existing.deleted || element.deleted }\n\t\t);\n\t}\n\treturn { elements: [...byId.values()] };\n};\n\n/** How many tombstones (deleted-but-retained elements) a state carries. Use it\n * to decide when to {@link compact} (e.g. a server-side threshold). */\nexport const tombstoneCount = (state: TextState): number =>\n\tstate.elements.reduce(\n\t\t(total, element) => (element.deleted ? total + 1 : total),\n\t\t0\n\t);\n\n/**\n * Drop tombstones that no remaining element anchors to (`after`), bounding state\n * growth from deletions — the visible text is unchanged. Pure.\n *\n * Future inserts only ever anchor to *visible* elements, so a tombstone nothing\n * currently references will never be referenced again; removing it is safe for\n * the canonical (server-held) state. Run it server-side on the stored state\n * (e.g. once `tombstoneCount` crosses a threshold); clients adopt the compacted\n * state on the next broadcast. {@link textOf}/{@link mergeTextState} and the\n * linearizer tolerate a stale client that briefly references a compacted\n * tombstone (its insert is re-rooted deterministically, not lost).\n */\nexport const compact = (state: TextState): TextState => {\n\tconst byId = new Map(\n\t\tstate.elements.map((element) => [element.id, element])\n\t);\n\t// Keep a tombstone only if it lies on the `after`-chain from a live element\n\t// (so positions are preserved); a deleted run that nothing live anchors\n\t// through is dropped. Walk each live element's chain of tombstone anchors.\n\tconst keep = new Set<string>();\n\tfor (const element of state.elements) {\n\t\tif (element.deleted) {\n\t\t\tcontinue;\n\t\t}\n\t\tlet anchor = element.after;\n\t\twhile (anchor !== null && !keep.has(anchor)) {\n\t\t\tconst target = byId.get(anchor);\n\t\t\tif (target === undefined || !target.deleted) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tkeep.add(anchor);\n\t\t\tanchor = target.after;\n\t\t}\n\t}\n\treturn {\n\t\telements: state.elements.filter(\n\t\t\t(element) => !element.deleted || keep.has(element.id)\n\t\t)\n\t};\n};\n\n/** The RGA text CRDT — {@link CrdtText} plus direct positional edits. */\nexport type TextCrdt = CrdtText<TextState> & {\n\t/** Insert `value` at visible `index`. */\n\tinsert: (index: number, value: string) => void;\n\t/** Tombstone `count` visible characters from `index`. */\n\tdelete: (index: number, count: number) => void;\n\t/** Locally-authored changes since the last call, then clears the buffer. */\n\ttakeDelta: () => TextState;\n\t/** The stable element-id anchor for a caret at visible `index`. */\n\tanchorAt: (index: number) => string | null;\n\t/** The current visible index of a caret anchored after `anchor`. */\n\tindexOfAnchor: (anchor: string | null) => number;\n};\n\n/**\n * A collaborative text buffer backed by an RGA sequence CRDT. Concurrent inserts\n * and deletes from different replicas merge without conflict and converge. Drive\n * it from an input via {@link TextCrdt.setText}; persist/broadcast\n * {@link TextCrdt.state}; apply remote state via {@link TextCrdt.merge}.\n */\nexport const createTextCrdt = (\n\treplica: string,\n\tinitial?: TextState\n): TextCrdt => {\n\tconst elements = new Map<string, TextElement>();\n\t// Elements this replica created or tombstoned since the last takeDelta — the\n\t// delta to broadcast. Local edits add here; `merge` (remote) deliberately\n\t// does not, so a client only ever re-broadcasts its own ops.\n\tconst pending = new Map<string, TextElement>();\n\tlet clock = 0;\n\tif (initial !== undefined) {\n\t\tfor (const element of initial.elements) {\n\t\t\telements.set(element.id, element);\n\t\t\tclock = Math.max(clock, element.clock);\n\t\t}\n\t}\n\n\tconst visible = () =>\n\t\tlinearize([...elements.values()]).filter((element) => !element.deleted);\n\n\tconst insert = (index: number, value: string) => {\n\t\tconst seen = visible();\n\t\tlet after = index <= 0 ? null : (seen[index - 1]?.id ?? null);\n\t\tfor (const char of [...value]) {\n\t\t\tclock += 1;\n\t\t\tconst element: TextElement = {\n\t\t\t\tid: `${replica}:${clock}`,\n\t\t\t\treplica,\n\t\t\t\tclock,\n\t\t\t\tafter,\n\t\t\t\tvalue: char,\n\t\t\t\tdeleted: false\n\t\t\t};\n\t\t\telements.set(element.id, element);\n\t\t\tpending.set(element.id, element);\n\t\t\tafter = element.id;\n\t\t}\n\t};\n\n\tconst remove = (index: number, count: number) => {\n\t\tconst seen = visible();\n\t\tfor (let offset = 0; offset < count; offset += 1) {\n\t\t\tconst target = seen[index + offset];\n\t\t\tif (target !== undefined) {\n\t\t\t\tconst tombstoned = { ...target, deleted: true };\n\t\t\t\telements.set(target.id, tombstoned);\n\t\t\t\tpending.set(target.id, tombstoned);\n\t\t\t}\n\t\t}\n\t};\n\n\treturn {\n\t\ttext: () => textOf({ elements: [...elements.values()] }),\n\t\tinsert,\n\t\tdelete: remove,\n\t\tmerge: (state) => {\n\t\t\tfor (const element of state.elements) {\n\t\t\t\tconst existing = elements.get(element.id);\n\t\t\t\telements.set(\n\t\t\t\t\telement.id,\n\t\t\t\t\texisting === undefined\n\t\t\t\t\t\t? element\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t...existing,\n\t\t\t\t\t\t\t\tdeleted: existing.deleted || element.deleted\n\t\t\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tclock = Math.max(clock, element.clock);\n\t\t\t}\n\t\t},\n\t\t// Reconcile to `next` by editing only the changed middle: keep the common\n\t\t// prefix/suffix, delete the old middle, insert the new — so two clients\n\t\t// typing in different places merge instead of overwriting.\n\t\tsetText: (next) => {\n\t\t\tconst current = textOf({ elements: [...elements.values()] });\n\t\t\tif (current === next) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet prefix = 0;\n\t\t\tconst maxPrefix = Math.min(current.length, next.length);\n\t\t\twhile (prefix < maxPrefix && current[prefix] === next[prefix]) {\n\t\t\t\tprefix += 1;\n\t\t\t}\n\t\t\tlet suffix = 0;\n\t\t\twhile (\n\t\t\t\tsuffix < maxPrefix - prefix &&\n\t\t\t\tcurrent[current.length - 1 - suffix] ===\n\t\t\t\t\tnext[next.length - 1 - suffix]\n\t\t\t) {\n\t\t\t\tsuffix += 1;\n\t\t\t}\n\t\t\tconst removed = current.length - prefix - suffix;\n\t\t\tif (removed > 0) {\n\t\t\t\tremove(prefix, removed);\n\t\t\t}\n\t\t\tconst inserted = next.slice(prefix, next.length - suffix);\n\t\t\tif (inserted.length > 0) {\n\t\t\t\tinsert(prefix, inserted);\n\t\t\t}\n\t\t},\n\t\tstate: () => ({ elements: [...elements.values()] }),\n\t\ttakeDelta: () => {\n\t\t\tconst delta = { elements: [...pending.values()] };\n\t\t\tpending.clear();\n\n\t\t\treturn delta;\n\t\t},\n\t\tanchorAt: (index) => {\n\t\t\tif (index <= 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst seen = visible();\n\n\t\t\treturn seen[Math.min(index, seen.length) - 1]?.id ?? null;\n\t\t},\n\t\tindexOfAnchor: (anchor) => {\n\t\t\tif (anchor === null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t// Count visible elements up to (and including) the anchor — the caret\n\t\t\t// renders right after it. A deleted/compacted anchor resolves to the\n\t\t\t// next visible position, so a caret never lands on stale text.\n\t\t\tlet visibleCount = 0;\n\t\t\tfor (const element of linearize([...elements.values()])) {\n\t\t\t\tif (!element.deleted) {\n\t\t\t\t\tvisibleCount += 1;\n\t\t\t\t}\n\t\t\t\tif (element.id === anchor) {\n\t\t\t\t\treturn visibleCount;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn visibleCount;\n\t\t}\n\t};\n};\n\n/**\n * The first-party collaborative-text backend (the RGA above) packaged as a\n * {@link TextCrdtAdapter}. Zero dependencies. Use it directly, or swap in an\n * adapter from `sync-adapters` (e.g. `@absolutejs/sync-yjs`) for the same shape.\n */\nexport const rgaText: TextCrdtAdapter<TextState> = {\n\tcompact,\n\tcreate: createTextCrdt,\n\tempty: () => ({ elements: [] }),\n\tmerge: mergeTextState,\n\ttextOf\n};\n",
|
|
9
9
|
"import { computed, Injectable, OnDestroy, signal } from '@angular/core';\nimport { createSyncCollection } from '../client/syncCollection';\nimport type {\n\tMutateOptions,\n\tSyncCollection,\n\tSyncCollectionOptions,\n\tSyncCollectionStatus\n} from '../client/syncCollection';\nimport { createCollaborativeText } from '../client/collaborativeText';\nimport type {\n\tCollaborativeText,\n\tCollaborativeTextOptions\n} from '../client/collaborativeText';\nimport type { TextState } from '../crdt';\n\n/**\n * Angular binding for live sync-engine collections (the Tier 3 store). Inject\n * the service and call `connect(options)` to get `data`/`status`/`error` signals\n * maintained from the WebSocket diff stream, plus an optimistic `mutate`. All\n * opened collections close on the service's destroy.\n *\n * SSR-safe: the socket only opens in a browser, so server rendering is inert.\n */\n@Injectable({ providedIn: 'root' })\nexport class SyncCollectionService implements OnDestroy {\n\tprivate readonly collections = new Set<SyncCollection<unknown>>();\n\n\tprivate readonly texts = new Set<CollaborativeText>();\n\n\tconnect<T>(options: SyncCollectionOptions<T>) {\n\t\tconst data = signal<T[]>([]);\n\t\tconst status = signal<SyncCollectionStatus>('connecting');\n\t\tconst error = signal<unknown>(undefined);\n\n\t\tlet collection: SyncCollection<T> | null = null;\n\n\t\tif (typeof window !== 'undefined') {\n\t\t\tcollection = createSyncCollection<T>(options);\n\t\t\tthis.collections.add(collection as SyncCollection<unknown>);\n\t\t\tconst apply = (state: {\n\t\t\t\tdata: T[];\n\t\t\t\tstatus: SyncCollectionStatus;\n\t\t\t\terror: unknown;\n\t\t\t}) => {\n\t\t\t\tdata.set(state.data);\n\t\t\t\tstatus.set(state.status);\n\t\t\t\terror.set(state.error);\n\t\t\t};\n\t\t\tapply(collection.get());\n\t\t\tcollection.subscribe(apply);\n\t\t}\n\n\t\tconst mutate = <R = unknown>(\n\t\t\tmutateOptions: MutateOptions<T>\n\t\t): Promise<R> =>\n\t\t\tcollection\n\t\t\t\t? collection.mutate<R>(mutateOptions)\n\t\t\t\t: Promise.reject(new Error('sync collection is not ready'));\n\n\t\treturn {\n\t\t\tdata: computed(() => data()),\n\t\t\terror: computed(() => error()),\n\t\t\tmutate,\n\t\t\tstatus: computed(() => status())\n\t\t};\n\t}\n\n\t/**\n\t * Connect a CRDT collaborative-text field. Returns `text`/`status` signals\n\t * (maintained from the merge of every client's edits) plus a `setText` that\n\t * broadcasts the merge. Concurrent edits converge with no clobbering and no\n\t * custom server mutation. SSR-safe (inert on the server).\n\t */\n\tcollaborativeText<State = TextState>(\n\t\toptions: CollaborativeTextOptions<State>\n\t) {\n\t\tconst text = signal('');\n\t\tconst status = signal<SyncCollectionStatus>('connecting');\n\n\t\tlet controller: CollaborativeText | null = null;\n\n\t\tif (typeof window !== 'undefined') {\n\t\t\tcontroller = createCollaborativeText<State>(options);\n\t\t\tthis.texts.add(controller);\n\t\t\tcontroller.subscribe((state) => {\n\t\t\t\ttext.set(state.text);\n\t\t\t\tstatus.set(state.status);\n\t\t\t});\n\t\t}\n\n\t\tconst setText = (next: string) => controller?.setText(next);\n\t\tconst anchorAt = (index: number) => controller?.anchorAt(index) ?? null;\n\t\tconst indexOfAnchor = (anchor: string | null) =>\n\t\t\tcontroller?.indexOfAnchor(anchor) ?? 0;\n\n\t\treturn {\n\t\t\tanchorAt,\n\t\t\tindexOfAnchor,\n\t\t\tsetText,\n\t\t\tstatus: computed(() => status()),\n\t\t\ttext: computed(() => text())\n\t\t};\n\t}\n\n\tngOnDestroy() {\n\t\tfor (const collection of this.collections) {\n\t\t\tcollection.close();\n\t\t}\n\t\tthis.collections.clear();\n\t\tfor (const text of this.texts) {\n\t\t\ttext.close();\n\t\t}\n\t\tthis.texts.clear();\n\t}\n}\n",
|
|
10
|
-
"import type { ServerFrame } from '../engine/connection';\nimport type { RowKey } from '../engine/types';\n\nexport type { ServerFrame } from '../engine/connection';\n\nexport type SyncCollectionStatus = 'connecting' | 'ready' | 'closed';\n\nexport type SyncCollectionState<T> = {\n\t/** Visible rows: the server state with pending optimistic mutations applied. */\n\tdata: T[];\n\t/** Connection/sync status. */\n\tstatus: SyncCollectionStatus;\n\t/** Last error message from the server, or `undefined`. */\n\terror: unknown;\n};\n\n/** A working set a mutation's optimistic effect edits in place. */\nexport type OptimisticDraft<T> = {\n\t/** Insert or replace a row by key. */\n\tset: (row: T) => void;\n\t/** Remove a row by key. */\n\tdelete: (key: RowKey) => void;\n};\n\nexport type MutateOptions<T> = {\n\t/** Registered server mutation name. */\n\tname: string;\n\t/** Arguments forwarded to the mutation handler. */\n\targs?: unknown;\n\t/**\n\t * Apply this mutation's effect to the local set immediately for instant UI.\n\t * Reverted automatically if the server rejects it. Omit for a non-optimistic\n\t * mutation (UI updates only once the authoritative diff arrives).\n\t */\n\toptimistic?: (draft: OptimisticDraft<T>) => void;\n};\n\n/** A pending mutation persisted for replay across reloads. */\nexport type PendingMutationRecord = {\n\tmutationId: number;\n\tname: string;\n\targs: unknown;\n};\n\n/**\n * Durable storage for the pending-mutation queue, so unconfirmed mutations\n * survive a page reload (offline). The queue is replayed when the socket\n * connects; records are dropped as they're acked.\n */\nexport type MutationStorage = {\n\tload: () => PendingMutationRecord[] | Promise<PendingMutationRecord[]>;\n\tsave: (records: PendingMutationRecord[]) => void | Promise<void>;\n};\n\n/**\n * A {@link MutationStorage} backed by `localStorage` under `key`. No-ops where\n * `localStorage` is unavailable (e.g. SSR).\n */\nexport const localStorageMutationStorage = (key: string): MutationStorage => ({\n\tload: () => {\n\t\tconst raw = globalThis.localStorage?.getItem(key);\n\t\treturn raw ? (JSON.parse(raw) as PendingMutationRecord[]) : [];\n\t},\n\tsave: (records) => {\n\t\tglobalThis.localStorage?.setItem(key, JSON.stringify(records));\n\t}\n});\n\n/**\n * A persisted snapshot of a collection's server-authoritative rows plus the\n * change-feed `version` they were current as of — the cursor used to resume on\n * the next connect (catch-up diff if the server's changelog still covers it, a\n * fresh snapshot otherwise).\n */\nexport type CollectionCacheSnapshot<T> = {\n\trows: T[];\n\tversion: number;\n};\n\n/**\n * Durable local cache of a collection's confirmed rows, so reads are instant on\n * reload and available offline (local-first). Distinct from {@link\n * MutationStorage}, which persists *unconfirmed writes*: the cache is the\n * read side, the queue is the write side. On startup the cache hydrates the\n * collection before the socket connects; the engine then resumes from the\n * cached `version`.\n */\nexport type CollectionCache<T> = {\n\tload: () =>\n\t\t| CollectionCacheSnapshot<T>\n\t\t| undefined\n\t\t| Promise<CollectionCacheSnapshot<T> | undefined>;\n\tsave: (snapshot: CollectionCacheSnapshot<T>) => void | Promise<void>;\n\t/** Drop the cached snapshot (optional). */\n\tclear?: () => void | Promise<void>;\n};\n\n/**\n * A {@link CollectionCache} backed by `localStorage` under `key`. Synchronous\n * and capped (~5MB); fine for small collections. No-ops where `localStorage`\n * is unavailable (e.g. SSR). For larger sets use {@link indexedDbCollectionCache}.\n */\nexport const localStorageCollectionCache = <T>(\n\tkey: string\n): CollectionCache<T> => ({\n\tload: () => {\n\t\tconst raw = globalThis.localStorage?.getItem(key);\n\t\treturn raw\n\t\t\t? (JSON.parse(raw) as CollectionCacheSnapshot<T>)\n\t\t\t: undefined;\n\t},\n\tsave: (snapshot) => {\n\t\tglobalThis.localStorage?.setItem(key, JSON.stringify(snapshot));\n\t},\n\tclear: () => {\n\t\tglobalThis.localStorage?.removeItem(key);\n\t}\n});\n\nconst openIndexedDb = (\n\tdatabaseName: string,\n\tstoreName: string\n): Promise<IDBDatabase> =>\n\tnew Promise((resolve, reject) => {\n\t\tconst request = globalThis.indexedDB.open(databaseName, 1);\n\t\trequest.onupgradeneeded = () => {\n\t\t\trequest.result.createObjectStore(storeName);\n\t\t};\n\t\trequest.onsuccess = () => resolve(request.result);\n\t\trequest.onerror = () => reject(request.error);\n\t});\n\n/**\n * A {@link CollectionCache} backed by IndexedDB — the durable, large-capacity\n * local-first store. Asynchronous; one row per collection `key` in a shared\n * object store. No-ops (resolving to `undefined`) where `indexedDB` is\n * unavailable (e.g. SSR), so the collection falls back to the server snapshot.\n */\nexport const indexedDbCollectionCache = <T>({\n\tkey,\n\tdatabaseName = 'absolutejs-sync',\n\tstoreName = 'collections'\n}: {\n\t/** Distinct entry name within the store (e.g. the collection + params). */\n\tkey: string;\n\t/** IndexedDB database name. Defaults to `absolutejs-sync`. */\n\tdatabaseName?: string;\n\t/** Object-store name. Defaults to `collections`. */\n\tstoreName?: string;\n}): CollectionCache<T> => {\n\tlet handle: Promise<IDBDatabase> | undefined;\n\tconst database = () => {\n\t\thandle ??= openIndexedDb(databaseName, storeName);\n\t\treturn handle;\n\t};\n\tconst withStore = async <R>(\n\t\tmode: IDBTransactionMode,\n\t\trun: (store: IDBObjectStore) => IDBRequest\n\t): Promise<R | undefined> => {\n\t\tif (globalThis.indexedDB === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst db = await database();\n\t\treturn new Promise<R>((resolve, reject) => {\n\t\t\tconst request = run(\n\t\t\t\tdb.transaction(storeName, mode).objectStore(storeName)\n\t\t\t);\n\t\t\trequest.onsuccess = () => resolve(request.result as R);\n\t\t\trequest.onerror = () => reject(request.error);\n\t\t});\n\t};\n\n\treturn {\n\t\tload: () =>\n\t\t\twithStore<CollectionCacheSnapshot<T>>('readonly', (store) =>\n\t\t\t\tstore.get(key)\n\t\t\t),\n\t\tsave: async (snapshot) => {\n\t\t\tawait withStore('readwrite', (store) => store.put(snapshot, key));\n\t\t},\n\t\tclear: async () => {\n\t\t\tawait withStore('readwrite', (store) => store.delete(key));\n\t\t}\n\t};\n};\n\nexport type SyncCollectionOptions<T> = {\n\t/** WebSocket URL of the {@link syncSocket} endpoint (e.g. `ws://host/sync/ws`). */\n\turl: string;\n\t/** Registered collection name to subscribe to. */\n\tcollection: string;\n\t/** Query params forwarded to the server collection's hydrate/match/authorize. */\n\tparams?: unknown;\n\t/** Row identity, used to apply diffs and optimistic edits. Defaults to `row.id`. */\n\tkey?: (row: T) => RowKey;\n\t/** WebSocket implementation; defaults to the global one (pass for tests/SSR). */\n\twebSocketImpl?: typeof WebSocket;\n\t/**\n\t * Base reconnect delay (ms), doubled each attempt up to `maxReconnectMs`.\n\t * Set 0 to disable auto-reconnect. Defaults to 500.\n\t */\n\treconnectMs?: number;\n\t/** Maximum reconnect backoff (ms). Defaults to 10000. */\n\tmaxReconnectMs?: number;\n\t/**\n\t * Persist the pending-mutation queue so it survives a reload (offline) and\n\t * replays on connect. See {@link localStorageMutationStorage}.\n\t */\n\tstorage?: MutationStorage;\n\t/**\n\t * Persist confirmed rows locally for instant reads on reload and offline\n\t * (local-first). Hydrated before the socket connects; the engine then\n\t * resumes from the cached version (catch-up diff, or a fresh snapshot if the\n\t * server's changelog no longer covers it). See {@link\n\t * localStorageCollectionCache} / {@link indexedDbCollectionCache}.\n\t */\n\tcache?: CollectionCache<T>;\n\t/** Called with each server error message. */\n\tonError?: (error: unknown) => void;\n};\n\nexport type SyncCollection<T> = {\n\t/** Current state snapshot (stable reference until the next change). */\n\tget: () => SyncCollectionState<T>;\n\t/** Subscribe to state changes; returns an unsubscribe. */\n\tsubscribe: (\n\t\tlistener: (state: SyncCollectionState<T>) => void\n\t) => () => void;\n\t/**\n\t * Run a server mutation, optionally applying it optimistically. Resolves with\n\t * the server's result on ack, rejects (and rolls back) on reject. Pending\n\t * mutations are replayed when the socket reconnects, so they survive a drop.\n\t */\n\tmutate: <R = unknown>(options: MutateOptions<T>) => Promise<R>;\n\t/**\n\t * Force-close the underlying WebSocket without tearing down state. The\n\t * auto-reconnect loop fires after `reconnectMs`; the collection's\n\t * `appliedVersion` is preserved so the resumed subscribe carries `since`\n\t * and the engine replies with a catch-up diff (or a fresh snapshot if\n\t * the change log no longer covers the gap).\n\t *\n\t * Useful for simulating an offline blip in tests and benches that need\n\t * to measure resume cost specifically (vs cold-hydration on a fresh\n\t * collection). No-op if the collection has been `close()`d.\n\t */\n\tdisconnect: () => void;\n\t/** Unsubscribe on the server, close the socket, and stop reconnecting. */\n\tclose: () => void;\n};\n\n// One store subscribes to exactly one collection, so a fixed frame id suffices.\nconst SUBSCRIPTION_ID = 's';\n\ntype PendingMutation<T> = {\n\tmutationId: number;\n\tname: string;\n\targs: unknown;\n\toptimistic?: (draft: OptimisticDraft<T>) => void;\n\tresolve: (result: unknown) => void;\n\treject: (error: unknown) => void;\n};\n\n/**\n * A live collection backed by the WebSocket sync engine. Reads: connect,\n * subscribe, apply the server's snapshot then row-level diffs, re-sync on\n * reconnect. Writes: {@link SyncCollection.mutate} applies an optimistic overlay\n * immediately, sends the mutation, and reconciles on ack (drop the overlay — the\n * authoritative diff already arrived) or reject (roll back). Framework-agnostic\n * (`get` + `subscribe`).\n *\n * Mutations are replayed on reconnect, so make server mutations idempotent —\n * delivery is at-least-once if an ack is lost across a drop.\n */\nexport const createSyncCollection = <T>(\n\toptions: SyncCollectionOptions<T>\n): SyncCollection<T> => {\n\tconst key = options.key ?? ((row: T) => (row as { id: RowKey }).id);\n\tconst reconnectMs = options.reconnectMs ?? 500;\n\tconst maxReconnectMs = options.maxReconnectMs ?? 10_000;\n\tconst Impl = options.webSocketImpl ?? globalThis.WebSocket;\n\tif (!Impl) {\n\t\tthrow new Error(\n\t\t\t'createSyncCollection requires WebSocket. Run in a browser or pass webSocketImpl.'\n\t\t);\n\t}\n\n\t// Server-authoritative rows; `pending` is the optimistic overlay on top.\n\tconst confirmed = new Map<RowKey, T>();\n\tconst pending: PendingMutation<T>[] = [];\n\tlet mutationSeq = 0;\n\n\tlet state: SyncCollectionState<T> = {\n\t\tdata: [],\n\t\tstatus: 'connecting',\n\t\terror: undefined\n\t};\n\tconst listeners = new Set<(state: SyncCollectionState<T>) => void>();\n\tconst setState = (patch: Partial<SyncCollectionState<T>>) => {\n\t\tstate = { ...state, ...patch };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener(state);\n\t\t}\n\t};\n\n\t/** Recompute visible rows = confirmed + pending optimistic effects. */\n\tconst recompute = (patch: Partial<SyncCollectionState<T>> = {}) => {\n\t\tconst working = new Map(confirmed);\n\t\tconst draft: OptimisticDraft<T> = {\n\t\t\tset: (row) => working.set(key(row), row),\n\t\t\tdelete: (rowKey) => working.delete(rowKey)\n\t\t};\n\t\tfor (const mutation of pending) {\n\t\t\tmutation.optimistic?.(draft);\n\t\t}\n\t\tsetState({ ...patch, data: [...working.values()] });\n\t};\n\n\tlet socket: WebSocket | undefined;\n\tlet connected = false;\n\tlet closed = false;\n\tlet attempt = 0;\n\tlet reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n\t// Highest change-feed version applied; sent as `since` to resume on reconnect.\n\tlet appliedVersion = 0;\n\n\tconst persist = () => {\n\t\tvoid options.storage?.save(\n\t\t\tpending.map((mutation) => ({\n\t\t\t\tmutationId: mutation.mutationId,\n\t\t\t\tname: mutation.name,\n\t\t\t\targs: mutation.args\n\t\t\t}))\n\t\t);\n\t};\n\n\t// Coalesce a burst of confirmed changes (a frame of diffs) into one cache\n\t// write per tick. Persists only the server-authoritative set — never the\n\t// optimistic overlay (those live in the mutation queue instead).\n\tlet cacheScheduled = false;\n\tconst persistCache = () => {\n\t\tif (options.cache === undefined || cacheScheduled) {\n\t\t\treturn;\n\t\t}\n\t\tcacheScheduled = true;\n\t\tqueueMicrotask(() => {\n\t\t\tcacheScheduled = false;\n\t\t\tvoid options.cache?.save({\n\t\t\t\trows: [...confirmed.values()],\n\t\t\t\tversion: appliedVersion\n\t\t\t});\n\t\t});\n\t};\n\n\tconst settlePending = (mutationId: number) => {\n\t\tconst index = pending.findIndex(\n\t\t\t(mutation) => mutation.mutationId === mutationId\n\t\t);\n\t\tif (index === -1) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst [mutation] = pending.splice(index, 1);\n\t\tpersist();\n\t\treturn mutation;\n\t};\n\n\tconst applyFrame = (frame: ServerFrame<T>) => {\n\t\tif (frame.type === 'snapshot') {\n\t\t\tconfirmed.clear();\n\t\t\tfor (const row of frame.rows) {\n\t\t\t\tconfirmed.set(key(row), row);\n\t\t\t}\n\t\t\tif (frame.version !== undefined) {\n\t\t\t\tappliedVersion = frame.version;\n\t\t\t}\n\t\t\tpersistCache();\n\t\t\trecompute({ status: 'ready', error: undefined });\n\t\t} else if (frame.type === 'diff') {\n\t\t\tfor (const row of frame.removed) {\n\t\t\t\tconfirmed.delete(key(row));\n\t\t\t}\n\t\t\tfor (const row of frame.added) {\n\t\t\t\tconfirmed.set(key(row), row);\n\t\t\t}\n\t\t\tfor (const row of frame.changed) {\n\t\t\t\tconfirmed.set(key(row), row);\n\t\t\t}\n\t\t\tif (frame.version !== undefined) {\n\t\t\t\tappliedVersion = Math.max(appliedVersion, frame.version);\n\t\t\t}\n\t\t\tpersistCache();\n\t\t\t// A diff only arrives once subscribed — including the catch-up diff a\n\t\t\t// resume replies with — so receiving one means we're live.\n\t\t\trecompute({ status: 'ready', error: undefined });\n\t\t} else if (frame.type === 'error') {\n\t\t\tsetState({ error: frame.message });\n\t\t\toptions.onError?.(frame.message);\n\t\t} else if (frame.type === 'ack') {\n\t\t\t// The authoritative diff already arrived (ordered before the ack), so\n\t\t\t// dropping the overlay leaves the confirmed row in place — no flicker.\n\t\t\tconst mutation = settlePending(frame.mutationId);\n\t\t\tif (mutation !== undefined) {\n\t\t\t\trecompute();\n\t\t\t\tmutation.resolve(frame.result);\n\t\t\t}\n\t\t} else if (frame.type === 'reject') {\n\t\t\t// roll the optimistic overlay back.\n\t\t\tconst mutation = settlePending(frame.mutationId);\n\t\t\tif (mutation !== undefined) {\n\t\t\t\trecompute();\n\t\t\t\tmutation.reject(new Error(String(frame.message)));\n\t\t\t}\n\t\t}\n\t\t// A `frame` (multi-collection batch) never reaches a single-collection\n\t\t// store — that's the multiplexed createSyncClient's job — so ignore it.\n\t};\n\n\tconst sendMutate = (mutation: PendingMutation<T>) => {\n\t\tif (connected) {\n\t\t\tsocket?.send(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\ttype: 'mutate',\n\t\t\t\t\tmutationId: mutation.mutationId,\n\t\t\t\t\tname: mutation.name,\n\t\t\t\t\targs: mutation.args\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\t};\n\n\tconst connect = () => {\n\t\tif (closed) {\n\t\t\treturn;\n\t\t}\n\t\tsetState({ status: 'connecting' });\n\t\tconst ws = new Impl(options.url);\n\t\tsocket = ws;\n\t\tws.onopen = () => {\n\t\t\tattempt = 0;\n\t\t\tconnected = true;\n\t\t\tws.send(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\ttype: 'subscribe',\n\t\t\t\t\tid: SUBSCRIPTION_ID,\n\t\t\t\t\tcollection: options.collection,\n\t\t\t\t\tparams: options.params,\n\t\t\t\t\t// Resume from what we've applied (catch-up instead of snapshot).\n\t\t\t\t\tsince: appliedVersion > 0 ? appliedVersion : undefined\n\t\t\t\t})\n\t\t\t);\n\t\t\t// Replay anything still pending across the (re)connect.\n\t\t\tfor (const mutation of pending) {\n\t\t\t\tsendMutate(mutation);\n\t\t\t}\n\t\t};\n\t\tws.onmessage = (event) => {\n\t\t\ttry {\n\t\t\t\tapplyFrame(JSON.parse(event.data as string) as ServerFrame<T>);\n\t\t\t} catch {\n\t\t\t\t// ignore non-JSON frames\n\t\t\t}\n\t\t};\n\t\tws.onclose = () => {\n\t\t\tconnected = false;\n\t\t\tif (closed || reconnectMs <= 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst delay = Math.min(reconnectMs * 2 ** attempt, maxReconnectMs);\n\t\t\tattempt += 1;\n\t\t\treconnectTimer = setTimeout(connect, delay);\n\t\t};\n\t};\n\n\t// Reload recovery: re-queue persisted unconfirmed mutations so they replay on\n\t// connect. They carry no optimistic effect or promise (the resumed/snapshot\n\t// state is authoritative); resending produces the diffs that bring them in.\n\tconst hydratePersisted = async () => {\n\t\tif (options.storage === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tconst records = await options.storage.load();\n\t\tfor (const record of records) {\n\t\t\tif (pending.some((m) => m.mutationId === record.mutationId)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tpending.push({\n\t\t\t\tmutationId: record.mutationId,\n\t\t\t\tname: record.name,\n\t\t\t\targs: record.args,\n\t\t\t\tresolve: () => {},\n\t\t\t\treject: () => {}\n\t\t\t});\n\t\t\tmutationSeq = Math.max(mutationSeq, record.mutationId);\n\t\t}\n\t\tif (connected) {\n\t\t\tfor (const mutation of pending) {\n\t\t\t\tsendMutate(mutation);\n\t\t\t}\n\t\t}\n\t};\n\n\t// Local-first: load cached rows + version before connecting, so reads are\n\t// instant on reload and available offline. The subscribe then resumes from\n\t// the cached version — a catch-up diff if the server's changelog still\n\t// covers it, else a fresh snapshot that replaces the stale cache.\n\tconst hydrateCache = async () => {\n\t\tif (options.cache === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tlet snapshot: CollectionCacheSnapshot<T> | undefined;\n\t\ttry {\n\t\t\tsnapshot = await options.cache.load();\n\t\t} catch {\n\t\t\treturn; // corrupt/unavailable cache: fall back to the server snapshot\n\t\t}\n\t\t// Don't clobber server data if a frame somehow already landed.\n\t\tif (snapshot === undefined || appliedVersion > 0) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const row of snapshot.rows) {\n\t\t\tconfirmed.set(key(row), row);\n\t\t}\n\t\tappliedVersion = snapshot.version;\n\t\trecompute(); // show cached rows immediately (status stays 'connecting')\n\t};\n\n\tif (options.cache === undefined) {\n\t\t// No cache: preserve the original connect-then-hydrate ordering/timing.\n\t\tconnect();\n\t\tvoid hydratePersisted();\n\t} else {\n\t\t// Cache: hydrate reads + queued writes first, then connect so the\n\t\t// subscribe carries the cached resume version.\n\t\tvoid (async () => {\n\t\t\tawait hydrateCache();\n\t\t\tawait hydratePersisted();\n\t\t\tconnect();\n\t\t})();\n\t}\n\n\treturn {\n\t\tget: () => state,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tmutate: <R = unknown>(mutateOptions: MutateOptions<T>) =>\n\t\t\tnew Promise<R>((resolve, reject) => {\n\t\t\t\tconst mutation: PendingMutation<T> = {\n\t\t\t\t\tmutationId: (mutationSeq += 1),\n\t\t\t\t\tname: mutateOptions.name,\n\t\t\t\t\targs: mutateOptions.args,\n\t\t\t\t\toptimistic: mutateOptions.optimistic,\n\t\t\t\t\tresolve: (result) => resolve(result as R),\n\t\t\t\t\treject\n\t\t\t\t};\n\t\t\t\tpending.push(mutation);\n\t\t\t\tpersist();\n\t\t\t\trecompute(); // apply the optimistic overlay immediately\n\t\t\t\tsendMutate(mutation);\n\t\t\t}),\n\t\tdisconnect: () => {\n\t\t\t// Force-close the WS without tearing down state. The existing\n\t\t\t// `ws.onclose` handler schedules a reconnect via the auto-\n\t\t\t// reconnect loop (unless the collection has been `close()`d).\n\t\t\t// `appliedVersion` is preserved, so the resumed subscribe carries\n\t\t\t// `since` and the engine sends a catch-up diff (or snapshot if\n\t\t\t// the change log can't cover the gap).\n\t\t\tif (closed || socket === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tsocket.close();\n\t\t\t} catch {\n\t\t\t\t// already closing/closed\n\t\t\t}\n\t\t},\n\t\tclose: () => {\n\t\t\tif (closed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclosed = true;\n\t\t\tconnected = false;\n\t\t\tif (reconnectTimer !== undefined) {\n\t\t\t\tclearTimeout(reconnectTimer);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tsocket?.send(\n\t\t\t\t\tJSON.stringify({ type: 'unsubscribe', id: SUBSCRIPTION_ID })\n\t\t\t\t);\n\t\t\t\tsocket?.close();\n\t\t\t} catch {\n\t\t\t\t// socket already closing/closed\n\t\t\t}\n\t\t\t// Fail any still-pending mutations so their promises don't hang.\n\t\t\tfor (const mutation of pending.splice(0)) {\n\t\t\t\tmutation.reject(new Error('sync collection closed'));\n\t\t\t}\n\t\t\tpersist();\n\t\t\tsetState({ status: 'closed' });\n\t\t\tlisteners.clear();\n\t\t}\n\t};\n};\n",
|
|
10
|
+
"import type { ClientFrame, ServerFrame } from './engine/connection';\n\n/**\n * Wire-format adapter (1.16.0). The engine and client default to JSON, but\n * for high-throughput deployments — a customer pushing 1 MB initial\n * snapshots, a tenant fan-out hitting 100k frames/sec — a binary serializer\n * (msgpack, cbor, or a custom tagged layout) cuts both bandwidth and\n * parse-side CPU.\n *\n * Both ends of the connection MUST use the same serializer. The default\n * `jsonSerializer` keeps every existing client + server pair working\n * unchanged; opt in to a different one on BOTH `syncSocket` and the client\n * lib to gain the win.\n *\n * The serializer only handles the wire format. Frame-shape validation\n * stays in the engine (`parseFrame` in connection.ts) — it runs on the\n * decoded object, so the same validation works for JSON, msgpack, etc.\n */\nexport type FrameSerializer = {\n\t/** Server→client: encode an outgoing `ServerFrame` for transport. */\n\tencodeServer: (frame: ServerFrame) => string | ArrayBufferLike | Uint8Array;\n\t/** Client→server: encode an outgoing `ClientFrame` for transport. */\n\tencodeClient: (frame: ClientFrame) => string | ArrayBufferLike | Uint8Array;\n\t/**\n\t * Deserialize a wire payload into a raw object. Return `null` for\n\t * unparseable input — the engine's validation step turns that into\n\t * a protocol error.\n\t */\n\tdecode: (raw: unknown) => unknown;\n};\n\n/**\n * Default JSON serializer — what `@absolutejs/sync` has always shipped.\n * Strings go through `JSON.parse`; already-parsed objects pass through\n * (some WS adapters auto-decode). `Uint8Array` / `ArrayBuffer` get\n * UTF-8 decoded first (binary WS frames carrying JSON text).\n */\nexport const jsonSerializer: FrameSerializer = {\n\tdecode: (raw: unknown): unknown => {\n\t\tif (typeof raw === 'string') {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(raw);\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tif (raw instanceof Uint8Array) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(new TextDecoder().decode(raw));\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tif (raw instanceof ArrayBuffer) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(new TextDecoder().decode(new Uint8Array(raw)));\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn raw;\n\t},\n\tencodeClient: (frame: ClientFrame): string => JSON.stringify(frame),\n\tencodeServer: (frame: ServerFrame): string => JSON.stringify(frame)\n};\n",
|
|
11
|
+
"import type { ServerFrame } from '../engine/connection';\nimport type { RowKey } from '../engine/types';\nimport { jsonSerializer, type FrameSerializer } from '../serializer';\n\nexport type { ServerFrame } from '../engine/connection';\n\nexport type SyncCollectionStatus = 'connecting' | 'ready' | 'closed';\n\nexport type SyncCollectionState<T> = {\n\t/** Visible rows: the server state with pending optimistic mutations applied. */\n\tdata: T[];\n\t/** Connection/sync status. */\n\tstatus: SyncCollectionStatus;\n\t/** Last error message from the server, or `undefined`. */\n\terror: unknown;\n};\n\n/** A working set a mutation's optimistic effect edits in place. */\nexport type OptimisticDraft<T> = {\n\t/** Insert or replace a row by key. */\n\tset: (row: T) => void;\n\t/** Remove a row by key. */\n\tdelete: (key: RowKey) => void;\n};\n\nexport type MutateOptions<T> = {\n\t/** Registered server mutation name. */\n\tname: string;\n\t/** Arguments forwarded to the mutation handler. */\n\targs?: unknown;\n\t/**\n\t * Apply this mutation's effect to the local set immediately for instant UI.\n\t * Reverted automatically if the server rejects it. Omit for a non-optimistic\n\t * mutation (UI updates only once the authoritative diff arrives).\n\t */\n\toptimistic?: (draft: OptimisticDraft<T>) => void;\n};\n\n/** A pending mutation persisted for replay across reloads. */\nexport type PendingMutationRecord = {\n\tmutationId: number;\n\tname: string;\n\targs: unknown;\n};\n\n/**\n * Durable storage for the pending-mutation queue, so unconfirmed mutations\n * survive a page reload (offline). The queue is replayed when the socket\n * connects; records are dropped as they're acked.\n */\nexport type MutationStorage = {\n\tload: () => PendingMutationRecord[] | Promise<PendingMutationRecord[]>;\n\tsave: (records: PendingMutationRecord[]) => void | Promise<void>;\n};\n\n/**\n * A {@link MutationStorage} backed by `localStorage` under `key`. No-ops where\n * `localStorage` is unavailable (e.g. SSR).\n */\nexport const localStorageMutationStorage = (key: string): MutationStorage => ({\n\tload: () => {\n\t\tconst raw = globalThis.localStorage?.getItem(key);\n\t\treturn raw ? (JSON.parse(raw) as PendingMutationRecord[]) : [];\n\t},\n\tsave: (records) => {\n\t\tglobalThis.localStorage?.setItem(key, JSON.stringify(records));\n\t}\n});\n\n/**\n * A persisted snapshot of a collection's server-authoritative rows plus the\n * change-feed `version` they were current as of — the cursor used to resume on\n * the next connect (catch-up diff if the server's changelog still covers it, a\n * fresh snapshot otherwise).\n */\nexport type CollectionCacheSnapshot<T> = {\n\trows: T[];\n\tversion: number;\n};\n\n/**\n * Durable local cache of a collection's confirmed rows, so reads are instant on\n * reload and available offline (local-first). Distinct from {@link\n * MutationStorage}, which persists *unconfirmed writes*: the cache is the\n * read side, the queue is the write side. On startup the cache hydrates the\n * collection before the socket connects; the engine then resumes from the\n * cached `version`.\n */\nexport type CollectionCache<T> = {\n\tload: () =>\n\t\t| CollectionCacheSnapshot<T>\n\t\t| undefined\n\t\t| Promise<CollectionCacheSnapshot<T> | undefined>;\n\tsave: (snapshot: CollectionCacheSnapshot<T>) => void | Promise<void>;\n\t/** Drop the cached snapshot (optional). */\n\tclear?: () => void | Promise<void>;\n};\n\n/**\n * A {@link CollectionCache} backed by `localStorage` under `key`. Synchronous\n * and capped (~5MB); fine for small collections. No-ops where `localStorage`\n * is unavailable (e.g. SSR). For larger sets use {@link indexedDbCollectionCache}.\n */\nexport const localStorageCollectionCache = <T>(\n\tkey: string\n): CollectionCache<T> => ({\n\tload: () => {\n\t\tconst raw = globalThis.localStorage?.getItem(key);\n\t\treturn raw\n\t\t\t? (JSON.parse(raw) as CollectionCacheSnapshot<T>)\n\t\t\t: undefined;\n\t},\n\tsave: (snapshot) => {\n\t\tglobalThis.localStorage?.setItem(key, JSON.stringify(snapshot));\n\t},\n\tclear: () => {\n\t\tglobalThis.localStorage?.removeItem(key);\n\t}\n});\n\nconst openIndexedDb = (\n\tdatabaseName: string,\n\tstoreName: string\n): Promise<IDBDatabase> =>\n\tnew Promise((resolve, reject) => {\n\t\tconst request = globalThis.indexedDB.open(databaseName, 1);\n\t\trequest.onupgradeneeded = () => {\n\t\t\trequest.result.createObjectStore(storeName);\n\t\t};\n\t\trequest.onsuccess = () => resolve(request.result);\n\t\trequest.onerror = () => reject(request.error);\n\t});\n\n/**\n * A {@link CollectionCache} backed by IndexedDB — the durable, large-capacity\n * local-first store. Asynchronous; one row per collection `key` in a shared\n * object store. No-ops (resolving to `undefined`) where `indexedDB` is\n * unavailable (e.g. SSR), so the collection falls back to the server snapshot.\n */\nexport const indexedDbCollectionCache = <T>({\n\tkey,\n\tdatabaseName = 'absolutejs-sync',\n\tstoreName = 'collections'\n}: {\n\t/** Distinct entry name within the store (e.g. the collection + params). */\n\tkey: string;\n\t/** IndexedDB database name. Defaults to `absolutejs-sync`. */\n\tdatabaseName?: string;\n\t/** Object-store name. Defaults to `collections`. */\n\tstoreName?: string;\n}): CollectionCache<T> => {\n\tlet handle: Promise<IDBDatabase> | undefined;\n\tconst database = () => {\n\t\thandle ??= openIndexedDb(databaseName, storeName);\n\t\treturn handle;\n\t};\n\tconst withStore = async <R>(\n\t\tmode: IDBTransactionMode,\n\t\trun: (store: IDBObjectStore) => IDBRequest\n\t): Promise<R | undefined> => {\n\t\tif (globalThis.indexedDB === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst db = await database();\n\t\treturn new Promise<R>((resolve, reject) => {\n\t\t\tconst request = run(\n\t\t\t\tdb.transaction(storeName, mode).objectStore(storeName)\n\t\t\t);\n\t\t\trequest.onsuccess = () => resolve(request.result as R);\n\t\t\trequest.onerror = () => reject(request.error);\n\t\t});\n\t};\n\n\treturn {\n\t\tload: () =>\n\t\t\twithStore<CollectionCacheSnapshot<T>>('readonly', (store) =>\n\t\t\t\tstore.get(key)\n\t\t\t),\n\t\tsave: async (snapshot) => {\n\t\t\tawait withStore('readwrite', (store) => store.put(snapshot, key));\n\t\t},\n\t\tclear: async () => {\n\t\t\tawait withStore('readwrite', (store) => store.delete(key));\n\t\t}\n\t};\n};\n\nexport type SyncCollectionOptions<T> = {\n\t/** WebSocket URL of the {@link syncSocket} endpoint (e.g. `ws://host/sync/ws`). */\n\turl: string;\n\t/** Registered collection name to subscribe to. */\n\tcollection: string;\n\t/** Query params forwarded to the server collection's hydrate/match/authorize. */\n\tparams?: unknown;\n\t/** Row identity, used to apply diffs and optimistic edits. Defaults to `row.id`. */\n\tkey?: (row: T) => RowKey;\n\t/** WebSocket implementation; defaults to the global one (pass for tests/SSR). */\n\twebSocketImpl?: typeof WebSocket;\n\t/**\n\t * Base reconnect delay (ms), doubled each attempt up to `maxReconnectMs`.\n\t * Set 0 to disable auto-reconnect. Defaults to 500.\n\t */\n\treconnectMs?: number;\n\t/** Maximum reconnect backoff (ms). Defaults to 10000. */\n\tmaxReconnectMs?: number;\n\t/**\n\t * Persist the pending-mutation queue so it survives a reload (offline) and\n\t * replays on connect. See {@link localStorageMutationStorage}.\n\t */\n\tstorage?: MutationStorage;\n\t/**\n\t * Persist confirmed rows locally for instant reads on reload and offline\n\t * (local-first). Hydrated before the socket connects; the engine then\n\t * resumes from the cached version (catch-up diff, or a fresh snapshot if the\n\t * server's changelog no longer covers it). See {@link\n\t * localStorageCollectionCache} / {@link indexedDbCollectionCache}.\n\t */\n\tcache?: CollectionCache<T>;\n\t/** Called with each server error message. */\n\tonError?: (error: unknown) => void;\n\t/**\n\t * Wire-format serializer (1.16.0). Defaults to `jsonSerializer`. MUST\n\t * match the server's `syncSocket` serializer.\n\t */\n\tserializer?: FrameSerializer;\n};\n\nexport type SyncCollection<T> = {\n\t/** Current state snapshot (stable reference until the next change). */\n\tget: () => SyncCollectionState<T>;\n\t/** Subscribe to state changes; returns an unsubscribe. */\n\tsubscribe: (\n\t\tlistener: (state: SyncCollectionState<T>) => void\n\t) => () => void;\n\t/**\n\t * Run a server mutation, optionally applying it optimistically. Resolves with\n\t * the server's result on ack, rejects (and rolls back) on reject. Pending\n\t * mutations are replayed when the socket reconnects, so they survive a drop.\n\t */\n\tmutate: <R = unknown>(options: MutateOptions<T>) => Promise<R>;\n\t/**\n\t * Force-close the underlying WebSocket without tearing down state. The\n\t * auto-reconnect loop fires after `reconnectMs`; the collection's\n\t * `appliedVersion` is preserved so the resumed subscribe carries `since`\n\t * and the engine replies with a catch-up diff (or a fresh snapshot if\n\t * the change log no longer covers the gap).\n\t *\n\t * Useful for simulating an offline blip in tests and benches that need\n\t * to measure resume cost specifically (vs cold-hydration on a fresh\n\t * collection). No-op if the collection has been `close()`d.\n\t */\n\tdisconnect: () => void;\n\t/** Unsubscribe on the server, close the socket, and stop reconnecting. */\n\tclose: () => void;\n};\n\n// One store subscribes to exactly one collection, so a fixed frame id suffices.\nconst SUBSCRIPTION_ID = 's';\n\ntype PendingMutation<T> = {\n\tmutationId: number;\n\tname: string;\n\targs: unknown;\n\toptimistic?: (draft: OptimisticDraft<T>) => void;\n\tresolve: (result: unknown) => void;\n\treject: (error: unknown) => void;\n};\n\n/**\n * A live collection backed by the WebSocket sync engine. Reads: connect,\n * subscribe, apply the server's snapshot then row-level diffs, re-sync on\n * reconnect. Writes: {@link SyncCollection.mutate} applies an optimistic overlay\n * immediately, sends the mutation, and reconciles on ack (drop the overlay — the\n * authoritative diff already arrived) or reject (roll back). Framework-agnostic\n * (`get` + `subscribe`).\n *\n * Mutations are replayed on reconnect, so make server mutations idempotent —\n * delivery is at-least-once if an ack is lost across a drop.\n */\nexport const createSyncCollection = <T>(\n\toptions: SyncCollectionOptions<T>\n): SyncCollection<T> => {\n\tconst key = options.key ?? ((row: T) => (row as { id: RowKey }).id);\n\tconst reconnectMs = options.reconnectMs ?? 500;\n\tconst maxReconnectMs = options.maxReconnectMs ?? 10_000;\n\tconst serializer: FrameSerializer = options.serializer ?? jsonSerializer;\n\tconst Impl = options.webSocketImpl ?? globalThis.WebSocket;\n\tif (!Impl) {\n\t\tthrow new Error(\n\t\t\t'createSyncCollection requires WebSocket. Run in a browser or pass webSocketImpl.'\n\t\t);\n\t}\n\n\t// Server-authoritative rows; `pending` is the optimistic overlay on top.\n\tconst confirmed = new Map<RowKey, T>();\n\tconst pending: PendingMutation<T>[] = [];\n\tlet mutationSeq = 0;\n\n\tlet state: SyncCollectionState<T> = {\n\t\tdata: [],\n\t\tstatus: 'connecting',\n\t\terror: undefined\n\t};\n\tconst listeners = new Set<(state: SyncCollectionState<T>) => void>();\n\tconst setState = (patch: Partial<SyncCollectionState<T>>) => {\n\t\tstate = { ...state, ...patch };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener(state);\n\t\t}\n\t};\n\n\t/** Recompute visible rows = confirmed + pending optimistic effects. */\n\tconst recompute = (patch: Partial<SyncCollectionState<T>> = {}) => {\n\t\tconst working = new Map(confirmed);\n\t\tconst draft: OptimisticDraft<T> = {\n\t\t\tset: (row) => working.set(key(row), row),\n\t\t\tdelete: (rowKey) => working.delete(rowKey)\n\t\t};\n\t\tfor (const mutation of pending) {\n\t\t\tmutation.optimistic?.(draft);\n\t\t}\n\t\tsetState({ ...patch, data: [...working.values()] });\n\t};\n\n\tlet socket: WebSocket | undefined;\n\tlet connected = false;\n\tlet closed = false;\n\tlet attempt = 0;\n\tlet reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n\t// Highest change-feed version applied; sent as `since` to resume on reconnect.\n\tlet appliedVersion = 0;\n\n\tconst persist = () => {\n\t\tvoid options.storage?.save(\n\t\t\tpending.map((mutation) => ({\n\t\t\t\tmutationId: mutation.mutationId,\n\t\t\t\tname: mutation.name,\n\t\t\t\targs: mutation.args\n\t\t\t}))\n\t\t);\n\t};\n\n\t// Coalesce a burst of confirmed changes (a frame of diffs) into one cache\n\t// write per tick. Persists only the server-authoritative set — never the\n\t// optimistic overlay (those live in the mutation queue instead).\n\tlet cacheScheduled = false;\n\tconst persistCache = () => {\n\t\tif (options.cache === undefined || cacheScheduled) {\n\t\t\treturn;\n\t\t}\n\t\tcacheScheduled = true;\n\t\tqueueMicrotask(() => {\n\t\t\tcacheScheduled = false;\n\t\t\tvoid options.cache?.save({\n\t\t\t\trows: [...confirmed.values()],\n\t\t\t\tversion: appliedVersion\n\t\t\t});\n\t\t});\n\t};\n\n\tconst settlePending = (mutationId: number) => {\n\t\tconst index = pending.findIndex(\n\t\t\t(mutation) => mutation.mutationId === mutationId\n\t\t);\n\t\tif (index === -1) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst [mutation] = pending.splice(index, 1);\n\t\tpersist();\n\t\treturn mutation;\n\t};\n\n\tconst applyFrame = (frame: ServerFrame<T>) => {\n\t\tif (frame.type === 'snapshot') {\n\t\t\tconfirmed.clear();\n\t\t\tfor (const row of frame.rows) {\n\t\t\t\tconfirmed.set(key(row), row);\n\t\t\t}\n\t\t\tif (frame.version !== undefined) {\n\t\t\t\tappliedVersion = frame.version;\n\t\t\t}\n\t\t\tpersistCache();\n\t\t\trecompute({ status: 'ready', error: undefined });\n\t\t} else if (frame.type === 'diff') {\n\t\t\tfor (const row of frame.removed) {\n\t\t\t\tconfirmed.delete(key(row));\n\t\t\t}\n\t\t\tfor (const row of frame.added) {\n\t\t\t\tconfirmed.set(key(row), row);\n\t\t\t}\n\t\t\tfor (const row of frame.changed) {\n\t\t\t\tconfirmed.set(key(row), row);\n\t\t\t}\n\t\t\tif (frame.version !== undefined) {\n\t\t\t\tappliedVersion = Math.max(appliedVersion, frame.version);\n\t\t\t}\n\t\t\tpersistCache();\n\t\t\t// A diff only arrives once subscribed — including the catch-up diff a\n\t\t\t// resume replies with — so receiving one means we're live.\n\t\t\trecompute({ status: 'ready', error: undefined });\n\t\t} else if (frame.type === 'error') {\n\t\t\tsetState({ error: frame.message });\n\t\t\toptions.onError?.(frame.message);\n\t\t} else if (frame.type === 'ack') {\n\t\t\t// The authoritative diff already arrived (ordered before the ack), so\n\t\t\t// dropping the overlay leaves the confirmed row in place — no flicker.\n\t\t\tconst mutation = settlePending(frame.mutationId);\n\t\t\tif (mutation !== undefined) {\n\t\t\t\trecompute();\n\t\t\t\tmutation.resolve(frame.result);\n\t\t\t}\n\t\t} else if (frame.type === 'reject') {\n\t\t\t// roll the optimistic overlay back.\n\t\t\tconst mutation = settlePending(frame.mutationId);\n\t\t\tif (mutation !== undefined) {\n\t\t\t\trecompute();\n\t\t\t\tmutation.reject(new Error(String(frame.message)));\n\t\t\t}\n\t\t}\n\t\t// A `frame` (multi-collection batch) never reaches a single-collection\n\t\t// store — that's the multiplexed createSyncClient's job — so ignore it.\n\t};\n\n\tconst wsSend = (payload: string | ArrayBufferLike | Uint8Array) => {\n\t\tsocket?.send(payload as string);\n\t};\n\n\tconst sendMutate = (mutation: PendingMutation<T>) => {\n\t\tif (connected) {\n\t\t\twsSend(serializer.encodeClient({\n\t\t\t\ttype: 'mutate',\n\t\t\t\tmutationId: mutation.mutationId,\n\t\t\t\tname: mutation.name,\n\t\t\t\targs: mutation.args\n\t\t\t}));\n\t\t}\n\t};\n\n\tconst connect = () => {\n\t\tif (closed) {\n\t\t\treturn;\n\t\t}\n\t\tsetState({ status: 'connecting' });\n\t\tconst ws = new Impl(options.url);\n\t\tsocket = ws;\n\t\tws.onopen = () => {\n\t\t\tattempt = 0;\n\t\t\tconnected = true;\n\t\t\tws.send(serializer.encodeClient({\n\t\t\t\ttype: 'subscribe',\n\t\t\t\tid: SUBSCRIPTION_ID,\n\t\t\t\tcollection: options.collection,\n\t\t\t\tparams: options.params,\n\t\t\t\t// Resume from what we've applied (catch-up instead of snapshot).\n\t\t\t\tsince: appliedVersion > 0 ? appliedVersion : undefined\n\t\t\t}) as string);\n\t\t\t// Replay anything still pending across the (re)connect.\n\t\t\tfor (const mutation of pending) {\n\t\t\t\tsendMutate(mutation);\n\t\t\t}\n\t\t};\n\t\tws.onmessage = (event) => {\n\t\t\ttry {\n\t\t\t\tconst decoded = serializer.decode(event.data);\n\t\t\t\tif (decoded !== null && typeof decoded === 'object') {\n\t\t\t\t\tapplyFrame(decoded as ServerFrame<T>);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// ignore non-JSON frames\n\t\t\t}\n\t\t};\n\t\tws.onclose = () => {\n\t\t\tconnected = false;\n\t\t\tif (closed || reconnectMs <= 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst delay = Math.min(reconnectMs * 2 ** attempt, maxReconnectMs);\n\t\t\tattempt += 1;\n\t\t\treconnectTimer = setTimeout(connect, delay);\n\t\t};\n\t};\n\n\t// Reload recovery: re-queue persisted unconfirmed mutations so they replay on\n\t// connect. They carry no optimistic effect or promise (the resumed/snapshot\n\t// state is authoritative); resending produces the diffs that bring them in.\n\tconst hydratePersisted = async () => {\n\t\tif (options.storage === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tconst records = await options.storage.load();\n\t\tfor (const record of records) {\n\t\t\tif (pending.some((m) => m.mutationId === record.mutationId)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tpending.push({\n\t\t\t\tmutationId: record.mutationId,\n\t\t\t\tname: record.name,\n\t\t\t\targs: record.args,\n\t\t\t\tresolve: () => {},\n\t\t\t\treject: () => {}\n\t\t\t});\n\t\t\tmutationSeq = Math.max(mutationSeq, record.mutationId);\n\t\t}\n\t\tif (connected) {\n\t\t\tfor (const mutation of pending) {\n\t\t\t\tsendMutate(mutation);\n\t\t\t}\n\t\t}\n\t};\n\n\t// Local-first: load cached rows + version before connecting, so reads are\n\t// instant on reload and available offline. The subscribe then resumes from\n\t// the cached version — a catch-up diff if the server's changelog still\n\t// covers it, else a fresh snapshot that replaces the stale cache.\n\tconst hydrateCache = async () => {\n\t\tif (options.cache === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tlet snapshot: CollectionCacheSnapshot<T> | undefined;\n\t\ttry {\n\t\t\tsnapshot = await options.cache.load();\n\t\t} catch {\n\t\t\treturn; // corrupt/unavailable cache: fall back to the server snapshot\n\t\t}\n\t\t// Don't clobber server data if a frame somehow already landed.\n\t\tif (snapshot === undefined || appliedVersion > 0) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const row of snapshot.rows) {\n\t\t\tconfirmed.set(key(row), row);\n\t\t}\n\t\tappliedVersion = snapshot.version;\n\t\trecompute(); // show cached rows immediately (status stays 'connecting')\n\t};\n\n\tif (options.cache === undefined) {\n\t\t// No cache: preserve the original connect-then-hydrate ordering/timing.\n\t\tconnect();\n\t\tvoid hydratePersisted();\n\t} else {\n\t\t// Cache: hydrate reads + queued writes first, then connect so the\n\t\t// subscribe carries the cached resume version.\n\t\tvoid (async () => {\n\t\t\tawait hydrateCache();\n\t\t\tawait hydratePersisted();\n\t\t\tconnect();\n\t\t})();\n\t}\n\n\treturn {\n\t\tget: () => state,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tmutate: <R = unknown>(mutateOptions: MutateOptions<T>) =>\n\t\t\tnew Promise<R>((resolve, reject) => {\n\t\t\t\tconst mutation: PendingMutation<T> = {\n\t\t\t\t\tmutationId: (mutationSeq += 1),\n\t\t\t\t\tname: mutateOptions.name,\n\t\t\t\t\targs: mutateOptions.args,\n\t\t\t\t\toptimistic: mutateOptions.optimistic,\n\t\t\t\t\tresolve: (result) => resolve(result as R),\n\t\t\t\t\treject\n\t\t\t\t};\n\t\t\t\tpending.push(mutation);\n\t\t\t\tpersist();\n\t\t\t\trecompute(); // apply the optimistic overlay immediately\n\t\t\t\tsendMutate(mutation);\n\t\t\t}),\n\t\tdisconnect: () => {\n\t\t\t// Force-close the WS without tearing down state. The existing\n\t\t\t// `ws.onclose` handler schedules a reconnect via the auto-\n\t\t\t// reconnect loop (unless the collection has been `close()`d).\n\t\t\t// `appliedVersion` is preserved, so the resumed subscribe carries\n\t\t\t// `since` and the engine sends a catch-up diff (or snapshot if\n\t\t\t// the change log can't cover the gap).\n\t\t\tif (closed || socket === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tsocket.close();\n\t\t\t} catch {\n\t\t\t\t// already closing/closed\n\t\t\t}\n\t\t},\n\t\tclose: () => {\n\t\t\tif (closed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclosed = true;\n\t\t\tconnected = false;\n\t\t\tif (reconnectTimer !== undefined) {\n\t\t\t\tclearTimeout(reconnectTimer);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\twsSend(serializer.encodeClient({\n\t\t\t\t\ttype: 'unsubscribe',\n\t\t\t\t\tid: SUBSCRIPTION_ID\n\t\t\t\t}));\n\t\t\t\tsocket?.close();\n\t\t\t} catch {\n\t\t\t\t// socket already closing/closed\n\t\t\t}\n\t\t\t// Fail any still-pending mutations so their promises don't hang.\n\t\t\tfor (const mutation of pending.splice(0)) {\n\t\t\t\tmutation.reject(new Error('sync collection closed'));\n\t\t\t}\n\t\t\tpersist();\n\t\t\tsetState({ status: 'closed' });\n\t\t\tlisteners.clear();\n\t\t}\n\t};\n};\n",
|
|
11
12
|
"import { createSyncCollection } from './syncCollection';\nimport type { SyncCollectionStatus } from './syncCollection';\nimport { createTextCrdt } from '../crdt';\nimport type { CrdtText, TextState } from '../crdt';\nimport type { RowKey } from '../engine/types';\n\n/**\n * Options for a live collaborative-text binding. It subscribes to a sync\n * collection, tracks one row's CRDT field, and merges remote edits into a local\n * replica — so the visible text reflects everyone's edits and converges. Edits\n * are sent through the engine's auto-registered `\"<collection>:merge\"` mutation\n * (override with `mutation`), which merges instead of overwriting.\n */\nexport type CollaborativeTextOptions<State = TextState> = {\n\t/** The sync WebSocket URL (same one your collections use). */\n\turl: string;\n\t/** Collection (and table) name holding the document rows. */\n\tcollection: string;\n\t/** Which row to edit (its key value). */\n\tid: RowKey;\n\t/** The row field holding the CRDT state. */\n\tfield: string;\n\t/** The row's key field name (defaults to `\"id\"`). */\n\tkeyField?: string;\n\t/** Mutation to send edits through (defaults to `\"<collection>:merge\"`). */\n\tmutation?: string;\n\t/** This client's replica id (defaults to a random UUID). */\n\treplica?: string;\n\t/**\n\t * CRDT backend factory (defaults to the first-party RGA `createTextCrdt`).\n\t * Pass e.g. `(replica) => createYjsText(replica)` from `@absolutejs/sync-yjs`\n\t * — it must match the backend the server registered for this field.\n\t */\n\tcreate?: (replica: string) => CrdtText<State>;\n};\n\nexport type CollaborativeTextState = {\n\t/** The current merged, visible text. */\n\ttext: string;\n\t/** The underlying collection's connection status. */\n\tstatus: SyncCollectionStatus;\n};\n\nexport type CollaborativeText = {\n\tget: () => CollaborativeTextState;\n\tsubscribe: (run: (state: CollaborativeTextState) => void) => () => void;\n\t/** Reconcile the local text to `next` and broadcast the merged state. */\n\tsetText: (next: string) => void;\n\t/** Stable anchor for a caret at visible `index` — broadcast it (e.g. via\n\t * presence) for collaborative cursors that survive concurrent edits. */\n\tanchorAt: (index: number) => string | null;\n\t/** Current visible index of a caret anchored after `anchor`. */\n\tindexOfAnchor: (anchor: string | null) => number;\n\tclose: () => void;\n};\n\n/**\n * Framework-agnostic controller behind the `useCollaborativeText` bindings. Opens\n * a {@link createSyncCollection}, so create it on the client only (the framework\n * wrappers do this in an effect / on mount).\n */\nexport const createCollaborativeText = <State = TextState>(\n\toptions: CollaborativeTextOptions<State>\n): CollaborativeText => {\n\tconst keyField = options.keyField ?? 'id';\n\tconst mutation = options.mutation ?? `${options.collection}:merge`;\n\tconst replica = options.replica ?? globalThis.crypto.randomUUID();\n\tconst make =\n\t\toptions.create ??\n\t\t((id: string) => createTextCrdt(id) as unknown as CrdtText<State>);\n\tconst crdt = make(replica);\n\n\tlet current: CollaborativeTextState = { status: 'connecting', text: '' };\n\tconst subscribers = new Set<(state: CollaborativeTextState) => void>();\n\tconst emit = () => {\n\t\tfor (const run of subscribers) {\n\t\t\trun(current);\n\t\t}\n\t};\n\n\tconst collection = createSyncCollection<Record<string, unknown>>({\n\t\tcollection: options.collection,\n\t\tkey: (row) => row[keyField] as RowKey,\n\t\turl: options.url\n\t});\n\n\tconst apply = (state: {\n\t\tdata: Record<string, unknown>[];\n\t\tstatus: SyncCollectionStatus;\n\t}) => {\n\t\tlet { text } = current;\n\t\tconst row = state.data.find(\n\t\t\t(candidate) => candidate[keyField] === options.id\n\t\t);\n\t\tconst fieldState = row?.[options.field];\n\t\tif (fieldState !== undefined) {\n\t\t\t// Idempotent for our own echoes; folds in other replicas' edits.\n\t\t\tcrdt.merge(fieldState as State);\n\t\t\ttext = crdt.text();\n\t\t}\n\t\tcurrent = { status: state.status, text };\n\t\temit();\n\t};\n\tapply(collection.get());\n\tconst unsubscribe = collection.subscribe(apply);\n\n\treturn {\n\t\tget: () => current,\n\t\tsubscribe(run) {\n\t\t\tsubscribers.add(run);\n\t\t\trun(current);\n\n\t\t\treturn () => {\n\t\t\t\tsubscribers.delete(run);\n\t\t\t};\n\t\t},\n\t\tsetText(next) {\n\t\t\tcrdt.setText(next);\n\t\t\tcurrent = { status: current.status, text: next };\n\t\t\temit();\n\t\t\t// Upload only this edit's ops when the backend supports delta-state\n\t\t\t// (O(edit)); otherwise the full state. The server merges either the\n\t\t\t// same way (union) and keeps full state for late-joiner hydration.\n\t\t\tconst payload = crdt.takeDelta ? crdt.takeDelta() : crdt.state();\n\t\t\tvoid collection.mutate({\n\t\t\t\targs: { [keyField]: options.id, [options.field]: payload },\n\t\t\t\tname: mutation\n\t\t\t});\n\t\t},\n\t\tanchorAt: (index) => crdt.anchorAt?.(index) ?? null,\n\t\tindexOfAnchor: (anchor) => crdt.indexOfAnchor?.(anchor) ?? 0,\n\t\tclose() {\n\t\t\tunsubscribe();\n\t\t\tcollection.close();\n\t\t\tsubscribers.clear();\n\t\t}\n\t};\n};\n"
|
|
12
13
|
],
|
|
13
|
-
"mappings": "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",
|
|
14
|
-
"debugId": "
|
|
14
|
+
"mappings": "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",
|
|
15
|
+
"debugId": "B7FB2C3EE968F18164756E2164756E21",
|
|
15
16
|
"names": []
|
|
16
17
|
}
|
package/dist/client/index.js
CHANGED
|
@@ -656,6 +656,36 @@ var jsonFetcher = (url, init) => async (signal) => {
|
|
|
656
656
|
}
|
|
657
657
|
return await response.json();
|
|
658
658
|
};
|
|
659
|
+
// src/serializer.ts
|
|
660
|
+
var jsonSerializer = {
|
|
661
|
+
decode: (raw) => {
|
|
662
|
+
if (typeof raw === "string") {
|
|
663
|
+
try {
|
|
664
|
+
return JSON.parse(raw);
|
|
665
|
+
} catch {
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (raw instanceof Uint8Array) {
|
|
670
|
+
try {
|
|
671
|
+
return JSON.parse(new TextDecoder().decode(raw));
|
|
672
|
+
} catch {
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (raw instanceof ArrayBuffer) {
|
|
677
|
+
try {
|
|
678
|
+
return JSON.parse(new TextDecoder().decode(new Uint8Array(raw)));
|
|
679
|
+
} catch {
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return raw;
|
|
684
|
+
},
|
|
685
|
+
encodeClient: (frame) => JSON.stringify(frame),
|
|
686
|
+
encodeServer: (frame) => JSON.stringify(frame)
|
|
687
|
+
};
|
|
688
|
+
|
|
659
689
|
// src/client/syncCollection.ts
|
|
660
690
|
var localStorageMutationStorage = (key) => ({
|
|
661
691
|
load: () => {
|
|
@@ -722,6 +752,7 @@ var createSyncCollection = (options) => {
|
|
|
722
752
|
const key = options.key ?? ((row) => row.id);
|
|
723
753
|
const reconnectMs = options.reconnectMs ?? 500;
|
|
724
754
|
const maxReconnectMs = options.maxReconnectMs ?? 1e4;
|
|
755
|
+
const serializer = options.serializer ?? jsonSerializer;
|
|
725
756
|
const Impl = options.webSocketImpl ?? globalThis.WebSocket;
|
|
726
757
|
if (!Impl) {
|
|
727
758
|
throw new Error("createSyncCollection requires WebSocket. Run in a browser or pass webSocketImpl.");
|
|
@@ -831,9 +862,12 @@ var createSyncCollection = (options) => {
|
|
|
831
862
|
}
|
|
832
863
|
}
|
|
833
864
|
};
|
|
865
|
+
const wsSend = (payload) => {
|
|
866
|
+
socket?.send(payload);
|
|
867
|
+
};
|
|
834
868
|
const sendMutate = (mutation) => {
|
|
835
869
|
if (connected) {
|
|
836
|
-
|
|
870
|
+
wsSend(serializer.encodeClient({
|
|
837
871
|
type: "mutate",
|
|
838
872
|
mutationId: mutation.mutationId,
|
|
839
873
|
name: mutation.name,
|
|
@@ -851,7 +885,7 @@ var createSyncCollection = (options) => {
|
|
|
851
885
|
ws.onopen = () => {
|
|
852
886
|
attempt = 0;
|
|
853
887
|
connected = true;
|
|
854
|
-
ws.send(
|
|
888
|
+
ws.send(serializer.encodeClient({
|
|
855
889
|
type: "subscribe",
|
|
856
890
|
id: SUBSCRIPTION_ID,
|
|
857
891
|
collection: options.collection,
|
|
@@ -864,7 +898,10 @@ var createSyncCollection = (options) => {
|
|
|
864
898
|
};
|
|
865
899
|
ws.onmessage = (event) => {
|
|
866
900
|
try {
|
|
867
|
-
|
|
901
|
+
const decoded = serializer.decode(event.data);
|
|
902
|
+
if (decoded !== null && typeof decoded === "object") {
|
|
903
|
+
applyFrame(decoded);
|
|
904
|
+
}
|
|
868
905
|
} catch {}
|
|
869
906
|
};
|
|
870
907
|
ws.onclose = () => {
|
|
@@ -970,7 +1007,10 @@ var createSyncCollection = (options) => {
|
|
|
970
1007
|
clearTimeout(reconnectTimer);
|
|
971
1008
|
}
|
|
972
1009
|
try {
|
|
973
|
-
|
|
1010
|
+
wsSend(serializer.encodeClient({
|
|
1011
|
+
type: "unsubscribe",
|
|
1012
|
+
id: SUBSCRIPTION_ID
|
|
1013
|
+
}));
|
|
974
1014
|
socket?.close();
|
|
975
1015
|
} catch {}
|
|
976
1016
|
for (const mutation of pending.splice(0)) {
|
|
@@ -1046,6 +1086,7 @@ var createCollaborativeText = (options) => {
|
|
|
1046
1086
|
var createPresence = (options) => {
|
|
1047
1087
|
const reconnectMs = options.reconnectMs ?? 500;
|
|
1048
1088
|
const maxReconnectMs = options.maxReconnectMs ?? 1e4;
|
|
1089
|
+
const serializer = options.serializer ?? jsonSerializer;
|
|
1049
1090
|
const Impl = options.webSocketImpl ?? globalThis.WebSocket;
|
|
1050
1091
|
if (!Impl) {
|
|
1051
1092
|
throw new Error("createPresence requires WebSocket. Run in a browser or pass webSocketImpl.");
|
|
@@ -1071,7 +1112,7 @@ var createPresence = (options) => {
|
|
|
1071
1112
|
let reconnectTimer;
|
|
1072
1113
|
const send = (frame) => {
|
|
1073
1114
|
if (connected) {
|
|
1074
|
-
socket?.send(
|
|
1115
|
+
socket?.send(serializer.encodeClient(frame));
|
|
1075
1116
|
}
|
|
1076
1117
|
};
|
|
1077
1118
|
const connect = () => {
|
|
@@ -1083,7 +1124,7 @@ var createPresence = (options) => {
|
|
|
1083
1124
|
ws.onopen = () => {
|
|
1084
1125
|
attempt = 0;
|
|
1085
1126
|
connected = true;
|
|
1086
|
-
ws.send(
|
|
1127
|
+
ws.send(serializer.encodeClient({
|
|
1087
1128
|
type: "presence-join",
|
|
1088
1129
|
room: options.room,
|
|
1089
1130
|
memberId: id,
|
|
@@ -1092,11 +1133,11 @@ var createPresence = (options) => {
|
|
|
1092
1133
|
};
|
|
1093
1134
|
ws.onmessage = (event) => {
|
|
1094
1135
|
let frame;
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
} catch {
|
|
1136
|
+
const decoded = serializer.decode(event.data);
|
|
1137
|
+
if (decoded === null || typeof decoded !== "object") {
|
|
1098
1138
|
return;
|
|
1099
1139
|
}
|
|
1140
|
+
frame = decoded;
|
|
1100
1141
|
if (frame.type !== "presence" || frame.room !== options.room) {
|
|
1101
1142
|
return;
|
|
1102
1143
|
}
|
|
@@ -1151,6 +1192,7 @@ var createPresence = (options) => {
|
|
|
1151
1192
|
var createSyncClient = (options) => {
|
|
1152
1193
|
const reconnectMs = options.reconnectMs ?? 500;
|
|
1153
1194
|
const maxReconnectMs = options.maxReconnectMs ?? 1e4;
|
|
1195
|
+
const serializer = options.serializer ?? jsonSerializer;
|
|
1154
1196
|
const Impl = options.webSocketImpl ?? globalThis.WebSocket;
|
|
1155
1197
|
if (!Impl) {
|
|
1156
1198
|
throw new Error("createSyncClient requires WebSocket. Run in a browser or pass webSocketImpl.");
|
|
@@ -1275,8 +1317,11 @@ var createSyncClient = (options) => {
|
|
|
1275
1317
|
}
|
|
1276
1318
|
}
|
|
1277
1319
|
};
|
|
1320
|
+
const wsSend = (payload) => {
|
|
1321
|
+
socket?.send(payload);
|
|
1322
|
+
};
|
|
1278
1323
|
const sendSubscribe = (entry) => {
|
|
1279
|
-
|
|
1324
|
+
wsSend(serializer.encodeClient({
|
|
1280
1325
|
type: "subscribe",
|
|
1281
1326
|
id: entry.id,
|
|
1282
1327
|
collection: entry.collection,
|
|
@@ -1286,7 +1331,7 @@ var createSyncClient = (options) => {
|
|
|
1286
1331
|
};
|
|
1287
1332
|
const sendMutate = (mutation) => {
|
|
1288
1333
|
if (connected) {
|
|
1289
|
-
|
|
1334
|
+
wsSend(serializer.encodeClient({
|
|
1290
1335
|
type: "mutate",
|
|
1291
1336
|
mutationId: mutation.mutationId,
|
|
1292
1337
|
name: mutation.name,
|
|
@@ -1314,7 +1359,10 @@ var createSyncClient = (options) => {
|
|
|
1314
1359
|
};
|
|
1315
1360
|
ws.onmessage = (event) => {
|
|
1316
1361
|
try {
|
|
1317
|
-
|
|
1362
|
+
const decoded = serializer.decode(event.data);
|
|
1363
|
+
if (decoded !== null && typeof decoded === "object") {
|
|
1364
|
+
applyFrame(decoded);
|
|
1365
|
+
}
|
|
1318
1366
|
} catch {}
|
|
1319
1367
|
};
|
|
1320
1368
|
ws.onclose = () => {
|
|
@@ -1379,7 +1427,10 @@ var createSyncClient = (options) => {
|
|
|
1379
1427
|
entry.closed = true;
|
|
1380
1428
|
entries.delete(entryId);
|
|
1381
1429
|
if (connected) {
|
|
1382
|
-
|
|
1430
|
+
wsSend(serializer.encodeClient({
|
|
1431
|
+
type: "unsubscribe",
|
|
1432
|
+
id: entryId
|
|
1433
|
+
}));
|
|
1383
1434
|
}
|
|
1384
1435
|
}
|
|
1385
1436
|
};
|
|
@@ -1409,6 +1460,7 @@ var syncStore = (options) => {
|
|
|
1409
1460
|
const maxReconnectMs = options.maxReconnectMs ?? 1e4;
|
|
1410
1461
|
const reconcileGraceMs = options.reconcileGraceMs ?? 3000;
|
|
1411
1462
|
const mutations = options.mutations ?? {};
|
|
1463
|
+
const serializer = options.serializer ?? jsonSerializer;
|
|
1412
1464
|
const Impl = options.webSocketImpl ?? globalThis.WebSocket;
|
|
1413
1465
|
if (!Impl) {
|
|
1414
1466
|
throw new Error("syncStore requires WebSocket. Run in a browser or pass webSocketImpl.");
|
|
@@ -1567,7 +1619,7 @@ var syncStore = (options) => {
|
|
|
1567
1619
|
ws.onopen = () => {
|
|
1568
1620
|
attempt = 0;
|
|
1569
1621
|
connected = true;
|
|
1570
|
-
ws.send(
|
|
1622
|
+
ws.send(serializer.encodeClient({
|
|
1571
1623
|
type: "subscribe",
|
|
1572
1624
|
id: SUBSCRIPTION_ID2,
|
|
1573
1625
|
collection: options.collection,
|
|
@@ -1582,7 +1634,10 @@ var syncStore = (options) => {
|
|
|
1582
1634
|
};
|
|
1583
1635
|
ws.onmessage = (event) => {
|
|
1584
1636
|
try {
|
|
1585
|
-
|
|
1637
|
+
const decoded = serializer.decode(event.data);
|
|
1638
|
+
if (decoded !== null && typeof decoded === "object") {
|
|
1639
|
+
applyFrame(decoded);
|
|
1640
|
+
}
|
|
1586
1641
|
} catch {}
|
|
1587
1642
|
};
|
|
1588
1643
|
ws.onclose = () => {
|
|
@@ -1696,7 +1751,10 @@ var syncStore = (options) => {
|
|
|
1696
1751
|
clearTimeout(reconnectTimer);
|
|
1697
1752
|
}
|
|
1698
1753
|
try {
|
|
1699
|
-
socket?.send(
|
|
1754
|
+
socket?.send(serializer.encodeClient({
|
|
1755
|
+
type: "unsubscribe",
|
|
1756
|
+
id: SUBSCRIPTION_ID2
|
|
1757
|
+
}));
|
|
1700
1758
|
socket?.close();
|
|
1701
1759
|
} catch {}
|
|
1702
1760
|
for (const mutation of pending.splice(0)) {
|
|
@@ -1733,5 +1791,5 @@ export {
|
|
|
1733
1791
|
createCollaborativeText
|
|
1734
1792
|
};
|
|
1735
1793
|
|
|
1736
|
-
//# debugId=
|
|
1794
|
+
//# debugId=91907A0D295C48AD64756E2164756E21
|
|
1737
1795
|
//# sourceMappingURL=index.js.map
|