@syncular/server 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -5
- package/dist/d1-storage.d.ts +9 -0
- package/dist/d1-storage.js +409 -106
- package/dist/postgres-storage.d.ts +2 -0
- package/dist/postgres-storage.js +41 -14
- package/dist/pull.js +16 -7
- package/dist/realtime.d.ts +1 -1
- package/dist/realtime.js +16 -10
- package/dist/relational-rows.d.ts +7 -1
- package/dist/relational-rows.js +17 -2
- package/dist/sqlite-storage.d.ts +2 -0
- package/dist/sqlite-storage.js +26 -6
- package/dist/storage-errors.d.ts +1 -1
- package/dist/storage-errors.js +4 -0
- package/dist/storage.d.ts +9 -0
- package/package.json +2 -2
- package/src/d1-storage.ts +555 -142
- package/src/postgres-storage.ts +64 -21
- package/src/pull.ts +22 -7
- package/src/realtime.ts +20 -9
- package/src/relational-rows.ts +18 -2
- package/src/sqlite-storage.ts +45 -9
- package/src/storage-errors.ts +12 -0
- package/src/storage.ts +21 -0
package/README.md
CHANGED
|
@@ -110,6 +110,11 @@ Log the cause for operators and stop startup. Do not catch readiness errors in
|
|
|
110
110
|
authentication or convert them to a 401; request-time schema checks are only a
|
|
111
111
|
defensive fallback.
|
|
112
112
|
|
|
113
|
+
For D1, finish `storage.migrateSchema(compileSchema(schema))` across separate
|
|
114
|
+
Worker invocations before admitting traffic. Each call returns `complete` and
|
|
115
|
+
`statementsExecuted`; the default budget is 50 statements. See
|
|
116
|
+
[D1 schema migration](https://syncular.dev/server-workers/#schema-migration).
|
|
117
|
+
|
|
113
118
|
After restoring an authoritative database, keep traffic stopped and call
|
|
114
119
|
`rotatePartitionLogEpoch({ storage, partition })` for every restored
|
|
115
120
|
partition. The rotation clears stale client cursors and requires version 2
|
|
@@ -1111,13 +1116,19 @@ cannot silently return.
|
|
|
1111
1116
|
### commitSeq allocation under concurrency
|
|
1112
1117
|
|
|
1113
1118
|
Per-partition `commitSeq` is dense and gap-free (§2.1). `appendCommit`
|
|
1114
|
-
allocates it with
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
+
allocates it with an upsert that increments `sync_partitions.max_commit_seq`
|
|
1120
|
+
and returns the allocated value. A common table expression feeds that value
|
|
1121
|
+
into the commit metadata insert in the same SQL statement. The upsert takes a
|
|
1122
|
+
row-level write lock on the partition for the transaction duration. Concurrent
|
|
1123
|
+
pushes to that partition serialize; separate partitions use separate locks. A Postgres `SEQUENCE` is deliberately **not** used: it would leave
|
|
1119
1124
|
gaps on rollback, which the §4.5 pull-window arithmetic does not tolerate.
|
|
1120
1125
|
|
|
1126
|
+
Each change insert expands its scope object into the inverted scope entries in
|
|
1127
|
+
the same statement. Serialized scopes bind as text before JSONB parsing; this
|
|
1128
|
+
avoids driver-specific JSON string encoding. Historical string-form scopes
|
|
1129
|
+
remain readable. Empty scopes still produce a change row, and repeated scopes
|
|
1130
|
+
within a commit retain one index entry.
|
|
1131
|
+
|
|
1121
1132
|
### Multi-instance fanout (LISTEN/NOTIFY)
|
|
1122
1133
|
|
|
1123
1134
|
Behind a load balancer, a commit applied on instance A fans out to A's
|
|
@@ -1186,3 +1197,12 @@ identity after authorization. Sharing is local to one process. Signed URL
|
|
|
1186
1197
|
grants remain per request. The first eligibility probe has at most
|
|
1187
1198
|
`limitSnapshotRows + 1` rows; subsequent builder batches have at most 5,000
|
|
1188
1199
|
rows. The image database and serialized output still consume memory.
|
|
1200
|
+
|
|
1201
|
+
|
|
1202
|
+
Realtime acknowledgements call `advanceClientCursor(partition, clientId,
|
|
1203
|
+
actorId, logEpoch, cursor, updatedAtMs)`. Custom storage adapters must implement
|
|
1204
|
+
this atomic update: advance the cursor and activity timestamp to their respective
|
|
1205
|
+
maxima, preserve registration fields, and require a matching actor and current
|
|
1206
|
+
partition log epoch. Leave missing records unchanged. SQLite, Postgres, and D1
|
|
1207
|
+
perform one update without reading or serializing the subscription list. HTTP
|
|
1208
|
+
registration keeps its existing cursor and subscription replacement rules.
|
package/dist/d1-storage.d.ts
CHANGED
|
@@ -37,6 +37,13 @@ export declare class D1ServerStorage implements ServerStorage {
|
|
|
37
37
|
/** Resolve a table's compiled schema; row operations require `ensureSchema`. */
|
|
38
38
|
table(name: string): CompiledTable;
|
|
39
39
|
ensureSchema(schema: CompiledSchema): Promise<void>;
|
|
40
|
+
/** Run once per Worker invocation. Resume an incomplete result in another invocation. */
|
|
41
|
+
migrateSchema(schema: CompiledSchema, options?: {
|
|
42
|
+
readonly maxStatements?: number;
|
|
43
|
+
}): Promise<{
|
|
44
|
+
readonly complete: boolean;
|
|
45
|
+
readonly statementsExecuted: number;
|
|
46
|
+
}>;
|
|
40
47
|
touchPartition(partition: string, authenticatedAtMs: number, initialLogEpoch: string): Promise<PartitionRegistryEntry>;
|
|
41
48
|
rotatePartitionLogEpoch(partition: string, logEpoch: string, authenticatedAtMs: number): Promise<PartitionRegistryEntry>;
|
|
42
49
|
listPartitionRegistry(): Promise<PartitionRegistryEntry[]>;
|
|
@@ -63,6 +70,8 @@ export declare class D1ServerStorage implements ServerStorage {
|
|
|
63
70
|
scanRowsByIndex(partition: string, query: IndexRowScanQuery): Promise<StoredRow[]>;
|
|
64
71
|
getClientRecord(partition: string, clientId: string): Promise<ClientRecord | undefined>;
|
|
65
72
|
putClientRecord(partition: string, record: ClientRecord): Promise<void>;
|
|
73
|
+
advanceClientCursor(partition: string, clientId: string, actorId: string, logEpoch: string, cursor: number, updatedAtMs: number): Promise<void>;
|
|
74
|
+
updateClientCursor(partition: string, clientId: string, cursor: number, updatedAtMs: number): Promise<void>;
|
|
66
75
|
getActiveClientCursorFloor(partition: string, cutoffMs: number): Promise<number | null>;
|
|
67
76
|
listClientCursors(partition: string): Promise<ClientCursorInfo[]>;
|
|
68
77
|
listRowsReferencingBlob(partition: string, blobId: string): Promise<{
|