bunderstack-sync 0.17.0-beta.2 → 0.17.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,106 @@
1
+ import type { QueryClient } from '@tanstack/react-query';
2
+ import { type Collection, type StandardSchema } from '@tanstack/db';
3
+ type TableListResult<TRow> = {
4
+ items: TRow[];
5
+ hasMore: boolean;
6
+ nextCursor?: string;
7
+ total?: number;
8
+ limit?: number;
9
+ offset?: number;
10
+ };
11
+ type TableProcedures<TRow, TCreate, TUpdate> = {
12
+ list: {
13
+ call(input?: Record<string, unknown>): Promise<TableListResult<TRow>>;
14
+ };
15
+ get: {
16
+ call(input: {
17
+ id: string;
18
+ }): Promise<TRow>;
19
+ };
20
+ create: {
21
+ call(input: TCreate): Promise<TRow>;
22
+ };
23
+ update: {
24
+ call(input: {
25
+ params: {
26
+ id: string;
27
+ };
28
+ query: {};
29
+ headers: {};
30
+ body: TUpdate;
31
+ }): Promise<TRow>;
32
+ };
33
+ delete: {
34
+ call(input: {
35
+ id: string;
36
+ }): Promise<void>;
37
+ };
38
+ };
39
+ export type DirectTableApi<TRow, TCreate, TUpdate> = {
40
+ list(input?: Record<string, unknown>): Promise<TableListResult<TRow>>;
41
+ get(id: string | number): Promise<TRow>;
42
+ create(input: TCreate): Promise<TRow>;
43
+ update(id: string | number, input: TUpdate): Promise<TRow>;
44
+ delete(id: string | number): Promise<void>;
45
+ };
46
+ export type TableCollectionConfig = {
47
+ tableName: string;
48
+ procedures: TableProcedures<any, any, any>;
49
+ queryClient: QueryClient;
50
+ /** Rows the default `.collection` syncs per fetch. Defaults to 100. For
51
+ * feed-shaped tables that need real pagination use `scopedCollection`. */
52
+ limit?: number;
53
+ };
54
+ export type ScopedFilterValue = string | number | boolean | null | readonly (string | number)[];
55
+ export type ScopedCollectionOptions = {
56
+ /** Equality filters, e.g. `{ replyToId: null }` — columns must be in the
57
+ * table's `filterableColumns` server-side. Same name and shape as the
58
+ * `filters` accepted by the list procedure. */
59
+ filters?: Record<string, ScopedFilterValue>;
60
+ sort?: string;
61
+ order?: 'asc' | 'desc';
62
+ /** Rows per underlying request; clamped to the server cap (200). */
63
+ pageSize?: number;
64
+ /** Window size on first load and default `loadMore` step. Defaults to 20. */
65
+ initialCount?: number;
66
+ };
67
+ export declare function createTableCollection<TRow extends {
68
+ id: string | number;
69
+ }, TCreate = Partial<TRow>, TUpdate = Partial<TRow>>(config: TableCollectionConfig): {
70
+ collection: import("@tanstack/db").Collection<TRow, string | number, import("@tanstack/query-db-collection").QueryCollectionUtils<TRow, string | number, TRow, unknown>, never, TRow> & import("@tanstack/db").NonSingleResult;
71
+ table: DirectTableApi<TRow, TCreate, TUpdate>;
72
+ scopedCollection: (options?: ScopedCollectionOptions) => {
73
+ collection: import("@tanstack/db").Collection<TRow, string | number, import("@tanstack/query-db-collection").QueryCollectionUtils<TRow, string | number, TRow, unknown>, never, TRow> & import("@tanstack/db").NonSingleResult;
74
+ /** Grow the window by `count` (default initialCount) and refetch in place. */
75
+ loadMore: (count?: number) => Promise<void>;
76
+ /** Whether the server reported rows beyond the window (as of last fetch). */
77
+ hasMore: () => boolean;
78
+ /** Current desired window size. */
79
+ size: () => number;
80
+ };
81
+ collectionByIds: (ids: readonly TRow["id"][], options?: {
82
+ column?: string;
83
+ }) => import("@tanstack/db").Collection<TRow, string | number, import("@tanstack/query-db-collection").QueryCollectionUtils<TRow, string | number, TRow, unknown>, never, TRow> & import("@tanstack/db").NonSingleResult;
84
+ applyRealtimeEvent: (action: "create" | "update" | "delete", record: Record<string, unknown>) => void;
85
+ refetchAll: () => Promise<void>;
86
+ };
87
+ export type ScopedCollection<TRow extends {
88
+ id: string | number;
89
+ }> = {
90
+ collection: Collection<TRow, string | number, Record<string, any>, StandardSchema<TRow>>;
91
+ loadMore: (count?: number) => Promise<void>;
92
+ hasMore: () => boolean;
93
+ size: () => number;
94
+ };
95
+ export type TableCollection<TRow extends {
96
+ id: string | number;
97
+ }, TCreate = Partial<TRow>, TUpdate = Partial<TRow>> = {
98
+ collection: Collection<TRow, string | number, Record<string, any>, StandardSchema<TRow>>;
99
+ table: DirectTableApi<TRow, TCreate, TUpdate>;
100
+ scopedCollection: (options?: ScopedCollectionOptions) => ScopedCollection<TRow>;
101
+ collectionByIds: (ids: readonly (string | number)[], column?: string) => Collection<TRow, string | number, Record<string, any>, StandardSchema<TRow>>;
102
+ applyRealtimeEvent: (action: 'create' | 'update' | 'delete', record: Record<string, unknown>) => void;
103
+ refetchAll: () => Promise<void>;
104
+ };
105
+ export {};
106
+ //# sourceMappingURL=collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,258 @@
1
+ import { createCollection, } from '@tanstack/db';
2
+ import { queryCollectionOptions } from '@tanstack/query-db-collection';
3
+ import { createUpdateQueue } from './update-queue.js';
4
+ const MAX_LIST_LIMIT = 200;
5
+ function matchesFilter(record, filters) {
6
+ for (const [col, expected] of Object.entries(filters)) {
7
+ const actual = record[col];
8
+ if (expected === null) {
9
+ if (actual != null)
10
+ return false;
11
+ }
12
+ else if (Array.isArray(expected)) {
13
+ if (!expected.map(String).includes(String(actual)))
14
+ return false;
15
+ }
16
+ else if (String(actual) !== String(expected))
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ /** Deterministic serialization for cache keys (object key order ignored). */
22
+ function stableKey(value) {
23
+ if (value === null || typeof value !== 'object')
24
+ return JSON.stringify(value);
25
+ if (Array.isArray(value))
26
+ return `[${value.map(stableKey).join(',')}]`;
27
+ const entries = Object.entries(value)
28
+ .sort(([a], [b]) => (a < b ? -1 : 1))
29
+ .map(([k, v]) => `${JSON.stringify(k)}:${stableKey(v)}`);
30
+ return `{${entries.join(',')}}`;
31
+ }
32
+ export function createTableCollection(config) {
33
+ const table = config.procedures;
34
+ const direct = {
35
+ list: (input = {}) => table.list.call(input),
36
+ get: (id) => table.get.call({ id: String(id) }),
37
+ create: (input) => table.create.call(input),
38
+ update: (id, input) => table.update.call({
39
+ params: { id: String(id) },
40
+ query: {},
41
+ headers: {},
42
+ body: input,
43
+ }),
44
+ delete: (id) => table.delete.call({ id: String(id) }),
45
+ };
46
+ const collection = createCollection(queryCollectionOptions({
47
+ queryKey: [config.tableName, 'collection'],
48
+ queryFn: async () => {
49
+ const page = await table.list.call({ limit: config.limit ?? 100 });
50
+ return page.items;
51
+ },
52
+ queryClient: config.queryClient,
53
+ getKey: (item) => item.id,
54
+ onInsert: async ({ transaction }) => {
55
+ let reconciled = true;
56
+ for (const mutation of transaction.mutations) {
57
+ // Pass the client-generated `id` through as-is. TanStack DB's
58
+ // optimistic insert keys the local row by this `id` (via `getKey`),
59
+ // and this matches `sanitizeWriteBody`'s default on the server: a
60
+ // client-supplied `id` on create is accepted unless the table's
61
+ // access config sets an explicit `writableColumns` allowlist that
62
+ // excludes `id`.
63
+ const row = (await table.create.call(mutation.modified));
64
+ // Apps that DO restrict it that way get a server-assigned id, which
65
+ // leaves the optimistic row keyed under the client's — `writeUpsert`
66
+ // can't retire that, so those fall back to the refetch.
67
+ if (row?.id != null && String(row.id) === String(mutation.key)) {
68
+ applyRealtimeEvent('create', row);
69
+ }
70
+ else {
71
+ reconciled = false;
72
+ }
73
+ }
74
+ return reconciled ? { refetch: false } : {};
75
+ },
76
+ onUpdate: async ({ transaction }) => {
77
+ await Promise.all(transaction.mutations.map((mutation) => updateQueue.enqueue(mutation.key, mutation.changes)));
78
+ return { refetch: false };
79
+ },
80
+ onDelete: async ({ transaction }) => {
81
+ for (const mutation of transaction.mutations) {
82
+ // Updates still queued for this row are superseded, and one already
83
+ // in flight must land before the DELETE or the two race.
84
+ await updateQueue.settle(mutation.key);
85
+ await table.delete.call({ id: String(mutation.key) });
86
+ applyRealtimeEvent('delete', { id: mutation.key });
87
+ }
88
+ return { refetch: false };
89
+ },
90
+ }));
91
+ // Cursor-shaped workloads call `update()` many times a second. The queue
92
+ // merges everything that piles up for a row while its request is in flight
93
+ // into a single follow-up, so request rate tracks RTT, not call rate.
94
+ const updateQueue = createUpdateQueue({
95
+ send: (id, changes) => table.update.call({
96
+ params: { id: String(id) },
97
+ query: {},
98
+ headers: {},
99
+ body: changes,
100
+ }),
101
+ onResult: async (row) => {
102
+ // `writeUpsert` writes the response whole, so mutation endpoints are
103
+ // contracted to return a full row. A body without an id can't be
104
+ // reconciled locally — fall back to the refetch rather than write it.
105
+ if (row?.id == null)
106
+ await collection.utils.refetch();
107
+ else
108
+ applyRealtimeEvent('update', row);
109
+ },
110
+ });
111
+ // Scoped/byIds collections register here so realtime events fan out to
112
+ // every live view of this table, filtered client-side by each view's
113
+ // own predicate (broadcasts are already access-filtered server-side).
114
+ const registry = [];
115
+ const scopedCache = new Map();
116
+ function scopedCollection(options = {}) {
117
+ const pageSize = Math.min(options.pageSize ?? MAX_LIST_LIMIT, MAX_LIST_LIMIT);
118
+ const initialCount = options.initialCount ?? 20;
119
+ const filters = options.filters ?? {};
120
+ const cacheKey = stableKey({
121
+ filters,
122
+ sort: options.sort ?? null,
123
+ order: options.order ?? null,
124
+ pageSize,
125
+ initialCount,
126
+ });
127
+ const cached = scopedCache.get(cacheKey);
128
+ if (cached)
129
+ return cached;
130
+ let desiredCount = initialCount;
131
+ let serverHasMore = false;
132
+ const scoped = createCollection(queryCollectionOptions({
133
+ queryKey: [config.tableName, 'scoped', cacheKey],
134
+ queryFn: async () => {
135
+ // Growing window: walk cursor pages (each ≤ the server cap) until
136
+ // the current desired count is collected or the table runs out.
137
+ // The collection stays stable across loadMore — refetching in
138
+ // place only ever adds rows, so already-rendered items never
139
+ // unmount (no scroll jumps or zero-item flashes).
140
+ const items = [];
141
+ let cursor;
142
+ let more = false;
143
+ while (items.length < desiredCount) {
144
+ const remaining = Math.min(pageSize, desiredCount - items.length);
145
+ const page = await table.list.call({
146
+ ...(Object.keys(filters).length ? { filters } : {}),
147
+ ...(options.sort ? { sort: options.sort } : {}),
148
+ ...(options.order ? { order: options.order } : {}),
149
+ limit: remaining,
150
+ ...(cursor ? { cursor } : {}),
151
+ });
152
+ items.push(...page.items);
153
+ more = Boolean(page.hasMore && page.nextCursor);
154
+ if (!more)
155
+ break;
156
+ cursor = page.nextCursor;
157
+ }
158
+ serverHasMore = more;
159
+ return items.slice(0, desiredCount);
160
+ },
161
+ queryClient: config.queryClient,
162
+ getKey: (item) => item.id,
163
+ }));
164
+ const entry = {
165
+ collection: scoped,
166
+ loadMore: async (count) => {
167
+ desiredCount += count ?? initialCount;
168
+ await scoped.utils.refetch();
169
+ },
170
+ hasMore: () => serverHasMore,
171
+ size: () => desiredCount,
172
+ };
173
+ registry.push({
174
+ collection: scoped,
175
+ matches: (record) => matchesFilter(record, filters),
176
+ refetch: async () => {
177
+ await scoped.utils.refetch();
178
+ },
179
+ });
180
+ scopedCache.set(cacheKey, entry);
181
+ return entry;
182
+ }
183
+ const byIdsCache = new Map();
184
+ function collectionByIds(ids, options = {}) {
185
+ const column = options.column ?? 'id';
186
+ const unique = Array.from(new Set(ids.map(String))).sort();
187
+ const cacheKey = `${column}:${unique.join(',')}`;
188
+ const cached = byIdsCache.get(cacheKey);
189
+ if (cached)
190
+ return cached;
191
+ const idSet = new Set(unique);
192
+ const byIds = createCollection(queryCollectionOptions({
193
+ queryKey: [config.tableName, 'byIds', column, unique],
194
+ queryFn: async () => {
195
+ if (unique.length === 0)
196
+ return [];
197
+ const items = [];
198
+ // Chunked at the server's IN-filter cap so any id set works.
199
+ for (let i = 0; i < unique.length; i += MAX_LIST_LIMIT) {
200
+ const chunk = unique.slice(i, i + MAX_LIST_LIMIT);
201
+ const page = await table.list.call({
202
+ filters: { [column]: chunk },
203
+ limit: chunk.length,
204
+ });
205
+ items.push(...page.items);
206
+ }
207
+ return items;
208
+ },
209
+ queryClient: config.queryClient,
210
+ getKey: (item) => item.id,
211
+ }));
212
+ registry.push({
213
+ collection: byIds,
214
+ matches: (record) => idSet.has(String(record[column])),
215
+ refetch: async () => {
216
+ await byIds.utils.refetch();
217
+ },
218
+ });
219
+ byIdsCache.set(cacheKey, byIds);
220
+ return byIds;
221
+ }
222
+ function applyRealtimeEvent(action, record) {
223
+ const id = record['id'];
224
+ const apply = (target, matches) => {
225
+ // Collections that never started syncing (no subscribers yet) can't
226
+ // accept manual writes — and don't need to: their first sync fetches
227
+ // fresh data anyway.
228
+ if (target.status !== 'ready')
229
+ return;
230
+ if (action === 'delete' || !matches(record)) {
231
+ if (target.get(id) !== undefined)
232
+ target.utils.writeDelete(id);
233
+ }
234
+ else {
235
+ target.utils.writeUpsert(record);
236
+ }
237
+ };
238
+ apply(collection, () => true);
239
+ for (const entry of registry)
240
+ apply(entry.collection, entry.matches);
241
+ }
242
+ /** Refetch the base collection plus every scoped/byIds view after reconnect. */
243
+ async function refetchAll() {
244
+ await Promise.all([
245
+ collection.utils.refetch(),
246
+ ...registry.map((entry) => entry.refetch()),
247
+ ]);
248
+ }
249
+ return {
250
+ collection,
251
+ table: direct,
252
+ scopedCollection,
253
+ collectionByIds,
254
+ applyRealtimeEvent,
255
+ refetchAll,
256
+ };
257
+ }
258
+ //# sourceMappingURL=collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection.js","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { createSyncClient } from './sync-client.js';
2
+ export type { BunderstackSyncClient, CreateFor, RowFor, SyncClientOptions } from './sync-client.js';
3
+ export { createTableCollection } from './collection.js';
4
+ export type { ScopedCollectionOptions, ScopedFilterValue, TableCollection, TableCollectionConfig } from './collection.js';
5
+ export { createSyncRealtimeClient } from './realtime-sync.js';
6
+ export type { SyncRealtimeConfig, SyncRealtimeTarget } from './realtime-sync.js';
7
+ export type { AnyBunderstackApp, InferBuckets, InferInsert, InferSchema, InferSelect, InferTables, UploadedFile } from 'bunderstack-query';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,YAAY,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAChG,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,YAAY,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACtH,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAC7E,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { createSyncClient } from './sync-client.js';
2
+ export { createTableCollection } from './collection.js';
3
+ export { createSyncRealtimeClient } from './realtime-sync.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,25 @@
1
+ import type { QueryClient } from '@tanstack/react-query';
2
+ import { type RealtimeQueryApi, type RealtimeSyncHandle } from 'bunderstack-query';
3
+ type SyncableCollection = {
4
+ utils: {
5
+ writeUpsert: (item: unknown) => void;
6
+ writeDelete: (key: unknown) => void;
7
+ refetch: () => Promise<void>;
8
+ };
9
+ };
10
+ export type SyncRealtimeTarget = {
11
+ applyRealtimeEvent: (action: 'create' | 'update' | 'delete', record: Record<string, unknown>) => void;
12
+ refetchAll: () => Promise<void>;
13
+ };
14
+ export type SyncRealtimeConfig = {
15
+ api: RealtimeQueryApi;
16
+ queryClient: QueryClient;
17
+ tables: string[];
18
+ collections?: Record<string, SyncableCollection>;
19
+ resolve?: (table: string) => SyncRealtimeTarget | undefined;
20
+ resolveAll?: () => Iterable<SyncRealtimeTarget>;
21
+ retryMs?: number;
22
+ };
23
+ export declare function createSyncRealtimeClient(config: SyncRealtimeConfig): RealtimeSyncHandle;
24
+ export {};
25
+ //# sourceMappingURL=realtime-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-sync.d.ts","sourceRoot":"","sources":["../src/realtime-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAA;AAE1B,KAAK,kBAAkB,GAAG;IACxB,KAAK,EAAE;QACL,WAAW,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;QACpC,WAAW,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;QACnC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAC7B,CAAA;CACF,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kBAAkB,EAAE,CAClB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,IAAI,CAAA;IACT,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,gBAAgB,CAAA;IACrB,WAAW,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAA;IAC3D,UAAU,CAAC,EAAE,MAAM,QAAQ,CAAC,kBAAkB,CAAC,CAAA;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,kBAAkB,GACzB,kBAAkB,CAyBpB"}
@@ -0,0 +1,31 @@
1
+ import { syncRealtime, } from 'bunderstack-query';
2
+ export function createSyncRealtimeClient(config) {
3
+ const collections = config.collections ?? {};
4
+ return syncRealtime({
5
+ api: config.api,
6
+ queryClient: config.queryClient,
7
+ tables: config.tables,
8
+ retryMs: config.retryMs,
9
+ onChange: (event) => {
10
+ if (config.resolve) {
11
+ config.resolve(event.table)?.applyRealtimeEvent(event.action, event.record);
12
+ return;
13
+ }
14
+ const collection = collections[event.table];
15
+ if (!collection)
16
+ return;
17
+ if (event.action === 'delete')
18
+ collection.utils.writeDelete(event.record['id']);
19
+ else
20
+ collection.utils.writeUpsert(event.record);
21
+ },
22
+ onReconnect: async () => {
23
+ if (config.resolveAll) {
24
+ await Promise.all([...config.resolveAll()].map((target) => target.refetchAll()));
25
+ return;
26
+ }
27
+ await Promise.all(Object.values(collections).map((collection) => collection.utils.refetch()));
28
+ },
29
+ });
30
+ }
31
+ //# sourceMappingURL=realtime-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-sync.js","sourceRoot":"","sources":["../src/realtime-sync.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,GAGb,MAAM,mBAAmB,CAAA;AA4B1B,MAAM,UAAU,wBAAwB,CACtC,MAA0B;IAE1B,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,EAAE,CAAA;IAC5C,OAAO,YAAY,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;YAClB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;gBAC3E,OAAM;YACR,CAAC;YACD,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC3C,IAAI,CAAC,UAAU;gBAAE,OAAM;YACvB,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ;gBAAE,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;;gBAC1E,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACjD,CAAC;QACD,WAAW,EAAE,KAAK,IAAI,EAAE;YACtB,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;gBAChF,OAAM;YACR,CAAC;YACD,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QAC/F,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { QueryClient } from '@tanstack/react-query';
2
+ import { type AnyBunderstackApp, type BunderstackClient, type InferInsert, type InferSchema, type InferSelect, type InferTables } from 'bunderstack-query';
3
+ import { type TableCollection } from './collection.js';
4
+ export type RowFor<TSchema extends Record<string, unknown>, K extends keyof TSchema> = [
5
+ InferSelect<TSchema[K]>
6
+ ] extends [never] ? {
7
+ id: string | number;
8
+ } : InferSelect<TSchema[K]> extends {
9
+ id: string | number;
10
+ } ? InferSelect<TSchema[K]> : {
11
+ id: string | number;
12
+ };
13
+ export type CreateFor<TSchema extends Record<string, unknown>, K extends keyof TSchema> = [
14
+ InferInsert<TSchema[K]>
15
+ ] extends [never] ? Partial<RowFor<TSchema, K>> : InferInsert<TSchema[K]>;
16
+ export type SyncClientOptions = {
17
+ baseUrl?: string;
18
+ fetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
19
+ queryClient: QueryClient;
20
+ realtime?: boolean;
21
+ };
22
+ export type BunderstackSyncClient<TApp extends AnyBunderstackApp> = {
23
+ [K in InferTables<TApp>]: TableCollection<RowFor<InferSchema<TApp>, K>, CreateFor<InferSchema<TApp>, K>, Partial<RowFor<InferSchema<TApp>, K>>>;
24
+ } & {
25
+ files: BunderstackClient<TApp>['files'];
26
+ realtime: {
27
+ close(): void;
28
+ subscribe(tables: string[]): Promise<void>;
29
+ } | undefined;
30
+ };
31
+ export declare function createSyncClient<TApp extends AnyBunderstackApp>(options: SyncClientOptions): BunderstackSyncClient<TApp>;
32
+ //# sourceMappingURL=sync-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-client.d.ts","sourceRoot":"","sources":["../src/sync-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AAG1E,MAAM,MAAM,MAAM,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,OAAO,IACjF;IAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAAC,SAAS,CAAC,KAAK,CAAC,GACrC;IAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GACvB,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GACrD,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACvB;IAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAA;AAE/B,MAAM,MAAM,SAAS,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,OAAO,IACpF;IAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAAC,SAAS,CAAC,KAAK,CAAC,GACrC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,GAC3B,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAE7B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,CACN,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,KACf,OAAO,CAAC,QAAQ,CAAC,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,IAAI,SAAS,iBAAiB,IAAI;KACjE,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,eAAe,CACvC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAC5B,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAC/B,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CACtC;CACF,GAAG;IACF,KAAK,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAA;IACvC,QAAQ,EAAE;QAAE,KAAK,IAAI,IAAI,CAAC;QAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GAAG,SAAS,CAAA;CACpF,CAAA;AAED,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,iBAAiB,EAC7D,OAAO,EAAE,iBAAiB,GACzB,qBAAqB,CAAC,IAAI,CAAC,CA+C7B"}
@@ -0,0 +1,53 @@
1
+ import { createClient, } from 'bunderstack-query';
2
+ import { createTableCollection } from './collection.js';
3
+ import { createSyncRealtimeClient } from './realtime-sync.js';
4
+ export function createSyncClient(options) {
5
+ const api = createClient(options);
6
+ const materialized = new Map();
7
+ const realtimeHandles = new Map();
8
+ const tables = new Map();
9
+ const realtimeEnabled = options.realtime ?? typeof window !== 'undefined';
10
+ const result = new Proxy({}, {
11
+ get(_target, property) {
12
+ if (typeof property !== 'string')
13
+ return undefined;
14
+ if (property === 'files')
15
+ return api.files;
16
+ if (property === 'realtime') {
17
+ return realtimeEnabled
18
+ ? {
19
+ close: () => realtimeHandles.forEach((handle) => handle.close()),
20
+ subscribe: async (names) => {
21
+ for (const name of names)
22
+ void result[name];
23
+ },
24
+ }
25
+ : undefined;
26
+ }
27
+ if (['then', 'toJSON', 'constructor', '$$typeof'].includes(property))
28
+ return undefined;
29
+ const cached = tables.get(property);
30
+ if (cached)
31
+ return cached;
32
+ const collection = createTableCollection({
33
+ tableName: property,
34
+ procedures: api[property],
35
+ queryClient: options.queryClient,
36
+ });
37
+ tables.set(property, collection);
38
+ materialized.set(property, collection);
39
+ if (realtimeEnabled) {
40
+ realtimeHandles.set(property, createSyncRealtimeClient({
41
+ api: api,
42
+ queryClient: options.queryClient,
43
+ tables: [property],
44
+ resolve: (table) => materialized.get(table),
45
+ resolveAll: () => materialized.values(),
46
+ }));
47
+ }
48
+ return collection;
49
+ },
50
+ });
51
+ return result;
52
+ }
53
+ //# sourceMappingURL=sync-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-client.js","sourceRoot":"","sources":["../src/sync-client.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,GAOb,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,qBAAqB,EAAwB,MAAM,cAAc,CAAA;AAC1E,OAAO,EAAE,wBAAwB,EAA2B,MAAM,iBAAiB,CAAA;AAmCnF,MAAM,UAAU,gBAAgB,CAC9B,OAA0B;IAE1B,MAAM,GAAG,GAAG,YAAY,CAAO,OAAO,CAAC,CAAA;IACvC,MAAM,YAAY,GAAG,IAAI,GAAG,EAA8B,CAAA;IAC1D,MAAM,eAAe,GAAG,IAAI,GAAG,EAA6B,CAAA;IAC5D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAA;IACzC,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,MAAM,KAAK,WAAW,CAAA;IAEzE,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,EAAiC,EAAE;QAC1D,GAAG,CAAC,OAAO,EAAE,QAAQ;YACnB,IAAI,OAAO,QAAQ,KAAK,QAAQ;gBAAE,OAAO,SAAS,CAAA;YAClD,IAAI,QAAQ,KAAK,OAAO;gBAAE,OAAO,GAAG,CAAC,KAAK,CAAA;YAC1C,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;gBAC5B,OAAO,eAAe;oBACpB,CAAC,CAAC;wBACE,KAAK,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;wBAChE,SAAS,EAAE,KAAK,EAAE,KAAe,EAAE,EAAE;4BACnC,KAAK,MAAM,IAAI,IAAI,KAAK;gCAAE,KAAM,MAAc,CAAC,IAAI,CAAC,CAAA;wBACtD,CAAC;qBACF;oBACH,CAAC,CAAC,SAAS,CAAA;YACf,CAAC;YACD,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAE,OAAO,SAAS,CAAA;YACtF,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACnC,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAA;YACzB,MAAM,UAAU,GAAG,qBAAqB,CAAC;gBACvC,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAG,GAAW,CAAC,QAAQ,CAAC;gBAClC,WAAW,EAAE,OAAO,CAAC,WAAW;aACjC,CAAC,CAAA;YACF,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;YAChC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;YACtC,IAAI,eAAe,EAAE,CAAC;gBACpB,eAAe,CAAC,GAAG,CACjB,QAAQ,EACR,wBAAwB,CAAC;oBACvB,GAAG,EAAE,GAAU;oBACf,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,MAAM,EAAE,CAAC,QAAQ,CAAC;oBAClB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;oBAC3C,UAAU,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE;iBACxC,CAAC,CACH,CAAA;YACH,CAAC;YACD,OAAO,UAAU,CAAA;QACnB,CAAC;KACF,CAAC,CAAA;IACF,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,27 @@
1
+ /** Per-key coalescing queue for high-frequency row updates.
2
+ *
3
+ * Cursor-shaped workloads call `collection.update()` many times a second. Sent
4
+ * one-for-one, each call is a request, a database write and a broadcast. This
5
+ * queue holds a single merged slot per row key: while a request is in flight,
6
+ * further updates for that key merge into the slot and go out as one follow-up
7
+ * once it lands. Request frequency settles at `min(update rate, 1/RTT)` without
8
+ * a tuned throttle constant, and the optimistic UI is untouched — only the
9
+ * network is coalesced.
10
+ */
11
+ export type UpdateQueueConfig<TKey, TRow> = {
12
+ /** Sends one merged batch of changes and resolves with the canonical row. */
13
+ send: (key: TKey, changes: Record<string, unknown>) => Promise<TRow>;
14
+ /** Called with the server's row before the batch's waiters resolve. Awaited,
15
+ * so a handler that needs to recover (refetch) finishes first. */
16
+ onResult: (row: TRow) => void | Promise<void>;
17
+ };
18
+ export type UpdateQueue<TKey> = {
19
+ /** Queues changes for `key`. Resolves once a request carrying them lands. */
20
+ enqueue: (key: TKey, changes: Record<string, unknown>) => Promise<void>;
21
+ /** Drops changes still queued for `key` (resolving their waiters) and waits
22
+ * for any in-flight request to land. For operations that supersede pending
23
+ * updates and must not race them — a delete of the same row. */
24
+ settle: (key: TKey) => Promise<void>;
25
+ };
26
+ export declare function createUpdateQueue<TKey, TRow>(config: UpdateQueueConfig<TKey, TRow>): UpdateQueue<TKey>;
27
+ //# sourceMappingURL=update-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-queue.d.ts","sourceRoot":"","sources":["../src/update-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAcH,MAAM,MAAM,iBAAiB,CAAC,IAAI,EAAE,IAAI,IAAI;IAC1C,6EAA6E;IAC7E,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpE;sEACkE;IAClE,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9C,CAAA;AAED,MAAM,MAAM,WAAW,CAAC,IAAI,IAAI;IAC9B,6EAA6E;IAC7E,OAAO,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvE;;oEAEgE;IAChE,MAAM,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACrC,CAAA;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAC1C,MAAM,EAAE,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,GACpC,WAAW,CAAC,IAAI,CAAC,CAkDnB"}