@ovineko/spa-guard 0.0.1-alpha-5 → 0.0.1-alpha-6

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
@@ -76,7 +76,7 @@ export default defineConfig({
76
76
  endpoint: "/api/beacon",
77
77
  },
78
78
  errors: {
79
- ignore: [], // Filter out specific error messages from reporting
79
+ ignore: [], // Error substrings to fully skip (no log, no beacon, no reload)
80
80
  forceRetry: [], // Custom error messages that trigger retry/reload (like chunk errors)
81
81
  },
82
82
  useRetryId: true, // Use query parameters for cache busting (default: true)
@@ -274,7 +274,7 @@ spaGuardVitePlugin({
274
274
 
275
275
  // Error filtering and retry
276
276
  errors: {
277
- ignore: [], // Array of error message substrings to ignore
277
+ ignore: [], // Array of error message substrings to fully skip (no log, no beacon, no reload)
278
278
  forceRetry: [], // Array of error message substrings that trigger retry/reload
279
279
  },
280
280
 
@@ -322,7 +322,7 @@ interface Options {
322
322
  };
323
323
 
324
324
  errors?: {
325
- ignore?: string[]; // Error message substrings to filter out (default: [])
325
+ ignore?: string[]; // Error message substrings to fully skip (no log, no beacon, no reload) (default: [])
326
326
  forceRetry?: string[]; // Error message substrings that trigger retry/reload (default: [])
327
327
  };
328
328
 
@@ -1138,7 +1138,7 @@ interface Options {
1138
1138
  };
1139
1139
 
1140
1140
  errors?: {
1141
- ignore?: string[]; // Error message substrings to filter out (default: [])
1141
+ ignore?: string[]; // Error message substrings to fully skip (no log, no beacon, no reload) (default: [])
1142
1142
  forceRetry?: string[]; // Error message substrings that trigger retry/reload (default: [])
1143
1143
  };
1144
1144
 
@@ -1521,8 +1521,8 @@ import spaGuardEslint from "@ovineko/spa-guard/eslint";
1521
1521
 
1522
1522
  ## Build Sizes
1523
1523
 
1524
- - **Production:** `dist-inline/index.js` ~8.3 KB minified (Terser)
1525
- - **Trace:** `dist-inline-trace/index.js` ~13.3 KB minified (Terser)
1524
+ - **Production:** `dist-inline/index.js` ~8.9 KB minified (Terser)
1525
+ - **Trace:** `dist-inline-trace/index.js` ~13.8 KB minified (Terser)
1526
1526
  - **Main library:** `dist/` varies by export
1527
1527
 
1528
1528
  ## Advanced Usage
@@ -1646,7 +1646,7 @@ spaGuardVitePlugin({
1646
1646
  });
1647
1647
  ```
1648
1648
 
1649
- **`errors.ignore`** - Errors containing any of these substrings will not be logged to console and beacons will not be sent. Case-sensitive substring matching.
1649
+ **`errors.ignore`** - Errors containing any of these substrings are fully ignored: no console log, no beacon, no reload, and no further processing. The error handler returns immediately after the ignore check. Case-sensitive substring matching.
1650
1650
 
1651
1651
  **`errors.forceRetry`** - Errors containing any of these substrings will trigger the same retry/reload process as chunk load errors (calls `attemptReload()`). Useful for custom error patterns that indicate a stale deployment. Case-sensitive substring matching.
1652
1652
 
@@ -1709,6 +1709,16 @@ throw new ForceRetryError("stale module detected");
1709
1709
 
1710
1710
  // Works with no message too
1711
1711
  throw new ForceRetryError();
1712
+
1713
+ // Wrap an original error with { cause } (ES2022 ErrorOptions)
1714
+ try {
1715
+ await initializeAuth();
1716
+ } catch (error) {
1717
+ throw new ForceRetryError("Failed to init auth", { cause: error });
1718
+ }
1719
+
1720
+ // cause-only (no custom message)
1721
+ throw new ForceRetryError(undefined, { cause: originalError });
1712
1722
  ```
1713
1723
 
1714
1724
  **Use cases:**
@@ -1729,6 +1739,11 @@ err.name; // "ForceRetryError"
1729
1739
  err.message; // "__SPA_GUARD_FORCE_RETRY__version mismatch"
1730
1740
  err instanceof ForceRetryError; // true
1731
1741
  err instanceof Error; // true
1742
+
1743
+ // With cause
1744
+ const original = new TypeError("network timeout");
1745
+ const err2 = new ForceRetryError("version mismatch", { cause: original });
1746
+ err2.cause; // TypeError: network timeout
1732
1747
  ```
1733
1748
 
1734
1749
  ### Custom Retry Strategy
@@ -5,20 +5,22 @@ import {
5
5
  attemptReload,
6
6
  isChunkError,
7
7
  sendBeacon,
8
- shouldForceRetry
9
- } from "./chunk-RFGT43OM.js";
10
- import {
11
- getRetryInfoForBeacon
12
- } from "./chunk-T5RWH2HR.js";
8
+ shouldForceRetry,
9
+ shouldIgnoreMessages
10
+ } from "./chunk-PVLEHXOQ.js";
13
11
  import {
14
12
  defaultErrorFallbackHtml,
15
13
  defaultLoadingFallbackHtml
16
- } from "./chunk-G6QM353W.js";
14
+ } from "./chunk-UVB6PO4N.js";
15
+ import {
16
+ getRetryInfoForBeacon
17
+ } from "./chunk-T5RWH2HR.js";
17
18
 
18
19
  // src/common/DefaultErrorFallback.tsx
19
20
  import { useLayoutEffect, useMemo, useRef } from "react";
20
21
  import { jsx } from "react/jsx-runtime";
21
22
  var escapeHtml = (str) => str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
23
+ var reloadHandler = () => location.reload();
22
24
  var DefaultErrorFallback = ({
23
25
  error,
24
26
  isChunkError: isChunk,
@@ -52,14 +54,19 @@ var DefaultErrorFallback = ({
52
54
  if (!el) {
53
55
  return;
54
56
  }
55
- if (onReset) {
56
- const tryAgainBtn = el.querySelector('[data-spa-guard-action="try-again"]');
57
- if (tryAgainBtn) {
58
- const handler = () => onReset();
59
- tryAgainBtn.addEventListener("click", handler);
60
- return () => tryAgainBtn.removeEventListener("click", handler);
61
- }
57
+ const reloadBtn = el.querySelector('[data-spa-guard-action="reload"]');
58
+ reloadBtn?.addEventListener("click", reloadHandler);
59
+ const tryAgainHandler = onReset ? () => onReset() : null;
60
+ const tryAgainBtn = onReset ? el.querySelector('[data-spa-guard-action="try-again"]') : null;
61
+ if (tryAgainHandler && tryAgainBtn) {
62
+ tryAgainBtn.addEventListener("click", tryAgainHandler);
62
63
  }
64
+ return () => {
65
+ reloadBtn?.removeEventListener("click", reloadHandler);
66
+ if (tryAgainHandler && tryAgainBtn) {
67
+ tryAgainBtn.removeEventListener("click", tryAgainHandler);
68
+ }
69
+ };
63
70
  }, [onReset, html]);
64
71
  const innerHtml = useMemo(() => ({ __html: html }), [html]);
65
72
  return /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: innerHtml, ref: containerRef });
@@ -78,8 +85,11 @@ var handleErrorWithSpaGuard = (error, options) => {
78
85
  onError?.(error);
79
86
  } catch {
80
87
  }
81
- const isChunk = isChunkError(error);
82
88
  const errorMessage = error instanceof Error ? error.message : String(error);
89
+ if (shouldIgnoreMessages([errorMessage])) {
90
+ return;
91
+ }
92
+ const isChunk = isChunkError(error);
83
93
  const isForceRetry = shouldForceRetry([errorMessage]);
84
94
  if ((isChunk || isForceRetry) && autoRetryChunkErrors) {
85
95
  attemptReload(error);
@@ -1,9 +1,9 @@
1
+ import {
2
+ getOptions
3
+ } from "./chunk-UVB6PO4N.js";
1
4
  import {
2
5
  getLogger
3
6
  } from "./chunk-T5RWH2HR.js";
4
- import {
5
- getOptions
6
- } from "./chunk-G6QM353W.js";
7
7
 
8
8
  // src/common/checkVersion.ts
9
9
  var versionCheckInterval = null;
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  attemptReload,
3
3
  isChunkError
4
- } from "./chunk-RFGT43OM.js";
4
+ } from "./chunk-PVLEHXOQ.js";
5
5
  import {
6
6
  getState,
7
7
  subscribeToState
8
8
  } from "./chunk-2DFYUVHH.js";
9
+ import {
10
+ getOptions
11
+ } from "./chunk-UVB6PO4N.js";
9
12
  import {
10
13
  emitEvent,
11
14
  isDefaultRetryEnabled,
12
15
  subscribe
13
16
  } from "./chunk-T5RWH2HR.js";
14
- import {
15
- getOptions
16
- } from "./chunk-G6QM353W.js";
17
17
  import {
18
18
  debugSyncErrorEventType
19
19
  } from "./chunk-EDRTFPCN.js";
@@ -38,9 +38,7 @@ function DebugSyncErrorTrigger() {
38
38
  };
39
39
  }, []);
40
40
  if (error) {
41
- const err = error;
42
- setError(null);
43
- throw err;
41
+ throw error;
44
42
  }
45
43
  return null;
46
44
  }
@@ -1,8 +1,8 @@
1
1
  // src/common/errors/ForceRetryError.ts
2
2
  var FORCE_RETRY_MAGIC = "__SPA_GUARD_FORCE_RETRY__";
3
3
  var ForceRetryError = class extends Error {
4
- constructor(message) {
5
- super(`${FORCE_RETRY_MAGIC}${message ?? ""}`);
4
+ constructor(message, options) {
5
+ super(`${FORCE_RETRY_MAGIC}${message ?? ""}`, options);
6
6
  this.name = "ForceRetryError";
7
7
  }
8
8
  };
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  FORCE_RETRY_MAGIC
3
- } from "./chunk-L5UEVGWR.js";
3
+ } from "./chunk-OQGJLNZ2.js";
4
+ import {
5
+ getOptions
6
+ } from "./chunk-UVB6PO4N.js";
4
7
  import {
5
8
  clearLastReloadTime,
6
9
  clearRetryAttemptFromUrl,
@@ -16,9 +19,6 @@ import {
16
19
  setLastRetryResetInfo,
17
20
  shouldResetRetryCycle
18
21
  } from "./chunk-T5RWH2HR.js";
19
- import {
20
- getOptions
21
- } from "./chunk-G6QM353W.js";
22
22
  import {
23
23
  RETRY_ATTEMPT_PARAM,
24
24
  RETRY_ID_PARAM
@@ -60,7 +60,7 @@ var getErrorMessage = (error) => {
60
60
  // src/common/shouldIgnore.ts
61
61
  var shouldIgnoreMessages = (messages) => {
62
62
  const options = getOptions();
63
- const ignorePatterns = options.errors?.ignore ?? [];
63
+ const ignorePatterns = (options.errors?.ignore ?? []).filter((p) => p !== "");
64
64
  if (ignorePatterns.length === 0) {
65
65
  return false;
66
66
  }
@@ -71,7 +71,9 @@ var shouldIgnoreMessages = (messages) => {
71
71
  };
72
72
  var shouldForceRetry = (messages) => {
73
73
  const options = getOptions();
74
- const forceRetryPatterns = [...options.errors?.forceRetry ?? [], FORCE_RETRY_MAGIC];
74
+ const forceRetryPatterns = [...options.errors?.forceRetry ?? [], FORCE_RETRY_MAGIC].filter(
75
+ (p) => p !== ""
76
+ );
75
77
  const validMessages = messages.filter((msg) => typeof msg === "string");
76
78
  return validMessages.some(
77
79
  (message) => forceRetryPatterns.some((pattern) => message.includes(pattern))
@@ -249,6 +251,10 @@ var showFallbackUI = () => {
249
251
  } else if (!useRetryId && !retryState) {
250
252
  clearRetryAttemptFromUrl();
251
253
  }
254
+ const reloadBtn = targetElement.querySelector('[data-spa-guard-action="reload"]');
255
+ if (reloadBtn) {
256
+ reloadBtn.addEventListener("click", () => location.reload());
257
+ }
252
258
  if (retryState) {
253
259
  const retryIdElements = document.getElementsByClassName("spa-guard-retry-id");
254
260
  for (const element of retryIdElements) {
@@ -13,7 +13,7 @@ __export(options_exports, {
13
13
  });
14
14
 
15
15
  // src/common/fallbackHtml.generated.ts
16
- var defaultErrorFallbackHtml = `<style>.spa-guard-error-id:has(.spa-guard-retry-id:empty){display:none}</style><div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h1 data-spa-guard-content="heading">Something went wrong</h1><p data-spa-guard-content="message" style="max-width:600px;margin:1rem auto">Please refresh the page to continue.</p><div style="display:flex;gap:.5rem;justify-content:center"><button data-spa-guard-action="try-again" type="button" style="display:none">Try again</button> <button data-spa-guard-action="reload" type="button" onclick="location.reload()">Reload page</button></div><p class="spa-guard-error-id" style="margin-top:20px;font-size:12px">Error ID: <span class="spa-guard-retry-id"></span></p></div></div>`;
16
+ var defaultErrorFallbackHtml = `<style>.spa-guard-error-id:has(.spa-guard-retry-id:empty){display:none}</style><div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h1 data-spa-guard-content="heading">Something went wrong</h1><p data-spa-guard-content="message" style="max-width:600px;margin:1rem auto">Please refresh the page to continue.</p><div style="display:flex;gap:.5rem;justify-content:center"><button data-spa-guard-action="try-again" type="button" style="display:none">Try again</button> <button data-spa-guard-action="reload" type="button">Reload page</button></div><p class="spa-guard-error-id" style="margin-top:20px;font-size:12px">Error ID: <span class="spa-guard-retry-id"></span></p></div></div>`;
17
17
  var defaultLoadingFallbackHtml = `<div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h2>Loading...</h2><p data-spa-guard-section="retrying" style="display:none">Retry attempt <span data-spa-guard-content="attempt"></span></p></div></div>`;
18
18
 
19
19
  // src/common/options.ts
@@ -1,5 +1,5 @@
1
1
  declare const FORCE_RETRY_MAGIC = "__SPA_GUARD_FORCE_RETRY__";
2
2
  export { FORCE_RETRY_MAGIC };
3
3
  export declare class ForceRetryError extends Error {
4
- constructor(message?: string);
4
+ constructor(message?: string, options?: ErrorOptions);
5
5
  }
@@ -1,2 +1,2 @@
1
- export declare const defaultErrorFallbackHtml = "<style>.spa-guard-error-id:has(.spa-guard-retry-id:empty){display:none}</style><div style=\"display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem\"><div style=\"text-align:center\"><h1 data-spa-guard-content=\"heading\">Something went wrong</h1><p data-spa-guard-content=\"message\" style=\"max-width:600px;margin:1rem auto\">Please refresh the page to continue.</p><div style=\"display:flex;gap:.5rem;justify-content:center\"><button data-spa-guard-action=\"try-again\" type=\"button\" style=\"display:none\">Try again</button> <button data-spa-guard-action=\"reload\" type=\"button\" onclick=\"location.reload()\">Reload page</button></div><p class=\"spa-guard-error-id\" style=\"margin-top:20px;font-size:12px\">Error ID: <span class=\"spa-guard-retry-id\"></span></p></div></div>";
1
+ export declare const defaultErrorFallbackHtml = "<style>.spa-guard-error-id:has(.spa-guard-retry-id:empty){display:none}</style><div style=\"display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem\"><div style=\"text-align:center\"><h1 data-spa-guard-content=\"heading\">Something went wrong</h1><p data-spa-guard-content=\"message\" style=\"max-width:600px;margin:1rem auto\">Please refresh the page to continue.</p><div style=\"display:flex;gap:.5rem;justify-content:center\"><button data-spa-guard-action=\"try-again\" type=\"button\" style=\"display:none\">Try again</button> <button data-spa-guard-action=\"reload\" type=\"button\">Reload page</button></div><p class=\"spa-guard-error-id\" style=\"margin-top:20px;font-size:12px\">Error ID: <span class=\"spa-guard-retry-id\"></span></p></div></div>";
2
2
  export declare const defaultLoadingFallbackHtml = "<div style=\"display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem\"><div style=\"text-align:center\"><h2>Loading...</h2><p data-spa-guard-section=\"retrying\" style=\"display:none\">Retry attempt <span data-spa-guard-content=\"attempt\"></span></p></div></div>";
@@ -10,10 +10,14 @@ import {
10
10
  sendBeacon,
11
11
  shouldForceRetry,
12
12
  shouldIgnoreMessages
13
- } from "../chunk-RFGT43OM.js";
13
+ } from "../chunk-PVLEHXOQ.js";
14
14
  import {
15
15
  ForceRetryError
16
- } from "../chunk-L5UEVGWR.js";
16
+ } from "../chunk-OQGJLNZ2.js";
17
+ import {
18
+ getOptions,
19
+ options_exports
20
+ } from "../chunk-UVB6PO4N.js";
17
21
  import {
18
22
  disableDefaultRetry,
19
23
  emitEvent,
@@ -28,10 +32,6 @@ import {
28
32
  subscribe,
29
33
  updateRetryStateInUrl
30
34
  } from "../chunk-T5RWH2HR.js";
31
- import {
32
- getOptions,
33
- options_exports
34
- } from "../chunk-G6QM353W.js";
35
35
  import "../chunk-EDRTFPCN.js";
36
36
  import "../chunk-RP52SPBK.js";
37
37
  import {
@@ -212,10 +212,10 @@ var listenInternal = (serializeError2, logger) => {
212
212
  wa(
213
213
  "error",
214
214
  (event) => {
215
- const shouldIgnore = shouldIgnoreMessages([event.message]);
216
- if (!shouldIgnore) {
217
- getLogger()?.capturedError("error", event);
215
+ if (shouldIgnoreMessages([event.message])) {
216
+ return;
218
217
  }
218
+ getLogger()?.capturedError("error", event);
219
219
  if (isChunkError(event)) {
220
220
  event.preventDefault();
221
221
  attemptReload(event.error ?? event);
@@ -238,10 +238,10 @@ var listenInternal = (serializeError2, logger) => {
238
238
  );
239
239
  wa("unhandledrejection", (event) => {
240
240
  const errorMessage = String(event.reason);
241
- const shouldIgnore = shouldIgnoreMessages([errorMessage]);
242
- if (!shouldIgnore) {
243
- getLogger()?.capturedError("unhandledrejection", event);
241
+ if (shouldIgnoreMessages([errorMessage])) {
242
+ return;
244
243
  }
244
+ getLogger()?.capturedError("unhandledrejection", event);
245
245
  if (isChunkError(event.reason)) {
246
246
  event.preventDefault();
247
247
  attemptReload(event.reason);
@@ -269,10 +269,10 @@ var listenInternal = (serializeError2, logger) => {
269
269
  });
270
270
  wa("securitypolicyviolation", (event) => {
271
271
  const eventMessage = `${event.violatedDirective}: ${event.blockedURI}`;
272
- const shouldIgnore = shouldIgnoreMessages([eventMessage]);
273
- if (!shouldIgnore) {
274
- getLogger()?.capturedError("csp", event.blockedURI, event.violatedDirective);
272
+ if (shouldIgnoreMessages([eventMessage])) {
273
+ return;
275
274
  }
275
+ getLogger()?.capturedError("csp", event.blockedURI, event.violatedDirective);
276
276
  const serialized = serializeError2(event);
277
277
  sendBeacon({
278
278
  eventMessage,
@@ -283,10 +283,10 @@ var listenInternal = (serializeError2, logger) => {
283
283
  });
284
284
  wa("vite:preloadError", (event) => {
285
285
  const errorMsg = event?.payload?.message || event?.message;
286
- const shouldIgnore = shouldIgnoreMessages([errorMsg]);
287
- if (!shouldIgnore) {
288
- getLogger()?.capturedError("vite:preloadError", event);
286
+ if (shouldIgnoreMessages([errorMsg])) {
287
+ return;
289
288
  }
289
+ getLogger()?.capturedError("vite:preloadError", event);
290
290
  event.preventDefault();
291
291
  attemptReload(event?.payload ?? event);
292
292
  });
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  parseBeacon
3
3
  } from "../chunk-WE7SWL5H.js";
4
- import "../chunk-KZEBQNOZ.js";
5
4
  import {
6
5
  BeaconError
7
6
  } from "../chunk-3SCN2UE4.js";
8
7
  import {
9
8
  name
10
9
  } from "../chunk-RP52SPBK.js";
10
+ import "../chunk-KZEBQNOZ.js";
11
11
  import "../chunk-MLKGABMK.js";
12
12
 
13
13
  // src/fastify/index.ts
@@ -4,15 +4,15 @@ import {
4
4
  useSPAGuardChunkError,
5
5
  useSPAGuardEvents,
6
6
  useSpaGuardState
7
- } from "../chunk-IC7SCT5F.js";
8
- import "../chunk-RFGT43OM.js";
9
- import "../chunk-LGPIRNKE.js";
7
+ } from "../chunk-FMEBY5ND.js";
8
+ import "../chunk-PVLEHXOQ.js";
9
+ import "../chunk-CMBBYLOH.js";
10
10
  import "../chunk-2DFYUVHH.js";
11
11
  import {
12
12
  ForceRetryError
13
- } from "../chunk-L5UEVGWR.js";
13
+ } from "../chunk-OQGJLNZ2.js";
14
+ import "../chunk-UVB6PO4N.js";
14
15
  import "../chunk-T5RWH2HR.js";
15
- import "../chunk-G6QM353W.js";
16
16
  import "../chunk-EDRTFPCN.js";
17
17
  import "../chunk-RP52SPBK.js";
18
18
  import "../chunk-MLKGABMK.js";
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  DefaultErrorFallback,
3
3
  handleErrorWithSpaGuard
4
- } from "../chunk-RXW44IWI.js";
4
+ } from "../chunk-563JZA5T.js";
5
5
  import "../chunk-HUAI4DRW.js";
6
6
  import {
7
7
  useSpaGuardState
8
- } from "../chunk-IC7SCT5F.js";
8
+ } from "../chunk-FMEBY5ND.js";
9
9
  import {
10
10
  isChunkError
11
- } from "../chunk-RFGT43OM.js";
12
- import "../chunk-LGPIRNKE.js";
11
+ } from "../chunk-PVLEHXOQ.js";
12
+ import "../chunk-CMBBYLOH.js";
13
13
  import "../chunk-2DFYUVHH.js";
14
- import "../chunk-L5UEVGWR.js";
14
+ import "../chunk-OQGJLNZ2.js";
15
+ import "../chunk-UVB6PO4N.js";
15
16
  import "../chunk-T5RWH2HR.js";
16
- import "../chunk-G6QM353W.js";
17
17
  import "../chunk-EDRTFPCN.js";
18
18
  import "../chunk-RP52SPBK.js";
19
19
  import "../chunk-MLKGABMK.js";
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  DefaultErrorFallback,
3
3
  handleErrorWithSpaGuard
4
- } from "../chunk-RXW44IWI.js";
4
+ } from "../chunk-563JZA5T.js";
5
5
  import "../chunk-HUAI4DRW.js";
6
6
  import {
7
7
  useSpaGuardState
8
- } from "../chunk-IC7SCT5F.js";
8
+ } from "../chunk-FMEBY5ND.js";
9
9
  import {
10
10
  isChunkError
11
- } from "../chunk-RFGT43OM.js";
12
- import "../chunk-LGPIRNKE.js";
11
+ } from "../chunk-PVLEHXOQ.js";
12
+ import "../chunk-CMBBYLOH.js";
13
13
  import "../chunk-2DFYUVHH.js";
14
- import "../chunk-L5UEVGWR.js";
14
+ import "../chunk-OQGJLNZ2.js";
15
+ import "../chunk-UVB6PO4N.js";
15
16
  import "../chunk-T5RWH2HR.js";
16
- import "../chunk-G6QM353W.js";
17
17
  import "../chunk-EDRTFPCN.js";
18
18
  import "../chunk-RP52SPBK.js";
19
19
  import "../chunk-MLKGABMK.js";
@@ -2,16 +2,16 @@ import {
2
2
  recommendedSetup,
3
3
  startVersionCheck,
4
4
  stopVersionCheck
5
- } from "../chunk-LGPIRNKE.js";
5
+ } from "../chunk-CMBBYLOH.js";
6
6
  import {
7
7
  getState,
8
8
  subscribeToState
9
9
  } from "../chunk-2DFYUVHH.js";
10
10
  import {
11
11
  ForceRetryError
12
- } from "../chunk-L5UEVGWR.js";
12
+ } from "../chunk-OQGJLNZ2.js";
13
+ import "../chunk-UVB6PO4N.js";
13
14
  import "../chunk-T5RWH2HR.js";
14
- import "../chunk-G6QM353W.js";
15
15
  import "../chunk-EDRTFPCN.js";
16
16
  import "../chunk-RP52SPBK.js";
17
17
  import "../chunk-MLKGABMK.js";
@@ -1,4 +1,4 @@
1
- import "../chunk-G6QM353W.js";
1
+ import "../chunk-UVB6PO4N.js";
2
2
  import {
3
3
  optionsWindowKey
4
4
  } from "../chunk-EDRTFPCN.js";
@@ -1 +1 @@
1
- var e="@ovineko/spa-guard",t=Symbol.for(e+":event-subscribers"),r=Symbol.for(e+":internal-config"),a=Symbol.for(e+":initialized"),n=Symbol.for(e+":logger"),l="spaGuardRetryId",o="spaGuardRetryAttempt";globalThis.window&&!globalThis.window[t]&&(globalThis.window[t]=new Set),globalThis.window&&!globalThis.window[r]&&(globalThis.window[r]={defaultRetryEnabled:!0,initialized:!1,inlineScriptLoaded:!1});var i=globalThis.window?.[t]??new Set,s=globalThis.window?.[r]??{defaultRetryEnabled:!0,initialized:!1,inlineScriptLoaded:!1},d=()=>globalThis.window?.[n],c=(e,t)=>{t?.silent||d()?.logEvent(e),i.forEach(t=>{try{t(e)}catch{}})},y=e=>{let t=p(e);return!!t&&[/Failed to fetch dynamically imported module/i,/Importing a module script failed/i,/error loading dynamically imported module/i,/Unable to preload CSS/i,/Loading chunk \d+ failed/i,/Loading CSS chunk \d+ failed/i,/ChunkLoadError/i].some(e=>e.test(t))},p=e=>e instanceof Error?e.message:"string"==typeof e?e:e&&"object"==typeof e&&"message"in e?e.message+"":e&&"object"==typeof e&&"reason"in e?p(e.reason):null,m={checkVersion:{interval:3e5,mode:"html",onUpdate:"reload"},enableRetryReset:!0,errors:{forceRetry:[],ignore:[]},handleUnhandledRejections:{retry:!0,sendBeacon:!0},html:{fallback:{content:'<style>.spa-guard-error-id:has(.spa-guard-retry-id:empty){display:none}</style><div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h1 data-spa-guard-content="heading">Something went wrong</h1><p data-spa-guard-content="message" style="max-width:600px;margin:1rem auto">Please refresh the page to continue.</p><div style="display:flex;gap:.5rem;justify-content:center"><button data-spa-guard-action="try-again" type="button" style="display:none">Try again</button> <button data-spa-guard-action="reload" type="button" onclick="location.reload()">Reload page</button></div><p class="spa-guard-error-id" style="margin-top:20px;font-size:12px">Error ID: <span class="spa-guard-retry-id"></span></p></div></div>',selector:"body"},loading:{content:'<div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h2>Loading...</h2><p data-spa-guard-section="retrying" style="display:none">Retry attempt <span data-spa-guard-content="attempt"></span></p></div></div>'}},lazyRetry:{callReloadOnFailure:!0,retryDelays:[1e3,2e3]},minTimeBetweenResets:5e3,reloadDelays:[1e3,2e3,5e3],useRetryId:!0},u=()=>{let e=globalThis.window?.__SPA_GUARD_OPTIONS__;return{...m,...e,checkVersion:{...m.checkVersion,...e?.checkVersion},errors:{...m.errors,...e?.errors},handleUnhandledRejections:{...m.handleUnhandledRejections,...e?.handleUnhandledRejections},html:{fallback:{...m.html?.fallback,...e?.html?.fallback},loading:{...m.html?.loading,...e?.html?.loading}},lazyRetry:{...m.lazyRetry,...e?.lazyRetry},reportBeacon:{...m.reportBeacon,...e?.reportBeacon}}},g="__spa_guard_last_reload_timestamp__",h="__spa_guard_last_retry_reset__",f=null,w=null,b=()=>{try{return void 0!==globalThis.window&&typeof sessionStorage<"u"}catch{return!1}},v=()=>{if(b())try{let e=sessionStorage.getItem(g);if(e)return JSON.parse(e)}catch{return f}return f},R=()=>{try{let e=new URLSearchParams(globalThis.window.location.search),t=e.get(l),r=e.get(o);if(t&&r){let e=parseInt(r,10);return Number.isNaN(e)?null:{retryAttempt:e,retryId:t}}return null}catch{return null}},S=()=>{try{let e=new URL(globalThis.window.location.href);e.searchParams.delete(l),e.searchParams.delete(o),globalThis.window.history.replaceState(null,"",e.toString())}catch{}},I=()=>{if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint32Array(2);return crypto.getRandomValues(e),`${Date.now()}-${e[0].toString(36)}${e[1].toString(36)}`}return`${Date.now()}-${Math.random().toString(36).slice(2,15)}`},T=()=>{try{let e=new URL(globalThis.window.location.href);e.searchParams.delete(o),globalThis.window.history.replaceState(null,"",e.toString())}catch{}},_=()=>{let e=R();return e?{retryAttempt:e.retryAttempt,retryId:e.retryId}:{}},k=e=>{let t=u().errors?.ignore??[];return 0!==t.length&&e.filter(e=>"string"==typeof e).some(e=>t.some(t=>e.includes(t)))},N=e=>{let t=[...u().errors?.forceRetry??[],"__SPA_GUARD_FORCE_RETRY__"];return e.filter(e=>"string"==typeof e).some(e=>t.some(t=>e.includes(t)))},A=e=>{if((e=>k([e.errorMessage,e.eventMessage]))(e))return;let t=u();if(!t.reportBeacon?.endpoint)return void d()?.noBeaconEndpoint();let r=t.appName?{...e,appName:t.appName}:e,a=JSON.stringify(r);"function"==typeof globalThis.window?.navigator?.sendBeacon&&globalThis.window.navigator.sendBeacon(t.reportBeacon.endpoint,a)||fetch(t.reportBeacon.endpoint,{body:a,keepalive:!0,method:"POST"}).catch(e=>{d()?.beaconSendFailed(e)})},D=!1,U=e=>{if(D)return void d()?.reloadAlreadyScheduled(e);let t,r=u(),a=r.reloadDelays??[1e3,2e3,5e3],n=r.useRetryId??!0,i=r.enableRetryReset??!0,y=r.minTimeBetweenResets??5e3;if(n)t=R();else{let e=(()=>{try{let e=new URLSearchParams(globalThis.window.location.search).get(o);if(e){let t=parseInt(e,10);return Number.isNaN(t)?null:t}return null}catch{return null}})();t=null===e?null:{retryAttempt:e,retryId:I()}}let p=t?t.retryAttempt:0,m=t?.retryId??I();d()?.retryCycleStarting(m,p);let _=s.defaultRetryEnabled;if(c({error:e,isRetrying:_&&p>=0&&p<a.length,name:"chunk-error"}),!_)return;if(i&&t&&t.retryAttempt>0&&((e,t,r=5e3)=>{if(0===e.retryAttempt)return!1;let a=v();if(!a||a.retryId!==e.retryId)return!1;let n=(()=>{if(b())try{let e=sessionStorage.getItem(h);if(e)return JSON.parse(e)}catch{return w}return w})();return!(n&&Date.now()-n.timestamp<r)&&Date.now()-a.timestamp>(t[a.attemptNumber-1]??1e3)+3e4})(t,a,y)){let r=v(),a=r?Date.now()-r.timestamp:0;S(),(()=>{if(b())try{sessionStorage.removeItem(g)}catch{}f=null})(),(e=>{let t={previousRetryId:e,timestamp:Date.now()};if(b())try{sessionStorage.setItem(h,JSON.stringify(t))}catch{w=t}else w=t})(t.retryId);let n=e+"";c({name:"retry-reset",previousAttempt:t.retryAttempt,previousRetryId:t.retryId,timeSinceReload:a},{silent:k([n])}),p=0,m=I()}if(-1===p)return k([e+""])||d()?.fallbackAlreadyShown(e),void E();if(p>=a.length){let r=e+"";return c({finalAttempt:p,name:"retry-exhausted",retryId:t?.retryId??""},{silent:k([r])}),A({errorMessage:"Exceeded maximum reload attempts",eventName:"chunk_error_max_reloads",retryAttempt:p,retryId:t?.retryId,serialized:JSON.stringify({error:e+"",retryAttempt:p,retryId:t?.retryId})}),n||T(),void E()}let N=p+1,U=a[p]??1e3;c({attempt:N,delay:U,name:"retry-attempt",retryId:m},{silent:k([e+""])}),D=!0,d()?.retrySchedulingReload(m,N,U),setTimeout(()=>{if(n&&i&&((e,t)=>{let r={attemptNumber:t,retryId:e,timestamp:Date.now()};if(b())try{sessionStorage.setItem(g,JSON.stringify(r))}catch{f=r}else f=r})(m,N),n){let e=((e,t)=>{let r=new URL(globalThis.window.location.href);return r.searchParams.set(l,e),r.searchParams.set(o,t+""),r.toString()})(m,N);globalThis.window.location.href=e}else globalThis.window.location.href=(e=>{let t=new URL(globalThis.window.location.href);return t.searchParams.set(o,e+""),t.toString()})(N)},U)},E=()=>{let e=u(),t=e.html?.fallback?.content,r=e.html?.fallback?.selector??"body";if(t)try{let a=document.querySelector(r);if(!a)return void d()?.fallbackTargetNotFound(r);a.innerHTML=t;let n=e.useRetryId??!0,l=R();if(l&&-1===l.retryAttempt?(d()?.clearingRetryState(),S()):!n&&!l&&T(),l){let e=document.getElementsByClassName("spa-guard-retry-id");for(let t of e)t.textContent=l.retryId}c({name:"fallback-ui-shown"})}catch(e){d()?.fallbackInjectFailed(e)}else d()?.noFallbackConfigured()};(()=>{if(s.initialized)return;s.initialized=!0,void 0!==globalThis.window&&(globalThis.window[a]=!0);let e=u(),t=e.reloadDelays??[],r=R();r&&r.retryAttempt>=t.length&&(d()?.retryLimitExceeded(r.retryAttempt,t.length),(e=>{try{let t=new URL(globalThis.window.location.href);t.searchParams.set(l,e),t.searchParams.set(o,"-1"),globalThis.window.history.replaceState(null,"",t.toString())}catch{}})(r.retryId));let n=globalThis.window.addEventListener.bind(globalThis.window);n("error",e=>(k([e.message])||d()?.capturedError("error",e),y(e)||N([e.message])?(e.preventDefault(),void U(e.error??e)):void A({errorMessage:e.message,eventName:"error",serialized:"",..._()})),!0),n("unhandledrejection",t=>{let r=t.reason+"";if(k([r])||d()?.capturedError("unhandledrejection",t),y(t.reason))return t.preventDefault(),void U(t.reason);if(N([r]))return t.preventDefault(),void U(t.reason);let a=e.handleUnhandledRejections;!1!==a?.sendBeacon&&A({errorMessage:r,eventName:"unhandledrejection",serialized:"",..._()}),!1!==a?.retry&&(t.preventDefault(),U(t.reason))}),n("securitypolicyviolation",e=>{let t=`${e.violatedDirective}: ${e.blockedURI}`;k([t])||d()?.capturedError("csp",e.blockedURI,e.violatedDirective),A({eventMessage:t,eventName:"securitypolicyviolation",serialized:"",..._()})}),n("vite:preloadError",e=>{k([e?.payload?.message||e?.message])||d()?.capturedError("vite:preloadError",e),e.preventDefault(),U(e?.payload??e)})})();
1
+ var e="@ovineko/spa-guard",t=Symbol.for(e+":event-subscribers"),r=Symbol.for(e+":internal-config"),a=Symbol.for(e+":initialized"),n=Symbol.for(e+":logger"),l="spaGuardRetryId",o="spaGuardRetryAttempt";globalThis.window&&!globalThis.window[t]&&(globalThis.window[t]=new Set),globalThis.window&&!globalThis.window[r]&&(globalThis.window[r]={defaultRetryEnabled:!0,initialized:!1,inlineScriptLoaded:!1});var i=globalThis.window?.[t]??new Set,s=globalThis.window?.[r]??{defaultRetryEnabled:!0,initialized:!1,inlineScriptLoaded:!1},d=()=>globalThis.window?.[n],c=(e,t)=>{t?.silent||d()?.logEvent(e),i.forEach(t=>{try{t(e)}catch{}})},y=e=>{let t=p(e);return!!t&&[/Failed to fetch dynamically imported module/i,/Importing a module script failed/i,/error loading dynamically imported module/i,/Unable to preload CSS/i,/Loading chunk \d+ failed/i,/Loading CSS chunk \d+ failed/i,/ChunkLoadError/i].some(e=>e.test(t))},p=e=>e instanceof Error?e.message:"string"==typeof e?e:e&&"object"==typeof e&&"message"in e?e.message+"":e&&"object"==typeof e&&"reason"in e?p(e.reason):null,u={checkVersion:{interval:3e5,mode:"html",onUpdate:"reload"},enableRetryReset:!0,errors:{forceRetry:[],ignore:[]},handleUnhandledRejections:{retry:!0,sendBeacon:!0},html:{fallback:{content:'<style>.spa-guard-error-id:has(.spa-guard-retry-id:empty){display:none}</style><div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h1 data-spa-guard-content="heading">Something went wrong</h1><p data-spa-guard-content="message" style="max-width:600px;margin:1rem auto">Please refresh the page to continue.</p><div style="display:flex;gap:.5rem;justify-content:center"><button data-spa-guard-action="try-again" type="button" style="display:none">Try again</button> <button data-spa-guard-action="reload" type="button">Reload page</button></div><p class="spa-guard-error-id" style="margin-top:20px;font-size:12px">Error ID: <span class="spa-guard-retry-id"></span></p></div></div>',selector:"body"},loading:{content:'<div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h2>Loading...</h2><p data-spa-guard-section="retrying" style="display:none">Retry attempt <span data-spa-guard-content="attempt"></span></p></div></div>'}},lazyRetry:{callReloadOnFailure:!0,retryDelays:[1e3,2e3]},minTimeBetweenResets:5e3,reloadDelays:[1e3,2e3,5e3],useRetryId:!0},m=()=>{let e=globalThis.window?.__SPA_GUARD_OPTIONS__;return{...u,...e,checkVersion:{...u.checkVersion,...e?.checkVersion},errors:{...u.errors,...e?.errors},handleUnhandledRejections:{...u.handleUnhandledRejections,...e?.handleUnhandledRejections},html:{fallback:{...u.html?.fallback,...e?.html?.fallback},loading:{...u.html?.loading,...e?.html?.loading}},lazyRetry:{...u.lazyRetry,...e?.lazyRetry},reportBeacon:{...u.reportBeacon,...e?.reportBeacon}}},g="__spa_guard_last_reload_timestamp__",h="__spa_guard_last_retry_reset__",f=null,w=null,b=()=>{try{return void 0!==globalThis.window&&typeof sessionStorage<"u"}catch{return!1}},v=()=>{if(b())try{let e=sessionStorage.getItem(g);if(e)return JSON.parse(e)}catch{return f}return f},S=()=>{try{let e=new URLSearchParams(globalThis.window.location.search),t=e.get(l),r=e.get(o);if(t&&r){let e=parseInt(r,10);return Number.isNaN(e)?null:{retryAttempt:e,retryId:t}}return null}catch{return null}},R=()=>{try{let e=new URL(globalThis.window.location.href);e.searchParams.delete(l),e.searchParams.delete(o),globalThis.window.history.replaceState(null,"",e.toString())}catch{}},I=()=>{if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint32Array(2);return crypto.getRandomValues(e),`${Date.now()}-${e[0].toString(36)}${e[1].toString(36)}`}return`${Date.now()}-${Math.random().toString(36).slice(2,15)}`},T=()=>{try{let e=new URL(globalThis.window.location.href);e.searchParams.delete(o),globalThis.window.history.replaceState(null,"",e.toString())}catch{}},_=()=>{let e=S();return e?{retryAttempt:e.retryAttempt,retryId:e.retryId}:{}},k="__SPA_GUARD_FORCE_RETRY__",N=e=>{let t=(m().errors?.ignore??[]).filter(e=>""!==e);return 0!==t.length&&e.filter(e=>"string"==typeof e).some(e=>t.some(t=>e.includes(t)))},A=e=>{let t=[...m().errors?.forceRetry??[],k].filter(e=>""!==e);return e.filter(e=>"string"==typeof e).some(e=>t.some(t=>e.includes(t)))},D=e=>{if((e=>N([e.errorMessage,e.eventMessage]))(e))return;let t=m();if(!t.reportBeacon?.endpoint)return void d()?.noBeaconEndpoint();let r=t.appName?{...e,appName:t.appName}:e,a=JSON.stringify(r);"function"==typeof globalThis.window?.navigator?.sendBeacon&&globalThis.window.navigator.sendBeacon(t.reportBeacon.endpoint,a)||fetch(t.reportBeacon.endpoint,{body:a,keepalive:!0,method:"POST"}).catch(e=>{d()?.beaconSendFailed(e)})},U=!1,E=e=>{if(U)return void d()?.reloadAlreadyScheduled(e);let t,r=m(),a=r.reloadDelays??[1e3,2e3,5e3],n=r.useRetryId??!0,i=r.enableRetryReset??!0,y=r.minTimeBetweenResets??5e3;if(n)t=S();else{let e=(()=>{try{let e=new URLSearchParams(globalThis.window.location.search).get(o);if(e){let t=parseInt(e,10);return Number.isNaN(t)?null:t}return null}catch{return null}})();t=null===e?null:{retryAttempt:e,retryId:I()}}let p=t?t.retryAttempt:0,u=t?.retryId??I();d()?.retryCycleStarting(u,p);let _=s.defaultRetryEnabled;if(c({error:e,isRetrying:_&&p>=0&&p<a.length,name:"chunk-error"}),!_)return;if(i&&t&&t.retryAttempt>0&&((e,t,r=5e3)=>{if(0===e.retryAttempt)return!1;let a=v();if(!a||a.retryId!==e.retryId)return!1;let n=(()=>{if(b())try{let e=sessionStorage.getItem(h);if(e)return JSON.parse(e)}catch{return w}return w})();return!(n&&Date.now()-n.timestamp<r)&&Date.now()-a.timestamp>(t[a.attemptNumber-1]??1e3)+3e4})(t,a,y)){let r=v(),a=r?Date.now()-r.timestamp:0;R(),(()=>{if(b())try{sessionStorage.removeItem(g)}catch{}f=null})(),(e=>{let t={previousRetryId:e,timestamp:Date.now()};if(b())try{sessionStorage.setItem(h,JSON.stringify(t))}catch{w=t}else w=t})(t.retryId);let n=e+"";c({name:"retry-reset",previousAttempt:t.retryAttempt,previousRetryId:t.retryId,timeSinceReload:a},{silent:N([n])}),p=0,u=I()}if(-1===p)return N([e+""])||d()?.fallbackAlreadyShown(e),void L();if(p>=a.length){let r=e+"";return c({finalAttempt:p,name:"retry-exhausted",retryId:t?.retryId??""},{silent:N([r])}),D({errorMessage:"Exceeded maximum reload attempts",eventName:"chunk_error_max_reloads",retryAttempt:p,retryId:t?.retryId,serialized:JSON.stringify({error:e+"",retryAttempt:p,retryId:t?.retryId})}),n||T(),void L()}let k=p+1,A=a[p]??1e3;c({attempt:k,delay:A,name:"retry-attempt",retryId:u},{silent:N([e+""])}),U=!0,d()?.retrySchedulingReload(u,k,A),setTimeout(()=>{if(n&&i&&((e,t)=>{let r={attemptNumber:t,retryId:e,timestamp:Date.now()};if(b())try{sessionStorage.setItem(g,JSON.stringify(r))}catch{f=r}else f=r})(u,k),n){let e=((e,t)=>{let r=new URL(globalThis.window.location.href);return r.searchParams.set(l,e),r.searchParams.set(o,t+""),r.toString()})(u,k);globalThis.window.location.href=e}else globalThis.window.location.href=(e=>{let t=new URL(globalThis.window.location.href);return t.searchParams.set(o,e+""),t.toString()})(k)},A)},L=()=>{let e=m(),t=e.html?.fallback?.content,r=e.html?.fallback?.selector??"body";if(t)try{let a=document.querySelector(r);if(!a)return void d()?.fallbackTargetNotFound(r);a.innerHTML=t;let n=e.useRetryId??!0,l=S();l&&-1===l.retryAttempt?(d()?.clearingRetryState(),R()):!n&&!l&&T();let o=a.querySelector('[data-spa-guard-action="reload"]');if(o&&o.addEventListener("click",()=>location.reload()),l){let e=document.getElementsByClassName("spa-guard-retry-id");for(let t of e)t.textContent=l.retryId}c({name:"fallback-ui-shown"})}catch(e){d()?.fallbackInjectFailed(e)}else d()?.noFallbackConfigured()};(()=>{if(s.initialized)return;s.initialized=!0,void 0!==globalThis.window&&(globalThis.window[a]=!0);let e=m(),t=e.reloadDelays??[],r=S();r&&r.retryAttempt>=t.length&&(d()?.retryLimitExceeded(r.retryAttempt,t.length),(e=>{try{let t=new URL(globalThis.window.location.href);t.searchParams.set(l,e),t.searchParams.set(o,"-1"),globalThis.window.history.replaceState(null,"",t.toString())}catch{}})(r.retryId));let n=globalThis.window.addEventListener.bind(globalThis.window);n("error",e=>{if(!N([e.message]))return d()?.capturedError("error",e),y(e)||A([e.message])?(e.preventDefault(),void E(e.error??e)):void D({errorMessage:e.message,eventName:"error",serialized:"",..._()})},!0),n("unhandledrejection",t=>{let r=t.reason+"";if(N([r]))return;if(d()?.capturedError("unhandledrejection",t),y(t.reason))return t.preventDefault(),void E(t.reason);if(A([r]))return t.preventDefault(),void E(t.reason);let a=e.handleUnhandledRejections;!1!==a?.sendBeacon&&D({errorMessage:r,eventName:"unhandledrejection",serialized:"",..._()}),!1!==a?.retry&&(t.preventDefault(),E(t.reason))}),n("securitypolicyviolation",e=>{let t=`${e.violatedDirective}: ${e.blockedURI}`;N([t])||(d()?.capturedError("csp",e.blockedURI,e.violatedDirective),D({eventMessage:t,eventName:"securitypolicyviolation",serialized:"",..._()}))}),n("vite:preloadError",e=>{N([e?.payload?.message||e?.message])||(d()?.capturedError("vite:preloadError",e),e.preventDefault(),E(e?.payload??e))})})();
@@ -1 +1 @@
1
- var e="@ovineko/spa-guard",t=Symbol.for(e+":event-subscribers"),r=Symbol.for(e+":internal-config"),a=Symbol.for(e+":initialized"),n=Symbol.for(e+":logger"),o="spaGuardRetryId",l="spaGuardRetryAttempt";globalThis.window&&!globalThis.window[t]&&(globalThis.window[t]=new Set),globalThis.window&&!globalThis.window[r]&&(globalThis.window[r]={defaultRetryEnabled:!0,initialized:!1,inlineScriptLoaded:!1});var i=globalThis.window?.[t]??new Set,s=globalThis.window?.[r]??{defaultRetryEnabled:!0,initialized:!1,inlineScriptLoaded:!1},d=()=>globalThis.window?.[n],c=(e,t)=>{t?.silent||d()?.logEvent(e),i.forEach(t=>{try{t(e)}catch{}})},y=e=>{let t=u(e);return!!t&&[/Failed to fetch dynamically imported module/i,/Importing a module script failed/i,/error loading dynamically imported module/i,/Unable to preload CSS/i,/Loading chunk \d+ failed/i,/Loading CSS chunk \d+ failed/i,/ChunkLoadError/i].some(e=>e.test(t))},u=e=>e instanceof Error?e.message:"string"==typeof e?e:e&&"object"==typeof e&&"message"in e?e.message+"":e&&"object"==typeof e&&"reason"in e?u(e.reason):null,m={checkVersion:{interval:3e5,mode:"html",onUpdate:"reload"},enableRetryReset:!0,errors:{forceRetry:[],ignore:[]},handleUnhandledRejections:{retry:!0,sendBeacon:!0},html:{fallback:{content:'<style>.spa-guard-error-id:has(.spa-guard-retry-id:empty){display:none}</style><div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h1 data-spa-guard-content="heading">Something went wrong</h1><p data-spa-guard-content="message" style="max-width:600px;margin:1rem auto">Please refresh the page to continue.</p><div style="display:flex;gap:.5rem;justify-content:center"><button data-spa-guard-action="try-again" type="button" style="display:none">Try again</button> <button data-spa-guard-action="reload" type="button" onclick="location.reload()">Reload page</button></div><p class="spa-guard-error-id" style="margin-top:20px;font-size:12px">Error ID: <span class="spa-guard-retry-id"></span></p></div></div>',selector:"body"},loading:{content:'<div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h2>Loading...</h2><p data-spa-guard-section="retrying" style="display:none">Retry attempt <span data-spa-guard-content="attempt"></span></p></div></div>'}},lazyRetry:{callReloadOnFailure:!0,retryDelays:[1e3,2e3]},minTimeBetweenResets:5e3,reloadDelays:[1e3,2e3,5e3],useRetryId:!0},p=()=>{let e=globalThis.window?.__SPA_GUARD_OPTIONS__;return{...m,...e,checkVersion:{...m.checkVersion,...e?.checkVersion},errors:{...m.errors,...e?.errors},handleUnhandledRejections:{...m.handleUnhandledRejections,...e?.handleUnhandledRejections},html:{fallback:{...m.html?.fallback,...e?.html?.fallback},loading:{...m.html?.loading,...e?.html?.loading}},lazyRetry:{...m.lazyRetry,...e?.lazyRetry},reportBeacon:{...m.reportBeacon,...e?.reportBeacon}}},g="__spa_guard_last_reload_timestamp__",h="__spa_guard_last_retry_reset__",f=null,w=null,b=()=>{try{return void 0!==globalThis.window&&typeof sessionStorage<"u"}catch{return!1}},v=()=>{if(b())try{let e=sessionStorage.getItem(g);if(e)return JSON.parse(e)}catch{return f}return f},k=()=>{try{let e=new URLSearchParams(globalThis.window.location.search),t=e.get(o),r=e.get(l);if(t&&r){let e=parseInt(r,10);return Number.isNaN(e)?null:{retryAttempt:e,retryId:t}}return null}catch{return null}},R=()=>{try{let e=new URL(globalThis.window.location.href);e.searchParams.delete(o),e.searchParams.delete(l),globalThis.window.history.replaceState(null,"",e.toString())}catch{}},S=()=>{if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint32Array(2);return crypto.getRandomValues(e),`${Date.now()}-${e[0].toString(36)}${e[1].toString(36)}`}return`${Date.now()}-${Math.random().toString(36).slice(2,15)}`},$=()=>{try{let e=new URL(globalThis.window.location.href);e.searchParams.delete(l),globalThis.window.history.replaceState(null,"",e.toString())}catch{}},I=()=>{let e=k();return e?{retryAttempt:e.retryAttempt,retryId:e.retryId}:{}},T=e=>{let t=p().errors?.ignore??[];return 0!==t.length&&e.filter(e=>"string"==typeof e).some(e=>t.some(t=>e.includes(t)))},N=e=>{let t=[...p().errors?.forceRetry??[],"__SPA_GUARD_FORCE_RETRY__"];return e.filter(e=>"string"==typeof e).some(e=>t.some(t=>e.includes(t)))},E=e=>{if((e=>T([e.errorMessage,e.eventMessage]))(e))return;let t=p();if(!t.reportBeacon?.endpoint)return void d()?.noBeaconEndpoint();let r=t.appName?{...e,appName:t.appName}:e,a=JSON.stringify(r);"function"==typeof globalThis.window?.navigator?.sendBeacon&&globalThis.window.navigator.sendBeacon(t.reportBeacon.endpoint,a)||fetch(t.reportBeacon.endpoint,{body:a,keepalive:!0,method:"POST"}).catch(e=>{d()?.beaconSendFailed(e)})},U=!1,A=e=>{if(U)return void d()?.reloadAlreadyScheduled(e);let t,r=p(),a=r.reloadDelays??[1e3,2e3,5e3],n=r.useRetryId??!0,i=r.enableRetryReset??!0,y=r.minTimeBetweenResets??5e3;if(n)t=k();else{let e=(()=>{try{let e=new URLSearchParams(globalThis.window.location.search).get(l);if(e){let t=parseInt(e,10);return Number.isNaN(t)?null:t}return null}catch{return null}})();t=null===e?null:{retryAttempt:e,retryId:S()}}let u=t?t.retryAttempt:0,m=t?.retryId??S();d()?.retryCycleStarting(m,u);let I=s.defaultRetryEnabled;if(c({error:e,isRetrying:I&&u>=0&&u<a.length,name:"chunk-error"}),!I)return;if(i&&t&&t.retryAttempt>0&&((e,t,r=5e3)=>{if(0===e.retryAttempt)return!1;let a=v();if(!a||a.retryId!==e.retryId)return!1;let n=(()=>{if(b())try{let e=sessionStorage.getItem(h);if(e)return JSON.parse(e)}catch{return w}return w})();return!(n&&Date.now()-n.timestamp<r)&&Date.now()-a.timestamp>(t[a.attemptNumber-1]??1e3)+3e4})(t,a,y)){let r=v(),a=r?Date.now()-r.timestamp:0;R(),(()=>{if(b())try{sessionStorage.removeItem(g)}catch{}f=null})(),(e=>{let t={previousRetryId:e,timestamp:Date.now()};if(b())try{sessionStorage.setItem(h,JSON.stringify(t))}catch{w=t}else w=t})(t.retryId);let n=e+"";c({name:"retry-reset",previousAttempt:t.retryAttempt,previousRetryId:t.retryId,timeSinceReload:a},{silent:T([n])}),u=0,m=S()}if(-1===u)return T([e+""])||d()?.fallbackAlreadyShown(e),void _();if(u>=a.length){let r=e+"";return c({finalAttempt:u,name:"retry-exhausted",retryId:t?.retryId??""},{silent:T([r])}),E({errorMessage:"Exceeded maximum reload attempts",eventName:"chunk_error_max_reloads",retryAttempt:u,retryId:t?.retryId,serialized:JSON.stringify({error:e+"",retryAttempt:u,retryId:t?.retryId})}),n||$(),void _()}let N=u+1,A=a[u]??1e3;c({attempt:N,delay:A,name:"retry-attempt",retryId:m},{silent:T([e+""])}),U=!0,d()?.retrySchedulingReload(m,N,A),setTimeout(()=>{if(n&&i&&((e,t)=>{let r={attemptNumber:t,retryId:e,timestamp:Date.now()};if(b())try{sessionStorage.setItem(g,JSON.stringify(r))}catch{f=r}else f=r})(m,N),n){let e=((e,t)=>{let r=new URL(globalThis.window.location.href);return r.searchParams.set(o,e),r.searchParams.set(l,t+""),r.toString()})(m,N);globalThis.window.location.href=e}else globalThis.window.location.href=(e=>{let t=new URL(globalThis.window.location.href);return t.searchParams.set(l,e+""),t.toString()})(N)},A)},_=()=>{let e=p(),t=e.html?.fallback?.content,r=e.html?.fallback?.selector??"body";if(t)try{let a=document.querySelector(r);if(!a)return void d()?.fallbackTargetNotFound(r);a.innerHTML=t;let n=e.useRetryId??!0,o=k();if(o&&-1===o.retryAttempt?(d()?.clearingRetryState(),R()):!n&&!o&&$(),o){let e=document.getElementsByClassName("spa-guard-retry-id");for(let t of e)t.textContent=o.retryId}c({name:"fallback-ui-shown"})}catch(e){d()?.fallbackInjectFailed(e)}else d()?.noFallbackConfigured()},D="[spa-guard]",z={"chunk-error":"error","fallback-ui-shown":"warn","lazy-retry-attempt":"warn","lazy-retry-exhausted":"error","lazy-retry-success":"log","retry-attempt":"warn","retry-exhausted":"error","retry-reset":"log"},P=e=>{if(null==e)return{type:"null",value:e};if("object"!=typeof e)return{type:typeof e,value:e};if(e instanceof Error)return{message:e.message,name:e.name,stack:e.stack,type:"Error",...x(e)};if("reason"in e&&"promise"in e)return{reason:P(e.reason),type:"PromiseRejectionEvent"};if("error"in e&&"message"in e&&"filename"in e)return{colno:e.colno,error:P(e.error),filename:e.filename,lineno:e.lineno,message:e.message,type:"ErrorEvent"};if("violatedDirective"in e&&"blockedURI"in e){let t=e;return{blockedURI:t.blockedURI,columnNumber:t.columnNumber,effectiveDirective:t.effectiveDirective,lineNumber:t.lineNumber,originalPolicy:t.originalPolicy,sourceFile:t.sourceFile,type:"SecurityPolicyViolationEvent",violatedDirective:t.violatedDirective}}if("type"in e&&"target"in e){let t=e;return{eventType:t.type,target:C(t.target),timeStamp:t.timeStamp,type:"Event"}}return{type:"object",value:j(e)}},x=e=>{let t={};for(let r of Object.getOwnPropertyNames(e))if(!["message","name","stack"].includes(r))try{t[r]=e[r]}catch{}return t},C=e=>e?e instanceof HTMLElement?{className:e.className,href:e.href,id:e.id,src:e.src,tagName:e.tagName}:{type:e+""}:null,j=e=>{let t={};for(let r of Object.keys(e))try{let a=e[r];t[r]="object"==typeof a?a+"":a}catch{}return t};((e,t)=>{if(t&&(e=>{void 0!==globalThis.window&&(globalThis.window[n]=e)})(t),s.initialized)return;s.initialized=!0,void 0!==globalThis.window&&(globalThis.window[a]=!0);let r=p(),i=r.reloadDelays??[],c=k();c&&c.retryAttempt>=i.length&&(d()?.retryLimitExceeded(c.retryAttempt,i.length),(e=>{try{let t=new URL(globalThis.window.location.href);t.searchParams.set(o,e),t.searchParams.set(l,"-1"),globalThis.window.history.replaceState(null,"",t.toString())}catch{}})(c.retryId));let u=globalThis.window.addEventListener.bind(globalThis.window);u("error",t=>{if(T([t.message])||d()?.capturedError("error",t),y(t))return t.preventDefault(),void A(t.error??t);if(N([t.message]))return t.preventDefault(),void A(t.error??t);let r=e(t);E({errorMessage:t.message,eventName:"error",serialized:r,...I()})},!0),u("unhandledrejection",t=>{let a=t.reason+"";if(T([a])||d()?.capturedError("unhandledrejection",t),y(t.reason))return t.preventDefault(),void A(t.reason);if(N([a]))return t.preventDefault(),void A(t.reason);let n=r.handleUnhandledRejections;if(!1!==n?.sendBeacon){let r=e(t);E({errorMessage:a,eventName:"unhandledrejection",serialized:r,...I()})}!1!==n?.retry&&(t.preventDefault(),A(t.reason))}),u("securitypolicyviolation",t=>{let r=`${t.violatedDirective}: ${t.blockedURI}`;T([r])||d()?.capturedError("csp",t.blockedURI,t.violatedDirective);let a=e(t);E({eventMessage:r,eventName:"securitypolicyviolation",serialized:a,...I()})}),u("vite:preloadError",e=>{T([e?.payload?.message||e?.message])||d()?.capturedError("vite:preloadError",e),e.preventDefault(),A(e?.payload??e)})})(e=>{try{let t=P(e);return JSON.stringify(t,null,2)}catch{return JSON.stringify({error:"Failed to serialize error",fallback:e+""})}},{beaconSendFailed(e){console.error(D+" Failed to send beacon:",e)},capturedError(e,...t){console.error(`${D} ${e}:capture:`,...t)},clearingRetryState(){console.log(D+" Clearing retry state from URL to allow clean reload attempt")},error(e,...t){console.error(`${D} ${e}`,...t)},fallbackAlreadyShown(e){console.error(D+" Fallback UI was already shown. Not retrying to prevent infinite loop.",e)},fallbackInjectFailed(e){console.error(D+" Failed to inject fallback UI",e)},fallbackTargetNotFound(e){console.error(`${D} Target element not found for selector: ${e}`)},log(e,...t){console.log(`${D} ${e}`,...t)},logEvent(e){let t=z[e.name],r=(e=>{switch(e.name){case"chunk-error":return`${D} chunk-error: isRetrying=${e.isRetrying}`;case"fallback-ui-shown":return D+" fallback-ui-shown";case"lazy-retry-attempt":return`${D} lazy-retry-attempt: attempt ${e.attempt}/${e.totalAttempts}, delay ${e.delay}ms`;case"lazy-retry-exhausted":return`${D} lazy-retry-exhausted: ${e.totalAttempts} attempts, willReload=${e.willReload}`;case"lazy-retry-success":return`${D} lazy-retry-success: succeeded on attempt ${e.attempt}`;case"retry-attempt":return`${D} retry-attempt: attempt ${e.attempt} in ${e.delay}ms (retryId: ${e.retryId})`;case"retry-exhausted":return`${D} retry-exhausted: finalAttempt=${e.finalAttempt} (retryId: ${e.retryId})`;case"retry-reset":return`${D} retry-reset: ${e.timeSinceReload}ms since last reload (retryId: ${e.previousRetryId})`}})(e);"chunk-error"===e.name?console[t](r,e.error):console[t](r)},noBeaconEndpoint(){console.warn(D+" Report endpoint is not configured")},noFallbackConfigured(){console.error(D+" No fallback UI configured")},reloadAlreadyScheduled(e){console.log(D+" Reload already scheduled, ignoring duplicate chunk error:",e)},retryCycleStarting(e,t){console.log(`${D} Retry cycle starting: retryId=${e}, fromAttempt=${t}`)},retryLimitExceeded(e,t){console.log(`${D} Retry limit exceeded (${e}/${t}), marking as fallback shown`)},retrySchedulingReload(e,t,r){console.log(`${D} Scheduling reload: retryId=${e}, attempt=${t}, delay=${r}ms`)},updatedRetryAttempt(e){console.log(`${D} Updated retry attempt to ${e} in URL for fallback UI`)},versionChangeDetected(e,t){console.warn(`${D} New version available (${e??"unknown"} → ${t}). Please refresh to get the latest version.`)},versionCheckAlreadyRunning(){console.warn(D+" Version check already running")},versionCheckDisabled(){console.warn(D+" Version checking disabled: no version configured")},versionCheckFailed(e){console.error(D+" Version check failed",e)},versionCheckHttpError(e){console.warn(`${D} Version check HTTP error: ${e}`)},versionCheckParseError(){console.warn(D+" Failed to parse version from HTML")},versionCheckPaused(){console.log(D+" Version check paused (tab hidden)")},versionCheckRequiresEndpoint(){console.warn(D+" JSON version check mode requires endpoint")},versionCheckResumed(){console.log(D+" Version check resumed (tab visible)")},versionCheckResumedImmediate(){console.log(D+" Version check resumed with immediate check (tab visible, interval elapsed)")},versionCheckStarted(e,t,r){console.log(`${D} Starting version check (mode: ${e}, interval: ${t}ms, current: ${r})`)},versionCheckStopped(){console.log(D+" Version check stopped")},warn(e,...t){console.warn(`${D} ${e}`,...t)}});
1
+ var e="@ovineko/spa-guard",t=Symbol.for(e+":event-subscribers"),r=Symbol.for(e+":internal-config"),a=Symbol.for(e+":initialized"),n=Symbol.for(e+":logger"),o="spaGuardRetryId",l="spaGuardRetryAttempt";globalThis.window&&!globalThis.window[t]&&(globalThis.window[t]=new Set),globalThis.window&&!globalThis.window[r]&&(globalThis.window[r]={defaultRetryEnabled:!0,initialized:!1,inlineScriptLoaded:!1});var i=globalThis.window?.[t]??new Set,s=globalThis.window?.[r]??{defaultRetryEnabled:!0,initialized:!1,inlineScriptLoaded:!1},d=()=>globalThis.window?.[n],c=(e,t)=>{t?.silent||d()?.logEvent(e),i.forEach(t=>{try{t(e)}catch{}})},y=e=>{let t=u(e);return!!t&&[/Failed to fetch dynamically imported module/i,/Importing a module script failed/i,/error loading dynamically imported module/i,/Unable to preload CSS/i,/Loading chunk \d+ failed/i,/Loading CSS chunk \d+ failed/i,/ChunkLoadError/i].some(e=>e.test(t))},u=e=>e instanceof Error?e.message:"string"==typeof e?e:e&&"object"==typeof e&&"message"in e?e.message+"":e&&"object"==typeof e&&"reason"in e?u(e.reason):null,m={checkVersion:{interval:3e5,mode:"html",onUpdate:"reload"},enableRetryReset:!0,errors:{forceRetry:[],ignore:[]},handleUnhandledRejections:{retry:!0,sendBeacon:!0},html:{fallback:{content:'<style>.spa-guard-error-id:has(.spa-guard-retry-id:empty){display:none}</style><div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h1 data-spa-guard-content="heading">Something went wrong</h1><p data-spa-guard-content="message" style="max-width:600px;margin:1rem auto">Please refresh the page to continue.</p><div style="display:flex;gap:.5rem;justify-content:center"><button data-spa-guard-action="try-again" type="button" style="display:none">Try again</button> <button data-spa-guard-action="reload" type="button">Reload page</button></div><p class="spa-guard-error-id" style="margin-top:20px;font-size:12px">Error ID: <span class="spa-guard-retry-id"></span></p></div></div>',selector:"body"},loading:{content:'<div style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem"><div style="text-align:center"><h2>Loading...</h2><p data-spa-guard-section="retrying" style="display:none">Retry attempt <span data-spa-guard-content="attempt"></span></p></div></div>'}},lazyRetry:{callReloadOnFailure:!0,retryDelays:[1e3,2e3]},minTimeBetweenResets:5e3,reloadDelays:[1e3,2e3,5e3],useRetryId:!0},p=()=>{let e=globalThis.window?.__SPA_GUARD_OPTIONS__;return{...m,...e,checkVersion:{...m.checkVersion,...e?.checkVersion},errors:{...m.errors,...e?.errors},handleUnhandledRejections:{...m.handleUnhandledRejections,...e?.handleUnhandledRejections},html:{fallback:{...m.html?.fallback,...e?.html?.fallback},loading:{...m.html?.loading,...e?.html?.loading}},lazyRetry:{...m.lazyRetry,...e?.lazyRetry},reportBeacon:{...m.reportBeacon,...e?.reportBeacon}}},g="__spa_guard_last_reload_timestamp__",h="__spa_guard_last_retry_reset__",f=null,w=null,b=()=>{try{return void 0!==globalThis.window&&typeof sessionStorage<"u"}catch{return!1}},v=()=>{if(b())try{let e=sessionStorage.getItem(g);if(e)return JSON.parse(e)}catch{return f}return f},k=()=>{try{let e=new URLSearchParams(globalThis.window.location.search),t=e.get(o),r=e.get(l);if(t&&r){let e=parseInt(r,10);return Number.isNaN(e)?null:{retryAttempt:e,retryId:t}}return null}catch{return null}},R=()=>{try{let e=new URL(globalThis.window.location.href);e.searchParams.delete(o),e.searchParams.delete(l),globalThis.window.history.replaceState(null,"",e.toString())}catch{}},S=()=>{if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint32Array(2);return crypto.getRandomValues(e),`${Date.now()}-${e[0].toString(36)}${e[1].toString(36)}`}return`${Date.now()}-${Math.random().toString(36).slice(2,15)}`},$=()=>{try{let e=new URL(globalThis.window.location.href);e.searchParams.delete(l),globalThis.window.history.replaceState(null,"",e.toString())}catch{}},I=()=>{let e=k();return e?{retryAttempt:e.retryAttempt,retryId:e.retryId}:{}},T="__SPA_GUARD_FORCE_RETRY__",N=e=>{let t=(p().errors?.ignore??[]).filter(e=>""!==e);return 0!==t.length&&e.filter(e=>"string"==typeof e).some(e=>t.some(t=>e.includes(t)))},E=e=>{let t=[...p().errors?.forceRetry??[],T].filter(e=>""!==e);return e.filter(e=>"string"==typeof e).some(e=>t.some(t=>e.includes(t)))},U=e=>{if((e=>N([e.errorMessage,e.eventMessage]))(e))return;let t=p();if(!t.reportBeacon?.endpoint)return void d()?.noBeaconEndpoint();let r=t.appName?{...e,appName:t.appName}:e,a=JSON.stringify(r);"function"==typeof globalThis.window?.navigator?.sendBeacon&&globalThis.window.navigator.sendBeacon(t.reportBeacon.endpoint,a)||fetch(t.reportBeacon.endpoint,{body:a,keepalive:!0,method:"POST"}).catch(e=>{d()?.beaconSendFailed(e)})},A=!1,_=e=>{if(A)return void d()?.reloadAlreadyScheduled(e);let t,r=p(),a=r.reloadDelays??[1e3,2e3,5e3],n=r.useRetryId??!0,i=r.enableRetryReset??!0,y=r.minTimeBetweenResets??5e3;if(n)t=k();else{let e=(()=>{try{let e=new URLSearchParams(globalThis.window.location.search).get(l);if(e){let t=parseInt(e,10);return Number.isNaN(t)?null:t}return null}catch{return null}})();t=null===e?null:{retryAttempt:e,retryId:S()}}let u=t?t.retryAttempt:0,m=t?.retryId??S();d()?.retryCycleStarting(m,u);let I=s.defaultRetryEnabled;if(c({error:e,isRetrying:I&&u>=0&&u<a.length,name:"chunk-error"}),!I)return;if(i&&t&&t.retryAttempt>0&&((e,t,r=5e3)=>{if(0===e.retryAttempt)return!1;let a=v();if(!a||a.retryId!==e.retryId)return!1;let n=(()=>{if(b())try{let e=sessionStorage.getItem(h);if(e)return JSON.parse(e)}catch{return w}return w})();return!(n&&Date.now()-n.timestamp<r)&&Date.now()-a.timestamp>(t[a.attemptNumber-1]??1e3)+3e4})(t,a,y)){let r=v(),a=r?Date.now()-r.timestamp:0;R(),(()=>{if(b())try{sessionStorage.removeItem(g)}catch{}f=null})(),(e=>{let t={previousRetryId:e,timestamp:Date.now()};if(b())try{sessionStorage.setItem(h,JSON.stringify(t))}catch{w=t}else w=t})(t.retryId);let n=e+"";c({name:"retry-reset",previousAttempt:t.retryAttempt,previousRetryId:t.retryId,timeSinceReload:a},{silent:N([n])}),u=0,m=S()}if(-1===u)return N([e+""])||d()?.fallbackAlreadyShown(e),void D();if(u>=a.length){let r=e+"";return c({finalAttempt:u,name:"retry-exhausted",retryId:t?.retryId??""},{silent:N([r])}),U({errorMessage:"Exceeded maximum reload attempts",eventName:"chunk_error_max_reloads",retryAttempt:u,retryId:t?.retryId,serialized:JSON.stringify({error:e+"",retryAttempt:u,retryId:t?.retryId})}),n||$(),void D()}let T=u+1,E=a[u]??1e3;c({attempt:T,delay:E,name:"retry-attempt",retryId:m},{silent:N([e+""])}),A=!0,d()?.retrySchedulingReload(m,T,E),setTimeout(()=>{if(n&&i&&((e,t)=>{let r={attemptNumber:t,retryId:e,timestamp:Date.now()};if(b())try{sessionStorage.setItem(g,JSON.stringify(r))}catch{f=r}else f=r})(m,T),n){let e=((e,t)=>{let r=new URL(globalThis.window.location.href);return r.searchParams.set(o,e),r.searchParams.set(l,t+""),r.toString()})(m,T);globalThis.window.location.href=e}else globalThis.window.location.href=(e=>{let t=new URL(globalThis.window.location.href);return t.searchParams.set(l,e+""),t.toString()})(T)},E)},D=()=>{let e=p(),t=e.html?.fallback?.content,r=e.html?.fallback?.selector??"body";if(t)try{let a=document.querySelector(r);if(!a)return void d()?.fallbackTargetNotFound(r);a.innerHTML=t;let n=e.useRetryId??!0,o=k();o&&-1===o.retryAttempt?(d()?.clearingRetryState(),R()):!n&&!o&&$();let l=a.querySelector('[data-spa-guard-action="reload"]');if(l&&l.addEventListener("click",()=>location.reload()),o){let e=document.getElementsByClassName("spa-guard-retry-id");for(let t of e)t.textContent=o.retryId}c({name:"fallback-ui-shown"})}catch(e){d()?.fallbackInjectFailed(e)}else d()?.noFallbackConfigured()},z="[spa-guard]",P={"chunk-error":"error","fallback-ui-shown":"warn","lazy-retry-attempt":"warn","lazy-retry-exhausted":"error","lazy-retry-success":"log","retry-attempt":"warn","retry-exhausted":"error","retry-reset":"log"},x=e=>{if(null==e)return{type:"null",value:e};if("object"!=typeof e)return{type:typeof e,value:e};if(e instanceof Error)return{message:e.message,name:e.name,stack:e.stack,type:"Error",...C(e)};if("reason"in e&&"promise"in e)return{reason:x(e.reason),type:"PromiseRejectionEvent"};if("error"in e&&"message"in e&&"filename"in e)return{colno:e.colno,error:x(e.error),filename:e.filename,lineno:e.lineno,message:e.message,type:"ErrorEvent"};if("violatedDirective"in e&&"blockedURI"in e){let t=e;return{blockedURI:t.blockedURI,columnNumber:t.columnNumber,effectiveDirective:t.effectiveDirective,lineNumber:t.lineNumber,originalPolicy:t.originalPolicy,sourceFile:t.sourceFile,type:"SecurityPolicyViolationEvent",violatedDirective:t.violatedDirective}}if("type"in e&&"target"in e){let t=e;return{eventType:t.type,target:j(t.target),timeStamp:t.timeStamp,type:"Event"}}return{type:"object",value:L(e)}},C=e=>{let t={};for(let r of Object.getOwnPropertyNames(e))if(!["message","name","stack"].includes(r))try{t[r]=e[r]}catch{}return t},j=e=>e?e instanceof HTMLElement?{className:e.className,href:e.href,id:e.id,src:e.src,tagName:e.tagName}:{type:e+""}:null,L=e=>{let t={};for(let r of Object.keys(e))try{let a=e[r];t[r]="object"==typeof a?a+"":a}catch{}return t};((e,t)=>{if(t&&(e=>{void 0!==globalThis.window&&(globalThis.window[n]=e)})(t),s.initialized)return;s.initialized=!0,void 0!==globalThis.window&&(globalThis.window[a]=!0);let r=p(),i=r.reloadDelays??[],c=k();c&&c.retryAttempt>=i.length&&(d()?.retryLimitExceeded(c.retryAttempt,i.length),(e=>{try{let t=new URL(globalThis.window.location.href);t.searchParams.set(o,e),t.searchParams.set(l,"-1"),globalThis.window.history.replaceState(null,"",t.toString())}catch{}})(c.retryId));let u=globalThis.window.addEventListener.bind(globalThis.window);u("error",t=>{if(N([t.message]))return;if(d()?.capturedError("error",t),y(t))return t.preventDefault(),void _(t.error??t);if(E([t.message]))return t.preventDefault(),void _(t.error??t);let r=e(t);U({errorMessage:t.message,eventName:"error",serialized:r,...I()})},!0),u("unhandledrejection",t=>{let a=t.reason+"";if(N([a]))return;if(d()?.capturedError("unhandledrejection",t),y(t.reason))return t.preventDefault(),void _(t.reason);if(E([a]))return t.preventDefault(),void _(t.reason);let n=r.handleUnhandledRejections;if(!1!==n?.sendBeacon){let r=e(t);U({errorMessage:a,eventName:"unhandledrejection",serialized:r,...I()})}!1!==n?.retry&&(t.preventDefault(),_(t.reason))}),u("securitypolicyviolation",t=>{let r=`${t.violatedDirective}: ${t.blockedURI}`;if(N([r]))return;d()?.capturedError("csp",t.blockedURI,t.violatedDirective);let a=e(t);U({eventMessage:r,eventName:"securitypolicyviolation",serialized:a,...I()})}),u("vite:preloadError",e=>{N([e?.payload?.message||e?.message])||(d()?.capturedError("vite:preloadError",e),e.preventDefault(),_(e?.payload??e))})})(e=>{try{let t=x(e);return JSON.stringify(t,null,2)}catch{return JSON.stringify({error:"Failed to serialize error",fallback:e+""})}},{beaconSendFailed(e){console.error(z+" Failed to send beacon:",e)},capturedError(e,...t){console.error(`${z} ${e}:capture:`,...t)},clearingRetryState(){console.log(z+" Clearing retry state from URL to allow clean reload attempt")},error(e,...t){console.error(`${z} ${e}`,...t)},fallbackAlreadyShown(e){console.error(z+" Fallback UI was already shown. Not retrying to prevent infinite loop.",e)},fallbackInjectFailed(e){console.error(z+" Failed to inject fallback UI",e)},fallbackTargetNotFound(e){console.error(`${z} Target element not found for selector: ${e}`)},log(e,...t){console.log(`${z} ${e}`,...t)},logEvent(e){let t=P[e.name],r=(e=>{switch(e.name){case"chunk-error":return`${z} chunk-error: isRetrying=${e.isRetrying}`;case"fallback-ui-shown":return z+" fallback-ui-shown";case"lazy-retry-attempt":return`${z} lazy-retry-attempt: attempt ${e.attempt}/${e.totalAttempts}, delay ${e.delay}ms`;case"lazy-retry-exhausted":return`${z} lazy-retry-exhausted: ${e.totalAttempts} attempts, willReload=${e.willReload}`;case"lazy-retry-success":return`${z} lazy-retry-success: succeeded on attempt ${e.attempt}`;case"retry-attempt":return`${z} retry-attempt: attempt ${e.attempt} in ${e.delay}ms (retryId: ${e.retryId})`;case"retry-exhausted":return`${z} retry-exhausted: finalAttempt=${e.finalAttempt} (retryId: ${e.retryId})`;case"retry-reset":return`${z} retry-reset: ${e.timeSinceReload}ms since last reload (retryId: ${e.previousRetryId})`}})(e);"chunk-error"===e.name?console[t](r,e.error):console[t](r)},noBeaconEndpoint(){console.warn(z+" Report endpoint is not configured")},noFallbackConfigured(){console.error(z+" No fallback UI configured")},reloadAlreadyScheduled(e){console.log(z+" Reload already scheduled, ignoring duplicate chunk error:",e)},retryCycleStarting(e,t){console.log(`${z} Retry cycle starting: retryId=${e}, fromAttempt=${t}`)},retryLimitExceeded(e,t){console.log(`${z} Retry limit exceeded (${e}/${t}), marking as fallback shown`)},retrySchedulingReload(e,t,r){console.log(`${z} Scheduling reload: retryId=${e}, attempt=${t}, delay=${r}ms`)},updatedRetryAttempt(e){console.log(`${z} Updated retry attempt to ${e} in URL for fallback UI`)},versionChangeDetected(e,t){console.warn(`${z} New version available (${e??"unknown"} → ${t}). Please refresh to get the latest version.`)},versionCheckAlreadyRunning(){console.warn(z+" Version check already running")},versionCheckDisabled(){console.warn(z+" Version checking disabled: no version configured")},versionCheckFailed(e){console.error(z+" Version check failed",e)},versionCheckHttpError(e){console.warn(`${z} Version check HTTP error: ${e}`)},versionCheckParseError(){console.warn(z+" Failed to parse version from HTML")},versionCheckPaused(){console.log(z+" Version check paused (tab hidden)")},versionCheckRequiresEndpoint(){console.warn(z+" JSON version check mode requires endpoint")},versionCheckResumed(){console.log(z+" Version check resumed (tab visible)")},versionCheckResumedImmediate(){console.log(z+" Version check resumed with immediate check (tab visible, interval elapsed)")},versionCheckStarted(e,t,r){console.log(`${z} Starting version check (mode: ${e}, interval: ${t}ms, current: ${r})`)},versionCheckStopped(){console.log(z+" Version check stopped")},warn(e,...t){console.warn(`${z} ${e}`,...t)}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ovineko/spa-guard",
3
- "version": "0.0.1-alpha-5",
3
+ "version": "0.0.1-alpha-6",
4
4
  "description": "Chunk load error handling for SPAs with automatic recovery, beacon reporting, and deployment monitoring",
5
5
  "keywords": [
6
6
  "spa",