heliumts 0.6.0 → 0.6.2
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/dist/bin/helium.js +0 -0
- package/dist/client/rpcClient.d.ts.map +1 -1
- package/dist/client/rpcClient.js +65 -4
- package/dist/client/rpcClient.js.map +1 -1
- package/dist/server/config.d.ts +1 -0
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js +1 -0
- package/dist/server/config.js.map +1 -1
- package/dist/vite/heliumPlugin.d.ts.map +1 -1
- package/dist/vite/heliumPlugin.js +1 -0
- package/dist/vite/heliumPlugin.js.map +1 -1
- package/package.json +1 -1
- package/dist/server/ipExtractor.d.ts +0 -48
- package/dist/server/ipExtractor.d.ts.map +0 -1
- package/dist/server/ipExtractor.js +0 -96
- package/dist/server/ipExtractor.js.map +0 -1
- package/dist/utils/deepEqual.d.ts +0 -1
- package/dist/utils/deepEqual.d.ts.map +0 -1
- package/dist/utils/deepEqual.js +0 -2
- package/dist/utils/deepEqual.js.map +0 -1
- package/dist/utils/formatError.d.ts +0 -2
- package/dist/utils/formatError.d.ts.map +0 -1
- package/dist/utils/formatError.js +0 -18
- package/dist/utils/formatError.js.map +0 -1
package/dist/bin/helium.js
CHANGED
|
File without changes
|
|
@@ -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;
|
|
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;AAezD;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAswBD;;;;;;;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
|
@@ -11,6 +11,9 @@ function toArrayBuffer(data) {
|
|
|
11
11
|
// Read build-time config with fallback defaults
|
|
12
12
|
const configuredTransport = typeof __HELIUM_RPC_TRANSPORT__ !== "undefined" ? __HELIUM_RPC_TRANSPORT__ : "websocket";
|
|
13
13
|
const configuredAutoHttpOnMobile = typeof __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__ !== "undefined" ? __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__ : false;
|
|
14
|
+
const configuredTokenValidityMs = typeof __HELIUM_RPC_TOKEN_VALIDITY_MS__ !== "undefined" && Number.isFinite(__HELIUM_RPC_TOKEN_VALIDITY_MS__) && __HELIUM_RPC_TOKEN_VALIDITY_MS__ > 0
|
|
15
|
+
? __HELIUM_RPC_TOKEN_VALIDITY_MS__
|
|
16
|
+
: 30000;
|
|
14
17
|
/**
|
|
15
18
|
* Get the configured RPC transport mode (from helium.config.js).
|
|
16
19
|
*/
|
|
@@ -27,14 +30,23 @@ function isMobileDevice() {
|
|
|
27
30
|
if (typeof navigator === "undefined") {
|
|
28
31
|
return false;
|
|
29
32
|
}
|
|
33
|
+
const MOBILE_BREAKPOINT_MAX_WIDTH = 1024; // 1024px or less is a common breakpoint for mobile devices
|
|
30
34
|
const nav = navigator;
|
|
31
|
-
if (
|
|
32
|
-
return
|
|
35
|
+
if (nav.userAgentData?.mobile === true) {
|
|
36
|
+
return true;
|
|
33
37
|
}
|
|
34
38
|
const userAgent = navigator.userAgent || "";
|
|
35
39
|
if (/Android|iPhone|iPad|iPod|IEMobile|Opera Mini|Mobi/i.test(userAgent)) {
|
|
36
40
|
return true;
|
|
37
41
|
}
|
|
42
|
+
if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
|
|
43
|
+
if (window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT_MAX_WIDTH}px)`).matches) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (window.matchMedia("(pointer: coarse)").matches || window.matchMedia("(any-pointer: coarse)").matches) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
38
50
|
return navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
|
|
39
51
|
}
|
|
40
52
|
// Detect if we should prefer HTTP transport (mobile/slow networks)
|
|
@@ -42,10 +54,10 @@ function shouldUseHttpTransport() {
|
|
|
42
54
|
if (isTemporaryHttpFallbackActive()) {
|
|
43
55
|
return true;
|
|
44
56
|
}
|
|
45
|
-
if (
|
|
57
|
+
if (isMobileDevice()) {
|
|
46
58
|
return true;
|
|
47
59
|
}
|
|
48
|
-
if (
|
|
60
|
+
if (configuredTransport === "http") {
|
|
49
61
|
return true;
|
|
50
62
|
}
|
|
51
63
|
if (configuredTransport === "websocket") {
|
|
@@ -376,6 +388,7 @@ if (import.meta.hot) {
|
|
|
376
388
|
socket = null;
|
|
377
389
|
connectionPromise = null;
|
|
378
390
|
}
|
|
391
|
+
clearTokenRefreshTimer();
|
|
379
392
|
rejectAllPending(new Error("Module reloaded"));
|
|
380
393
|
});
|
|
381
394
|
}
|
|
@@ -384,15 +397,63 @@ function nextId() {
|
|
|
384
397
|
return msgId++;
|
|
385
398
|
}
|
|
386
399
|
let cachedAuthToken;
|
|
400
|
+
let tokenRefreshTimer = null;
|
|
401
|
+
const TOKEN_REFRESH_MIN_DELAY_MS = 5000;
|
|
402
|
+
const TOKEN_REFRESH_RETRY_DELAY_MS = 5000;
|
|
403
|
+
const TOKEN_REFRESH_SAFETY_WINDOW_MS = Math.min(5000, Math.max(1000, Math.floor(configuredTokenValidityMs * 0.2)));
|
|
404
|
+
function clearTokenRefreshTimer() {
|
|
405
|
+
if (!tokenRefreshTimer) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
clearTimeout(tokenRefreshTimer);
|
|
409
|
+
tokenRefreshTimer = null;
|
|
410
|
+
}
|
|
411
|
+
function parseTokenIssuedAt(token) {
|
|
412
|
+
const [timestampPart] = token.split(".");
|
|
413
|
+
if (!timestampPart) {
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
const issuedAt = Number.parseInt(timestampPart, 10);
|
|
417
|
+
if (!Number.isFinite(issuedAt) || issuedAt <= 0) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
return issuedAt;
|
|
421
|
+
}
|
|
422
|
+
function scheduleTokenRefreshFromToken(token) {
|
|
423
|
+
if (typeof window === "undefined") {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
const issuedAt = parseTokenIssuedAt(token);
|
|
427
|
+
if (!issuedAt) {
|
|
428
|
+
clearTokenRefreshTimer();
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const expiresAt = issuedAt + configuredTokenValidityMs;
|
|
432
|
+
const refreshAt = expiresAt - TOKEN_REFRESH_SAFETY_WINDOW_MS;
|
|
433
|
+
const delay = Math.max(TOKEN_REFRESH_MIN_DELAY_MS, refreshAt - Date.now());
|
|
434
|
+
clearTokenRefreshTimer();
|
|
435
|
+
tokenRefreshTimer = setTimeout(() => {
|
|
436
|
+
void fetchFreshToken(true).then((nextToken) => {
|
|
437
|
+
if (!nextToken) {
|
|
438
|
+
clearTokenRefreshTimer();
|
|
439
|
+
tokenRefreshTimer = setTimeout(() => {
|
|
440
|
+
void fetchFreshToken(true);
|
|
441
|
+
}, TOKEN_REFRESH_RETRY_DELAY_MS);
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
}, delay);
|
|
445
|
+
}
|
|
387
446
|
function hasCachedToken() {
|
|
388
447
|
return Boolean(cachedAuthToken);
|
|
389
448
|
}
|
|
390
449
|
function setCachedToken(token) {
|
|
391
450
|
if (!token) {
|
|
392
451
|
cachedAuthToken = undefined;
|
|
452
|
+
clearTokenRefreshTimer();
|
|
393
453
|
return;
|
|
394
454
|
}
|
|
395
455
|
cachedAuthToken = token;
|
|
456
|
+
scheduleTokenRefreshFromToken(token);
|
|
396
457
|
}
|
|
397
458
|
async function fetchFreshToken(forceRefresh = false) {
|
|
398
459
|
if (!forceRefresh && hasCachedToken()) {
|
|
@@ -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 (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"]}
|
|
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;\ndeclare const __HELIUM_RPC_TOKEN_VALIDITY_MS__: number;\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;\nconst configuredTokenValidityMs: number =\n typeof __HELIUM_RPC_TOKEN_VALIDITY_MS__ !== \"undefined\" && Number.isFinite(__HELIUM_RPC_TOKEN_VALIDITY_MS__) && __HELIUM_RPC_TOKEN_VALIDITY_MS__ > 0\n ? __HELIUM_RPC_TOKEN_VALIDITY_MS__\n : 30_000;\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 MOBILE_BREAKPOINT_MAX_WIDTH = 1024; // 1024px or less is a common breakpoint for mobile devices\n\n const nav = navigator as NavigatorWithConnection;\n if (nav.userAgentData?.mobile === true) {\n return true;\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 if (typeof window !== \"undefined\" && typeof window.matchMedia === \"function\") {\n if (window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT_MAX_WIDTH}px)`).matches) {\n return true;\n }\n\n if (window.matchMedia(\"(pointer: coarse)\").matches || window.matchMedia(\"(any-pointer: coarse)\").matches) {\n return true;\n }\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 (isMobileDevice()) {\n return true;\n }\n\n if (configuredTransport === \"http\") {\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 clearTokenRefreshTimer();\n rejectAllPending(new Error(\"Module reloaded\"));\n });\n}\n\nlet msgId = 0;\nfunction nextId() {\n return msgId++;\n}\n\nlet cachedAuthToken: string | undefined;\nlet tokenRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n\nconst TOKEN_REFRESH_MIN_DELAY_MS = 5_000;\nconst TOKEN_REFRESH_RETRY_DELAY_MS = 5_000;\nconst TOKEN_REFRESH_SAFETY_WINDOW_MS = Math.min(5_000, Math.max(1_000, Math.floor(configuredTokenValidityMs * 0.2)));\n\nfunction clearTokenRefreshTimer(): void {\n if (!tokenRefreshTimer) {\n return;\n }\n clearTimeout(tokenRefreshTimer);\n tokenRefreshTimer = null;\n}\n\nfunction parseTokenIssuedAt(token: string): number | null {\n const [timestampPart] = token.split(\".\");\n if (!timestampPart) {\n return null;\n }\n const issuedAt = Number.parseInt(timestampPart, 10);\n if (!Number.isFinite(issuedAt) || issuedAt <= 0) {\n return null;\n }\n return issuedAt;\n}\n\nfunction scheduleTokenRefreshFromToken(token: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n const issuedAt = parseTokenIssuedAt(token);\n if (!issuedAt) {\n clearTokenRefreshTimer();\n return;\n }\n\n const expiresAt = issuedAt + configuredTokenValidityMs;\n const refreshAt = expiresAt - TOKEN_REFRESH_SAFETY_WINDOW_MS;\n const delay = Math.max(TOKEN_REFRESH_MIN_DELAY_MS, refreshAt - Date.now());\n\n clearTokenRefreshTimer();\n tokenRefreshTimer = setTimeout(() => {\n void fetchFreshToken(true).then((nextToken) => {\n if (!nextToken) {\n clearTokenRefreshTimer();\n tokenRefreshTimer = setTimeout(() => {\n void fetchFreshToken(true);\n }, TOKEN_REFRESH_RETRY_DELAY_MS);\n }\n });\n }, delay);\n}\n\nfunction hasCachedToken(): boolean {\n return Boolean(cachedAuthToken);\n}\n\nfunction setCachedToken(token: string | undefined): void {\n if (!token) {\n cachedAuthToken = undefined;\n clearTokenRefreshTimer();\n return;\n }\n\n cachedAuthToken = token;\n scheduleTokenRefreshFromToken(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"]}
|
package/dist/server/config.d.ts
CHANGED
|
@@ -254,6 +254,7 @@ export declare function getRpcConfig(config?: HeliumConfig): {
|
|
|
254
254
|
export interface RpcClientTransportConfig {
|
|
255
255
|
transport: "http" | "websocket" | "auto";
|
|
256
256
|
autoHttpOnMobile: boolean;
|
|
257
|
+
tokenValidityMs: number;
|
|
257
258
|
}
|
|
258
259
|
/**
|
|
259
260
|
* Get client-side RPC transport configuration.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACpC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACpC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAEhC;;;;;OAKG;IACH,GAAG,CAAC,EAAE;QACF;;;;;;;;;;;;;;;;;;WAkBG;QACH,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;QAE1C;;;;;;;;;WASG;QACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAE3B;;;;;WAKG;QACH,WAAW,CAAC,EAAE,uBAAuB,CAAC;QAEtC;;;;;WAKG;QACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;QAEnC;;;;;WAKG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;;;;WAKG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;QAEtB;;;;;WAKG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACL;AAgBD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuCpF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,YAAiB,GAAG,MAAM,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,YAAiB,GAAG,QAAQ,CAAC,uBAAuB,CAAC,CASjG;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,YAAiB,GAAG,QAAQ,CAAC,uBAAuB,CAAC,CAOjG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,GAAE,YAAiB;;;;;;EAQrD;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACrC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IACzC,gBAAgB,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACpC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACpC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAEhC;;;;;OAKG;IACH,GAAG,CAAC,EAAE;QACF;;;;;;;;;;;;;;;;;;WAkBG;QACH,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;QAE1C;;;;;;;;;WASG;QACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAE3B;;;;;WAKG;QACH,WAAW,CAAC,EAAE,uBAAuB,CAAC;QAEtC;;;;;WAKG;QACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;QAEnC;;;;;WAKG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;;;;WAKG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;QAEtB;;;;;WAKG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACL;AAgBD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuCpF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,YAAiB,GAAG,MAAM,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,YAAiB,GAAG,QAAQ,CAAC,uBAAuB,CAAC,CASjG;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,YAAiB,GAAG,QAAQ,CAAC,uBAAuB,CAAC,CAOjG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,GAAE,YAAiB;;;;;;EAQrD;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACrC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IACzC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,YAAiB,GAAG,wBAAwB,CAMtF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,SAE/B"}
|
package/dist/server/config.js
CHANGED
|
@@ -119,6 +119,7 @@ export function getRpcClientConfig(config = {}) {
|
|
|
119
119
|
return {
|
|
120
120
|
transport: config.rpc?.transport ?? "websocket",
|
|
121
121
|
autoHttpOnMobile: config.rpc?.autoHttpOnMobile ?? false,
|
|
122
|
+
tokenValidityMs: getRpcSecurityConfig(config).tokenValidityMs,
|
|
122
123
|
};
|
|
123
124
|
}
|
|
124
125
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { pathToFileURL } from \"url\";\n\n/**\n * WebSocket per-message compression configuration.\n * Uses the permessage-deflate extension to compress messages on the wire.\n */\nexport interface HeliumCompressionConfig {\n /**\n * Enable WebSocket per-message compression (permessage-deflate extension).\n * When enabled, messages are compressed before sending to reduce bandwidth usage.\n *\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Minimum message size in bytes to apply compression.\n * Messages smaller than this threshold will not be compressed to avoid overhead.\n * Only applies when compression is enabled.\n *\n * @default 1024 (1KB)\n */\n threshold?: number;\n}\n\n/**\n * RPC security and rate limiting configuration.\n * Controls WebSocket connection limits, message rate limits, and token-based authentication.\n */\nexport interface HeliumRpcSecurityConfig {\n /**\n * Maximum number of concurrent WebSocket connections allowed per IP address.\n * Helps prevent a single client from exhausting connection resources.\n * Set to 0 to disable this limit.\n *\n * @default 10\n */\n maxConnectionsPerIP?: number;\n\n /**\n * Maximum number of RPC messages allowed per connection within the time window.\n * Helps prevent abuse by limiting message throughput per connection.\n * Set to 0 to disable rate limiting.\n *\n * @default 100\n */\n maxMessagesPerWindow?: number;\n\n /**\n * Time window in milliseconds for rate limiting.\n * Rate limits reset after this duration.\n *\n * @default 60000 (1 minute)\n */\n rateLimitWindowMs?: number;\n\n /**\n * WebSocket connection token validity duration in milliseconds.\n * Tokens are generated server-side and must be used within this timeframe.\n * Shorter durations improve security but may cause issues with slow networks.\n *\n * @default 30000 (30 seconds)\n */\n tokenValidityMs?: number;\n}\n\n/**\n * Security configuration for HTTP responses.\n */\nexport interface HeliumSecurityConfig {\n /**\n * Content-Security-Policy header value.\n * Set to a CSP string to enable, or omit to skip CSP.\n *\n * @default undefined (no CSP header)\n */\n contentSecurityPolicy?: string;\n\n /**\n * Enable Strict-Transport-Security header.\n * Set to false to disable HSTS.\n *\n * @default true\n */\n hsts?: boolean;\n\n /**\n * Allowed CORS origins.\n * Set to [\"*\"] to allow all origins, or provide specific origins.\n * Empty array or omit to restrict to same-origin only (default, most secure).\n *\n * @default [] (same-origin only)\n */\n corsOrigins?: string[];\n}\n\n/**\n * Helium framework configuration.\n *\n * Configure your Helium application behavior including RPC transport settings,\n * compression, security, and proxy configuration for production deployments.\n */\nexport interface HeliumConfig {\n /**\n * Number of proxy levels to trust when extracting client IP addresses.\n *\n * This setting is crucial for deployments behind reverse proxies, load balancers,\n * or CDNs (like Vercel, Cloudflare, AWS ALB, etc.). It determines how the framework\n * extracts the real client IP from headers like X-Forwarded-For.\n *\n * **How it works:**\n * When behind proxies, the X-Forwarded-For header contains a chain of IPs:\n * `X-Forwarded-For: <client-ip>, <proxy1-ip>, <proxy2-ip>`\n *\n * This setting tells Helium how many proxy IPs to skip from the right to find the real client IP.\n *\n * **Values:**\n * - `0`: Don't trust any proxies, use direct connection IP (default, most secure)\n * - `1`: Trust 1 proxy level (recommended for most platforms: Vercel, Netlify, Railway)\n * - `2+`: Trust multiple proxy levels (for complex setups like Cloudflare → Load Balancer → Your Server)\n *\n * **Common configurations:**\n * - Local development: `0`\n * - Vercel/Netlify/Railway: `1`\n * - Cloudflare → Your server: `1` or `2`\n * - AWS ALB → EC2: `1`\n * - Nginx → Node.js: `1`\n * - Cloudflare → AWS ALB → EC2: `2`\n *\n * **Security note:** Setting this too high can allow IP spoofing. Only trust as many\n * proxy levels as you actually have in your infrastructure.\n *\n * This setting applies to both HTTP requests and WebSocket connections.\n *\n * @default 0\n */\n trustProxyDepth?: number;\n\n /**\n * HTTP response security configuration.\n * Controls CORS, CSP, HSTS, and other security headers.\n */\n security?: HeliumSecurityConfig;\n\n /**\n * RPC transport configuration.\n *\n * Configure the WebSocket-based RPC layer including compression\n * and security settings.\n */\n rpc?: {\n /**\n * Client-side transport mode for RPC calls.\n *\n * - `\"websocket\"` (default): Uses persistent WebSocket connection\n * - ✅ Lower latency for subsequent calls (connection reuse)\n * - ✅ Real-time bidirectional communication ready\n * - ⚠️ Higher initial connection overhead\n *\n * - `\"http\"`: Uses HTTP POST requests for each RPC call\n * - ✅ Better performance on mobile/cellular networks (HTTP/2 optimizations)\n * - ✅ No connection state to maintain\n * - ⚠️ Slightly higher per-request overhead on fast networks\n *\n * - `\"auto\"`: Automatically selects based on network conditions\n * - Uses HTTP on cellular/slow networks when `autoHttpOnMobile` is true\n * - Uses WebSocket on fast networks (WiFi, wired)\n *\n * @default \"websocket\"\n */\n transport?: \"http\" | \"websocket\" | \"auto\";\n\n /**\n * Automatically switch to HTTP transport on mobile/cellular networks.\n *\n * When enabled and `transport` is `\"auto\"`, the client will use HTTP\n * instead of WebSocket on cellular connections (4G/LTE, 5G) and slow\n * connections (2G, 3G). This improves performance on mobile networks\n * where HTTP/2 is more efficient due to carrier network optimizations.\n *\n * @default false\n */\n autoHttpOnMobile?: boolean;\n\n /**\n * WebSocket per-message compression configuration.\n *\n * Enable and configure the permessage-deflate extension to compress\n * messages on the wire, reducing bandwidth usage.\n */\n compression?: HeliumCompressionConfig;\n\n /**\n * RPC security and rate limiting configuration.\n *\n * Configure connection limits, message rate limits, and token validity\n * to protect your RPC endpoints from abuse.\n */\n security?: HeliumRpcSecurityConfig;\n\n /**\n * Maximum HTTP request body size in bytes.\n * Requests exceeding this limit receive a 413 status.\n *\n * @default 1048576 (1 MB)\n */\n maxBodySize?: number;\n\n /**\n * Maximum number of RPC calls in a single batch request.\n * Batches exceeding this limit are rejected.\n *\n * @default 20\n */\n maxBatchSize?: number;\n\n /**\n * Maximum WebSocket message payload size in bytes.\n * Messages exceeding this limit cause the connection to be closed.\n *\n * @default 1048576 (1 MB)\n */\n maxWsPayload?: number;\n };\n}\n\nconst DEFAULT_RPC_SECURITY: Required<HeliumRpcSecurityConfig> = {\n maxConnectionsPerIP: 10,\n maxMessagesPerWindow: 100,\n rateLimitWindowMs: 60000,\n tokenValidityMs: 30000,\n};\n\nconst DEFAULT_COMPRESSION: Required<HeliumCompressionConfig> = {\n enabled: true,\n threshold: 1024,\n};\n\nlet cachedConfig: HeliumConfig | null = null;\n\n/**\n * Load Helium configuration from the project root.\n * Searches for helium.config.js, helium.config.mjs, or helium.config.ts.\n * Results are cached for the lifetime of the process.\n *\n * In production, the build process automatically transpiles .ts config files\n * to .js in the dist directory. The loader checks dist/ first when available.\n *\n * @internal - Used by framework internals only\n */\nexport async function loadConfig(root: string = process.cwd()): Promise<HeliumConfig> {\n if (cachedConfig) {\n return cachedConfig;\n }\n\n // Check if there's a custom config directory (used in production)\n const configDir = process.env.HELIUM_CONFIG_DIR || root;\n\n // Prioritize .js/.mjs (work in both dev and production)\n // .ts files work in dev with Vite but fail in production without transpilation\n const configFiles = [\"helium.config.js\", \"helium.config.mjs\", \"helium.config.ts\"];\n\n // In production with HELIUM_CONFIG_DIR set, check dist directory first\n const searchPaths = configDir !== root ? [configDir, root] : [root];\n\n for (const searchPath of searchPaths) {\n for (const configFile of configFiles) {\n const configPath = path.join(searchPath, configFile);\n if (fs.existsSync(configPath)) {\n try {\n const fileUrl = pathToFileURL(configPath).href;\n const module = await import(/* @vite-ignore */ `${fileUrl}?t=${Date.now()}`);\n const config = module.default || {};\n cachedConfig = config;\n return config;\n } catch (err) {\n // In production, .ts files will fail to load without a TypeScript loader\n if (configFile.endsWith(\".ts\") && err instanceof Error && \"code\" in err && err.code === \"ERR_UNKNOWN_FILE_EXTENSION\") {\n console.warn(`[Helium] Cannot load ${configFile} in production. The build process should have transpiled it.`);\n } else {\n console.warn(`[Helium] Failed to load config from ${configFile}:`, err);\n }\n }\n }\n }\n }\n\n cachedConfig = {};\n return cachedConfig;\n}\n\n/**\n * Get the proxy trust depth from config.\n * Used for extracting client IPs from X-Forwarded-For headers.\n *\n * @internal - Used by framework internals only\n */\nexport function getTrustProxyDepth(config: HeliumConfig = {}): number {\n return config.trustProxyDepth ?? 0;\n}\n\n/**\n * Get RPC security configuration with defaults applied.\n * Returns rate limiting, connection limits, and token settings.\n *\n * @internal - Used by framework internals only\n */\nexport function getRpcSecurityConfig(config: HeliumConfig = {}): Required<HeliumRpcSecurityConfig> {\n const src = config.rpc?.security;\n\n return {\n maxConnectionsPerIP: src?.maxConnectionsPerIP ?? DEFAULT_RPC_SECURITY.maxConnectionsPerIP,\n maxMessagesPerWindow: src?.maxMessagesPerWindow ?? DEFAULT_RPC_SECURITY.maxMessagesPerWindow,\n rateLimitWindowMs: src?.rateLimitWindowMs ?? DEFAULT_RPC_SECURITY.rateLimitWindowMs,\n tokenValidityMs: src?.tokenValidityMs ?? DEFAULT_RPC_SECURITY.tokenValidityMs,\n };\n}\n\n/**\n * Get WebSocket compression configuration with defaults applied.\n *\n * @internal - Used by framework internals only\n */\nexport function getCompressionConfig(config: HeliumConfig = {}): Required<HeliumCompressionConfig> {\n const src = config.rpc?.compression;\n\n return {\n enabled: src?.enabled ?? DEFAULT_COMPRESSION.enabled,\n threshold: src?.threshold ?? DEFAULT_COMPRESSION.threshold,\n };\n}\n\n/**\n * Get complete RPC configuration including compression, and security.\n *\n * @internal - Used by framework internals only\n */\nexport function getRpcConfig(config: HeliumConfig = {}) {\n return {\n compression: getCompressionConfig(config),\n security: getRpcSecurityConfig(config),\n maxBodySize: config.rpc?.maxBodySize ?? 1_048_576,\n maxBatchSize: config.rpc?.maxBatchSize ?? 20,\n maxWsPayload: config.rpc?.maxWsPayload ?? 1_048_576,\n };\n}\n\n/**\n * Client-side RPC transport configuration.\n * This is injected into the client bundle at build time.\n */\nexport interface RpcClientTransportConfig {\n transport: \"http\" | \"websocket\" | \"auto\";\n autoHttpOnMobile: boolean;\n}\n\n/**\n * Get client-side RPC transport configuration.\n * This configuration is injected into the client bundle via Vite defines.\n *\n * @internal - Used by framework internals only\n */\nexport function getRpcClientConfig(config: HeliumConfig = {}): RpcClientTransportConfig {\n return {\n transport: config.rpc?.transport ?? \"websocket\",\n autoHttpOnMobile: config.rpc?.autoHttpOnMobile ?? false,\n };\n}\n\n/**\n * Clear the cached configuration.\n * Useful for testing or when you need to reload config.\n *\n * @internal - Used by framework internals only\n */\nexport function clearConfigCache() {\n cachedConfig = null;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { pathToFileURL } from \"url\";\n\n/**\n * WebSocket per-message compression configuration.\n * Uses the permessage-deflate extension to compress messages on the wire.\n */\nexport interface HeliumCompressionConfig {\n /**\n * Enable WebSocket per-message compression (permessage-deflate extension).\n * When enabled, messages are compressed before sending to reduce bandwidth usage.\n *\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Minimum message size in bytes to apply compression.\n * Messages smaller than this threshold will not be compressed to avoid overhead.\n * Only applies when compression is enabled.\n *\n * @default 1024 (1KB)\n */\n threshold?: number;\n}\n\n/**\n * RPC security and rate limiting configuration.\n * Controls WebSocket connection limits, message rate limits, and token-based authentication.\n */\nexport interface HeliumRpcSecurityConfig {\n /**\n * Maximum number of concurrent WebSocket connections allowed per IP address.\n * Helps prevent a single client from exhausting connection resources.\n * Set to 0 to disable this limit.\n *\n * @default 10\n */\n maxConnectionsPerIP?: number;\n\n /**\n * Maximum number of RPC messages allowed per connection within the time window.\n * Helps prevent abuse by limiting message throughput per connection.\n * Set to 0 to disable rate limiting.\n *\n * @default 100\n */\n maxMessagesPerWindow?: number;\n\n /**\n * Time window in milliseconds for rate limiting.\n * Rate limits reset after this duration.\n *\n * @default 60000 (1 minute)\n */\n rateLimitWindowMs?: number;\n\n /**\n * WebSocket connection token validity duration in milliseconds.\n * Tokens are generated server-side and must be used within this timeframe.\n * Shorter durations improve security but may cause issues with slow networks.\n *\n * @default 30000 (30 seconds)\n */\n tokenValidityMs?: number;\n}\n\n/**\n * Security configuration for HTTP responses.\n */\nexport interface HeliumSecurityConfig {\n /**\n * Content-Security-Policy header value.\n * Set to a CSP string to enable, or omit to skip CSP.\n *\n * @default undefined (no CSP header)\n */\n contentSecurityPolicy?: string;\n\n /**\n * Enable Strict-Transport-Security header.\n * Set to false to disable HSTS.\n *\n * @default true\n */\n hsts?: boolean;\n\n /**\n * Allowed CORS origins.\n * Set to [\"*\"] to allow all origins, or provide specific origins.\n * Empty array or omit to restrict to same-origin only (default, most secure).\n *\n * @default [] (same-origin only)\n */\n corsOrigins?: string[];\n}\n\n/**\n * Helium framework configuration.\n *\n * Configure your Helium application behavior including RPC transport settings,\n * compression, security, and proxy configuration for production deployments.\n */\nexport interface HeliumConfig {\n /**\n * Number of proxy levels to trust when extracting client IP addresses.\n *\n * This setting is crucial for deployments behind reverse proxies, load balancers,\n * or CDNs (like Vercel, Cloudflare, AWS ALB, etc.). It determines how the framework\n * extracts the real client IP from headers like X-Forwarded-For.\n *\n * **How it works:**\n * When behind proxies, the X-Forwarded-For header contains a chain of IPs:\n * `X-Forwarded-For: <client-ip>, <proxy1-ip>, <proxy2-ip>`\n *\n * This setting tells Helium how many proxy IPs to skip from the right to find the real client IP.\n *\n * **Values:**\n * - `0`: Don't trust any proxies, use direct connection IP (default, most secure)\n * - `1`: Trust 1 proxy level (recommended for most platforms: Vercel, Netlify, Railway)\n * - `2+`: Trust multiple proxy levels (for complex setups like Cloudflare → Load Balancer → Your Server)\n *\n * **Common configurations:**\n * - Local development: `0`\n * - Vercel/Netlify/Railway: `1`\n * - Cloudflare → Your server: `1` or `2`\n * - AWS ALB → EC2: `1`\n * - Nginx → Node.js: `1`\n * - Cloudflare → AWS ALB → EC2: `2`\n *\n * **Security note:** Setting this too high can allow IP spoofing. Only trust as many\n * proxy levels as you actually have in your infrastructure.\n *\n * This setting applies to both HTTP requests and WebSocket connections.\n *\n * @default 0\n */\n trustProxyDepth?: number;\n\n /**\n * HTTP response security configuration.\n * Controls CORS, CSP, HSTS, and other security headers.\n */\n security?: HeliumSecurityConfig;\n\n /**\n * RPC transport configuration.\n *\n * Configure the WebSocket-based RPC layer including compression\n * and security settings.\n */\n rpc?: {\n /**\n * Client-side transport mode for RPC calls.\n *\n * - `\"websocket\"` (default): Uses persistent WebSocket connection\n * - ✅ Lower latency for subsequent calls (connection reuse)\n * - ✅ Real-time bidirectional communication ready\n * - ⚠️ Higher initial connection overhead\n *\n * - `\"http\"`: Uses HTTP POST requests for each RPC call\n * - ✅ Better performance on mobile/cellular networks (HTTP/2 optimizations)\n * - ✅ No connection state to maintain\n * - ⚠️ Slightly higher per-request overhead on fast networks\n *\n * - `\"auto\"`: Automatically selects based on network conditions\n * - Uses HTTP on cellular/slow networks when `autoHttpOnMobile` is true\n * - Uses WebSocket on fast networks (WiFi, wired)\n *\n * @default \"websocket\"\n */\n transport?: \"http\" | \"websocket\" | \"auto\";\n\n /**\n * Automatically switch to HTTP transport on mobile/cellular networks.\n *\n * When enabled and `transport` is `\"auto\"`, the client will use HTTP\n * instead of WebSocket on cellular connections (4G/LTE, 5G) and slow\n * connections (2G, 3G). This improves performance on mobile networks\n * where HTTP/2 is more efficient due to carrier network optimizations.\n *\n * @default false\n */\n autoHttpOnMobile?: boolean;\n\n /**\n * WebSocket per-message compression configuration.\n *\n * Enable and configure the permessage-deflate extension to compress\n * messages on the wire, reducing bandwidth usage.\n */\n compression?: HeliumCompressionConfig;\n\n /**\n * RPC security and rate limiting configuration.\n *\n * Configure connection limits, message rate limits, and token validity\n * to protect your RPC endpoints from abuse.\n */\n security?: HeliumRpcSecurityConfig;\n\n /**\n * Maximum HTTP request body size in bytes.\n * Requests exceeding this limit receive a 413 status.\n *\n * @default 1048576 (1 MB)\n */\n maxBodySize?: number;\n\n /**\n * Maximum number of RPC calls in a single batch request.\n * Batches exceeding this limit are rejected.\n *\n * @default 20\n */\n maxBatchSize?: number;\n\n /**\n * Maximum WebSocket message payload size in bytes.\n * Messages exceeding this limit cause the connection to be closed.\n *\n * @default 1048576 (1 MB)\n */\n maxWsPayload?: number;\n };\n}\n\nconst DEFAULT_RPC_SECURITY: Required<HeliumRpcSecurityConfig> = {\n maxConnectionsPerIP: 10,\n maxMessagesPerWindow: 100,\n rateLimitWindowMs: 60000,\n tokenValidityMs: 30000,\n};\n\nconst DEFAULT_COMPRESSION: Required<HeliumCompressionConfig> = {\n enabled: true,\n threshold: 1024,\n};\n\nlet cachedConfig: HeliumConfig | null = null;\n\n/**\n * Load Helium configuration from the project root.\n * Searches for helium.config.js, helium.config.mjs, or helium.config.ts.\n * Results are cached for the lifetime of the process.\n *\n * In production, the build process automatically transpiles .ts config files\n * to .js in the dist directory. The loader checks dist/ first when available.\n *\n * @internal - Used by framework internals only\n */\nexport async function loadConfig(root: string = process.cwd()): Promise<HeliumConfig> {\n if (cachedConfig) {\n return cachedConfig;\n }\n\n // Check if there's a custom config directory (used in production)\n const configDir = process.env.HELIUM_CONFIG_DIR || root;\n\n // Prioritize .js/.mjs (work in both dev and production)\n // .ts files work in dev with Vite but fail in production without transpilation\n const configFiles = [\"helium.config.js\", \"helium.config.mjs\", \"helium.config.ts\"];\n\n // In production with HELIUM_CONFIG_DIR set, check dist directory first\n const searchPaths = configDir !== root ? [configDir, root] : [root];\n\n for (const searchPath of searchPaths) {\n for (const configFile of configFiles) {\n const configPath = path.join(searchPath, configFile);\n if (fs.existsSync(configPath)) {\n try {\n const fileUrl = pathToFileURL(configPath).href;\n const module = await import(/* @vite-ignore */ `${fileUrl}?t=${Date.now()}`);\n const config = module.default || {};\n cachedConfig = config;\n return config;\n } catch (err) {\n // In production, .ts files will fail to load without a TypeScript loader\n if (configFile.endsWith(\".ts\") && err instanceof Error && \"code\" in err && err.code === \"ERR_UNKNOWN_FILE_EXTENSION\") {\n console.warn(`[Helium] Cannot load ${configFile} in production. The build process should have transpiled it.`);\n } else {\n console.warn(`[Helium] Failed to load config from ${configFile}:`, err);\n }\n }\n }\n }\n }\n\n cachedConfig = {};\n return cachedConfig;\n}\n\n/**\n * Get the proxy trust depth from config.\n * Used for extracting client IPs from X-Forwarded-For headers.\n *\n * @internal - Used by framework internals only\n */\nexport function getTrustProxyDepth(config: HeliumConfig = {}): number {\n return config.trustProxyDepth ?? 0;\n}\n\n/**\n * Get RPC security configuration with defaults applied.\n * Returns rate limiting, connection limits, and token settings.\n *\n * @internal - Used by framework internals only\n */\nexport function getRpcSecurityConfig(config: HeliumConfig = {}): Required<HeliumRpcSecurityConfig> {\n const src = config.rpc?.security;\n\n return {\n maxConnectionsPerIP: src?.maxConnectionsPerIP ?? DEFAULT_RPC_SECURITY.maxConnectionsPerIP,\n maxMessagesPerWindow: src?.maxMessagesPerWindow ?? DEFAULT_RPC_SECURITY.maxMessagesPerWindow,\n rateLimitWindowMs: src?.rateLimitWindowMs ?? DEFAULT_RPC_SECURITY.rateLimitWindowMs,\n tokenValidityMs: src?.tokenValidityMs ?? DEFAULT_RPC_SECURITY.tokenValidityMs,\n };\n}\n\n/**\n * Get WebSocket compression configuration with defaults applied.\n *\n * @internal - Used by framework internals only\n */\nexport function getCompressionConfig(config: HeliumConfig = {}): Required<HeliumCompressionConfig> {\n const src = config.rpc?.compression;\n\n return {\n enabled: src?.enabled ?? DEFAULT_COMPRESSION.enabled,\n threshold: src?.threshold ?? DEFAULT_COMPRESSION.threshold,\n };\n}\n\n/**\n * Get complete RPC configuration including compression, and security.\n *\n * @internal - Used by framework internals only\n */\nexport function getRpcConfig(config: HeliumConfig = {}) {\n return {\n compression: getCompressionConfig(config),\n security: getRpcSecurityConfig(config),\n maxBodySize: config.rpc?.maxBodySize ?? 1_048_576,\n maxBatchSize: config.rpc?.maxBatchSize ?? 20,\n maxWsPayload: config.rpc?.maxWsPayload ?? 1_048_576,\n };\n}\n\n/**\n * Client-side RPC transport configuration.\n * This is injected into the client bundle at build time.\n */\nexport interface RpcClientTransportConfig {\n transport: \"http\" | \"websocket\" | \"auto\";\n autoHttpOnMobile: boolean;\n tokenValidityMs: number;\n}\n\n/**\n * Get client-side RPC transport configuration.\n * This configuration is injected into the client bundle via Vite defines.\n *\n * @internal - Used by framework internals only\n */\nexport function getRpcClientConfig(config: HeliumConfig = {}): RpcClientTransportConfig {\n return {\n transport: config.rpc?.transport ?? \"websocket\",\n autoHttpOnMobile: config.rpc?.autoHttpOnMobile ?? false,\n tokenValidityMs: getRpcSecurityConfig(config).tokenValidityMs,\n };\n}\n\n/**\n * Clear the cached configuration.\n * Useful for testing or when you need to reload config.\n *\n * @internal - Used by framework internals only\n */\nexport function clearConfigCache() {\n cachedConfig = null;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heliumPlugin.d.ts","sourceRoot":"","sources":["../../src/vite/heliumPlugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAkBnC,MAAM,CAAC,OAAO,UAAU,MAAM,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"heliumPlugin.d.ts","sourceRoot":"","sources":["../../src/vite/heliumPlugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAkBnC,MAAM,CAAC,OAAO,UAAU,MAAM,IAAI,MAAM,CAqavC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAiBrG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAUhD"}
|
|
@@ -105,6 +105,7 @@ export default function helium() {
|
|
|
105
105
|
...envDefines,
|
|
106
106
|
__HELIUM_RPC_TRANSPORT__: JSON.stringify(rpcClientConfig.transport),
|
|
107
107
|
__HELIUM_RPC_AUTO_HTTP_ON_MOBILE__: JSON.stringify(rpcClientConfig.autoHttpOnMobile),
|
|
108
|
+
__HELIUM_RPC_TOKEN_VALIDITY_MS__: JSON.stringify(rpcClientConfig.tokenValidityMs),
|
|
108
109
|
},
|
|
109
110
|
};
|
|
110
111
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heliumPlugin.js","sourceRoot":"","sources":["../../src/vite/heliumPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { Plugin } from \"vite\";\n\nimport { clearConfigCache, getRpcClientConfig, loadConfig } from \"../server/config.js\";\nimport { attachToDevServer } from \"../server/devServer.js\";\nimport { createEnvDefines, injectEnvToProcess, loadEnvFiles } from \"../utils/envLoader.js\";\nimport { log } from \"../utils/logger.js\";\nimport {\n RESOLVED_VIRTUAL_CLIENT_MODULE_ID,\n RESOLVED_VIRTUAL_ENTRY_MODULE_ID,\n RESOLVED_VIRTUAL_SERVER_MANIFEST_ID,\n SERVER_DIR,\n VIRTUAL_CLIENT_MODULE_ID,\n VIRTUAL_ENTRY_MODULE_ID,\n VIRTUAL_SERVER_MANIFEST_ID,\n} from \"./paths.js\";\nimport { checkRouteCollisions, scanServerExports } from \"./scanner.js\";\nimport { generateClientModule, generateEntryModule, generateServerManifest, generateTypeDefinitions } from \"./virtualServerModule.js\";\n\nexport default function helium(): Plugin {\n let root = process.cwd();\n const serverDir = normalizeToPosix(SERVER_DIR);\n\n return {\n name: \"vite-plugin-helium\",\n enforce: \"pre\",\n configResolved(config) {\n root = config.root;\n\n // Load and inject environment variables\n const mode = config.mode || \"development\";\n const envVars = loadEnvFiles({ root, mode });\n injectEnvToProcess(envVars);\n },\n transformIndexHtml: {\n order: \"pre\",\n handler(html, _ctx) {\n // Check if HTML already has a script tag for entry\n if (html.includes(\"src/main.tsx\") || html.includes(\"src/main.ts\")) {\n return html; // User has their own entry, don't modify\n }\n\n // Ensure root div exists\n let modifiedHtml = html;\n if (!modifiedHtml.includes('id=\"root\"')) {\n modifiedHtml = modifiedHtml.replace(\"<body>\", '<body>\\n <div id=\"root\"></div>');\n }\n\n // Generate physical entry file\n const heliumDir = path.join(root, \"node_modules\", \".heliumts\");\n if (!fs.existsSync(heliumDir)) {\n fs.mkdirSync(heliumDir, { recursive: true });\n }\n const entryPath = path.join(heliumDir, \"entry.tsx\");\n fs.writeFileSync(entryPath, generateEntryModule());\n\n // Return with tags to inject the entry (runtime config is fetched by the client)\n return [\n {\n tag: \"script\",\n attrs: {\n type: \"module\",\n src: \"/node_modules/.heliumts/entry.tsx\",\n },\n injectTo: \"body\",\n },\n ];\n },\n },\n async config(config) {\n // Load environment variables before config is finalized\n const mode = config.mode || \"development\";\n const envVars = loadEnvFiles({ root, mode });\n\n // Create defines for client-side env variables\n const envDefines = createEnvDefines(envVars);\n\n // Load helium config to get client-side RPC transport settings\n const heliumConfig = await loadConfig(root);\n const rpcClientConfig = getRpcClientConfig(heliumConfig);\n\n // Provide default index.html if none exists\n return {\n appType: \"spa\",\n optimizeDeps: {\n include: [\"react-dom/client\"],\n // Exclude helium from pre-bundling since it's the framework itself\n // This ensures changes to helium are picked up immediately\n exclude: [\"heliumts\", \"heliumts/client\", \"heliumts/server\", \"heliumts/vite\"],\n },\n // SSR configuration to properly isolate server-only code\n ssr: {\n // Externalize Node.js built-in modules - these should never be bundled\n external: [\"util\", \"zlib\", \"http\", \"https\", \"http2\", \"fs\", \"path\", \"crypto\", \"stream\", \"os\", \"url\", \"net\", \"tls\", \"child_process\", \"worker_threads\"],\n // Don't externalize heliumts - let the plugin handle the client/server split\n noExternal: [\"heliumts\"],\n },\n // Ensure Node.js built-ins are not bundled for client\n build: {\n rollupOptions: {\n external: [\n // Node.js built-in modules should never be in client bundle\n /^node:/,\n \"util\",\n \"zlib\",\n \"http\",\n \"https\",\n \"http2\",\n \"fs\",\n \"path\",\n \"crypto\",\n \"stream\",\n \"os\",\n \"url\",\n \"net\",\n \"tls\",\n \"child_process\",\n \"worker_threads\",\n ],\n },\n },\n define: {\n ...envDefines,\n __HELIUM_RPC_TRANSPORT__: JSON.stringify(rpcClientConfig.transport),\n __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__: JSON.stringify(rpcClientConfig.autoHttpOnMobile),\n },\n };\n },\n resolveId(id, importer) {\n if (id === VIRTUAL_CLIENT_MODULE_ID) {\n if (isServerModule(importer, root, serverDir)) {\n return null;\n }\n return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;\n }\n if (id === VIRTUAL_SERVER_MANIFEST_ID) {\n return RESOLVED_VIRTUAL_SERVER_MANIFEST_ID;\n }\n if (id === VIRTUAL_ENTRY_MODULE_ID) {\n // Add .tsx extension so Vite knows it contains JSX\n return RESOLVED_VIRTUAL_ENTRY_MODULE_ID + \".tsx\";\n }\n // Intercept heliumts/server imports from client code\n if (id === \"heliumts/server\") {\n // If imported from server code, let it resolve normally\n if (isServerModule(importer, root, serverDir)) {\n return null;\n }\n // For client code, redirect to virtual client module\n return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;\n }\n return null;\n },\n load(id) {\n if (id === RESOLVED_VIRTUAL_CLIENT_MODULE_ID) {\n const { methods } = scanServerExports(root);\n return generateClientModule(methods);\n }\n if (id === RESOLVED_VIRTUAL_SERVER_MANIFEST_ID) {\n const { methods, httpHandlers, middleware, workers } = scanServerExports(root);\n return generateServerManifest(methods, httpHandlers, middleware, workers);\n }\n if (id === RESOLVED_VIRTUAL_ENTRY_MODULE_ID + \".tsx\") {\n return generateEntryModule();\n }\n },\n buildStart() {\n const { methods } = scanServerExports(root);\n const dts = generateTypeDefinitions(methods, root);\n const typesDir = path.join(root, \"src\", \"types\");\n const dtsPath = path.join(typesDir, \"heliumts-server.d.ts\");\n\n // Ensure src/types exists\n if (!fs.existsSync(typesDir)) {\n fs.mkdirSync(typesDir, { recursive: true });\n }\n\n // At build start we always allow writing the canonical set.\n // Only skip if content is identical to avoid needless TS invalidation.\n if (!fs.existsSync(dtsPath) || fs.readFileSync(dtsPath, \"utf-8\") !== dts) {\n fs.writeFileSync(dtsPath, dts);\n touchTsConfig(root);\n }\n\n // Check for route collisions in pages directory\n checkRouteCollisions(root);\n },\n configureServer(server) {\n // Add middleware to handle HTML fallback for nested routes\n // This ensures that routes like /docs/guides/auth properly serve index.html\n // so the client-side router can handle them\n server.middlewares.use((req, res, next) => {\n const url = req.url || \"\";\n const cleanUrl = url.split(\"?\")[0];\n\n // Skip if:\n // - Has file extension (asset request)\n // - Is an API/special endpoint\n // - Is a dev server endpoint\n if (\n path.extname(cleanUrl) !== \"\" ||\n cleanUrl.startsWith(\"/api\") ||\n cleanUrl.startsWith(\"/webhooks\") ||\n cleanUrl.startsWith(\"/auth\") ||\n cleanUrl.startsWith(\"/@\") ||\n cleanUrl.startsWith(\"/__helium__\")\n ) {\n return next();\n }\n\n // For all other routes (including nested paths like /docs/guides/auth),\n // rewrite to index.html so Vite serves it and the client-side router handles routing\n req.url = \"/index.html\";\n next();\n });\n\n /**\n * Write type definitions only if content has changed.\n * This prevents unnecessary TypeScript recompilation.\n *\n * When `allowFewer` is false (default) the file will NOT be\n * overwritten if the new content has fewer method declarations\n * than the existing file — this guards against writing a\n * degraded .d.ts while the user's file is only partially saved.\n */\n const writeTypesIfChanged = (dts: string, allowFewer = false): boolean => {\n const typesDir = path.join(root, \"src\", \"types\");\n const dtsPath = path.join(typesDir, \"heliumts-server.d.ts\");\n\n if (!fs.existsSync(typesDir)) {\n fs.mkdirSync(typesDir, { recursive: true });\n }\n\n // Check if file exists and content is the same\n if (fs.existsSync(dtsPath)) {\n const existing = fs.readFileSync(dtsPath, \"utf-8\");\n if (existing === dts) {\n return false; // No change needed\n }\n\n // Guard: don't overwrite with fewer methods unless explicitly allowed\n // (e.g. on unlink). This prevents losing types during partial saves.\n if (!allowFewer) {\n const countExports = (s: string) => (s.match(/export const \\w+:/g) || []).length;\n const existingCount = countExports(existing);\n const newCount = countExports(dts);\n if (newCount < existingCount) {\n log(\"info\", `Skipping type generation: found ${newCount} methods, existing has ${existingCount} (likely partial save)`);\n return false;\n }\n }\n }\n\n fs.writeFileSync(dtsPath, dts);\n\n // Touch tsconfig.json to force the TypeScript language server\n // to reload the project. Without this, TS may cache stale\n // module augmentations and autocomplete won't reflect the\n // new methods until a manual restart.\n touchTsConfig(root);\n\n return true; // File was written\n };\n\n const regenerateTypes = (allowFewer = false): boolean => {\n try {\n const { methods } = scanServerExports(root);\n const dts = generateTypeDefinitions(methods, root);\n return writeTypesIfChanged(dts, allowFewer);\n } catch (e) {\n log(\"error\", \"Failed to regenerate types\", e);\n return false;\n }\n };\n\n // Debounce timer for file changes\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n const DEBOUNCE_DELAY = 300; // ms — long enough for format-on-save to finish\n\n const handleServerFileChange = async (allowFewer = false) => {\n // Regenerate type definitions\n regenerateTypes(allowFewer);\n\n // Invalidate the virtual modules so they get regenerated\n const clientModule = server.environments.client?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_CLIENT_MODULE_ID);\n const serverModule = server.environments.ssr?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_SERVER_MANIFEST_ID);\n\n if (clientModule) {\n server.environments.client?.moduleGraph.invalidateModule(clientModule);\n }\n if (serverModule) {\n server.environments.ssr?.moduleGraph.invalidateModule(serverModule);\n }\n\n // Reload the server manifest and re-register methods\n try {\n // Clear config cache to ensure fresh config is loaded\n clearConfigCache();\n const config = await loadConfig(root);\n const mod = await server.ssrLoadModule(VIRTUAL_SERVER_MANIFEST_ID);\n const registerAll = mod.registerAll;\n const httpHandlers = mod.httpHandlers || [];\n const middlewareHandler = mod.middlewareHandler || null;\n const workers = mod.workers || [];\n\n // Update the dev server registry with new methods and HTTP handlers\n if (server.httpServer) {\n attachToDevServer(\n server.httpServer,\n (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n config,\n workers\n );\n }\n } catch (e) {\n log(\"error\", \"Failed to reload Helium server manifest\", e);\n }\n\n // Trigger HMR for any client code that imports heliumts/server\n server.ws.send({\n type: \"full-reload\",\n path: \"*\",\n });\n };\n\n // Watch server directory for changes\n const serverPath = path.join(root, serverDir);\n server.watcher.add(serverPath);\n\n // Watch config files for changes\n const configFiles = [\"helium.config.ts\", \"helium.config.js\", \"helium.config.mjs\"];\n for (const configFile of configFiles) {\n const configPath = path.join(root, configFile);\n if (fs.existsSync(configPath)) {\n server.watcher.add(configPath);\n }\n }\n\n /**\n * Debounced handler for server file changes.\n * This prevents multiple rapid regenerations during file saves.\n * @param allowFewer - pass true when files are deleted, so the\n * method count is allowed to decrease.\n */\n let pendingAllowFewer = false;\n const debouncedHandleServerFileChange = (allowFewer = false) => {\n // If any event in the batch is an unlink, honour it\n if (allowFewer) {\n pendingAllowFewer = true;\n }\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n const shouldAllowFewer = pendingAllowFewer;\n pendingAllowFewer = false;\n handleServerFileChange(shouldAllowFewer);\n }, DEBOUNCE_DELAY);\n };\n\n server.watcher.on(\"change\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file changed, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange();\n }\n\n // If config file changed, reload config and regenerate\n if (configFiles.some((cf) => normalized === cf)) {\n log(\"info\", `Config file changed: ${normalized}`);\n debouncedHandleServerFileChange();\n }\n });\n\n server.watcher.on(\"add\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file was added, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange();\n }\n });\n\n server.watcher.on(\"unlink\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file was removed, regenerate (allow fewer methods)\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange(true);\n }\n });\n\n // We hook into the server start to attach our RPC server\n server.httpServer?.on(\"listening\", async () => {\n try {\n // Load config\n const config = await loadConfig(root);\n\n // Load the manifest using Vite's SSR loader\n // This allows us to load TS files directly and handle dependencies\n const mod = await server.ssrLoadModule(VIRTUAL_SERVER_MANIFEST_ID);\n const registerAll = mod.registerAll;\n const httpHandlers = mod.httpHandlers || [];\n const middlewareHandler = mod.middlewareHandler || null;\n const workers = mod.workers || [];\n\n if (server.httpServer) {\n attachToDevServer(\n server.httpServer,\n (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n config,\n workers\n );\n }\n } catch (e) {\n log(\"error\", \"Failed to attach Helium RPC server\", e);\n }\n });\n },\n };\n}\n\n/**\n * Convert file path to POSIX format\n * @internal Exported for testing\n */\nexport function normalizeToPosix(filePath: string): string {\n return filePath.split(path.sep).join(\"/\");\n}\n\n/**\n * Check if an importer is a server module\n * @internal Exported for testing\n */\nexport function isServerModule(importer: string | undefined, root: string, serverDir: string): boolean {\n if (!importer || importer.startsWith(\"\\0\")) {\n return false;\n }\n\n const [importerPath] = importer.split(\"?\");\n if (!importerPath) {\n return false;\n }\n\n const relative = path.relative(root, importerPath);\n if (!relative || relative.startsWith(\"..\")) {\n return false;\n }\n\n const normalized = normalizeToPosix(relative);\n return normalized === serverDir || normalized.startsWith(`${serverDir}/`);\n}\n\n/**\n * Touch the project's tsconfig.json to force the TypeScript language server\n * to reload the project and pick up changed module augmentations.\n *\n * TS language server watches tsconfig.json for changes. When a `.d.ts` file\n * with `declare module` augmentations is regenerated, TS doesn't always\n * detect the new content — leading to stale autocomplete. By updating\n * tsconfig.json's mtime we trigger a full project reload.\n *\n * The file content is NOT modified; only the filesystem timestamp changes.\n *\n * @internal Exported for testing\n */\nexport function touchTsConfig(root: string): void {\n const tsconfigPath = path.join(root, \"tsconfig.json\");\n try {\n if (fs.existsSync(tsconfigPath)) {\n const now = new Date();\n fs.utimesSync(tsconfigPath, now, now);\n }\n } catch {\n // Non-critical: if we can't touch the file, TS may just need a manual reload\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"heliumPlugin.js","sourceRoot":"","sources":["../../src/vite/heliumPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { Plugin } from \"vite\";\n\nimport { clearConfigCache, getRpcClientConfig, loadConfig } from \"../server/config.js\";\nimport { attachToDevServer } from \"../server/devServer.js\";\nimport { createEnvDefines, injectEnvToProcess, loadEnvFiles } from \"../utils/envLoader.js\";\nimport { log } from \"../utils/logger.js\";\nimport {\n RESOLVED_VIRTUAL_CLIENT_MODULE_ID,\n RESOLVED_VIRTUAL_ENTRY_MODULE_ID,\n RESOLVED_VIRTUAL_SERVER_MANIFEST_ID,\n SERVER_DIR,\n VIRTUAL_CLIENT_MODULE_ID,\n VIRTUAL_ENTRY_MODULE_ID,\n VIRTUAL_SERVER_MANIFEST_ID,\n} from \"./paths.js\";\nimport { checkRouteCollisions, scanServerExports } from \"./scanner.js\";\nimport { generateClientModule, generateEntryModule, generateServerManifest, generateTypeDefinitions } from \"./virtualServerModule.js\";\n\nexport default function helium(): Plugin {\n let root = process.cwd();\n const serverDir = normalizeToPosix(SERVER_DIR);\n\n return {\n name: \"vite-plugin-helium\",\n enforce: \"pre\",\n configResolved(config) {\n root = config.root;\n\n // Load and inject environment variables\n const mode = config.mode || \"development\";\n const envVars = loadEnvFiles({ root, mode });\n injectEnvToProcess(envVars);\n },\n transformIndexHtml: {\n order: \"pre\",\n handler(html, _ctx) {\n // Check if HTML already has a script tag for entry\n if (html.includes(\"src/main.tsx\") || html.includes(\"src/main.ts\")) {\n return html; // User has their own entry, don't modify\n }\n\n // Ensure root div exists\n let modifiedHtml = html;\n if (!modifiedHtml.includes('id=\"root\"')) {\n modifiedHtml = modifiedHtml.replace(\"<body>\", '<body>\\n <div id=\"root\"></div>');\n }\n\n // Generate physical entry file\n const heliumDir = path.join(root, \"node_modules\", \".heliumts\");\n if (!fs.existsSync(heliumDir)) {\n fs.mkdirSync(heliumDir, { recursive: true });\n }\n const entryPath = path.join(heliumDir, \"entry.tsx\");\n fs.writeFileSync(entryPath, generateEntryModule());\n\n // Return with tags to inject the entry (runtime config is fetched by the client)\n return [\n {\n tag: \"script\",\n attrs: {\n type: \"module\",\n src: \"/node_modules/.heliumts/entry.tsx\",\n },\n injectTo: \"body\",\n },\n ];\n },\n },\n async config(config) {\n // Load environment variables before config is finalized\n const mode = config.mode || \"development\";\n const envVars = loadEnvFiles({ root, mode });\n\n // Create defines for client-side env variables\n const envDefines = createEnvDefines(envVars);\n\n // Load helium config to get client-side RPC transport settings\n const heliumConfig = await loadConfig(root);\n const rpcClientConfig = getRpcClientConfig(heliumConfig);\n\n // Provide default index.html if none exists\n return {\n appType: \"spa\",\n optimizeDeps: {\n include: [\"react-dom/client\"],\n // Exclude helium from pre-bundling since it's the framework itself\n // This ensures changes to helium are picked up immediately\n exclude: [\"heliumts\", \"heliumts/client\", \"heliumts/server\", \"heliumts/vite\"],\n },\n // SSR configuration to properly isolate server-only code\n ssr: {\n // Externalize Node.js built-in modules - these should never be bundled\n external: [\"util\", \"zlib\", \"http\", \"https\", \"http2\", \"fs\", \"path\", \"crypto\", \"stream\", \"os\", \"url\", \"net\", \"tls\", \"child_process\", \"worker_threads\"],\n // Don't externalize heliumts - let the plugin handle the client/server split\n noExternal: [\"heliumts\"],\n },\n // Ensure Node.js built-ins are not bundled for client\n build: {\n rollupOptions: {\n external: [\n // Node.js built-in modules should never be in client bundle\n /^node:/,\n \"util\",\n \"zlib\",\n \"http\",\n \"https\",\n \"http2\",\n \"fs\",\n \"path\",\n \"crypto\",\n \"stream\",\n \"os\",\n \"url\",\n \"net\",\n \"tls\",\n \"child_process\",\n \"worker_threads\",\n ],\n },\n },\n define: {\n ...envDefines,\n __HELIUM_RPC_TRANSPORT__: JSON.stringify(rpcClientConfig.transport),\n __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__: JSON.stringify(rpcClientConfig.autoHttpOnMobile),\n __HELIUM_RPC_TOKEN_VALIDITY_MS__: JSON.stringify(rpcClientConfig.tokenValidityMs),\n },\n };\n },\n resolveId(id, importer) {\n if (id === VIRTUAL_CLIENT_MODULE_ID) {\n if (isServerModule(importer, root, serverDir)) {\n return null;\n }\n return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;\n }\n if (id === VIRTUAL_SERVER_MANIFEST_ID) {\n return RESOLVED_VIRTUAL_SERVER_MANIFEST_ID;\n }\n if (id === VIRTUAL_ENTRY_MODULE_ID) {\n // Add .tsx extension so Vite knows it contains JSX\n return RESOLVED_VIRTUAL_ENTRY_MODULE_ID + \".tsx\";\n }\n // Intercept heliumts/server imports from client code\n if (id === \"heliumts/server\") {\n // If imported from server code, let it resolve normally\n if (isServerModule(importer, root, serverDir)) {\n return null;\n }\n // For client code, redirect to virtual client module\n return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;\n }\n return null;\n },\n load(id) {\n if (id === RESOLVED_VIRTUAL_CLIENT_MODULE_ID) {\n const { methods } = scanServerExports(root);\n return generateClientModule(methods);\n }\n if (id === RESOLVED_VIRTUAL_SERVER_MANIFEST_ID) {\n const { methods, httpHandlers, middleware, workers } = scanServerExports(root);\n return generateServerManifest(methods, httpHandlers, middleware, workers);\n }\n if (id === RESOLVED_VIRTUAL_ENTRY_MODULE_ID + \".tsx\") {\n return generateEntryModule();\n }\n },\n buildStart() {\n const { methods } = scanServerExports(root);\n const dts = generateTypeDefinitions(methods, root);\n const typesDir = path.join(root, \"src\", \"types\");\n const dtsPath = path.join(typesDir, \"heliumts-server.d.ts\");\n\n // Ensure src/types exists\n if (!fs.existsSync(typesDir)) {\n fs.mkdirSync(typesDir, { recursive: true });\n }\n\n // At build start we always allow writing the canonical set.\n // Only skip if content is identical to avoid needless TS invalidation.\n if (!fs.existsSync(dtsPath) || fs.readFileSync(dtsPath, \"utf-8\") !== dts) {\n fs.writeFileSync(dtsPath, dts);\n touchTsConfig(root);\n }\n\n // Check for route collisions in pages directory\n checkRouteCollisions(root);\n },\n configureServer(server) {\n // Add middleware to handle HTML fallback for nested routes\n // This ensures that routes like /docs/guides/auth properly serve index.html\n // so the client-side router can handle them\n server.middlewares.use((req, res, next) => {\n const url = req.url || \"\";\n const cleanUrl = url.split(\"?\")[0];\n\n // Skip if:\n // - Has file extension (asset request)\n // - Is an API/special endpoint\n // - Is a dev server endpoint\n if (\n path.extname(cleanUrl) !== \"\" ||\n cleanUrl.startsWith(\"/api\") ||\n cleanUrl.startsWith(\"/webhooks\") ||\n cleanUrl.startsWith(\"/auth\") ||\n cleanUrl.startsWith(\"/@\") ||\n cleanUrl.startsWith(\"/__helium__\")\n ) {\n return next();\n }\n\n // For all other routes (including nested paths like /docs/guides/auth),\n // rewrite to index.html so Vite serves it and the client-side router handles routing\n req.url = \"/index.html\";\n next();\n });\n\n /**\n * Write type definitions only if content has changed.\n * This prevents unnecessary TypeScript recompilation.\n *\n * When `allowFewer` is false (default) the file will NOT be\n * overwritten if the new content has fewer method declarations\n * than the existing file — this guards against writing a\n * degraded .d.ts while the user's file is only partially saved.\n */\n const writeTypesIfChanged = (dts: string, allowFewer = false): boolean => {\n const typesDir = path.join(root, \"src\", \"types\");\n const dtsPath = path.join(typesDir, \"heliumts-server.d.ts\");\n\n if (!fs.existsSync(typesDir)) {\n fs.mkdirSync(typesDir, { recursive: true });\n }\n\n // Check if file exists and content is the same\n if (fs.existsSync(dtsPath)) {\n const existing = fs.readFileSync(dtsPath, \"utf-8\");\n if (existing === dts) {\n return false; // No change needed\n }\n\n // Guard: don't overwrite with fewer methods unless explicitly allowed\n // (e.g. on unlink). This prevents losing types during partial saves.\n if (!allowFewer) {\n const countExports = (s: string) => (s.match(/export const \\w+:/g) || []).length;\n const existingCount = countExports(existing);\n const newCount = countExports(dts);\n if (newCount < existingCount) {\n log(\"info\", `Skipping type generation: found ${newCount} methods, existing has ${existingCount} (likely partial save)`);\n return false;\n }\n }\n }\n\n fs.writeFileSync(dtsPath, dts);\n\n // Touch tsconfig.json to force the TypeScript language server\n // to reload the project. Without this, TS may cache stale\n // module augmentations and autocomplete won't reflect the\n // new methods until a manual restart.\n touchTsConfig(root);\n\n return true; // File was written\n };\n\n const regenerateTypes = (allowFewer = false): boolean => {\n try {\n const { methods } = scanServerExports(root);\n const dts = generateTypeDefinitions(methods, root);\n return writeTypesIfChanged(dts, allowFewer);\n } catch (e) {\n log(\"error\", \"Failed to regenerate types\", e);\n return false;\n }\n };\n\n // Debounce timer for file changes\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n const DEBOUNCE_DELAY = 300; // ms — long enough for format-on-save to finish\n\n const handleServerFileChange = async (allowFewer = false) => {\n // Regenerate type definitions\n regenerateTypes(allowFewer);\n\n // Invalidate the virtual modules so they get regenerated\n const clientModule = server.environments.client?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_CLIENT_MODULE_ID);\n const serverModule = server.environments.ssr?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_SERVER_MANIFEST_ID);\n\n if (clientModule) {\n server.environments.client?.moduleGraph.invalidateModule(clientModule);\n }\n if (serverModule) {\n server.environments.ssr?.moduleGraph.invalidateModule(serverModule);\n }\n\n // Reload the server manifest and re-register methods\n try {\n // Clear config cache to ensure fresh config is loaded\n clearConfigCache();\n const config = await loadConfig(root);\n const mod = await server.ssrLoadModule(VIRTUAL_SERVER_MANIFEST_ID);\n const registerAll = mod.registerAll;\n const httpHandlers = mod.httpHandlers || [];\n const middlewareHandler = mod.middlewareHandler || null;\n const workers = mod.workers || [];\n\n // Update the dev server registry with new methods and HTTP handlers\n if (server.httpServer) {\n attachToDevServer(\n server.httpServer,\n (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n config,\n workers\n );\n }\n } catch (e) {\n log(\"error\", \"Failed to reload Helium server manifest\", e);\n }\n\n // Trigger HMR for any client code that imports heliumts/server\n server.ws.send({\n type: \"full-reload\",\n path: \"*\",\n });\n };\n\n // Watch server directory for changes\n const serverPath = path.join(root, serverDir);\n server.watcher.add(serverPath);\n\n // Watch config files for changes\n const configFiles = [\"helium.config.ts\", \"helium.config.js\", \"helium.config.mjs\"];\n for (const configFile of configFiles) {\n const configPath = path.join(root, configFile);\n if (fs.existsSync(configPath)) {\n server.watcher.add(configPath);\n }\n }\n\n /**\n * Debounced handler for server file changes.\n * This prevents multiple rapid regenerations during file saves.\n * @param allowFewer - pass true when files are deleted, so the\n * method count is allowed to decrease.\n */\n let pendingAllowFewer = false;\n const debouncedHandleServerFileChange = (allowFewer = false) => {\n // If any event in the batch is an unlink, honour it\n if (allowFewer) {\n pendingAllowFewer = true;\n }\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n const shouldAllowFewer = pendingAllowFewer;\n pendingAllowFewer = false;\n handleServerFileChange(shouldAllowFewer);\n }, DEBOUNCE_DELAY);\n };\n\n server.watcher.on(\"change\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file changed, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange();\n }\n\n // If config file changed, reload config and regenerate\n if (configFiles.some((cf) => normalized === cf)) {\n log(\"info\", `Config file changed: ${normalized}`);\n debouncedHandleServerFileChange();\n }\n });\n\n server.watcher.on(\"add\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file was added, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange();\n }\n });\n\n server.watcher.on(\"unlink\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file was removed, regenerate (allow fewer methods)\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange(true);\n }\n });\n\n // We hook into the server start to attach our RPC server\n server.httpServer?.on(\"listening\", async () => {\n try {\n // Load config\n const config = await loadConfig(root);\n\n // Load the manifest using Vite's SSR loader\n // This allows us to load TS files directly and handle dependencies\n const mod = await server.ssrLoadModule(VIRTUAL_SERVER_MANIFEST_ID);\n const registerAll = mod.registerAll;\n const httpHandlers = mod.httpHandlers || [];\n const middlewareHandler = mod.middlewareHandler || null;\n const workers = mod.workers || [];\n\n if (server.httpServer) {\n attachToDevServer(\n server.httpServer,\n (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n config,\n workers\n );\n }\n } catch (e) {\n log(\"error\", \"Failed to attach Helium RPC server\", e);\n }\n });\n },\n };\n}\n\n/**\n * Convert file path to POSIX format\n * @internal Exported for testing\n */\nexport function normalizeToPosix(filePath: string): string {\n return filePath.split(path.sep).join(\"/\");\n}\n\n/**\n * Check if an importer is a server module\n * @internal Exported for testing\n */\nexport function isServerModule(importer: string | undefined, root: string, serverDir: string): boolean {\n if (!importer || importer.startsWith(\"\\0\")) {\n return false;\n }\n\n const [importerPath] = importer.split(\"?\");\n if (!importerPath) {\n return false;\n }\n\n const relative = path.relative(root, importerPath);\n if (!relative || relative.startsWith(\"..\")) {\n return false;\n }\n\n const normalized = normalizeToPosix(relative);\n return normalized === serverDir || normalized.startsWith(`${serverDir}/`);\n}\n\n/**\n * Touch the project's tsconfig.json to force the TypeScript language server\n * to reload the project and pick up changed module augmentations.\n *\n * TS language server watches tsconfig.json for changes. When a `.d.ts` file\n * with `declare module` augmentations is regenerated, TS doesn't always\n * detect the new content — leading to stale autocomplete. By updating\n * tsconfig.json's mtime we trigger a full project reload.\n *\n * The file content is NOT modified; only the filesystem timestamp changes.\n *\n * @internal Exported for testing\n */\nexport function touchTsConfig(root: string): void {\n const tsconfigPath = path.join(root, \"tsconfig.json\");\n try {\n if (fs.existsSync(tsconfigPath)) {\n const now = new Date();\n fs.utimesSync(tsconfigPath, now, now);\n }\n } catch {\n // Non-critical: if we can't touch the file, TS may just need a manual reload\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type http from "http";
|
|
2
|
-
/**
|
|
3
|
-
* Extracts the client IP address from an HTTP request, taking into account proxy configurations.
|
|
4
|
-
*
|
|
5
|
-
* When behind proxies (like Vercel, Cloudflare, AWS ALB, etc.), the X-Forwarded-For header
|
|
6
|
-
* contains a chain of IP addresses. The format is: "client, proxy1, proxy2, ..."
|
|
7
|
-
*
|
|
8
|
-
* @param req - The HTTP request object
|
|
9
|
-
* @param trustProxyDepth - Number of proxy levels to trust
|
|
10
|
-
* - 0: Only use req.socket.remoteAddress (no proxy trust)
|
|
11
|
-
* - 1: Trust 1 proxy level (get the last IP before your server)
|
|
12
|
-
* - 2+: Trust multiple proxy levels (for complex setups)
|
|
13
|
-
*
|
|
14
|
-
* Examples:
|
|
15
|
-
* - trustProxyDepth=0: Direct connection, no proxies
|
|
16
|
-
* X-Forwarded-For: ignored
|
|
17
|
-
* Result: req.socket.remoteAddress
|
|
18
|
-
*
|
|
19
|
-
* - trustProxyDepth=1: Behind one proxy (e.g., Vercel, Netlify)
|
|
20
|
-
* X-Forwarded-For: "203.0.113.1, 198.51.100.1"
|
|
21
|
-
* Result: "203.0.113.1" (client IP)
|
|
22
|
-
*
|
|
23
|
-
* - trustProxyDepth=2: Behind two proxies (e.g., Cloudflare -> Load Balancer)
|
|
24
|
-
* X-Forwarded-For: "203.0.113.1, 198.51.100.1, 192.0.2.1"
|
|
25
|
-
* Result: "203.0.113.1" (client IP)
|
|
26
|
-
*
|
|
27
|
-
* Common configurations:
|
|
28
|
-
* - Vercel/Netlify/Railway: trustProxyDepth=1
|
|
29
|
-
* - Cloudflare -> Origin: trustProxyDepth=1 or 2 (depending on your setup)
|
|
30
|
-
* - AWS ALB -> EC2: trustProxyDepth=1
|
|
31
|
-
* - Nginx -> Node: trustProxyDepth=1
|
|
32
|
-
* - Cloudflare -> Nginx -> Node: trustProxyDepth=2
|
|
33
|
-
*/
|
|
34
|
-
export declare function extractClientIP(req: http.IncomingMessage, trustProxyDepth?: number): string;
|
|
35
|
-
/**
|
|
36
|
-
* Alternative extraction method that works from the right (trusts the rightmost IPs).
|
|
37
|
-
* This is useful when you want to trust the last N proxies in the chain.
|
|
38
|
-
*
|
|
39
|
-
* @param req - The HTTP request object
|
|
40
|
-
* @param trustProxyDepth - Number of proxy levels to trust from the right
|
|
41
|
-
*
|
|
42
|
-
* Example:
|
|
43
|
-
* X-Forwarded-For: "203.0.113.1, 198.51.100.1, 192.0.2.1"
|
|
44
|
-
* trustProxyDepth=1: Result is "198.51.100.1" (skip the last trusted proxy)
|
|
45
|
-
* trustProxyDepth=2: Result is "203.0.113.1" (skip the last 2 trusted proxies)
|
|
46
|
-
*/
|
|
47
|
-
export declare function extractClientIPFromRight(req: http.IncomingMessage, trustProxyDepth?: number): string;
|
|
48
|
-
//# sourceMappingURL=ipExtractor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ipExtractor.d.ts","sourceRoot":"","sources":["../../src/server/ipExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,GAAE,MAAU,GAAG,MAAM,CAqC9F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,GAAE,MAAU,GAAG,MAAM,CAsBvG"}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extracts the client IP address from an HTTP request, taking into account proxy configurations.
|
|
3
|
-
*
|
|
4
|
-
* When behind proxies (like Vercel, Cloudflare, AWS ALB, etc.), the X-Forwarded-For header
|
|
5
|
-
* contains a chain of IP addresses. The format is: "client, proxy1, proxy2, ..."
|
|
6
|
-
*
|
|
7
|
-
* @param req - The HTTP request object
|
|
8
|
-
* @param trustProxyDepth - Number of proxy levels to trust
|
|
9
|
-
* - 0: Only use req.socket.remoteAddress (no proxy trust)
|
|
10
|
-
* - 1: Trust 1 proxy level (get the last IP before your server)
|
|
11
|
-
* - 2+: Trust multiple proxy levels (for complex setups)
|
|
12
|
-
*
|
|
13
|
-
* Examples:
|
|
14
|
-
* - trustProxyDepth=0: Direct connection, no proxies
|
|
15
|
-
* X-Forwarded-For: ignored
|
|
16
|
-
* Result: req.socket.remoteAddress
|
|
17
|
-
*
|
|
18
|
-
* - trustProxyDepth=1: Behind one proxy (e.g., Vercel, Netlify)
|
|
19
|
-
* X-Forwarded-For: "203.0.113.1, 198.51.100.1"
|
|
20
|
-
* Result: "203.0.113.1" (client IP)
|
|
21
|
-
*
|
|
22
|
-
* - trustProxyDepth=2: Behind two proxies (e.g., Cloudflare -> Load Balancer)
|
|
23
|
-
* X-Forwarded-For: "203.0.113.1, 198.51.100.1, 192.0.2.1"
|
|
24
|
-
* Result: "203.0.113.1" (client IP)
|
|
25
|
-
*
|
|
26
|
-
* Common configurations:
|
|
27
|
-
* - Vercel/Netlify/Railway: trustProxyDepth=1
|
|
28
|
-
* - Cloudflare -> Origin: trustProxyDepth=1 or 2 (depending on your setup)
|
|
29
|
-
* - AWS ALB -> EC2: trustProxyDepth=1
|
|
30
|
-
* - Nginx -> Node: trustProxyDepth=1
|
|
31
|
-
* - Cloudflare -> Nginx -> Node: trustProxyDepth=2
|
|
32
|
-
*/
|
|
33
|
-
export function extractClientIP(req, trustProxyDepth = 0) {
|
|
34
|
-
// If not trusting any proxies, return the direct connection IP
|
|
35
|
-
if (trustProxyDepth === 0) {
|
|
36
|
-
return req.socket.remoteAddress || "unknown";
|
|
37
|
-
}
|
|
38
|
-
// Get X-Forwarded-For header
|
|
39
|
-
const forwardedFor = req.headers["x-forwarded-for"];
|
|
40
|
-
if (!forwardedFor) {
|
|
41
|
-
// No X-Forwarded-For header, fall back to direct connection
|
|
42
|
-
return req.socket.remoteAddress || "unknown";
|
|
43
|
-
}
|
|
44
|
-
// Parse X-Forwarded-For header (can be a string or array of strings)
|
|
45
|
-
const forwardedIPs = (Array.isArray(forwardedFor) ? forwardedFor.join(",") : forwardedFor)
|
|
46
|
-
.split(",")
|
|
47
|
-
.map((ip) => ip.trim())
|
|
48
|
-
.filter((ip) => ip.length > 0);
|
|
49
|
-
if (forwardedIPs.length === 0) {
|
|
50
|
-
// Empty X-Forwarded-For, fall back to direct connection
|
|
51
|
-
return req.socket.remoteAddress || "unknown";
|
|
52
|
-
}
|
|
53
|
-
// The client IP is at the beginning of the chain
|
|
54
|
-
// We trust the chain up to trustProxyDepth levels
|
|
55
|
-
// Format: [clientIP, proxy1, proxy2, ..., lastProxy]
|
|
56
|
-
// We want the clientIP, but we need to verify we have enough trusted proxies
|
|
57
|
-
if (forwardedIPs.length < trustProxyDepth) {
|
|
58
|
-
// Not enough IPs in the chain, the chain might be incomplete or spoofed
|
|
59
|
-
// Fall back to direct connection for safety
|
|
60
|
-
return req.socket.remoteAddress || "unknown";
|
|
61
|
-
}
|
|
62
|
-
// Return the client IP (first in the chain)
|
|
63
|
-
return forwardedIPs[0];
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Alternative extraction method that works from the right (trusts the rightmost IPs).
|
|
67
|
-
* This is useful when you want to trust the last N proxies in the chain.
|
|
68
|
-
*
|
|
69
|
-
* @param req - The HTTP request object
|
|
70
|
-
* @param trustProxyDepth - Number of proxy levels to trust from the right
|
|
71
|
-
*
|
|
72
|
-
* Example:
|
|
73
|
-
* X-Forwarded-For: "203.0.113.1, 198.51.100.1, 192.0.2.1"
|
|
74
|
-
* trustProxyDepth=1: Result is "198.51.100.1" (skip the last trusted proxy)
|
|
75
|
-
* trustProxyDepth=2: Result is "203.0.113.1" (skip the last 2 trusted proxies)
|
|
76
|
-
*/
|
|
77
|
-
export function extractClientIPFromRight(req, trustProxyDepth = 0) {
|
|
78
|
-
if (trustProxyDepth === 0) {
|
|
79
|
-
return req.socket.remoteAddress || "unknown";
|
|
80
|
-
}
|
|
81
|
-
const forwardedFor = req.headers["x-forwarded-for"];
|
|
82
|
-
if (!forwardedFor) {
|
|
83
|
-
return req.socket.remoteAddress || "unknown";
|
|
84
|
-
}
|
|
85
|
-
const forwardedIPs = (Array.isArray(forwardedFor) ? forwardedFor.join(",") : forwardedFor)
|
|
86
|
-
.split(",")
|
|
87
|
-
.map((ip) => ip.trim())
|
|
88
|
-
.filter((ip) => ip.length > 0);
|
|
89
|
-
if (forwardedIPs.length === 0) {
|
|
90
|
-
return req.socket.remoteAddress || "unknown";
|
|
91
|
-
}
|
|
92
|
-
// Calculate which IP to trust by skipping the rightmost N trusted proxies
|
|
93
|
-
const clientIPIndex = Math.max(0, forwardedIPs.length - trustProxyDepth - 1);
|
|
94
|
-
return forwardedIPs[clientIPIndex];
|
|
95
|
-
}
|
|
96
|
-
//# sourceMappingURL=ipExtractor.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ipExtractor.js","sourceRoot":"","sources":["../../src/server/ipExtractor.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,eAAe,CAAC,GAAyB,EAAE,kBAA0B,CAAC;IAClF,+DAA+D;IAC/D,IAAI,eAAe,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;IACjD,CAAC;IAED,6BAA6B;IAC7B,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpD,IAAI,CAAC,YAAY,EAAE,CAAC;QAChB,4DAA4D;QAC5D,OAAO,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;IACjD,CAAC;IAED,qEAAqE;IACrE,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;SACrF,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;SACtB,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEnC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,wDAAwD;QACxD,OAAO,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;IACjD,CAAC;IAED,iDAAiD;IACjD,kDAAkD;IAClD,qDAAqD;IACrD,6EAA6E;IAE7E,IAAI,YAAY,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACxC,wEAAwE;QACxE,4CAA4C;QAC5C,OAAO,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;IACjD,CAAC;IAED,4CAA4C;IAC5C,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAyB,EAAE,kBAA0B,CAAC;IAC3F,IAAI,eAAe,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;IACjD,CAAC;IAED,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpD,IAAI,CAAC,YAAY,EAAE,CAAC;QAChB,OAAO,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;IACjD,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;SACrF,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;SACtB,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEnC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;IACjD,CAAC;IAED,0EAA0E;IAC1E,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,GAAG,eAAe,GAAG,CAAC,CAAC,CAAC;IAC7E,OAAO,YAAY,CAAC,aAAa,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=deepEqual.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deepEqual.d.ts","sourceRoot":"","sources":["../../src/utils/deepEqual.ts"],"names":[],"mappings":""}
|
package/dist/utils/deepEqual.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deepEqual.js","sourceRoot":"","sources":["../../src/utils/deepEqual.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"formatError.d.ts","sourceRoot":"","sources":["../../src/utils/formatError.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAgBhD"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export function formatError(err) {
|
|
2
|
-
console.log("🚀 ~ formatError ~ err:", err);
|
|
3
|
-
if (err instanceof Error) {
|
|
4
|
-
return err.message;
|
|
5
|
-
}
|
|
6
|
-
if (typeof err === "object" && err !== null) {
|
|
7
|
-
if ("message" in err) {
|
|
8
|
-
return String(err.message);
|
|
9
|
-
}
|
|
10
|
-
// Format Record<string, string> errors
|
|
11
|
-
return JSON.stringify(err, null, 2);
|
|
12
|
-
}
|
|
13
|
-
if (typeof err === "string") {
|
|
14
|
-
return err;
|
|
15
|
-
}
|
|
16
|
-
return String(err);
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=formatError.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"formatError.js","sourceRoot":"","sources":["../../src/utils/formatError.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,GAAY;IACpC,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,OAAO,CAAC;IACvB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC1C,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QACD,uCAAuC;QACvC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,GAAG,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC"}
|