@ovineko/spa-guard 0.0.1-alpha-30 → 0.0.1-alpha-31
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 +9 -1
- package/dist/_internal.js +4 -4
- package/dist/{chunk-A5HF6LY6.js → chunk-ALPGMLNW.js} +1 -1
- package/dist/{chunk-6TP2S7L6.js → chunk-QDYSBRW2.js} +1 -1
- package/dist/{chunk-EFWD2I2Y.js → chunk-SCBBWARW.js} +1 -1
- package/dist/{chunk-XRBUBTPZ.js → chunk-X6IW7S2K.js} +49 -7
- package/dist/{chunk-DINLBER6.js → chunk-YTH35AWC.js} +152 -14
- package/dist/common/fallbackRendering.d.ts +11 -1
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.js +10 -4
- package/dist/common/logger.d.ts +0 -3
- package/dist/common/retryOrchestrator.d.ts +2 -0
- package/dist/runtime/debug/index.js +3 -3
- package/dist/runtime/index.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ When a recoverable error occurs (chunk load error, unhandled rejection, `vite:pr
|
|
|
47
47
|
1. Event listener classifies the event and calls `triggerRetry({ source, error })`.
|
|
48
48
|
2. Orchestrator checks phase — if already `scheduled` or `fallback`, returns immediately without scheduling another reload.
|
|
49
49
|
3. On first trigger: reads `RETRY_ATTEMPT_PARAM` from URL to restore attempt count after a reload.
|
|
50
|
-
4. If attempts remain: increments attempt, sets a timer for `reloadDelays[currentAttempt]`, encodes `retryId` and attempt count into the reload URL, then navigates.
|
|
50
|
+
4. If attempts remain: increments attempt, calls `showLoadingUI(nextAttempt)` to render the loading UI immediately (before the timer fires), sets a timer for `reloadDelays[currentAttempt]`, encodes `retryId` and attempt count into the reload URL, then navigates. Requires `options.html.loading.content` to be configured; if absent, `showLoadingUI` returns silently and the retry still proceeds.
|
|
51
51
|
5. If attempts are exhausted: transitions to `fallback`, calls `setFallbackMode()`, sends a beacon, and renders fallback UI.
|
|
52
52
|
|
|
53
53
|
### URL params
|
|
@@ -58,6 +58,14 @@ The orchestrator serializes state into URL params for cross-reload continuity:
|
|
|
58
58
|
- `RETRY_ID_PARAM` — unique ID for this retry session
|
|
59
59
|
- `CACHE_BUST_PARAM` — timestamp for cache busting (set when `cacheBust: true` is passed, e.g. for static asset errors)
|
|
60
60
|
|
|
61
|
+
### Loading UI during retry delay
|
|
62
|
+
|
|
63
|
+
When `options.html.loading.content` is configured, `showLoadingUI(attempt)` is called before the reload timer fires. It injects the loading HTML into the target element (selector from `options.html.fallback.selector`, defaulting to `body`), reveals the `data-spa-guard-section="retrying"` element, fills attempt numbers into `[data-spa-guard-content="attempt"]` elements, applies i18n via `applyI18n`/`getI18n`, and optionally hides or replaces the spinner based on `options.html.spinner`. If loading content is not configured or the target element is not found, `showLoadingUI` returns silently — the retry still proceeds normally.
|
|
64
|
+
|
|
65
|
+
### Unhandledrejection serialization
|
|
66
|
+
|
|
67
|
+
`serializeError` handles `PromiseRejectionEvent` with strict redaction guardrails. For HTTP-like errors it extracts only safe metadata: `status`, `statusText`, `url`, `method`, `response.type`, and `X-Request-ID` from response headers when present. Response body, request/response payload, and the full headers object are **never** included in serialized output. For request wrappers (`reason.request` / `reason.config`) only `method`, `url`, and `baseURL` are extracted. Deep object traversal is bounded by `MAX_DEPTH=4`, `MAX_KEYS=20`, and `MAX_STRING_LEN=500` to prevent oversized beacons. Circular references are handled via a `WeakSet` visited tracker. The output also includes `isTrusted`, `timeStamp` from the event, and runtime context (`pageUrl`, `constructorName`).
|
|
68
|
+
|
|
61
69
|
### Retry reset
|
|
62
70
|
|
|
63
71
|
If enough time has passed since the last reload (configurable via `minTimeBetweenResets`, default 5000 ms), the orchestrator resets the attempt counter and starts a fresh retry cycle instead of continuing to fallback. This prevents stale URL params from triggering fallback on a clean page load.
|
package/dist/_internal.js
CHANGED
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
defaultSpinnerSvg,
|
|
4
4
|
extractVersionFromHtml,
|
|
5
5
|
sanitizeCssValue
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QDYSBRW2.js";
|
|
7
7
|
import {
|
|
8
8
|
createLogger,
|
|
9
9
|
isChunkError,
|
|
10
10
|
listenInternal,
|
|
11
11
|
serializeError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YTH35AWC.js";
|
|
13
13
|
import {
|
|
14
14
|
dispatchAsyncRuntimeError,
|
|
15
15
|
dispatchChunkLoadError,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
dispatchNetworkTimeout,
|
|
19
19
|
dispatchSyncRuntimeError,
|
|
20
20
|
dispatchUnhandledRejection
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-ALPGMLNW.js";
|
|
22
22
|
import {
|
|
23
23
|
applyI18n,
|
|
24
24
|
debugSyncErrorEventType,
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
shouldIgnoreMessages,
|
|
41
41
|
subscribe,
|
|
42
42
|
triggerRetry
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-X6IW7S2K.js";
|
|
44
44
|
import "./chunk-MLKGABMK.js";
|
|
45
45
|
|
|
46
46
|
// src/common/handleErrorWithSpaGuard.ts
|
|
@@ -327,7 +327,47 @@ var getRetryInfoForBeacon = () => {
|
|
|
327
327
|
};
|
|
328
328
|
|
|
329
329
|
// src/common/fallbackRendering.ts
|
|
330
|
-
var
|
|
330
|
+
var showLoadingUI = (attempt) => {
|
|
331
|
+
const options = getOptions();
|
|
332
|
+
const loadingHtml = options.html?.loading?.content;
|
|
333
|
+
if (!loadingHtml) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const selector = options.html?.fallback?.selector ?? "body";
|
|
337
|
+
try {
|
|
338
|
+
const targetElement = document.querySelector(selector);
|
|
339
|
+
if (!targetElement) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const container = document.createElement("div");
|
|
343
|
+
container.innerHTML = loadingHtml;
|
|
344
|
+
const t = getI18n();
|
|
345
|
+
if (t) {
|
|
346
|
+
applyI18n(container, t);
|
|
347
|
+
}
|
|
348
|
+
targetElement.innerHTML = container.innerHTML;
|
|
349
|
+
const retrySection = targetElement.querySelector('[data-spa-guard-section="retrying"]');
|
|
350
|
+
if (retrySection) {
|
|
351
|
+
retrySection.style.display = "";
|
|
352
|
+
retrySection.style.visibility = "visible";
|
|
353
|
+
}
|
|
354
|
+
const attemptElements = targetElement.querySelectorAll('[data-spa-guard-content="attempt"]');
|
|
355
|
+
for (const el of attemptElements) {
|
|
356
|
+
el.textContent = String(attempt);
|
|
357
|
+
}
|
|
358
|
+
const spinnerEl = targetElement.querySelector("[data-spa-guard-spinner]");
|
|
359
|
+
if (spinnerEl) {
|
|
360
|
+
const spinnerOptions = options.html?.spinner;
|
|
361
|
+
if (spinnerOptions?.disabled) {
|
|
362
|
+
spinnerEl.style.display = "none";
|
|
363
|
+
} else if (spinnerOptions?.content) {
|
|
364
|
+
spinnerEl.innerHTML = spinnerOptions.content;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
} catch {
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
var showFallbackUI = (override) => {
|
|
331
371
|
const options = getOptions();
|
|
332
372
|
const fallbackHtml = options.html?.fallback?.content;
|
|
333
373
|
const selector = options.html?.fallback?.selector ?? "body";
|
|
@@ -354,11 +394,11 @@ var showFallbackUI = () => {
|
|
|
354
394
|
if (reloadBtn) {
|
|
355
395
|
reloadBtn.addEventListener("click", () => globalThis.window.location.reload());
|
|
356
396
|
}
|
|
357
|
-
const
|
|
358
|
-
if (
|
|
397
|
+
const retryId = override?.retryId ?? getRetryStateFromUrl()?.retryId;
|
|
398
|
+
if (retryId) {
|
|
359
399
|
const retryIdElements = document.getElementsByClassName("spa-guard-retry-id");
|
|
360
400
|
for (const element of retryIdElements) {
|
|
361
|
-
element.textContent =
|
|
401
|
+
element.textContent = retryId;
|
|
362
402
|
}
|
|
363
403
|
}
|
|
364
404
|
emitEvent({
|
|
@@ -703,7 +743,8 @@ var triggerRetry = (input = {}) => {
|
|
|
703
743
|
});
|
|
704
744
|
setState({ attempt: currentAttempt, phase: "fallback", retryId });
|
|
705
745
|
setFallbackMode();
|
|
706
|
-
|
|
746
|
+
clearRetryFromUrl();
|
|
747
|
+
showFallbackUI({ retryId });
|
|
707
748
|
return { status: "fallback" };
|
|
708
749
|
}
|
|
709
750
|
const nextAttempt = currentAttempt + 1;
|
|
@@ -720,6 +761,7 @@ var triggerRetry = (input = {}) => {
|
|
|
720
761
|
);
|
|
721
762
|
getLogger()?.retrySchedulingReload(retryId, nextAttempt, delay);
|
|
722
763
|
setState({ attempt: nextAttempt, retryId });
|
|
764
|
+
showLoadingUI(nextAttempt);
|
|
723
765
|
const timer = setTimeout(() => {
|
|
724
766
|
try {
|
|
725
767
|
if (useRetryId && enableRetryReset) {
|
|
@@ -737,7 +779,7 @@ var triggerRetry = (input = {}) => {
|
|
|
737
779
|
} catch (error) {
|
|
738
780
|
getLogger()?.error("triggerRetry internal error", error);
|
|
739
781
|
setState({ lastSource: void 0, lastTriggerTime: void 0, phase: "idle" });
|
|
740
|
-
return {
|
|
782
|
+
return { status: "internal-error" };
|
|
741
783
|
}
|
|
742
784
|
};
|
|
743
785
|
var markRetryHealthyBoot = () => {
|
|
@@ -768,7 +810,7 @@ var setFallbackStateForDebug = () => {
|
|
|
768
810
|
}
|
|
769
811
|
setState({ phase: "fallback", timer: null });
|
|
770
812
|
setFallbackMode();
|
|
771
|
-
showFallbackUI();
|
|
813
|
+
showFallbackUI({ retryId: state.retryId ?? void 0 });
|
|
772
814
|
};
|
|
773
815
|
var resetRetryOrchestratorForTests = () => {
|
|
774
816
|
const state = getState();
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
shouldIgnoreMessages,
|
|
12
12
|
staticAssetRecoveryKey,
|
|
13
13
|
triggerRetry
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-X6IW7S2K.js";
|
|
15
15
|
|
|
16
16
|
// src/common/isChunkError.ts
|
|
17
17
|
var isChunkError = (error) => {
|
|
@@ -58,6 +58,10 @@ var serializeError = (error) => {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
|
+
var MAX_DEPTH = 4;
|
|
62
|
+
var MAX_KEYS = 20;
|
|
63
|
+
var MAX_STRING_LEN = 500;
|
|
64
|
+
var truncate = (str) => str.length > MAX_STRING_LEN ? str.slice(0, MAX_STRING_LEN) + "\u2026" : str;
|
|
61
65
|
var serializeErrorInternal = (error) => {
|
|
62
66
|
if (error === null || error === void 0) {
|
|
63
67
|
return { type: "null", value: error };
|
|
@@ -75,8 +79,15 @@ var serializeErrorInternal = (error) => {
|
|
|
75
79
|
};
|
|
76
80
|
}
|
|
77
81
|
if ("reason" in error && "promise" in error) {
|
|
82
|
+
const evt = error;
|
|
83
|
+
const reason = evt.reason;
|
|
84
|
+
const pageUrl = typeof window !== "undefined" && typeof window.location?.href === "string" ? window.location.href : void 0;
|
|
78
85
|
return {
|
|
79
|
-
|
|
86
|
+
constructorName: reason?.constructor?.name,
|
|
87
|
+
isTrusted: evt.isTrusted,
|
|
88
|
+
pageUrl,
|
|
89
|
+
reason: serializeRejectionReason(reason, /* @__PURE__ */ new WeakSet(), 0),
|
|
90
|
+
timeStamp: evt.timeStamp,
|
|
80
91
|
type: "PromiseRejectionEvent"
|
|
81
92
|
};
|
|
82
93
|
}
|
|
@@ -117,6 +128,140 @@ var serializeErrorInternal = (error) => {
|
|
|
117
128
|
value: extractOwnProperties(error)
|
|
118
129
|
};
|
|
119
130
|
};
|
|
131
|
+
var serializeRejectionReason = (reason, visited, depth) => {
|
|
132
|
+
if (reason === null || reason === void 0) {
|
|
133
|
+
return { type: "null", value: reason };
|
|
134
|
+
}
|
|
135
|
+
if (typeof reason !== "object") {
|
|
136
|
+
const val = typeof reason === "string" ? truncate(reason) : reason;
|
|
137
|
+
return { type: typeof reason, value: val };
|
|
138
|
+
}
|
|
139
|
+
if (visited.has(reason)) {
|
|
140
|
+
return { type: "circular" };
|
|
141
|
+
}
|
|
142
|
+
visited.add(reason);
|
|
143
|
+
if (typeof AggregateError !== "undefined" && reason instanceof AggregateError) {
|
|
144
|
+
return {
|
|
145
|
+
errors: reason.errors.slice(0, 3).map((e) => serializeSafeError(e, visited, depth + 1)),
|
|
146
|
+
message: truncate(reason.message),
|
|
147
|
+
name: reason.name,
|
|
148
|
+
stack: reason.stack ? truncate(reason.stack) : void 0,
|
|
149
|
+
type: "Error"
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (typeof DOMException !== "undefined" && reason instanceof DOMException) {
|
|
153
|
+
return {
|
|
154
|
+
code: reason.code,
|
|
155
|
+
message: truncate(reason.message),
|
|
156
|
+
name: reason.name,
|
|
157
|
+
type: "Error"
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (reason instanceof Error) {
|
|
161
|
+
return serializeSafeError(reason, visited, depth);
|
|
162
|
+
}
|
|
163
|
+
const reasonObj = reason;
|
|
164
|
+
if (reasonObj.response != null) {
|
|
165
|
+
const response = reasonObj.response;
|
|
166
|
+
const result = {
|
|
167
|
+
type: "HttpError"
|
|
168
|
+
};
|
|
169
|
+
if (response.status !== void 0) {
|
|
170
|
+
result.status = response.status;
|
|
171
|
+
}
|
|
172
|
+
if (response.statusText !== void 0) {
|
|
173
|
+
result.statusText = typeof response.statusText === "string" ? truncate(response.statusText) : response.statusText;
|
|
174
|
+
}
|
|
175
|
+
if (response.url !== void 0) {
|
|
176
|
+
result.url = typeof response.url === "string" ? truncate(response.url) : response.url;
|
|
177
|
+
}
|
|
178
|
+
if (response.method !== void 0) {
|
|
179
|
+
result.method = response.method;
|
|
180
|
+
}
|
|
181
|
+
if (response.type !== void 0) {
|
|
182
|
+
result.responseType = response.type;
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
const headers = response.headers;
|
|
186
|
+
if (headers) {
|
|
187
|
+
let xRequestId;
|
|
188
|
+
if (typeof headers.get === "function") {
|
|
189
|
+
xRequestId = headers.get("X-Request-ID") ?? headers.get("x-request-id");
|
|
190
|
+
} else if (typeof headers === "object") {
|
|
191
|
+
xRequestId = headers["X-Request-ID"] ?? headers["x-request-id"];
|
|
192
|
+
}
|
|
193
|
+
if (xRequestId) {
|
|
194
|
+
result.xRequestId = truncate(String(xRequestId));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
}
|
|
199
|
+
const reqSource = reasonObj.config ?? reasonObj.request;
|
|
200
|
+
if (reqSource != null) {
|
|
201
|
+
const req = {};
|
|
202
|
+
if (reqSource.method !== void 0) {
|
|
203
|
+
req.method = reqSource.method;
|
|
204
|
+
}
|
|
205
|
+
if (reqSource.url !== void 0) {
|
|
206
|
+
req.url = typeof reqSource.url === "string" ? truncate(reqSource.url) : reqSource.url;
|
|
207
|
+
}
|
|
208
|
+
if (reqSource.baseURL !== void 0) {
|
|
209
|
+
req.baseURL = typeof reqSource.baseURL === "string" ? truncate(reqSource.baseURL) : reqSource.baseURL;
|
|
210
|
+
}
|
|
211
|
+
result.request = req;
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
type: "object",
|
|
217
|
+
value: extractBoundedObject(reasonObj, visited, depth)
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
var serializeSafeError = (error, visited, depth) => {
|
|
221
|
+
if (!(error instanceof Error)) {
|
|
222
|
+
return serializeRejectionReason(error, visited, depth + 1);
|
|
223
|
+
}
|
|
224
|
+
const result = {
|
|
225
|
+
message: truncate(error.message),
|
|
226
|
+
name: error.name,
|
|
227
|
+
stack: error.stack ? truncate(error.stack) : void 0,
|
|
228
|
+
type: "Error"
|
|
229
|
+
};
|
|
230
|
+
if (depth < MAX_DEPTH && error.cause !== void 0) {
|
|
231
|
+
const cause = error.cause;
|
|
232
|
+
if (typeof cause === "object" && cause !== null) {
|
|
233
|
+
if (!visited.has(cause)) {
|
|
234
|
+
result.cause = serializeRejectionReason(cause, visited, depth + 1);
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
result.cause = cause;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return result;
|
|
241
|
+
};
|
|
242
|
+
var extractBoundedObject = (obj, visited, depth) => {
|
|
243
|
+
const result = {};
|
|
244
|
+
let keyCount = 0;
|
|
245
|
+
for (const key of Object.keys(obj)) {
|
|
246
|
+
if (keyCount >= MAX_KEYS) {
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const value = obj[key];
|
|
251
|
+
if (value === null || value === void 0 || typeof value !== "object") {
|
|
252
|
+
result[key] = typeof value === "string" ? truncate(value) : value;
|
|
253
|
+
} else if (depth < MAX_DEPTH && !visited.has(value)) {
|
|
254
|
+
visited.add(value);
|
|
255
|
+
result[key] = extractBoundedObject(value, visited, depth + 1);
|
|
256
|
+
} else {
|
|
257
|
+
result[key] = "[object]";
|
|
258
|
+
}
|
|
259
|
+
} catch {
|
|
260
|
+
}
|
|
261
|
+
keyCount++;
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
};
|
|
120
265
|
var extractErrorProperties = (error) => {
|
|
121
266
|
const props = {};
|
|
122
267
|
for (const key of Object.getOwnPropertyNames(error)) {
|
|
@@ -247,6 +392,9 @@ var handleStaticAssetFailure = (url) => {
|
|
|
247
392
|
|
|
248
393
|
// src/common/listen/internal.ts
|
|
249
394
|
var listenInternal = (serializeError2, logger) => {
|
|
395
|
+
if (globalThis.window === void 0) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
250
398
|
if (isInitialized()) {
|
|
251
399
|
return;
|
|
252
400
|
}
|
|
@@ -254,7 +402,6 @@ var listenInternal = (serializeError2, logger) => {
|
|
|
254
402
|
setLogger(logger);
|
|
255
403
|
}
|
|
256
404
|
markInitialized();
|
|
257
|
-
const options = getOptions();
|
|
258
405
|
const wa = globalThis.window.addEventListener.bind(globalThis.window);
|
|
259
406
|
wa(
|
|
260
407
|
"error",
|
|
@@ -266,7 +413,7 @@ var listenInternal = (serializeError2, logger) => {
|
|
|
266
413
|
}
|
|
267
414
|
event.preventDefault();
|
|
268
415
|
emitEvent({ name: "static-asset-load-failed", url: assetUrl });
|
|
269
|
-
if (
|
|
416
|
+
if (getOptions().staticAssets?.autoRecover !== false) {
|
|
270
417
|
handleStaticAssetFailure(assetUrl);
|
|
271
418
|
}
|
|
272
419
|
return;
|
|
@@ -311,7 +458,7 @@ var listenInternal = (serializeError2, logger) => {
|
|
|
311
458
|
triggerRetry({ error: event.reason, source: "force-retry" });
|
|
312
459
|
return;
|
|
313
460
|
}
|
|
314
|
-
const rejectionConfig =
|
|
461
|
+
const rejectionConfig = getOptions().handleUnhandledRejections;
|
|
315
462
|
if (rejectionConfig?.sendBeacon !== false) {
|
|
316
463
|
const serialized = serializeError2(event);
|
|
317
464
|
sendBeacon({
|
|
@@ -413,9 +560,6 @@ var createLogger = () => ({
|
|
|
413
560
|
capturedError(type, ...args) {
|
|
414
561
|
console.error(`${PREFIX} ${type}:capture:`, ...args);
|
|
415
562
|
},
|
|
416
|
-
clearingRetryState() {
|
|
417
|
-
console.log(`${PREFIX} Clearing retry state from URL to allow clean reload attempt`);
|
|
418
|
-
},
|
|
419
563
|
error(msg, ...args) {
|
|
420
564
|
console.error(`${PREFIX} ${msg}`, ...args);
|
|
421
565
|
},
|
|
@@ -455,17 +599,11 @@ var createLogger = () => ({
|
|
|
455
599
|
retryCycleStarting(retryId, fromAttempt) {
|
|
456
600
|
console.log(`${PREFIX} Retry cycle starting: retryId=${retryId}, fromAttempt=${fromAttempt}`);
|
|
457
601
|
},
|
|
458
|
-
retryLimitExceeded(attempt, max) {
|
|
459
|
-
console.log(`${PREFIX} Retry limit exceeded (${attempt}/${max}), marking as fallback shown`);
|
|
460
|
-
},
|
|
461
602
|
retrySchedulingReload(retryId, attempt, delay) {
|
|
462
603
|
console.log(
|
|
463
604
|
`${PREFIX} Scheduling reload: retryId=${retryId}, attempt=${attempt}, delay=${delay}ms`
|
|
464
605
|
);
|
|
465
606
|
},
|
|
466
|
-
updatedRetryAttempt(attempt) {
|
|
467
|
-
console.log(`${PREFIX} Updated retry attempt to ${attempt} in URL for fallback UI`);
|
|
468
|
-
},
|
|
469
607
|
versionChangeDetected(oldVersion, latestVersion) {
|
|
470
608
|
console.warn(
|
|
471
609
|
`${PREFIX} New version available (${oldVersion ?? "unknown"} \u2192 ${latestVersion}). Please refresh to get the latest version.`
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders the loading UI into the DOM during a retry delay before reload.
|
|
3
|
+
*
|
|
4
|
+
* Fail-safe: if loading content is not configured or the target element is not
|
|
5
|
+
* found, returns silently with no log, no event, and no side effects.
|
|
6
|
+
* All DOM access is wrapped in try/catch.
|
|
7
|
+
*/
|
|
8
|
+
export declare const showLoadingUI: (attempt: number) => void;
|
|
1
9
|
/**
|
|
2
10
|
* Renders the fallback UI into the DOM.
|
|
3
11
|
*
|
|
@@ -10,4 +18,6 @@
|
|
|
10
18
|
* Fails safely: if fallback HTML is not configured or the target element
|
|
11
19
|
* is not found, logs a warning and returns without side effects or errors.
|
|
12
20
|
*/
|
|
13
|
-
export declare const showFallbackUI: (
|
|
21
|
+
export declare const showFallbackUI: (override?: {
|
|
22
|
+
retryId?: string;
|
|
23
|
+
}) => void;
|
package/dist/common/index.d.ts
CHANGED
|
@@ -5,3 +5,5 @@ export { disableDefaultRetry, enableDefaultRetry, isDefaultRetryEnabled } from "
|
|
|
5
5
|
export { isInFallbackMode, resetFallbackMode } from "./fallbackState";
|
|
6
6
|
export { listen } from "./listen";
|
|
7
7
|
export * as options from "./options";
|
|
8
|
+
export { getRetrySnapshot, markRetryHealthyBoot, triggerRetry } from "./retryOrchestrator";
|
|
9
|
+
export type { RetryPhase, RetrySnapshot, TriggerInput, TriggerResult } from "./retryOrchestrator";
|
package/dist/common/index.js
CHANGED
|
@@ -2,18 +2,21 @@ import {
|
|
|
2
2
|
createLogger,
|
|
3
3
|
listenInternal,
|
|
4
4
|
serializeError
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-YTH35AWC.js";
|
|
6
6
|
import {
|
|
7
7
|
ForceRetryError,
|
|
8
8
|
disableDefaultRetry,
|
|
9
9
|
emitEvent,
|
|
10
10
|
enableDefaultRetry,
|
|
11
|
+
getRetrySnapshot,
|
|
11
12
|
isDefaultRetryEnabled,
|
|
12
13
|
isInFallbackMode,
|
|
14
|
+
markRetryHealthyBoot,
|
|
13
15
|
options_exports,
|
|
14
16
|
resetFallbackMode,
|
|
15
|
-
subscribe
|
|
16
|
-
|
|
17
|
+
subscribe,
|
|
18
|
+
triggerRetry
|
|
19
|
+
} from "../chunk-X6IW7S2K.js";
|
|
17
20
|
import {
|
|
18
21
|
__export
|
|
19
22
|
} from "../chunk-MLKGABMK.js";
|
|
@@ -73,9 +76,12 @@ export {
|
|
|
73
76
|
disableDefaultRetry,
|
|
74
77
|
enableDefaultRetry,
|
|
75
78
|
events_exports as events,
|
|
79
|
+
getRetrySnapshot,
|
|
76
80
|
isDefaultRetryEnabled,
|
|
77
81
|
isInFallbackMode,
|
|
78
82
|
listen,
|
|
83
|
+
markRetryHealthyBoot,
|
|
79
84
|
options_exports as options,
|
|
80
|
-
resetFallbackMode
|
|
85
|
+
resetFallbackMode,
|
|
86
|
+
triggerRetry
|
|
81
87
|
};
|
package/dist/common/logger.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { SPAGuardEvent } from "./events/types";
|
|
|
2
2
|
export interface Logger {
|
|
3
3
|
beaconSendFailed(error: unknown): void;
|
|
4
4
|
capturedError(type: string, ...args: unknown[]): void;
|
|
5
|
-
clearingRetryState(): void;
|
|
6
5
|
error(msg: string, ...args: unknown[]): void;
|
|
7
6
|
fallbackAlreadyShown(error: unknown): void;
|
|
8
7
|
fallbackInjectFailed(error: unknown): void;
|
|
@@ -13,9 +12,7 @@ export interface Logger {
|
|
|
13
12
|
noFallbackConfigured(): void;
|
|
14
13
|
reloadAlreadyScheduled(error: unknown): void;
|
|
15
14
|
retryCycleStarting(retryId: string, fromAttempt: number): void;
|
|
16
|
-
retryLimitExceeded(attempt: number, max: number): void;
|
|
17
15
|
retrySchedulingReload(retryId: string, attempt: number, delay: number): void;
|
|
18
|
-
updatedRetryAttempt(attempt: number): void;
|
|
19
16
|
versionChangeDetected(oldVersion: null | string, latestVersion: string): void;
|
|
20
17
|
versionCheckAlreadyRunning(): void;
|
|
21
18
|
versionCheckDisabled(): void;
|
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
dispatchStaticAsset404,
|
|
9
9
|
dispatchSyncRuntimeError,
|
|
10
10
|
dispatchUnhandledRejection
|
|
11
|
-
} from "../../chunk-
|
|
11
|
+
} from "../../chunk-ALPGMLNW.js";
|
|
12
12
|
import {
|
|
13
13
|
subscribeToState
|
|
14
|
-
} from "../../chunk-
|
|
14
|
+
} from "../../chunk-SCBBWARW.js";
|
|
15
15
|
import {
|
|
16
16
|
subscribe
|
|
17
|
-
} from "../../chunk-
|
|
17
|
+
} from "../../chunk-X6IW7S2K.js";
|
|
18
18
|
import "../../chunk-MLKGABMK.js";
|
|
19
19
|
|
|
20
20
|
// src/runtime/debug/index.ts
|
package/dist/runtime/index.js
CHANGED
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
extractVersionFromHtml,
|
|
4
4
|
getSpinnerHtml,
|
|
5
5
|
showSpinner
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-QDYSBRW2.js";
|
|
7
7
|
import {
|
|
8
8
|
getState,
|
|
9
9
|
subscribeToState
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-SCBBWARW.js";
|
|
11
11
|
import {
|
|
12
12
|
ForceRetryError,
|
|
13
13
|
getLogger,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
markRetryHealthyBoot,
|
|
16
16
|
setTranslations,
|
|
17
17
|
versionCheckStateWindowKey
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-X6IW7S2K.js";
|
|
19
19
|
import "../chunk-MLKGABMK.js";
|
|
20
20
|
|
|
21
21
|
// src/common/checkVersion.ts
|