@farm.js/sync 0.1.0-beta.3 → 0.1.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.
- package/dist/client.d.ts +6 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +50 -5
- package/dist/store.d.ts +12 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +21 -0
- package/package.json +2 -2
package/dist/client.d.ts
CHANGED
|
@@ -100,7 +100,12 @@ type SyncPersistence = {
|
|
|
100
100
|
};
|
|
101
101
|
/** Replace the default browser store, for example with an IndexedDB one. */
|
|
102
102
|
export declare function setSyncPersistence(store: SyncPersistence | null): void;
|
|
103
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Forget every synced row, on disk and in memory. Call it when the session
|
|
105
|
+
* changes (sign out, sign in as someone else, switch organization) so the next
|
|
106
|
+
* account never sees the previous one's rows. Each model reloads in full on its
|
|
107
|
+
* next use, scoped to the session current at that point.
|
|
108
|
+
*/
|
|
104
109
|
export declare function clearSyncedRows(): void;
|
|
105
110
|
export declare function hydrateModel(model: string): void;
|
|
106
111
|
export {};
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAEd,KAAK,OAAO,EACZ,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,kBAAkB,CAAC,IAAI,GAAG,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG;IACnE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,KAAK,CAAC,OAAO,GAAG,KAAK,EACnB,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GACxE,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;IAC3B,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAClC,uEAAuE;IACvE,KAAK,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;KAAE,CAAC;CAC5E,CAAC;AAUF,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE,iBAAsB,GAAG,IAAI,CAGjG;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -30,11 +30,31 @@ function requireRuntime() {
|
|
|
30
30
|
}
|
|
31
31
|
throw new Error("The sync runtime is not started. Add `sync({ ... })` to the plugins in farm.config.ts.");
|
|
32
32
|
}
|
|
33
|
+
const scheduledReloads = new Set();
|
|
34
|
+
/**
|
|
35
|
+
* A store cleared by clearSyncedRows() reloads on its next use, under whichever
|
|
36
|
+
* session is current by then. Deferred so the reload's status change never
|
|
37
|
+
* fires while a component is rendering, and so loadModel's own lookup of the
|
|
38
|
+
* store does not schedule it again.
|
|
39
|
+
*/
|
|
40
|
+
function scheduleReload(model, store) {
|
|
41
|
+
if (scheduledReloads.has(model))
|
|
42
|
+
return;
|
|
43
|
+
scheduledReloads.add(model);
|
|
44
|
+
queueMicrotask(() => {
|
|
45
|
+
if (store.status === "idle")
|
|
46
|
+
void loadModel(model);
|
|
47
|
+
scheduledReloads.delete(model);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
33
50
|
export function getSyncStore(model) {
|
|
34
51
|
const state = requireRuntime();
|
|
35
52
|
let store = state.stores.get(model);
|
|
36
|
-
if (store)
|
|
53
|
+
if (store) {
|
|
54
|
+
if (store.status === "idle" && isBrowser())
|
|
55
|
+
scheduleReload(model, store);
|
|
37
56
|
return store;
|
|
57
|
+
}
|
|
38
58
|
const descriptor = state.config.models[model];
|
|
39
59
|
if (!descriptor) {
|
|
40
60
|
if (!isBrowser())
|
|
@@ -68,10 +88,13 @@ async function request(body) {
|
|
|
68
88
|
/** Fetch rows for a model, incrementally when the schema supports a cursor. */
|
|
69
89
|
export async function loadModel(model) {
|
|
70
90
|
const store = getSyncStore(model);
|
|
91
|
+
const generation = store.generation;
|
|
71
92
|
if (store.status === "idle")
|
|
72
93
|
store.setStatus("loading");
|
|
73
94
|
try {
|
|
74
95
|
const result = await request({ model, operation: "list", since: store.cursor });
|
|
96
|
+
if (store.generation !== generation)
|
|
97
|
+
return;
|
|
75
98
|
store.applyServerRows(result.rows ?? [], {
|
|
76
99
|
full: result.full !== false,
|
|
77
100
|
cursor: result.cursor ?? null,
|
|
@@ -80,6 +103,8 @@ export async function loadModel(model) {
|
|
|
80
103
|
persistModel(model);
|
|
81
104
|
}
|
|
82
105
|
catch (cause) {
|
|
106
|
+
if (store.generation !== generation)
|
|
107
|
+
return;
|
|
83
108
|
store.setStatus("error", cause instanceof Error ? cause : new Error(String(cause)));
|
|
84
109
|
}
|
|
85
110
|
}
|
|
@@ -147,18 +172,24 @@ function runMutation(model, operation, input, optimistic) {
|
|
|
147
172
|
: { type: "upsert", key: optimistic.key, row: optimistic.row };
|
|
148
173
|
store.addLayer(layer);
|
|
149
174
|
store.trackPending(1);
|
|
175
|
+
const generation = store.generation;
|
|
150
176
|
let handleState = "pending";
|
|
151
177
|
const isPersisted = (async () => {
|
|
152
178
|
try {
|
|
153
179
|
const result = await dispatchWrite(store, { model, operation, input }, state.options);
|
|
154
|
-
store.commitLayer(layer, operation === "delete" ? null : result);
|
|
155
180
|
handleState = "completed";
|
|
181
|
+
// The store was cleared for a new session while this was in flight.
|
|
182
|
+
if (store.generation !== generation)
|
|
183
|
+
return result;
|
|
184
|
+
store.commitLayer(layer, operation === "delete" ? null : result);
|
|
156
185
|
persistModel(model);
|
|
157
186
|
return result;
|
|
158
187
|
}
|
|
159
188
|
catch (error) {
|
|
160
|
-
store.removeLayer(layer);
|
|
161
189
|
handleState = "failed";
|
|
190
|
+
if (store.generation !== generation)
|
|
191
|
+
throw error;
|
|
192
|
+
store.removeLayer(layer);
|
|
162
193
|
store.recordFailure({
|
|
163
194
|
operation,
|
|
164
195
|
input,
|
|
@@ -217,6 +248,7 @@ export function runSyncAction(model, action, invoke, input, explicitPatch) {
|
|
|
217
248
|
if (layer)
|
|
218
249
|
store.addLayer(layer);
|
|
219
250
|
store.trackPending(1);
|
|
251
|
+
const generation = store.generation;
|
|
220
252
|
let handleState = "pending";
|
|
221
253
|
const isPersisted = (async () => {
|
|
222
254
|
try {
|
|
@@ -231,6 +263,10 @@ export function runSyncAction(model, action, invoke, input, explicitPatch) {
|
|
|
231
263
|
}
|
|
232
264
|
const result = await invoke(input);
|
|
233
265
|
const rows = Array.isArray(result) ? result : [result];
|
|
266
|
+
if (store.generation !== generation) {
|
|
267
|
+
handleState = "completed";
|
|
268
|
+
return (rows[0] ?? null);
|
|
269
|
+
}
|
|
234
270
|
let committed = false;
|
|
235
271
|
for (const row of rows) {
|
|
236
272
|
if (row && typeof row === "object" && row[keyField] !== undefined) {
|
|
@@ -254,9 +290,11 @@ export function runSyncAction(model, action, invoke, input, explicitPatch) {
|
|
|
254
290
|
return (rows[0] ?? null);
|
|
255
291
|
}
|
|
256
292
|
catch (error) {
|
|
293
|
+
handleState = "failed";
|
|
294
|
+
if (store.generation !== generation)
|
|
295
|
+
throw error;
|
|
257
296
|
if (layer)
|
|
258
297
|
store.removeLayer(layer);
|
|
259
|
-
handleState = "failed";
|
|
260
298
|
store.recordFailure({
|
|
261
299
|
operation: action,
|
|
262
300
|
input,
|
|
@@ -406,9 +444,16 @@ function getPersistence() {
|
|
|
406
444
|
export function setSyncPersistence(store) {
|
|
407
445
|
persistence = store;
|
|
408
446
|
}
|
|
409
|
-
/**
|
|
447
|
+
/**
|
|
448
|
+
* Forget every synced row, on disk and in memory. Call it when the session
|
|
449
|
+
* changes (sign out, sign in as someone else, switch organization) so the next
|
|
450
|
+
* account never sees the previous one's rows. Each model reloads in full on its
|
|
451
|
+
* next use, scoped to the session current at that point.
|
|
452
|
+
*/
|
|
410
453
|
export function clearSyncedRows() {
|
|
411
454
|
getPersistence()?.clear();
|
|
455
|
+
for (const store of runtime?.stores.values() ?? [])
|
|
456
|
+
store.reset();
|
|
412
457
|
}
|
|
413
458
|
function persistModel(model) {
|
|
414
459
|
const store = runtime?.stores.get(model);
|
package/dist/store.d.ts
CHANGED
|
@@ -54,6 +54,12 @@ export declare class SyncModelStore {
|
|
|
54
54
|
/** Rolled-back writes awaiting the user. Replaced, never mutated, so a
|
|
55
55
|
* useSyncExternalStore snapshot of it stays referentially stable. */
|
|
56
56
|
failures: readonly SyncWriteFailure[];
|
|
57
|
+
/**
|
|
58
|
+
* Bumped by reset(). A load or write that started before a reset compares
|
|
59
|
+
* against it and drops its result, so a response for the previous session
|
|
60
|
+
* cannot land in the store after it was cleared.
|
|
61
|
+
*/
|
|
62
|
+
generation: number;
|
|
57
63
|
private nextFailureId;
|
|
58
64
|
constructor(name: string, descriptor: SyncModelDescriptor);
|
|
59
65
|
subscribe(listener: () => void): () => void;
|
|
@@ -71,6 +77,12 @@ export declare class SyncModelStore {
|
|
|
71
77
|
/** Fold a confirmed server row in and drop the layer that predicted it. */
|
|
72
78
|
commitLayer(layer: OptimisticLayer, confirmed: SyncRow | null): void;
|
|
73
79
|
mergeRow(key: unknown, changes: SyncRow): SyncRow;
|
|
80
|
+
/**
|
|
81
|
+
* Forget everything this store holds for a session change: confirmed rows,
|
|
82
|
+
* optimistic layers, recorded failures, and the incremental cursor. The next
|
|
83
|
+
* load is a full one, scoped to whoever is signed in by then.
|
|
84
|
+
*/
|
|
85
|
+
reset(): void;
|
|
74
86
|
/** Rows worth persisting: confirmed only, never optimistic guesses. */
|
|
75
87
|
confirmedRows(): SyncRow[];
|
|
76
88
|
hydrate(rows: SyncRow[], cursor: string | null): void;
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;sEACkE;IAClE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAErE,+EAA+E;AAC/E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,KAAK,EAAE,MAAM,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,KAAK,eAAe,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC;AAErC;;;;GAIG;AACH,qBAAa,cAAc;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/store.js
CHANGED
|
@@ -19,6 +19,12 @@ export class SyncModelStore {
|
|
|
19
19
|
/** Rolled-back writes awaiting the user. Replaced, never mutated, so a
|
|
20
20
|
* useSyncExternalStore snapshot of it stays referentially stable. */
|
|
21
21
|
failures = [];
|
|
22
|
+
/**
|
|
23
|
+
* Bumped by reset(). A load or write that started before a reset compares
|
|
24
|
+
* against it and drops its result, so a response for the previous session
|
|
25
|
+
* cannot land in the store after it was cleared.
|
|
26
|
+
*/
|
|
27
|
+
generation = 0;
|
|
22
28
|
nextFailureId = 1;
|
|
23
29
|
constructor(name, descriptor) {
|
|
24
30
|
this.name = name;
|
|
@@ -98,6 +104,21 @@ export class SyncModelStore {
|
|
|
98
104
|
const current = this.get(key) ?? { [this.descriptor.key]: key };
|
|
99
105
|
return { ...current, ...changes };
|
|
100
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Forget everything this store holds for a session change: confirmed rows,
|
|
109
|
+
* optimistic layers, recorded failures, and the incremental cursor. The next
|
|
110
|
+
* load is a full one, scoped to whoever is signed in by then.
|
|
111
|
+
*/
|
|
112
|
+
reset() {
|
|
113
|
+
this.generation += 1;
|
|
114
|
+
this.confirmed.clear();
|
|
115
|
+
this.layers = [];
|
|
116
|
+
this.failures = [];
|
|
117
|
+
this.cursor = null;
|
|
118
|
+
this.status = "idle";
|
|
119
|
+
this.error = null;
|
|
120
|
+
this.invalidate();
|
|
121
|
+
}
|
|
101
122
|
/** Rows worth persisting: confirmed only, never optimistic guesses. */
|
|
102
123
|
confirmedRows() {
|
|
103
124
|
return Array.from(this.confirmed.values());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farm.js/sync",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.4",
|
|
4
4
|
"description": "Local-first collections for Farm.js: schema-driven reads, optimistic writes, offline queueing",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"farm.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@farm.js/core": "0.1.0-beta.
|
|
43
|
+
"@farm.js/core": "0.1.0-beta.109"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@farming-labs/orm": "0.0.62",
|