@firtoz/collection-sync 4.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 (130) 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 +27 -21
  129. package/src/connect-partial-sync.ts +16 -12
  130. package/src/connect-sync.ts +12 -10
@@ -0,0 +1,157 @@
1
+ import { SyncMessage } from '@firtoz/db-helpers';
2
+ import { SyncClientMessage, SyncRangeSort, SyncRange, RangeFingerprint, SyncServerMessage } from './sync-protocol.js';
3
+ import { PartialSyncRowShape } from './partial-sync-row-key.js';
4
+ import { PartialSyncViewTransition } from './partial-sync-interest.js';
5
+ import 'zod';
6
+
7
+ type PartialSyncViewTransitionEvent<TItem extends PartialSyncRowShape> = {
8
+ type: PartialSyncViewTransition;
9
+ change: SyncMessage<TItem>;
10
+ };
11
+ type PartialSyncRangePatchAppliedEvent<TItem extends PartialSyncRowShape> = {
12
+ change: SyncMessage<TItem>;
13
+ viewTransition?: PartialSyncViewTransition;
14
+ };
15
+ type CollectionWithReceiveSync<TItem> = {
16
+ utils: {
17
+ receiveSync: (messages: SyncMessage<TItem>[]) => Promise<void>;
18
+ };
19
+ /**
20
+ * When set, server `queryRangeChunk` rows can become `update` messages when the collection
21
+ * already holds that id — including durable hydration (IndexedDB / SQLite reload) where rows
22
+ * exist before {@link PartialSyncClientBridge.seedHydratedLocalRows} runs or if it is skipped.
23
+ * Without this, the bridge may emit `insert` and hit duplicate-key errors from `receiveSync`.
24
+ */
25
+ get?: (key: string | number) => TItem | undefined;
26
+ };
27
+ type SendFn = (msg: SyncClientMessage) => void;
28
+ type PartialSyncState = {
29
+ status: "offline";
30
+ } | {
31
+ status: "connecting";
32
+ } | {
33
+ status: "connected";
34
+ } | {
35
+ status: "fetching";
36
+ requestId: string;
37
+ chunksReceived: number;
38
+ } | {
39
+ status: "partial";
40
+ cachedCount: number;
41
+ totalCount: number;
42
+ cacheUtilization: number;
43
+ } | {
44
+ status: "realtime";
45
+ cachedCount: number;
46
+ totalCount: number;
47
+ cacheUtilization: number;
48
+ } | {
49
+ status: "evicting";
50
+ cachedCount: number;
51
+ evictingCount: number;
52
+ } | {
53
+ status: "disconnected";
54
+ cachedCount: number;
55
+ } | {
56
+ status: "error";
57
+ message: string;
58
+ };
59
+ type PartialSyncRangeResult<TItem> = {
60
+ rows: TItem[];
61
+ totalCount: number;
62
+ lastCursor: unknown | null;
63
+ hasMore: boolean;
64
+ /** Server applied a small delta; caller may need to refetch the window without fingerprint. */
65
+ invalidateWindow?: boolean;
66
+ /** Server confirmed fingerprint; no new rows on the wire. */
67
+ upToDate?: boolean;
68
+ };
69
+ type PartialSyncReconcileResult<TItem extends PartialSyncRowShape> = {
70
+ added: TItem[];
71
+ updated: TItem[];
72
+ staleIds: Array<string | number>;
73
+ movedHints: Array<{
74
+ id: string | number;
75
+ hint: Record<string, unknown>;
76
+ }>;
77
+ totalCount: number;
78
+ };
79
+ interface PartialSyncClientBridgeOptions<TItem extends PartialSyncRowShape> {
80
+ /** Defaults to a random UUID when omitted (must match {@link SyncClientBridge} when using mutations). */
81
+ clientId?: string;
82
+ /** Must match the server's partial-sync {@link PartialSyncServerBridgeOptions.collectionId}. */
83
+ collectionId?: string;
84
+ collection: CollectionWithReceiveSync<TItem>;
85
+ send: SendFn;
86
+ onStateChange?: (state: PartialSyncState) => void;
87
+ beforeApplyRows?: (rows: TItem[]) => Promise<void>;
88
+ /** Fired when a `rangePatch` carries `viewTransition` (row crossed client interest). */
89
+ onViewTransition?: (event: PartialSyncViewTransitionEvent<TItem>) => void;
90
+ /** Fired after any `rangePatch` is applied (including view transitions). */
91
+ onRangePatchApplied?: (event: PartialSyncRangePatchAppliedEvent<TItem>) => void;
92
+ }
93
+ declare class PartialSyncClientBridge<TItem extends PartialSyncRowShape> {
94
+ #private;
95
+ private readonly options;
96
+ readonly clientId: string;
97
+ readonly collectionId: string;
98
+ constructor(options: PartialSyncClientBridgeOptions<TItem>);
99
+ get state(): PartialSyncState;
100
+ get cachedCount(): number;
101
+ setConnecting(): void;
102
+ setConnected(connected: boolean): void;
103
+ setOffline(): void;
104
+ setSend(send: SendFn): void;
105
+ setError(message: string): void;
106
+ setCacheUtilization(utilization: number): void;
107
+ setEvicting(evictingCount: number): void;
108
+ clearEvictingState(): void;
109
+ /**
110
+ * Drop in-flight `queryRange` / `queryByOffset` / `rangeQuery` requests (e.g. user seek / sort reset).
111
+ * {@link requestRange}, {@link requestByOffset}, and {@link requestRangeQuery} call this first so
112
+ * overlapping viewport debounces cannot double-apply the same rows.
113
+ */
114
+ abortRangeRequests(): void;
115
+ /**
116
+ * Clear tracked row ids (e.g. after a local `truncate()` on the collection). Local truncate
117
+ * does not flow through `receiveSync`, so the bridge must be reset to match.
118
+ */
119
+ clearServerConfirmedKeys(): void;
120
+ /** Keys from the latest completed `rangeQuery` / chunk response. */
121
+ get serverConfirmedKeys(): ReadonlySet<string | number>;
122
+ /** Bumps when {@link serverConfirmedKeys} changes; pass into predicate hooks as a dependency. */
123
+ get serverConfirmedKeysRevision(): number;
124
+ /** Subscribe to {@link serverConfirmedKeysRevision} changes (for `useSyncExternalStore`). */
125
+ subscribeConfirmedKeysRevision(listener: () => void): () => void;
126
+ clearTrackedRowIds(): void;
127
+ requestRange(sort: SyncRangeSort, limit: number, afterCursor: unknown | null): Promise<PartialSyncRangeResult<TItem>>;
128
+ requestByOffset(sort: SyncRangeSort, limit: number, offset: number): Promise<PartialSyncRangeResult<TItem>>;
129
+ requestRangeQuery(range: SyncRange, fingerprint?: RangeFingerprint): Promise<PartialSyncRangeResult<TItem>>;
130
+ /**
131
+ * Reconcile the client's cached window against the server using a row manifest (id + version ms).
132
+ * Pass `manifest` to override rows; otherwise uses {@link PartialSyncClientBridge.serverConfirmedKeys} and {@link PartialSyncClientBridgeOptions.collection} `get`.
133
+ */
134
+ requestRangeReconcile(range: SyncRange, manifest?: Array<{
135
+ id: string | number;
136
+ version: number;
137
+ }>): Promise<PartialSyncReconcileResult<TItem>>;
138
+ handleServerMessage(message: SyncServerMessage<TItem>): Promise<void>;
139
+ /**
140
+ * Merge rows already present in the local collection (e.g. IndexedDB eager `initialLoad`) into
141
+ * `#cachedIds` so {@link cachedCount} and React-driven `bridgeState` match durable storage after reload.
142
+ * Safe to call multiple times; ids are a set. Does not call `receiveSync`.
143
+ */
144
+ seedHydratedLocalRows(rows: readonly TItem[]): void;
145
+ /**
146
+ * Updates `#cachedIds` after {@link SyncClientBridge} has already applied the same messages via `receiveSync`
147
+ * (e.g. `syncBatch`) so we do not double-apply.
148
+ */
149
+ syncTrackedIdsFromMessages(changes: SyncMessage<TItem>[]): void;
150
+ /**
151
+ * Apply pending plain `rangePatch` updates coalesced by row id. Idempotent when the map is empty.
152
+ * Invoked automatically by `connectPartialSync` after each inbound pump drain.
153
+ */
154
+ flushPendingCoalescedInboundUpdates(): Promise<void>;
155
+ }
156
+
157
+ export { PartialSyncClientBridge, type PartialSyncClientBridgeOptions, type PartialSyncRangePatchAppliedEvent, type PartialSyncRangeResult, type PartialSyncReconcileResult, type PartialSyncState, type PartialSyncViewTransitionEvent };
@@ -0,0 +1,6 @@
1
+ export { PartialSyncClientBridge } from './chunk-P3JOTUAB.js';
2
+ import './chunk-BJJEAKXL.js';
3
+ import './chunk-UJ24XW52.js';
4
+ import './chunk-HMLY7DHA.js';
5
+ //# sourceMappingURL=partial-sync-client-bridge.js.map
6
+ //# sourceMappingURL=partial-sync-client-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-client-bridge.js"}
@@ -0,0 +1,48 @@
1
+ import { SyncMessage } from '@firtoz/db-helpers';
2
+ import { RangeCondition } from './sync-protocol.js';
3
+ import { PartialSyncRowShape } from './partial-sync-row-key.js';
4
+ import 'zod';
5
+
6
+ /** Metadata on `rangePatch` when an update crosses client interest boundaries. */
7
+ type PartialSyncViewTransition = "enterView" | "exitView";
8
+ type PartialSyncPatchResult<TItem extends PartialSyncRowShape> = {
9
+ change: SyncMessage<TItem>;
10
+ viewTransition?: PartialSyncViewTransition;
11
+ };
12
+ /** Tracked 1D sort interval delivered to a client (index / cursor queries). */
13
+ type DeliveredRange = {
14
+ sortColumn: string;
15
+ sortDirection: "asc" | "desc";
16
+ fromValue: unknown;
17
+ toValue: unknown;
18
+ };
19
+ declare function compareInterestValues(left: unknown, right: unknown): number;
20
+ declare function sortValueWithinDeliveredRange(value: unknown, range: DeliveredRange): boolean;
21
+ declare function rowMatchesDeliveredSortRanges<TItem>(ranges: DeliveredRange[], row: TItem, getSortValue: (row: TItem, column: string) => unknown): boolean;
22
+ declare function rowMatchesPredicateGroups<TItem>(predicateGroups: RangeCondition[][], row: TItem, getColumnValue: (row: TItem, column: string) => unknown): boolean;
23
+ declare function rowMatchesClientInterest<TItem>(sortRanges: DeliveredRange[], predicateGroups: RangeCondition[][], row: TItem, getSortValue: (row: TItem, column: string) => unknown, getColumnValue: (row: TItem, column: string) => unknown): boolean;
24
+ type ClassifyPartialSyncRangePatchOptions = {
25
+ /**
26
+ * When set, `delete` is only forwarded if the key was previously delivered to this client
27
+ * (viewport-scoped deletes). When omitted, `delete` is always forwarded (legacy behavior).
28
+ */
29
+ deliveredRowIds?: ReadonlySet<string> | undefined;
30
+ };
31
+ /**
32
+ * Maps a server-side change to a `rangePatch` payload, or `null` if this client should not
33
+ * receive a patch. View enter/exit keeps the real `update` on the wire so clients can cache
34
+ * rows and filter locally instead of fake delete/insert.
35
+ */
36
+ declare function classifyPartialSyncRangePatch<TItem extends PartialSyncRowShape>(sortRanges: DeliveredRange[], predicateGroups: RangeCondition[][], change: SyncMessage<TItem>, getSortValue: (row: TItem, column: string) => unknown, getColumnValue: (row: TItem, column: string) => unknown, options?: ClassifyPartialSyncRangePatchOptions): PartialSyncPatchResult<TItem> | null;
37
+ /**
38
+ * Filters sync messages to those relevant to a single predicate range (viewport). Used for
39
+ * `rangeDelta` so clients never receive changelog rows outside their requested conditions.
40
+ *
41
+ * - `insert` / `update` / `truncate`: uses {@link classifyPartialSyncRangePatch} with only this
42
+ * predicate group (no sort ranges).
43
+ * - `delete`: passed through unchanged — callers should filter deletes in the store when the
44
+ * deleted row snapshot is available (e.g. changelog payload).
45
+ */
46
+ declare function filterSyncMessagesForPredicateRange<TItem extends PartialSyncRowShape>(conditions: RangeCondition[], changes: SyncMessage<TItem>[], getSortValue: (row: TItem, column: string) => unknown, getColumnValue: (row: TItem, column: string) => unknown): SyncMessage<TItem>[];
47
+
48
+ export { type ClassifyPartialSyncRangePatchOptions, type DeliveredRange, type PartialSyncPatchResult, type PartialSyncViewTransition, classifyPartialSyncRangePatch, compareInterestValues, filterSyncMessagesForPredicateRange, rowMatchesClientInterest, rowMatchesDeliveredSortRanges, rowMatchesPredicateGroups, sortValueWithinDeliveredRange };
@@ -0,0 +1,6 @@
1
+ export { classifyPartialSyncRangePatch, compareInterestValues, filterSyncMessagesForPredicateRange, rowMatchesClientInterest, rowMatchesDeliveredSortRanges, rowMatchesPredicateGroups, sortValueWithinDeliveredRange } from './chunk-6EHROJFY.js';
2
+ import './chunk-3EHHMLSV.js';
3
+ import './chunk-UJ24XW52.js';
4
+ import './chunk-HMLY7DHA.js';
5
+ //# sourceMappingURL=partial-sync-interest.js.map
6
+ //# sourceMappingURL=partial-sync-interest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-interest.js"}
@@ -0,0 +1,31 @@
1
+ import { SyncMessage } from '@firtoz/db-helpers';
2
+ import { PartialSyncServerBridge } from './partial-sync-server-bridge.js';
3
+ import { PartialSyncRowShape } from './partial-sync-row-key.js';
4
+ import { SyncServerMessage, SyncClientMessage } from './sync-protocol.js';
5
+ import './partial-sync-interest.js';
6
+ import 'zod';
7
+
8
+ interface PartialSyncMutationHandlerStore<TItem extends PartialSyncRowShape> {
9
+ applySyncMessages: (messages: SyncMessage<TItem>[]) => Promise<void>;
10
+ getRow: (key: string | number) => Promise<TItem | undefined>;
11
+ }
12
+ interface PartialSyncMutationHandlerOptions<TItem extends PartialSyncRowShape> {
13
+ store: PartialSyncMutationHandlerStore<TItem>;
14
+ partialBridge: Pick<PartialSyncServerBridge<TItem>, "pushServerChanges">;
15
+ sendToClient: (clientId: string, message: SyncServerMessage<TItem>) => void;
16
+ collectionId?: string;
17
+ }
18
+ /**
19
+ * Partial-sync durable object mutation path: `mutateBatch` → `ack` / `reject` + interest-scoped
20
+ * `rangePatch` via {@link PartialSyncServerBridge.pushServerChanges}. No `serverVersion`, changelog,
21
+ * or `syncBatch` broadcast.
22
+ */
23
+ declare class PartialSyncMutationHandler<TItem extends PartialSyncRowShape> {
24
+ #private;
25
+ private readonly options;
26
+ constructor(options: PartialSyncMutationHandlerOptions<TItem>);
27
+ get collectionId(): string;
28
+ handleClientMessage(message: SyncClientMessage): Promise<void>;
29
+ }
30
+
31
+ export { PartialSyncMutationHandler, type PartialSyncMutationHandlerOptions, type PartialSyncMutationHandlerStore };
@@ -0,0 +1,6 @@
1
+ export { PartialSyncMutationHandler } from './chunk-5VMFQT5Z.js';
2
+ import './chunk-BJJEAKXL.js';
3
+ import './chunk-UJ24XW52.js';
4
+ import './chunk-HMLY7DHA.js';
5
+ //# sourceMappingURL=partial-sync-mutation-handler.js.map
6
+ //# sourceMappingURL=partial-sync-mutation-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-mutation-handler.js"}
@@ -0,0 +1,8 @@
1
+ import { RangeCondition } from './sync-protocol.js';
2
+ import '@firtoz/db-helpers';
3
+ import 'zod';
4
+
5
+ declare function defaultPredicateColumnValue<TItem>(row: TItem, column: string): unknown;
6
+ declare function matchesPredicate<TItem>(row: TItem, conditions: RangeCondition[], getColumnValue: (row: TItem, column: string) => unknown): boolean;
7
+
8
+ export { defaultPredicateColumnValue, matchesPredicate };
@@ -0,0 +1,4 @@
1
+ export { defaultPredicateColumnValue, matchesPredicate } from './chunk-3EHHMLSV.js';
2
+ import './chunk-HMLY7DHA.js';
3
+ //# sourceMappingURL=partial-sync-predicate-match.js.map
4
+ //# sourceMappingURL=partial-sync-predicate-match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-predicate-match.js"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Row `id` values accepted by partial-sync (plain keys and ORM outputs such as drizzle-sqlite-wasm
3
+ * insert-schema types that are string-like but not assignable to `string | number` in TypeScript).
4
+ */
5
+ type PartialSyncRowId = string | number | {
6
+ toString(): string;
7
+ };
8
+ /**
9
+ * Minimal object shape keyed by a partial-sync row id. Use when only identity matters (e.g. cache
10
+ * keys). Prefer {@link PartialSyncRowShape} for sync / partial-sync bridges and hooks.
11
+ */
12
+ type PartialSyncRowRef = {
13
+ id: PartialSyncRowId;
14
+ };
15
+ /**
16
+ * Version watermark for sync / partial-sync (fingerprints, reconciliation). The **`updatedAt` key
17
+ * must exist** on the object; `null` or `undefined` mean “no ms watermark” at runtime (treated as
18
+ * `0` where a number is needed). Rows or ORM types **without** this property are not suitable for
19
+ * sync / partial-sync APIs—use {@link PartialSyncRowRef} only when you only need identity (e.g.
20
+ * cache keys). (`undefined` is included in the union so Drizzle `InferSelectModel` / optional
21
+ * columns remain assignable.)
22
+ */
23
+ type PartialSyncRowVersion = {
24
+ updatedAt: number | Date | null | undefined;
25
+ };
26
+ /**
27
+ * Row shape required across {@link PartialSyncClientBridge}, {@link SyncClientBridge}, and React
28
+ * partial-sync hooks: stable id plus a mandatory {@link PartialSyncRowVersion} key (see there).
29
+ */
30
+ type PartialSyncRowShape = PartialSyncRowRef & PartialSyncRowVersion;
31
+ /** Max `updatedAt` as epoch ms; `null` / `undefined` → 0. */
32
+ declare function partialSyncRowVersionWatermarkMs(row: PartialSyncRowVersion): number;
33
+ /**
34
+ * Like {@link partialSyncRowVersionWatermarkMs} for decoded protocol payloads that are not yet
35
+ * narrowed to {@link PartialSyncRowVersion} (e.g. mutate-batch `value` fields). Missing
36
+ * `updatedAt` → 0.
37
+ */
38
+ declare function partialSyncRowVersionWatermarkMsUnknown(row: unknown): number;
39
+ declare function partialSyncRowKey(id: PartialSyncRowId): string | number;
40
+
41
+ export { type PartialSyncRowId, type PartialSyncRowRef, type PartialSyncRowShape, type PartialSyncRowVersion, partialSyncRowKey, partialSyncRowVersionWatermarkMs, partialSyncRowVersionWatermarkMsUnknown };
@@ -0,0 +1,4 @@
1
+ export { partialSyncRowKey, partialSyncRowVersionWatermarkMs, partialSyncRowVersionWatermarkMsUnknown } from './chunk-UJ24XW52.js';
2
+ import './chunk-HMLY7DHA.js';
3
+ //# sourceMappingURL=partial-sync-row-key.js.map
4
+ //# sourceMappingURL=partial-sync-row-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-row-key.js"}
@@ -0,0 +1,102 @@
1
+ import { SyncMessage } from '@firtoz/db-helpers';
2
+ import { DeliveredRange, PartialSyncPatchResult } from './partial-sync-interest.js';
3
+ import { SyncRangeSort, RangeCondition, SyncRange, SyncServerMessage, SyncClientMessage } from './sync-protocol.js';
4
+ import { PartialSyncRowShape } from './partial-sync-row-key.js';
5
+ import 'zod';
6
+
7
+ type ClientQueryState<TItem extends PartialSyncRowShape = {
8
+ id: string;
9
+ updatedAt: null;
10
+ }> = {
11
+ clientId: string;
12
+ deliveredRanges: DeliveredRange[];
13
+ /** Each entry is one predicate query's `conditions` (AND); OR across entries. */
14
+ predicateGroups: RangeCondition[][];
15
+ /** Row ids delivered to this client in the current interest session (for scoped deletes). */
16
+ deliveredRowIds: Set<string>;
17
+ pendingPatches: PartialSyncPatchResult<TItem>[];
18
+ streaming: boolean;
19
+ };
20
+ interface PartialSyncServerBridgeStore<TItem extends PartialSyncRowShape> {
21
+ queryRange: (options: {
22
+ sort: SyncRangeSort;
23
+ limit: number;
24
+ afterCursor: unknown | null;
25
+ chunkSize: number;
26
+ }) => AsyncIterable<TItem[]>;
27
+ queryByOffset: (options: {
28
+ sort: SyncRangeSort;
29
+ limit: number;
30
+ offset: number;
31
+ chunkSize: number;
32
+ }) => AsyncIterable<TItem[]>;
33
+ getTotalCount: () => Promise<number>;
34
+ getSortValue: (row: TItem, column: string) => unknown;
35
+ /** Predicate-based range (optional). */
36
+ queryByPredicate?: (options: {
37
+ conditions: RangeCondition[];
38
+ sort?: SyncRangeSort;
39
+ limit?: number;
40
+ chunkSize: number;
41
+ }) => AsyncIterable<TItem[]>;
42
+ getPredicateCount?: (conditions: RangeCondition[]) => Promise<number>;
43
+ /**
44
+ * Changes since `sinceVersion` within `range`. `null` if changelog cannot answer
45
+ * (caller should full-fetch).
46
+ */
47
+ changesSince?: (options: {
48
+ range: SyncRange;
49
+ sinceVersion: number;
50
+ chunkSize: number;
51
+ }) => Promise<{
52
+ changes: SyncMessage<TItem>[];
53
+ totalCount: number;
54
+ } | null>;
55
+ /** Authoritative row lookup (e.g. for {@link PartialSyncServerBridgeOptions.resolveMovedHint}). */
56
+ getRow?: (key: string | number) => Promise<TItem | undefined>;
57
+ }
58
+ type PartialSyncPushServerChangesOptions = {
59
+ /**
60
+ * Do not emit `rangePatch` to this client (e.g. the mutation author already applied the change
61
+ * locally and receives `ack` with the same payload).
62
+ */
63
+ excludeClientId?: string;
64
+ };
65
+ interface PartialSyncServerBridgeOptions<TItem extends PartialSyncRowShape> {
66
+ store: PartialSyncServerBridgeStore<TItem>;
67
+ sendToClient: (clientId: string, message: SyncServerMessage<TItem>) => void;
68
+ queryChunkSize?: number;
69
+ /** Multiplex key for sync messages. Default {@link DEFAULT_SYNC_COLLECTION_ID}. */
70
+ collectionId?: string;
71
+ /**
72
+ * Narrow client-requested predicate conditions (e.g. fog of war). Applied before querying and
73
+ * before interest tracking for predicate `rangeQuery`.
74
+ */
75
+ resolveClientVisibility?: (clientId: string, requestedConditions: RangeCondition[]) => RangeCondition[] | Promise<RangeCondition[]>;
76
+ /**
77
+ * Optional hint for rows that left the client's range during `rangeReconcile`.
78
+ * Return `null` to enforce fog of war (default when omitted).
79
+ */
80
+ resolveMovedHint?: (row: TItem, range: SyncRange) => Record<string, unknown> | null | Promise<Record<string, unknown> | null>;
81
+ }
82
+ declare class PartialSyncServerBridge<TItem extends PartialSyncRowShape> {
83
+ #private;
84
+ private readonly options;
85
+ constructor(options: PartialSyncServerBridgeOptions<TItem>);
86
+ get collectionId(): string;
87
+ handleClientMessage(message: SyncClientMessage): Promise<void>;
88
+ pushServerChanges(changes: SyncMessage<TItem>[], options?: PartialSyncPushServerChangesOptions): Promise<void>;
89
+ /**
90
+ * Drop partial-sync interest for a disconnected client (prevents unbounded `#clientStates`
91
+ * growth and stale subscriptions).
92
+ */
93
+ removeClient(clientId: string): void;
94
+ /**
95
+ * Replace predicate interest for a client (server-authoritative visibility). Clears sort-range
96
+ * tracking; the next `rangeQuery` should re-establish delivered ranges from fresh chunks.
97
+ */
98
+ setClientVisibility(clientId: string, conditions: RangeCondition[]): void;
99
+ getClientState(clientId: string): ClientQueryState<TItem> | undefined;
100
+ }
101
+
102
+ export { type ClientQueryState, DeliveredRange, type PartialSyncPushServerChangesOptions, PartialSyncServerBridge, type PartialSyncServerBridgeOptions, type PartialSyncServerBridgeStore };
@@ -0,0 +1,8 @@
1
+ export { PartialSyncServerBridge } from './chunk-RDDS7JQW.js';
2
+ import './chunk-BJJEAKXL.js';
3
+ import './chunk-6EHROJFY.js';
4
+ import './chunk-3EHHMLSV.js';
5
+ import './chunk-UJ24XW52.js';
6
+ import './chunk-HMLY7DHA.js';
7
+ //# sourceMappingURL=partial-sync-server-bridge.js.map
8
+ //# sourceMappingURL=partial-sync-server-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-server-bridge.js"}
@@ -0,0 +1,12 @@
1
+ declare const DEFAULT_PAGE_LIMIT = 50;
2
+ declare const DEFAULT_SEEK_ROW_GAP = 80;
3
+ declare const DEFAULT_SEEK_COOLDOWN_MS = 200;
4
+ /** Default quiet period before coalesced predicate `rangeQuery` after viewport motion. */
5
+ declare const DEFAULT_VIEWPORT_RANGE_QUIET_MS = 72;
6
+ /**
7
+ * Default max time between predicate `rangeQuery` calls while the viewport keeps changing
8
+ * (still issues a fetch even during continuous motion).
9
+ */
10
+ declare const DEFAULT_VIEWPORT_RANGE_MAX_WAIT_MS = 200;
11
+
12
+ export { DEFAULT_PAGE_LIMIT, DEFAULT_SEEK_COOLDOWN_MS, DEFAULT_SEEK_ROW_GAP, DEFAULT_VIEWPORT_RANGE_MAX_WAIT_MS, DEFAULT_VIEWPORT_RANGE_QUIET_MS };
@@ -0,0 +1,4 @@
1
+ export { DEFAULT_PAGE_LIMIT, DEFAULT_SEEK_COOLDOWN_MS, DEFAULT_SEEK_ROW_GAP, DEFAULT_VIEWPORT_RANGE_MAX_WAIT_MS, DEFAULT_VIEWPORT_RANGE_QUIET_MS } from '../chunk-M5MJHS6A.js';
2
+ import '../chunk-HMLY7DHA.js';
3
+ //# sourceMappingURL=constants.js.map
4
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"constants.js"}
@@ -0,0 +1,19 @@
1
+ export { DEFAULT_PAGE_LIMIT, DEFAULT_SEEK_COOLDOWN_MS, DEFAULT_SEEK_ROW_GAP, DEFAULT_VIEWPORT_RANGE_MAX_WAIT_MS, DEFAULT_VIEWPORT_RANGE_QUIET_MS } from './constants.js';
2
+ export { CacheDisplayMode, PartialSyncCollection, PartialSyncItem, PartialSyncLiveCollection, PartialSyncRowSlot, PartialSyncRowSlotView, UsePartialSyncCollectionOptions, UsePartialSyncCollectionResult, UsePartialSyncViewportOptions, UsePartialSyncViewportResult, UsePartialSyncWindowOptions, UsePartialSyncWindowResult, UsePredicateFilteredRowsOptions, ViewportInfo } from './types.js';
3
+ export { CreatePartialSyncAdapterConfig, NumericAxisSpec, PartialSyncViewportAdapter, PartialSyncViewportItem, PredicateSortSpec, betweenConditionsForNumericAxes, createPartialSyncAdapter } from './partial-sync-adapter.js';
4
+ export { assertSyncUtils, computeFingerprintForIndexWindow, defaultPartialSyncVersionMs, getPartialSyncRowByMapId, tryIdsForIndexWindow } from './partial-sync-utils.js';
5
+ export { usePartialSyncWindow } from './usePartialSyncWindow.js';
6
+ export { usePartialSyncCollection } from './usePartialSyncCollection.js';
7
+ export { usePartialSyncViewport } from './usePartialSyncViewport.js';
8
+ export { usePredicateFilteredRows } from './usePredicateFilteredRows.js';
9
+ export { PartialSyncRowRef, PartialSyncRowShape, PartialSyncRowVersion } from '../partial-sync-row-key.js';
10
+ export { defaultPredicateColumnValue, matchesPredicate } from '../partial-sync-predicate-match.js';
11
+ import '@tanstack/db';
12
+ import '../cache-manager.js';
13
+ import '../partial-sync-client-bridge.js';
14
+ import '@firtoz/db-helpers';
15
+ import '../sync-protocol.js';
16
+ import 'zod';
17
+ import '../partial-sync-interest.js';
18
+ import '../connect-partial-sync.js';
19
+ import '../sync-client-bridge.js';
@@ -0,0 +1,17 @@
1
+ export { usePartialSyncCollection } from '../chunk-I6RJWBGF.js';
2
+ export { usePartialSyncViewport } from '../chunk-BGJH6PH2.js';
3
+ export { usePartialSyncWindow } from '../chunk-O3KBDCEI.js';
4
+ export { usePredicateFilteredRows } from '../chunk-YD5LVGWX.js';
5
+ import '../chunk-43KYAIKY.js';
6
+ export { DEFAULT_PAGE_LIMIT, DEFAULT_SEEK_COOLDOWN_MS, DEFAULT_SEEK_ROW_GAP, DEFAULT_VIEWPORT_RANGE_MAX_WAIT_MS, DEFAULT_VIEWPORT_RANGE_QUIET_MS } from '../chunk-M5MJHS6A.js';
7
+ export { betweenConditionsForNumericAxes, createPartialSyncAdapter } from '../chunk-6X3434GJ.js';
8
+ export { assertSyncUtils, computeFingerprintForIndexWindow, defaultPartialSyncVersionMs, getPartialSyncRowByMapId, tryIdsForIndexWindow } from '../chunk-4BEXLBCH.js';
9
+ import '../chunk-5V6BSQAB.js';
10
+ import '../chunk-XC4QNFSQ.js';
11
+ import '../chunk-P3JOTUAB.js';
12
+ import '../chunk-BJJEAKXL.js';
13
+ export { defaultPredicateColumnValue, matchesPredicate } from '../chunk-3EHHMLSV.js';
14
+ import '../chunk-UJ24XW52.js';
15
+ import '../chunk-HMLY7DHA.js';
16
+ //# sourceMappingURL=index.js.map
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,40 @@
1
+ import { PartialSyncRowShape } from '../partial-sync-row-key.js';
2
+ import { RangeCondition, SyncRangeSort } from '../sync-protocol.js';
3
+ import '@firtoz/db-helpers';
4
+ import 'zod';
5
+
6
+ /** Row shape compatible with partial-sync viewport hooks (matches {@link PartialSyncItem}). */
7
+ type PartialSyncViewportItem = PartialSyncRowShape;
8
+ type PredicateSortSpec<TSortColumn extends string> = {
9
+ column: TSortColumn;
10
+ direction: SyncRangeSort["direction"];
11
+ };
12
+ /**
13
+ * Bundles predicate ↔ viewport mapping, optional prefetch expansion, and sort accessors for
14
+ * {@link usePartialSyncViewport} + {@link usePredicateFilteredRows}.
15
+ */
16
+ type PartialSyncViewportAdapter<TItem extends PartialSyncViewportItem, TViewport, TSortColumn extends keyof TItem & string> = {
17
+ toConditions: (viewport: TViewport) => RangeCondition[];
18
+ expandViewport: (viewport: TViewport, pad: number) => TViewport;
19
+ sort: PredicateSortSpec<TSortColumn>;
20
+ getSortValue: (row: TItem, column: TSortColumn) => unknown;
21
+ };
22
+ type CreatePartialSyncAdapterConfig<TItem extends PartialSyncViewportItem, TViewport, TSortColumn extends keyof TItem & string> = {
23
+ toConditions: (viewport: TViewport) => RangeCondition[];
24
+ /** Widen viewport before server `rangeQuery`. Default: identity (no prefetch). */
25
+ expandViewport?: (viewport: TViewport, pad: number) => TViewport;
26
+ sort: PredicateSortSpec<TSortColumn>;
27
+ getSortValue: (row: TItem, column: TSortColumn) => unknown;
28
+ };
29
+ declare function createPartialSyncAdapter<TItem extends PartialSyncViewportItem, TViewport, TSortColumn extends keyof TItem & string>(config: CreatePartialSyncAdapterConfig<TItem, TViewport, TSortColumn>): PartialSyncViewportAdapter<TItem, TViewport, TSortColumn>;
30
+ type NumericAxisSpec<TViewport> = {
31
+ readonly column: string;
32
+ readonly min: (viewport: TViewport) => number;
33
+ readonly max: (viewport: TViewport) => number;
34
+ };
35
+ /**
36
+ * Builds `between` {@link RangeCondition}s from numeric axis accessors (N-D box / interval per column).
37
+ */
38
+ declare function betweenConditionsForNumericAxes<TViewport>(viewport: TViewport, axes: readonly NumericAxisSpec<TViewport>[]): RangeCondition[];
39
+
40
+ export { type CreatePartialSyncAdapterConfig, type NumericAxisSpec, type PartialSyncViewportAdapter, type PartialSyncViewportItem, type PredicateSortSpec, betweenConditionsForNumericAxes, createPartialSyncAdapter };
@@ -0,0 +1,4 @@
1
+ export { betweenConditionsForNumericAxes, createPartialSyncAdapter } from '../chunk-6X3434GJ.js';
2
+ import '../chunk-HMLY7DHA.js';
3
+ //# sourceMappingURL=partial-sync-adapter.js.map
4
+ //# sourceMappingURL=partial-sync-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-adapter.js"}
@@ -0,0 +1,42 @@
1
+ import { CollectionUtils } from '@firtoz/db-helpers';
2
+ import { UtilsRecord } from '@tanstack/db';
3
+ import { RangeFingerprint } from '../sync-protocol.js';
4
+ import { PartialSyncItem, PartialSyncCollection } from './types.js';
5
+ export { defaultPredicateColumnValue, matchesPredicate } from '../partial-sync-predicate-match.js';
6
+ import 'zod';
7
+ import '../cache-manager.js';
8
+ import '../partial-sync-row-key.js';
9
+ import '../partial-sync-client-bridge.js';
10
+ import '../partial-sync-interest.js';
11
+ import './partial-sync-adapter.js';
12
+ import '../connect-partial-sync.js';
13
+ import '../sync-client-bridge.js';
14
+
15
+ /** Merge every row currently in the collection into the bridge cache (id set only). Idempotent. */
16
+ declare function primePartialSyncBridgeCachedIdsFromCollection<TItem extends PartialSyncItem>(bridge: {
17
+ seedHydratedLocalRows: (rows: readonly TItem[]) => void;
18
+ }, collection: Pick<PartialSyncCollection<TItem>, "entries">): void;
19
+ /**
20
+ * TanStack `Collection` types `utils` as {@link UtilsRecord}. This narrows to sync helpers when
21
+ * present (e.g. after `memoryCollectionOptions` / Drizzle sync config).
22
+ */
23
+ declare function assertSyncUtils<TItem>(utils: UtilsRecord): CollectionUtils<TItem>;
24
+ /** Default fingerprint version: max `updatedAt` as epoch ms. */
25
+ declare function defaultPartialSyncVersionMs<TItem extends PartialSyncItem>(row: TItem): number;
26
+ /**
27
+ * Resolve a row for an id stored in the partial-sync index map. Uses {@link PartialSyncCollection.get}
28
+ * first; if that misses (e.g. key type / boxed string mismatch vs TanStack’s internal map), scans
29
+ * {@link PartialSyncCollection.entries} by `String(key)`.
30
+ */
31
+ declare function getPartialSyncRowByMapId<TItem extends PartialSyncItem>(collection: PartialSyncCollection<TItem>, id: string | number): TItem | undefined;
32
+ /**
33
+ * Returns consecutive row ids for `[offset, offset + want)` if all present in the map; else null.
34
+ */
35
+ declare function tryIdsForIndexWindow<TKey extends string | number>(map: Map<number, TKey>, offset: number, want: number, totalCount: number): TKey[] | null;
36
+ /**
37
+ * Fingerprint for reconciliation when every index in `[offset, offset + want)` is mapped and rows
38
+ * exist in the collection.
39
+ */
40
+ declare function computeFingerprintForIndexWindow<TItem extends PartialSyncItem>(collection: PartialSyncCollection<TItem>, map: Map<number, string | number>, offset: number, want: number, getVersionMs?: (row: TItem) => number): RangeFingerprint | undefined;
41
+
42
+ export { assertSyncUtils, computeFingerprintForIndexWindow, defaultPartialSyncVersionMs, getPartialSyncRowByMapId, primePartialSyncBridgeCachedIdsFromCollection, tryIdsForIndexWindow };
@@ -0,0 +1,5 @@
1
+ export { assertSyncUtils, computeFingerprintForIndexWindow, defaultPartialSyncVersionMs, getPartialSyncRowByMapId, primePartialSyncBridgeCachedIdsFromCollection, tryIdsForIndexWindow } from '../chunk-4BEXLBCH.js';
2
+ export { defaultPredicateColumnValue, matchesPredicate } from '../chunk-3EHHMLSV.js';
3
+ import '../chunk-HMLY7DHA.js';
4
+ //# sourceMappingURL=partial-sync-utils.js.map
5
+ //# sourceMappingURL=partial-sync-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-utils.js"}