@firtoz/collection-sync 5.0.0 → 6.0.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.
Files changed (128) hide show
  1. package/README.md +46 -0
  2. package/dist/cache-manager.d.ts +52 -0
  3. package/dist/cache-manager.js +5 -0
  4. package/dist/cache-manager.js.map +1 -0
  5. package/dist/chunk-3EHHMLSV.js +57 -0
  6. package/dist/chunk-3EHHMLSV.js.map +1 -0
  7. package/dist/chunk-43KYAIKY.js +46 -0
  8. package/dist/chunk-43KYAIKY.js.map +1 -0
  9. package/dist/chunk-4BEXLBCH.js +64 -0
  10. package/dist/chunk-4BEXLBCH.js.map +1 -0
  11. package/dist/chunk-5V6BSQAB.js +148 -0
  12. package/dist/chunk-5V6BSQAB.js.map +1 -0
  13. package/dist/chunk-5VMFQT5Z.js +112 -0
  14. package/dist/chunk-5VMFQT5Z.js.map +1 -0
  15. package/dist/chunk-6EHROJFY.js +111 -0
  16. package/dist/chunk-6EHROJFY.js.map +1 -0
  17. package/dist/chunk-6X3434GJ.js +21 -0
  18. package/dist/chunk-6X3434GJ.js.map +1 -0
  19. package/dist/chunk-BGJH6PH2.js +175 -0
  20. package/dist/chunk-BGJH6PH2.js.map +1 -0
  21. package/dist/chunk-BJJEAKXL.js +252 -0
  22. package/dist/chunk-BJJEAKXL.js.map +1 -0
  23. package/dist/chunk-GWIOC5CP.js +51 -0
  24. package/dist/chunk-GWIOC5CP.js.map +1 -0
  25. package/dist/chunk-HMLY7DHA.js +12 -0
  26. package/dist/chunk-HMLY7DHA.js.map +1 -0
  27. package/dist/chunk-I6RJWBGF.js +112 -0
  28. package/dist/chunk-I6RJWBGF.js.map +1 -0
  29. package/dist/chunk-M5MJHS6A.js +10 -0
  30. package/dist/chunk-M5MJHS6A.js.map +1 -0
  31. package/dist/chunk-O3KBDCEI.js +615 -0
  32. package/dist/chunk-O3KBDCEI.js.map +1 -0
  33. package/dist/chunk-OP53UBPN.js +19 -0
  34. package/dist/chunk-OP53UBPN.js.map +1 -0
  35. package/dist/chunk-P3JOTUAB.js +802 -0
  36. package/dist/chunk-P3JOTUAB.js.map +1 -0
  37. package/dist/chunk-QJP4GSJH.js +373 -0
  38. package/dist/chunk-QJP4GSJH.js.map +1 -0
  39. package/dist/chunk-RDDS7JQW.js +623 -0
  40. package/dist/chunk-RDDS7JQW.js.map +1 -0
  41. package/dist/chunk-TEH7V76G.js +209 -0
  42. package/dist/chunk-TEH7V76G.js.map +1 -0
  43. package/dist/chunk-UJ24XW52.js +20 -0
  44. package/dist/chunk-UJ24XW52.js.map +1 -0
  45. package/dist/chunk-UVZJL6QV.js +18 -0
  46. package/dist/chunk-UVZJL6QV.js.map +1 -0
  47. package/dist/chunk-XC4QNFSQ.js +238 -0
  48. package/dist/chunk-XC4QNFSQ.js.map +1 -0
  49. package/dist/chunk-YD5LVGWX.js +125 -0
  50. package/dist/chunk-YD5LVGWX.js.map +1 -0
  51. package/dist/chunk-YYGPIHHJ.js +166 -0
  52. package/dist/chunk-YYGPIHHJ.js.map +1 -0
  53. package/dist/connect-partial-sync.d.ts +41 -0
  54. package/dist/connect-partial-sync.js +6 -0
  55. package/dist/connect-partial-sync.js.map +1 -0
  56. package/dist/connect-sync.d.ts +26 -0
  57. package/dist/connect-sync.js +5 -0
  58. package/dist/connect-sync.js.map +1 -0
  59. package/dist/create-partial-synced-collection.d.ts +24 -0
  60. package/dist/create-partial-synced-collection.js +8 -0
  61. package/dist/create-partial-synced-collection.js.map +1 -0
  62. package/dist/create-synced-collection.d.ts +26 -0
  63. package/dist/create-synced-collection.js +8 -0
  64. package/dist/create-synced-collection.js.map +1 -0
  65. package/dist/index.d.ts +18 -0
  66. package/dist/index.js +18 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/partial-sync-client-bridge.d.ts +157 -0
  69. package/dist/partial-sync-client-bridge.js +6 -0
  70. package/dist/partial-sync-client-bridge.js.map +1 -0
  71. package/dist/partial-sync-interest.d.ts +48 -0
  72. package/dist/partial-sync-interest.js +6 -0
  73. package/dist/partial-sync-interest.js.map +1 -0
  74. package/dist/partial-sync-mutation-handler.d.ts +31 -0
  75. package/dist/partial-sync-mutation-handler.js +6 -0
  76. package/dist/partial-sync-mutation-handler.js.map +1 -0
  77. package/dist/partial-sync-predicate-match.d.ts +8 -0
  78. package/dist/partial-sync-predicate-match.js +4 -0
  79. package/dist/partial-sync-predicate-match.js.map +1 -0
  80. package/dist/partial-sync-row-key.d.ts +41 -0
  81. package/dist/partial-sync-row-key.js +4 -0
  82. package/dist/partial-sync-row-key.js.map +1 -0
  83. package/dist/partial-sync-server-bridge.d.ts +102 -0
  84. package/dist/partial-sync-server-bridge.js +8 -0
  85. package/dist/partial-sync-server-bridge.js.map +1 -0
  86. package/dist/react/constants.d.ts +12 -0
  87. package/dist/react/constants.js +4 -0
  88. package/dist/react/constants.js.map +1 -0
  89. package/dist/react/index.d.ts +19 -0
  90. package/dist/react/index.js +17 -0
  91. package/dist/react/index.js.map +1 -0
  92. package/dist/react/partial-sync-adapter.d.ts +40 -0
  93. package/dist/react/partial-sync-adapter.js +4 -0
  94. package/dist/react/partial-sync-adapter.js.map +1 -0
  95. package/dist/react/partial-sync-utils.d.ts +42 -0
  96. package/dist/react/partial-sync-utils.js +5 -0
  97. package/dist/react/partial-sync-utils.js.map +1 -0
  98. package/dist/react/range-conditions-expression.d.ts +49 -0
  99. package/dist/react/range-conditions-expression.js +4 -0
  100. package/dist/react/range-conditions-expression.js.map +1 -0
  101. package/dist/react/types.d.ts +196 -0
  102. package/dist/react/types.js +3 -0
  103. package/dist/react/types.js.map +1 -0
  104. package/dist/react/usePartialSyncCollection.d.ts +20 -0
  105. package/dist/react/usePartialSyncCollection.js +10 -0
  106. package/dist/react/usePartialSyncCollection.js.map +1 -0
  107. package/dist/react/usePartialSyncViewport.d.ts +20 -0
  108. package/dist/react/usePartialSyncViewport.js +7 -0
  109. package/dist/react/usePartialSyncViewport.js.map +1 -0
  110. package/dist/react/usePartialSyncWindow.d.ts +17 -0
  111. package/dist/react/usePartialSyncWindow.js +12 -0
  112. package/dist/react/usePartialSyncWindow.js.map +1 -0
  113. package/dist/react/usePredicateFilteredRows.d.ts +20 -0
  114. package/dist/react/usePredicateFilteredRows.js +6 -0
  115. package/dist/react/usePredicateFilteredRows.js.map +1 -0
  116. package/dist/sync-client-bridge.d.ts +48 -0
  117. package/dist/sync-client-bridge.js +6 -0
  118. package/dist/sync-client-bridge.js.map +1 -0
  119. package/dist/sync-protocol.d.ts +378 -0
  120. package/dist/sync-protocol.js +4 -0
  121. package/dist/sync-protocol.js.map +1 -0
  122. package/dist/sync-server-bridge.d.ts +35 -0
  123. package/dist/sync-server-bridge.js +6 -0
  124. package/dist/sync-server-bridge.js.map +1 -0
  125. package/dist/with-sync.d.ts +107 -0
  126. package/dist/with-sync.js +7 -0
  127. package/dist/with-sync.js.map +1 -0
  128. package/package.json +23 -17
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/connect-partial-sync.ts"],"names":[],"mappings":"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","file":"chunk-XC4QNFSQ.js","sourcesContent":["import { exhaustiveGuard } from \"@firtoz/maybe-error\";\nimport type { SyncMessage } from \"@firtoz/db-helpers\";\nimport { StandardSchemaWebSocketClient } from \"@firtoz/websocket-do/schema-client\";\nimport type { PartialSyncClientBridge } from \"./partial-sync-client-bridge\";\nimport type { SyncClientBridge } from \"./sync-client-bridge\";\nimport {\n\tpartialSyncRowKey,\n\ttype PartialSyncRowShape,\n} from \"./partial-sync-row-key\";\nimport {\n\tcreateClientMessageSchema,\n\tcreateServerMessageSchema,\n\tDEFAULT_SYNC_COLLECTION_ID,\n\ttype SyncClientMessage,\n\ttype SyncServerMessage,\n} from \"./sync-protocol\";\n\n/**\n * Optional browser `document` for Page Visibility — accessed via `globalThis` so this module typechecks\n * under configs that omit the DOM global (e.g. Worker-only `lib`).\n */\ntype PageVisibilityDocument = {\n\treadonly visibilityState: string;\n\taddEventListener(type: \"visibilitychange\", listener: () => void): void;\n\tremoveEventListener(type: \"visibilitychange\", listener: () => void): void;\n};\n\nfunction pageVisibilityDocument(): PageVisibilityDocument | undefined {\n\treturn (\n\t\tglobalThis as typeof globalThis & { document?: PageVisibilityDocument }\n\t).document;\n}\n\nexport type ConnectPartialSyncTransport = \"json\" | \"msgpack\";\n\nexport type ConnectPartialSyncOptions<\n\tTItem extends PartialSyncRowShape = PartialSyncRowShape,\n> = {\n\turl: string;\n\ttransport?: ConnectPartialSyncTransport;\n\t/** Prefer a module-level function or `useCallback`; a new inline function each render can churn effects. */\n\tserializeJson?: (value: unknown) => string;\n\t/** Prefer a module-level function or `useCallback`; a new inline function each render can churn effects. */\n\tdeserializeJson?: (raw: string) => unknown;\n\tsetTransportSend: (send: (msg: SyncClientMessage) => void) => void;\n\tonServerMessage?: (msg: SyncServerMessage<TItem>) => void;\n\t/**\n\t * When set, inbound messages are split: range traffic → `bridge`, ack/reject/syncBackfill → mutation bridge;\n\t * `syncBatch` applies via mutation bridge then updates partial cache ids (no double `receiveSync`).\n\t */\n\tmutationBridge?: SyncClientBridge<TItem>;\n};\n\n/**\n * @internal Exported for unit tests; prefer {@link connectPartialSync} in apps.\n * After a `rangePatch`, call `partialBridge.flushPendingCoalescedInboundUpdates()` unless you use\n * `connectPartialSync` (the pump flushes coalesced updates after each inbound job).\n */\nexport async function dispatchPartialSyncServerMessage<\n\tTItem extends PartialSyncRowShape,\n>(\n\tmsg: SyncServerMessage<TItem>,\n\tpartialBridge: PartialSyncClientBridge<TItem>,\n\tmutationBridge: SyncClientBridge<TItem> | undefined,\n): Promise<void> {\n\tconst mid = msg.collectionId ?? DEFAULT_SYNC_COLLECTION_ID;\n\tconst forPartial = mid === partialBridge.collectionId;\n\tconst forMutation =\n\t\tmutationBridge !== undefined && mid === mutationBridge.collectionId;\n\n\tif (mutationBridge === undefined) {\n\t\tif (!forPartial) return;\n\t\tawait partialBridge.handleServerMessage(msg);\n\t\treturn;\n\t}\n\n\tswitch (msg.type) {\n\t\tcase \"queryRangeChunk\":\n\t\tcase \"rangeUpToDate\":\n\t\tcase \"rangeDelta\":\n\t\tcase \"rangeReconcileResult\":\n\t\tcase \"rangePatch\":\n\t\tcase \"pong\":\n\t\t\tif (!forPartial) return;\n\t\t\tawait partialBridge.handleServerMessage(msg);\n\t\t\treturn;\n\t\tcase \"ack\":\n\t\tcase \"reject\":\n\t\tcase \"syncBackfill\":\n\t\t\tif (!forMutation) return;\n\t\t\tawait mutationBridge.handleServerMessage(msg);\n\t\t\treturn;\n\t\tcase \"syncBatch\": {\n\t\t\tif (!forMutation) return;\n\t\t\tawait mutationBridge.handleServerMessage(msg);\n\t\t\tif (forPartial) {\n\t\t\t\tconst changes = msg.changes as SyncMessage<TItem>[];\n\t\t\t\tpartialBridge.syncTrackedIdsFromMessages(changes);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tdefault:\n\t\t\texhaustiveGuard(msg);\n\t}\n}\n\nexport type CoalescedRangePatchMessage<TItem extends PartialSyncRowShape> =\n\tExtract<SyncServerMessage<TItem>, { type: \"rangePatch\" }>;\n\n/**\n * Last-wins merge of buffered `rangePatch` messages (same row id keeps the latest patch).\n * @internal Exported for unit tests.\n */\nexport function mergeCoalescedRangePatches<TItem extends PartialSyncRowShape>(\n\tpatches: CoalescedRangePatchMessage<TItem>[],\n): CoalescedRangePatchMessage<TItem>[] {\n\tlet truncateWinner: CoalescedRangePatchMessage<TItem> | undefined;\n\tconst byRow = new Map<string | number, CoalescedRangePatchMessage<TItem>>();\n\tfor (const p of patches) {\n\t\tconst ch = p.change;\n\t\tswitch (ch.type) {\n\t\t\tcase \"truncate\":\n\t\t\t\ttruncateWinner = p;\n\t\t\t\tbyRow.clear();\n\t\t\t\tbreak;\n\t\t\tcase \"insert\":\n\t\t\tcase \"update\": {\n\t\t\t\tconst k = partialSyncRowKey(ch.value.id);\n\t\t\t\tbyRow.set(k, p);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"delete\":\n\t\t\t\tbyRow.set(ch.key, p);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\texhaustiveGuard(ch);\n\t\t}\n\t}\n\tif (truncateWinner !== undefined) return [truncateWinner];\n\treturn [...byRow.values()];\n}\n\nexport function connectPartialSync<\n\tTItem extends PartialSyncRowShape = PartialSyncRowShape,\n>(\n\tbridge: PartialSyncClientBridge<TItem>,\n\toptions: ConnectPartialSyncOptions<TItem>,\n): () => void {\n\tconst clientSchema = createClientMessageSchema();\n\tconst serverSchema = createServerMessageSchema<TItem>();\n\tconst useMsgpack = options.transport === \"msgpack\";\n\tconst mutationBridge = options.mutationBridge;\n\t/**\n\t * Serialized inbound handling without chaining `.then` per message (that grows the promise graph\n\t * linearly with traffic → accumulating latency, memory pressure, and eventual tab crashes).\n\t */\n\ttype InboundJob = () => Promise<void>;\n\tconst inboundWorkQueue: InboundJob[] = [];\n\tlet inboundPumpRunning = false;\n\tlet connectDisposed = false;\n\n\t/**\n\t * Single pump: drain all queued jobs, then **await** `flushPendingCoalescedInboundUpdates` so\n\t * coalesced `rangePatch` rows are applied before the next drain pass (prevents duplicate-insert\n\t * from `ack`/`syncBatch`). If new jobs arrived during the flush, loop.\n\t *\n\t * Only one pump runs at a time (`inboundPumpRunning`). Unlike the earlier version that left\n\t * the flag set while awaiting a potentially-stalled flush, the flag is reset in a `finally`\n\t * that runs **after** both the drain and the flush, and errors are caught per-job so one\n\t * failure cannot block subsequent work.\n\t */\n\tconst runInboundPump = async (): Promise<void> => {\n\t\tif (inboundPumpRunning) return;\n\t\tinboundPumpRunning = true;\n\t\ttry {\n\t\t\tdo {\n\t\t\t\twhile (inboundWorkQueue.length > 0) {\n\t\t\t\t\tconst job = inboundWorkQueue.shift();\n\t\t\t\t\tif (job === undefined) continue;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait job();\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.error(\"[connectPartialSync] inbound job error\", err);\n\t\t\t\t\t}\n\t\t\t\t\tif (connectDisposed) return;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait bridge.flushPendingCoalescedInboundUpdates();\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(\"[connectPartialSync] coalesced flush error\", err);\n\t\t\t\t}\n\t\t\t} while (!connectDisposed && inboundWorkQueue.length > 0);\n\t\t} finally {\n\t\t\tinboundPumpRunning = false;\n\t\t\tif (!connectDisposed && inboundWorkQueue.length > 0) {\n\t\t\t\tvoid runInboundPump();\n\t\t\t}\n\t\t}\n\t};\n\n\tconst enqueueInbound = (job: InboundJob): void => {\n\t\tinboundWorkQueue.push(job);\n\t\tvoid runInboundPump();\n\t};\n\n\tlet rangePatchCoalesceBuffer: CoalescedRangePatchMessage<TItem>[] = [];\n\t/**\n\t * `requestAnimationFrame` can run between WebSocket deliveries, flushing a single `rangePatch`\n\t * while more patches are still queued on the inbound chain — causing duplicate `receiveSync`\n\t * and stepped replay. A deduped microtask flush runs after the current sync work so bursts\n\t * in the same turn coalesce before paint.\n\t */\n\tlet rangePatchFlushMicrotaskQueued = false;\n\n\tconst drainRangePatchCoalesceBuffer = async (): Promise<void> => {\n\t\tif (rangePatchCoalesceBuffer.length === 0) return;\n\t\tconst merged = mergeCoalescedRangePatches(rangePatchCoalesceBuffer);\n\t\trangePatchCoalesceBuffer = [];\n\t\tfor (const m of merged) {\n\t\t\tawait dispatchPartialSyncServerMessage(m, bridge, mutationBridge);\n\t\t}\n\t};\n\n\tconst scheduleCoalescedRangePatchFlushMicrotask = (): void => {\n\t\tif (rangePatchFlushMicrotaskQueued) return;\n\t\trangePatchFlushMicrotaskQueued = true;\n\t\tqueueMicrotask(() => {\n\t\t\trangePatchFlushMicrotaskQueued = false;\n\t\t\tenqueueInbound(async () => {\n\t\t\t\tawait drainRangePatchCoalesceBuffer();\n\t\t\t});\n\t\t});\n\t};\n\n\tconst cancelCoalescedRangePatchDeferredFlush = (): void => {\n\t\trangePatchFlushMicrotaskQueued = false;\n\t};\n\n\tconst flushCoalescedRangePatchesInline = async (): Promise<void> => {\n\t\tcancelCoalescedRangePatchDeferredFlush();\n\t\tawait drainRangePatchCoalesceBuffer();\n\t};\n\n\tconst schemaClient = new StandardSchemaWebSocketClient({\n\t\turl: options.url,\n\t\tclientSchema,\n\t\tserverSchema,\n\t\tenableBufferMessages: useMsgpack,\n\t\t...(useMsgpack\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tserializeJson: options.serializeJson ?? JSON.stringify,\n\t\t\t\t\tdeserializeJson: options.deserializeJson ?? JSON.parse,\n\t\t\t\t}),\n\t\tonMessage: (msg) => {\n\t\t\tenqueueInbound(async () => {\n\t\t\t\toptions.onServerMessage?.(msg);\n\t\t\t\tif (mutationBridge === undefined) {\n\t\t\t\t\tawait dispatchPartialSyncServerMessage(msg, bridge, mutationBridge);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst mid = msg.collectionId ?? DEFAULT_SYNC_COLLECTION_ID;\n\t\t\t\tconst forPartial = mid === bridge.collectionId;\n\t\t\t\tif (msg.type === \"rangePatch\" && forPartial) {\n\t\t\t\t\trangePatchCoalesceBuffer.push(msg);\n\t\t\t\t\tscheduleCoalescedRangePatchFlushMicrotask();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait flushCoalescedRangePatchesInline();\n\t\t\t\tawait dispatchPartialSyncServerMessage(msg, bridge, mutationBridge);\n\t\t\t});\n\t\t},\n\t});\n\n\t/** DO not call `WebSocket.send` until `OPEN`; queue outbound messages until then. */\n\tconst pendingOutbound: SyncClientMessage[] = [];\n\n\tconst flushPendingOutbound = () => {\n\t\twhile (\n\t\t\tpendingOutbound.length > 0 &&\n\t\t\tschemaClient.socket.readyState === WebSocket.OPEN\n\t\t) {\n\t\t\tconst message = pendingOutbound.shift();\n\t\t\tif (message !== undefined) {\n\t\t\t\tvoid schemaClient.send(message).catch((err: unknown) => {\n\t\t\t\t\tconsole.error(\"[connectPartialSync] WebSocket send failed\", err);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\n\toptions.setTransportSend((message) => {\n\t\tif (schemaClient.socket.readyState === WebSocket.OPEN) {\n\t\t\tvoid schemaClient.send(message).catch((err: unknown) => {\n\t\t\t\tconsole.error(\"[connectPartialSync] WebSocket send failed\", err);\n\t\t\t});\n\t\t} else {\n\t\t\tpendingOutbound.push(message);\n\t\t}\n\t});\n\n\tbridge.setConnecting();\n\n\tconst onOpen = () => {\n\t\tflushPendingOutbound();\n\t\tbridge.setConnected(true);\n\t\tmutationBridge?.setConnected(true);\n\t};\n\tconst onClose = () => {\n\t\tpendingOutbound.length = 0;\n\t\tbridge.setConnected(false);\n\t\tmutationBridge?.setConnected(false);\n\t};\n\n\tschemaClient.socket.addEventListener(\"open\", onOpen);\n\tschemaClient.socket.addEventListener(\"close\", onClose);\n\n\tif (schemaClient.socket.readyState === WebSocket.OPEN) {\n\t\tonOpen();\n\t}\n\n\tconst onVisibilityFlush = (): void => {\n\t\tconst doc = pageVisibilityDocument();\n\t\tif (doc === undefined) return;\n\t\tif (doc.visibilityState !== \"visible\") return;\n\t\tenqueueInbound(async () => {\n\t\t\tawait flushCoalescedRangePatchesInline();\n\t\t});\n\t};\n\n\tconst visibilityDoc = pageVisibilityDocument();\n\tif (visibilityDoc !== undefined) {\n\t\tvisibilityDoc.addEventListener(\"visibilitychange\", onVisibilityFlush);\n\t}\n\n\treturn () => {\n\t\tconnectDisposed = true;\n\t\tconst docCleanup = pageVisibilityDocument();\n\t\tif (docCleanup !== undefined) {\n\t\t\tdocCleanup.removeEventListener(\"visibilitychange\", onVisibilityFlush);\n\t\t}\n\t\tcancelCoalescedRangePatchDeferredFlush();\n\t\tinboundWorkQueue.length = 0;\n\t\trangePatchCoalesceBuffer = [];\n\t\tschemaClient.socket.removeEventListener(\"open\", onOpen);\n\t\tschemaClient.socket.removeEventListener(\"close\", onClose);\n\t\tpendingOutbound.length = 0;\n\t\tbridge.setConnected(false);\n\t\tmutationBridge?.setConnected(false);\n\t\toptions.setTransportSend(() => {});\n\t\tschemaClient.close();\n\t};\n}\n"]}
@@ -0,0 +1,125 @@
1
+ import { buildRangeConditionsAndExpression } from './chunk-43KYAIKY.js';
2
+ import { DEFAULT_PAGE_LIMIT } from './chunk-M5MJHS6A.js';
3
+ import { inArray } from '@tanstack/db';
4
+ import { useLiveQuery } from '@tanstack/react-db';
5
+ import { useMemo } from 'react';
6
+
7
+ var PIN_IDS_SEP = "\0";
8
+ function compareByPartialSort(a, b, sort, getSortValue) {
9
+ const va = getSortValue(a, sort.column);
10
+ const vb = getSortValue(b, sort.column);
11
+ let primary = 0;
12
+ if (typeof va === "number" && typeof vb === "number") {
13
+ if (va < vb) primary = -1;
14
+ else if (va > vb) primary = 1;
15
+ } else {
16
+ const sa = String(va);
17
+ const sb = String(vb);
18
+ if (sa < sb) primary = -1;
19
+ else if (sa > sb) primary = 1;
20
+ }
21
+ if (primary !== 0) {
22
+ return sort.direction === "desc" ? -primary : primary;
23
+ }
24
+ return String(a.id).localeCompare(String(b.id));
25
+ }
26
+ function usePredicateFilteredRows({
27
+ collection,
28
+ conditions,
29
+ sort,
30
+ getSortValue,
31
+ getColumnValue: _getColumnValue,
32
+ limit = DEFAULT_PAGE_LIMIT,
33
+ cacheDisplayMode = "immediate",
34
+ confirmedRowKeys,
35
+ confirmedKeysRevision = 0,
36
+ alwaysIncludeRowIds
37
+ }) {
38
+ const conditionsKey = useMemo(() => JSON.stringify(conditions), [conditions]);
39
+ const pinIdsSerialized = alwaysIncludeRowIds === void 0 || alwaysIncludeRowIds.length === 0 ? "" : [...new Set([...alwaysIncludeRowIds].map(String))].sort().join(PIN_IDS_SEP);
40
+ const { data } = useLiveQuery(
41
+ (q) => {
42
+ if (cacheDisplayMode === "confirmed" && (confirmedRowKeys === void 0 || confirmedRowKeys.size === 0)) {
43
+ return null;
44
+ }
45
+ let query = q.from({ items: collection });
46
+ if (conditions.length > 0) {
47
+ query = query.where(
48
+ (refs) => buildRangeConditionsAndExpression(
49
+ refs.items,
50
+ conditions
51
+ )
52
+ );
53
+ }
54
+ if (cacheDisplayMode === "confirmed" && confirmedRowKeys !== void 0) {
55
+ const keys = [...confirmedRowKeys];
56
+ query = query.where(
57
+ (refs) => inArray(refs.items.id, keys)
58
+ );
59
+ }
60
+ query = query.orderBy(
61
+ (refs) => refs.items[sort.column],
62
+ sort.direction
63
+ );
64
+ return query.limit(limit);
65
+ },
66
+ [
67
+ collection,
68
+ conditionsKey,
69
+ sort.column,
70
+ sort.direction,
71
+ limit,
72
+ cacheDisplayMode,
73
+ confirmedKeysRevision,
74
+ confirmedRowKeys
75
+ ]
76
+ );
77
+ const { data: pinnedData } = useLiveQuery(
78
+ (q) => {
79
+ if (pinIdsSerialized === "") return null;
80
+ if (cacheDisplayMode === "confirmed" && (confirmedRowKeys === void 0 || confirmedRowKeys.size === 0)) {
81
+ return null;
82
+ }
83
+ const pinKeys = pinIdsSerialized.split(PIN_IDS_SEP);
84
+ let query = q.from({ items: collection });
85
+ if (cacheDisplayMode === "confirmed" && confirmedRowKeys !== void 0) {
86
+ const keys = [...confirmedRowKeys];
87
+ query = query.where(
88
+ (refs) => inArray(refs.items.id, keys)
89
+ );
90
+ }
91
+ query = query.where(
92
+ (refs) => inArray(refs.items.id, pinKeys)
93
+ );
94
+ query = query.orderBy(
95
+ (refs) => refs.items[sort.column],
96
+ sort.direction
97
+ );
98
+ return query.limit(pinKeys.length);
99
+ },
100
+ [
101
+ collection,
102
+ pinIdsSerialized,
103
+ sort.column,
104
+ sort.direction,
105
+ cacheDisplayMode,
106
+ confirmedKeysRevision,
107
+ confirmedRowKeys
108
+ ]
109
+ );
110
+ const predicateRows = data ?? [];
111
+ const pinnedRows = pinnedData ?? [];
112
+ return useMemo(() => {
113
+ if (pinIdsSerialized === "") return predicateRows;
114
+ const map = /* @__PURE__ */ new Map();
115
+ for (const r of predicateRows) map.set(String(r.id), r);
116
+ for (const r of pinnedRows) map.set(String(r.id), r);
117
+ const merged = [...map.values()];
118
+ merged.sort((a, b) => compareByPartialSort(a, b, sort, getSortValue));
119
+ return merged;
120
+ }, [predicateRows, pinnedRows, pinIdsSerialized, sort, getSortValue]);
121
+ }
122
+
123
+ export { usePredicateFilteredRows };
124
+ //# sourceMappingURL=chunk-YD5LVGWX.js.map
125
+ //# sourceMappingURL=chunk-YD5LVGWX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/usePredicateFilteredRows.ts"],"names":[],"mappings":"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","file":"chunk-YD5LVGWX.js","sourcesContent":["import { inArray } from \"@tanstack/db\";\nimport { useLiveQuery } from \"@tanstack/react-db\";\nimport { useMemo } from \"react\";\nimport { DEFAULT_PAGE_LIMIT } from \"./constants\";\nimport {\n\tbuildRangeConditionsAndExpression,\n\ttype PredicateRowRef,\n} from \"./range-conditions-expression\";\nimport type { PartialSyncItem, UsePredicateFilteredRowsOptions } from \"./types\";\n\nconst PIN_IDS_SEP = \"\\u0000\";\n\nfunction compareByPartialSort<\n\tTItem extends PartialSyncItem,\n\tTSortColumn extends keyof TItem & string,\n>(\n\ta: TItem,\n\tb: TItem,\n\tsort: { column: TSortColumn; direction: \"asc\" | \"desc\" },\n\tgetSortValue: (row: TItem, column: TSortColumn) => unknown,\n): number {\n\tconst va = getSortValue(a, sort.column);\n\tconst vb = getSortValue(b, sort.column);\n\tlet primary = 0;\n\tif (typeof va === \"number\" && typeof vb === \"number\") {\n\t\tif (va < vb) primary = -1;\n\t\telse if (va > vb) primary = 1;\n\t} else {\n\t\tconst sa = String(va);\n\t\tconst sb = String(vb);\n\t\tif (sa < sb) primary = -1;\n\t\telse if (sa > sb) primary = 1;\n\t}\n\tif (primary !== 0) {\n\t\treturn sort.direction === \"desc\" ? -primary : primary;\n\t}\n\treturn String(a.id).localeCompare(String(b.id));\n}\n\n/**\n * Reactive predicate filter + sort + limit via TanStack DB `useLiveQuery` (IVM), instead of\n * scanning the whole collection on each change.\n */\nexport function usePredicateFilteredRows<\n\tTItem extends PartialSyncItem,\n\tTSortColumn extends keyof TItem & string,\n>({\n\tcollection,\n\tconditions,\n\tsort,\n\tgetSortValue,\n\tgetColumnValue: _getColumnValue,\n\tlimit = DEFAULT_PAGE_LIMIT,\n\tcacheDisplayMode = \"immediate\",\n\tconfirmedRowKeys,\n\tconfirmedKeysRevision = 0,\n\talwaysIncludeRowIds,\n}: UsePredicateFilteredRowsOptions<TItem, TSortColumn>): TItem[] {\n\tvoid _getColumnValue;\n\n\tconst conditionsKey = useMemo(() => JSON.stringify(conditions), [conditions]);\n\n\tconst pinIdsSerialized =\n\t\talwaysIncludeRowIds === undefined || alwaysIncludeRowIds.length === 0\n\t\t\t? \"\"\n\t\t\t: [...new Set([...alwaysIncludeRowIds].map(String))]\n\t\t\t\t\t.sort()\n\t\t\t\t\t.join(PIN_IDS_SEP);\n\n\tconst { data } = useLiveQuery(\n\t\t(q) => {\n\t\t\tif (\n\t\t\t\tcacheDisplayMode === \"confirmed\" &&\n\t\t\t\t(confirmedRowKeys === undefined || confirmedRowKeys.size === 0)\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlet query = q.from({ items: collection });\n\n\t\t\tif (conditions.length > 0) {\n\t\t\t\tquery = query.where((refs) =>\n\t\t\t\t\tbuildRangeConditionsAndExpression(\n\t\t\t\t\t\trefs.items as PredicateRowRef,\n\t\t\t\t\t\tconditions,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (cacheDisplayMode === \"confirmed\" && confirmedRowKeys !== undefined) {\n\t\t\t\tconst keys = [...confirmedRowKeys];\n\t\t\t\tquery = query.where((refs) =>\n\t\t\t\t\tinArray((refs.items as PredicateRowRef).id, keys),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tquery = query.orderBy(\n\t\t\t\t(refs) => (refs.items as PredicateRowRef)[sort.column],\n\t\t\t\tsort.direction,\n\t\t\t);\n\t\t\treturn query.limit(limit);\n\t\t},\n\t\t[\n\t\t\tcollection,\n\t\t\tconditionsKey,\n\t\t\tsort.column,\n\t\t\tsort.direction,\n\t\t\tlimit,\n\t\t\tcacheDisplayMode,\n\t\t\tconfirmedKeysRevision,\n\t\t\tconfirmedRowKeys,\n\t\t],\n\t);\n\n\tconst { data: pinnedData } = useLiveQuery(\n\t\t(q) => {\n\t\t\tif (pinIdsSerialized === \"\") return null;\n\t\t\tif (\n\t\t\t\tcacheDisplayMode === \"confirmed\" &&\n\t\t\t\t(confirmedRowKeys === undefined || confirmedRowKeys.size === 0)\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst pinKeys = pinIdsSerialized.split(PIN_IDS_SEP);\n\n\t\t\tlet query = q.from({ items: collection });\n\n\t\t\tif (cacheDisplayMode === \"confirmed\" && confirmedRowKeys !== undefined) {\n\t\t\t\tconst keys = [...confirmedRowKeys];\n\t\t\t\tquery = query.where((refs) =>\n\t\t\t\t\tinArray((refs.items as PredicateRowRef).id, keys),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tquery = query.where((refs) =>\n\t\t\t\tinArray((refs.items as PredicateRowRef).id, pinKeys),\n\t\t\t);\n\n\t\t\tquery = query.orderBy(\n\t\t\t\t(refs) => (refs.items as PredicateRowRef)[sort.column],\n\t\t\t\tsort.direction,\n\t\t\t);\n\t\t\treturn query.limit(pinKeys.length);\n\t\t},\n\t\t[\n\t\t\tcollection,\n\t\t\tpinIdsSerialized,\n\t\t\tsort.column,\n\t\t\tsort.direction,\n\t\t\tcacheDisplayMode,\n\t\t\tconfirmedKeysRevision,\n\t\t\tconfirmedRowKeys,\n\t\t],\n\t);\n\n\tconst predicateRows = (data ?? []) as TItem[];\n\tconst pinnedRows = (pinnedData ?? []) as TItem[];\n\n\treturn useMemo(() => {\n\t\tif (pinIdsSerialized === \"\") return predicateRows;\n\t\tconst map = new Map<string, TItem>();\n\t\tfor (const r of predicateRows) map.set(String(r.id), r);\n\t\tfor (const r of pinnedRows) map.set(String(r.id), r);\n\t\tconst merged = [...map.values()];\n\t\tmerged.sort((a, b) => compareByPartialSort(a, b, sort, getSortValue));\n\t\treturn merged;\n\t}, [predicateRows, pinnedRows, pinIdsSerialized, sort, getSortValue]);\n}\n"]}
@@ -0,0 +1,166 @@
1
+ import { SyncClientBridge } from './chunk-QJP4GSJH.js';
2
+
3
+ // src/with-sync.ts
4
+ function getBrowserLocalStorageSyncStateStorage() {
5
+ const g = globalThis;
6
+ const ls = g.localStorage;
7
+ if (!ls || typeof ls.getItem !== "function") return null;
8
+ return ls;
9
+ }
10
+ function resolveSyncStateStorage(syncOptions) {
11
+ if (typeof syncOptions?.syncStateKey !== "string") return null;
12
+ if (syncOptions.syncStateStorage !== void 0) {
13
+ return syncOptions.syncStateStorage;
14
+ }
15
+ return getBrowserLocalStorageSyncStateStorage();
16
+ }
17
+ function readPersistedSyncState(key, storage) {
18
+ if (!storage) return null;
19
+ try {
20
+ const raw = storage.getItem(key);
21
+ if (!raw) return null;
22
+ const parsed = JSON.parse(raw);
23
+ if (typeof parsed.clientId !== "string") return null;
24
+ return {
25
+ clientId: parsed.clientId,
26
+ lastAckedServerVersion: typeof parsed.lastAckedServerVersion === "number" ? parsed.lastAckedServerVersion : 0
27
+ };
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ function writePersistedSyncState(key, storage, state) {
33
+ if (!storage) return;
34
+ try {
35
+ storage.setItem(key, JSON.stringify(state));
36
+ } catch {
37
+ }
38
+ }
39
+ function withSync(baseOptions, syncOptions) {
40
+ const syncStateKey = syncOptions?.syncStateKey;
41
+ const syncStateStorage = resolveSyncStateStorage(syncOptions);
42
+ const persisted = typeof syncStateKey === "string" ? readPersistedSyncState(syncStateKey, syncStateStorage) : null;
43
+ const shouldPersistLastAckedServerVersion = syncOptions?.persistLastAckedServerVersion ?? (typeof syncStateKey === "string" && syncStateStorage !== null);
44
+ const clientId = persisted?.clientId ?? `client-${crypto.randomUUID()}`;
45
+ const persistedLastAcked = persisted?.lastAckedServerVersion ?? 0;
46
+ let lastAckedServerVersion = shouldPersistLastAckedServerVersion ? persistedLastAcked : 0;
47
+ if (typeof syncStateKey === "string") {
48
+ writePersistedSyncState(syncStateKey, syncStateStorage, {
49
+ clientId,
50
+ lastAckedServerVersion: shouldPersistLastAckedServerVersion ? lastAckedServerVersion : persistedLastAcked
51
+ });
52
+ }
53
+ let transportSend = () => {
54
+ };
55
+ const forwardTruncateToMutations = syncOptions?.forwardTruncateToMutations ?? true;
56
+ const originalReceiveSync = baseOptions.utils.receiveSync.bind(
57
+ baseOptions.utils
58
+ );
59
+ const originalTruncate = baseOptions.utils.truncate.bind(baseOptions.utils);
60
+ const bridge = new SyncClientBridge({
61
+ clientId,
62
+ ...syncOptions?.collectionId !== void 0 ? { collectionId: syncOptions.collectionId } : {},
63
+ collection: {
64
+ utils: {
65
+ receiveSync: originalReceiveSync
66
+ }
67
+ },
68
+ send: (message) => transportSend(message),
69
+ initialLastAckedServerVersion: lastAckedServerVersion,
70
+ onLastAckedServerVersionChange: (version) => {
71
+ lastAckedServerVersion = Math.max(lastAckedServerVersion, version);
72
+ if (typeof syncStateKey === "string") {
73
+ writePersistedSyncState(syncStateKey, syncStateStorage, {
74
+ clientId,
75
+ lastAckedServerVersion
76
+ });
77
+ }
78
+ },
79
+ onRejectedMutation: syncOptions?.onRejectedMutation,
80
+ sendSyncHelloOnConnect: syncOptions?.sendSyncHelloOnConnect
81
+ });
82
+ const throttleMs = syncOptions?.localMutationThrottleMs;
83
+ let mutationThrottleBuffer = [];
84
+ let mutationThrottleTimer = null;
85
+ const flushMutationThrottle = () => {
86
+ mutationThrottleTimer = null;
87
+ if (mutationThrottleBuffer.length === 0) return;
88
+ const batch = mutationThrottleBuffer;
89
+ mutationThrottleBuffer = [];
90
+ bridge.onLocalMutation(batch);
91
+ };
92
+ const emitLocalMutation = (writes) => {
93
+ if (throttleMs === void 0 || throttleMs <= 0 || writes.some((w) => w.type === "truncate")) {
94
+ if (mutationThrottleTimer !== null) {
95
+ clearTimeout(mutationThrottleTimer);
96
+ mutationThrottleTimer = null;
97
+ flushMutationThrottle();
98
+ }
99
+ bridge.onLocalMutation(writes);
100
+ return;
101
+ }
102
+ mutationThrottleBuffer.push(...writes);
103
+ if (mutationThrottleTimer !== null) {
104
+ clearTimeout(mutationThrottleTimer);
105
+ }
106
+ mutationThrottleTimer = setTimeout(flushMutationThrottle, throttleMs);
107
+ };
108
+ const onInsert = baseOptions.onInsert ? async (params) => {
109
+ const writes = params.transaction.mutations.map(
110
+ (mutation) => ({
111
+ type: "insert",
112
+ value: mutation.modified
113
+ })
114
+ );
115
+ emitLocalMutation(writes);
116
+ await baseOptions.onInsert?.(params);
117
+ } : void 0;
118
+ const onUpdate = baseOptions.onUpdate ? async (params) => {
119
+ const writes = params.transaction.mutations.map(
120
+ (mutation) => ({
121
+ type: "update",
122
+ value: mutation.modified,
123
+ previousValue: mutation.original
124
+ })
125
+ );
126
+ emitLocalMutation(writes);
127
+ await baseOptions.onUpdate?.(params);
128
+ } : void 0;
129
+ const onDelete = baseOptions.onDelete ? async (params) => {
130
+ const writes = params.transaction.mutations.map(
131
+ (mutation) => ({
132
+ type: "delete",
133
+ key: mutation.key
134
+ })
135
+ );
136
+ emitLocalMutation(writes);
137
+ await baseOptions.onDelete?.(params);
138
+ } : void 0;
139
+ const utils = {
140
+ ...baseOptions.utils,
141
+ truncate: async () => {
142
+ await originalTruncate();
143
+ if (forwardTruncateToMutations) {
144
+ emitLocalMutation([{ type: "truncate" }]);
145
+ }
146
+ }
147
+ };
148
+ const options = {
149
+ ...baseOptions,
150
+ ...onInsert !== void 0 ? { onInsert } : {},
151
+ ...onUpdate !== void 0 ? { onUpdate } : {},
152
+ ...onDelete !== void 0 ? { onDelete } : {},
153
+ utils
154
+ };
155
+ return {
156
+ options,
157
+ bridge,
158
+ setTransportSend: (send) => {
159
+ transportSend = send;
160
+ }
161
+ };
162
+ }
163
+
164
+ export { getBrowserLocalStorageSyncStateStorage, withSync };
165
+ //# sourceMappingURL=chunk-YYGPIHHJ.js.map
166
+ //# sourceMappingURL=chunk-YYGPIHHJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-sync.ts"],"names":[],"mappings":"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","file":"chunk-YYGPIHHJ.js","sourcesContent":["import type { SyncMessage } from \"@firtoz/db-helpers\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type {\n\tCollectionConfig,\n\tNonSingleResult,\n\tUtilsRecord,\n} from \"@tanstack/db\";\nimport { SyncClientBridge } from \"./sync-client-bridge\";\nimport type { PartialSyncRowShape } from \"./partial-sync-row-key\";\nimport type { SyncClientMessage } from \"./sync-protocol\";\n\n/**\n * Sync cursor persistence (see {@link WithSyncOptions}):\n *\n * - **Ephemeral collections** (in-memory only, no durable row storage): omit `syncStateKey`.\n * Each load gets a new `clientId` and `lastAckedServerVersion: 0`, so the server answers with a\n * **full snapshot** backfill — correct because local rows do not survive refresh.\n *\n * - **Durable collections** (IndexedDB, sqlite-wasm, etc.): set `syncStateKey` (and default storage).\n * `persistLastAckedServerVersion` defaults to **true**, so reconnect sends the last acked server\n * version and the server can return **delta** backfill when the changelog allows.\n *\n * - To keep a stable `clientId` in storage but **always** request a full snapshot (rare), set\n * `syncStateKey` and `persistLastAckedServerVersion: false`.\n */\n\n/** Row shape required for sync (matches {@link SyncClientBridge}). */\nexport type SyncableCollectionItem = PartialSyncRowShape;\n\n/**\n * Key/value persistence for sync metadata (`clientId`, `lastAckedServerVersion`).\n * Same shape as `Storage`; use `localStorage`, `sessionStorage`, a `Map` adapter, etc.\n */\nexport type SyncStateStorage = {\n\tgetItem(key: string): string | null;\n\tsetItem(key: string, value: string): void;\n};\n\nexport type WithSyncOptions = {\n\t/**\n\t * If set, sync metadata (`clientId`, optionally `lastAckedServerVersion`) is read/written via\n\t * {@link syncStateStorage} or `localStorage`. Omit for ephemeral collections (e.g. memory) so\n\t * every load handshakes as a fresh client with a full snapshot — see module note above.\n\t */\n\tsyncStateKey?: string;\n\t/**\n\t * Where to read/write {@link syncStateKey}. Defaults to `globalThis.localStorage` when `syncStateKey` is set and this is omitted.\n\t * Pass `null` to skip persistence even when `syncStateKey` is set (e.g. tests).\n\t */\n\tsyncStateStorage?: SyncStateStorage | null;\n\t/**\n\t * Persist and reuse lastAcked server version across page reloads (enables delta backfill on reconnect).\n\t * Defaults to `true` when {@link syncStateKey} is set and a storage backend is resolved; set `false` to always handshake with `lastAckedServerVersion: 0` (full snapshot). When `false`, existing stored `lastAckedServerVersion` is preserved in storage so it is not wiped on load.\n\t */\n\tpersistLastAckedServerVersion?: boolean;\n\tonRejectedMutation?: (reason: string, mutationId: string) => void;\n\t/**\n\t * When `false`, the bridge does not send `syncHello` on connect (use with partial sync + `mutateBatch`).\n\t * Default `true`.\n\t */\n\tsendSyncHelloOnConnect?: boolean;\n\t/**\n\t * When `false`, local {@link CollectionConfig.utils.truncate} clears storage only — it does **not**\n\t * enqueue a `truncate` for the next `mutateBatch`. Partial sync calls truncate on window reset; forwarding\n\t * it would batch with unrelated user edits and make the server apply `truncate` + `update`, wiping data.\n\t * Default `true` (full sync). {@link createPartialSyncedCollection} sets this to `false`.\n\t */\n\tforwardTruncateToMutations?: boolean;\n\t/**\n\t * Must match the server's {@link SyncServerBridgeOptions.collectionId} on the same WebSocket.\n\t */\n\tcollectionId?: string;\n\t/**\n\t * When set to a positive number (milliseconds), local mutation batches are debounced: each\n\t * burst merges into one `onLocalMutation` call after this many milliseconds of quiet time.\n\t * `truncate` messages flush any pending batch immediately and are not delayed.\n\t */\n\tlocalMutationThrottleMs?: number;\n};\n\n/** Returns `globalThis.localStorage` when it looks usable; otherwise `null`. */\nexport function getBrowserLocalStorageSyncStateStorage(): SyncStateStorage | null {\n\tconst g = globalThis as typeof globalThis & {\n\t\tlocalStorage?: SyncStateStorage;\n\t};\n\tconst ls = g.localStorage;\n\tif (!ls || typeof ls.getItem !== \"function\") return null;\n\treturn ls;\n}\n\nfunction resolveSyncStateStorage(\n\tsyncOptions: WithSyncOptions | undefined,\n): SyncStateStorage | null {\n\tif (typeof syncOptions?.syncStateKey !== \"string\") return null;\n\tif (syncOptions.syncStateStorage !== undefined) {\n\t\treturn syncOptions.syncStateStorage;\n\t}\n\treturn getBrowserLocalStorageSyncStateStorage();\n}\n\n/**\n * Infer the collection row type from options passed to {@link withSync} / {@link createSyncedCollection}.\n * Prefer `CollectionConfig`'s first type parameter (the select row). That matches Drizzle SQLite configs\n * where `schema` is an insert schema whose {@link InferSchemaOutput} can differ from the row type.\n */\nexport type InferItemFromCollectionOptions<T> = T extends Omit<\n\tCollectionConfig<infer TItem, infer _K, infer _S, infer _U>,\n\t\"utils\"\n> & { utils: UtilsRecord }\n\t? TItem\n\t: T extends WithSyncableCollectionConfig<\n\t\t\t\tinfer TItem,\n\t\t\t\tinfer _K,\n\t\t\t\tinfer _S,\n\t\t\t\tinfer _U\n\t\t\t>\n\t\t? TItem\n\t\t: T extends CollectionConfig<\n\t\t\t\t\tinfer TItem,\n\t\t\t\t\tinfer _TKey,\n\t\t\t\t\tinfer _TSchema,\n\t\t\t\t\tinfer _TUtils\n\t\t\t\t>\n\t\t\t? TItem\n\t\t\t: T extends { getKey: (item: infer I) => unknown }\n\t\t\t\t? I\n\t\t\t\t: never;\n\n/**\n * Any TanStack {@link CollectionConfig} (from memory / IndexedDB / SQLite helpers, etc.)\n * that is not a single-row collection. Requires `utils` (sync backends always provide it).\n */\nexport type WithSyncableCollectionConfig<\n\tTItem extends SyncableCollectionItem = SyncableCollectionItem,\n\tTKey extends string | number = string | number,\n\tTSchema extends StandardSchemaV1 = never,\n\tTUtils extends UtilsRecord = UtilsRecord,\n> = Omit<CollectionConfig<TItem, TKey, TSchema, TUtils>, \"utils\"> &\n\tNonSingleResult & {\n\t\tutils: TUtils;\n\t};\n\ntype PersistedSyncState = {\n\tclientId: string;\n\tlastAckedServerVersion: number;\n};\n\nfunction readPersistedSyncState(\n\tkey: string,\n\tstorage: SyncStateStorage | null,\n): PersistedSyncState | null {\n\tif (!storage) return null;\n\ttry {\n\t\tconst raw = storage.getItem(key);\n\t\tif (!raw) return null;\n\t\tconst parsed = JSON.parse(raw) as Partial<PersistedSyncState>;\n\t\tif (typeof parsed.clientId !== \"string\") return null;\n\t\treturn {\n\t\t\tclientId: parsed.clientId,\n\t\t\tlastAckedServerVersion:\n\t\t\t\ttypeof parsed.lastAckedServerVersion === \"number\"\n\t\t\t\t\t? parsed.lastAckedServerVersion\n\t\t\t\t\t: 0,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction writePersistedSyncState(\n\tkey: string,\n\tstorage: SyncStateStorage | null,\n\tstate: PersistedSyncState,\n): void {\n\tif (!storage) return;\n\ttry {\n\t\tstorage.setItem(key, JSON.stringify(state));\n\t} catch {\n\t\t// ignore quota / private mode\n\t}\n}\n\n/**\n * Wraps TanStack DB collection options so local mutations are forwarded to {@link SyncClientBridge}.\n * Pair with {@link connectSync} or {@link createSyncedCollection} to attach a WebSocket transport.\n *\n * Row type is inferred from your collection config via {@link InferItemFromCollectionOptions}.\n */\n/** Widened config union from memory / Drizzle / IndexedDB helpers. */\nexport type AnyWithSyncableCollectionConfig = WithSyncableCollectionConfig<\n\t// biome-ignore lint/suspicious/noExplicitAny: item type slot for heterogeneous backends\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: key type slot\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: schema type slot\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: utils type slot\n\tany\n>;\n\nexport function withSync<TConfig extends AnyWithSyncableCollectionConfig>(\n\tbaseOptions: TConfig,\n\tsyncOptions?: WithSyncOptions,\n): {\n\toptions: TConfig;\n\tbridge: SyncClientBridge<InferItemFromCollectionOptions<TConfig>>;\n\tsetTransportSend: (send: (msg: SyncClientMessage) => void) => void;\n} {\n\ttype TItem = InferItemFromCollectionOptions<TConfig>;\n\n\tconst syncStateKey = syncOptions?.syncStateKey;\n\tconst syncStateStorage = resolveSyncStateStorage(syncOptions);\n\n\tconst persisted =\n\t\ttypeof syncStateKey === \"string\"\n\t\t\t? readPersistedSyncState(syncStateKey, syncStateStorage)\n\t\t\t: null;\n\tconst shouldPersistLastAckedServerVersion =\n\t\tsyncOptions?.persistLastAckedServerVersion ??\n\t\t(typeof syncStateKey === \"string\" && syncStateStorage !== null);\n\tconst clientId = persisted?.clientId ?? `client-${crypto.randomUUID()}`;\n\tconst persistedLastAcked = persisted?.lastAckedServerVersion ?? 0;\n\tlet lastAckedServerVersion = shouldPersistLastAckedServerVersion\n\t\t? persistedLastAcked\n\t\t: 0;\n\tif (typeof syncStateKey === \"string\") {\n\t\twritePersistedSyncState(syncStateKey, syncStateStorage, {\n\t\t\tclientId,\n\t\t\tlastAckedServerVersion: shouldPersistLastAckedServerVersion\n\t\t\t\t? lastAckedServerVersion\n\t\t\t\t: persistedLastAcked,\n\t\t});\n\t}\n\n\tlet transportSend: (msg: SyncClientMessage) => void = () => {};\n\n\tconst forwardTruncateToMutations =\n\t\tsyncOptions?.forwardTruncateToMutations ?? true;\n\n\tconst originalReceiveSync = baseOptions.utils.receiveSync.bind(\n\t\tbaseOptions.utils,\n\t);\n\tconst originalTruncate = baseOptions.utils.truncate.bind(baseOptions.utils);\n\n\tconst bridge = new SyncClientBridge<TItem>({\n\t\tclientId,\n\t\t...(syncOptions?.collectionId !== undefined\n\t\t\t? { collectionId: syncOptions.collectionId }\n\t\t\t: {}),\n\t\tcollection: {\n\t\t\tutils: {\n\t\t\t\treceiveSync: originalReceiveSync,\n\t\t\t},\n\t\t},\n\t\tsend: (message) => transportSend(message),\n\t\tinitialLastAckedServerVersion: lastAckedServerVersion,\n\t\tonLastAckedServerVersionChange: (version) => {\n\t\t\tlastAckedServerVersion = Math.max(lastAckedServerVersion, version);\n\t\t\tif (typeof syncStateKey === \"string\") {\n\t\t\t\twritePersistedSyncState(syncStateKey, syncStateStorage, {\n\t\t\t\t\tclientId,\n\t\t\t\t\tlastAckedServerVersion,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tonRejectedMutation: syncOptions?.onRejectedMutation,\n\t\tsendSyncHelloOnConnect: syncOptions?.sendSyncHelloOnConnect,\n\t});\n\n\tconst throttleMs = syncOptions?.localMutationThrottleMs;\n\tlet mutationThrottleBuffer: SyncMessage<TItem>[] = [];\n\tlet mutationThrottleTimer: ReturnType<typeof setTimeout> | null = null;\n\n\tconst flushMutationThrottle = (): void => {\n\t\tmutationThrottleTimer = null;\n\t\tif (mutationThrottleBuffer.length === 0) return;\n\t\tconst batch = mutationThrottleBuffer;\n\t\tmutationThrottleBuffer = [];\n\t\tbridge.onLocalMutation(batch);\n\t};\n\n\tconst emitLocalMutation = (writes: SyncMessage<TItem>[]): void => {\n\t\tif (\n\t\t\tthrottleMs === undefined ||\n\t\t\tthrottleMs <= 0 ||\n\t\t\twrites.some((w) => w.type === \"truncate\")\n\t\t) {\n\t\t\tif (mutationThrottleTimer !== null) {\n\t\t\t\tclearTimeout(mutationThrottleTimer);\n\t\t\t\tmutationThrottleTimer = null;\n\t\t\t\tflushMutationThrottle();\n\t\t\t}\n\t\t\tbridge.onLocalMutation(writes);\n\t\t\treturn;\n\t\t}\n\t\tmutationThrottleBuffer.push(...writes);\n\t\tif (mutationThrottleTimer !== null) {\n\t\t\tclearTimeout(mutationThrottleTimer);\n\t\t}\n\t\tmutationThrottleTimer = setTimeout(flushMutationThrottle, throttleMs);\n\t};\n\n\tconst onInsert = baseOptions.onInsert\n\t\t? async (params: Parameters<NonNullable<TConfig[\"onInsert\"]>>[0]) => {\n\t\t\t\tconst writes: SyncMessage<TItem>[] = params.transaction.mutations.map(\n\t\t\t\t\t(mutation) => ({\n\t\t\t\t\t\ttype: \"insert\" as const,\n\t\t\t\t\t\tvalue: mutation.modified,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\temitLocalMutation(writes);\n\t\t\t\tawait baseOptions.onInsert?.(params);\n\t\t\t}\n\t\t: undefined;\n\n\tconst onUpdate = baseOptions.onUpdate\n\t\t? async (params: Parameters<NonNullable<TConfig[\"onUpdate\"]>>[0]) => {\n\t\t\t\tconst writes: SyncMessage<TItem>[] = params.transaction.mutations.map(\n\t\t\t\t\t(mutation) => ({\n\t\t\t\t\t\ttype: \"update\" as const,\n\t\t\t\t\t\tvalue: mutation.modified,\n\t\t\t\t\t\tpreviousValue: mutation.original,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\temitLocalMutation(writes);\n\t\t\t\tawait baseOptions.onUpdate?.(params);\n\t\t\t}\n\t\t: undefined;\n\n\tconst onDelete = baseOptions.onDelete\n\t\t? async (params: Parameters<NonNullable<TConfig[\"onDelete\"]>>[0]) => {\n\t\t\t\tconst writes: SyncMessage<TItem>[] = params.transaction.mutations.map(\n\t\t\t\t\t(mutation) => ({\n\t\t\t\t\t\ttype: \"delete\" as const,\n\t\t\t\t\t\tkey: mutation.key as string | number,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\temitLocalMutation(writes);\n\t\t\t\tawait baseOptions.onDelete?.(params);\n\t\t\t}\n\t\t: undefined;\n\n\tconst utils = {\n\t\t...baseOptions.utils,\n\t\ttruncate: async () => {\n\t\t\tawait originalTruncate();\n\t\t\tif (forwardTruncateToMutations) {\n\t\t\t\temitLocalMutation([{ type: \"truncate\" } as SyncMessage<TItem>]);\n\t\t\t}\n\t\t},\n\t};\n\n\tconst options = {\n\t\t...baseOptions,\n\t\t...(onInsert !== undefined ? { onInsert } : {}),\n\t\t...(onUpdate !== undefined ? { onUpdate } : {}),\n\t\t...(onDelete !== undefined ? { onDelete } : {}),\n\t\tutils,\n\t} as unknown as TConfig;\n\n\treturn {\n\t\toptions,\n\t\tbridge,\n\t\tsetTransportSend: (send) => {\n\t\t\ttransportSend = send;\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { PartialSyncClientBridge } from './partial-sync-client-bridge.js';
2
+ import { SyncClientBridge } from './sync-client-bridge.js';
3
+ import { PartialSyncRowShape } from './partial-sync-row-key.js';
4
+ import { SyncClientMessage, SyncServerMessage } from './sync-protocol.js';
5
+ import '@firtoz/db-helpers';
6
+ import './partial-sync-interest.js';
7
+ import 'zod';
8
+
9
+ type ConnectPartialSyncTransport = "json" | "msgpack";
10
+ type ConnectPartialSyncOptions<TItem extends PartialSyncRowShape = PartialSyncRowShape> = {
11
+ url: string;
12
+ transport?: ConnectPartialSyncTransport;
13
+ /** Prefer a module-level function or `useCallback`; a new inline function each render can churn effects. */
14
+ serializeJson?: (value: unknown) => string;
15
+ /** Prefer a module-level function or `useCallback`; a new inline function each render can churn effects. */
16
+ deserializeJson?: (raw: string) => unknown;
17
+ setTransportSend: (send: (msg: SyncClientMessage) => void) => void;
18
+ onServerMessage?: (msg: SyncServerMessage<TItem>) => void;
19
+ /**
20
+ * When set, inbound messages are split: range traffic → `bridge`, ack/reject/syncBackfill → mutation bridge;
21
+ * `syncBatch` applies via mutation bridge then updates partial cache ids (no double `receiveSync`).
22
+ */
23
+ mutationBridge?: SyncClientBridge<TItem>;
24
+ };
25
+ /**
26
+ * @internal Exported for unit tests; prefer {@link connectPartialSync} in apps.
27
+ * After a `rangePatch`, call `partialBridge.flushPendingCoalescedInboundUpdates()` unless you use
28
+ * `connectPartialSync` (the pump flushes coalesced updates after each inbound job).
29
+ */
30
+ declare function dispatchPartialSyncServerMessage<TItem extends PartialSyncRowShape>(msg: SyncServerMessage<TItem>, partialBridge: PartialSyncClientBridge<TItem>, mutationBridge: SyncClientBridge<TItem> | undefined): Promise<void>;
31
+ type CoalescedRangePatchMessage<TItem extends PartialSyncRowShape> = Extract<SyncServerMessage<TItem>, {
32
+ type: "rangePatch";
33
+ }>;
34
+ /**
35
+ * Last-wins merge of buffered `rangePatch` messages (same row id keeps the latest patch).
36
+ * @internal Exported for unit tests.
37
+ */
38
+ declare function mergeCoalescedRangePatches<TItem extends PartialSyncRowShape>(patches: CoalescedRangePatchMessage<TItem>[]): CoalescedRangePatchMessage<TItem>[];
39
+ declare function connectPartialSync<TItem extends PartialSyncRowShape = PartialSyncRowShape>(bridge: PartialSyncClientBridge<TItem>, options: ConnectPartialSyncOptions<TItem>): () => void;
40
+
41
+ export { type CoalescedRangePatchMessage, type ConnectPartialSyncOptions, type ConnectPartialSyncTransport, connectPartialSync, dispatchPartialSyncServerMessage, mergeCoalescedRangePatches };
@@ -0,0 +1,6 @@
1
+ export { connectPartialSync, dispatchPartialSyncServerMessage, mergeCoalescedRangePatches } from './chunk-XC4QNFSQ.js';
2
+ import './chunk-BJJEAKXL.js';
3
+ import './chunk-UJ24XW52.js';
4
+ import './chunk-HMLY7DHA.js';
5
+ //# sourceMappingURL=connect-partial-sync.js.map
6
+ //# sourceMappingURL=connect-partial-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"connect-partial-sync.js"}
@@ -0,0 +1,26 @@
1
+ import { SyncClientBridge } from './sync-client-bridge.js';
2
+ import { PartialSyncRowShape } from './partial-sync-row-key.js';
3
+ import { SyncClientMessage, SyncServerMessage } from './sync-protocol.js';
4
+ import '@firtoz/db-helpers';
5
+ import 'zod';
6
+
7
+ type ConnectSyncTransport = "json" | "msgpack";
8
+ type ConnectSyncOptions<TItem = unknown> = {
9
+ /** WebSocket URL (e.g. `wss://host/room/x/websocket`). */
10
+ url: string;
11
+ transport?: ConnectSyncTransport;
12
+ /** Prefer a module-level function or `useCallback`; a new inline function each render can churn effects. */
13
+ serializeJson?: (value: unknown) => string;
14
+ /** Prefer a module-level function or `useCallback`; a new inline function each render can churn effects. */
15
+ deserializeJson?: (raw: string) => unknown;
16
+ /** Wire transport after {@link SyncClientBridge} is created (from {@link withSync}). */
17
+ setTransportSend: (send: (msg: SyncClientMessage) => void) => void;
18
+ /** Optional tap before messages reach the bridge (e.g. debug / inspector). */
19
+ onServerMessage?: (msg: SyncServerMessage<TItem>) => void;
20
+ };
21
+ /**
22
+ * Connects a {@link SyncClientBridge} to a WebSocket using the same codec as `StandardSchemaSession` (`@firtoz/websocket-do`) on the server.
23
+ */
24
+ declare function connectSync<TItem extends PartialSyncRowShape>(bridge: SyncClientBridge<TItem>, options: ConnectSyncOptions<TItem>): () => void;
25
+
26
+ export { type ConnectSyncOptions, type ConnectSyncTransport, connectSync };
@@ -0,0 +1,5 @@
1
+ export { connectSync } from './chunk-GWIOC5CP.js';
2
+ import './chunk-BJJEAKXL.js';
3
+ import './chunk-HMLY7DHA.js';
4
+ //# sourceMappingURL=connect-sync.js.map
5
+ //# sourceMappingURL=connect-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"connect-sync.js"}
@@ -0,0 +1,24 @@
1
+ import { SyncClientMessage } from './sync-protocol.js';
2
+ import { SyncClientBridge } from './sync-client-bridge.js';
3
+ import * as _standard_schema_spec from '@standard-schema/spec';
4
+ import * as _tanstack_db from '@tanstack/db';
5
+ import { Collection } from '@tanstack/db';
6
+ import { AnyWithSyncableCollectionConfig, WithSyncOptions, InferItemFromCollectionOptions } from './with-sync.js';
7
+ import '@firtoz/db-helpers';
8
+ import 'zod';
9
+ import './partial-sync-row-key.js';
10
+
11
+ /**
12
+ * Like {@link createSyncedCollection}, but defaults `sendSyncHelloOnConnect` to `false` and
13
+ * `forwardTruncateToMutations` to `false` for use with {@link connectPartialSync} +
14
+ * {@link usePartialSyncWindow} (`mutateBatch` without `syncHello`). Local window resets call
15
+ * `truncate()` on the collection; those must not be sent to the server or they can batch with user
16
+ * edits and wipe authoritative data.
17
+ */
18
+ declare function createPartialSyncedCollection<TConfig extends AnyWithSyncableCollectionConfig>(baseOptions: TConfig, syncOptions?: WithSyncOptions): {
19
+ collection: Collection<InferItemFromCollectionOptions<TConfig>, string | number, _tanstack_db.UtilsRecord, _standard_schema_spec.StandardSchemaV1<unknown, unknown>, InferItemFromCollectionOptions<TConfig>>;
20
+ bridge: SyncClientBridge<InferItemFromCollectionOptions<TConfig>>;
21
+ setTransportSend: (send: (msg: SyncClientMessage) => void) => void;
22
+ };
23
+
24
+ export { createPartialSyncedCollection };
@@ -0,0 +1,8 @@
1
+ export { createPartialSyncedCollection } from './chunk-OP53UBPN.js';
2
+ import './chunk-YYGPIHHJ.js';
3
+ import './chunk-QJP4GSJH.js';
4
+ import './chunk-BJJEAKXL.js';
5
+ import './chunk-UJ24XW52.js';
6
+ import './chunk-HMLY7DHA.js';
7
+ //# sourceMappingURL=create-partial-synced-collection.js.map
8
+ //# sourceMappingURL=create-partial-synced-collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"create-partial-synced-collection.js"}
@@ -0,0 +1,26 @@
1
+ import { SyncClientMessage } from './sync-protocol.js';
2
+ import { SyncClientBridge } from './sync-client-bridge.js';
3
+ import * as _standard_schema_spec from '@standard-schema/spec';
4
+ import * as _tanstack_db from '@tanstack/db';
5
+ import { Collection } from '@tanstack/db';
6
+ import { AnyWithSyncableCollectionConfig, WithSyncOptions, InferItemFromCollectionOptions } from './with-sync.js';
7
+ import '@firtoz/db-helpers';
8
+ import 'zod';
9
+ import './partial-sync-row-key.js';
10
+
11
+ /**
12
+ * Builds a {@link withSync} wrapper and a TanStack {@link createCollection} in one step.
13
+ * Row type is inferred from the collection config (see {@link InferItemFromCollectionOptions}).
14
+ * (The internal `as unknown as Collection<TItem>` bridges `createCollection`'s overloads to the inferred row type.)
15
+ *
16
+ * Pass `syncOptions` for durable backends (IndexedDB, sqlite-wasm): use `syncStateKey` so incremental
17
+ * reconnect works. Omit `syncOptions` (or omit `syncStateKey`) for in-memory collections that need a
18
+ * full snapshot every load — see the module doc on {@link withSync} / `with-sync.ts`.
19
+ */
20
+ declare function createSyncedCollection<TConfig extends AnyWithSyncableCollectionConfig>(baseOptions: TConfig, syncOptions?: WithSyncOptions): {
21
+ collection: Collection<InferItemFromCollectionOptions<TConfig>, string | number, _tanstack_db.UtilsRecord, _standard_schema_spec.StandardSchemaV1<unknown, unknown>, InferItemFromCollectionOptions<TConfig>>;
22
+ bridge: SyncClientBridge<InferItemFromCollectionOptions<TConfig>>;
23
+ setTransportSend: (send: (msg: SyncClientMessage) => void) => void;
24
+ };
25
+
26
+ export { createSyncedCollection };
@@ -0,0 +1,8 @@
1
+ export { createSyncedCollection } from './chunk-UVZJL6QV.js';
2
+ import './chunk-YYGPIHHJ.js';
3
+ import './chunk-QJP4GSJH.js';
4
+ import './chunk-BJJEAKXL.js';
5
+ import './chunk-UJ24XW52.js';
6
+ import './chunk-HMLY7DHA.js';
7
+ //# sourceMappingURL=create-synced-collection.js.map
8
+ //# sourceMappingURL=create-synced-collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"create-synced-collection.js"}
@@ -0,0 +1,18 @@
1
+ export { DEFAULT_SYNC_COLLECTION_ID, IndexRangeCursor, IndexRangeOffset, MutationIntent, PredicateRange, RangeCondition, RangeConditionOp, RangeFingerprint, SyncBackfillMode, SyncClientMessage, SyncClientMessageBody, SyncRange, SyncRangeSort, SyncServerMessage, SyncServerMessageBody, SyncSortDirection, clientMessageSchema, createClientMessageSchema, createClientMutationId, createServerMessageSchema, mutationIntentSchema, serverMessageSchema, syncRangeSchema, toSyncMessage } from './sync-protocol.js';
2
+ export { SyncClientBridge, SyncClientBridgeOptions } from './sync-client-bridge.js';
3
+ export { PartialSyncClientBridge, PartialSyncClientBridgeOptions, PartialSyncRangePatchAppliedEvent, PartialSyncRangeResult, PartialSyncReconcileResult, PartialSyncState, PartialSyncViewTransitionEvent } from './partial-sync-client-bridge.js';
4
+ export { CacheEntry, CacheManager, CacheManagerOptions, CacheStorageEstimate, CacheViewport } from './cache-manager.js';
5
+ export { SyncServerBridge, SyncServerBridgeOptions, SyncServerBridgeStore } from './sync-server-bridge.js';
6
+ export { ClientQueryState, PartialSyncPushServerChangesOptions, PartialSyncServerBridge, PartialSyncServerBridgeOptions, PartialSyncServerBridgeStore } from './partial-sync-server-bridge.js';
7
+ export { PartialSyncMutationHandler, PartialSyncMutationHandlerOptions, PartialSyncMutationHandlerStore } from './partial-sync-mutation-handler.js';
8
+ export { AnyWithSyncableCollectionConfig, InferItemFromCollectionOptions, SyncStateStorage, SyncableCollectionItem, WithSyncOptions, WithSyncableCollectionConfig, getBrowserLocalStorageSyncStateStorage, withSync } from './with-sync.js';
9
+ export { createSyncedCollection } from './create-synced-collection.js';
10
+ export { createPartialSyncedCollection } from './create-partial-synced-collection.js';
11
+ export { ConnectSyncOptions, ConnectSyncTransport, connectSync } from './connect-sync.js';
12
+ export { ConnectPartialSyncOptions, ConnectPartialSyncTransport, connectPartialSync } from './connect-partial-sync.js';
13
+ export { PartialSyncRowId, PartialSyncRowRef, PartialSyncRowShape, PartialSyncRowVersion, partialSyncRowKey, partialSyncRowVersionWatermarkMs, partialSyncRowVersionWatermarkMsUnknown } from './partial-sync-row-key.js';
14
+ export { ClassifyPartialSyncRangePatchOptions, DeliveredRange, PartialSyncPatchResult, PartialSyncViewTransition, compareInterestValues, filterSyncMessagesForPredicateRange, rowMatchesClientInterest } from './partial-sync-interest.js';
15
+ import '@firtoz/db-helpers';
16
+ import 'zod';
17
+ import '@standard-schema/spec';
18
+ import '@tanstack/db';
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ export { SyncServerBridge } from './chunk-TEH7V76G.js';
2
+ export { PartialSyncMutationHandler } from './chunk-5VMFQT5Z.js';
3
+ export { PartialSyncServerBridge } from './chunk-RDDS7JQW.js';
4
+ export { CacheManager } from './chunk-5V6BSQAB.js';
5
+ export { connectPartialSync } from './chunk-XC4QNFSQ.js';
6
+ export { connectSync } from './chunk-GWIOC5CP.js';
7
+ export { createPartialSyncedCollection } from './chunk-OP53UBPN.js';
8
+ export { createSyncedCollection } from './chunk-UVZJL6QV.js';
9
+ export { getBrowserLocalStorageSyncStateStorage, withSync } from './chunk-YYGPIHHJ.js';
10
+ export { SyncClientBridge } from './chunk-QJP4GSJH.js';
11
+ export { PartialSyncClientBridge } from './chunk-P3JOTUAB.js';
12
+ export { DEFAULT_SYNC_COLLECTION_ID, clientMessageSchema, createClientMessageSchema, createClientMutationId, createServerMessageSchema, mutationIntentSchema, serverMessageSchema, syncRangeSchema, toSyncMessage } from './chunk-BJJEAKXL.js';
13
+ export { compareInterestValues, filterSyncMessagesForPredicateRange, rowMatchesClientInterest } from './chunk-6EHROJFY.js';
14
+ import './chunk-3EHHMLSV.js';
15
+ export { partialSyncRowKey, partialSyncRowVersionWatermarkMs, partialSyncRowVersionWatermarkMsUnknown } from './chunk-UJ24XW52.js';
16
+ import './chunk-HMLY7DHA.js';
17
+ //# sourceMappingURL=index.js.map
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}