@drakkar.software/starfish-client 3.0.0-alpha.35 → 3.0.0-alpha.36
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/bindings/zustand.js +38 -16
- package/dist/bindings/zustand.js.map +2 -2
- package/dist/client.d.ts +6 -0
- package/dist/index.js +38 -16
- package/dist/index.js.map +2 -2
- package/dist/sync.d.ts +14 -4
- package/package.json +2 -2
package/dist/client.d.ts
CHANGED
|
@@ -110,6 +110,12 @@ export declare class StarfishClient {
|
|
|
110
110
|
private readonly cacheFallbackStatuses?;
|
|
111
111
|
private readonly onRevalidated?;
|
|
112
112
|
private readonly revalidating;
|
|
113
|
+
/**
|
|
114
|
+
* In-memory mirror of the latest document timestamp written to each cache
|
|
115
|
+
* key via {@link writeCache}. Updated synchronously so {@link revalidateLoop}
|
|
116
|
+
* can guard against stale overwrites without an extra async cache read.
|
|
117
|
+
*/
|
|
118
|
+
private readonly latestCacheTimestamp;
|
|
113
119
|
/**
|
|
114
120
|
* Installed client-side plugins. Currently stored as inert data; no
|
|
115
121
|
* hooks fire yet. Extensions can inspect this list if needed.
|
package/dist/index.js
CHANGED
|
@@ -110,6 +110,12 @@ var StarfishClient = class {
|
|
|
110
110
|
cacheFallbackStatuses;
|
|
111
111
|
onRevalidated;
|
|
112
112
|
revalidating = /* @__PURE__ */ new Set();
|
|
113
|
+
/**
|
|
114
|
+
* In-memory mirror of the latest document timestamp written to each cache
|
|
115
|
+
* key via {@link writeCache}. Updated synchronously so {@link revalidateLoop}
|
|
116
|
+
* can guard against stale overwrites without an extra async cache read.
|
|
117
|
+
*/
|
|
118
|
+
latestCacheTimestamp = /* @__PURE__ */ new Map();
|
|
113
119
|
/**
|
|
114
120
|
* Installed client-side plugins. Currently stored as inert data; no
|
|
115
121
|
* hooks fire yet. Extensions can inspect this list if needed.
|
|
@@ -320,6 +326,9 @@ var StarfishClient = class {
|
|
|
320
326
|
*/
|
|
321
327
|
writeCache(cacheKey, result) {
|
|
322
328
|
if (!this.cache) return;
|
|
329
|
+
if (result.timestamp > (this.latestCacheTimestamp.get(cacheKey) ?? -1)) {
|
|
330
|
+
this.latestCacheTimestamp.set(cacheKey, result.timestamp);
|
|
331
|
+
}
|
|
323
332
|
const snapshot = {
|
|
324
333
|
data: result.data,
|
|
325
334
|
hash: result.hash,
|
|
@@ -381,8 +390,11 @@ var StarfishClient = class {
|
|
|
381
390
|
const res = await this.revalidateFetch(pathAndQuery);
|
|
382
391
|
if (res.ok) {
|
|
383
392
|
const result = await res.json();
|
|
384
|
-
this.
|
|
385
|
-
|
|
393
|
+
const latestTs = this.latestCacheTimestamp.get(cacheKey) ?? -1;
|
|
394
|
+
if (result.timestamp >= latestTs) {
|
|
395
|
+
this.writeCache(cacheKey, result);
|
|
396
|
+
this.onRevalidated?.(pathAndQuery, result);
|
|
397
|
+
}
|
|
386
398
|
return;
|
|
387
399
|
}
|
|
388
400
|
if (!fallbackSet?.has(res.status)) {
|
|
@@ -794,20 +806,32 @@ var SyncManager = class {
|
|
|
794
806
|
* action to absorb a background revalidation result (delivered via
|
|
795
807
|
* {@link StarfishClientOptions.onRevalidated}) into the store.
|
|
796
808
|
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
809
|
+
* Like {@link pull}, `ingest` conflict-merges the snapshot against the
|
|
810
|
+
* established baseline via `this.onConflict` when a checkpoint exists — so a
|
|
811
|
+
* union-merge store does not lose array items when a revalidation result
|
|
812
|
+
* (e.g. a stale cache-fallback on 429/5xx) is a shorter snapshot. The first
|
|
813
|
+
* ingest (no checkpoint yet) takes the snapshot wholesale. Sets
|
|
814
|
+
* `lastFromCache = false` (a revalidation is a live response) so the binding
|
|
815
|
+
* can clear its `stale` flag.
|
|
816
|
+
*
|
|
817
|
+
* **Staleness guard**: if a `push()` advanced `lastCheckpoint` between the
|
|
818
|
+
* time the revalidation request was sent and the time it resolves, the
|
|
819
|
+
* result is from an older document version. Ingesting it would clobber the
|
|
820
|
+
* user's just-saved edit and reset `lastHash` to a stale server hash
|
|
821
|
+
* (causing a spurious 409 on the next push). We silently drop the result in
|
|
822
|
+
* that case — the store's post-push state is already correct.
|
|
801
823
|
*/
|
|
802
824
|
async ingest(result) {
|
|
803
825
|
if (this.aborted) return;
|
|
826
|
+
if (result.timestamp < this.lastCheckpoint) return;
|
|
827
|
+
let incoming;
|
|
804
828
|
if (this.encryptor) {
|
|
805
|
-
|
|
829
|
+
incoming = await this.encryptor.decrypt(result.data);
|
|
806
830
|
if (this.aborted) return;
|
|
807
|
-
this.localData = decrypted;
|
|
808
831
|
} else {
|
|
809
|
-
|
|
832
|
+
incoming = result.data;
|
|
810
833
|
}
|
|
834
|
+
this.localData = this.lastCheckpoint > 0 ? this.onConflict(this.localData, incoming) : incoming;
|
|
811
835
|
this.lastHash = result.hash;
|
|
812
836
|
this.lastCheckpoint = result.timestamp;
|
|
813
837
|
this.lastFromCache = false;
|
|
@@ -820,17 +844,15 @@ var SyncManager = class {
|
|
|
820
844
|
const result = await this.client.pull(this.pullPath, this.lastCheckpoint);
|
|
821
845
|
if (this.aborted) throw new AbortError();
|
|
822
846
|
this.lastFromCache = pullWasFromCache(result);
|
|
847
|
+
let incoming;
|
|
823
848
|
if (this.encryptor) {
|
|
824
|
-
|
|
849
|
+
incoming = await this.encryptor.decrypt(result.data);
|
|
825
850
|
if (this.aborted) throw new AbortError();
|
|
826
|
-
this.localData = decrypted;
|
|
827
|
-
result.data = decrypted;
|
|
828
|
-
} else if (this.lastCheckpoint > 0) {
|
|
829
|
-
this.localData = deepMerge(this.localData, result.data);
|
|
830
|
-
result.data = this.localData;
|
|
831
851
|
} else {
|
|
832
|
-
|
|
852
|
+
incoming = result.data;
|
|
833
853
|
}
|
|
854
|
+
this.localData = this.lastCheckpoint > 0 ? this.onConflict(this.localData, incoming) : incoming;
|
|
855
|
+
result.data = this.localData;
|
|
834
856
|
this.lastHash = result.hash;
|
|
835
857
|
this.lastCheckpoint = result.timestamp;
|
|
836
858
|
this.logger?.pullSuccess(this.loggerName, Math.round(performance.now() - start));
|