@drakkar.software/starfish-client 3.0.0-alpha.26 → 3.0.0-alpha.28
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.d.ts +14 -0
- package/dist/bindings/zustand.js +49 -3
- package/dist/bindings/zustand.js.map +2 -2
- package/dist/index.js +14 -1
- package/dist/index.js.map +2 -2
- package/package.json +2 -2
|
@@ -79,6 +79,20 @@ export interface CreateStarfishStoreOptions {
|
|
|
79
79
|
* ```
|
|
80
80
|
*/
|
|
81
81
|
onRemoteUpdate?: (data: Record<string, unknown>) => void;
|
|
82
|
+
/**
|
|
83
|
+
* Auto re-attempt a failed flush with exponential backoff while the store
|
|
84
|
+
* stays dirty + online. Omit to keep the current no-retry behavior.
|
|
85
|
+
*
|
|
86
|
+
* Defaults when the option is present: `maxRetries: 5`, `initialDelayMs: 500`,
|
|
87
|
+
* `maxDelayMs: 30_000`. Backoff is `min(initial * 2^attempt, max) + jitter(100ms)`.
|
|
88
|
+
* A successful flush resets the counter. Going offline cancels any pending retry.
|
|
89
|
+
* `AbortError`s are never retried.
|
|
90
|
+
*/
|
|
91
|
+
flushRetry?: {
|
|
92
|
+
maxRetries?: number;
|
|
93
|
+
initialDelayMs?: number;
|
|
94
|
+
maxDelayMs?: number;
|
|
95
|
+
};
|
|
82
96
|
}
|
|
83
97
|
export type { DevtoolsOptions };
|
|
84
98
|
export declare function createStarfishStore(options: CreateStarfishStoreOptions): StoreApi<StarfishStore>;
|
package/dist/bindings/zustand.js
CHANGED
|
@@ -679,7 +679,20 @@ var StarfishClient = class {
|
|
|
679
679
|
if (!res.ok) {
|
|
680
680
|
throw new StarfishHttpError(res.status, await res.text());
|
|
681
681
|
}
|
|
682
|
-
|
|
682
|
+
const result = await res.json();
|
|
683
|
+
if (this.cache) {
|
|
684
|
+
const pullPath = sendPath.replace("/push/", "/pull/");
|
|
685
|
+
const cacheKey = pullCacheKey(pullPath);
|
|
686
|
+
const snapshot = {
|
|
687
|
+
data,
|
|
688
|
+
hash: result.hash,
|
|
689
|
+
timestamp: result.timestamp,
|
|
690
|
+
cachedAt: Date.now()
|
|
691
|
+
};
|
|
692
|
+
void this.cache.set(cacheKey, JSON.stringify(snapshot)).catch(() => {
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
return result;
|
|
683
696
|
}
|
|
684
697
|
/**
|
|
685
698
|
* Append an element to an appendOnly (`by_timestamp`) collection.
|
|
@@ -1069,6 +1082,30 @@ function createStarfishStore(options) {
|
|
|
1069
1082
|
const { name, syncManager, storage } = options;
|
|
1070
1083
|
const storeCreator = (rawSet, get) => {
|
|
1071
1084
|
const set = rawSet;
|
|
1085
|
+
let retryTimer;
|
|
1086
|
+
let retryAttempt = 0;
|
|
1087
|
+
const scheduleFlushRetry = () => {
|
|
1088
|
+
const retryOpts = options.flushRetry;
|
|
1089
|
+
if (!retryOpts) return;
|
|
1090
|
+
const maxRetries = retryOpts.maxRetries ?? 5;
|
|
1091
|
+
if (retryAttempt >= maxRetries) return;
|
|
1092
|
+
const initialMs = retryOpts.initialDelayMs ?? 500;
|
|
1093
|
+
const maxMs = retryOpts.maxDelayMs ?? 3e4;
|
|
1094
|
+
const delayMs = Math.min(initialMs * Math.pow(2, retryAttempt), maxMs) + Math.random() * 100;
|
|
1095
|
+
retryAttempt++;
|
|
1096
|
+
clearTimeout(retryTimer);
|
|
1097
|
+
retryTimer = setTimeout(() => {
|
|
1098
|
+
if (get().dirty && get().online && !get().syncing) {
|
|
1099
|
+
get().flush().catch(() => {
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
}, delayMs);
|
|
1103
|
+
};
|
|
1104
|
+
const cancelFlushRetry = () => {
|
|
1105
|
+
clearTimeout(retryTimer);
|
|
1106
|
+
retryTimer = void 0;
|
|
1107
|
+
retryAttempt = 0;
|
|
1108
|
+
};
|
|
1072
1109
|
return {
|
|
1073
1110
|
data: {},
|
|
1074
1111
|
syncing: false,
|
|
@@ -1103,6 +1140,8 @@ function createStarfishStore(options) {
|
|
|
1103
1140
|
set: (modifier) => {
|
|
1104
1141
|
try {
|
|
1105
1142
|
const next = options.produce ? options.produce(get().data, modifier) : modifier(get().data);
|
|
1143
|
+
retryAttempt = 0;
|
|
1144
|
+
clearTimeout(retryTimer);
|
|
1106
1145
|
set({ data: next, dirty: true, error: null }, false, "set");
|
|
1107
1146
|
if (get().online) get().flush().catch(() => {
|
|
1108
1147
|
});
|
|
@@ -1118,15 +1157,22 @@ function createStarfishStore(options) {
|
|
|
1118
1157
|
set({ syncing: true, error: null }, false, "flush/start");
|
|
1119
1158
|
try {
|
|
1120
1159
|
await syncManager.push(get().data);
|
|
1160
|
+
cancelFlushRetry();
|
|
1121
1161
|
set({ data: syncManager.getData(), syncing: false, dirty: false, hash: syncManager.getHash(), stale: false }, false, "flush/success");
|
|
1122
1162
|
} catch (err) {
|
|
1163
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || typeof DOMException !== "undefined" && err instanceof DOMException && err.name === "AbortError");
|
|
1123
1164
|
set({ syncing: false, error: err instanceof Error ? err.message : String(err) }, false, "flush/error");
|
|
1165
|
+
if (!isAbort) scheduleFlushRetry();
|
|
1124
1166
|
}
|
|
1125
1167
|
},
|
|
1126
1168
|
setOnline: (online) => {
|
|
1127
1169
|
set({ online }, false, "setOnline");
|
|
1128
|
-
if (online && get().dirty)
|
|
1129
|
-
|
|
1170
|
+
if (online && get().dirty) {
|
|
1171
|
+
get().flush().catch(() => {
|
|
1172
|
+
});
|
|
1173
|
+
} else if (!online) {
|
|
1174
|
+
cancelFlushRetry();
|
|
1175
|
+
}
|
|
1130
1176
|
}
|
|
1131
1177
|
};
|
|
1132
1178
|
};
|