powersync-bridge 0.0.1-alpha.0 → 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -20
- package/dist/{chunk-TANEBEGU.js → chunk-KAR4QIIU.js} +64 -64
- package/dist/chunk-KAR4QIIU.js.map +1 -0
- package/dist/{clock-BAt_Za0Q.d.cts → clock-DANrBsZH.d.cts} +2 -2
- package/dist/{clock-BAt_Za0Q.d.ts → clock-DANrBsZH.d.ts} +2 -2
- package/dist/index.cjs +645 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +300 -171
- package/dist/index.d.ts +300 -171
- package/dist/index.js +583 -14
- package/dist/index.js.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-TANEBEGU.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,24 +1,87 @@
|
|
|
1
1
|
# powersync-bridge
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
Local SQLite and your HTTP API, behind one list interface for React and React Native.
|
|
4
|
+
|
|
5
|
+
The application defines its SQL, API calls, filters and permissions. The bridge owns racing,
|
|
6
|
+
pagination, pending-write protection, reconciliation, subscriptions, connectivity, retries and
|
|
7
|
+
bounded memory. API results stay in memory; only PowerSync makes records durable offline.
|
|
8
|
+
|
|
9
|
+
## Start with `useInfiniteQuery`
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { useInfiniteQuery } from '@powersync-bridge/react';
|
|
13
|
+
|
|
14
|
+
type Transaction = { id: string; date: string; amount: string };
|
|
15
|
+
|
|
16
|
+
const transactions = useInfiniteQuery<Transaction>({
|
|
17
|
+
queryKey: ['transactions', organizationId, filters, permissionVersion],
|
|
18
|
+
orderBy: ['date', 'id'],
|
|
19
|
+
// Descending order, 25 rows per page and a 500-row memory window are defaults.
|
|
20
|
+
query: ({ cursor, limit }) =>
|
|
21
|
+
db.select().from(transaction)
|
|
22
|
+
.where(and(
|
|
23
|
+
eq(transaction.organizationId, organizationId),
|
|
24
|
+
cursor ? or(
|
|
25
|
+
lt(transaction.date, cursor.date),
|
|
26
|
+
and(eq(transaction.date, cursor.date), lt(transaction.id, cursor.id)),
|
|
27
|
+
) : undefined,
|
|
28
|
+
))
|
|
29
|
+
.orderBy(desc(transaction.date), desc(transaction.id))
|
|
30
|
+
.limit(limit),
|
|
31
|
+
fetchPage: async ({ cursor, limit, signal }) =>
|
|
32
|
+
api.transactions.list({ organizationId, filters,
|
|
33
|
+
cursor: cursor ? { date: cursor.date, id: cursor.id } : undefined,
|
|
34
|
+
limit, signal,
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// FlatList / virtualized list:
|
|
39
|
+
// data={transactions.data}
|
|
40
|
+
// onEndReached={() => transactions.hasNextPage && transactions.fetchNextPage()}
|
|
41
|
+
// refreshing={transactions.isFetching}
|
|
42
|
+
// onRefresh={transactions.refresh}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The local and API rows must have the same decoded shape and a strict, stable sort order.
|
|
46
|
+
Honor the requested `limit`: the bridge requests one extra row to detect another page.
|
|
47
|
+
`cursor` is the previous API row, never a cursor guessed from a sparse local feed. Local reads
|
|
48
|
+
can fill a requested page while its API request is still pending. Every requested page races;
|
|
49
|
+
API requests follow a single cursor chain, including when scrolling outpaces the network.
|
|
50
|
+
|
|
51
|
+
`data` contains ordinary rows. `items` additionally exposes each row's source and local presence
|
|
52
|
+
for edit guards. `error` reports an error preventing the requested range from being filled;
|
|
53
|
+
`errors` retains independent local/API diagnostics even when usable rows are displayed.
|
|
54
|
+
`retry()` retries the pending range. `refresh()` / `refetch()` starts again at the current window.
|
|
55
|
+
At `maxRows`, `needsOlderWindow` becomes true when more history may exist; `continueOlder()`
|
|
56
|
+
opens the next bounded window. Changing `queryKey` discards the previous scope.
|
|
57
|
+
|
|
58
|
+
Include every organization, filter and permission predicate in `queryKey`; the bridge does not
|
|
59
|
+
invent business authorization. It infers the business table for single-table queries. Supply `table`
|
|
60
|
+
for joins or ambiguous queries, or `getRowIdentity(row) => ({ table, id })` for a heterogeneous feed whose display
|
|
61
|
+
IDs differ from the underlying business IDs.
|
|
62
|
+
|
|
63
|
+
`mapQuery(builder, decode)` preserves ORM metadata when decoding rows. `rawQuery(db,
|
|
64
|
+
{ text, params }, tables, decode)` supports parameterized SQL feeds with explicit source tables.
|
|
65
|
+
Both come from `@powersync-bridge/drizzle`; no application adapter or custom watch is needed.
|
|
66
|
+
|
|
67
|
+
## Connectivity
|
|
68
|
+
|
|
69
|
+
Browser connectivity is observed automatically. In React Native, pass the existing network
|
|
70
|
+
hook's boolean once at the provider:
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<BridgeProvider bridge={bridge} online={online}>
|
|
74
|
+
<App />
|
|
75
|
+
</BridgeProvider>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`online` is optional and may be `undefined`. The bridge also handles HTTP failures when a
|
|
79
|
+
connectivity hint incorrectly says online. A disconnected sync socket does not by itself mean
|
|
80
|
+
the API is unavailable. Downloaded rows continue to paginate offline; additional archive rows
|
|
81
|
+
require a connection. Reconnection resumes the pending API range without clearing visible rows.
|
|
82
|
+
|
|
83
|
+
The lower-level `useRacedList`, `useInfiniteList`, `useOnDemandStream` and `useAutoSync` APIs
|
|
84
|
+
remain available for specialized workflows. Ordinary paginated lists need only `useInfiniteQuery`.
|
|
22
85
|
|
|
23
86
|
## What your backend must change
|
|
24
87
|
|
|
@@ -39,7 +102,7 @@ alignment, not a change: your list endpoint sorts rows the same way your local q
|
|
|
39
102
|
pnpm add powersync-bridge @powersync-bridge/react @powersync-bridge/drizzle @powersync-bridge/powersync
|
|
40
103
|
```
|
|
41
104
|
|
|
42
|
-
Peers: `@powersync/common ^
|
|
105
|
+
Peers: `@powersync/common ^1.57.3 || ^2.3`, with your compatible web or native SDK,
|
|
43
106
|
`@powersync/drizzle-driver`, `drizzle-orm`, `react ^18.2 || ^19`. TanStack Query is optional.
|
|
44
107
|
|
|
45
108
|
## Setup (once, in a plain module)
|
|
@@ -1,3 +1,65 @@
|
|
|
1
|
+
// src/keyset.ts
|
|
2
|
+
function keyColumns(orderKey) {
|
|
3
|
+
if (typeof orderKey === "string") return [orderKey, "id"];
|
|
4
|
+
return [orderKey[0], orderKey[1]];
|
|
5
|
+
}
|
|
6
|
+
function idOf(row) {
|
|
7
|
+
const r = row;
|
|
8
|
+
if (r == null || r.id === void 0 || r.id === null) {
|
|
9
|
+
throw new Error("powersync-bridge: every row must have an `id`");
|
|
10
|
+
}
|
|
11
|
+
return String(r.id);
|
|
12
|
+
}
|
|
13
|
+
function compareValues(a, b) {
|
|
14
|
+
if (a === b) return 0;
|
|
15
|
+
if (a === null || a === void 0) return 1;
|
|
16
|
+
if (b === null || b === void 0) return -1;
|
|
17
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
|
|
18
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
19
|
+
if (typeof a === "boolean" && typeof b === "boolean") return Number(a) - Number(b);
|
|
20
|
+
const sa = String(a);
|
|
21
|
+
const sb = String(b);
|
|
22
|
+
return sa < sb ? -1 : sa > sb ? 1 : 0;
|
|
23
|
+
}
|
|
24
|
+
function rowComparator(orderKey, direction = "asc") {
|
|
25
|
+
const [k1, k2] = keyColumns(orderKey);
|
|
26
|
+
const sign = direction === "desc" ? -1 : 1;
|
|
27
|
+
return (a, b) => {
|
|
28
|
+
const c1 = compareValues(a[k1], b[k1]);
|
|
29
|
+
if (c1 !== 0) return c1 * sign;
|
|
30
|
+
return compareValues(a[k2], b[k2]) * sign;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function cursorOfRow(row, orderKey) {
|
|
34
|
+
const r = row;
|
|
35
|
+
if (typeof orderKey === "string") return r[orderKey];
|
|
36
|
+
return [r[orderKey[0]], r[orderKey[1]]];
|
|
37
|
+
}
|
|
38
|
+
function isAfterCursor(row, cursor, orderKey, direction = "asc") {
|
|
39
|
+
const [k1, k2] = keyColumns(orderKey);
|
|
40
|
+
const r = row;
|
|
41
|
+
const sign = direction === "desc" ? -1 : 1;
|
|
42
|
+
const [c1, c2] = typeof orderKey === "string" ? [cursor, void 0] : cursor;
|
|
43
|
+
const d1 = compareValues(r[k1], c1) * sign;
|
|
44
|
+
if (d1 !== 0) return d1 > 0;
|
|
45
|
+
if (c2 === void 0) return false;
|
|
46
|
+
return compareValues(r[k2], c2) * sign > 0;
|
|
47
|
+
}
|
|
48
|
+
function toBase64(s) {
|
|
49
|
+
if (typeof btoa === "function") return btoa(unescape(encodeURIComponent(s)));
|
|
50
|
+
return Buffer.from(s, "utf8").toString("base64");
|
|
51
|
+
}
|
|
52
|
+
function fromBase64(s) {
|
|
53
|
+
if (typeof atob === "function") return decodeURIComponent(escape(atob(s)));
|
|
54
|
+
return Buffer.from(s, "base64").toString("utf8");
|
|
55
|
+
}
|
|
56
|
+
function encodeCursor(cursor) {
|
|
57
|
+
return toBase64(JSON.stringify(cursor));
|
|
58
|
+
}
|
|
59
|
+
function decodeCursor(opaque) {
|
|
60
|
+
return JSON.parse(fromBase64(opaque));
|
|
61
|
+
}
|
|
62
|
+
|
|
1
63
|
// src/freshness.ts
|
|
2
64
|
function streamKey(desc) {
|
|
3
65
|
return `${desc.name}:${desc.params ? JSON.stringify(desc.params) : ""}`;
|
|
@@ -131,68 +193,6 @@ var FreshnessTracker = class {
|
|
|
131
193
|
}
|
|
132
194
|
};
|
|
133
195
|
|
|
134
|
-
// src/keyset.ts
|
|
135
|
-
function keyColumns(orderKey) {
|
|
136
|
-
if (typeof orderKey === "string") return [orderKey, "id"];
|
|
137
|
-
return [orderKey[0], orderKey[1]];
|
|
138
|
-
}
|
|
139
|
-
function idOf(row) {
|
|
140
|
-
const r = row;
|
|
141
|
-
if (r == null || r.id === void 0 || r.id === null) {
|
|
142
|
-
throw new Error("powersync-bridge: every row must have an `id`");
|
|
143
|
-
}
|
|
144
|
-
return String(r.id);
|
|
145
|
-
}
|
|
146
|
-
function compareValues(a, b) {
|
|
147
|
-
if (a === b) return 0;
|
|
148
|
-
if (a === null || a === void 0) return 1;
|
|
149
|
-
if (b === null || b === void 0) return -1;
|
|
150
|
-
if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
|
|
151
|
-
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
152
|
-
if (typeof a === "boolean" && typeof b === "boolean") return Number(a) - Number(b);
|
|
153
|
-
const sa = String(a);
|
|
154
|
-
const sb = String(b);
|
|
155
|
-
return sa < sb ? -1 : sa > sb ? 1 : 0;
|
|
156
|
-
}
|
|
157
|
-
function rowComparator(orderKey, direction = "asc") {
|
|
158
|
-
const [k1, k2] = keyColumns(orderKey);
|
|
159
|
-
const sign = direction === "desc" ? -1 : 1;
|
|
160
|
-
return (a, b) => {
|
|
161
|
-
const c1 = compareValues(a[k1], b[k1]);
|
|
162
|
-
if (c1 !== 0) return c1 * sign;
|
|
163
|
-
return compareValues(a[k2], b[k2]) * sign;
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
function cursorOfRow(row, orderKey) {
|
|
167
|
-
const r = row;
|
|
168
|
-
if (typeof orderKey === "string") return r[orderKey];
|
|
169
|
-
return [r[orderKey[0]], r[orderKey[1]]];
|
|
170
|
-
}
|
|
171
|
-
function isAfterCursor(row, cursor, orderKey, direction = "asc") {
|
|
172
|
-
const [k1, k2] = keyColumns(orderKey);
|
|
173
|
-
const r = row;
|
|
174
|
-
const sign = direction === "desc" ? -1 : 1;
|
|
175
|
-
const [c1, c2] = typeof orderKey === "string" ? [cursor, void 0] : cursor;
|
|
176
|
-
const d1 = compareValues(r[k1], c1) * sign;
|
|
177
|
-
if (d1 !== 0) return d1 > 0;
|
|
178
|
-
if (c2 === void 0) return false;
|
|
179
|
-
return compareValues(r[k2], c2) * sign > 0;
|
|
180
|
-
}
|
|
181
|
-
function toBase64(s) {
|
|
182
|
-
if (typeof btoa === "function") return btoa(unescape(encodeURIComponent(s)));
|
|
183
|
-
return Buffer.from(s, "utf8").toString("base64");
|
|
184
|
-
}
|
|
185
|
-
function fromBase64(s) {
|
|
186
|
-
if (typeof atob === "function") return decodeURIComponent(escape(atob(s)));
|
|
187
|
-
return Buffer.from(s, "base64").toString("utf8");
|
|
188
|
-
}
|
|
189
|
-
function encodeCursor(cursor) {
|
|
190
|
-
return toBase64(JSON.stringify(cursor));
|
|
191
|
-
}
|
|
192
|
-
function decodeCursor(opaque) {
|
|
193
|
-
return JSON.parse(fromBase64(opaque));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
196
|
export { FreshnessTracker, cursorOfRow, decodeCursor, encodeCursor, idOf, isAfterCursor, keyColumns, rowComparator, streamKey };
|
|
197
|
-
//# sourceMappingURL=chunk-
|
|
198
|
-
//# sourceMappingURL=chunk-
|
|
197
|
+
//# sourceMappingURL=chunk-KAR4QIIU.js.map
|
|
198
|
+
//# sourceMappingURL=chunk-KAR4QIIU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/keyset.ts","../src/freshness.ts"],"names":[],"mappings":"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","file":"chunk-KAR4QIIU.js","sourcesContent":["import type { CursorOf, KeyOf, OpaqueCursor, OrderKey, SortDirection } from './types';\n\n/** `id` is always the implicit tiebreaker (§8.3): a scalar key K is treated as [K, 'id']. */\nexport function keyColumns<T>(orderKey: OrderKey<T>): [KeyOf<T>, KeyOf<T>] {\n if (typeof orderKey === 'string') return [orderKey, 'id' as KeyOf<T>];\n return [orderKey[0], orderKey[1]];\n}\n\nexport function idOf(row: unknown): string {\n const r = row as { id?: unknown };\n if (r == null || r.id === undefined || r.id === null) {\n throw new Error('powersync-bridge: every row must have an `id`');\n }\n return String(r.id);\n}\n\nfunction compareValues(a: unknown, b: unknown): number {\n if (a === b) return 0;\n if (a === null || a === undefined) return 1; // nulls last\n if (b === null || b === undefined) return -1;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n if (typeof a === 'boolean' && typeof b === 'boolean') return Number(a) - Number(b);\n const sa = String(a);\n const sb = String(b);\n return sa < sb ? -1 : sa > sb ? 1 : 0;\n}\n\n/** Comparator over rows for the declared order key + direction. Byte order for strings (SQLite BINARY). */\nexport function rowComparator<T>(orderKey: OrderKey<T>, direction: SortDirection = 'asc'): (a: T, b: T) => number {\n const [k1, k2] = keyColumns(orderKey);\n const sign = direction === 'desc' ? -1 : 1;\n return (a, b) => {\n const c1 = compareValues((a as Record<string, unknown>)[k1], (b as Record<string, unknown>)[k1]);\n if (c1 !== 0) return c1 * sign;\n return compareValues((a as Record<string, unknown>)[k2], (b as Record<string, unknown>)[k2]) * sign;\n };\n}\n\n/** The cursor a row yields, in the definition's cursor shape. */\nexport function cursorOfRow<T, K extends OrderKey<T>>(row: T, orderKey: K): CursorOf<T, K> {\n const r = row as Record<string, unknown>;\n if (typeof orderKey === 'string') return r[orderKey] as CursorOf<T, K>;\n return [r[orderKey[0]], r[orderKey[1]]] as CursorOf<T, K>;\n}\n\n/** Whether `row` sorts strictly after `cursor` in the list's order (i.e. is \"beyond\" it). */\nexport function isAfterCursor<T, K extends OrderKey<T>>(\n row: T,\n cursor: CursorOf<T, K>,\n orderKey: K,\n direction: SortDirection = 'asc',\n): boolean {\n const [k1, k2] = keyColumns(orderKey);\n const r = row as Record<string, unknown>;\n const sign = direction === 'desc' ? -1 : 1;\n const [c1, c2] = typeof orderKey === 'string' ? [cursor, undefined] : (cursor as [unknown, unknown]);\n const d1 = compareValues(r[k1], c1) * sign;\n if (d1 !== 0) return d1 > 0;\n if (c2 === undefined) return false;\n return compareValues(r[k2], c2) * sign > 0;\n}\n\nfunction toBase64(s: string): string {\n if (typeof btoa === 'function') return btoa(unescape(encodeURIComponent(s)));\n return Buffer.from(s, 'utf8').toString('base64');\n}\n\nfunction fromBase64(s: string): string {\n if (typeof atob === 'function') return decodeURIComponent(escape(atob(s)));\n return Buffer.from(s, 'base64').toString('utf8');\n}\n\nexport function encodeCursor(cursor: unknown): OpaqueCursor {\n return toBase64(JSON.stringify(cursor)) as OpaqueCursor;\n}\n\nexport function decodeCursor<C>(opaque: OpaqueCursor): C {\n return JSON.parse(fromBase64(opaque)) as C;\n}\n","import type { BridgeDriver, StreamDescription, SyncStatusView } from './types';\n\nexport type Clock = () => number;\n\nexport interface CheckpointCompletion {\n /** Lower-bound stamp of the checkpoint's data position (download start), ms. */\n readonly stamp: number;\n readonly completedAt: number;\n /** Stream this completion was observed on; null for the global status. */\n readonly stream: string | null;\n}\n\nexport function streamKey(desc: StreamDescription): string {\n return `${desc.name}:${desc.params ? JSON.stringify(desc.params) : ''}`;\n}\n\n/**\n * Session-scoped, monotonic, transition-independent freshness (§5.2, R3/R5).\n *\n * stamp(checkpoint_n) = max(observed download start ≤ its completion,\n * completion time of checkpoint n−1,\n * sessionConnectAt when no other bound exists)\n * localFreshAt = max(previous, stamp) — a null observation never lowers it.\n */\nexport class FreshnessTracker {\n private sessionConnectAt: number | null = null;\n private localFreshAt = Number.NEGATIVE_INFINITY;\n private prevCompletionAt: number | null = null;\n private lastDownloadStart: number | null = null;\n private lastSeenSyncedAt: number | null = null;\n private lastDownloading = false;\n private lastConnected = false;\n private lastHasSynced: boolean | undefined = undefined;\n private readonly streamFreshAt = new Map<string, number>();\n private readonly streamSeenSyncedAt = new Map<string, number>();\n private readonly completions: CheckpointCompletion[] = [];\n private readonly completionListeners = new Set<(c: CheckpointCompletion) => void>();\n private readonly clearListeners = new Set<() => void>();\n private unsubscribe: (() => void) | null = null;\n\n constructor(\n private readonly driver: BridgeDriver,\n private readonly clock: Clock,\n ) {}\n\n /** Call once at engine init and again after every identity swap. */\n start(epochStartedAt: number): void {\n this.stop();\n this.reset();\n const status = this.driver.syncStatus();\n this.lastConnected = status.connected;\n this.lastDownloading = status.downloading;\n this.lastHasSynced = status.hasSynced;\n this.lastSeenSyncedAt = status.lastSyncedAt?.getTime() ?? null;\n if (status.connected) this.sessionConnectAt = epochStartedAt;\n // Boot mid-download: provisional bound for the FIRST completion, never applied to localFreshAt now.\n if (status.downloading) {\n this.prevCompletionAt = Math.max(epochStartedAt, this.lastSeenSyncedAt ?? Number.NEGATIVE_INFINITY);\n }\n for (const s of status.syncStreams) {\n if (s.lastSyncedAt) this.streamSeenSyncedAt.set(streamKey(s), s.lastSyncedAt.getTime());\n }\n this.unsubscribe = this.driver.onStatusChanged(() => this.onStatus(this.driver.syncStatus()));\n }\n\n stop(): void {\n this.unsubscribe?.();\n this.unsubscribe = null;\n }\n\n private reset(): void {\n this.sessionConnectAt = null;\n this.localFreshAt = Number.NEGATIVE_INFINITY;\n this.prevCompletionAt = null;\n this.lastDownloadStart = null;\n this.lastSeenSyncedAt = null;\n this.streamFreshAt.clear();\n this.streamSeenSyncedAt.clear();\n this.completions.length = 0;\n }\n\n get sessionConnectAtMs(): number | null {\n return this.sessionConnectAt;\n }\n\n get localFreshAtMs(): number {\n return this.localFreshAt;\n }\n\n streamFreshAtMs(desc: StreamDescription): number {\n return this.streamFreshAt.get(streamKey(desc)) ?? Number.NEGATIVE_INFINITY;\n }\n\n /** Freshness for a list: the owning stream's stamp when declared, else the global stamp. */\n freshAtFor(stream: StreamDescription | undefined): number {\n if (!stream) return this.localFreshAt;\n return Math.max(this.streamFreshAtMs(stream), this.localFreshAt);\n }\n\n /** \"Answered\" = in-session freshness evidence (R5). */\n isFresh(stream: StreamDescription | undefined): boolean {\n if (this.sessionConnectAt === null) return false;\n return this.freshAtFor(stream) >= this.sessionConnectAt;\n }\n\n onCompletion(l: (c: CheckpointCompletion) => void): () => void {\n this.completionListeners.add(l);\n return () => this.completionListeners.delete(l);\n }\n\n onClear(l: () => void): () => void {\n this.clearListeners.add(l);\n return () => this.clearListeners.delete(l);\n }\n\n private onStatus(status: SyncStatusView): void {\n const now = this.clock();\n\n if (status.connected && !this.lastConnected && this.sessionConnectAt === null) {\n this.sessionConnectAt = now; // FIRST connect of the epoch — never per reconnect (R5)\n }\n this.lastConnected = status.connected;\n\n if (status.downloading && !this.lastDownloading) this.lastDownloadStart = now;\n this.lastDownloading = status.downloading;\n\n const syncedAt = status.lastSyncedAt?.getTime() ?? null;\n if (syncedAt !== null && syncedAt !== this.lastSeenSyncedAt) {\n this.recordCompletion(now, null);\n }\n if (syncedAt !== null) this.lastSeenSyncedAt = syncedAt; // null never lowers anything (R5)\n\n for (const s of status.syncStreams) {\n const key = streamKey(s);\n const at = s.lastSyncedAt?.getTime() ?? null;\n if (at !== null && at !== this.streamSeenSyncedAt.get(key)) {\n this.streamSeenSyncedAt.set(key, at);\n const stamp = this.stampFor(now);\n const prev = this.streamFreshAt.get(key) ?? Number.NEGATIVE_INFINITY;\n this.streamFreshAt.set(key, Math.max(prev, stamp));\n const c: CheckpointCompletion = { stamp: Math.max(prev, stamp), completedAt: now, stream: key };\n for (const l of this.completionListeners) l(c);\n }\n }\n\n if (this.lastHasSynced === true && status.hasSynced !== true) {\n for (const l of this.clearListeners) l();\n }\n this.lastHasSynced = status.hasSynced;\n }\n\n private stampFor(now: number): number {\n const candidates: number[] = [];\n if (this.lastDownloadStart !== null && this.lastDownloadStart <= now) candidates.push(this.lastDownloadStart);\n if (this.prevCompletionAt !== null) candidates.push(this.prevCompletionAt);\n if (candidates.length === 0 && this.sessionConnectAt !== null) candidates.push(this.sessionConnectAt);\n if (candidates.length === 0) return Number.NEGATIVE_INFINITY;\n return Math.max(...candidates);\n }\n\n private recordCompletion(now: number, stream: string | null): void {\n const stamp = this.stampFor(now);\n this.localFreshAt = Math.max(this.localFreshAt, stamp);\n this.prevCompletionAt = now;\n this.lastDownloadStart = null; // consumed; the next stamp derives from this completion\n const c: CheckpointCompletion = { stamp: this.localFreshAt, completedAt: now, stream };\n this.completions.push(c);\n for (const l of this.completionListeners) l(c);\n }\n}\n"]}
|
|
@@ -109,7 +109,7 @@ interface BridgeDriver {
|
|
|
109
109
|
diffs<T>(q: PreparedQuery<T>, opts?: {
|
|
110
110
|
throttleMs?: number;
|
|
111
111
|
}): DifferentialStream<T>;
|
|
112
|
-
/** Full read of the upload queue
|
|
112
|
+
/** Full read of the upload queue without acknowledgement, keyed (table, id), last operation wins. */
|
|
113
113
|
pendingUploadIds(): Promise<PendingOpRef[]>;
|
|
114
114
|
/** The driver diffs consecutive queue snapshots and EMITS the delta; core never re-diffs. */
|
|
115
115
|
onCrudChange(cb: (delta: CrudDelta) => void): () => void;
|
|
@@ -268,4 +268,4 @@ interface BridgeClock {
|
|
|
268
268
|
}
|
|
269
269
|
declare const realClock: BridgeClock;
|
|
270
270
|
|
|
271
|
-
export { type ApiOffsetPolicy as A, type BridgeDriver as B, type CursorOf as C, type DifferentialStream as D, type EscalationPolicy as E, type Snapshot as F, type StreamHandle as G, type StreamStatus as H, type InfiniteListResult as I, type SyncStatusView as J, type KeyOf as K, type ListErrors as L, type MeasureSink as M, realClock as N, type OrderKey as O, type
|
|
271
|
+
export { type ApiOffsetPolicy as A, type BridgeDriver as B, type CursorOf as C, type DifferentialStream as D, type EscalationPolicy as E, type Snapshot as F, type StreamHandle as G, type StreamStatus as H, type InfiniteListResult as I, type SyncStatusView as J, type KeyOf as K, type ListErrors as L, type MeasureSink as M, realClock as N, type OrderKey as O, type PendingOpRef as P, type QueryAdapter as Q, type RacedListResult as R, type StreamDescription as S, type OpaqueCursor as a, type SortDirection as b, type CrudDelta as c, type BridgeClock as d, type Store as e, type RacedListDefinition as f, type RowsBuilder as g, type PagedRow as h, type InfiniteListDefinition as i, type OnDemandResult as j, type Params as k, type ApiPolicy as l, type Boundary as m, type BoundaryReason as n, type CompilableQuery as o, type Cursor as p, type ListState as q, type OnDemandStatus as r, type PageArgs as s, type PartitionPolicy as t, type PendingOp as u, type PreparedQuery as v, type PriorityStatus as w, type RaceMeasurement as x, type RowDiff as y, type RowOrigin as z };
|
|
@@ -109,7 +109,7 @@ interface BridgeDriver {
|
|
|
109
109
|
diffs<T>(q: PreparedQuery<T>, opts?: {
|
|
110
110
|
throttleMs?: number;
|
|
111
111
|
}): DifferentialStream<T>;
|
|
112
|
-
/** Full read of the upload queue
|
|
112
|
+
/** Full read of the upload queue without acknowledgement, keyed (table, id), last operation wins. */
|
|
113
113
|
pendingUploadIds(): Promise<PendingOpRef[]>;
|
|
114
114
|
/** The driver diffs consecutive queue snapshots and EMITS the delta; core never re-diffs. */
|
|
115
115
|
onCrudChange(cb: (delta: CrudDelta) => void): () => void;
|
|
@@ -268,4 +268,4 @@ interface BridgeClock {
|
|
|
268
268
|
}
|
|
269
269
|
declare const realClock: BridgeClock;
|
|
270
270
|
|
|
271
|
-
export { type ApiOffsetPolicy as A, type BridgeDriver as B, type CursorOf as C, type DifferentialStream as D, type EscalationPolicy as E, type Snapshot as F, type StreamHandle as G, type StreamStatus as H, type InfiniteListResult as I, type SyncStatusView as J, type KeyOf as K, type ListErrors as L, type MeasureSink as M, realClock as N, type OrderKey as O, type
|
|
271
|
+
export { type ApiOffsetPolicy as A, type BridgeDriver as B, type CursorOf as C, type DifferentialStream as D, type EscalationPolicy as E, type Snapshot as F, type StreamHandle as G, type StreamStatus as H, type InfiniteListResult as I, type SyncStatusView as J, type KeyOf as K, type ListErrors as L, type MeasureSink as M, realClock as N, type OrderKey as O, type PendingOpRef as P, type QueryAdapter as Q, type RacedListResult as R, type StreamDescription as S, type OpaqueCursor as a, type SortDirection as b, type CrudDelta as c, type BridgeClock as d, type Store as e, type RacedListDefinition as f, type RowsBuilder as g, type PagedRow as h, type InfiniteListDefinition as i, type OnDemandResult as j, type Params as k, type ApiPolicy as l, type Boundary as m, type BoundaryReason as n, type CompilableQuery as o, type Cursor as p, type ListState as q, type OnDemandStatus as r, type PageArgs as s, type PartitionPolicy as t, type PendingOp as u, type PreparedQuery as v, type PriorityStatus as w, type RaceMeasurement as x, type RowDiff as y, type RowOrigin as z };
|