heliumts 0.5.12 → 0.5.14
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":"rpcClient.d.ts","sourceRoot":"","sources":["../../src/client/rpcClient.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA2B,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGhF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACvB,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,QAAQ,CAAC;CACnB,CAAC;AAWF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;AAUzD;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;
|
|
1
|
+
{"version":3,"file":"rpcClient.d.ts","sourceRoot":"","sources":["../../src/client/rpcClient.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA2B,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGhF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACvB,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,QAAQ,CAAC;CACnB,CAAC;AAWF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;AAUzD;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAksBD;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,OAAO,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAE7H;AAuCD;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAYjC"}
|
package/dist/client/rpcClient.js
CHANGED
|
@@ -39,9 +39,15 @@ function isMobileDevice() {
|
|
|
39
39
|
}
|
|
40
40
|
// Detect if we should prefer HTTP transport (mobile/slow networks)
|
|
41
41
|
function shouldUseHttpTransport() {
|
|
42
|
+
if (isTemporaryHttpFallbackActive()) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
42
45
|
if (configuredTransport === "http") {
|
|
43
46
|
return true;
|
|
44
47
|
}
|
|
48
|
+
if (configuredAutoHttpOnMobile && isMobileDevice()) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
45
51
|
if (configuredTransport === "websocket") {
|
|
46
52
|
return false;
|
|
47
53
|
}
|
|
@@ -49,10 +55,6 @@ function shouldUseHttpTransport() {
|
|
|
49
55
|
if (!configuredAutoHttpOnMobile) {
|
|
50
56
|
return false;
|
|
51
57
|
}
|
|
52
|
-
// autoHttpOnMobile must always prefer HTTP on mobile devices
|
|
53
|
-
if (isMobileDevice()) {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
58
|
// For non-mobile devices, prefer HTTP on slow/cellular connections
|
|
57
59
|
if (typeof navigator !== "undefined") {
|
|
58
60
|
const conn = navigator.connection;
|
|
@@ -102,20 +104,27 @@ async function flushBatch() {
|
|
|
102
104
|
async function sendBatchHttp(batch) {
|
|
103
105
|
const requests = batch.map((b) => b.req);
|
|
104
106
|
const encoded = msgpackEncode(requests);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
const sendWithToken = async (token) => {
|
|
108
|
+
const headers = {
|
|
109
|
+
"Content-Type": "application/msgpack",
|
|
110
|
+
Accept: "application/msgpack",
|
|
111
|
+
};
|
|
112
|
+
if (token) {
|
|
113
|
+
headers["X-Helium-Token"] = token;
|
|
114
|
+
}
|
|
115
|
+
return fetch("/__helium__/rpc", {
|
|
116
|
+
method: "POST",
|
|
117
|
+
headers,
|
|
118
|
+
body: encoded,
|
|
119
|
+
});
|
|
110
120
|
};
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
let response = await sendWithToken(await fetchFreshToken());
|
|
122
|
+
if (response.status === 401) {
|
|
123
|
+
const refreshedToken = await fetchFreshToken(true);
|
|
124
|
+
if (refreshedToken) {
|
|
125
|
+
response = await sendWithToken(refreshedToken);
|
|
126
|
+
}
|
|
113
127
|
}
|
|
114
|
-
const response = await fetch("/__helium__/rpc", {
|
|
115
|
-
method: "POST",
|
|
116
|
-
headers,
|
|
117
|
-
body: encoded,
|
|
118
|
-
});
|
|
119
128
|
handleBlockedResponse(response.status, "rpc-http");
|
|
120
129
|
if (!response.ok) {
|
|
121
130
|
throw new Error(`HTTP RPC failed: ${response.status}`);
|
|
@@ -242,7 +251,9 @@ function handleBlockedSocketClose(code) {
|
|
|
242
251
|
/** How long (ms) the page must be hidden before we consider the WebSocket stale. */
|
|
243
252
|
const STALE_THRESHOLD_MS = 15000;
|
|
244
253
|
/** Max time (ms) to wait for a WebSocket connection to open. */
|
|
245
|
-
const SOCKET_CONNECT_TIMEOUT_MS =
|
|
254
|
+
const SOCKET_CONNECT_TIMEOUT_MS = 10000;
|
|
255
|
+
/** Duration (ms) to temporarily force HTTP after repeated WebSocket failures. */
|
|
256
|
+
const WS_FAILURE_HTTP_COOLDOWN_MS = 60000;
|
|
246
257
|
/** Max time (ms) to wait for a response before timing out a request. */
|
|
247
258
|
const REQUEST_TIMEOUT_MS = 30000;
|
|
248
259
|
/** Number of automatic retries on retriable connection errors. */
|
|
@@ -253,6 +264,13 @@ const RETRY_BASE_DELAY_MS = 500;
|
|
|
253
264
|
const RETRY_MAX_DELAY_MS = 5000;
|
|
254
265
|
/** Timestamp when the page was last hidden (for visibility-change detection). */
|
|
255
266
|
let lastHiddenTimestamp = null;
|
|
267
|
+
let forceHttpUntilTimestamp = 0;
|
|
268
|
+
function isTemporaryHttpFallbackActive(now = Date.now()) {
|
|
269
|
+
return now < forceHttpUntilTimestamp;
|
|
270
|
+
}
|
|
271
|
+
function activateTemporaryHttpFallback(now = Date.now()) {
|
|
272
|
+
forceHttpUntilTimestamp = now + WS_FAILURE_HTTP_COOLDOWN_MS;
|
|
273
|
+
}
|
|
256
274
|
// ── Pending-request helpers ──────────────────────────────────────────────────
|
|
257
275
|
/**
|
|
258
276
|
* Register a pending request with an automatic timeout safeguard.
|
|
@@ -365,7 +383,21 @@ let msgId = 0;
|
|
|
365
383
|
function nextId() {
|
|
366
384
|
return msgId++;
|
|
367
385
|
}
|
|
368
|
-
|
|
386
|
+
let cachedAuthToken;
|
|
387
|
+
function hasCachedToken() {
|
|
388
|
+
return Boolean(cachedAuthToken);
|
|
389
|
+
}
|
|
390
|
+
function setCachedToken(token) {
|
|
391
|
+
if (!token) {
|
|
392
|
+
cachedAuthToken = undefined;
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
cachedAuthToken = token;
|
|
396
|
+
}
|
|
397
|
+
async function fetchFreshToken(forceRefresh = false) {
|
|
398
|
+
if (!forceRefresh && hasCachedToken()) {
|
|
399
|
+
return cachedAuthToken;
|
|
400
|
+
}
|
|
369
401
|
try {
|
|
370
402
|
const response = await fetch("/__helium__/refresh-token", {
|
|
371
403
|
method: "POST",
|
|
@@ -376,18 +408,22 @@ async function fetchFreshToken() {
|
|
|
376
408
|
handleBlockedResponse(response.status, "refresh-token");
|
|
377
409
|
if (!response.ok) {
|
|
378
410
|
console.warn("Failed to fetch fresh token:", response.status);
|
|
411
|
+
setCachedToken(undefined);
|
|
379
412
|
return undefined;
|
|
380
413
|
}
|
|
381
414
|
const data = await response.json();
|
|
382
|
-
|
|
415
|
+
const token = data.token;
|
|
416
|
+
setCachedToken(token);
|
|
417
|
+
return token;
|
|
383
418
|
}
|
|
384
419
|
catch (error) {
|
|
385
420
|
console.warn("Error fetching fresh token:", error);
|
|
421
|
+
setCachedToken(undefined);
|
|
386
422
|
return undefined;
|
|
387
423
|
}
|
|
388
424
|
}
|
|
389
425
|
async function createSocket() {
|
|
390
|
-
// Fetch a
|
|
426
|
+
// Fetch a token before creating the WebSocket connection
|
|
391
427
|
const token = await fetchFreshToken();
|
|
392
428
|
// Use the same protocol, hostname and port as the current page
|
|
393
429
|
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
@@ -495,6 +531,7 @@ function waitForSocketOpen(ws) {
|
|
|
495
531
|
if (socket === ws) {
|
|
496
532
|
socket = null;
|
|
497
533
|
}
|
|
534
|
+
setCachedToken(undefined);
|
|
498
535
|
reject(new Error("WebSocket connection failed"));
|
|
499
536
|
};
|
|
500
537
|
const handleClose = () => {
|
|
@@ -502,6 +539,7 @@ function waitForSocketOpen(ws) {
|
|
|
502
539
|
if (socket === ws) {
|
|
503
540
|
socket = null;
|
|
504
541
|
}
|
|
542
|
+
setCachedToken(undefined);
|
|
505
543
|
reject(new Error("WebSocket closed before opening"));
|
|
506
544
|
};
|
|
507
545
|
const timeout = setTimeout(() => {
|
|
@@ -509,12 +547,7 @@ function waitForSocketOpen(ws) {
|
|
|
509
547
|
if (socket === ws) {
|
|
510
548
|
socket = null;
|
|
511
549
|
}
|
|
512
|
-
|
|
513
|
-
ws.close();
|
|
514
|
-
}
|
|
515
|
-
catch {
|
|
516
|
-
// ignore close errors
|
|
517
|
-
}
|
|
550
|
+
setCachedToken(undefined);
|
|
518
551
|
reject(new Error("WebSocket connection timed out"));
|
|
519
552
|
}, SOCKET_CONNECT_TIMEOUT_MS);
|
|
520
553
|
ws.addEventListener("open", handleOpen);
|
|
@@ -591,15 +624,18 @@ async function rpcCallWebSocket(methodId, args) {
|
|
|
591
624
|
export async function rpcCall(methodId, args) {
|
|
592
625
|
return rpcCallWithRetry(methodId, args);
|
|
593
626
|
}
|
|
627
|
+
async function rpcCallViaHttpBatch(methodId, args) {
|
|
628
|
+
const id = nextId();
|
|
629
|
+
const req = { id, method: methodId, args };
|
|
630
|
+
return new Promise((resolve, reject) => {
|
|
631
|
+
pendingBatch.push({ req, resolve: resolve, reject });
|
|
632
|
+
scheduleBatch();
|
|
633
|
+
});
|
|
634
|
+
}
|
|
594
635
|
async function rpcCallWithRetry(methodId, args, attempt = 0) {
|
|
595
636
|
try {
|
|
596
637
|
if (shouldUseHttpTransport()) {
|
|
597
|
-
|
|
598
|
-
const req = { id, method: methodId, args };
|
|
599
|
-
return await new Promise((resolve, reject) => {
|
|
600
|
-
pendingBatch.push({ req, resolve: resolve, reject });
|
|
601
|
-
scheduleBatch();
|
|
602
|
-
});
|
|
638
|
+
return await rpcCallViaHttpBatch(methodId, args);
|
|
603
639
|
}
|
|
604
640
|
return await rpcCallWebSocket(methodId, args);
|
|
605
641
|
}
|
|
@@ -613,6 +649,10 @@ async function rpcCallWithRetry(methodId, args, attempt = 0) {
|
|
|
613
649
|
await new Promise((r) => setTimeout(r, baseDelay + jitter));
|
|
614
650
|
return rpcCallWithRetry(methodId, args, attempt + 1);
|
|
615
651
|
}
|
|
652
|
+
if (isRetriableError(err) && configuredTransport !== "http") {
|
|
653
|
+
activateTemporaryHttpFallback();
|
|
654
|
+
return rpcCallViaHttpBatch(methodId, args);
|
|
655
|
+
}
|
|
616
656
|
throw err;
|
|
617
657
|
}
|
|
618
658
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpcClient.js","sourceRoot":"","sources":["../../src/client/rpcClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { decode as msgpackDecode, encode as msgpackEncode } from \"@msgpack/msgpack\";\n\nimport type { RpcRequest, RpcResponse, RpcStats } from \"../runtime/protocol.js\";\nimport { RpcError } from \"./RpcError.js\";\n\nexport type RpcResult<T> = {\n data: T;\n stats: RpcStats;\n};\n\nfunction toArrayBuffer(data: Uint8Array<ArrayBufferLike>): ArrayBuffer {\n if (data.buffer instanceof ArrayBuffer && data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) {\n return data.buffer;\n }\n const buffer = new ArrayBuffer(data.byteLength);\n new Uint8Array(buffer).set(data);\n return buffer;\n}\n\n/**\n * Transport mode for RPC calls.\n * - \"http\": Uses HTTP POST requests (faster on mobile/high-latency networks, benefits from HTTP/2)\n * - \"websocket\": Uses persistent WebSocket connection (lower latency on desktop/low-latency networks)\n * - \"auto\": Automatically selects based on connection type\n */\nexport type RpcTransport = \"http\" | \"websocket\" | \"auto\";\n\n// Build-time configuration injected by Vite plugin from helium.config.js\ndeclare const __HELIUM_RPC_TRANSPORT__: RpcTransport;\ndeclare const __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__: boolean;\n\n// Read build-time config with fallback defaults\nconst configuredTransport: RpcTransport = typeof __HELIUM_RPC_TRANSPORT__ !== \"undefined\" ? __HELIUM_RPC_TRANSPORT__ : \"websocket\";\nconst configuredAutoHttpOnMobile: boolean = typeof __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__ !== \"undefined\" ? __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__ : false;\n\n/**\n * Get the configured RPC transport mode (from helium.config.js).\n */\nexport function getRpcTransport(): RpcTransport {\n return configuredTransport;\n}\n\n/**\n * Check if auto HTTP on mobile is enabled (from helium.config.js).\n */\nexport function isAutoHttpOnMobileEnabled(): boolean {\n return configuredAutoHttpOnMobile;\n}\n\ninterface NetworkInformation {\n type?: string;\n effectiveType?: string;\n}\n\ninterface NavigatorWithConnection extends Navigator {\n connection?: NetworkInformation;\n userAgentData?: {\n mobile?: boolean;\n };\n}\n\nfunction isMobileDevice(): boolean {\n if (typeof navigator === \"undefined\") {\n return false;\n }\n\n const nav = navigator as NavigatorWithConnection;\n if (typeof nav.userAgentData?.mobile === \"boolean\") {\n return nav.userAgentData.mobile;\n }\n\n const userAgent = navigator.userAgent || \"\";\n if (/Android|iPhone|iPad|iPod|IEMobile|Opera Mini|Mobi/i.test(userAgent)) {\n return true;\n }\n\n return navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1;\n}\n\n// Detect if we should prefer HTTP transport (mobile/slow networks)\nfunction shouldUseHttpTransport(): boolean {\n if (configuredTransport === \"http\") {\n return true;\n }\n if (configuredTransport === \"websocket\") {\n return false;\n }\n\n // Auto mode: check if mobile HTTP optimization is enabled\n if (!configuredAutoHttpOnMobile) {\n return false;\n }\n\n // autoHttpOnMobile must always prefer HTTP on mobile devices\n if (isMobileDevice()) {\n return true;\n }\n\n // For non-mobile devices, prefer HTTP on slow/cellular connections\n if (typeof navigator !== \"undefined\") {\n const conn = (navigator as NavigatorWithConnection).connection;\n if (conn) {\n // Use HTTP for cellular connections or slow effective types\n const slowTypes = [\"slow-2g\", \"2g\", \"3g\"];\n if (conn.type === \"cellular\" || (conn.effectiveType && slowTypes.includes(conn.effectiveType))) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n// ============================================================================\n// Batching Logic\n// ============================================================================\n\ntype PendingRequest = {\n req: RpcRequest;\n resolve: (value: RpcResult<any>) => void;\n reject: (reason?: any) => void;\n};\n\nlet pendingBatch: PendingRequest[] = [];\nlet isBatchScheduled = false;\n\nfunction scheduleBatch() {\n if (isBatchScheduled) {\n return;\n }\n isBatchScheduled = true;\n queueMicrotask(() => {\n isBatchScheduled = false;\n flushBatch();\n });\n}\n\nasync function flushBatch() {\n const batch = pendingBatch;\n pendingBatch = [];\n\n if (batch.length === 0) {\n return;\n }\n\n try {\n if (shouldUseHttpTransport()) {\n await sendBatchHttp(batch);\n } else {\n await sendBatchWebSocket(batch);\n }\n } catch (err) {\n // Transport error, fail all\n for (const item of batch) {\n item.reject(err);\n }\n }\n}\n\nasync function sendBatchHttp(batch: PendingRequest[]) {\n const requests = batch.map((b) => b.req);\n const encoded = msgpackEncode(requests);\n\n // Fetch a fresh token for HTTP RPC authentication\n const token = await fetchFreshToken();\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/msgpack\",\n Accept: \"application/msgpack\",\n };\n if (token) {\n headers[\"X-Helium-Token\"] = token;\n }\n\n const response = await fetch(\"/__helium__/rpc\", {\n method: \"POST\",\n headers,\n body: encoded as unknown as BodyInit,\n });\n\n handleBlockedResponse(response.status, \"rpc-http\");\n if (!response.ok) {\n throw new Error(`HTTP RPC failed: ${response.status}`);\n }\n\n const responseBuffer = await response.arrayBuffer();\n const msg = msgpackDecode(new Uint8Array(responseBuffer)) as RpcResponse | RpcResponse[];\n\n const responses = Array.isArray(msg) ? msg : [msg];\n const responseMap = new Map(responses.map((r) => [r.id, r]));\n\n for (const item of batch) {\n const res = responseMap.get(item.req.id);\n if (res) {\n if (res.ok) {\n item.resolve({ data: res.result, stats: res.stats });\n } else {\n item.reject(new RpcError(res.error, res.stats));\n }\n } else {\n item.reject(new RpcError(\"No response for request\"));\n }\n }\n}\n\nasync function sendBatchWebSocket(batch: PendingRequest[]) {\n const ws = await ensureSocketReady();\n const requests = batch.map((b) => b.req);\n\n // Register pending promises with timeout safeguards\n batch.forEach((item) => {\n trackPending(item.req.id, (v: unknown) => item.resolve(v as RpcResult<any>), item.reject);\n });\n\n try {\n // Always use msgpack encoding\n const encoded = msgpackEncode(requests);\n ws.send(toArrayBuffer(encoded));\n } catch (err) {\n batch.forEach((item) => {\n removePending(item.req.id);\n item.reject(err);\n });\n }\n}\n\n// ============================================================================\n// WebSocket Transport (original implementation)\n// ============================================================================\n\nlet socket: WebSocket | null = null;\nlet connectionPromise: Promise<WebSocket> | null = null;\n\nconst pending = new Map<string | number, { resolve: (v: unknown) => void; reject: (e: unknown) => void }>();\nconst pendingTimeouts = new Map<string | number, ReturnType<typeof setTimeout>>();\n\n// ── Block detection (rate-limited reload) ──────────────────────────────────\n\ntype BlockedSource = \"refresh-token\" | \"rpc-http\" | \"rpc-websocket\";\n\nconst BLOCKED_HTTP_STATUSES = new Set([401, 403, 429]);\nconst BLOCKED_WS_CLOSE_CODES = new Set([1008, 1011, 1013]);\nconst BLOCKED_RETRY_THRESHOLD = 3;\nconst BLOCKED_RETRY_WINDOW_MS = 1_000;\nconst BLOCKED_RELOAD_COOLDOWN_MS = 120_000;\nconst BLOCKED_RELOAD_KEY = \"helium:blocked-reload-ts\";\n\nconst blockedAttempts = new Map<BlockedSource, { count: number; lastTs: number }>();\nlet lastBlockedReloadAt = 0;\n\nfunction shouldAutoReloadOnBlock(now: number): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n try {\n const stored = window.sessionStorage.getItem(BLOCKED_RELOAD_KEY);\n const storedTs = stored ? Number(stored) : 0;\n if (storedTs && now - storedTs < BLOCKED_RELOAD_COOLDOWN_MS) {\n return false;\n }\n window.sessionStorage.setItem(BLOCKED_RELOAD_KEY, String(now));\n return true;\n } catch {\n if (now - lastBlockedReloadAt < BLOCKED_RELOAD_COOLDOWN_MS) {\n return false;\n }\n lastBlockedReloadAt = now;\n return true;\n }\n}\n\nfunction shouldTriggerBlockedAction(source: BlockedSource, now: number): boolean {\n const state = blockedAttempts.get(source);\n if (!state || now - state.lastTs > BLOCKED_RETRY_WINDOW_MS) {\n blockedAttempts.set(source, { count: 1, lastTs: now });\n return false;\n }\n const nextCount = state.count + 1;\n blockedAttempts.set(source, { count: nextCount, lastTs: now });\n return nextCount > BLOCKED_RETRY_THRESHOLD;\n}\n\nfunction dispatchBlockedEvent(detail: { source: BlockedSource; status?: number; code?: number }): void {\n if (typeof window === \"undefined\") {\n return;\n }\n window.dispatchEvent(\n new CustomEvent(\"helium:blocked\", {\n detail,\n })\n );\n}\n\nfunction handleBlockedResponse(status: number, source: BlockedSource): void {\n if (!BLOCKED_HTTP_STATUSES.has(status)) {\n return;\n }\n const now = Date.now();\n if (!shouldTriggerBlockedAction(source, now)) {\n return;\n }\n\n dispatchBlockedEvent({ status, source });\n\n if (shouldAutoReloadOnBlock(now) && typeof window.location?.reload === \"function\") {\n window.location.reload();\n }\n}\n\nfunction handleBlockedSocketClose(code: number): void {\n if (!BLOCKED_WS_CLOSE_CODES.has(code)) {\n return;\n }\n const now = Date.now();\n if (!shouldTriggerBlockedAction(\"rpc-websocket\", now)) {\n return;\n }\n\n dispatchBlockedEvent({ code, source: \"rpc-websocket\" });\n if (shouldAutoReloadOnBlock(now) && typeof window.location?.reload === \"function\") {\n window.location.reload();\n }\n}\n\n// ── Connection resilience constants ──────────────────────────────────────────\n\n/** How long (ms) the page must be hidden before we consider the WebSocket stale. */\nconst STALE_THRESHOLD_MS = 15_000;\n\n/** Max time (ms) to wait for a WebSocket connection to open. */\nconst SOCKET_CONNECT_TIMEOUT_MS = 5_000;\n\n/** Max time (ms) to wait for a response before timing out a request. */\nconst REQUEST_TIMEOUT_MS = 30_000;\n\n/** Number of automatic retries on retriable connection errors. */\nconst MAX_RETRIES = 3;\n\n/** Base delay (ms) for exponential backoff between retries (doubles each attempt). */\nconst RETRY_BASE_DELAY_MS = 500;\n\n/** Maximum delay (ms) cap for backoff to avoid excessively long waits. */\nconst RETRY_MAX_DELAY_MS = 5_000;\n\n/** Timestamp when the page was last hidden (for visibility-change detection). */\nlet lastHiddenTimestamp: number | null = null;\n\n// ── Pending-request helpers ──────────────────────────────────────────────────\n\n/**\n * Register a pending request with an automatic timeout safeguard.\n * If no response arrives within REQUEST_TIMEOUT_MS the promise is rejected\n * so the caller's retry logic can kick in.\n */\nfunction trackPending(id: string | number, resolve: (v: unknown) => void, reject: (e: unknown) => void): void {\n pending.set(id, { resolve, reject });\n const timer = setTimeout(() => {\n const entry = pending.get(id);\n if (entry) {\n pending.delete(id);\n pendingTimeouts.delete(id);\n entry.reject(new RpcError(\"Request timed out\"));\n }\n }, REQUEST_TIMEOUT_MS);\n pendingTimeouts.set(id, timer);\n}\n\n/**\n * Remove a pending request and clear its timeout.\n * Returns the entry so the caller can resolve/reject it.\n */\nfunction removePending(id: string | number): { resolve: (v: unknown) => void; reject: (e: unknown) => void } | undefined {\n const entry = pending.get(id);\n if (!entry) {\n return undefined;\n }\n pending.delete(id);\n const timer = pendingTimeouts.get(id);\n if (timer) {\n clearTimeout(timer);\n pendingTimeouts.delete(id);\n }\n return entry;\n}\n\n/** Reject every in-flight request (e.g. when the socket closes unexpectedly). */\nfunction rejectAllPending(reason: Error): void {\n for (const timer of pendingTimeouts.values()) {\n clearTimeout(timer);\n }\n pendingTimeouts.clear();\n const entries = [...pending.entries()];\n pending.clear();\n for (const [, entry] of entries) {\n entry.reject(reason);\n }\n}\n\n// ── Reconnection helpers ─────────────────────────────────────────────────────\n\n/**\n * Force-close the current WebSocket so the next call creates a fresh\n * connection (which fetches a brand-new token).\n */\nfunction forceReconnect(): void {\n const oldSocket = socket;\n socket = null;\n connectionPromise = null;\n\n if (oldSocket) {\n // Detach handlers to avoid double-rejecting pending from the close event\n oldSocket.onclose = null;\n oldSocket.onerror = null;\n oldSocket.onmessage = null;\n oldSocket.close();\n }\n\n // Reject all in-flight requests – callers with retry logic will resend\n rejectAllPending(new Error(\"Connection reset\"));\n}\n\nfunction reconnectIfLikelyStale(force = false): void {\n if (!socket) {\n lastHiddenTimestamp = null;\n return;\n }\n\n if (force) {\n forceReconnect();\n lastHiddenTimestamp = null;\n return;\n }\n\n if (lastHiddenTimestamp !== null) {\n const hiddenDuration = Date.now() - lastHiddenTimestamp;\n if (hiddenDuration > STALE_THRESHOLD_MS) {\n forceReconnect();\n }\n }\n\n lastHiddenTimestamp = null;\n}\n\n/** Determine whether an error warrants an automatic retry. */\nfunction isRetriableError(err: unknown): boolean {\n // Network / connection errors are always retriable\n if (err instanceof Error && !(err instanceof RpcError)) {\n return true;\n }\n // Timed-out requests are retriable (socket may have died silently)\n if (err instanceof RpcError && err.message === \"Request timed out\") {\n return true;\n }\n return false;\n}\n\n// Clean up WebSocket connection on HMR (Hot Module Replacement)\nif (import.meta.hot) {\n import.meta.hot.dispose(() => {\n if (socket) {\n socket.onclose = null;\n socket.close();\n socket = null;\n connectionPromise = null;\n }\n rejectAllPending(new Error(\"Module reloaded\"));\n });\n}\n\nlet msgId = 0;\nfunction nextId() {\n return msgId++;\n}\n\nasync function fetchFreshToken(): Promise<string | undefined> {\n try {\n const response = await fetch(\"/__helium__/refresh-token\", {\n method: \"POST\",\n headers: {\n \"X-Requested-With\": \"HeliumRPC\",\n },\n });\n handleBlockedResponse(response.status, \"refresh-token\");\n if (!response.ok) {\n console.warn(\"Failed to fetch fresh token:\", response.status);\n return undefined;\n }\n const data = await response.json();\n return data.token;\n } catch (error) {\n console.warn(\"Error fetching fresh token:\", error);\n return undefined;\n }\n}\n\nasync function createSocket(): Promise<WebSocket> {\n // Fetch a fresh token before creating the WebSocket connection\n const token = await fetchFreshToken();\n\n // Use the same protocol, hostname and port as the current page\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = window.location.host; // includes hostname and port\n const url = `${protocol}//${host}/rpc`;\n // Security: pass token via Sec-WebSocket-Protocol header instead of query string\n const ws = token ? new WebSocket(url, [token]) : new WebSocket(url);\n ws.binaryType = \"arraybuffer\";\n\n ws.onmessage = async (event) => {\n let data = new Uint8Array(event.data as ArrayBuffer);\n\n // Check for Gzip header (0x1f 0x8b) to detect compressed messages\n if (data.length > 2 && data[0] === 0x1f && data[1] === 0x8b) {\n try {\n // Use DecompressionStream if available (Chrome 80+, Firefox 113+, Safari 16.4+)\n if (typeof DecompressionStream !== \"undefined\") {\n const ds = new DecompressionStream(\"gzip\");\n const stream = new Response(data).body;\n if (stream) {\n const decompressed = stream.pipeThrough(ds);\n const reader = decompressed.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n const MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024; // 10 MB\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n break;\n }\n totalSize += value.length;\n if (totalSize > MAX_DECOMPRESSED_SIZE) {\n reader.cancel();\n console.error(\"Decompressed message exceeds size limit\");\n return;\n }\n chunks.push(value);\n }\n const combined = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n data = combined;\n }\n }\n } catch (err) {\n console.error(\"Failed to decompress WebSocket message:\", err);\n return;\n }\n }\n\n // Always expect binary MessagePack\n const msg = msgpackDecode(data) as RpcResponse | RpcResponse[];\n\n const handleResponse = (res: RpcResponse) => {\n const entry = removePending(res.id);\n if (!entry) {\n return;\n }\n if (res.ok) {\n entry.resolve({ data: res.result, stats: res.stats });\n } else {\n entry.reject(new RpcError(res.error, res.stats));\n }\n };\n\n if (Array.isArray(msg)) {\n msg.forEach(handleResponse);\n } else {\n handleResponse(msg);\n }\n };\n\n ws.onerror = () => {\n // WebSocket errors are always followed by a close event.\n // The close handler takes care of rejecting pending promises.\n };\n\n ws.onclose = (event) => {\n handleBlockedSocketClose(event.code);\n if (socket === ws) {\n socket = null;\n connectionPromise = null;\n // Reject every in-flight request so callers can retry\n rejectAllPending(new Error(\"WebSocket connection closed\"));\n }\n };\n\n return ws;\n}\n\nfunction waitForSocketOpen(ws: WebSocket): Promise<WebSocket> {\n if (ws.readyState === WebSocket.OPEN) {\n return Promise.resolve(ws);\n }\n\n return new Promise<WebSocket>((resolve, reject) => {\n const cleanup = () => {\n ws.removeEventListener(\"open\", handleOpen);\n ws.removeEventListener(\"error\", handleError);\n ws.removeEventListener(\"close\", handleClose);\n clearTimeout(timeout);\n };\n\n const handleOpen = () => {\n cleanup();\n resolve(ws);\n };\n\n const handleError = () => {\n cleanup();\n if (socket === ws) {\n socket = null;\n }\n reject(new Error(\"WebSocket connection failed\"));\n };\n\n const handleClose = () => {\n cleanup();\n if (socket === ws) {\n socket = null;\n }\n reject(new Error(\"WebSocket closed before opening\"));\n };\n\n const timeout = setTimeout(() => {\n cleanup();\n if (socket === ws) {\n socket = null;\n }\n try {\n ws.close();\n } catch {\n // ignore close errors\n }\n reject(new Error(\"WebSocket connection timed out\"));\n }, SOCKET_CONNECT_TIMEOUT_MS);\n\n ws.addEventListener(\"open\", handleOpen);\n ws.addEventListener(\"error\", handleError);\n ws.addEventListener(\"close\", handleClose);\n });\n}\n\nasync function ensureSocketReady(): Promise<WebSocket> {\n // If we have an open socket, return it immediately\n if (socket && socket.readyState === WebSocket.OPEN) {\n return socket;\n }\n\n // If we have a connection in progress, reuse that promise\n if (connectionPromise) {\n return connectionPromise;\n }\n\n const pendingConnectPromise = (async () => {\n if (!socket || socket.readyState === WebSocket.CLOSED || socket.readyState === WebSocket.CLOSING) {\n socket = await createSocket();\n }\n\n return waitForSocketOpen(socket);\n })();\n\n connectionPromise = pendingConnectPromise;\n\n try {\n return await pendingConnectPromise;\n } finally {\n if (connectionPromise === pendingConnectPromise) {\n connectionPromise = null;\n }\n }\n}\n\nasync function rpcCallWebSocket<TResult, TArgs>(methodId: string, args?: TArgs): Promise<RpcResult<TResult>> {\n // Optimization: If socket is open, send immediately without awaiting ensureSocketReady (which adds a microtask tick)\n if (socket && socket.readyState === WebSocket.OPEN) {\n const id = nextId();\n const req: RpcRequest = { id, method: methodId, args };\n return new Promise<RpcResult<TResult>>((resolve, reject) => {\n trackPending(id, (v: unknown) => resolve(v as RpcResult<TResult>), reject);\n try {\n const encoded = msgpackEncode(req);\n socket!.send(toArrayBuffer(encoded));\n } catch (err) {\n removePending(id);\n reject(err);\n }\n });\n }\n\n const ws = await ensureSocketReady();\n const id = nextId();\n\n const req: RpcRequest = { id, method: methodId, args };\n\n return new Promise<RpcResult<TResult>>((resolve, reject) => {\n trackPending(id, (v: unknown) => resolve(v as RpcResult<TResult>), reject);\n try {\n // Always use msgpack encoding\n const encoded = msgpackEncode(req);\n ws.send(toArrayBuffer(encoded));\n } catch (err) {\n removePending(id);\n reject(err);\n }\n });\n}\n\n/**\n * Make an RPC call using the appropriate transport.\n * Automatically selects HTTP or WebSocket based on network conditions and configuration.\n *\n * Includes automatic retry logic: if a call fails due to a connection error\n * (e.g. stale WebSocket after mobile browser was backgrounded), the client\n * forces a fresh connection (with a new token) and retries once.\n */\nexport async function rpcCall<TResult = unknown, TArgs = unknown>(methodId: string, args?: TArgs): Promise<RpcResult<TResult>> {\n return rpcCallWithRetry<TResult, TArgs>(methodId, args);\n}\n\nasync function rpcCallWithRetry<TResult, TArgs>(methodId: string, args: TArgs | undefined, attempt = 0): Promise<RpcResult<TResult>> {\n try {\n if (shouldUseHttpTransport()) {\n const id = nextId();\n const req: RpcRequest = { id, method: methodId, args };\n\n return await new Promise<RpcResult<TResult>>((resolve, reject) => {\n pendingBatch.push({ req, resolve: resolve as (value: RpcResult<TResult>) => void, reject });\n scheduleBatch();\n });\n }\n\n return await rpcCallWebSocket<TResult, TArgs>(methodId, args);\n } catch (err) {\n if (attempt < MAX_RETRIES && isRetriableError(err)) {\n // Force a fresh connection (fetches a new token)\n forceReconnect();\n // Exponential backoff with jitter: 500ms, 1000ms, 2000ms (capped at 5s)\n const baseDelay = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS);\n const jitter = Math.random() * baseDelay * 0.3;\n await new Promise<void>((r) => setTimeout(r, baseDelay + jitter));\n return rpcCallWithRetry<TResult, TArgs>(methodId, args, attempt + 1);\n }\n throw err;\n }\n}\n\n/**\n * Pre-establishes the WebSocket connection.\n * Call this early (e.g., on page load) to avoid connection latency on first RPC call.\n * This is especially beneficial on high-latency networks like mobile LTE.\n * Note: Only effective when using WebSocket transport (not HTTP transport).\n */\nexport function preconnect(): void {\n if (typeof window === \"undefined\") {\n return;\n }\n // Only preconnect if we're using WebSocket transport\n if (shouldUseHttpTransport()) {\n return;\n }\n // Fire and forget - establishes connection in background\n ensureSocketReady().catch(() => {\n // Silently ignore preconnect failures, will retry on actual call\n });\n}\n\n// Auto-preconnect when the module loads (browser only, WebSocket transport only)\nif (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n // Use requestIdleCallback if available, otherwise setTimeout\n const schedulePreconnect = window.requestIdleCallback || ((cb: () => void) => setTimeout(cb, 1));\n schedulePreconnect(() => preconnect());\n}\n\n// ============================================================================\n// Visibility-change reconnection (critical for mobile browsers)\n// ============================================================================\n//\n// Mobile browsers freeze or kill WebSocket connections when the tab is\n// backgrounded. When the user returns the socket may *appear* open but\n// is actually stale. We detect this via the Page Visibility API and\n// proactively tear down the old connection so the next RPC call creates\n// a fresh one (with a brand-new auth token).\n// ============================================================================\n\nif (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", () => {\n if (document.hidden) {\n lastHiddenTimestamp = Date.now();\n } else {\n reconnectIfLikelyStale(false);\n }\n });\n\n document.addEventListener(\"pagehide\", () => {\n lastHiddenTimestamp = Date.now();\n });\n}\n\nif (typeof window !== \"undefined\") {\n window.addEventListener(\"pageshow\", (event) => {\n if ((event as PageTransitionEvent).persisted) {\n reconnectIfLikelyStale(true);\n return;\n }\n reconnectIfLikelyStale(false);\n });\n\n window.addEventListener(\"focus\", () => {\n reconnectIfLikelyStale(false);\n });\n\n window.addEventListener(\"online\", () => {\n reconnectIfLikelyStale(true);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rpcClient.js","sourceRoot":"","sources":["../../src/client/rpcClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { decode as msgpackDecode, encode as msgpackEncode } from \"@msgpack/msgpack\";\n\nimport type { RpcRequest, RpcResponse, RpcStats } from \"../runtime/protocol.js\";\nimport { RpcError } from \"./RpcError.js\";\n\nexport type RpcResult<T> = {\n data: T;\n stats: RpcStats;\n};\n\nfunction toArrayBuffer(data: Uint8Array<ArrayBufferLike>): ArrayBuffer {\n if (data.buffer instanceof ArrayBuffer && data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) {\n return data.buffer;\n }\n const buffer = new ArrayBuffer(data.byteLength);\n new Uint8Array(buffer).set(data);\n return buffer;\n}\n\n/**\n * Transport mode for RPC calls.\n * - \"http\": Uses HTTP POST requests (faster on mobile/high-latency networks, benefits from HTTP/2)\n * - \"websocket\": Uses persistent WebSocket connection (lower latency on desktop/low-latency networks)\n * - \"auto\": Automatically selects based on connection type\n */\nexport type RpcTransport = \"http\" | \"websocket\" | \"auto\";\n\n// Build-time configuration injected by Vite plugin from helium.config.js\ndeclare const __HELIUM_RPC_TRANSPORT__: RpcTransport;\ndeclare const __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__: boolean;\n\n// Read build-time config with fallback defaults\nconst configuredTransport: RpcTransport = typeof __HELIUM_RPC_TRANSPORT__ !== \"undefined\" ? __HELIUM_RPC_TRANSPORT__ : \"websocket\";\nconst configuredAutoHttpOnMobile: boolean = typeof __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__ !== \"undefined\" ? __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__ : false;\n\n/**\n * Get the configured RPC transport mode (from helium.config.js).\n */\nexport function getRpcTransport(): RpcTransport {\n return configuredTransport;\n}\n\n/**\n * Check if auto HTTP on mobile is enabled (from helium.config.js).\n */\nexport function isAutoHttpOnMobileEnabled(): boolean {\n return configuredAutoHttpOnMobile;\n}\n\ninterface NetworkInformation {\n type?: string;\n effectiveType?: string;\n}\n\ninterface NavigatorWithConnection extends Navigator {\n connection?: NetworkInformation;\n userAgentData?: {\n mobile?: boolean;\n };\n}\n\nfunction isMobileDevice(): boolean {\n if (typeof navigator === \"undefined\") {\n return false;\n }\n\n const nav = navigator as NavigatorWithConnection;\n if (typeof nav.userAgentData?.mobile === \"boolean\") {\n return nav.userAgentData.mobile;\n }\n\n const userAgent = navigator.userAgent || \"\";\n if (/Android|iPhone|iPad|iPod|IEMobile|Opera Mini|Mobi/i.test(userAgent)) {\n return true;\n }\n\n return navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1;\n}\n\n// Detect if we should prefer HTTP transport (mobile/slow networks)\nfunction shouldUseHttpTransport(): boolean {\n if (isTemporaryHttpFallbackActive()) {\n return true;\n }\n\n if (configuredTransport === \"http\") {\n return true;\n }\n\n if (configuredAutoHttpOnMobile && isMobileDevice()) {\n return true;\n }\n\n if (configuredTransport === \"websocket\") {\n return false;\n }\n\n // Auto mode: check if mobile HTTP optimization is enabled\n if (!configuredAutoHttpOnMobile) {\n return false;\n }\n\n // For non-mobile devices, prefer HTTP on slow/cellular connections\n if (typeof navigator !== \"undefined\") {\n const conn = (navigator as NavigatorWithConnection).connection;\n if (conn) {\n // Use HTTP for cellular connections or slow effective types\n const slowTypes = [\"slow-2g\", \"2g\", \"3g\"];\n if (conn.type === \"cellular\" || (conn.effectiveType && slowTypes.includes(conn.effectiveType))) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n// ============================================================================\n// Batching Logic\n// ============================================================================\n\ntype PendingRequest = {\n req: RpcRequest;\n resolve: (value: RpcResult<any>) => void;\n reject: (reason?: any) => void;\n};\n\nlet pendingBatch: PendingRequest[] = [];\nlet isBatchScheduled = false;\n\nfunction scheduleBatch() {\n if (isBatchScheduled) {\n return;\n }\n isBatchScheduled = true;\n queueMicrotask(() => {\n isBatchScheduled = false;\n flushBatch();\n });\n}\n\nasync function flushBatch() {\n const batch = pendingBatch;\n pendingBatch = [];\n\n if (batch.length === 0) {\n return;\n }\n\n try {\n if (shouldUseHttpTransport()) {\n await sendBatchHttp(batch);\n } else {\n await sendBatchWebSocket(batch);\n }\n } catch (err) {\n // Transport error, fail all\n for (const item of batch) {\n item.reject(err);\n }\n }\n}\n\nasync function sendBatchHttp(batch: PendingRequest[]) {\n const requests = batch.map((b) => b.req);\n const encoded = msgpackEncode(requests);\n\n const sendWithToken = async (token: string | undefined) => {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/msgpack\",\n Accept: \"application/msgpack\",\n };\n if (token) {\n headers[\"X-Helium-Token\"] = token;\n }\n\n return fetch(\"/__helium__/rpc\", {\n method: \"POST\",\n headers,\n body: encoded as unknown as BodyInit,\n });\n };\n\n let response = await sendWithToken(await fetchFreshToken());\n\n if (response.status === 401) {\n const refreshedToken = await fetchFreshToken(true);\n if (refreshedToken) {\n response = await sendWithToken(refreshedToken);\n }\n }\n\n handleBlockedResponse(response.status, \"rpc-http\");\n if (!response.ok) {\n throw new Error(`HTTP RPC failed: ${response.status}`);\n }\n\n const responseBuffer = await response.arrayBuffer();\n const msg = msgpackDecode(new Uint8Array(responseBuffer)) as RpcResponse | RpcResponse[];\n\n const responses = Array.isArray(msg) ? msg : [msg];\n const responseMap = new Map(responses.map((r) => [r.id, r]));\n\n for (const item of batch) {\n const res = responseMap.get(item.req.id);\n if (res) {\n if (res.ok) {\n item.resolve({ data: res.result, stats: res.stats });\n } else {\n item.reject(new RpcError(res.error, res.stats));\n }\n } else {\n item.reject(new RpcError(\"No response for request\"));\n }\n }\n}\n\nasync function sendBatchWebSocket(batch: PendingRequest[]) {\n const ws = await ensureSocketReady();\n const requests = batch.map((b) => b.req);\n\n // Register pending promises with timeout safeguards\n batch.forEach((item) => {\n trackPending(item.req.id, (v: unknown) => item.resolve(v as RpcResult<any>), item.reject);\n });\n\n try {\n // Always use msgpack encoding\n const encoded = msgpackEncode(requests);\n ws.send(toArrayBuffer(encoded));\n } catch (err) {\n batch.forEach((item) => {\n removePending(item.req.id);\n item.reject(err);\n });\n }\n}\n\n// ============================================================================\n// WebSocket Transport (original implementation)\n// ============================================================================\n\nlet socket: WebSocket | null = null;\nlet connectionPromise: Promise<WebSocket> | null = null;\n\nconst pending = new Map<string | number, { resolve: (v: unknown) => void; reject: (e: unknown) => void }>();\nconst pendingTimeouts = new Map<string | number, ReturnType<typeof setTimeout>>();\n\n// ── Block detection (rate-limited reload) ──────────────────────────────────\n\ntype BlockedSource = \"refresh-token\" | \"rpc-http\" | \"rpc-websocket\";\n\nconst BLOCKED_HTTP_STATUSES = new Set([401, 403, 429]);\nconst BLOCKED_WS_CLOSE_CODES = new Set([1008, 1011, 1013]);\nconst BLOCKED_RETRY_THRESHOLD = 3;\nconst BLOCKED_RETRY_WINDOW_MS = 1_000;\nconst BLOCKED_RELOAD_COOLDOWN_MS = 120_000;\nconst BLOCKED_RELOAD_KEY = \"helium:blocked-reload-ts\";\n\nconst blockedAttempts = new Map<BlockedSource, { count: number; lastTs: number }>();\nlet lastBlockedReloadAt = 0;\n\nfunction shouldAutoReloadOnBlock(now: number): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n try {\n const stored = window.sessionStorage.getItem(BLOCKED_RELOAD_KEY);\n const storedTs = stored ? Number(stored) : 0;\n if (storedTs && now - storedTs < BLOCKED_RELOAD_COOLDOWN_MS) {\n return false;\n }\n window.sessionStorage.setItem(BLOCKED_RELOAD_KEY, String(now));\n return true;\n } catch {\n if (now - lastBlockedReloadAt < BLOCKED_RELOAD_COOLDOWN_MS) {\n return false;\n }\n lastBlockedReloadAt = now;\n return true;\n }\n}\n\nfunction shouldTriggerBlockedAction(source: BlockedSource, now: number): boolean {\n const state = blockedAttempts.get(source);\n if (!state || now - state.lastTs > BLOCKED_RETRY_WINDOW_MS) {\n blockedAttempts.set(source, { count: 1, lastTs: now });\n return false;\n }\n const nextCount = state.count + 1;\n blockedAttempts.set(source, { count: nextCount, lastTs: now });\n return nextCount > BLOCKED_RETRY_THRESHOLD;\n}\n\nfunction dispatchBlockedEvent(detail: { source: BlockedSource; status?: number; code?: number }): void {\n if (typeof window === \"undefined\") {\n return;\n }\n window.dispatchEvent(\n new CustomEvent(\"helium:blocked\", {\n detail,\n })\n );\n}\n\nfunction handleBlockedResponse(status: number, source: BlockedSource): void {\n if (!BLOCKED_HTTP_STATUSES.has(status)) {\n return;\n }\n const now = Date.now();\n if (!shouldTriggerBlockedAction(source, now)) {\n return;\n }\n\n dispatchBlockedEvent({ status, source });\n\n if (shouldAutoReloadOnBlock(now) && typeof window.location?.reload === \"function\") {\n window.location.reload();\n }\n}\n\nfunction handleBlockedSocketClose(code: number): void {\n if (!BLOCKED_WS_CLOSE_CODES.has(code)) {\n return;\n }\n const now = Date.now();\n if (!shouldTriggerBlockedAction(\"rpc-websocket\", now)) {\n return;\n }\n\n dispatchBlockedEvent({ code, source: \"rpc-websocket\" });\n if (shouldAutoReloadOnBlock(now) && typeof window.location?.reload === \"function\") {\n window.location.reload();\n }\n}\n\n// ── Connection resilience constants ──────────────────────────────────────────\n\n/** How long (ms) the page must be hidden before we consider the WebSocket stale. */\nconst STALE_THRESHOLD_MS = 15_000;\n\n/** Max time (ms) to wait for a WebSocket connection to open. */\nconst SOCKET_CONNECT_TIMEOUT_MS = 10_000;\n\n/** Duration (ms) to temporarily force HTTP after repeated WebSocket failures. */\nconst WS_FAILURE_HTTP_COOLDOWN_MS = 60_000;\n\n/** Max time (ms) to wait for a response before timing out a request. */\nconst REQUEST_TIMEOUT_MS = 30_000;\n\n/** Number of automatic retries on retriable connection errors. */\nconst MAX_RETRIES = 3;\n\n/** Base delay (ms) for exponential backoff between retries (doubles each attempt). */\nconst RETRY_BASE_DELAY_MS = 500;\n\n/** Maximum delay (ms) cap for backoff to avoid excessively long waits. */\nconst RETRY_MAX_DELAY_MS = 5_000;\n\n/** Timestamp when the page was last hidden (for visibility-change detection). */\nlet lastHiddenTimestamp: number | null = null;\nlet forceHttpUntilTimestamp = 0;\n\nfunction isTemporaryHttpFallbackActive(now = Date.now()): boolean {\n return now < forceHttpUntilTimestamp;\n}\n\nfunction activateTemporaryHttpFallback(now = Date.now()): void {\n forceHttpUntilTimestamp = now + WS_FAILURE_HTTP_COOLDOWN_MS;\n}\n\n// ── Pending-request helpers ──────────────────────────────────────────────────\n\n/**\n * Register a pending request with an automatic timeout safeguard.\n * If no response arrives within REQUEST_TIMEOUT_MS the promise is rejected\n * so the caller's retry logic can kick in.\n */\nfunction trackPending(id: string | number, resolve: (v: unknown) => void, reject: (e: unknown) => void): void {\n pending.set(id, { resolve, reject });\n const timer = setTimeout(() => {\n const entry = pending.get(id);\n if (entry) {\n pending.delete(id);\n pendingTimeouts.delete(id);\n entry.reject(new RpcError(\"Request timed out\"));\n }\n }, REQUEST_TIMEOUT_MS);\n pendingTimeouts.set(id, timer);\n}\n\n/**\n * Remove a pending request and clear its timeout.\n * Returns the entry so the caller can resolve/reject it.\n */\nfunction removePending(id: string | number): { resolve: (v: unknown) => void; reject: (e: unknown) => void } | undefined {\n const entry = pending.get(id);\n if (!entry) {\n return undefined;\n }\n pending.delete(id);\n const timer = pendingTimeouts.get(id);\n if (timer) {\n clearTimeout(timer);\n pendingTimeouts.delete(id);\n }\n return entry;\n}\n\n/** Reject every in-flight request (e.g. when the socket closes unexpectedly). */\nfunction rejectAllPending(reason: Error): void {\n for (const timer of pendingTimeouts.values()) {\n clearTimeout(timer);\n }\n pendingTimeouts.clear();\n const entries = [...pending.entries()];\n pending.clear();\n for (const [, entry] of entries) {\n entry.reject(reason);\n }\n}\n\n// ── Reconnection helpers ─────────────────────────────────────────────────────\n\n/**\n * Force-close the current WebSocket so the next call creates a fresh\n * connection (which fetches a brand-new token).\n */\nfunction forceReconnect(): void {\n const oldSocket = socket;\n socket = null;\n connectionPromise = null;\n\n if (oldSocket) {\n // Detach handlers to avoid double-rejecting pending from the close event\n oldSocket.onclose = null;\n oldSocket.onerror = null;\n oldSocket.onmessage = null;\n oldSocket.close();\n }\n\n // Reject all in-flight requests – callers with retry logic will resend\n rejectAllPending(new Error(\"Connection reset\"));\n}\n\nfunction reconnectIfLikelyStale(force = false): void {\n if (!socket) {\n lastHiddenTimestamp = null;\n return;\n }\n\n if (force) {\n forceReconnect();\n lastHiddenTimestamp = null;\n return;\n }\n\n if (lastHiddenTimestamp !== null) {\n const hiddenDuration = Date.now() - lastHiddenTimestamp;\n if (hiddenDuration > STALE_THRESHOLD_MS) {\n forceReconnect();\n }\n }\n\n lastHiddenTimestamp = null;\n}\n\n/** Determine whether an error warrants an automatic retry. */\nfunction isRetriableError(err: unknown): boolean {\n // Network / connection errors are always retriable\n if (err instanceof Error && !(err instanceof RpcError)) {\n return true;\n }\n // Timed-out requests are retriable (socket may have died silently)\n if (err instanceof RpcError && err.message === \"Request timed out\") {\n return true;\n }\n return false;\n}\n\n// Clean up WebSocket connection on HMR (Hot Module Replacement)\nif (import.meta.hot) {\n import.meta.hot.dispose(() => {\n if (socket) {\n socket.onclose = null;\n socket.close();\n socket = null;\n connectionPromise = null;\n }\n rejectAllPending(new Error(\"Module reloaded\"));\n });\n}\n\nlet msgId = 0;\nfunction nextId() {\n return msgId++;\n}\n\nlet cachedAuthToken: string | undefined;\n\nfunction hasCachedToken(): boolean {\n return Boolean(cachedAuthToken);\n}\n\nfunction setCachedToken(token: string | undefined): void {\n if (!token) {\n cachedAuthToken = undefined;\n return;\n }\n\n cachedAuthToken = token;\n}\n\nasync function fetchFreshToken(forceRefresh = false): Promise<string | undefined> {\n if (!forceRefresh && hasCachedToken()) {\n return cachedAuthToken;\n }\n\n try {\n const response = await fetch(\"/__helium__/refresh-token\", {\n method: \"POST\",\n headers: {\n \"X-Requested-With\": \"HeliumRPC\",\n },\n });\n handleBlockedResponse(response.status, \"refresh-token\");\n if (!response.ok) {\n console.warn(\"Failed to fetch fresh token:\", response.status);\n setCachedToken(undefined);\n return undefined;\n }\n const data = await response.json();\n const token = data.token as string | undefined;\n setCachedToken(token);\n return token;\n } catch (error) {\n console.warn(\"Error fetching fresh token:\", error);\n setCachedToken(undefined);\n return undefined;\n }\n}\n\nasync function createSocket(): Promise<WebSocket> {\n // Fetch a token before creating the WebSocket connection\n const token = await fetchFreshToken();\n\n // Use the same protocol, hostname and port as the current page\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = window.location.host; // includes hostname and port\n const url = `${protocol}//${host}/rpc`;\n // Security: pass token via Sec-WebSocket-Protocol header instead of query string\n const ws = token ? new WebSocket(url, [token]) : new WebSocket(url);\n ws.binaryType = \"arraybuffer\";\n\n ws.onmessage = async (event) => {\n let data = new Uint8Array(event.data as ArrayBuffer);\n // Check for Gzip header (0x1f 0x8b) to detect compressed messages\n if (data.length > 2 && data[0] === 0x1f && data[1] === 0x8b) {\n try {\n // Use DecompressionStream if available (Chrome 80+, Firefox 113+, Safari 16.4+)\n if (typeof DecompressionStream !== \"undefined\") {\n const ds = new DecompressionStream(\"gzip\");\n const stream = new Response(data).body;\n if (stream) {\n const decompressed = stream.pipeThrough(ds);\n const reader = decompressed.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n const MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024; // 10 MB\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n break;\n }\n totalSize += value.length;\n if (totalSize > MAX_DECOMPRESSED_SIZE) {\n reader.cancel();\n console.error(\"Decompressed message exceeds size limit\");\n return;\n }\n chunks.push(value);\n }\n const combined = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n data = combined;\n }\n }\n } catch (err) {\n console.error(\"Failed to decompress WebSocket message:\", err);\n return;\n }\n }\n\n // Always expect binary MessagePack\n const msg = msgpackDecode(data) as RpcResponse | RpcResponse[];\n\n const handleResponse = (res: RpcResponse) => {\n const entry = removePending(res.id);\n if (!entry) {\n return;\n }\n if (res.ok) {\n entry.resolve({ data: res.result, stats: res.stats });\n } else {\n entry.reject(new RpcError(res.error, res.stats));\n }\n };\n\n if (Array.isArray(msg)) {\n msg.forEach(handleResponse);\n } else {\n handleResponse(msg);\n }\n };\n\n ws.onerror = () => {\n // WebSocket errors are always followed by a close event.\n // The close handler takes care of rejecting pending promises.\n };\n\n ws.onclose = (event) => {\n handleBlockedSocketClose(event.code);\n if (socket === ws) {\n socket = null;\n connectionPromise = null;\n // Reject every in-flight request so callers can retry\n rejectAllPending(new Error(\"WebSocket connection closed\"));\n }\n };\n\n return ws;\n}\n\nfunction waitForSocketOpen(ws: WebSocket): Promise<WebSocket> {\n if (ws.readyState === WebSocket.OPEN) {\n return Promise.resolve(ws);\n }\n\n return new Promise<WebSocket>((resolve, reject) => {\n const cleanup = () => {\n ws.removeEventListener(\"open\", handleOpen);\n ws.removeEventListener(\"error\", handleError);\n ws.removeEventListener(\"close\", handleClose);\n clearTimeout(timeout);\n };\n\n const handleOpen = () => {\n cleanup();\n resolve(ws);\n };\n\n const handleError = () => {\n cleanup();\n if (socket === ws) {\n socket = null;\n }\n setCachedToken(undefined);\n reject(new Error(\"WebSocket connection failed\"));\n };\n\n const handleClose = () => {\n cleanup();\n if (socket === ws) {\n socket = null;\n }\n setCachedToken(undefined);\n reject(new Error(\"WebSocket closed before opening\"));\n };\n\n const timeout = setTimeout(() => {\n cleanup();\n if (socket === ws) {\n socket = null;\n }\n setCachedToken(undefined);\n reject(new Error(\"WebSocket connection timed out\"));\n }, SOCKET_CONNECT_TIMEOUT_MS);\n\n ws.addEventListener(\"open\", handleOpen);\n ws.addEventListener(\"error\", handleError);\n ws.addEventListener(\"close\", handleClose);\n });\n}\n\nasync function ensureSocketReady(): Promise<WebSocket> {\n // If we have an open socket, return it immediately\n if (socket && socket.readyState === WebSocket.OPEN) {\n return socket;\n }\n\n // If we have a connection in progress, reuse that promise\n if (connectionPromise) {\n return connectionPromise;\n }\n\n const pendingConnectPromise = (async () => {\n if (!socket || socket.readyState === WebSocket.CLOSED || socket.readyState === WebSocket.CLOSING) {\n socket = await createSocket();\n }\n\n return waitForSocketOpen(socket);\n })();\n\n connectionPromise = pendingConnectPromise;\n\n try {\n return await pendingConnectPromise;\n } finally {\n if (connectionPromise === pendingConnectPromise) {\n connectionPromise = null;\n }\n }\n}\n\nasync function rpcCallWebSocket<TResult, TArgs>(methodId: string, args?: TArgs): Promise<RpcResult<TResult>> {\n // Optimization: If socket is open, send immediately without awaiting ensureSocketReady (which adds a microtask tick)\n if (socket && socket.readyState === WebSocket.OPEN) {\n const id = nextId();\n const req: RpcRequest = { id, method: methodId, args };\n return new Promise<RpcResult<TResult>>((resolve, reject) => {\n trackPending(id, (v: unknown) => resolve(v as RpcResult<TResult>), reject);\n try {\n const encoded = msgpackEncode(req);\n socket!.send(toArrayBuffer(encoded));\n } catch (err) {\n removePending(id);\n reject(err);\n }\n });\n }\n\n const ws = await ensureSocketReady();\n const id = nextId();\n\n const req: RpcRequest = { id, method: methodId, args };\n\n return new Promise<RpcResult<TResult>>((resolve, reject) => {\n trackPending(id, (v: unknown) => resolve(v as RpcResult<TResult>), reject);\n try {\n // Always use msgpack encoding\n const encoded = msgpackEncode(req);\n ws.send(toArrayBuffer(encoded));\n } catch (err) {\n removePending(id);\n reject(err);\n }\n });\n}\n\n/**\n * Make an RPC call using the appropriate transport.\n * Automatically selects HTTP or WebSocket based on network conditions and configuration.\n *\n * Includes automatic retry logic: if a call fails due to a connection error\n * (e.g. stale WebSocket after mobile browser was backgrounded), the client\n * forces a fresh connection (with a new token) and retries once.\n */\nexport async function rpcCall<TResult = unknown, TArgs = unknown>(methodId: string, args?: TArgs): Promise<RpcResult<TResult>> {\n return rpcCallWithRetry<TResult, TArgs>(methodId, args);\n}\n\nasync function rpcCallViaHttpBatch<TResult, TArgs>(methodId: string, args: TArgs | undefined): Promise<RpcResult<TResult>> {\n const id = nextId();\n const req: RpcRequest = { id, method: methodId, args };\n\n return new Promise<RpcResult<TResult>>((resolve, reject) => {\n pendingBatch.push({ req, resolve: resolve as (value: RpcResult<TResult>) => void, reject });\n scheduleBatch();\n });\n}\n\nasync function rpcCallWithRetry<TResult, TArgs>(methodId: string, args: TArgs | undefined, attempt = 0): Promise<RpcResult<TResult>> {\n try {\n if (shouldUseHttpTransport()) {\n return await rpcCallViaHttpBatch<TResult, TArgs>(methodId, args);\n }\n\n return await rpcCallWebSocket<TResult, TArgs>(methodId, args);\n } catch (err) {\n if (attempt < MAX_RETRIES && isRetriableError(err)) {\n // Force a fresh connection (fetches a new token)\n forceReconnect();\n // Exponential backoff with jitter: 500ms, 1000ms, 2000ms (capped at 5s)\n const baseDelay = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS);\n const jitter = Math.random() * baseDelay * 0.3;\n await new Promise<void>((r) => setTimeout(r, baseDelay + jitter));\n return rpcCallWithRetry<TResult, TArgs>(methodId, args, attempt + 1);\n }\n\n if (isRetriableError(err) && configuredTransport !== \"http\") {\n activateTemporaryHttpFallback();\n return rpcCallViaHttpBatch<TResult, TArgs>(methodId, args);\n }\n\n throw err;\n }\n}\n\n/**\n * Pre-establishes the WebSocket connection.\n * Call this early (e.g., on page load) to avoid connection latency on first RPC call.\n * This is especially beneficial on high-latency networks like mobile LTE.\n * Note: Only effective when using WebSocket transport (not HTTP transport).\n */\nexport function preconnect(): void {\n if (typeof window === \"undefined\") {\n return;\n }\n // Only preconnect if we're using WebSocket transport\n if (shouldUseHttpTransport()) {\n return;\n }\n // Fire and forget - establishes connection in background\n ensureSocketReady().catch(() => {\n // Silently ignore preconnect failures, will retry on actual call\n });\n}\n\n// Auto-preconnect when the module loads (browser only, WebSocket transport only)\nif (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n // Use requestIdleCallback if available, otherwise setTimeout\n const schedulePreconnect = window.requestIdleCallback || ((cb: () => void) => setTimeout(cb, 1));\n schedulePreconnect(() => preconnect());\n}\n\n// ============================================================================\n// Visibility-change reconnection (critical for mobile browsers)\n// ============================================================================\n//\n// Mobile browsers freeze or kill WebSocket connections when the tab is\n// backgrounded. When the user returns the socket may *appear* open but\n// is actually stale. We detect this via the Page Visibility API and\n// proactively tear down the old connection so the next RPC call creates\n// a fresh one (with a brand-new auth token).\n// ============================================================================\n\nif (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", () => {\n if (document.hidden) {\n lastHiddenTimestamp = Date.now();\n } else {\n reconnectIfLikelyStale(false);\n }\n });\n\n document.addEventListener(\"pagehide\", () => {\n lastHiddenTimestamp = Date.now();\n });\n}\n\nif (typeof window !== \"undefined\") {\n window.addEventListener(\"pageshow\", (event) => {\n if ((event as PageTransitionEvent).persisted) {\n reconnectIfLikelyStale(true);\n return;\n }\n reconnectIfLikelyStale(false);\n });\n\n window.addEventListener(\"focus\", () => {\n reconnectIfLikelyStale(false);\n });\n\n window.addEventListener(\"online\", () => {\n reconnectIfLikelyStale(true);\n });\n}\n"]}
|