heliumts 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/helium.js +3 -2
- package/dist/bin/helium.js.map +1 -1
- package/dist/client/rpcClient.d.ts.map +1 -1
- package/dist/client/rpcClient.js +79 -2
- package/dist/client/rpcClient.js.map +1 -1
- package/dist/server/ipExtractor.d.ts +48 -0
- package/dist/server/ipExtractor.d.ts.map +1 -0
- package/dist/server/ipExtractor.js +96 -0
- package/dist/server/ipExtractor.js.map +1 -0
- package/dist/utils/deepEqual.d.ts +1 -0
- package/dist/utils/deepEqual.d.ts.map +1 -0
- package/dist/utils/deepEqual.js +2 -0
- package/dist/utils/deepEqual.js.map +1 -0
- package/dist/utils/formatError.d.ts +2 -0
- package/dist/utils/formatError.d.ts.map +1 -0
- package/dist/utils/formatError.js +18 -0
- package/dist/utils/formatError.js.map +1 -0
- package/package.json +1 -1
package/dist/bin/helium.js
CHANGED
|
@@ -78,7 +78,7 @@ cli.command("build", "Build for production").action(async () => {
|
|
|
78
78
|
log("info", "Building server...");
|
|
79
79
|
// Generate server entry
|
|
80
80
|
const serverExports = scanServerExports(root);
|
|
81
|
-
const manifestCode = generateServerManifest(serverExports.methods, serverExports.httpHandlers, serverExports.middleware);
|
|
81
|
+
const manifestCode = generateServerManifest(serverExports.methods, serverExports.httpHandlers, serverExports.middleware, serverExports.workers);
|
|
82
82
|
// Create the main server module that will be imported after env is loaded
|
|
83
83
|
const serverModuleCode = `
|
|
84
84
|
import { startProdServer, loadConfig } from 'heliumts/server';
|
|
@@ -96,7 +96,8 @@ export async function start() {
|
|
|
96
96
|
registry.setMiddleware(middlewareHandler);
|
|
97
97
|
httpRouter.setMiddleware(middlewareHandler);
|
|
98
98
|
}
|
|
99
|
-
}
|
|
99
|
+
},
|
|
100
|
+
workers
|
|
100
101
|
});
|
|
101
102
|
}
|
|
102
103
|
`;
|
package/dist/bin/helium.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helium.js","sourceRoot":"","sources":["../../src/bin/helium.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { cac } from \"cac\";\nimport { spawn } from \"child_process\";\nimport { build as esbuild } from \"esbuild\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { build as viteBuild } from \"vite\";\n\nimport { log } from \"../utils/logger.js\";\nimport { scanServerExports } from \"../vite/scanner.js\";\nimport { generateStaticPages } from \"../vite/ssg.js\";\nimport { generateServerManifest } from \"../vite/virtualServerModule.js\";\n\nconst cli = cac(\"helium\");\nconst root = process.cwd();\n\ncli.command(\"dev\", \"Start development server\").action(async () => {\n const vite = spawn(\"vite\", [], { stdio: \"inherit\", shell: true });\n vite.on(\"close\", (code) => {\n process.exit(code || 0);\n });\n});\n\ncli.command(\"build\", \"Build for production\").action(async () => {\n log(\"info\", \"--------------------------------\");\n log(\"info\", \"Building client...\");\n\n try {\n const result = await viteBuild({\n root,\n logLevel: \"silent\",\n build: {\n outDir: \"dist\",\n },\n });\n\n // Display build output\n if (result && \"output\" in result) {\n const outputs = result.output;\n const zlib = await import(\"zlib\");\n\n for (const chunk of outputs) {\n if (chunk.type === \"asset\" || chunk.type === \"chunk\") {\n const fileName = chunk.fileName;\n const content = \"code\" in chunk ? chunk.code : chunk.source;\n const size = Buffer.byteLength(content, \"utf-8\");\n const sizeKB = (size / 1024).toFixed(2);\n\n // Calculate gzipped size\n const gzipped = zlib.gzipSync(content);\n const gzipSizeKB = (gzipped.length / 1024).toFixed(2);\n\n log(\"info\", ` ${fileName.padEnd(35)} ${sizeKB.padStart(8)} kB │ gzip: ${gzipSizeKB.padStart(7)} kB`);\n }\n }\n }\n\n log(\"info\", \"Client build complete.\");\n\n // Generate static pages for SSG\n log(\"info\", \"--------------------------------\");\n try {\n // Read the generated index.html as a template for SSG\n const distDir = path.join(root, \"dist\");\n const htmlPath = path.join(distDir, \"index.html\");\n\n if (fs.existsSync(htmlPath)) {\n let htmlTemplate = fs.readFileSync(htmlPath, \"utf-8\");\n\n // Clean up the template for SSG:\n // 1. Remove the build-time HELIUM_CONNECTION_TOKEN (SSG pages don't need it)\n htmlTemplate = htmlTemplate.replace(/<script>window\\.HELIUM_CONNECTION_TOKEN = \"build-time-placeholder\";<\\/script>/g, \"\");\n\n // 2. Clear any existing content in root div from SPA build\n htmlTemplate = htmlTemplate.replace(/<div\\s+id=\"root\"[^>]*>.*?<\\/div>/s, '<div id=\"root\"></div>');\n\n await generateStaticPages(null, root, htmlTemplate, distDir);\n } else {\n log(\"warn\", \"index.html not found in dist, skipping SSG\");\n }\n } catch (e) {\n log(\"warn\", \"SSG generation failed:\", e);\n // Don't fail the build if SSG fails\n }\n log(\"info\", \"--------------------------------\");\n } catch (e) {\n log(\"error\", \"Client build failed:\", e);\n process.exit(1);\n }\n\n log(\"info\", \"Building server...\");\n // Generate server entry\n const serverExports = scanServerExports(root);\n const manifestCode = generateServerManifest(serverExports.methods, serverExports.httpHandlers, serverExports.middleware);\n\n // Create the main server module that will be imported after env is loaded\n const serverModuleCode = `\nimport { startProdServer, loadConfig } from 'heliumts/server';\n${manifestCode}\n\nexport async function start() {\n const config = await loadConfig();\n\n startProdServer({\n config,\n registerHandlers: (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n }\n });\n}\n`;\n\n // Create the entry loader that loads env first, then imports the server module\n const entryCode = `\n// Load environment variables FIRST, before any other imports\nimport './env-loader.js';\n// Now import and start the server (this ensures handlers load after env)\nimport { start } from './server-module.js';\nawait start();\n`;\n\n const envLoaderCode = `\nimport { loadEnvFiles, injectEnvToProcess, log } from 'heliumts/server';\nconst envRoot = process.cwd();\nlog('info', \\`Loading .env files from: \\${envRoot}\\`);\nconst envVars = loadEnvFiles({ mode: 'production' });\ninjectEnvToProcess(envVars);\nif (Object.keys(envVars).length > 0) {\n log('info', \\`Loaded \\${Object.keys(envVars).length} environment variable(s) from .env files\\`);\n} else {\n log('info', 'No .env files found (using platform environment variables if available)');\n}\n`;\n\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, \"server-entry.ts\");\n const envLoaderPath = path.join(heliumDir, \"env-loader.ts\");\n const serverModuleSrcPath = path.join(heliumDir, \"server-module.ts\");\n\n fs.writeFileSync(entryPath, entryCode);\n fs.writeFileSync(envLoaderPath, envLoaderCode);\n fs.writeFileSync(serverModuleSrcPath, serverModuleCode);\n\n // Bundle with esbuild\n try {\n await esbuild({\n entryPoints: [entryPath],\n outfile: path.join(root, \"dist\", \"server.js\"),\n bundle: true,\n platform: \"node\",\n format: \"esm\",\n external: [\n // External common database and heavy dependencies\n \"mongodb\",\n \"mongoose\",\n \"pg\",\n \"mysql\",\n \"mysql2\",\n \"sqlite3\",\n \"better-sqlite3\",\n \"redis\",\n // Node.js built-ins are automatically external, but let's be explicit\n \"crypto\",\n \"fs\",\n \"path\",\n \"http\",\n \"https\",\n \"stream\",\n \"zlib\",\n \"util\",\n ],\n target: \"node18\",\n metafile: true,\n banner: {\n js: \"import { createRequire } from 'module'; const require = createRequire(import.meta.url);\",\n },\n });\n\n // Display server build output\n const serverOutputPath = path.relative(root, path.join(root, \"dist\", \"server.js\"));\n const serverStats = fs.statSync(path.join(root, \"dist\", \"server.js\"));\n const serverSizeKB = (serverStats.size / 1024).toFixed(2);\n log(\"info\", ` ${serverOutputPath.padEnd(35)} ${serverSizeKB.padStart(8)} kB`);\n\n log(\"info\", \"Server build complete.\");\n\n // Transpile helium.config.ts to helium.config.js if it exists\n const configTsPath = path.join(root, \"helium.config.ts\");\n if (fs.existsSync(configTsPath)) {\n log(\"info\", \"Transpiling helium.config.ts...\");\n try {\n await esbuild({\n entryPoints: [configTsPath],\n outfile: path.join(root, \"dist\", \"helium.config.js\"),\n bundle: false,\n platform: \"node\",\n format: \"esm\",\n target: \"node18\",\n });\n log(\"info\", \"Config file transpiled to dist/helium.config.js\");\n } catch (e) {\n log(\"warn\", \"Failed to transpile config file:\", e);\n log(\"warn\", \"You may need to manually rename helium.config.ts to helium.config.js\");\n }\n } else {\n // Check if .js or .mjs config exists and copy it to dist\n const configJsPath = path.join(root, \"helium.config.js\");\n const configMjsPath = path.join(root, \"helium.config.mjs\");\n\n if (fs.existsSync(configJsPath)) {\n fs.copyFileSync(configJsPath, path.join(root, \"dist\", \"helium.config.js\"));\n log(\"info\", \"Copied helium.config.js to dist/\");\n } else if (fs.existsSync(configMjsPath)) {\n fs.copyFileSync(configMjsPath, path.join(root, \"dist\", \"helium.config.mjs\"));\n log(\"info\", \"Copied helium.config.mjs to dist/\");\n }\n }\n\n log(\"info\", \"--------------------------------\");\n log(\"info\", \"✓ Build finished successfully.\");\n log(\"info\", \"▶ Run 'helium start' to start the production server.\");\n\n // Exit cleanly after build completes\n process.exit(0);\n } catch (e) {\n log(\"error\", \"Server build failed:\", e);\n process.exit(1);\n }\n});\n\ncli.command(\"start\", \"Start production server\").action(async () => {\n const serverPath = path.join(root, \"dist\", \"server.js\");\n if (!fs.existsSync(serverPath)) {\n log(\"error\", 'Server build not found. Run \"helium build\" first.');\n process.exit(1);\n }\n\n // When running in production, look for config in dist directory first\n // This allows the transpiled config to be found\n const server = spawn(\"node\", [serverPath], {\n stdio: \"inherit\",\n shell: true,\n env: { ...process.env, HELIUM_CONFIG_DIR: path.join(root, \"dist\") },\n });\n server.on(\"close\", (code) => {\n process.exit(code || 0);\n });\n});\n\ncli.help();\ncli.parse();\n"]}
|
|
1
|
+
{"version":3,"file":"helium.js","sourceRoot":"","sources":["../../src/bin/helium.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { cac } from \"cac\";\nimport { spawn } from \"child_process\";\nimport { build as esbuild } from \"esbuild\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { build as viteBuild } from \"vite\";\n\nimport { log } from \"../utils/logger.js\";\nimport { scanServerExports } from \"../vite/scanner.js\";\nimport { generateStaticPages } from \"../vite/ssg.js\";\nimport { generateServerManifest } from \"../vite/virtualServerModule.js\";\n\nconst cli = cac(\"helium\");\nconst root = process.cwd();\n\ncli.command(\"dev\", \"Start development server\").action(async () => {\n const vite = spawn(\"vite\", [], { stdio: \"inherit\", shell: true });\n vite.on(\"close\", (code) => {\n process.exit(code || 0);\n });\n});\n\ncli.command(\"build\", \"Build for production\").action(async () => {\n log(\"info\", \"--------------------------------\");\n log(\"info\", \"Building client...\");\n\n try {\n const result = await viteBuild({\n root,\n logLevel: \"silent\",\n build: {\n outDir: \"dist\",\n },\n });\n\n // Display build output\n if (result && \"output\" in result) {\n const outputs = result.output;\n const zlib = await import(\"zlib\");\n\n for (const chunk of outputs) {\n if (chunk.type === \"asset\" || chunk.type === \"chunk\") {\n const fileName = chunk.fileName;\n const content = \"code\" in chunk ? chunk.code : chunk.source;\n const size = Buffer.byteLength(content, \"utf-8\");\n const sizeKB = (size / 1024).toFixed(2);\n\n // Calculate gzipped size\n const gzipped = zlib.gzipSync(content);\n const gzipSizeKB = (gzipped.length / 1024).toFixed(2);\n\n log(\"info\", ` ${fileName.padEnd(35)} ${sizeKB.padStart(8)} kB │ gzip: ${gzipSizeKB.padStart(7)} kB`);\n }\n }\n }\n\n log(\"info\", \"Client build complete.\");\n\n // Generate static pages for SSG\n log(\"info\", \"--------------------------------\");\n try {\n // Read the generated index.html as a template for SSG\n const distDir = path.join(root, \"dist\");\n const htmlPath = path.join(distDir, \"index.html\");\n\n if (fs.existsSync(htmlPath)) {\n let htmlTemplate = fs.readFileSync(htmlPath, \"utf-8\");\n\n // Clean up the template for SSG:\n // 1. Remove the build-time HELIUM_CONNECTION_TOKEN (SSG pages don't need it)\n htmlTemplate = htmlTemplate.replace(/<script>window\\.HELIUM_CONNECTION_TOKEN = \"build-time-placeholder\";<\\/script>/g, \"\");\n\n // 2. Clear any existing content in root div from SPA build\n htmlTemplate = htmlTemplate.replace(/<div\\s+id=\"root\"[^>]*>.*?<\\/div>/s, '<div id=\"root\"></div>');\n\n await generateStaticPages(null, root, htmlTemplate, distDir);\n } else {\n log(\"warn\", \"index.html not found in dist, skipping SSG\");\n }\n } catch (e) {\n log(\"warn\", \"SSG generation failed:\", e);\n // Don't fail the build if SSG fails\n }\n log(\"info\", \"--------------------------------\");\n } catch (e) {\n log(\"error\", \"Client build failed:\", e);\n process.exit(1);\n }\n\n log(\"info\", \"Building server...\");\n // Generate server entry\n const serverExports = scanServerExports(root);\n const manifestCode = generateServerManifest(serverExports.methods, serverExports.httpHandlers, serverExports.middleware, serverExports.workers);\n\n // Create the main server module that will be imported after env is loaded\n const serverModuleCode = `\nimport { startProdServer, loadConfig } from 'heliumts/server';\n${manifestCode}\n\nexport async function start() {\n const config = await loadConfig();\n\n startProdServer({\n config,\n registerHandlers: (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n workers\n });\n}\n`;\n\n // Create the entry loader that loads env first, then imports the server module\n const entryCode = `\n// Load environment variables FIRST, before any other imports\nimport './env-loader.js';\n// Now import and start the server (this ensures handlers load after env)\nimport { start } from './server-module.js';\nawait start();\n`;\n\n const envLoaderCode = `\nimport { loadEnvFiles, injectEnvToProcess, log } from 'heliumts/server';\nconst envRoot = process.cwd();\nlog('info', \\`Loading .env files from: \\${envRoot}\\`);\nconst envVars = loadEnvFiles({ mode: 'production' });\ninjectEnvToProcess(envVars);\nif (Object.keys(envVars).length > 0) {\n log('info', \\`Loaded \\${Object.keys(envVars).length} environment variable(s) from .env files\\`);\n} else {\n log('info', 'No .env files found (using platform environment variables if available)');\n}\n`;\n\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, \"server-entry.ts\");\n const envLoaderPath = path.join(heliumDir, \"env-loader.ts\");\n const serverModuleSrcPath = path.join(heliumDir, \"server-module.ts\");\n\n fs.writeFileSync(entryPath, entryCode);\n fs.writeFileSync(envLoaderPath, envLoaderCode);\n fs.writeFileSync(serverModuleSrcPath, serverModuleCode);\n\n // Bundle with esbuild\n try {\n await esbuild({\n entryPoints: [entryPath],\n outfile: path.join(root, \"dist\", \"server.js\"),\n bundle: true,\n platform: \"node\",\n format: \"esm\",\n external: [\n // External common database and heavy dependencies\n \"mongodb\",\n \"mongoose\",\n \"pg\",\n \"mysql\",\n \"mysql2\",\n \"sqlite3\",\n \"better-sqlite3\",\n \"redis\",\n // Node.js built-ins are automatically external, but let's be explicit\n \"crypto\",\n \"fs\",\n \"path\",\n \"http\",\n \"https\",\n \"stream\",\n \"zlib\",\n \"util\",\n ],\n target: \"node18\",\n metafile: true,\n banner: {\n js: \"import { createRequire } from 'module'; const require = createRequire(import.meta.url);\",\n },\n });\n\n // Display server build output\n const serverOutputPath = path.relative(root, path.join(root, \"dist\", \"server.js\"));\n const serverStats = fs.statSync(path.join(root, \"dist\", \"server.js\"));\n const serverSizeKB = (serverStats.size / 1024).toFixed(2);\n log(\"info\", ` ${serverOutputPath.padEnd(35)} ${serverSizeKB.padStart(8)} kB`);\n\n log(\"info\", \"Server build complete.\");\n\n // Transpile helium.config.ts to helium.config.js if it exists\n const configTsPath = path.join(root, \"helium.config.ts\");\n if (fs.existsSync(configTsPath)) {\n log(\"info\", \"Transpiling helium.config.ts...\");\n try {\n await esbuild({\n entryPoints: [configTsPath],\n outfile: path.join(root, \"dist\", \"helium.config.js\"),\n bundle: false,\n platform: \"node\",\n format: \"esm\",\n target: \"node18\",\n });\n log(\"info\", \"Config file transpiled to dist/helium.config.js\");\n } catch (e) {\n log(\"warn\", \"Failed to transpile config file:\", e);\n log(\"warn\", \"You may need to manually rename helium.config.ts to helium.config.js\");\n }\n } else {\n // Check if .js or .mjs config exists and copy it to dist\n const configJsPath = path.join(root, \"helium.config.js\");\n const configMjsPath = path.join(root, \"helium.config.mjs\");\n\n if (fs.existsSync(configJsPath)) {\n fs.copyFileSync(configJsPath, path.join(root, \"dist\", \"helium.config.js\"));\n log(\"info\", \"Copied helium.config.js to dist/\");\n } else if (fs.existsSync(configMjsPath)) {\n fs.copyFileSync(configMjsPath, path.join(root, \"dist\", \"helium.config.mjs\"));\n log(\"info\", \"Copied helium.config.mjs to dist/\");\n }\n }\n\n log(\"info\", \"--------------------------------\");\n log(\"info\", \"✓ Build finished successfully.\");\n log(\"info\", \"▶ Run 'helium start' to start the production server.\");\n\n // Exit cleanly after build completes\n process.exit(0);\n } catch (e) {\n log(\"error\", \"Server build failed:\", e);\n process.exit(1);\n }\n});\n\ncli.command(\"start\", \"Start production server\").action(async () => {\n const serverPath = path.join(root, \"dist\", \"server.js\");\n if (!fs.existsSync(serverPath)) {\n log(\"error\", 'Server build not found. Run \"helium build\" first.');\n process.exit(1);\n }\n\n // When running in production, look for config in dist directory first\n // This allows the transpiled config to be found\n const server = spawn(\"node\", [serverPath], {\n stdio: \"inherit\",\n shell: true,\n env: { ...process.env, HELIUM_CONFIG_DIR: path.join(root, \"dist\") },\n });\n server.on(\"close\", (code) => {\n process.exit(code || 0);\n });\n});\n\ncli.help();\ncli.parse();\n"]}
|
|
@@ -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;AAEF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;AAUzD;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;
|
|
1
|
+
{"version":3,"file":"rpcClient.d.ts","sourceRoot":"","sources":["../../src/client/rpcClient.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA2B,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGhF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACvB,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,QAAQ,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;AAUzD;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAgmBD;;;;;;;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;AA6BD;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAYjC"}
|
package/dist/client/rpcClient.js
CHANGED
|
@@ -90,6 +90,7 @@ async function sendBatchHttp(batch) {
|
|
|
90
90
|
headers,
|
|
91
91
|
body: encoded,
|
|
92
92
|
});
|
|
93
|
+
handleBlockedResponse(response.status, "rpc-http");
|
|
93
94
|
if (!response.ok) {
|
|
94
95
|
throw new Error(`HTTP RPC failed: ${response.status}`);
|
|
95
96
|
}
|
|
@@ -138,6 +139,79 @@ let socket = null;
|
|
|
138
139
|
let connectionPromise = null;
|
|
139
140
|
const pending = new Map();
|
|
140
141
|
const pendingTimeouts = new Map();
|
|
142
|
+
const BLOCKED_HTTP_STATUSES = new Set([401, 403, 429]);
|
|
143
|
+
const BLOCKED_WS_CLOSE_CODES = new Set([1008, 1011, 1013]);
|
|
144
|
+
const BLOCKED_RETRY_THRESHOLD = 3;
|
|
145
|
+
const BLOCKED_RETRY_WINDOW_MS = 1000;
|
|
146
|
+
const BLOCKED_RELOAD_COOLDOWN_MS = 120000;
|
|
147
|
+
const BLOCKED_RELOAD_KEY = "helium:blocked-reload-ts";
|
|
148
|
+
const blockedAttempts = new Map();
|
|
149
|
+
let lastBlockedReloadAt = 0;
|
|
150
|
+
function shouldAutoReloadOnBlock(now) {
|
|
151
|
+
if (typeof window === "undefined") {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const stored = window.sessionStorage.getItem(BLOCKED_RELOAD_KEY);
|
|
156
|
+
const storedTs = stored ? Number(stored) : 0;
|
|
157
|
+
if (storedTs && now - storedTs < BLOCKED_RELOAD_COOLDOWN_MS) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
window.sessionStorage.setItem(BLOCKED_RELOAD_KEY, String(now));
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
if (now - lastBlockedReloadAt < BLOCKED_RELOAD_COOLDOWN_MS) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
lastBlockedReloadAt = now;
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function shouldTriggerBlockedAction(source, now) {
|
|
172
|
+
const state = blockedAttempts.get(source);
|
|
173
|
+
if (!state || now - state.lastTs > BLOCKED_RETRY_WINDOW_MS) {
|
|
174
|
+
blockedAttempts.set(source, { count: 1, lastTs: now });
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
const nextCount = state.count + 1;
|
|
178
|
+
blockedAttempts.set(source, { count: nextCount, lastTs: now });
|
|
179
|
+
return nextCount > BLOCKED_RETRY_THRESHOLD;
|
|
180
|
+
}
|
|
181
|
+
function dispatchBlockedEvent(detail) {
|
|
182
|
+
if (typeof window === "undefined") {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
window.dispatchEvent(new CustomEvent("helium:blocked", {
|
|
186
|
+
detail,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
function handleBlockedResponse(status, source) {
|
|
190
|
+
if (!BLOCKED_HTTP_STATUSES.has(status)) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const now = Date.now();
|
|
194
|
+
if (!shouldTriggerBlockedAction(source, now)) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
dispatchBlockedEvent({ status, source });
|
|
198
|
+
if (shouldAutoReloadOnBlock(now) && typeof window.location?.reload === "function") {
|
|
199
|
+
window.location.reload();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function handleBlockedSocketClose(code) {
|
|
203
|
+
if (!BLOCKED_WS_CLOSE_CODES.has(code)) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const now = Date.now();
|
|
207
|
+
if (!shouldTriggerBlockedAction("rpc-websocket", now)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
dispatchBlockedEvent({ code, source: "rpc-websocket" });
|
|
211
|
+
if (shouldAutoReloadOnBlock(now) && typeof window.location?.reload === "function") {
|
|
212
|
+
window.location.reload();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
141
215
|
// ── Connection resilience constants ──────────────────────────────────────────
|
|
142
216
|
/** How long (ms) the page must be hidden before we consider the WebSocket stale. */
|
|
143
217
|
const STALE_THRESHOLD_MS = 15000;
|
|
@@ -253,6 +327,7 @@ async function fetchFreshToken() {
|
|
|
253
327
|
"X-Requested-With": "HeliumRPC",
|
|
254
328
|
},
|
|
255
329
|
});
|
|
330
|
+
handleBlockedResponse(response.status, "refresh-token");
|
|
256
331
|
if (!response.ok) {
|
|
257
332
|
console.warn("Failed to fetch fresh token:", response.status);
|
|
258
333
|
return undefined;
|
|
@@ -292,8 +367,9 @@ async function createSocket() {
|
|
|
292
367
|
const MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024; // 10 MB
|
|
293
368
|
while (true) {
|
|
294
369
|
const { value, done } = await reader.read();
|
|
295
|
-
if (done)
|
|
370
|
+
if (done) {
|
|
296
371
|
break;
|
|
372
|
+
}
|
|
297
373
|
totalSize += value.length;
|
|
298
374
|
if (totalSize > MAX_DECOMPRESSED_SIZE) {
|
|
299
375
|
reader.cancel();
|
|
@@ -342,7 +418,8 @@ async function createSocket() {
|
|
|
342
418
|
// WebSocket errors are always followed by a close event.
|
|
343
419
|
// The close handler takes care of rejecting pending promises.
|
|
344
420
|
};
|
|
345
|
-
ws.onclose = () => {
|
|
421
|
+
ws.onclose = (event) => {
|
|
422
|
+
handleBlockedSocketClose(event.code);
|
|
346
423
|
if (socket === ws) {
|
|
347
424
|
socket = null;
|
|
348
425
|
connectionPromise = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpcClient.js","sourceRoot":"","sources":["../../src/client/rpcClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGpF,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAmBzC,gDAAgD;AAChD,MAAM,mBAAmB,GAAiB,OAAO,wBAAwB,KAAK,WAAW,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,WAAW,CAAC;AACnI,MAAM,0BAA0B,GAAY,OAAO,kCAAkC,KAAK,WAAW,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,KAAK,CAAC;AAEnJ;;GAEG;AACH,MAAM,UAAU,eAAe;IAC3B,OAAO,mBAAmB,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB;IACrC,OAAO,0BAA0B,CAAC;AACtC,CAAC;AAED,mEAAmE;AACnE,SAAS,sBAAsB;IAC3B,IAAI,mBAAmB,KAAK,MAAM,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,mBAAmB,KAAK,WAAW,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,0DAA0D;IAC1D,IAAI,CAAC,0BAA0B,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,yCAAyC;IACzC,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE,CAAC;QACnC,MAAM,IAAI,GAAI,SAAqC,CAAC,UAAU,CAAC;QAC/D,IAAI,IAAI,EAAE,CAAC;YACP,4DAA4D;YAC5D,MAAM,SAAS,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAC1C,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;gBAC7F,OAAO,IAAI,CAAC;YAChB,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAqBD,IAAI,YAAY,GAAqB,EAAE,CAAC;AACxC,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAE7B,SAAS,aAAa;IAClB,IAAI,gBAAgB,EAAE,CAAC;QACnB,OAAO;IACX,CAAC;IACD,gBAAgB,GAAG,IAAI,CAAC;IACxB,cAAc,CAAC,GAAG,EAAE;QAChB,gBAAgB,GAAG,KAAK,CAAC;QACzB,UAAU,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;AACP,CAAC;AAED,KAAK,UAAU,UAAU;IACrB,MAAM,KAAK,GAAG,YAAY,CAAC;IAC3B,YAAY,GAAG,EAAE,CAAC;IAElB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO;IACX,CAAC;IAED,IAAI,CAAC;QACD,IAAI,sBAAsB,EAAE,EAAE,CAAC;YAC3B,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACJ,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,4BAA4B;QAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;IACL,CAAC;AACL,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,KAAuB;IAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAExC,kDAAkD;IAClD,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;IAEtC,MAAM,OAAO,GAA2B;QACpC,cAAc,EAAE,qBAAqB;QACrC,MAAM,EAAE,qBAAqB;KAChC,CAAC;IACF,IAAI,KAAK,EAAE,CAAC;QACR,OAAO,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC;IACtC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,iBAAiB,EAAE;QAC5C,MAAM,EAAE,MAAM;QACd,OAAO;QACP,IAAI,EAAE,OAA8B;KACvC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,oBAAoB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,UAAU,CAAC,cAAc,CAAC,CAAgC,CAAC;IAEzF,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzC,IAAI,GAAG,EAAE,CAAC;YACN,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACT,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACJ,IAAI,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YACpD,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,yBAAyB,CAAC,CAAC,CAAC;QACzD,CAAC;IACL,CAAC;AACL,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,KAAuB;IACrD,MAAM,EAAE,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEzC,oDAAoD;IACpD,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACnB,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAU,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAmB,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACD,8BAA8B;QAC9B,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACxC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACnB,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACP,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,gDAAgD;AAChD,+EAA+E;AAE/E,IAAI,MAAM,GAAqB,IAAI,CAAC;AACpC,IAAI,iBAAiB,GAA8B,IAAI,CAAC;AAExD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoF,CAAC;AAC5G,MAAM,eAAe,GAAG,IAAI,GAAG,EAAkD,CAAC;AAElF,gFAAgF;AAEhF,oFAAoF;AACpF,MAAM,kBAAkB,GAAG,KAAM,CAAC;AAElC,wEAAwE;AACxE,MAAM,kBAAkB,GAAG,KAAM,CAAC;AAElC,kEAAkE;AAClE,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,sFAAsF;AACtF,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,0EAA0E;AAC1E,MAAM,kBAAkB,GAAG,IAAK,CAAC;AAEjC,iFAAiF;AACjF,IAAI,mBAAmB,GAAkB,IAAI,CAAC;AAE9C,gFAAgF;AAEhF;;;;GAIG;AACH,SAAS,YAAY,CAAC,EAAmB,EAAE,OAA6B,EAAE,MAA4B;IAClG,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;QAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,KAAK,EAAE,CAAC;YACR,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACnB,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC3B,KAAK,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;QACpD,CAAC;IACL,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACvB,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,EAAmB;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnB,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACtC,IAAI,KAAK,EAAE,CAAC;QACR,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,iFAAiF;AACjF,SAAS,gBAAgB,CAAC,MAAa;IACnC,KAAK,MAAM,KAAK,IAAI,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3C,YAAY,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IACD,eAAe,CAAC,KAAK,EAAE,CAAC;IACxB,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACvC,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QAC9B,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;AACL,CAAC;AAED,gFAAgF;AAEhF;;;GAGG;AACH,SAAS,cAAc;IACnB,MAAM,SAAS,GAAG,MAAM,CAAC;IACzB,MAAM,GAAG,IAAI,CAAC;IACd,iBAAiB,GAAG,IAAI,CAAC;IAEzB,IAAI,SAAS,EAAE,CAAC;QACZ,yEAAyE;QACzE,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC;QAC3B,SAAS,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,uEAAuE;IACvE,gBAAgB,CAAC,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,8DAA8D;AAC9D,SAAS,gBAAgB,CAAC,GAAY;IAClC,mDAAmD;IACnD,IAAI,GAAG,YAAY,KAAK,IAAI,CAAC,CAAC,GAAG,YAAY,QAAQ,CAAC,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,mEAAmE;IACnE,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,OAAO,KAAK,mBAAmB,EAAE,CAAC;QACjE,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,gEAAgE;AAChE,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IAClB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE;QACzB,IAAI,MAAM,EAAE,CAAC;YACT,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;YACtB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,IAAI,CAAC;YACd,iBAAiB,GAAG,IAAI,CAAC;QAC7B,CAAC;QACD,gBAAgB,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACP,CAAC;AAED,IAAI,KAAK,GAAG,CAAC,CAAC;AACd,SAAS,MAAM;IACX,OAAO,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,eAAe;IAC1B,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,2BAA2B,EAAE;YACtD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,kBAAkB,EAAE,WAAW;aAClC;SACJ,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC9D,OAAO,SAAS,CAAC;QACrB,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;QACnD,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC;AAED,KAAK,UAAU,YAAY;IACvB,+DAA+D;IAC/D,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;IAEtC,+DAA+D;IAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;IACxE,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,6BAA6B;IAChE,MAAM,GAAG,GAAG,GAAG,QAAQ,KAAK,IAAI,MAAM,CAAC;IACvC,iFAAiF;IACjF,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;IACpE,EAAE,CAAC,UAAU,GAAG,aAAa,CAAC;IAE9B,EAAE,CAAC,SAAS,GAAG,KAAK,EAAE,KAAK,EAAE,EAAE;QAC3B,IAAI,IAAI,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,IAAmB,CAAC,CAAC;QAErD,kEAAkE;QAClE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1D,IAAI,CAAC;gBACD,gFAAgF;gBAChF,IAAI,OAAO,mBAAmB,KAAK,WAAW,EAAE,CAAC;oBAC7C,MAAM,EAAE,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;oBAC3C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;oBACvC,IAAI,MAAM,EAAE,CAAC;wBACT,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;wBAC5C,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC;wBACxC,MAAM,MAAM,GAAiB,EAAE,CAAC;wBAChC,IAAI,SAAS,GAAG,CAAC,CAAC;wBAClB,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;wBACxD,OAAO,IAAI,EAAE,CAAC;4BACV,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;4BAC5C,IAAI,IAAI;gCAAE,MAAM;4BAChB,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC;4BAC1B,IAAI,SAAS,GAAG,qBAAqB,EAAE,CAAC;gCACpC,MAAM,CAAC,MAAM,EAAE,CAAC;gCAChB,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;gCACzD,OAAO;4BACX,CAAC;4BACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;wBACvB,CAAC;wBACD,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;wBAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;wBACf,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;4BACzB,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;4BAC5B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;wBAC3B,CAAC;wBACD,IAAI,GAAG,QAAQ,CAAC;oBACpB,CAAC;gBACL,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;gBAC9D,OAAO;YACX,CAAC;QACL,CAAC;QAED,mCAAmC;QACnC,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAgC,CAAC;QAE/D,MAAM,cAAc,GAAG,CAAC,GAAgB,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,OAAO;YACX,CAAC;YACD,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACT,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;YAC1D,CAAC;iBAAM,CAAC;gBACJ,KAAK,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YACrD,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACJ,cAAc,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;IACL,CAAC,CAAC;IAEF,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;QACd,yDAAyD;QACzD,8DAA8D;IAClE,CAAC,CAAC;IAEF,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;QACd,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;YAChB,MAAM,GAAG,IAAI,CAAC;YACd,iBAAiB,GAAG,IAAI,CAAC;YACzB,sDAAsD;YACtD,gBAAgB,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;QAC/D,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,EAAE,CAAC;AACd,CAAC;AAED,KAAK,UAAU,iBAAiB;IAC5B,mDAAmD;IACnD,IAAI,MAAM,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;QACjD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,0DAA0D;IAC1D,IAAI,iBAAiB,EAAE,CAAC;QACpB,OAAO,iBAAiB,CAAC;IAC7B,CAAC;IAED,qDAAqD;IACrD,IAAI,MAAM,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,UAAU,EAAE,CAAC;QACvD,iBAAiB,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAChD,MAAM,OAAO,GAAG,GAAG,EAAE;gBACjB,MAAO,CAAC,mBAAmB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;gBAChD,MAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;gBAClD,MAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YACtD,CAAC,CAAC;YACF,MAAM,UAAU,GAAG,GAAG,EAAE;gBACpB,OAAO,EAAE,CAAC;gBACV,iBAAiB,GAAG,IAAI,CAAC;gBACzB,OAAO,CAAC,MAAO,CAAC,CAAC;YACrB,CAAC,CAAC;YACF,MAAM,WAAW,GAAG,GAAG,EAAE;gBACrB,OAAO,EAAE,CAAC;gBACV,MAAM,GAAG,IAAI,CAAC;gBACd,iBAAiB,GAAG,IAAI,CAAC;gBACzB,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;YACrD,CAAC,CAAC;YACF,MAAM,WAAW,GAAG,GAAG,EAAE;gBACrB,OAAO,EAAE,CAAC;gBACV,MAAM,GAAG,IAAI,CAAC;gBACd,iBAAiB,GAAG,IAAI,CAAC;gBACzB,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;YACzD,CAAC,CAAC;YAEF,MAAO,CAAC,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAC7C,MAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAC/C,MAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QACH,OAAO,iBAAiB,CAAC;IAC7B,CAAC;IAED,6CAA6C;IAC7C,iBAAiB,GAAG,CAAC,KAAK,IAAI,EAAE;QAC5B,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;QAC9B,OAAO,IAAI,OAAO,CAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,MAAM,OAAO,GAAG,GAAG,EAAE;gBACjB,MAAO,CAAC,mBAAmB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;gBAChD,MAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;gBAClD,MAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YACtD,CAAC,CAAC;YACF,MAAM,UAAU,GAAG,GAAG,EAAE;gBACpB,OAAO,EAAE,CAAC;gBACV,iBAAiB,GAAG,IAAI,CAAC;gBACzB,OAAO,CAAC,MAAO,CAAC,CAAC;YACrB,CAAC,CAAC;YACF,MAAM,WAAW,GAAG,GAAG,EAAE;gBACrB,OAAO,EAAE,CAAC;gBACV,MAAM,GAAG,IAAI,CAAC;gBACd,iBAAiB,GAAG,IAAI,CAAC;gBACzB,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;YACrD,CAAC,CAAC;YACF,MAAM,WAAW,GAAG,GAAG,EAAE;gBACrB,OAAO,EAAE,CAAC;gBACV,MAAM,GAAG,IAAI,CAAC;gBACd,iBAAiB,GAAG,IAAI,CAAC;gBACzB,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;YACzD,CAAC,CAAC;YAEF,MAAO,CAAC,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAC7C,MAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAC/C,MAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,iBAAiB,CAAC;AAC7B,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAiB,QAAgB,EAAE,IAAY;IAC1E,qHAAqH;IACrH,IAAI,MAAM,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,MAAM,GAAG,GAAe,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACvD,OAAO,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACvD,YAAY,CAAC,EAAE,EAAE,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,CAAuB,CAAC,EAAE,MAAM,CAAC,CAAC;YAC3E,IAAI,CAAC;gBACD,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;gBACnC,MAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,aAAa,CAAC,EAAE,CAAC,CAAC;gBAClB,MAAM,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACrC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IAEpB,MAAM,GAAG,GAAe,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAEvD,OAAO,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACvD,YAAY,CAAC,EAAE,EAAE,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,CAAuB,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3E,IAAI,CAAC;YACD,8BAA8B;YAC9B,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;YACnC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,aAAa,CAAC,EAAE,CAAC,CAAC;YAClB,MAAM,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAqC,QAAgB,EAAE,IAAY;IAC5F,OAAO,gBAAgB,CAAiB,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC5D,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAiB,QAAgB,EAAE,IAAuB,EAAE,OAAO,GAAG,CAAC;IAClG,IAAI,CAAC;QACD,IAAI,sBAAsB,EAAE,EAAE,CAAC;YAC3B,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;YACpB,MAAM,GAAG,GAAe,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YAEvD,OAAO,MAAM,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC7D,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,OAA8C,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC5F,aAAa,EAAE,CAAC;YACpB,CAAC,CAAC,CAAC;QACP,CAAC;QAED,OAAO,MAAM,gBAAgB,CAAiB,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,OAAO,GAAG,WAAW,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YACjD,iDAAiD;YACjD,cAAc,EAAE,CAAC;YACjB,wEAAwE;YACxE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,GAAG,CAAC,IAAI,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACnF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,GAAG,GAAG,CAAC;YAC/C,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC;YAClE,OAAO,gBAAgB,CAAiB,QAAQ,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,GAAG,CAAC;IACd,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU;IACtB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAChC,OAAO;IACX,CAAC;IACD,qDAAqD;IACrD,IAAI,sBAAsB,EAAE,EAAE,CAAC;QAC3B,OAAO;IACX,CAAC;IACD,yDAAyD;IACzD,iBAAiB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;QAC3B,iEAAiE;IACrE,CAAC,CAAC,CAAC;AACP,CAAC;AAED,iFAAiF;AACjF,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;IACnE,6DAA6D;IAC7D,MAAM,kBAAkB,GAAG,MAAM,CAAC,mBAAmB,IAAI,CAAC,CAAC,EAAc,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACjG,kBAAkB,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,+EAA+E;AAC/E,gEAAgE;AAChE,+EAA+E;AAC/E,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,qEAAqE;AACrE,wEAAwE;AACxE,6CAA6C;AAC7C,+EAA+E;AAE/E,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;IAClC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/C,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YAClB,mBAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrC,CAAC;aAAM,CAAC;YACJ,4BAA4B;YAC5B,IAAI,mBAAmB,KAAK,IAAI,EAAE,CAAC;gBAC/B,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,mBAAmB,CAAC;gBACxD,IAAI,cAAc,GAAG,kBAAkB,IAAI,MAAM,EAAE,CAAC;oBAChD,cAAc,EAAE,CAAC;gBACrB,CAAC;gBACD,mBAAmB,GAAG,IAAI,CAAC;YAC/B,CAAC;QACL,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC","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\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\n// Detect if we should prefer HTTP transport (mobile/slow networks)\nfunction shouldUseHttpTransport(): boolean {\n if (configuredTransport === \"http\") {\n return true;\n }\n if (configuredTransport === \"websocket\") {\n return false;\n }\n\n // Auto mode: check if mobile HTTP optimization is enabled\n if (!configuredAutoHttpOnMobile) {\n return false;\n }\n\n // Prefer HTTP on mobile/slow 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\ninterface NetworkInformation {\n type?: string;\n effectiveType?: string;\n}\n\ninterface NavigatorWithConnection extends Navigator {\n connection?: NetworkInformation;\n}\n\n// ============================================================================\n// Batching Logic\n// ============================================================================\n\ntype PendingRequest = {\n req: RpcRequest;\n resolve: (value: RpcResult<any>) => void;\n reject: (reason?: any) => void;\n};\n\nlet pendingBatch: PendingRequest[] = [];\nlet isBatchScheduled = false;\n\nfunction scheduleBatch() {\n if (isBatchScheduled) {\n return;\n }\n isBatchScheduled = true;\n queueMicrotask(() => {\n isBatchScheduled = false;\n flushBatch();\n });\n}\n\nasync function flushBatch() {\n const batch = pendingBatch;\n pendingBatch = [];\n\n if (batch.length === 0) {\n return;\n }\n\n try {\n if (shouldUseHttpTransport()) {\n await sendBatchHttp(batch);\n } else {\n await sendBatchWebSocket(batch);\n }\n } catch (err) {\n // Transport error, fail all\n for (const item of batch) {\n item.reject(err);\n }\n }\n}\n\nasync function sendBatchHttp(batch: PendingRequest[]) {\n const requests = batch.map((b) => b.req);\n const encoded = msgpackEncode(requests);\n\n // Fetch a fresh token for HTTP RPC authentication\n const token = await fetchFreshToken();\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/msgpack\",\n Accept: \"application/msgpack\",\n };\n if (token) {\n headers[\"X-Helium-Token\"] = token;\n }\n\n const response = await fetch(\"/__helium__/rpc\", {\n method: \"POST\",\n headers,\n body: encoded as unknown as BodyInit,\n });\n\n 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(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// ── 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 response before timing out a request. */\nconst REQUEST_TIMEOUT_MS = 30_000;\n\n/** Number of automatic retries on retriable connection errors. */\nconst MAX_RETRIES = 3;\n\n/** Base delay (ms) for exponential backoff between retries (doubles each attempt). */\nconst RETRY_BASE_DELAY_MS = 500;\n\n/** Maximum delay (ms) cap for backoff to avoid excessively long waits. */\nconst RETRY_MAX_DELAY_MS = 5_000;\n\n/** Timestamp when the page was last hidden (for visibility-change detection). */\nlet lastHiddenTimestamp: number | null = null;\n\n// ── Pending-request helpers ──────────────────────────────────────────────────\n\n/**\n * Register a pending request with an automatic timeout safeguard.\n * If no response arrives within REQUEST_TIMEOUT_MS the promise is rejected\n * so the caller's retry logic can kick in.\n */\nfunction trackPending(id: string | number, resolve: (v: unknown) => void, reject: (e: unknown) => void): void {\n pending.set(id, { resolve, reject });\n const timer = setTimeout(() => {\n const entry = pending.get(id);\n if (entry) {\n pending.delete(id);\n pendingTimeouts.delete(id);\n entry.reject(new RpcError(\"Request timed out\"));\n }\n }, REQUEST_TIMEOUT_MS);\n pendingTimeouts.set(id, timer);\n}\n\n/**\n * Remove a pending request and clear its timeout.\n * Returns the entry so the caller can resolve/reject it.\n */\nfunction removePending(id: string | number): { resolve: (v: unknown) => void; reject: (e: unknown) => void } | undefined {\n const entry = pending.get(id);\n if (!entry) {\n return undefined;\n }\n pending.delete(id);\n const timer = pendingTimeouts.get(id);\n if (timer) {\n clearTimeout(timer);\n pendingTimeouts.delete(id);\n }\n return entry;\n}\n\n/** Reject every in-flight request (e.g. when the socket closes unexpectedly). */\nfunction rejectAllPending(reason: Error): void {\n for (const timer of pendingTimeouts.values()) {\n clearTimeout(timer);\n }\n pendingTimeouts.clear();\n const entries = [...pending.entries()];\n pending.clear();\n for (const [, entry] of entries) {\n entry.reject(reason);\n }\n}\n\n// ── Reconnection helpers ─────────────────────────────────────────────────────\n\n/**\n * Force-close the current WebSocket so the next call creates a fresh\n * connection (which fetches a brand-new token).\n */\nfunction forceReconnect(): void {\n const oldSocket = socket;\n socket = null;\n connectionPromise = null;\n\n if (oldSocket) {\n // Detach handlers to avoid double-rejecting pending from the close event\n oldSocket.onclose = null;\n oldSocket.onerror = null;\n oldSocket.onmessage = null;\n oldSocket.close();\n }\n\n // Reject all in-flight requests – callers with retry logic will resend\n rejectAllPending(new Error(\"Connection reset\"));\n}\n\n/** Determine whether an error warrants an automatic retry. */\nfunction isRetriableError(err: unknown): boolean {\n // Network / connection errors are always retriable\n if (err instanceof Error && !(err instanceof RpcError)) {\n return true;\n }\n // Timed-out requests are retriable (socket may have died silently)\n if (err instanceof RpcError && err.message === \"Request timed out\") {\n return true;\n }\n return false;\n}\n\n// Clean up WebSocket connection on HMR (Hot Module Replacement)\nif (import.meta.hot) {\n import.meta.hot.dispose(() => {\n if (socket) {\n socket.onclose = null;\n socket.close();\n socket = null;\n connectionPromise = null;\n }\n rejectAllPending(new Error(\"Module reloaded\"));\n });\n}\n\nlet msgId = 0;\nfunction nextId() {\n return msgId++;\n}\n\nasync function fetchFreshToken(): Promise<string | undefined> {\n try {\n const response = await fetch(\"/__helium__/refresh-token\", {\n method: \"POST\",\n headers: {\n \"X-Requested-With\": \"HeliumRPC\",\n },\n });\n if (!response.ok) {\n console.warn(\"Failed to fetch fresh token:\", response.status);\n return undefined;\n }\n const data = await response.json();\n return data.token;\n } catch (error) {\n console.warn(\"Error fetching fresh token:\", error);\n return undefined;\n }\n}\n\nasync function createSocket(): Promise<WebSocket> {\n // Fetch a fresh token before creating the WebSocket connection\n const token = await fetchFreshToken();\n\n // Use the same protocol, hostname and port as the current page\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = window.location.host; // includes hostname and port\n const url = `${protocol}//${host}/rpc`;\n // Security: pass token via Sec-WebSocket-Protocol header instead of query string\n const ws = token ? new WebSocket(url, [token]) : new WebSocket(url);\n ws.binaryType = \"arraybuffer\";\n\n ws.onmessage = async (event) => {\n let data = new Uint8Array(event.data as ArrayBuffer);\n\n // Check for Gzip header (0x1f 0x8b) to detect compressed messages\n if (data.length > 2 && data[0] === 0x1f && data[1] === 0x8b) {\n try {\n // Use DecompressionStream if available (Chrome 80+, Firefox 113+, Safari 16.4+)\n if (typeof DecompressionStream !== \"undefined\") {\n const ds = new DecompressionStream(\"gzip\");\n const stream = new Response(data).body;\n if (stream) {\n const decompressed = stream.pipeThrough(ds);\n const reader = decompressed.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n const MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024; // 10 MB\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\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 = () => {\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\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 // If we have a socket that's connecting, wait for it\n if (socket && socket.readyState === WebSocket.CONNECTING) {\n connectionPromise = new Promise((resolve, reject) => {\n const cleanup = () => {\n socket!.removeEventListener(\"open\", handleOpen);\n socket!.removeEventListener(\"error\", handleError);\n socket!.removeEventListener(\"close\", handleClose);\n };\n const handleOpen = () => {\n cleanup();\n connectionPromise = null;\n resolve(socket!);\n };\n const handleError = () => {\n cleanup();\n socket = null;\n connectionPromise = null;\n reject(new Error(\"WebSocket connection failed\"));\n };\n const handleClose = () => {\n cleanup();\n socket = null;\n connectionPromise = null;\n reject(new Error(\"WebSocket closed before opening\"));\n };\n\n socket!.addEventListener(\"open\", handleOpen);\n socket!.addEventListener(\"error\", handleError);\n socket!.addEventListener(\"close\", handleClose);\n });\n return connectionPromise;\n }\n\n // Create a new socket and connection promise\n connectionPromise = (async () => {\n socket = await createSocket();\n return new Promise<WebSocket>((resolve, reject) => {\n const cleanup = () => {\n socket!.removeEventListener(\"open\", handleOpen);\n socket!.removeEventListener(\"error\", handleError);\n socket!.removeEventListener(\"close\", handleClose);\n };\n const handleOpen = () => {\n cleanup();\n connectionPromise = null;\n resolve(socket!);\n };\n const handleError = () => {\n cleanup();\n socket = null;\n connectionPromise = null;\n reject(new Error(\"WebSocket connection failed\"));\n };\n const handleClose = () => {\n cleanup();\n socket = null;\n connectionPromise = null;\n reject(new Error(\"WebSocket closed before opening\"));\n };\n\n socket!.addEventListener(\"open\", handleOpen);\n socket!.addEventListener(\"error\", handleError);\n socket!.addEventListener(\"close\", handleClose);\n });\n })();\n\n return connectionPromise;\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(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(encoded);\n } catch (err) {\n removePending(id);\n reject(err);\n }\n });\n}\n\n/**\n * Make an RPC call using the appropriate transport.\n * Automatically selects HTTP or WebSocket based on network conditions and configuration.\n *\n * Includes automatic retry logic: if a call fails due to a connection error\n * (e.g. stale WebSocket after mobile browser was backgrounded), the client\n * forces a fresh connection (with a new token) and retries once.\n */\nexport async function rpcCall<TResult = unknown, TArgs = unknown>(methodId: string, args?: TArgs): Promise<RpcResult<TResult>> {\n return rpcCallWithRetry<TResult, TArgs>(methodId, args);\n}\n\nasync function rpcCallWithRetry<TResult, TArgs>(methodId: string, args: TArgs | undefined, attempt = 0): Promise<RpcResult<TResult>> {\n try {\n if (shouldUseHttpTransport()) {\n const id = nextId();\n const req: RpcRequest = { id, method: methodId, args };\n\n return await new Promise<RpcResult<TResult>>((resolve, reject) => {\n pendingBatch.push({ req, resolve: resolve as (value: RpcResult<TResult>) => void, reject });\n scheduleBatch();\n });\n }\n\n return await rpcCallWebSocket<TResult, TArgs>(methodId, args);\n } catch (err) {\n if (attempt < MAX_RETRIES && isRetriableError(err)) {\n // Force a fresh connection (fetches a new token)\n forceReconnect();\n // Exponential backoff with jitter: 500ms, 1000ms, 2000ms (capped at 5s)\n const baseDelay = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS);\n const jitter = Math.random() * baseDelay * 0.3;\n await new Promise<void>((r) => setTimeout(r, baseDelay + jitter));\n return rpcCallWithRetry<TResult, TArgs>(methodId, args, attempt + 1);\n }\n throw err;\n }\n}\n\n/**\n * Pre-establishes the WebSocket connection.\n * Call this early (e.g., on page load) to avoid connection latency on first RPC call.\n * This is especially beneficial on high-latency networks like mobile LTE.\n * Note: Only effective when using WebSocket transport (not HTTP transport).\n */\nexport function preconnect(): void {\n if (typeof window === \"undefined\") {\n return;\n }\n // Only preconnect if we're using WebSocket transport\n if (shouldUseHttpTransport()) {\n return;\n }\n // Fire and forget - establishes connection in background\n ensureSocketReady().catch(() => {\n // Silently ignore preconnect failures, will retry on actual call\n });\n}\n\n// Auto-preconnect when the module loads (browser only, WebSocket transport only)\nif (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n // Use requestIdleCallback if available, otherwise setTimeout\n const schedulePreconnect = window.requestIdleCallback || ((cb: () => void) => setTimeout(cb, 1));\n schedulePreconnect(() => preconnect());\n}\n\n// ============================================================================\n// Visibility-change reconnection (critical for mobile browsers)\n// ============================================================================\n//\n// Mobile browsers freeze or kill WebSocket connections when the tab is\n// backgrounded. When the user returns the socket may *appear* open but\n// is actually stale. We detect this via the Page Visibility API and\n// proactively tear down the old connection so the next RPC call creates\n// a fresh one (with a brand-new auth token).\n// ============================================================================\n\nif (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", () => {\n if (document.hidden) {\n lastHiddenTimestamp = Date.now();\n } else {\n // Page became visible again\n if (lastHiddenTimestamp !== null) {\n const hiddenDuration = Date.now() - lastHiddenTimestamp;\n if (hiddenDuration > STALE_THRESHOLD_MS && socket) {\n forceReconnect();\n }\n lastHiddenTimestamp = null;\n }\n }\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\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\n// Detect if we should prefer HTTP transport (mobile/slow networks)\nfunction shouldUseHttpTransport(): boolean {\n if (configuredTransport === \"http\") {\n return true;\n }\n if (configuredTransport === \"websocket\") {\n return false;\n }\n\n // Auto mode: check if mobile HTTP optimization is enabled\n if (!configuredAutoHttpOnMobile) {\n return false;\n }\n\n // Prefer HTTP on mobile/slow 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\ninterface NetworkInformation {\n type?: string;\n effectiveType?: string;\n}\n\ninterface NavigatorWithConnection extends Navigator {\n connection?: NetworkInformation;\n}\n\n// ============================================================================\n// Batching Logic\n// ============================================================================\n\ntype PendingRequest = {\n req: RpcRequest;\n resolve: (value: RpcResult<any>) => void;\n reject: (reason?: any) => void;\n};\n\nlet pendingBatch: PendingRequest[] = [];\nlet isBatchScheduled = false;\n\nfunction scheduleBatch() {\n if (isBatchScheduled) {\n return;\n }\n isBatchScheduled = true;\n queueMicrotask(() => {\n isBatchScheduled = false;\n flushBatch();\n });\n}\n\nasync function flushBatch() {\n const batch = pendingBatch;\n pendingBatch = [];\n\n if (batch.length === 0) {\n return;\n }\n\n try {\n if (shouldUseHttpTransport()) {\n await sendBatchHttp(batch);\n } else {\n await sendBatchWebSocket(batch);\n }\n } catch (err) {\n // Transport error, fail all\n for (const item of batch) {\n item.reject(err);\n }\n }\n}\n\nasync function sendBatchHttp(batch: PendingRequest[]) {\n const requests = batch.map((b) => b.req);\n const encoded = msgpackEncode(requests);\n\n // Fetch a fresh token for HTTP RPC authentication\n const token = await fetchFreshToken();\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/msgpack\",\n Accept: \"application/msgpack\",\n };\n if (token) {\n headers[\"X-Helium-Token\"] = token;\n }\n\n const response = await fetch(\"/__helium__/rpc\", {\n method: \"POST\",\n headers,\n body: encoded as unknown as BodyInit,\n });\n\n handleBlockedResponse(response.status, \"rpc-http\");\n if (!response.ok) {\n throw new Error(`HTTP RPC failed: ${response.status}`);\n }\n\n const responseBuffer = await response.arrayBuffer();\n const msg = msgpackDecode(new Uint8Array(responseBuffer)) as RpcResponse | RpcResponse[];\n\n const responses = Array.isArray(msg) ? msg : [msg];\n const responseMap = new Map(responses.map((r) => [r.id, r]));\n\n for (const item of batch) {\n const res = responseMap.get(item.req.id);\n if (res) {\n if (res.ok) {\n item.resolve({ data: res.result, stats: res.stats });\n } else {\n item.reject(new RpcError(res.error, res.stats));\n }\n } else {\n item.reject(new RpcError(\"No response for request\"));\n }\n }\n}\n\nasync function sendBatchWebSocket(batch: PendingRequest[]) {\n const ws = await ensureSocketReady();\n const requests = batch.map((b) => b.req);\n\n // Register pending promises with timeout safeguards\n batch.forEach((item) => {\n trackPending(item.req.id, (v: unknown) => item.resolve(v as RpcResult<any>), item.reject);\n });\n\n try {\n // Always use msgpack encoding\n const encoded = msgpackEncode(requests);\n ws.send(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 response before timing out a request. */\nconst REQUEST_TIMEOUT_MS = 30_000;\n\n/** Number of automatic retries on retriable connection errors. */\nconst MAX_RETRIES = 3;\n\n/** Base delay (ms) for exponential backoff between retries (doubles each attempt). */\nconst RETRY_BASE_DELAY_MS = 500;\n\n/** Maximum delay (ms) cap for backoff to avoid excessively long waits. */\nconst RETRY_MAX_DELAY_MS = 5_000;\n\n/** Timestamp when the page was last hidden (for visibility-change detection). */\nlet lastHiddenTimestamp: number | null = null;\n\n// ── Pending-request helpers ──────────────────────────────────────────────────\n\n/**\n * Register a pending request with an automatic timeout safeguard.\n * If no response arrives within REQUEST_TIMEOUT_MS the promise is rejected\n * so the caller's retry logic can kick in.\n */\nfunction trackPending(id: string | number, resolve: (v: unknown) => void, reject: (e: unknown) => void): void {\n pending.set(id, { resolve, reject });\n const timer = setTimeout(() => {\n const entry = pending.get(id);\n if (entry) {\n pending.delete(id);\n pendingTimeouts.delete(id);\n entry.reject(new RpcError(\"Request timed out\"));\n }\n }, REQUEST_TIMEOUT_MS);\n pendingTimeouts.set(id, timer);\n}\n\n/**\n * Remove a pending request and clear its timeout.\n * Returns the entry so the caller can resolve/reject it.\n */\nfunction removePending(id: string | number): { resolve: (v: unknown) => void; reject: (e: unknown) => void } | undefined {\n const entry = pending.get(id);\n if (!entry) {\n return undefined;\n }\n pending.delete(id);\n const timer = pendingTimeouts.get(id);\n if (timer) {\n clearTimeout(timer);\n pendingTimeouts.delete(id);\n }\n return entry;\n}\n\n/** Reject every in-flight request (e.g. when the socket closes unexpectedly). */\nfunction rejectAllPending(reason: Error): void {\n for (const timer of pendingTimeouts.values()) {\n clearTimeout(timer);\n }\n pendingTimeouts.clear();\n const entries = [...pending.entries()];\n pending.clear();\n for (const [, entry] of entries) {\n entry.reject(reason);\n }\n}\n\n// ── Reconnection helpers ─────────────────────────────────────────────────────\n\n/**\n * Force-close the current WebSocket so the next call creates a fresh\n * connection (which fetches a brand-new token).\n */\nfunction forceReconnect(): void {\n const oldSocket = socket;\n socket = null;\n connectionPromise = null;\n\n if (oldSocket) {\n // Detach handlers to avoid double-rejecting pending from the close event\n oldSocket.onclose = null;\n oldSocket.onerror = null;\n oldSocket.onmessage = null;\n oldSocket.close();\n }\n\n // Reject all in-flight requests – callers with retry logic will resend\n rejectAllPending(new Error(\"Connection reset\"));\n}\n\n/** Determine whether an error warrants an automatic retry. */\nfunction isRetriableError(err: unknown): boolean {\n // Network / connection errors are always retriable\n if (err instanceof Error && !(err instanceof RpcError)) {\n return true;\n }\n // Timed-out requests are retriable (socket may have died silently)\n if (err instanceof RpcError && err.message === \"Request timed out\") {\n return true;\n }\n return false;\n}\n\n// Clean up WebSocket connection on HMR (Hot Module Replacement)\nif (import.meta.hot) {\n import.meta.hot.dispose(() => {\n if (socket) {\n socket.onclose = null;\n socket.close();\n socket = null;\n connectionPromise = null;\n }\n rejectAllPending(new Error(\"Module reloaded\"));\n });\n}\n\nlet msgId = 0;\nfunction nextId() {\n return msgId++;\n}\n\nasync function fetchFreshToken(): Promise<string | undefined> {\n try {\n const response = await fetch(\"/__helium__/refresh-token\", {\n method: \"POST\",\n headers: {\n \"X-Requested-With\": \"HeliumRPC\",\n },\n });\n handleBlockedResponse(response.status, \"refresh-token\");\n if (!response.ok) {\n console.warn(\"Failed to fetch fresh token:\", response.status);\n return undefined;\n }\n const data = await response.json();\n return data.token;\n } catch (error) {\n console.warn(\"Error fetching fresh token:\", error);\n return undefined;\n }\n}\n\nasync function createSocket(): Promise<WebSocket> {\n // Fetch a fresh token before creating the WebSocket connection\n const token = await fetchFreshToken();\n\n // Use the same protocol, hostname and port as the current page\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = window.location.host; // includes hostname and port\n const url = `${protocol}//${host}/rpc`;\n // Security: pass token via Sec-WebSocket-Protocol header instead of query string\n const ws = token ? new WebSocket(url, [token]) : new WebSocket(url);\n ws.binaryType = \"arraybuffer\";\n\n ws.onmessage = async (event) => {\n let data = new Uint8Array(event.data as ArrayBuffer);\n\n // Check for Gzip header (0x1f 0x8b) to detect compressed messages\n if (data.length > 2 && data[0] === 0x1f && data[1] === 0x8b) {\n try {\n // Use DecompressionStream if available (Chrome 80+, Firefox 113+, Safari 16.4+)\n if (typeof DecompressionStream !== \"undefined\") {\n const ds = new DecompressionStream(\"gzip\");\n const stream = new Response(data).body;\n if (stream) {\n const decompressed = stream.pipeThrough(ds);\n const reader = decompressed.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n const MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024; // 10 MB\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n break;\n }\n totalSize += value.length;\n if (totalSize > MAX_DECOMPRESSED_SIZE) {\n reader.cancel();\n console.error(\"Decompressed message exceeds size limit\");\n return;\n }\n chunks.push(value);\n }\n const combined = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n data = combined;\n }\n }\n } catch (err) {\n console.error(\"Failed to decompress WebSocket message:\", err);\n return;\n }\n }\n\n // Always expect binary MessagePack\n const msg = msgpackDecode(data) as RpcResponse | RpcResponse[];\n\n const handleResponse = (res: RpcResponse) => {\n const entry = removePending(res.id);\n if (!entry) {\n return;\n }\n if (res.ok) {\n entry.resolve({ data: res.result, stats: res.stats });\n } else {\n entry.reject(new RpcError(res.error, res.stats));\n }\n };\n\n if (Array.isArray(msg)) {\n msg.forEach(handleResponse);\n } else {\n handleResponse(msg);\n }\n };\n\n ws.onerror = () => {\n // WebSocket errors are always followed by a close event.\n // The close handler takes care of rejecting pending promises.\n };\n\n ws.onclose = (event) => {\n handleBlockedSocketClose(event.code);\n if (socket === ws) {\n socket = null;\n connectionPromise = null;\n // Reject every in-flight request so callers can retry\n rejectAllPending(new Error(\"WebSocket connection closed\"));\n }\n };\n\n return ws;\n}\n\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 // If we have a socket that's connecting, wait for it\n if (socket && socket.readyState === WebSocket.CONNECTING) {\n connectionPromise = new Promise((resolve, reject) => {\n const cleanup = () => {\n socket!.removeEventListener(\"open\", handleOpen);\n socket!.removeEventListener(\"error\", handleError);\n socket!.removeEventListener(\"close\", handleClose);\n };\n const handleOpen = () => {\n cleanup();\n connectionPromise = null;\n resolve(socket!);\n };\n const handleError = () => {\n cleanup();\n socket = null;\n connectionPromise = null;\n reject(new Error(\"WebSocket connection failed\"));\n };\n const handleClose = () => {\n cleanup();\n socket = null;\n connectionPromise = null;\n reject(new Error(\"WebSocket closed before opening\"));\n };\n\n socket!.addEventListener(\"open\", handleOpen);\n socket!.addEventListener(\"error\", handleError);\n socket!.addEventListener(\"close\", handleClose);\n });\n return connectionPromise;\n }\n\n // Create a new socket and connection promise\n connectionPromise = (async () => {\n socket = await createSocket();\n return new Promise<WebSocket>((resolve, reject) => {\n const cleanup = () => {\n socket!.removeEventListener(\"open\", handleOpen);\n socket!.removeEventListener(\"error\", handleError);\n socket!.removeEventListener(\"close\", handleClose);\n };\n const handleOpen = () => {\n cleanup();\n connectionPromise = null;\n resolve(socket!);\n };\n const handleError = () => {\n cleanup();\n socket = null;\n connectionPromise = null;\n reject(new Error(\"WebSocket connection failed\"));\n };\n const handleClose = () => {\n cleanup();\n socket = null;\n connectionPromise = null;\n reject(new Error(\"WebSocket closed before opening\"));\n };\n\n socket!.addEventListener(\"open\", handleOpen);\n socket!.addEventListener(\"error\", handleError);\n socket!.addEventListener(\"close\", handleClose);\n });\n })();\n\n return connectionPromise;\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(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(encoded);\n } catch (err) {\n removePending(id);\n reject(err);\n }\n });\n}\n\n/**\n * Make an RPC call using the appropriate transport.\n * Automatically selects HTTP or WebSocket based on network conditions and configuration.\n *\n * Includes automatic retry logic: if a call fails due to a connection error\n * (e.g. stale WebSocket after mobile browser was backgrounded), the client\n * forces a fresh connection (with a new token) and retries once.\n */\nexport async function rpcCall<TResult = unknown, TArgs = unknown>(methodId: string, args?: TArgs): Promise<RpcResult<TResult>> {\n return rpcCallWithRetry<TResult, TArgs>(methodId, args);\n}\n\nasync function rpcCallWithRetry<TResult, TArgs>(methodId: string, args: TArgs | undefined, attempt = 0): Promise<RpcResult<TResult>> {\n try {\n if (shouldUseHttpTransport()) {\n const id = nextId();\n const req: RpcRequest = { id, method: methodId, args };\n\n return await new Promise<RpcResult<TResult>>((resolve, reject) => {\n pendingBatch.push({ req, resolve: resolve as (value: RpcResult<TResult>) => void, reject });\n scheduleBatch();\n });\n }\n\n return await rpcCallWebSocket<TResult, TArgs>(methodId, args);\n } catch (err) {\n if (attempt < MAX_RETRIES && isRetriableError(err)) {\n // Force a fresh connection (fetches a new token)\n forceReconnect();\n // Exponential backoff with jitter: 500ms, 1000ms, 2000ms (capped at 5s)\n const baseDelay = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS);\n const jitter = Math.random() * baseDelay * 0.3;\n await new Promise<void>((r) => setTimeout(r, baseDelay + jitter));\n return rpcCallWithRetry<TResult, TArgs>(methodId, args, attempt + 1);\n }\n throw err;\n }\n}\n\n/**\n * Pre-establishes the WebSocket connection.\n * Call this early (e.g., on page load) to avoid connection latency on first RPC call.\n * This is especially beneficial on high-latency networks like mobile LTE.\n * Note: Only effective when using WebSocket transport (not HTTP transport).\n */\nexport function preconnect(): void {\n if (typeof window === \"undefined\") {\n return;\n }\n // Only preconnect if we're using WebSocket transport\n if (shouldUseHttpTransport()) {\n return;\n }\n // Fire and forget - establishes connection in background\n ensureSocketReady().catch(() => {\n // Silently ignore preconnect failures, will retry on actual call\n });\n}\n\n// Auto-preconnect when the module loads (browser only, WebSocket transport only)\nif (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n // Use requestIdleCallback if available, otherwise setTimeout\n const schedulePreconnect = window.requestIdleCallback || ((cb: () => void) => setTimeout(cb, 1));\n schedulePreconnect(() => preconnect());\n}\n\n// ============================================================================\n// Visibility-change reconnection (critical for mobile browsers)\n// ============================================================================\n//\n// Mobile browsers freeze or kill WebSocket connections when the tab is\n// backgrounded. When the user returns the socket may *appear* open but\n// is actually stale. We detect this via the Page Visibility API and\n// proactively tear down the old connection so the next RPC call creates\n// a fresh one (with a brand-new auth token).\n// ============================================================================\n\nif (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", () => {\n if (document.hidden) {\n lastHiddenTimestamp = Date.now();\n } else {\n // Page became visible again\n if (lastHiddenTimestamp !== null) {\n const hiddenDuration = Date.now() - lastHiddenTimestamp;\n if (hiddenDuration > STALE_THRESHOLD_MS && socket) {\n forceReconnect();\n }\n lastHiddenTimestamp = null;\n }\n }\n });\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=deepEqual.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepEqual.d.ts","sourceRoot":"","sources":["../../src/utils/deepEqual.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepEqual.js","sourceRoot":"","sources":["../../src/utils/deepEqual.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|