@syncular/client 0.0.1-60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blobs/index.d.ts +7 -0
- package/dist/blobs/index.d.ts.map +1 -0
- package/dist/blobs/index.js +7 -0
- package/dist/blobs/index.js.map +1 -0
- package/dist/blobs/manager.d.ts +345 -0
- package/dist/blobs/manager.d.ts.map +1 -0
- package/dist/blobs/manager.js +749 -0
- package/dist/blobs/manager.js.map +1 -0
- package/dist/blobs/migrate.d.ts +14 -0
- package/dist/blobs/migrate.d.ts.map +1 -0
- package/dist/blobs/migrate.js +59 -0
- package/dist/blobs/migrate.js.map +1 -0
- package/dist/blobs/types.d.ts +62 -0
- package/dist/blobs/types.d.ts.map +1 -0
- package/dist/blobs/types.js +5 -0
- package/dist/blobs/types.js.map +1 -0
- package/dist/client.d.ts +338 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +834 -0
- package/dist/client.js.map +1 -0
- package/dist/conflicts.d.ts +31 -0
- package/dist/conflicts.d.ts.map +1 -0
- package/dist/conflicts.js +118 -0
- package/dist/conflicts.js.map +1 -0
- package/dist/create-client.d.ts +115 -0
- package/dist/create-client.d.ts.map +1 -0
- package/dist/create-client.js +162 -0
- package/dist/create-client.js.map +1 -0
- package/dist/engine/SyncEngine.d.ts +215 -0
- package/dist/engine/SyncEngine.d.ts.map +1 -0
- package/dist/engine/SyncEngine.js +1066 -0
- package/dist/engine/SyncEngine.js.map +1 -0
- package/dist/engine/index.d.ts +6 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +6 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/types.d.ts +230 -0
- package/dist/engine/types.d.ts.map +1 -0
- package/dist/engine/types.js +7 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/handlers/create-handler.d.ts +110 -0
- package/dist/handlers/create-handler.d.ts.map +1 -0
- package/dist/handlers/create-handler.js +140 -0
- package/dist/handlers/create-handler.js.map +1 -0
- package/dist/handlers/registry.d.ts +15 -0
- package/dist/handlers/registry.d.ts.map +1 -0
- package/dist/handlers/registry.js +29 -0
- package/dist/handlers/registry.js.map +1 -0
- package/dist/handlers/types.d.ts +83 -0
- package/dist/handlers/types.d.ts.map +1 -0
- package/dist/handlers/types.js +5 -0
- package/dist/handlers/types.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/migrate.d.ts +19 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +106 -0
- package/dist/migrate.js.map +1 -0
- package/dist/mutations.d.ts +138 -0
- package/dist/mutations.d.ts.map +1 -0
- package/dist/mutations.js +611 -0
- package/dist/mutations.js.map +1 -0
- package/dist/outbox.d.ts +112 -0
- package/dist/outbox.d.ts.map +1 -0
- package/dist/outbox.js +304 -0
- package/dist/outbox.js.map +1 -0
- package/dist/plugins/incrementing-version.d.ts +34 -0
- package/dist/plugins/incrementing-version.d.ts.map +1 -0
- package/dist/plugins/incrementing-version.js +83 -0
- package/dist/plugins/incrementing-version.js.map +1 -0
- package/dist/plugins/index.d.ts +3 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +3 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/types.d.ts +49 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +15 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/proxy/connection.d.ts +33 -0
- package/dist/proxy/connection.d.ts.map +1 -0
- package/dist/proxy/connection.js +153 -0
- package/dist/proxy/connection.js.map +1 -0
- package/dist/proxy/dialect.d.ts +46 -0
- package/dist/proxy/dialect.d.ts.map +1 -0
- package/dist/proxy/dialect.js +58 -0
- package/dist/proxy/dialect.js.map +1 -0
- package/dist/proxy/driver.d.ts +42 -0
- package/dist/proxy/driver.d.ts.map +1 -0
- package/dist/proxy/driver.js +78 -0
- package/dist/proxy/driver.js.map +1 -0
- package/dist/proxy/index.d.ts +10 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +10 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/proxy/mutations.d.ts +9 -0
- package/dist/proxy/mutations.d.ts.map +1 -0
- package/dist/proxy/mutations.js +11 -0
- package/dist/proxy/mutations.js.map +1 -0
- package/dist/pull-engine.d.ts +45 -0
- package/dist/pull-engine.d.ts.map +1 -0
- package/dist/pull-engine.js +391 -0
- package/dist/pull-engine.js.map +1 -0
- package/dist/push-engine.d.ts +18 -0
- package/dist/push-engine.d.ts.map +1 -0
- package/dist/push-engine.js +155 -0
- package/dist/push-engine.js.map +1 -0
- package/dist/query/FingerprintCollector.d.ts +18 -0
- package/dist/query/FingerprintCollector.d.ts.map +1 -0
- package/dist/query/FingerprintCollector.js +28 -0
- package/dist/query/FingerprintCollector.js.map +1 -0
- package/dist/query/QueryContext.d.ts +33 -0
- package/dist/query/QueryContext.d.ts.map +1 -0
- package/dist/query/QueryContext.js +16 -0
- package/dist/query/QueryContext.js.map +1 -0
- package/dist/query/fingerprint.d.ts +61 -0
- package/dist/query/fingerprint.d.ts.map +1 -0
- package/dist/query/fingerprint.js +91 -0
- package/dist/query/fingerprint.js.map +1 -0
- package/dist/query/index.d.ts +7 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +7 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/tracked-select.d.ts +18 -0
- package/dist/query/tracked-select.d.ts.map +1 -0
- package/dist/query/tracked-select.js +90 -0
- package/dist/query/tracked-select.js.map +1 -0
- package/dist/schema.d.ts +83 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +7 -0
- package/dist/schema.js.map +1 -0
- package/dist/sync-loop.d.ts +32 -0
- package/dist/sync-loop.d.ts.map +1 -0
- package/dist/sync-loop.js +249 -0
- package/dist/sync-loop.js.map +1 -0
- package/dist/utils/id.d.ts +8 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +19 -0
- package/dist/utils/id.js.map +1 -0
- package/package.json +58 -0
- package/src/blobs/index.ts +7 -0
- package/src/blobs/manager.ts +1027 -0
- package/src/blobs/migrate.ts +67 -0
- package/src/blobs/types.ts +84 -0
- package/src/client.ts +1222 -0
- package/src/conflicts.ts +180 -0
- package/src/create-client.ts +297 -0
- package/src/engine/SyncEngine.ts +1337 -0
- package/src/engine/index.ts +6 -0
- package/src/engine/types.ts +268 -0
- package/src/handlers/create-handler.ts +287 -0
- package/src/handlers/registry.ts +36 -0
- package/src/handlers/types.ts +102 -0
- package/src/index.ts +25 -0
- package/src/migrate.ts +122 -0
- package/src/mutations.ts +926 -0
- package/src/outbox.ts +397 -0
- package/src/plugins/incrementing-version.ts +133 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/types.ts +63 -0
- package/src/proxy/connection.ts +191 -0
- package/src/proxy/dialect.ts +76 -0
- package/src/proxy/driver.ts +126 -0
- package/src/proxy/index.ts +10 -0
- package/src/proxy/mutations.ts +18 -0
- package/src/pull-engine.ts +518 -0
- package/src/push-engine.ts +201 -0
- package/src/query/FingerprintCollector.ts +29 -0
- package/src/query/QueryContext.ts +54 -0
- package/src/query/fingerprint.ts +109 -0
- package/src/query/index.ts +10 -0
- package/src/query/tracked-select.ts +139 -0
- package/src/schema.ts +94 -0
- package/src/sync-loop.ts +368 -0
- package/src/utils/id.ts +20 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Query Context
|
|
3
|
+
*
|
|
4
|
+
* Provides a query context with tracked selectFrom for scope tracking
|
|
5
|
+
* and automatic fingerprint generation.
|
|
6
|
+
*/
|
|
7
|
+
import type { Kysely } from 'kysely';
|
|
8
|
+
import type { SyncClientDb } from '../schema';
|
|
9
|
+
import type { FingerprintCollector } from './FingerprintCollector';
|
|
10
|
+
import type { MutationTimestampSource } from './fingerprint';
|
|
11
|
+
import { createTrackedSelectFrom } from './tracked-select';
|
|
12
|
+
export type TrackedSelectFrom<DB> = ReturnType<typeof createTrackedSelectFrom<DB>>;
|
|
13
|
+
/**
|
|
14
|
+
* Query context provided to query functions.
|
|
15
|
+
*
|
|
16
|
+
* Only `selectFrom` is exposed to ensure proper scope tracking and fingerprinting.
|
|
17
|
+
* If you need raw database access, use the db directly outside the query function.
|
|
18
|
+
*/
|
|
19
|
+
export interface QueryContext<DB extends SyncClientDb = SyncClientDb> {
|
|
20
|
+
/**
|
|
21
|
+
* Wrapped selectFrom that:
|
|
22
|
+
* 1. Registers table as watched scope
|
|
23
|
+
* 2. Intercepts .execute() to auto-detect fingerprinting mode:
|
|
24
|
+
* - Result has keyField (default: 'id')? -> row-level fingerprinting
|
|
25
|
+
* - No keyField? -> value-based fingerprinting (for aggregates)
|
|
26
|
+
*/
|
|
27
|
+
selectFrom: TrackedSelectFrom<DB>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create a query context with tracked selectFrom.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createQueryContext<DB extends SyncClientDb>(db: Kysely<DB>, scopeCollector: Set<string>, fingerprintCollector: FingerprintCollector, engine: MutationTimestampSource, keyField?: string): QueryContext<DB>;
|
|
33
|
+
//# sourceMappingURL=QueryContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryContext.d.ts","sourceRoot":"","sources":["../../src/query/QueryContext.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,MAAM,MAAM,iBAAiB,CAAC,EAAE,IAAI,UAAU,CAC5C,OAAO,uBAAuB,CAAC,EAAE,CAAC,CACnC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,YAAY,CAAC,EAAE,SAAS,YAAY,GAAG,YAAY;IAClE;;;;;;OAMG;IACH,UAAU,EAAE,iBAAiB,CAAC,EAAE,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,YAAY,EACxD,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EACd,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,oBAAoB,EAAE,oBAAoB,EAC1C,MAAM,EAAE,uBAAuB,EAC/B,QAAQ,SAAO,GACd,YAAY,CAAC,EAAE,CAAC,CAUlB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Query Context
|
|
3
|
+
*
|
|
4
|
+
* Provides a query context with tracked selectFrom for scope tracking
|
|
5
|
+
* and automatic fingerprint generation.
|
|
6
|
+
*/
|
|
7
|
+
import { createTrackedSelectFrom } from './tracked-select';
|
|
8
|
+
/**
|
|
9
|
+
* Create a query context with tracked selectFrom.
|
|
10
|
+
*/
|
|
11
|
+
export function createQueryContext(db, scopeCollector, fingerprintCollector, engine, keyField = 'id') {
|
|
12
|
+
return {
|
|
13
|
+
selectFrom: createTrackedSelectFrom(db, scopeCollector, fingerprintCollector, engine, keyField),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=QueryContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryContext.js","sourceRoot":"","sources":["../../src/query/QueryContext.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAuB3D;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,EAAc,EACd,cAA2B,EAC3B,oBAA0C,EAC1C,MAA+B,EAC/B,QAAQ,GAAG,IAAI,EACG;IAClB,OAAO;QACL,UAAU,EAAE,uBAAuB,CACjC,EAAE,EACF,cAAc,EACd,oBAAoB,EACpB,MAAM,EACN,QAAQ,CACT;KACF,CAAC;AAAA,CACH"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Fingerprint-based rerender optimization utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides efficient fingerprint computation for query results to avoid
|
|
5
|
+
* expensive deep equality checks. Uses mutation timestamps from the SyncEngine.
|
|
6
|
+
*/
|
|
7
|
+
export interface MutationTimestampSource {
|
|
8
|
+
getMutationTimestamp(table: string, rowId: string): number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Compute a fingerprint for query results based on length + ids + mutation timestamps.
|
|
12
|
+
* Much faster than deep equality for large datasets.
|
|
13
|
+
*
|
|
14
|
+
* Fingerprint format: `length:id1@ts1,id2@ts2,...`
|
|
15
|
+
*
|
|
16
|
+
* @param rows - Query result rows (must have an id-like field)
|
|
17
|
+
* @param engine - SyncEngine to look up mutation timestamps
|
|
18
|
+
* @param table - Table name for timestamp lookup
|
|
19
|
+
* @param keyField - Field name to use as row identifier (default: 'id')
|
|
20
|
+
* @returns Fingerprint string for comparison
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const fingerprint = computeFingerprint(tasks, engine, 'tasks', 'id');
|
|
25
|
+
* // Returns: "3:abc@1706123456789,def@1706123456790,ghi@0"
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function computeFingerprint<T extends Record<string, unknown>>(rows: T[], engine: MutationTimestampSource, table: string, keyField?: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Check if rows have the required key field for fingerprinting.
|
|
31
|
+
* Returns true for empty arrays (no data to fingerprint).
|
|
32
|
+
*
|
|
33
|
+
* @param rows - Query result rows to check
|
|
34
|
+
* @param keyField - Field name to check for (default: 'id')
|
|
35
|
+
* @returns true if rows can be fingerprinted, false otherwise
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* // Can fingerprint - rows have 'id' field
|
|
40
|
+
* canFingerprint([{ id: '1', name: 'foo' }]); // true
|
|
41
|
+
*
|
|
42
|
+
* // Cannot fingerprint - rows lack 'id' field (aggregates, etc.)
|
|
43
|
+
* canFingerprint([{ count: 42 }]); // false
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function canFingerprint<T>(rows: T[], keyField?: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Compute row-level fingerprint from query results.
|
|
49
|
+
* Format: `table:count:id1@ts1,id2@ts2,...`
|
|
50
|
+
*/
|
|
51
|
+
export declare function computeRowFingerprint(rows: unknown[], table: string, engine: MutationTimestampSource, keyField: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Compute value-based fingerprint for aggregate/scalar queries.
|
|
54
|
+
* Format: `table:hash(value)`
|
|
55
|
+
*/
|
|
56
|
+
export declare function computeValueFingerprint(table: string, value: unknown): string;
|
|
57
|
+
/**
|
|
58
|
+
* Check if result rows have the key field for row-level fingerprinting.
|
|
59
|
+
*/
|
|
60
|
+
export declare function hasKeyField(rows: unknown[], keyField: string): boolean;
|
|
61
|
+
//# sourceMappingURL=fingerprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/query/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,IAAI,EAAE,CAAC,EAAE,EACT,MAAM,EAAE,uBAAuB,EAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,SAAO,GACd,MAAM,CAWR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,QAAQ,SAAO,GAAG,OAAO,CAGrE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,OAAO,EAAE,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,uBAAuB,EAC/B,QAAQ,EAAE,MAAM,GACf,MAAM,CAYR;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAI7E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGtE"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Fingerprint-based rerender optimization utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides efficient fingerprint computation for query results to avoid
|
|
5
|
+
* expensive deep equality checks. Uses mutation timestamps from the SyncEngine.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Compute a fingerprint for query results based on length + ids + mutation timestamps.
|
|
9
|
+
* Much faster than deep equality for large datasets.
|
|
10
|
+
*
|
|
11
|
+
* Fingerprint format: `length:id1@ts1,id2@ts2,...`
|
|
12
|
+
*
|
|
13
|
+
* @param rows - Query result rows (must have an id-like field)
|
|
14
|
+
* @param engine - SyncEngine to look up mutation timestamps
|
|
15
|
+
* @param table - Table name for timestamp lookup
|
|
16
|
+
* @param keyField - Field name to use as row identifier (default: 'id')
|
|
17
|
+
* @returns Fingerprint string for comparison
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const fingerprint = computeFingerprint(tasks, engine, 'tasks', 'id');
|
|
22
|
+
* // Returns: "3:abc@1706123456789,def@1706123456790,ghi@0"
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function computeFingerprint(rows, engine, table, keyField = 'id') {
|
|
26
|
+
if (rows.length === 0)
|
|
27
|
+
return '0:';
|
|
28
|
+
const parts = [];
|
|
29
|
+
for (const row of rows) {
|
|
30
|
+
const id = String(row[keyField] ?? '');
|
|
31
|
+
const ts = engine.getMutationTimestamp(table, id);
|
|
32
|
+
parts.push(`${id}@${ts}`);
|
|
33
|
+
}
|
|
34
|
+
return `${rows.length}:${parts.join(',')}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if rows have the required key field for fingerprinting.
|
|
38
|
+
* Returns true for empty arrays (no data to fingerprint).
|
|
39
|
+
*
|
|
40
|
+
* @param rows - Query result rows to check
|
|
41
|
+
* @param keyField - Field name to check for (default: 'id')
|
|
42
|
+
* @returns true if rows can be fingerprinted, false otherwise
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* // Can fingerprint - rows have 'id' field
|
|
47
|
+
* canFingerprint([{ id: '1', name: 'foo' }]); // true
|
|
48
|
+
*
|
|
49
|
+
* // Cannot fingerprint - rows lack 'id' field (aggregates, etc.)
|
|
50
|
+
* canFingerprint([{ count: 42 }]); // false
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function canFingerprint(rows, keyField = 'id') {
|
|
54
|
+
if (rows.length === 0)
|
|
55
|
+
return true;
|
|
56
|
+
return keyField in rows[0];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Compute row-level fingerprint from query results.
|
|
60
|
+
* Format: `table:count:id1@ts1,id2@ts2,...`
|
|
61
|
+
*/
|
|
62
|
+
export function computeRowFingerprint(rows, table, engine, keyField) {
|
|
63
|
+
if (rows.length === 0)
|
|
64
|
+
return `${table}:0:`;
|
|
65
|
+
const parts = [];
|
|
66
|
+
for (const row of rows) {
|
|
67
|
+
const r = row;
|
|
68
|
+
const id = String(r[keyField] ?? '');
|
|
69
|
+
const ts = engine.getMutationTimestamp(table, id);
|
|
70
|
+
parts.push(`${id}@${ts}`);
|
|
71
|
+
}
|
|
72
|
+
return `${table}:${rows.length}:${parts.join(',')}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Compute value-based fingerprint for aggregate/scalar queries.
|
|
76
|
+
* Format: `table:hash(value)`
|
|
77
|
+
*/
|
|
78
|
+
export function computeValueFingerprint(table, value) {
|
|
79
|
+
// Simple hash of the JSON representation
|
|
80
|
+
const json = JSON.stringify(value);
|
|
81
|
+
return `${table}:${json}`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if result rows have the key field for row-level fingerprinting.
|
|
85
|
+
*/
|
|
86
|
+
export function hasKeyField(rows, keyField) {
|
|
87
|
+
if (rows.length === 0)
|
|
88
|
+
return false;
|
|
89
|
+
return keyField in rows[0];
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/query/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAS,EACT,MAA+B,EAC/B,KAAa,EACb,QAAQ,GAAG,IAAI,EACP;IACR,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACvC,MAAM,EAAE,GAAG,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAAA,CAC5C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,cAAc,CAAI,IAAS,EAAE,QAAQ,GAAG,IAAI,EAAW;IACrE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,QAAQ,IAAK,IAAI,CAAC,CAAC,CAA6B,CAAC;AAAA,CACzD;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAe,EACf,KAAa,EACb,MAA+B,EAC/B,QAAgB,EACR;IACR,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,KAAK,KAAK,CAAC;IAE5C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,GAA8B,CAAC;QACzC,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACrC,MAAM,EAAE,GAAG,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,GAAG,KAAK,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAAA,CACrD;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa,EAAE,KAAc,EAAU;IAC7E,yCAAyC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,OAAO,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC;AAAA,CAC3B;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAe,EAAE,QAAgB,EAAW;IACtE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,QAAQ,IAAK,IAAI,CAAC,CAAC,CAA6B,CAAC;AAAA,CACzD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Query utilities exports
|
|
3
|
+
*/
|
|
4
|
+
export { FingerprintCollector } from './FingerprintCollector';
|
|
5
|
+
export { canFingerprint, computeFingerprint, } from './fingerprint';
|
|
6
|
+
export { createQueryContext, type QueryContext } from './QueryContext';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Query utilities exports
|
|
3
|
+
*/
|
|
4
|
+
export { FingerprintCollector } from './FingerprintCollector';
|
|
5
|
+
export { canFingerprint, computeFingerprint, } from './fingerprint';
|
|
6
|
+
export { createQueryContext } from './QueryContext';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAqB,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Tracked SelectFrom
|
|
3
|
+
*
|
|
4
|
+
* Provides a wrapped selectFrom that:
|
|
5
|
+
* 1. Tracks tables as watched scopes when called
|
|
6
|
+
* 2. Intercepts .execute() to auto-generate fingerprints
|
|
7
|
+
*/
|
|
8
|
+
import type { Kysely } from 'kysely';
|
|
9
|
+
import type { FingerprintCollector } from './FingerprintCollector';
|
|
10
|
+
/** Portable type alias for Kysely's selectFrom method signature */
|
|
11
|
+
type TrackedSelectFrom<DB> = Kysely<DB>['selectFrom'];
|
|
12
|
+
import { type MutationTimestampSource } from './fingerprint';
|
|
13
|
+
/**
|
|
14
|
+
* Create a tracked selectFrom that registers scopes and generates fingerprints.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createTrackedSelectFrom<DB>(db: Kysely<DB>, scopeCollector: Set<string>, fingerprintCollector: FingerprintCollector, engine: MutationTimestampSource, keyField?: string): TrackedSelectFrom<DB>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=tracked-select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracked-select.d.ts","sourceRoot":"","sources":["../../src/query/tracked-select.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,mEAAmE;AACnE,KAAK,iBAAiB,CAAC,EAAE,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;AAEtD,OAAO,EAIL,KAAK,uBAAuB,EAC7B,MAAM,eAAe,CAAC;AA4FvB;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EACxC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EACd,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,oBAAoB,EAAE,oBAAoB,EAC1C,MAAM,EAAE,uBAAuB,EAC/B,QAAQ,SAAO,GACd,iBAAiB,CAAC,EAAE,CAAC,CAkBvB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Tracked SelectFrom
|
|
3
|
+
*
|
|
4
|
+
* Provides a wrapped selectFrom that:
|
|
5
|
+
* 1. Tracks tables as watched scopes when called
|
|
6
|
+
* 2. Intercepts .execute() to auto-generate fingerprints
|
|
7
|
+
*/
|
|
8
|
+
import { computeRowFingerprint, computeValueFingerprint, hasKeyField, } from './fingerprint';
|
|
9
|
+
function isExecutableQuery(value) {
|
|
10
|
+
if (typeof value !== 'object' || value === null)
|
|
11
|
+
return false;
|
|
12
|
+
return (typeof Reflect.get(value, 'execute') === 'function' &&
|
|
13
|
+
typeof Reflect.get(value, 'executeTakeFirst') === 'function' &&
|
|
14
|
+
typeof Reflect.get(value, 'executeTakeFirstOrThrow') === 'function');
|
|
15
|
+
}
|
|
16
|
+
function createExecuteProxy(builder, table, collector, engine, keyField) {
|
|
17
|
+
return new Proxy(builder, {
|
|
18
|
+
get(target, prop) {
|
|
19
|
+
if (prop === 'execute') {
|
|
20
|
+
return async () => {
|
|
21
|
+
const rows = await target.execute();
|
|
22
|
+
// Auto-detect fingerprint mode based on result shape
|
|
23
|
+
if (Array.isArray(rows)) {
|
|
24
|
+
if (hasKeyField(rows, keyField)) {
|
|
25
|
+
// Row-level fingerprinting - result has keyField
|
|
26
|
+
const fp = computeRowFingerprint(rows, table, engine, keyField);
|
|
27
|
+
collector.add(fp);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Value-based fingerprinting - for aggregates/scalars
|
|
31
|
+
const fp = computeValueFingerprint(table, rows);
|
|
32
|
+
collector.add(fp);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Unexpected, but keep rerender behavior deterministic.
|
|
37
|
+
const fp = computeValueFingerprint(table, rows);
|
|
38
|
+
collector.add(fp);
|
|
39
|
+
}
|
|
40
|
+
return rows;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (prop === 'executeTakeFirst') {
|
|
44
|
+
return async () => {
|
|
45
|
+
const row = await target.executeTakeFirst();
|
|
46
|
+
// Value-based fingerprinting for single-row queries
|
|
47
|
+
const fp = computeValueFingerprint(table, row);
|
|
48
|
+
collector.add(fp);
|
|
49
|
+
return row;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (prop === 'executeTakeFirstOrThrow') {
|
|
53
|
+
return async () => {
|
|
54
|
+
const row = await target.executeTakeFirstOrThrow();
|
|
55
|
+
// Value-based fingerprinting for single-row queries
|
|
56
|
+
const fp = computeValueFingerprint(table, row);
|
|
57
|
+
collector.add(fp);
|
|
58
|
+
return row;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// For other methods, return wrapped builder for chaining
|
|
62
|
+
const value = Reflect.get(target, prop, target);
|
|
63
|
+
if (typeof value === 'function') {
|
|
64
|
+
return (...args) => {
|
|
65
|
+
const result = Reflect.apply(value, target, args);
|
|
66
|
+
if (isExecutableQuery(result)) {
|
|
67
|
+
return createExecuteProxy(result, table, collector, engine, keyField);
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create a tracked selectFrom that registers scopes and generates fingerprints.
|
|
78
|
+
*/
|
|
79
|
+
export function createTrackedSelectFrom(db, scopeCollector, fingerprintCollector, engine, keyField = 'id') {
|
|
80
|
+
const selectFrom = (table) => {
|
|
81
|
+
// 1. Register this table as a watched scope
|
|
82
|
+
scopeCollector.add(table);
|
|
83
|
+
// 2. Get the real query builder
|
|
84
|
+
const builder = db.selectFrom(table);
|
|
85
|
+
// 3. Return a proxy that intercepts .execute()
|
|
86
|
+
return createExecuteProxy(builder, table, fingerprintCollector, engine, keyField);
|
|
87
|
+
};
|
|
88
|
+
return selectFrom;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=tracked-select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracked-select.js","sourceRoot":"","sources":["../../src/query/tracked-select.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,WAAW,GAEZ,MAAM,eAAe,CAAC;AAYvB,SAAS,iBAAiB,CAAC,KAAc,EAA4B;IACnE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,OAAO,CACL,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,UAAU;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,kBAAkB,CAAC,KAAK,UAAU;QAC5D,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,yBAAyB,CAAC,KAAK,UAAU,CACpE,CAAC;AAAA,CACH;AAED,SAAS,kBAAkB,CACzB,OAAU,EACV,KAAa,EACb,SAA+B,EAC/B,MAA+B,EAC/B,QAAgB,EACb;IACH,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;QACxB,GAAG,CAAC,MAAM,EAAE,IAAqB,EAAE;YACjC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,OAAO,KAAK,IAAI,EAAE,CAAC;oBACjB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpC,qDAAqD;oBACrD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;wBACxB,IAAI,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;4BAChC,iDAAiD;4BACjD,MAAM,EAAE,GAAG,qBAAqB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;4BAChE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;wBACpB,CAAC;6BAAM,CAAC;4BACN,sDAAsD;4BACtD,MAAM,EAAE,GAAG,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;4BAChD,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;wBACpB,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,wDAAwD;wBACxD,MAAM,EAAE,GAAG,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;wBAChD,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACpB,CAAC;oBACD,OAAO,IAAI,CAAC;gBAAA,CACb,CAAC;YACJ,CAAC;YACD,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBAChC,OAAO,KAAK,IAAI,EAAE,CAAC;oBACjB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC;oBAC5C,oDAAoD;oBACpD,MAAM,EAAE,GAAG,uBAAuB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;oBAC/C,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAClB,OAAO,GAAG,CAAC;gBAAA,CACZ,CAAC;YACJ,CAAC;YACD,IAAI,IAAI,KAAK,yBAAyB,EAAE,CAAC;gBACvC,OAAO,KAAK,IAAI,EAAE,CAAC;oBACjB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,uBAAuB,EAAE,CAAC;oBACnD,oDAAoD;oBACpD,MAAM,EAAE,GAAG,uBAAuB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;oBAC/C,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAClB,OAAO,GAAG,CAAC;gBAAA,CACZ,CAAC;YACJ,CAAC;YACD,yDAAyD;YACzD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAChD,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC;oBAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;oBAClD,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC9B,OAAO,kBAAkB,CACvB,MAAM,EACN,KAAK,EACL,SAAS,EACT,MAAM,EACN,QAAQ,CACT,CAAC;oBACJ,CAAC;oBACD,OAAO,MAAM,CAAC;gBAAA,CACf,CAAC;YACJ,CAAC;YACD,OAAO,KAAK,CAAC;QAAA,CACd;KACF,CAAC,CAAC;AAAA,CACJ;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,EAAc,EACd,cAA2B,EAC3B,oBAA0C,EAC1C,MAA+B,EAC/B,QAAQ,GAAG,IAAI,EACQ;IACvB,MAAM,UAAU,GAAG,CAA+B,KAAS,EAAE,EAAE,CAAC;QAC9D,4CAA4C;QAC5C,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE1B,gCAAgC;QAChC,MAAM,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAErC,+CAA+C;QAC/C,OAAO,kBAAkB,CACvB,OAAO,EACP,KAAK,EACL,oBAAoB,EACpB,MAAM,EACN,QAAQ,CACT,CAAC;IAAA,CACH,CAAC;IACF,OAAO,UAAmC,CAAC;AAAA,CAC5C"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - Sync client schema types (SQLite reference)
|
|
3
|
+
*
|
|
4
|
+
* These tables are sync-internal and should not collide with app tables.
|
|
5
|
+
*/
|
|
6
|
+
import type { Generated, Kysely } from 'kysely';
|
|
7
|
+
import type { SyncBlobClientDb } from './blobs/types';
|
|
8
|
+
/**
|
|
9
|
+
* Database executor type that both Kysely and Transaction satisfy.
|
|
10
|
+
* Use this when a function needs to work with either a raw Kysely instance
|
|
11
|
+
* or within a transaction context.
|
|
12
|
+
*/
|
|
13
|
+
export type SyncClientExecutor<DB extends SyncClientDb = SyncClientDb> = Pick<Kysely<DB>, 'selectFrom' | 'insertInto' | 'updateTable' | 'deleteFrom'>;
|
|
14
|
+
export type OutboxCommitStatus = 'pending' | 'sending' | 'acked' | 'failed';
|
|
15
|
+
export type SubscriptionStatus = 'active' | 'revoked';
|
|
16
|
+
export interface SyncSubscriptionStateTable {
|
|
17
|
+
/** Logical profile id (default: 'default') */
|
|
18
|
+
state_id: string;
|
|
19
|
+
/** Subscription identifier (client-chosen) */
|
|
20
|
+
subscription_id: string;
|
|
21
|
+
/** Shape name (table) for this subscription */
|
|
22
|
+
shape: string;
|
|
23
|
+
/** JSON string of ScopeValues for this subscription */
|
|
24
|
+
scopes_json: string;
|
|
25
|
+
/** JSON string of params */
|
|
26
|
+
params_json: string;
|
|
27
|
+
/** Per-subscription cursor (last applied commit_seq) */
|
|
28
|
+
cursor: number;
|
|
29
|
+
/**
|
|
30
|
+
* JSON string of SyncBootstrapState (or null).
|
|
31
|
+
* When set, indicates a paginated bootstrap is in progress for this subscription.
|
|
32
|
+
*/
|
|
33
|
+
bootstrap_state_json: string | null;
|
|
34
|
+
/** active | revoked */
|
|
35
|
+
status: SubscriptionStatus;
|
|
36
|
+
created_at: number;
|
|
37
|
+
updated_at: number;
|
|
38
|
+
}
|
|
39
|
+
export interface SyncOutboxCommitsTable {
|
|
40
|
+
/** Local row id (uuid) */
|
|
41
|
+
id: string;
|
|
42
|
+
/** Client-provided idempotency key (uuid) */
|
|
43
|
+
client_commit_id: string;
|
|
44
|
+
/** pending | sending | acked | failed */
|
|
45
|
+
status: OutboxCommitStatus;
|
|
46
|
+
/** JSON string of SyncOperation[] */
|
|
47
|
+
operations_json: string;
|
|
48
|
+
/** JSON string of the last SyncPushResponse (optional) */
|
|
49
|
+
last_response_json: string | null;
|
|
50
|
+
/** Last error (if any) */
|
|
51
|
+
error: string | null;
|
|
52
|
+
/** Created timestamp (ms since epoch) */
|
|
53
|
+
created_at: number;
|
|
54
|
+
/** Updated timestamp (ms since epoch) */
|
|
55
|
+
updated_at: number;
|
|
56
|
+
/** How many send attempts have been made */
|
|
57
|
+
attempt_count: Generated<number>;
|
|
58
|
+
/** Server commit_seq if acked (optional) */
|
|
59
|
+
acked_commit_seq: number | null;
|
|
60
|
+
/** Client schema version when commit was created (default: 1 for legacy) */
|
|
61
|
+
schema_version: Generated<number>;
|
|
62
|
+
}
|
|
63
|
+
export interface SyncClientDb extends SyncBlobClientDb {
|
|
64
|
+
sync_subscription_state: SyncSubscriptionStateTable;
|
|
65
|
+
sync_outbox_commits: SyncOutboxCommitsTable;
|
|
66
|
+
sync_conflicts: SyncConflictsTable;
|
|
67
|
+
}
|
|
68
|
+
export type ConflictResultStatus = 'conflict' | 'error';
|
|
69
|
+
export interface SyncConflictsTable {
|
|
70
|
+
id: string;
|
|
71
|
+
outbox_commit_id: string;
|
|
72
|
+
client_commit_id: string;
|
|
73
|
+
op_index: number;
|
|
74
|
+
result_status: ConflictResultStatus;
|
|
75
|
+
message: string;
|
|
76
|
+
code: string | null;
|
|
77
|
+
server_version: number | null;
|
|
78
|
+
server_row_json: string | null;
|
|
79
|
+
created_at: number;
|
|
80
|
+
resolved_at: number | null;
|
|
81
|
+
resolution: string | null;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,CAAC,EAAE,SAAS,YAAY,GAAG,YAAY,IAAI,IAAI,CAC3E,MAAM,CAAC,EAAE,CAAC,EACV,YAAY,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAC3D,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtD,MAAM,WAAW,0BAA0B;IACzC,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uBAAuB;IACvB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,gBAAgB,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,0BAA0B;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,aAAa,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,4CAA4C;IAC5C,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,4EAA4E;IAC5E,cAAc,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,YAAa,SAAQ,gBAAgB;IACpD,uBAAuB,EAAE,0BAA0B,CAAC;IACpD,mBAAmB,EAAE,sBAAsB,CAAC;IAC5C,cAAc,EAAE,kBAAkB,CAAC;CACpC;AAED,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,OAAO,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,oBAAoB,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/client - High-level sync loops
|
|
3
|
+
*
|
|
4
|
+
* Helpers that run push/pull repeatedly until the client is caught up.
|
|
5
|
+
*/
|
|
6
|
+
import type { SyncPullResponse, SyncSubscriptionRequest, SyncTransport } from '@syncular/core';
|
|
7
|
+
import type { Kysely } from 'kysely';
|
|
8
|
+
import type { ClientTableRegistry } from './handlers/registry';
|
|
9
|
+
import { type SyncPushOnceOptions } from './push-engine';
|
|
10
|
+
import type { SyncClientDb } from './schema';
|
|
11
|
+
export interface SyncOnceOptions {
|
|
12
|
+
clientId: string;
|
|
13
|
+
actorId?: string;
|
|
14
|
+
plugins?: SyncPushOnceOptions['plugins'];
|
|
15
|
+
subscriptions: Array<Omit<SyncSubscriptionRequest, 'cursor'>>;
|
|
16
|
+
limitCommits?: number;
|
|
17
|
+
limitSnapshotRows?: number;
|
|
18
|
+
maxSnapshotPages?: number;
|
|
19
|
+
dedupeRows?: boolean;
|
|
20
|
+
stateId?: string;
|
|
21
|
+
maxPushCommits?: number;
|
|
22
|
+
maxPullRounds?: number;
|
|
23
|
+
/** When 'ws', peek outbox first and skip push if empty. */
|
|
24
|
+
trigger?: 'ws' | 'local' | 'poll';
|
|
25
|
+
}
|
|
26
|
+
export interface SyncOnceResult {
|
|
27
|
+
pushedCommits: number;
|
|
28
|
+
pullRounds: number;
|
|
29
|
+
pullResponse: SyncPullResponse;
|
|
30
|
+
}
|
|
31
|
+
export declare function syncOnce<DB extends SyncClientDb>(db: Kysely<DB>, transport: SyncTransport, shapes: ClientTableRegistry<DB>, options: SyncOnceOptions): Promise<SyncOnceResult>;
|
|
32
|
+
//# sourceMappingURL=sync-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-loop.d.ts","sourceRoot":"","sources":["../src/sync-loop.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAIhB,uBAAuB,EACvB,aAAa,EACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAc/D,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,eAAe,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAqH7C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACzC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,IAAI,GAAG,OAAO,GAAG,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,gBAAgB,CAAC;CAChC;AAgMD,wBAAsB,QAAQ,CAAC,EAAE,SAAS,YAAY,EACpD,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EACd,SAAS,EAAE,aAAa,EACxB,MAAM,EAAE,mBAAmB,CAAC,EAAE,CAAC,EAC/B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAEzB"}
|