@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 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-6TP2S7L6.js";
6
+ } from "./chunk-QDYSBRW2.js";
7
7
  import {
8
8
  createLogger,
9
9
  isChunkError,
10
10
  listenInternal,
11
11
  serializeError
12
- } from "./chunk-DINLBER6.js";
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-A5HF6LY6.js";
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-XRBUBTPZ.js";
43
+ } from "./chunk-X6IW7S2K.js";
44
44
  import "./chunk-MLKGABMK.js";
45
45
 
46
46
  // src/common/handleErrorWithSpaGuard.ts
@@ -4,7 +4,7 @@ import {
4
4
  emitEvent,
5
5
  getOptions,
6
6
  setFallbackStateForDebug
7
- } from "./chunk-XRBUBTPZ.js";
7
+ } from "./chunk-X6IW7S2K.js";
8
8
 
9
9
  // src/runtime/debug/errorDispatchers.ts
10
10
  function dispatchAsyncRuntimeError() {
@@ -2,7 +2,7 @@ import {
2
2
  defaultSpinnerHtml,
3
3
  getOptions,
4
4
  spinnerStateWindowKey
5
- } from "./chunk-XRBUBTPZ.js";
5
+ } from "./chunk-X6IW7S2K.js";
6
6
 
7
7
  // src/common/parseVersion.ts
8
8
  function extractVersionFromHtml(html) {
@@ -3,7 +3,7 @@ import {
3
3
  getRetryAttemptFromUrl,
4
4
  getRetryStateFromUrl,
5
5
  subscribe
6
- } from "./chunk-XRBUBTPZ.js";
6
+ } from "./chunk-X6IW7S2K.js";
7
7
 
8
8
  // src/runtime/state.ts
9
9
  var getInitialStateFromUrl = () => {
@@ -327,7 +327,47 @@ var getRetryInfoForBeacon = () => {
327
327
  };
328
328
 
329
329
  // src/common/fallbackRendering.ts
330
- var showFallbackUI = () => {
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 retryState = getRetryStateFromUrl();
358
- if (retryState) {
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 = retryState.retryId;
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
- showFallbackUI();
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 { reason: "internal-error", status: "deduped" };
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-XRBUBTPZ.js";
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
- reason: serializeErrorInternal(error.reason),
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 (options.staticAssets?.autoRecover !== false) {
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 = options.handleUnhandledRejections;
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: () => void;
21
+ export declare const showFallbackUI: (override?: {
22
+ retryId?: string;
23
+ }) => void;
@@ -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";
@@ -2,18 +2,21 @@ import {
2
2
  createLogger,
3
3
  listenInternal,
4
4
  serializeError
5
- } from "../chunk-DINLBER6.js";
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
- } from "../chunk-XRBUBTPZ.js";
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
  };
@@ -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;
@@ -18,6 +18,8 @@ export type TriggerResult = {
18
18
  status: "accepted";
19
19
  } | {
20
20
  status: "fallback";
21
+ } | {
22
+ status: "internal-error";
21
23
  } | {
22
24
  status: "retry-disabled";
23
25
  };
@@ -8,13 +8,13 @@ import {
8
8
  dispatchStaticAsset404,
9
9
  dispatchSyncRuntimeError,
10
10
  dispatchUnhandledRejection
11
- } from "../../chunk-A5HF6LY6.js";
11
+ } from "../../chunk-ALPGMLNW.js";
12
12
  import {
13
13
  subscribeToState
14
- } from "../../chunk-EFWD2I2Y.js";
14
+ } from "../../chunk-SCBBWARW.js";
15
15
  import {
16
16
  subscribe
17
- } from "../../chunk-XRBUBTPZ.js";
17
+ } from "../../chunk-X6IW7S2K.js";
18
18
  import "../../chunk-MLKGABMK.js";
19
19
 
20
20
  // src/runtime/debug/index.ts
@@ -3,11 +3,11 @@ import {
3
3
  extractVersionFromHtml,
4
4
  getSpinnerHtml,
5
5
  showSpinner
6
- } from "../chunk-6TP2S7L6.js";
6
+ } from "../chunk-QDYSBRW2.js";
7
7
  import {
8
8
  getState,
9
9
  subscribeToState
10
- } from "../chunk-EFWD2I2Y.js";
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-XRBUBTPZ.js";
18
+ } from "../chunk-X6IW7S2K.js";
19
19
  import "../chunk-MLKGABMK.js";
20
20
 
21
21
  // src/common/checkVersion.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ovineko/spa-guard",
3
- "version": "0.0.1-alpha-30",
3
+ "version": "0.0.1-alpha-31",
4
4
  "description": "Chunk load error handling for SPAs — core runtime, error handling, schema, i18n",
5
5
  "keywords": [
6
6
  "spa",