@syncular/client 0.15.6 → 0.15.7
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/client.js +6 -1
- package/dist/state.d.ts +7 -0
- package/dist/state.js +19 -0
- package/package.json +3 -3
- package/src/client.ts +6 -0
- package/src/state.ts +23 -0
package/dist/client.js
CHANGED
|
@@ -18,7 +18,7 @@ import { appendOutboxCommit, deleteOutboxCommit, dropOutboxCommitsInScope, encod
|
|
|
18
18
|
import { activeFailureRecords, listCommitOutcomes, persistCommitOutcomeResolution, pruneCommitOutcomes, commitOutcome as readCommitOutcome, recordCommitOutcome, } from './outcomes.js';
|
|
19
19
|
import { assertReadOnlyQuery } from './query-guard.js';
|
|
20
20
|
import { compileClientSchema, dropAndRecreateSyncedTables, ensureLocalBookkeepingSchema, ensureLocalSyncedSchema, fromSqlValue, jsonToRowValue, LOCAL_SCHEMA_VERSION_KEY, normalizeRecordKeys, OPTIMISTIC_VERSION, quoteIdent, recordToRowValues, rowValueToJson, SYNC_VERSION_COLUMN, stripSyncColumns, } from './schema.js';
|
|
21
|
-
import { bumpLocalRevision, deleteSubscription, getLocalRevision, getMeta, getSubscription, loadSubscriptions, resetSubscriptionsForBump, saveSubscription, setMeta, } from './state.js';
|
|
21
|
+
import { bumpLocalRevision, deleteSubscription, getLocalRevision, getMeta, getSubscription, loadSubscriptions, pruneUnknownSubscriptions, resetSubscriptionsForBump, saveSubscription, setMeta, } from './state.js';
|
|
22
22
|
import { deletePendingEviction, deleteWindowUnit, deriveSubId, getWindowUnitBySubId, insertWindowUnit, loadPendingEvictions, loadWindowUnits, savePendingEviction, unitScopes, windowBaseKey, } from './window.js';
|
|
23
23
|
/**
|
|
24
24
|
* True iff `unit` is windowed-in AND its bootstrap completed (§4.8 I3):
|
|
@@ -178,6 +178,11 @@ export class SyncClient {
|
|
|
178
178
|
// before the first sync round. A fresh install (no marker) is treated as
|
|
179
179
|
// already at the generated version.
|
|
180
180
|
this.#detectAndResetSchema();
|
|
181
|
+
// A registration remains app intent only while its table exists in the
|
|
182
|
+
// running schema. Removed-table registrations would poison every pull.
|
|
183
|
+
this.#db.transaction(() => {
|
|
184
|
+
pruneUnknownSubscriptions(this.#db, new Set(this.#schema.tables.keys()));
|
|
185
|
+
});
|
|
181
186
|
this.#started = true;
|
|
182
187
|
// A persisted active subscription needs one catch-up round on every open:
|
|
183
188
|
// realtime only covers changes after the socket connects, and an
|
package/dist/state.d.ts
CHANGED
|
@@ -38,6 +38,13 @@ export declare function deleteSubscription(db: ClientDatabase, id: string): void
|
|
|
38
38
|
* subscriptions the app still wants. Caller owns the transaction.
|
|
39
39
|
*/
|
|
40
40
|
export declare function resetSubscriptionsForBump(db: ClientDatabase): void;
|
|
41
|
+
/**
|
|
42
|
+
* Remove registrations whose table no longer exists in the running schema.
|
|
43
|
+
* Keeping one would make every subsequent pull fail with
|
|
44
|
+
* `sync.unknown_table`. Window bookkeeping belongs to the registration and
|
|
45
|
+
* is removed with it.
|
|
46
|
+
*/
|
|
47
|
+
export declare function pruneUnknownSubscriptions(db: ClientDatabase, tableNames: ReadonlySet<string>): void;
|
|
41
48
|
export declare function getMeta(db: ClientDatabase, key: string): string | undefined;
|
|
42
49
|
export declare function setMeta(db: ClientDatabase, key: string, value: string): void;
|
|
43
50
|
/** Read the durable client-local observer revision (SPEC §7.5). */
|
package/dist/state.js
CHANGED
|
@@ -65,6 +65,25 @@ export function resetSubscriptionsForBump(db) {
|
|
|
65
65
|
SET cursor = -1, bootstrap_state = NULL, effective_scopes = NULL,
|
|
66
66
|
status = 'active', reason_code = NULL`);
|
|
67
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Remove registrations whose table no longer exists in the running schema.
|
|
70
|
+
* Keeping one would make every subsequent pull fail with
|
|
71
|
+
* `sync.unknown_table`. Window bookkeeping belongs to the registration and
|
|
72
|
+
* is removed with it.
|
|
73
|
+
*/
|
|
74
|
+
export function pruneUnknownSubscriptions(db, tableNames) {
|
|
75
|
+
const staleIds = db
|
|
76
|
+
.query('SELECT id, tbl FROM _syncular_subscriptions')
|
|
77
|
+
.filter((row) => !tableNames.has(String(row.tbl)))
|
|
78
|
+
.map((row) => String(row.id));
|
|
79
|
+
for (const id of staleIds) {
|
|
80
|
+
db.exec('DELETE FROM _syncular_windows WHERE sub_id = ?', [id]);
|
|
81
|
+
db.exec('DELETE FROM _syncular_window_pending_evict WHERE sub_id = ?', [
|
|
82
|
+
id,
|
|
83
|
+
]);
|
|
84
|
+
db.exec('DELETE FROM _syncular_subscriptions WHERE id = ?', [id]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
68
87
|
export function getMeta(db, key) {
|
|
69
88
|
const row = db.query('SELECT value FROM _syncular_meta WHERE key = ?', [
|
|
70
89
|
key,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/client",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.7",
|
|
4
4
|
"description": "Syncular TypeScript client core — offline-first sync over SQLite (WASM/OPFS, Bun, Node)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"@sqlite.org/sqlite-wasm": "^3.53.0-build1",
|
|
84
|
-
"@syncular/core": "0.15.
|
|
84
|
+
"@syncular/core": "0.15.7"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"better-sqlite3": ">=11"
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
|
-
"@syncular/server": "0.15.
|
|
95
|
+
"@syncular/server": "0.15.7",
|
|
96
96
|
"@types/better-sqlite3": "^7.6.13",
|
|
97
97
|
"better-sqlite3": "^12.11.1"
|
|
98
98
|
}
|
package/src/client.ts
CHANGED
|
@@ -134,6 +134,7 @@ import {
|
|
|
134
134
|
getMeta,
|
|
135
135
|
getSubscription,
|
|
136
136
|
loadSubscriptions,
|
|
137
|
+
pruneUnknownSubscriptions,
|
|
137
138
|
resetSubscriptionsForBump,
|
|
138
139
|
type SubscriptionRecord,
|
|
139
140
|
saveSubscription,
|
|
@@ -585,6 +586,11 @@ export class SyncClient {
|
|
|
585
586
|
// before the first sync round. A fresh install (no marker) is treated as
|
|
586
587
|
// already at the generated version.
|
|
587
588
|
this.#detectAndResetSchema();
|
|
589
|
+
// A registration remains app intent only while its table exists in the
|
|
590
|
+
// running schema. Removed-table registrations would poison every pull.
|
|
591
|
+
this.#db.transaction(() => {
|
|
592
|
+
pruneUnknownSubscriptions(this.#db, new Set(this.#schema.tables.keys()));
|
|
593
|
+
});
|
|
588
594
|
this.#started = true;
|
|
589
595
|
// A persisted active subscription needs one catch-up round on every open:
|
|
590
596
|
// realtime only covers changes after the socket connects, and an
|
package/src/state.ts
CHANGED
|
@@ -115,6 +115,29 @@ export function resetSubscriptionsForBump(db: ClientDatabase): void {
|
|
|
115
115
|
);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Remove registrations whose table no longer exists in the running schema.
|
|
120
|
+
* Keeping one would make every subsequent pull fail with
|
|
121
|
+
* `sync.unknown_table`. Window bookkeeping belongs to the registration and
|
|
122
|
+
* is removed with it.
|
|
123
|
+
*/
|
|
124
|
+
export function pruneUnknownSubscriptions(
|
|
125
|
+
db: ClientDatabase,
|
|
126
|
+
tableNames: ReadonlySet<string>,
|
|
127
|
+
): void {
|
|
128
|
+
const staleIds = db
|
|
129
|
+
.query('SELECT id, tbl FROM _syncular_subscriptions')
|
|
130
|
+
.filter((row) => !tableNames.has(String(row.tbl)))
|
|
131
|
+
.map((row) => String(row.id));
|
|
132
|
+
for (const id of staleIds) {
|
|
133
|
+
db.exec('DELETE FROM _syncular_windows WHERE sub_id = ?', [id]);
|
|
134
|
+
db.exec('DELETE FROM _syncular_window_pending_evict WHERE sub_id = ?', [
|
|
135
|
+
id,
|
|
136
|
+
]);
|
|
137
|
+
db.exec('DELETE FROM _syncular_subscriptions WHERE id = ?', [id]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
118
141
|
export function getMeta(db: ClientDatabase, key: string): string | undefined {
|
|
119
142
|
const row = db.query('SELECT value FROM _syncular_meta WHERE key = ?', [
|
|
120
143
|
key,
|