heliumts 0.7.4 → 0.7.5
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staleRecovery.d.ts","sourceRoot":"","sources":["../../src/client/staleRecovery.ts"],"names":[],"mappings":"AAeA,KAAK,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC,CAAC;AAEvE,KAAK,iCAAiC,GAAG;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC1B,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;
|
|
1
|
+
{"version":3,"file":"staleRecovery.d.ts","sourceRoot":"","sources":["../../src/client/staleRecovery.ts"],"names":[],"mappings":"AAeA,KAAK,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC,CAAC;AAEvE,KAAK,iCAAiC,GAAG;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC1B,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AA2EF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAWzD;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,iCAAsC,GAAG,IAAI,CA+HhG"}
|
|
@@ -10,6 +10,17 @@ const CHUNK_ERROR_PATTERNS = [
|
|
|
10
10
|
/Importing a module script failed/i,
|
|
11
11
|
/dynamically imported module/i,
|
|
12
12
|
];
|
|
13
|
+
function resolveStorage(windowObject, override) {
|
|
14
|
+
if (override !== undefined) {
|
|
15
|
+
return override;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
return windowObject.sessionStorage;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
13
24
|
function readStoredNumber(storage, key) {
|
|
14
25
|
if (!storage) {
|
|
15
26
|
return null;
|
|
@@ -90,12 +101,14 @@ export function installStaleClientRecovery(options = {}) {
|
|
|
90
101
|
}
|
|
91
102
|
trackedWindow[INSTALL_FLAG] = true;
|
|
92
103
|
const now = options.now ?? (() => Date.now());
|
|
93
|
-
const storage = options.storage
|
|
104
|
+
const storage = resolveStorage(windowObject, options.storage);
|
|
94
105
|
const staleThresholdMs = options.staleThresholdMs ?? STALE_RESUME_THRESHOLD_MS;
|
|
95
106
|
const reloadCooldownMs = options.reloadCooldownMs ?? RELOAD_COOLDOWN_MS;
|
|
96
107
|
const reload = options.reload ?? (() => windowObject.location.reload());
|
|
97
108
|
let isReloading = false;
|
|
109
|
+
let hasPendingReload = false;
|
|
98
110
|
let hiddenAt = readStoredNumber(storage, HIDDEN_AT_STORAGE_KEY);
|
|
111
|
+
const isVisible = () => !documentObject.hidden;
|
|
99
112
|
const markHidden = () => {
|
|
100
113
|
hiddenAt = now();
|
|
101
114
|
writeStoredNumber(storage, HIDDEN_AT_STORAGE_KEY, hiddenAt);
|
|
@@ -104,7 +117,11 @@ export function installStaleClientRecovery(options = {}) {
|
|
|
104
117
|
hiddenAt = null;
|
|
105
118
|
writeStoredNumber(storage, HIDDEN_AT_STORAGE_KEY, null);
|
|
106
119
|
};
|
|
107
|
-
const
|
|
120
|
+
const executeReload = () => {
|
|
121
|
+
if (!isVisible()) {
|
|
122
|
+
hasPendingReload = true;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
108
125
|
if (isReloading) {
|
|
109
126
|
return;
|
|
110
127
|
}
|
|
@@ -114,9 +131,19 @@ export function installStaleClientRecovery(options = {}) {
|
|
|
114
131
|
return;
|
|
115
132
|
}
|
|
116
133
|
isReloading = true;
|
|
134
|
+
hasPendingReload = false;
|
|
117
135
|
writeStoredNumber(storage, LAST_RELOAD_STORAGE_KEY, current);
|
|
118
136
|
reload();
|
|
119
137
|
};
|
|
138
|
+
const flushPendingReload = () => {
|
|
139
|
+
if (!hasPendingReload) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
executeReload();
|
|
143
|
+
};
|
|
144
|
+
const attemptReload = () => {
|
|
145
|
+
executeReload();
|
|
146
|
+
};
|
|
120
147
|
const maybeRecoverFromStaleResume = () => {
|
|
121
148
|
const hiddenTimestamp = hiddenAt ?? readStoredNumber(storage, HIDDEN_AT_STORAGE_KEY);
|
|
122
149
|
if (hiddenTimestamp === null) {
|
|
@@ -133,6 +160,7 @@ export function installStaleClientRecovery(options = {}) {
|
|
|
133
160
|
markHidden();
|
|
134
161
|
return;
|
|
135
162
|
}
|
|
163
|
+
flushPendingReload();
|
|
136
164
|
maybeRecoverFromStaleResume();
|
|
137
165
|
}, { passive: true });
|
|
138
166
|
windowObject.addEventListener("pagehide", () => {
|
|
@@ -140,6 +168,7 @@ export function installStaleClientRecovery(options = {}) {
|
|
|
140
168
|
}, { passive: true });
|
|
141
169
|
windowObject.addEventListener("pageshow", (event) => {
|
|
142
170
|
if (event.persisted) {
|
|
171
|
+
flushPendingReload();
|
|
143
172
|
maybeRecoverFromStaleResume();
|
|
144
173
|
}
|
|
145
174
|
}, { passive: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staleRecovery.js","sourceRoot":"","sources":["../../src/client/staleRecovery.ts"],"names":[],"mappings":"AAAA,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACjD,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC;AAErC,MAAM,YAAY,GAAG,4CAA4C,CAAC;AAClE,MAAM,qBAAqB,GAAG,mCAAmC,CAAC;AAClE,MAAM,uBAAuB,GAAG,wCAAwC,CAAC;AAEzE,MAAM,oBAAoB,GAAa;IACnC,iBAAiB;IACjB,+BAA+B;IAC/B,8CAA8C;IAC9C,mCAAmC;IACnC,8BAA8B;CACjC,CAAC;AAmBF,SAAS,gBAAgB,CAAC,OAA2B,EAAE,GAAW;IAC9D,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,OAA2B,EAAE,GAAW,EAAE,KAAoB;IACrF,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO;IACX,CAAC;IAED,IAAI,CAAC;QACD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACxB,OAAO;QACX,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACL,qEAAqE;IACzE,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAe;IACrC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,YAAY,KAAK,EAAE,CAAC;QAC1B,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC;IAC/C,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACpD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;YACnC,OAAO,YAAY,CAAC;QACxB,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC;QACrB,CAAC;IACL,CAAC;IAED,OAAO,EAAE,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC5C,IAAI,MAAM,YAAY,KAAK,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAC9D,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACtE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,UAA6C,EAAE;IACtF,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClG,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,CAAC,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAE1G,IAAI,CAAC,YAAY,IAAI,CAAC,cAAc,EAAE,CAAC;QACnC,OAAO;IACX,CAAC;IAED,MAAM,aAAa,GAAG,YAAqC,CAAC;IAC5D,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;QACxD,OAAO;IACX,CAAC;IACD,aAAa,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAEnC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,YAAY,CAAC,cAAc,CAAC;IAC/D,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,yBAAyB,CAAC;IAC/E,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,kBAAkB,CAAC;IACxE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAExE,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,QAAQ,GAAG,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;IAEhE,MAAM,UAAU,GAAG,GAAG,EAAE;QACpB,QAAQ,GAAG,GAAG,EAAE,CAAC;QACjB,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAG,EAAE;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,GAAG,EAAE;QACvB,IAAI,WAAW,EAAE,CAAC;YACd,OAAO;QACX,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC;QACtB,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC;QAC7E,IAAI,OAAO,GAAG,YAAY,GAAG,gBAAgB,EAAE,CAAC;YAC5C,OAAO;QACX,CAAC;QAED,WAAW,GAAG,IAAI,CAAC;QACnB,iBAAiB,CAAC,OAAO,EAAE,uBAAuB,EAAE,OAAO,CAAC,CAAC;QAC7D,MAAM,EAAE,CAAC;IACb,CAAC,CAAC;IAEF,MAAM,2BAA2B,GAAG,GAAG,EAAE;QACrC,MAAM,eAAe,GAAG,QAAQ,IAAI,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;QACrF,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;YAC3B,OAAO;QACX,CAAC;QAED,MAAM,cAAc,GAAG,GAAG,EAAE,GAAG,eAAe,CAAC;QAC/C,WAAW,EAAE,CAAC;QACd,IAAI,cAAc,IAAI,gBAAgB,EAAE,CAAC;YACrC,aAAa,EAAE,CAAC;QACpB,CAAC;IACL,CAAC,CAAC;IAEF,cAAc,CAAC,gBAAgB,CAC3B,kBAAkB,EAClB,GAAG,EAAE;QACD,IAAI,cAAc,CAAC,MAAM,EAAE,CAAC;YACxB,UAAU,EAAE,CAAC;YACb,OAAO;QACX,CAAC;QACD,2BAA2B,EAAE,CAAC;IAClC,CAAC,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CACpB,CAAC;IAEF,YAAY,CAAC,gBAAgB,CACzB,UAAU,EACV,GAAG,EAAE;QACD,UAAU,EAAE,CAAC;IACjB,CAAC,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CACpB,CAAC;IAEF,YAAY,CAAC,gBAAgB,CACzB,UAAU,EACV,CAAC,KAAK,EAAE,EAAE;QACN,IAAK,KAA6B,CAAC,SAAS,EAAE,CAAC;YAC3C,2BAA2B,EAAE,CAAC;QAClC,CAAC;IACL,CAAC,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CACpB,CAAC;IAEF,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QAC7C,MAAM,UAAU,GAAG,KAAmB,CAAC;QACvC,IAAI,gBAAgB,CAAC,UAAU,CAAC,KAAK,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3D,aAAa,EAAE,CAAC;QACpB,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,YAAY,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,CAAC,KAAK,EAAE,EAAE;QAC1D,MAAM,cAAc,GAAG,KAA8B,CAAC;QACtD,IAAI,gBAAgB,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1C,aAAa,EAAE,CAAC;QACpB,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["const STALE_RESUME_THRESHOLD_MS = 30 * 60 * 1000;\nconst RELOAD_COOLDOWN_MS = 30 * 1000;\n\nconst INSTALL_FLAG = \"__helium_stale_client_recovery_installed__\";\nconst HIDDEN_AT_STORAGE_KEY = \"__helium_stale_client_hidden_at__\";\nconst LAST_RELOAD_STORAGE_KEY = \"__helium_stale_client_last_reload_at__\";\n\nconst CHUNK_ERROR_PATTERNS: RegExp[] = [\n /ChunkLoadError/i,\n /Loading chunk\\s+\\d+\\s+failed/i,\n /Failed to fetch dynamically imported module/i,\n /Importing a module script failed/i,\n /dynamically imported module/i,\n];\n\ntype StorageLike = Pick<Storage, \"getItem\" | \"setItem\" | \"removeItem\">;\n\ntype InstallStaleClientRecoveryOptions = {\n windowObject?: Window;\n documentObject?: Document;\n storage?: StorageLike | null;\n now?: () => number;\n reload?: () => void;\n staleThresholdMs?: number;\n reloadCooldownMs?: number;\n disableDedupe?: boolean;\n};\n\ntype WindowWithInstallFlag = Window & {\n [INSTALL_FLAG]?: boolean;\n};\n\nfunction readStoredNumber(storage: StorageLike | null, key: string): number | null {\n if (!storage) {\n return null;\n }\n\n try {\n const raw = storage.getItem(key);\n if (!raw) {\n return null;\n }\n const parsed = Number(raw);\n return Number.isFinite(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nfunction writeStoredNumber(storage: StorageLike | null, key: string, value: number | null): void {\n if (!storage) {\n return;\n }\n\n try {\n if (value === null) {\n storage.removeItem(key);\n return;\n }\n storage.setItem(key, String(value));\n } catch {\n // Ignore storage write failures (private mode, quota exceeded, etc.)\n }\n}\n\nfunction extractErrorText(reason: unknown): string {\n if (typeof reason === \"string\") {\n return reason;\n }\n\n if (reason instanceof Error) {\n return `${reason.name}: ${reason.message}`;\n }\n\n if (typeof reason === \"object\" && reason !== null) {\n const maybeMessage = Reflect.get(reason, \"message\");\n if (typeof maybeMessage === \"string\") {\n return maybeMessage;\n }\n\n const maybeName = Reflect.get(reason, \"name\");\n if (typeof maybeName === \"string\") {\n return maybeName;\n }\n }\n\n return \"\";\n}\n\n/**\n * @internal Exported for testing\n */\nexport function isChunkLoadError(reason: unknown): boolean {\n if (reason instanceof Error && reason.name === \"ChunkLoadError\") {\n return true;\n }\n\n const text = extractErrorText(reason);\n if (!text) {\n return false;\n }\n\n return CHUNK_ERROR_PATTERNS.some((pattern) => pattern.test(text));\n}\n\n/**\n * Installs default stale-client recovery for mobile suspend/resume and stale chunks.\n *\n * @internal Exported for testing\n */\nexport function installStaleClientRecovery(options: InstallStaleClientRecoveryOptions = {}): void {\n const windowObject = options.windowObject ?? (typeof window !== \"undefined\" ? window : undefined);\n const documentObject = options.documentObject ?? (typeof document !== \"undefined\" ? document : undefined);\n\n if (!windowObject || !documentObject) {\n return;\n }\n\n const trackedWindow = windowObject as WindowWithInstallFlag;\n if (!options.disableDedupe && trackedWindow[INSTALL_FLAG]) {\n return;\n }\n trackedWindow[INSTALL_FLAG] = true;\n\n const now = options.now ?? (() => Date.now());\n const storage = options.storage ?? windowObject.sessionStorage;\n const staleThresholdMs = options.staleThresholdMs ?? STALE_RESUME_THRESHOLD_MS;\n const reloadCooldownMs = options.reloadCooldownMs ?? RELOAD_COOLDOWN_MS;\n const reload = options.reload ?? (() => windowObject.location.reload());\n\n let isReloading = false;\n let hiddenAt = readStoredNumber(storage, HIDDEN_AT_STORAGE_KEY);\n\n const markHidden = () => {\n hiddenAt = now();\n writeStoredNumber(storage, HIDDEN_AT_STORAGE_KEY, hiddenAt);\n };\n\n const clearHidden = () => {\n hiddenAt = null;\n writeStoredNumber(storage, HIDDEN_AT_STORAGE_KEY, null);\n };\n\n const attemptReload = () => {\n if (isReloading) {\n return;\n }\n\n const current = now();\n const lastReloadAt = readStoredNumber(storage, LAST_RELOAD_STORAGE_KEY) ?? 0;\n if (current - lastReloadAt < reloadCooldownMs) {\n return;\n }\n\n isReloading = true;\n writeStoredNumber(storage, LAST_RELOAD_STORAGE_KEY, current);\n reload();\n };\n\n const maybeRecoverFromStaleResume = () => {\n const hiddenTimestamp = hiddenAt ?? readStoredNumber(storage, HIDDEN_AT_STORAGE_KEY);\n if (hiddenTimestamp === null) {\n return;\n }\n\n const hiddenDuration = now() - hiddenTimestamp;\n clearHidden();\n if (hiddenDuration >= staleThresholdMs) {\n attemptReload();\n }\n };\n\n documentObject.addEventListener(\n \"visibilitychange\",\n () => {\n if (documentObject.hidden) {\n markHidden();\n return;\n }\n maybeRecoverFromStaleResume();\n },\n { passive: true }\n );\n\n windowObject.addEventListener(\n \"pagehide\",\n () => {\n markHidden();\n },\n { passive: true }\n );\n\n windowObject.addEventListener(\n \"pageshow\",\n (event) => {\n if ((event as PageTransitionEvent).persisted) {\n maybeRecoverFromStaleResume();\n }\n },\n { passive: true }\n );\n\n windowObject.addEventListener(\"error\", (event) => {\n const errorEvent = event as ErrorEvent;\n if (isChunkLoadError(errorEvent.error ?? errorEvent.message)) {\n attemptReload();\n }\n });\n\n windowObject.addEventListener(\"unhandledrejection\", (event) => {\n const rejectionEvent = event as PromiseRejectionEvent;\n if (isChunkLoadError(rejectionEvent.reason)) {\n attemptReload();\n }\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"staleRecovery.js","sourceRoot":"","sources":["../../src/client/staleRecovery.ts"],"names":[],"mappings":"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","sourcesContent":["const STALE_RESUME_THRESHOLD_MS = 30 * 60 * 1000;\nconst RELOAD_COOLDOWN_MS = 30 * 1000;\n\nconst INSTALL_FLAG = \"__helium_stale_client_recovery_installed__\";\nconst HIDDEN_AT_STORAGE_KEY = \"__helium_stale_client_hidden_at__\";\nconst LAST_RELOAD_STORAGE_KEY = \"__helium_stale_client_last_reload_at__\";\n\nconst CHUNK_ERROR_PATTERNS: RegExp[] = [\n /ChunkLoadError/i,\n /Loading chunk\\s+\\d+\\s+failed/i,\n /Failed to fetch dynamically imported module/i,\n /Importing a module script failed/i,\n /dynamically imported module/i,\n];\n\ntype StorageLike = Pick<Storage, \"getItem\" | \"setItem\" | \"removeItem\">;\n\ntype InstallStaleClientRecoveryOptions = {\n windowObject?: Window;\n documentObject?: Document;\n storage?: StorageLike | null;\n now?: () => number;\n reload?: () => void;\n staleThresholdMs?: number;\n reloadCooldownMs?: number;\n disableDedupe?: boolean;\n};\n\ntype WindowWithInstallFlag = Window & {\n [INSTALL_FLAG]?: boolean;\n};\n\nfunction resolveStorage(windowObject: Window, override?: StorageLike | null): StorageLike | null {\n if (override !== undefined) {\n return override;\n }\n\n try {\n return windowObject.sessionStorage;\n } catch {\n return null;\n }\n}\n\nfunction readStoredNumber(storage: StorageLike | null, key: string): number | null {\n if (!storage) {\n return null;\n }\n\n try {\n const raw = storage.getItem(key);\n if (!raw) {\n return null;\n }\n const parsed = Number(raw);\n return Number.isFinite(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nfunction writeStoredNumber(storage: StorageLike | null, key: string, value: number | null): void {\n if (!storage) {\n return;\n }\n\n try {\n if (value === null) {\n storage.removeItem(key);\n return;\n }\n storage.setItem(key, String(value));\n } catch {\n // Ignore storage write failures (private mode, quota exceeded, etc.)\n }\n}\n\nfunction extractErrorText(reason: unknown): string {\n if (typeof reason === \"string\") {\n return reason;\n }\n\n if (reason instanceof Error) {\n return `${reason.name}: ${reason.message}`;\n }\n\n if (typeof reason === \"object\" && reason !== null) {\n const maybeMessage = Reflect.get(reason, \"message\");\n if (typeof maybeMessage === \"string\") {\n return maybeMessage;\n }\n\n const maybeName = Reflect.get(reason, \"name\");\n if (typeof maybeName === \"string\") {\n return maybeName;\n }\n }\n\n return \"\";\n}\n\n/**\n * @internal Exported for testing\n */\nexport function isChunkLoadError(reason: unknown): boolean {\n if (reason instanceof Error && reason.name === \"ChunkLoadError\") {\n return true;\n }\n\n const text = extractErrorText(reason);\n if (!text) {\n return false;\n }\n\n return CHUNK_ERROR_PATTERNS.some((pattern) => pattern.test(text));\n}\n\n/**\n * Installs default stale-client recovery for mobile suspend/resume and stale chunks.\n *\n * @internal Exported for testing\n */\nexport function installStaleClientRecovery(options: InstallStaleClientRecoveryOptions = {}): void {\n const windowObject = options.windowObject ?? (typeof window !== \"undefined\" ? window : undefined);\n const documentObject = options.documentObject ?? (typeof document !== \"undefined\" ? document : undefined);\n\n if (!windowObject || !documentObject) {\n return;\n }\n\n const trackedWindow = windowObject as WindowWithInstallFlag;\n if (!options.disableDedupe && trackedWindow[INSTALL_FLAG]) {\n return;\n }\n trackedWindow[INSTALL_FLAG] = true;\n\n const now = options.now ?? (() => Date.now());\n const storage = resolveStorage(windowObject, options.storage);\n const staleThresholdMs = options.staleThresholdMs ?? STALE_RESUME_THRESHOLD_MS;\n const reloadCooldownMs = options.reloadCooldownMs ?? RELOAD_COOLDOWN_MS;\n const reload = options.reload ?? (() => windowObject.location.reload());\n\n let isReloading = false;\n let hasPendingReload = false;\n let hiddenAt = readStoredNumber(storage, HIDDEN_AT_STORAGE_KEY);\n\n const isVisible = () => !documentObject.hidden;\n\n const markHidden = () => {\n hiddenAt = now();\n writeStoredNumber(storage, HIDDEN_AT_STORAGE_KEY, hiddenAt);\n };\n\n const clearHidden = () => {\n hiddenAt = null;\n writeStoredNumber(storage, HIDDEN_AT_STORAGE_KEY, null);\n };\n\n const executeReload = () => {\n if (!isVisible()) {\n hasPendingReload = true;\n return;\n }\n\n if (isReloading) {\n return;\n }\n\n const current = now();\n const lastReloadAt = readStoredNumber(storage, LAST_RELOAD_STORAGE_KEY) ?? 0;\n if (current - lastReloadAt < reloadCooldownMs) {\n return;\n }\n\n isReloading = true;\n hasPendingReload = false;\n writeStoredNumber(storage, LAST_RELOAD_STORAGE_KEY, current);\n reload();\n };\n\n const flushPendingReload = () => {\n if (!hasPendingReload) {\n return;\n }\n executeReload();\n };\n\n const attemptReload = () => {\n executeReload();\n };\n\n const maybeRecoverFromStaleResume = () => {\n const hiddenTimestamp = hiddenAt ?? readStoredNumber(storage, HIDDEN_AT_STORAGE_KEY);\n if (hiddenTimestamp === null) {\n return;\n }\n\n const hiddenDuration = now() - hiddenTimestamp;\n clearHidden();\n if (hiddenDuration >= staleThresholdMs) {\n attemptReload();\n }\n };\n\n documentObject.addEventListener(\n \"visibilitychange\",\n () => {\n if (documentObject.hidden) {\n markHidden();\n return;\n }\n flushPendingReload();\n maybeRecoverFromStaleResume();\n },\n { passive: true }\n );\n\n windowObject.addEventListener(\n \"pagehide\",\n () => {\n markHidden();\n },\n { passive: true }\n );\n\n windowObject.addEventListener(\n \"pageshow\",\n (event) => {\n if ((event as PageTransitionEvent).persisted) {\n flushPendingReload();\n maybeRecoverFromStaleResume();\n }\n },\n { passive: true }\n );\n\n windowObject.addEventListener(\"error\", (event) => {\n const errorEvent = event as ErrorEvent;\n if (isChunkLoadError(errorEvent.error ?? errorEvent.message)) {\n attemptReload();\n }\n });\n\n windowObject.addEventListener(\"unhandledrejection\", (event) => {\n const rejectionEvent = event as PromiseRejectionEvent;\n if (isChunkLoadError(rejectionEvent.reason)) {\n attemptReload();\n }\n });\n}\n"]}
|