@onyxsecurity/mcp-gateway 1.0.66 → 1.0.67

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.
Files changed (28) hide show
  1. package/dist/bin/mcp-gateway.js +2 -2
  2. package/dist/bin/mcp-gateway.js.map +1 -1
  3. package/dist/{cli-DQlVGyV_.js → cli-C9BerLdo.js} +2 -2
  4. package/dist/{cli-DQlVGyV_.js.map → cli-C9BerLdo.js.map} +1 -1
  5. package/dist/{env-CPU34WM0.js → env-DJH7bqWP.js} +1 -1
  6. package/dist/{env-BU-k04bk.js → env-_7CCeXgw.js} +2 -2
  7. package/dist/{env-BU-k04bk.js.map → env-_7CCeXgw.js.map} +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/{logger-BwqGcO50.js → logger-DN0aJNvI.js} +2 -2
  10. package/dist/{logger-BwqGcO50.js.map → logger-DN0aJNvI.js.map} +1 -1
  11. package/dist/{main-B46IHeJX.js → main-DrG-Ry9A.js} +2 -2
  12. package/dist/main-DrG-Ry9A.js.map +1 -0
  13. package/dist/oauthProvidersClient-77aNc59I.js +1 -0
  14. package/dist/{oauthProvidersClient-CoyIrpuA.js → oauthProvidersClient-CCyOKMJH.js} +2 -2
  15. package/dist/{oauthProvidersClient-CoyIrpuA.js.map → oauthProvidersClient-CCyOKMJH.js.map} +1 -1
  16. package/dist/{providers-xwC_AxDC.js → providers-qMBff1LW.js} +2 -2
  17. package/dist/{providers-xwC_AxDC.js.map → providers-qMBff1LW.js.map} +1 -1
  18. package/dist/secretstore-D1vTCZFj.js +2 -0
  19. package/dist/secretstore-D1vTCZFj.js.map +1 -0
  20. package/dist/{stdio-DLPm2NHB.js → stdio-COjRVz1N.js} +2 -2
  21. package/dist/{stdio-DLPm2NHB.js.map → stdio-COjRVz1N.js.map} +1 -1
  22. package/dist/{transportDetection-XcdORTci.js → transportDetection-B23P-H1Z.js} +2 -2
  23. package/dist/{transportDetection-XcdORTci.js.map → transportDetection-B23P-H1Z.js.map} +1 -1
  24. package/package.json +2 -1
  25. package/dist/main-B46IHeJX.js.map +0 -1
  26. package/dist/oauthProvidersClient-DqXf4kK7.js +0 -1
  27. package/dist/secretstore-Deoqfk8j.js +0 -2
  28. package/dist/secretstore-Deoqfk8j.js.map +0 -1
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{hideBin as e,setupProxyDispatcher as t,yargs_default as n}from"../helpers-yvgumKoO.js";await t();const r=n(e(process.argv)).parserConfiguration({"populate--":!0,"unknown-options-as-args":!0}).option(`access-control-url`,{type:`string`}).option(`oauth-providers-url`,{type:`string`}).option(`scanner-api-key`,{type:`string`}).option(`scanner-fail-open`,{type:`boolean`}).option(`scanner-timeout-ms`,{type:`number`}).option(`scanner-url`,{type:`string`}).help(!1).version(!1).parseSync();if(String(r._[0]??``)===`probe`){r.oauthProvidersUrl&&(process.env.MCP_GATEWAY_OAUTH_PROVIDERS_URL=r.oauthProvidersUrl),r.scannerApiKey&&(process.env.MCP_GATEWAY_SCANNER_API_KEY=r.scannerApiKey);let{config:e}=await import(`../env-CPU34WM0.js`),{initializeOAuthProviders:t}=await import(`../oauthProvidersClient-DqXf4kK7.js`),{runProbeCli:n}=await import(`../cli-DQlVGyV_.js`);await t(e.oauthProviders),process.exitCode=await n()}else{r.accessControlUrl&&(process.env.MCP_GATEWAY_ACCESS_CONTROL_URL=r.accessControlUrl),r.oauthProvidersUrl&&(process.env.MCP_GATEWAY_OAUTH_PROVIDERS_URL=r.oauthProvidersUrl),r.scannerApiKey&&(process.env.MCP_GATEWAY_SCANNER_API_KEY=r.scannerApiKey),r.scannerFailOpen!==void 0&&(process.env.MCP_GATEWAY_SCANNER_FAIL_OPEN=String(r.scannerFailOpen)),r.scannerTimeoutMs!==void 0&&(process.env.MCP_GATEWAY_SCANNER_TIMEOUT_MS=String(r.scannerTimeoutMs)),r.scannerUrl&&(process.env.MCP_GATEWAY_SCANNER_URL=r.scannerUrl);let e=`missing`;if(process.env.MCP_GATEWAY_SCANNER_API_KEY)e=`env`;else if(process.env.MCP_GATEWAY_DISABLE_KEYCHAIN===`1`)e=`missing`;else try{let{ACCOUNT_DEFAULT:t,getSecret:n}=await import(`../secretstore-Deoqfk8j.js`),r=await n(t);r&&(process.env.MCP_GATEWAY_SCANNER_API_KEY=r,process.env.MCP_GATEWAY_MIRROR_API_KEY||(process.env.MCP_GATEWAY_MIRROR_API_KEY=r),e=`keychain`)}catch{e=`error`}process.stderr.write(JSON.stringify({caller:`gateway_startup`,event:`keychain_outcome`,keychain_disabled_env_set:process.env.MCP_GATEWAY_DISABLE_KEYCHAIN===`1`,op:`get`,outcome:e,platform:process.platform,reason:e})+`
3
- `);let{main:t}=await import(`../main-B46IHeJX.js`);await t()}export{};
2
+ import{hideBin as e,setupProxyDispatcher as t,yargs_default as n}from"../helpers-yvgumKoO.js";await t();const r=n(e(process.argv)).parserConfiguration({"populate--":!0,"unknown-options-as-args":!0}).option(`access-control-url`,{type:`string`}).option(`oauth-providers-url`,{type:`string`}).option(`scanner-api-key`,{type:`string`}).option(`scanner-fail-open`,{type:`boolean`}).option(`scanner-timeout-ms`,{type:`number`}).option(`scanner-url`,{type:`string`}).help(!1).version(!1).parseSync();if(String(r._[0]??``)===`probe`){r.oauthProvidersUrl&&(process.env.MCP_GATEWAY_OAUTH_PROVIDERS_URL=r.oauthProvidersUrl),r.scannerApiKey&&(process.env.MCP_GATEWAY_SCANNER_API_KEY=r.scannerApiKey);let{config:e}=await import(`../env-DJH7bqWP.js`),{initializeOAuthProviders:t}=await import(`../oauthProvidersClient-77aNc59I.js`),{runProbeCli:n}=await import(`../cli-C9BerLdo.js`);await t(e.oauthProviders),process.exitCode=await n()}else{r.accessControlUrl&&(process.env.MCP_GATEWAY_ACCESS_CONTROL_URL=r.accessControlUrl),r.oauthProvidersUrl&&(process.env.MCP_GATEWAY_OAUTH_PROVIDERS_URL=r.oauthProvidersUrl),r.scannerApiKey&&(process.env.MCP_GATEWAY_SCANNER_API_KEY=r.scannerApiKey),r.scannerFailOpen!==void 0&&(process.env.MCP_GATEWAY_SCANNER_FAIL_OPEN=String(r.scannerFailOpen)),r.scannerTimeoutMs!==void 0&&(process.env.MCP_GATEWAY_SCANNER_TIMEOUT_MS=String(r.scannerTimeoutMs)),r.scannerUrl&&(process.env.MCP_GATEWAY_SCANNER_URL=r.scannerUrl);let e=`missing`;if(process.env.MCP_GATEWAY_SCANNER_API_KEY)e=`env`;else if(process.env.MCP_GATEWAY_DISABLE_KEYCHAIN===`1`)e=`missing`;else try{let{ACCOUNT_DEFAULT:t,getSecret:n}=await import(`../secretstore-D1vTCZFj.js`),r=await n(t);r&&(process.env.MCP_GATEWAY_SCANNER_API_KEY=r,process.env.MCP_GATEWAY_MIRROR_API_KEY||(process.env.MCP_GATEWAY_MIRROR_API_KEY=r),e=`keychain`)}catch{e=`error`}process.stderr.write(JSON.stringify({caller:`gateway_startup`,event:`keychain_outcome`,keychain_disabled_env_set:process.env.MCP_GATEWAY_DISABLE_KEYCHAIN===`1`,op:`get`,outcome:e,platform:process.platform,reason:e})+`
3
+ `);let{main:t}=await import(`../main-DrG-Ry9A.js`);await t()}export{};
4
4
  //# sourceMappingURL=mcp-gateway.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-gateway.js","names":["yargs","apiKeySource: \"env\" | \"error\" | \"keychain\" | \"missing\""],"sources":["../../src/bin/mcp-gateway.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Gateway Entry Point\n *\n * This file implements a pre-parse + dynamic import pattern to allow CLI arguments\n * to override environment variables BEFORE the config module is loaded.\n *\n * The problem: ES module imports are hoisted, so `import { config } from \"../config/env.js\"`\n * runs before any CLI parsing code. The config reads from process.env at import time.\n *\n * The solution:\n * 1. Pre-parse only the config-related CLI args with a minimal yargs setup\n * 2. Set process.env values from CLI args (CLI takes priority)\n * 3. Dynamically import the main module (which will read the updated process.env)\n *\n * This approach allows the scanner to use direct CLI args like:\n * npx -y @onyxsecurity/mcp-gateway --scanner-url URL --scanner-api-key KEY -- npx -y @original/server\n *\n * Instead of shell wrappers that cause console popups on Windows:\n * powershell -Command \"$env:MCP_GATEWAY_SCANNER_URL='URL'; npx -y @onyxsecurity/mcp-gateway -- ...\"\n */\n\n// PHASE 0: Configure proxy-aware global fetch dispatcher BEFORE any outbound requests.\n// See ../lib/proxySetup.ts for the rationale and behavior.\nimport { setupProxyDispatcher } from \"../lib/proxySetup.js\";\n\nawait setupProxyDispatcher();\n\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\n// PHASE 1: Pre-parse config-related CLI args BEFORE any other imports\n// We use a minimal yargs setup that only extracts the config options we need\nconst preArgv = yargs(hideBin(process.argv))\n .parserConfiguration({\n // Populate the -- separator array\n \"populate--\": true,\n // Don't fail on unknown options - main.ts will handle all parsing\n \"unknown-options-as-args\": true,\n })\n .option(\"access-control-url\", { type: \"string\" })\n .option(\"oauth-providers-url\", { type: \"string\" })\n .option(\"scanner-api-key\", { type: \"string\" })\n .option(\"scanner-fail-open\", { type: \"boolean\" })\n .option(\"scanner-timeout-ms\", { type: \"number\" })\n .option(\"scanner-url\", { type: \"string\" })\n .help(false) // Disable help in pre-parse (main.ts handles it)\n .version(false) // Disable version in pre-parse\n .parseSync();\n\n// PHASE 1.5: Short-circuit for standalone subcommands that don't need the proxy\n// env setup. The `probe` subcommand runs a DCR/auth probe over a batch of MCP\n// server URLs and exits — it doesn't start the proxy or need SCANNER_URL etc.\nconst firstCommand = String(preArgv._[0] ?? \"\");\nif (firstCommand === \"probe\") {\n // Mirror the non-probe branch's CLI→env mapping for the two flags the probe\n // cares about (pre-registered OAuth providers list). The scanner passes\n // these as CLI flags from copilot_config_manager.go's envToArg via\n // scanner/internal/config/probe.go::buildProbeArgs, matching the runtime\n // gateway invocation shape.\n if (preArgv.oauthProvidersUrl) {\n process.env.MCP_GATEWAY_OAUTH_PROVIDERS_URL = preArgv.oauthProvidersUrl;\n }\n if (preArgv.scannerApiKey) {\n process.env.MCP_GATEWAY_SCANNER_API_KEY = preArgv.scannerApiKey;\n }\n\n // Dynamic imports — same env-hoist reason as main.ts (config/env.ts reads\n // MCP_GATEWAY_* env vars at module-load time, so process.env must be set\n // first). Without this fetch, findProviderForUrl in probe/index.ts always\n // returns undefined for URLs the BE has pre-registered creds for (e.g.\n // GitHub), and the probe falsely classifies them oauth_dcr_not_supported.\n const { config } = await import(\"../config/env.js\");\n const { initializeOAuthProviders } = await import(\"../auth/oauthProvidersClient.js\");\n const { runProbeCli } = await import(\"../probe/cli.js\");\n\n // Fail-safe identical to main.ts:170 — on fetch error, the in-memory\n // provider store stays empty and the probe falls through to DCR for every\n // URL (same behavior as before this fix).\n await initializeOAuthProviders(config.oauthProviders);\n\n // Set process.exitCode and let the process exit naturally instead of\n // calling process.exit(). The scanner reads our stdout JSON via a\n // pipe, and process.exit() terminates Node before pending async\n // stdout writes flush — that truncates the payload mid-object and\n // the scanner reports it as probe_parse_error. Using exitCode lets\n // the event loop drain remaining writes before exiting.\n process.exitCode = await runProbeCli();\n} else {\n // PHASE 2: Set process.env from CLI args (CLI takes priority over existing env vars)\n // Only set if the CLI arg was explicitly provided\n if (preArgv.accessControlUrl) {\n process.env.MCP_GATEWAY_ACCESS_CONTROL_URL = preArgv.accessControlUrl;\n }\n if (preArgv.oauthProvidersUrl) {\n process.env.MCP_GATEWAY_OAUTH_PROVIDERS_URL = preArgv.oauthProvidersUrl;\n }\n if (preArgv.scannerApiKey) {\n process.env.MCP_GATEWAY_SCANNER_API_KEY = preArgv.scannerApiKey;\n }\n if (preArgv.scannerFailOpen !== undefined) {\n process.env.MCP_GATEWAY_SCANNER_FAIL_OPEN = String(preArgv.scannerFailOpen);\n }\n if (preArgv.scannerTimeoutMs !== undefined) {\n process.env.MCP_GATEWAY_SCANNER_TIMEOUT_MS = String(preArgv.scannerTimeoutMs);\n }\n if (preArgv.scannerUrl) {\n process.env.MCP_GATEWAY_SCANNER_URL = preArgv.scannerUrl;\n }\n\n // PHASE 2b: Fall back to the OS keychain for MCP_GATEWAY_SCANNER_API_KEY\n // when neither the CLI flag nor the existing env var supplied a value.\n // The scanner writes the key into (service=onyx-mcp-gateway, account=default)\n // at install time on keychain-capable hosts. MIRROR_API_KEY uses the same\n // value when not explicitly set, matching today's single-tenant pattern.\n //\n // Best-effort: getSecret returns null on backend miss / missing libsecret /\n // user-denied access, and we simply continue. config/env.ts already gates\n // every dependent feature on a non-empty API key, so a missing key\n // gracefully puts the gateway into degraded mode (the legacy behavior).\n //\n // MCP_GATEWAY_DISABLE_KEYCHAIN=1 skips the probe entirely — needed in CI\n // and in tests that spawn the gateway as a subprocess, where the macOS\n // Keychain Services first-read prompt would hang waiting for user\n // interaction the test runner cannot supply.\n // The api-key source decision is emitted once per gateway startup as a\n // structured JSON line on stderr so it's aggregable across the fleet\n // (the gateway's file-logger isn't initialized yet at this point —\n // it lives in main.ts which we dynamic-import next). Source values:\n // \"env\" — already in process.env from the scanner-written MCP\n // config (legacy pre-keychain leak path, or\n // MCP_GATEWAY_DISABLE_KEYCHAIN=1 opt-out).\n // \"keychain\" — read from the OS keychain at startup (the goal).\n // \"missing\" — neither env nor keychain produced a key; gateway runs\n // in degraded mode (config/env.ts gates dependent\n // features on the key being non-empty).\n // \"error\" — keychain backend threw / native binding missing.\n let apiKeySource: \"env\" | \"error\" | \"keychain\" | \"missing\" = \"missing\";\n\n if (process.env.MCP_GATEWAY_SCANNER_API_KEY) {\n apiKeySource = \"env\";\n } else if (process.env.MCP_GATEWAY_DISABLE_KEYCHAIN === \"1\") {\n apiKeySource = \"missing\"; // explicit opt-out, treated same as missing\n } else {\n // Defense in depth: secretstore.ts already lazy-loads @napi-rs/keyring via\n // createRequire and swallows backend errors inside its functions, so the\n // module itself shouldn't throw on load. We still wrap the dynamic import\n // and the call so that any future regression (e.g. someone re-introducing\n // a static `import { Entry }`) cannot crash startup on hosts where the\n // native binding is missing.\n try {\n const { ACCOUNT_DEFAULT, getSecret } = await import(\"../lib/secretstore.js\");\n const fromKeychain = await getSecret(ACCOUNT_DEFAULT);\n if (fromKeychain) {\n process.env.MCP_GATEWAY_SCANNER_API_KEY = fromKeychain;\n if (!process.env.MCP_GATEWAY_MIRROR_API_KEY) {\n process.env.MCP_GATEWAY_MIRROR_API_KEY = fromKeychain;\n }\n apiKeySource = \"keychain\";\n }\n } catch {\n // Keychain backend unavailable on this host (e.g. musl/alpine without a\n // prebuilt @napi-rs/keyring .node, sealed container without libsecret).\n // Fall through to the env-only path — the gateway runs in legacy mode.\n apiKeySource = \"error\";\n }\n }\n\n // Structured one-shot startup outcome on stderr. The gateway's main\n // file-logger comes online inside main.ts which we dynamic-import next;\n // until then stderr is the only sink — the cluster log forwarder picks\n // it up alongside the file-logger output. Schema matches the\n // scanner-side `event: \"keychain_outcome\"` lines so the same monitor\n // query aggregates both writer and reader paths.\n // `reason` mirrors `outcome` here. On the Node side we don't have the\n // Go reason classifier, but the reader-side outcomes (env / keychain /\n // missing / error) are themselves the canonical reasons — so dashboards\n // can group by `reason` uniformly across writer and reader logs.\n process.stderr.write(JSON.stringify({\n caller: \"gateway_startup\",\n event: \"keychain_outcome\",\n keychain_disabled_env_set: process.env.MCP_GATEWAY_DISABLE_KEYCHAIN === \"1\",\n op: \"get\",\n outcome: apiKeySource,\n platform: process.platform,\n reason: apiKeySource,\n }) + \"\\n\");\n\n // PHASE 3: NOW dynamically import the main module\n // At this point process.env has been updated with CLI args, so config will read the correct values\n const { main } = await import(\"./main.js\");\n\n await main();\n}\n"],"mappings":";8FA2BA,MAAM,GAAsB,CAO5B,MAAM,EAAUA,EAAM,EAAQ,QAAQ,KAAK,CAAC,CACzC,oBAAoB,CAEnB,aAAc,GAEd,0BAA2B,GAC5B,CAAC,CACD,OAAO,qBAAsB,CAAE,KAAM,SAAU,CAAC,CAChD,OAAO,sBAAuB,CAAE,KAAM,SAAU,CAAC,CACjD,OAAO,kBAAmB,CAAE,KAAM,SAAU,CAAC,CAC7C,OAAO,oBAAqB,CAAE,KAAM,UAAW,CAAC,CAChD,OAAO,qBAAsB,CAAE,KAAM,SAAU,CAAC,CAChD,OAAO,cAAe,CAAE,KAAM,SAAU,CAAC,CACzC,KAAK,GAAM,CACX,QAAQ,GAAM,CACd,WAAW,CAMd,GADqB,OAAO,EAAQ,EAAE,IAAM,GAAG,GAC1B,QAAS,CAMxB,EAAQ,oBACV,QAAQ,IAAI,gCAAkC,EAAQ,mBAEpD,EAAQ,gBACV,QAAQ,IAAI,4BAA8B,EAAQ,eAQpD,GAAM,CAAE,UAAW,MAAM,OAAO,sBAC1B,CAAE,4BAA6B,MAAM,OAAO,uCAC5C,CAAE,eAAgB,MAAM,OAAO,sBAKrC,MAAM,EAAyB,EAAO,eAAe,CAQrD,QAAQ,SAAW,MAAM,GAAa,KACjC,CAGD,EAAQ,mBACV,QAAQ,IAAI,+BAAiC,EAAQ,kBAEnD,EAAQ,oBACV,QAAQ,IAAI,gCAAkC,EAAQ,mBAEpD,EAAQ,gBACV,QAAQ,IAAI,4BAA8B,EAAQ,eAEhD,EAAQ,kBAAoB,IAAA,KAC9B,QAAQ,IAAI,8BAAgC,OAAO,EAAQ,gBAAgB,EAEzE,EAAQ,mBAAqB,IAAA,KAC/B,QAAQ,IAAI,+BAAiC,OAAO,EAAQ,iBAAiB,EAE3E,EAAQ,aACV,QAAQ,IAAI,wBAA0B,EAAQ,YA8BhD,IAAIC,EAAyD,UAE7D,GAAI,QAAQ,IAAI,4BACd,EAAe,cACN,QAAQ,IAAI,+BAAiC,IACtD,EAAe,eAQf,GAAI,CACF,GAAM,CAAE,kBAAiB,aAAc,MAAM,OAAO,8BAC9C,EAAe,MAAM,EAAU,EAAgB,CACjD,IACF,QAAQ,IAAI,4BAA8B,EACrC,QAAQ,IAAI,6BACf,QAAQ,IAAI,2BAA6B,GAE3C,EAAe,iBAEX,CAIN,EAAe,QAcnB,QAAQ,OAAO,MAAM,KAAK,UAAU,CAClC,OAAQ,kBACR,MAAO,mBACP,0BAA2B,QAAQ,IAAI,+BAAiC,IACxE,GAAI,MACJ,QAAS,EACT,SAAU,QAAQ,SAClB,OAAQ,EACT,CAAC,CAAG;EAAK,CAIV,GAAM,CAAE,QAAS,MAAM,OAAO,uBAE9B,MAAM,GAAM"}
1
+ {"version":3,"file":"mcp-gateway.js","names":["yargs","apiKeySource: \"env\" | \"error\" | \"keychain\" | \"missing\""],"sources":["../../src/bin/mcp-gateway.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Gateway Entry Point\n *\n * This file implements a pre-parse + dynamic import pattern to allow CLI arguments\n * to override environment variables BEFORE the config module is loaded.\n *\n * The problem: ES module imports are hoisted, so `import { config } from \"../config/env.js\"`\n * runs before any CLI parsing code. The config reads from process.env at import time.\n *\n * The solution:\n * 1. Pre-parse only the config-related CLI args with a minimal yargs setup\n * 2. Set process.env values from CLI args (CLI takes priority)\n * 3. Dynamically import the main module (which will read the updated process.env)\n *\n * This approach allows the scanner to use direct CLI args like:\n * npx -y @onyxsecurity/mcp-gateway --scanner-url URL --scanner-api-key KEY -- npx -y @original/server\n *\n * Instead of shell wrappers that cause console popups on Windows:\n * powershell -Command \"$env:MCP_GATEWAY_SCANNER_URL='URL'; npx -y @onyxsecurity/mcp-gateway -- ...\"\n */\n\n// PHASE 0: Configure proxy-aware global fetch dispatcher BEFORE any outbound requests.\n// See ../lib/proxySetup.ts for the rationale and behavior.\nimport { setupProxyDispatcher } from \"../lib/proxySetup.js\";\n\nawait setupProxyDispatcher();\n\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\n// PHASE 1: Pre-parse config-related CLI args BEFORE any other imports\n// We use a minimal yargs setup that only extracts the config options we need\nconst preArgv = yargs(hideBin(process.argv))\n .parserConfiguration({\n // Populate the -- separator array\n \"populate--\": true,\n // Don't fail on unknown options - main.ts will handle all parsing\n \"unknown-options-as-args\": true,\n })\n .option(\"access-control-url\", { type: \"string\" })\n .option(\"oauth-providers-url\", { type: \"string\" })\n .option(\"scanner-api-key\", { type: \"string\" })\n .option(\"scanner-fail-open\", { type: \"boolean\" })\n .option(\"scanner-timeout-ms\", { type: \"number\" })\n .option(\"scanner-url\", { type: \"string\" })\n .help(false) // Disable help in pre-parse (main.ts handles it)\n .version(false) // Disable version in pre-parse\n .parseSync();\n\n// PHASE 1.5: Short-circuit for standalone subcommands that don't need the proxy\n// env setup. The `probe` subcommand runs a DCR/auth probe over a batch of MCP\n// server URLs and exits — it doesn't start the proxy or need SCANNER_URL etc.\nconst firstCommand = String(preArgv._[0] ?? \"\");\nif (firstCommand === \"probe\") {\n // Mirror the non-probe branch's CLI→env mapping for the two flags the probe\n // cares about (pre-registered OAuth providers list). The scanner passes\n // these as CLI flags from copilot_config_manager.go's envToArg via\n // scanner/internal/config/probe.go::buildProbeArgs, matching the runtime\n // gateway invocation shape.\n if (preArgv.oauthProvidersUrl) {\n process.env.MCP_GATEWAY_OAUTH_PROVIDERS_URL = preArgv.oauthProvidersUrl;\n }\n if (preArgv.scannerApiKey) {\n process.env.MCP_GATEWAY_SCANNER_API_KEY = preArgv.scannerApiKey;\n }\n\n // Dynamic imports — same env-hoist reason as main.ts (config/env.ts reads\n // MCP_GATEWAY_* env vars at module-load time, so process.env must be set\n // first). Without this fetch, findProviderForUrl in probe/index.ts always\n // returns undefined for URLs the BE has pre-registered creds for (e.g.\n // GitHub), and the probe falsely classifies them oauth_dcr_not_supported.\n const { config } = await import(\"../config/env.js\");\n const { initializeOAuthProviders } = await import(\"../auth/oauthProvidersClient.js\");\n const { runProbeCli } = await import(\"../probe/cli.js\");\n\n // Fail-safe identical to main.ts:170 — on fetch error, the in-memory\n // provider store stays empty and the probe falls through to DCR for every\n // URL (same behavior as before this fix).\n await initializeOAuthProviders(config.oauthProviders);\n\n // Set process.exitCode and let the process exit naturally instead of\n // calling process.exit(). The scanner reads our stdout JSON via a\n // pipe, and process.exit() terminates Node before pending async\n // stdout writes flush — that truncates the payload mid-object and\n // the scanner reports it as probe_parse_error. Using exitCode lets\n // the event loop drain remaining writes before exiting.\n process.exitCode = await runProbeCli();\n} else {\n // PHASE 2: Set process.env from CLI args (CLI takes priority over existing env vars)\n // Only set if the CLI arg was explicitly provided\n if (preArgv.accessControlUrl) {\n process.env.MCP_GATEWAY_ACCESS_CONTROL_URL = preArgv.accessControlUrl;\n }\n if (preArgv.oauthProvidersUrl) {\n process.env.MCP_GATEWAY_OAUTH_PROVIDERS_URL = preArgv.oauthProvidersUrl;\n }\n if (preArgv.scannerApiKey) {\n process.env.MCP_GATEWAY_SCANNER_API_KEY = preArgv.scannerApiKey;\n }\n if (preArgv.scannerFailOpen !== undefined) {\n process.env.MCP_GATEWAY_SCANNER_FAIL_OPEN = String(preArgv.scannerFailOpen);\n }\n if (preArgv.scannerTimeoutMs !== undefined) {\n process.env.MCP_GATEWAY_SCANNER_TIMEOUT_MS = String(preArgv.scannerTimeoutMs);\n }\n if (preArgv.scannerUrl) {\n process.env.MCP_GATEWAY_SCANNER_URL = preArgv.scannerUrl;\n }\n\n // PHASE 2b: Fall back to the OS secret store for MCP_GATEWAY_SCANNER_API_KEY\n // when neither the CLI flag nor the existing env var supplied a value.\n // The scanner writes the key into a machine-scoped, boot-available store at\n // install time — macOS System keychain (-A) or Windows DPAPI LocalMachine\n // blob — under (service=onyx-mcp-gateway, account=default). getSecret()\n // resolves the right source per platform (see lib/secretstore.ts), so it\n // works even when no user is logged in. MIRROR_API_KEY uses the same value\n // when not explicitly set, matching today's single-tenant pattern.\n //\n // Best-effort: getSecret returns null on backend miss / missing libsecret /\n // user-denied access, and we simply continue. config/env.ts already gates\n // every dependent feature on a non-empty API key, so a missing key\n // gracefully puts the gateway into degraded mode (the legacy behavior).\n //\n // MCP_GATEWAY_DISABLE_KEYCHAIN=1 skips the probe entirely — needed in CI\n // and in tests that spawn the gateway as a subprocess, where the macOS\n // Keychain Services first-read prompt would hang waiting for user\n // interaction the test runner cannot supply.\n // The api-key source decision is emitted once per gateway startup as a\n // structured JSON line on stderr so it's aggregable across the fleet\n // (the gateway's file-logger isn't initialized yet at this point —\n // it lives in main.ts which we dynamic-import next). Source values:\n // \"env\" — already in process.env from the scanner-written MCP\n // config (legacy pre-keychain leak path, or\n // MCP_GATEWAY_DISABLE_KEYCHAIN=1 opt-out).\n // \"keychain\" — read from the OS keychain at startup (the goal).\n // \"missing\" — neither env nor keychain produced a key; gateway runs\n // in degraded mode (config/env.ts gates dependent\n // features on the key being non-empty).\n // \"error\" — keychain backend threw / native binding missing.\n let apiKeySource: \"env\" | \"error\" | \"keychain\" | \"missing\" = \"missing\";\n\n if (process.env.MCP_GATEWAY_SCANNER_API_KEY) {\n apiKeySource = \"env\";\n } else if (process.env.MCP_GATEWAY_DISABLE_KEYCHAIN === \"1\") {\n apiKeySource = \"missing\"; // explicit opt-out, treated same as missing\n } else {\n // Defense in depth: secretstore.ts already lazy-loads @napi-rs/keyring via\n // createRequire and swallows backend errors inside its functions, so the\n // module itself shouldn't throw on load. We still wrap the dynamic import\n // and the call so that any future regression (e.g. someone re-introducing\n // a static `import { Entry }`) cannot crash startup on hosts where the\n // native binding is missing.\n try {\n const { ACCOUNT_DEFAULT, getSecret } = await import(\"../lib/secretstore.js\");\n const fromKeychain = await getSecret(ACCOUNT_DEFAULT);\n if (fromKeychain) {\n process.env.MCP_GATEWAY_SCANNER_API_KEY = fromKeychain;\n if (!process.env.MCP_GATEWAY_MIRROR_API_KEY) {\n process.env.MCP_GATEWAY_MIRROR_API_KEY = fromKeychain;\n }\n apiKeySource = \"keychain\";\n }\n } catch {\n // Keychain backend unavailable on this host (e.g. musl/alpine without a\n // prebuilt @napi-rs/keyring .node, sealed container without libsecret).\n // Fall through to the env-only path — the gateway runs in legacy mode.\n apiKeySource = \"error\";\n }\n }\n\n // Structured one-shot startup outcome on stderr. The gateway's main\n // file-logger comes online inside main.ts which we dynamic-import next;\n // until then stderr is the only sink — the cluster log forwarder picks\n // it up alongside the file-logger output. Schema matches the\n // scanner-side `event: \"keychain_outcome\"` lines so the same monitor\n // query aggregates both writer and reader paths.\n // `reason` mirrors `outcome` here. On the Node side we don't have the\n // Go reason classifier, but the reader-side outcomes (env / keychain /\n // missing / error) are themselves the canonical reasons — so dashboards\n // can group by `reason` uniformly across writer and reader logs.\n process.stderr.write(JSON.stringify({\n caller: \"gateway_startup\",\n event: \"keychain_outcome\",\n keychain_disabled_env_set: process.env.MCP_GATEWAY_DISABLE_KEYCHAIN === \"1\",\n op: \"get\",\n outcome: apiKeySource,\n platform: process.platform,\n reason: apiKeySource,\n }) + \"\\n\");\n\n // PHASE 3: NOW dynamically import the main module\n // At this point process.env has been updated with CLI args, so config will read the correct values\n const { main } = await import(\"./main.js\");\n\n await main();\n}\n"],"mappings":";8FA2BA,MAAM,GAAsB,CAO5B,MAAM,EAAUA,EAAM,EAAQ,QAAQ,KAAK,CAAC,CACzC,oBAAoB,CAEnB,aAAc,GAEd,0BAA2B,GAC5B,CAAC,CACD,OAAO,qBAAsB,CAAE,KAAM,SAAU,CAAC,CAChD,OAAO,sBAAuB,CAAE,KAAM,SAAU,CAAC,CACjD,OAAO,kBAAmB,CAAE,KAAM,SAAU,CAAC,CAC7C,OAAO,oBAAqB,CAAE,KAAM,UAAW,CAAC,CAChD,OAAO,qBAAsB,CAAE,KAAM,SAAU,CAAC,CAChD,OAAO,cAAe,CAAE,KAAM,SAAU,CAAC,CACzC,KAAK,GAAM,CACX,QAAQ,GAAM,CACd,WAAW,CAMd,GADqB,OAAO,EAAQ,EAAE,IAAM,GAAG,GAC1B,QAAS,CAMxB,EAAQ,oBACV,QAAQ,IAAI,gCAAkC,EAAQ,mBAEpD,EAAQ,gBACV,QAAQ,IAAI,4BAA8B,EAAQ,eAQpD,GAAM,CAAE,UAAW,MAAM,OAAO,sBAC1B,CAAE,4BAA6B,MAAM,OAAO,uCAC5C,CAAE,eAAgB,MAAM,OAAO,sBAKrC,MAAM,EAAyB,EAAO,eAAe,CAQrD,QAAQ,SAAW,MAAM,GAAa,KACjC,CAGD,EAAQ,mBACV,QAAQ,IAAI,+BAAiC,EAAQ,kBAEnD,EAAQ,oBACV,QAAQ,IAAI,gCAAkC,EAAQ,mBAEpD,EAAQ,gBACV,QAAQ,IAAI,4BAA8B,EAAQ,eAEhD,EAAQ,kBAAoB,IAAA,KAC9B,QAAQ,IAAI,8BAAgC,OAAO,EAAQ,gBAAgB,EAEzE,EAAQ,mBAAqB,IAAA,KAC/B,QAAQ,IAAI,+BAAiC,OAAO,EAAQ,iBAAiB,EAE3E,EAAQ,aACV,QAAQ,IAAI,wBAA0B,EAAQ,YAiChD,IAAIC,EAAyD,UAE7D,GAAI,QAAQ,IAAI,4BACd,EAAe,cACN,QAAQ,IAAI,+BAAiC,IACtD,EAAe,eAQf,GAAI,CACF,GAAM,CAAE,kBAAiB,aAAc,MAAM,OAAO,8BAC9C,EAAe,MAAM,EAAU,EAAgB,CACjD,IACF,QAAQ,IAAI,4BAA8B,EACrC,QAAQ,IAAI,6BACf,QAAQ,IAAI,2BAA6B,GAE3C,EAAe,iBAEX,CAIN,EAAe,QAcnB,QAAQ,OAAO,MAAM,KAAK,UAAU,CAClC,OAAQ,kBACR,MAAO,mBACP,0BAA2B,QAAQ,IAAI,+BAAiC,IACxE,GAAI,MACJ,QAAS,EACT,SAAU,QAAQ,SAClB,OAAQ,EACT,CAAC,CAAG;EAAK,CAIV,GAAM,CAAE,QAAS,MAAM,OAAO,uBAE9B,MAAM,GAAM"}
@@ -1,3 +1,3 @@
1
- import"./normalizeUrl-fkFv5Mfb.js";import"./env-BU-k04bk.js";import"./logger-BwqGcO50.js";import{findProviderForUrl as e}from"./providers-xwC_AxDC.js";import{AuthServerDiscoveryError as t,discoverAuthServer as n,getDcrClientName as r,getDcrRedirectUris as i,walkTransports as a}from"./transportDetection-XcdORTci.js";async function o(e,t={}){let n=t.perServerTimeoutMs??15e3,r=t.maxRetries??1,i=t.retryDelayMs??200;return{results:await Promise.all(e.servers.map(e=>v(e.url,n,r,i)))}}async function s(e,t,n){let r=await fetch(e,{body:JSON.stringify(t),headers:{Accept:`application/json`,"Content-Type":`application/json`},method:`POST`,signal:n});if(r.status===200||r.status===201)try{let e=await r.json();return typeof e.client_id!=`string`||e.client_id.length===0?{status:r.status}:{body:e,status:r.status}}catch{return{status:r.status}}let i;try{i=(await r.text()).trim()}catch{}let a;return(r.status===429||r.status>=500)&&(a=h(r.headers.get(`Retry-After`))),{errorBody:i,retryAfterMs:a,status:r.status}}async function c(e,t){let{result:n}=await a(async n=>{let r=n===`streamable-http`?await g(e,t):await f(e,t);if(r.body?.cancel().catch(()=>{}),r.status===404||r.status===405)throw Object.assign(Error(`${n} returned ${r.status}`),{status:r.status});return r});return n}function l(e){return e<=0?0:Math.min(e,5e3)}function u(e){return e instanceof Error?e.message:String(e)}function d(e){if(e){try{let t=JSON.parse(e);if(t.error_description)return t.error_description;if(t.error)return t.error}catch{}return e.length>200?`${e.slice(0,200)}...`:e}}async function f(e,t){return fetch(e,{headers:{Accept:`text/event-stream`},method:`GET`,signal:t})}function p(e){return!!(e.reason===`network_error`&&!e.authServer||e.reason===`dcr_rejected`&&m(e.httpStatus))}function m(e){return e?e===429?!0:e>=500&&e<600:!1}function h(e){if(!e)return;let t=e.trim();if(!t)return;let n=Number(t);if(Number.isFinite(n))return l(n*1e3);let r=Date.parse(t);if(Number.isFinite(r)){let e=r-Date.now();return e>0?l(e):0}}async function g(e,t){return fetch(e,{body:JSON.stringify({id:1,jsonrpc:`2.0`,method:`initialize`,params:{capabilities:{},clientInfo:{name:`mcp-gateway-probe`,version:`1.0`},protocolVersion:`2024-11-05`}}),headers:{Accept:`application/json, text/event-stream`,"Content-Type":`application/json`},method:`POST`,signal:t})}async function _(a,o){let l=new URL(a);if(e(l))return{authType:`oauth_pre_registered`,reason:`pre_registered_provider`,url:a};let f;try{f=await c(a,o)}catch(e){return{authType:`probe_failed`,errorDetail:u(e),reason:`network_error`,url:a}}if(f.ok)return{authType:`public`,reason:`no_auth_required`,url:a};if(f.status!==401)return{authType:`probe_failed`,errorDetail:`initialize returned status ${f.status}`,httpStatus:f.status,reason:`network_error`,url:a};let p,m;try{let e=await n(l,{signal:o});p=e.authMetadata,m=e.authServerUrl}catch(e){return{authServer:e instanceof t?e.authServerUrl.toString():void 0,authType:`probe_failed`,errorDetail:u(e),reason:`auth_metadata_discovery_failed`,url:a}}if(!p)return{authServer:m.toString(),authType:`oauth_dcr_not_supported`,reason:`no_auth_metadata`,url:a};if(!p.registration_endpoint)return{authServer:m.toString(),authType:`oauth_dcr_not_supported`,reason:`no_registration_endpoint`,url:a};let h={client_name:r(),grant_types:[`authorization_code`,`refresh_token`],redirect_uris:i(l,`http://localhost:0/callback`),response_types:[`code`],token_endpoint_auth_method:`none`},g;try{g=await s(p.registration_endpoint,h,o)}catch(e){return{authServer:m.toString(),authType:`probe_failed`,errorDetail:u(e),reason:`network_error`,url:a}}return g.status!==200&&g.status!==201?{authServer:m.toString(),authType:`oauth_dcr_not_supported`,errorDetail:d(g.errorBody),httpStatus:g.status,reason:`dcr_rejected`,retryAfterMs:g.retryAfterMs,url:a}:g.body?{authServer:m.toString(),authType:`oauth_dcr`,reason:`dcr_success`,url:a}:{authServer:m.toString(),authType:`oauth_dcr_not_supported`,errorDetail:`DCR returned ${g.status} with unparseable body`,httpStatus:g.status,reason:`dcr_rejected`,url:a}}async function v(e,t,n,r){let i=await y(e,t);for(let a=0;a<n;a++){if(!p(i))return i;let n=Math.max(r,i.retryAfterMs??0);n>0&&await new Promise(e=>setTimeout(e,n)),i=await y(e,t)}return i}async function y(e,t){let n=new AbortController,r,i=new Promise(i=>{r=setTimeout(()=>{n.abort(),i({authType:`probe_failed`,errorDetail:`probe timed out after ${t}ms`,reason:`probe_timeout`,url:e})},t)}),a=_(e,n.signal).catch(r=>({authType:`probe_failed`,errorDetail:n.signal.aborted?`probe timed out after ${t}ms`:u(r),reason:n.signal.aborted?`probe_timeout`:`network_error`,url:e}));try{return await Promise.race([a,i])}finally{r&&clearTimeout(r)}}async function b(){let e;try{e=await S()}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`probe: failed to read stdin: ${t}\n`),2}let t;try{t=JSON.parse(e)}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`probe: stdin was not valid JSON: ${t}\n`),2}if(!x(t))return process.stderr.write(`probe: invalid input — expected {"servers":[{"url":"..."}]}
1
+ import"./normalizeUrl-fkFv5Mfb.js";import"./env-_7CCeXgw.js";import"./logger-DN0aJNvI.js";import{findProviderForUrl as e}from"./providers-qMBff1LW.js";import{AuthServerDiscoveryError as t,discoverAuthServer as n,getDcrClientName as r,getDcrRedirectUris as i,walkTransports as a}from"./transportDetection-B23P-H1Z.js";async function o(e,t={}){let n=t.perServerTimeoutMs??15e3,r=t.maxRetries??1,i=t.retryDelayMs??200;return{results:await Promise.all(e.servers.map(e=>v(e.url,n,r,i)))}}async function s(e,t,n){let r=await fetch(e,{body:JSON.stringify(t),headers:{Accept:`application/json`,"Content-Type":`application/json`},method:`POST`,signal:n});if(r.status===200||r.status===201)try{let e=await r.json();return typeof e.client_id!=`string`||e.client_id.length===0?{status:r.status}:{body:e,status:r.status}}catch{return{status:r.status}}let i;try{i=(await r.text()).trim()}catch{}let a;return(r.status===429||r.status>=500)&&(a=h(r.headers.get(`Retry-After`))),{errorBody:i,retryAfterMs:a,status:r.status}}async function c(e,t){let{result:n}=await a(async n=>{let r=n===`streamable-http`?await g(e,t):await f(e,t);if(r.body?.cancel().catch(()=>{}),r.status===404||r.status===405)throw Object.assign(Error(`${n} returned ${r.status}`),{status:r.status});return r});return n}function l(e){return e<=0?0:Math.min(e,5e3)}function u(e){return e instanceof Error?e.message:String(e)}function d(e){if(e){try{let t=JSON.parse(e);if(t.error_description)return t.error_description;if(t.error)return t.error}catch{}return e.length>200?`${e.slice(0,200)}...`:e}}async function f(e,t){return fetch(e,{headers:{Accept:`text/event-stream`},method:`GET`,signal:t})}function p(e){return!!(e.reason===`network_error`&&!e.authServer||e.reason===`dcr_rejected`&&m(e.httpStatus))}function m(e){return e?e===429?!0:e>=500&&e<600:!1}function h(e){if(!e)return;let t=e.trim();if(!t)return;let n=Number(t);if(Number.isFinite(n))return l(n*1e3);let r=Date.parse(t);if(Number.isFinite(r)){let e=r-Date.now();return e>0?l(e):0}}async function g(e,t){return fetch(e,{body:JSON.stringify({id:1,jsonrpc:`2.0`,method:`initialize`,params:{capabilities:{},clientInfo:{name:`mcp-gateway-probe`,version:`1.0`},protocolVersion:`2024-11-05`}}),headers:{Accept:`application/json, text/event-stream`,"Content-Type":`application/json`},method:`POST`,signal:t})}async function _(a,o){let l=new URL(a);if(e(l))return{authType:`oauth_pre_registered`,reason:`pre_registered_provider`,url:a};let f;try{f=await c(a,o)}catch(e){return{authType:`probe_failed`,errorDetail:u(e),reason:`network_error`,url:a}}if(f.ok)return{authType:`public`,reason:`no_auth_required`,url:a};if(f.status!==401)return{authType:`probe_failed`,errorDetail:`initialize returned status ${f.status}`,httpStatus:f.status,reason:`network_error`,url:a};let p,m;try{let e=await n(l,{signal:o});p=e.authMetadata,m=e.authServerUrl}catch(e){return{authServer:e instanceof t?e.authServerUrl.toString():void 0,authType:`probe_failed`,errorDetail:u(e),reason:`auth_metadata_discovery_failed`,url:a}}if(!p)return{authServer:m.toString(),authType:`oauth_dcr_not_supported`,reason:`no_auth_metadata`,url:a};if(!p.registration_endpoint)return{authServer:m.toString(),authType:`oauth_dcr_not_supported`,reason:`no_registration_endpoint`,url:a};let h={client_name:r(),grant_types:[`authorization_code`,`refresh_token`],redirect_uris:i(l,`http://localhost:0/callback`),response_types:[`code`],token_endpoint_auth_method:`none`},g;try{g=await s(p.registration_endpoint,h,o)}catch(e){return{authServer:m.toString(),authType:`probe_failed`,errorDetail:u(e),reason:`network_error`,url:a}}return g.status!==200&&g.status!==201?{authServer:m.toString(),authType:`oauth_dcr_not_supported`,errorDetail:d(g.errorBody),httpStatus:g.status,reason:`dcr_rejected`,retryAfterMs:g.retryAfterMs,url:a}:g.body?{authServer:m.toString(),authType:`oauth_dcr`,reason:`dcr_success`,url:a}:{authServer:m.toString(),authType:`oauth_dcr_not_supported`,errorDetail:`DCR returned ${g.status} with unparseable body`,httpStatus:g.status,reason:`dcr_rejected`,url:a}}async function v(e,t,n,r){let i=await y(e,t);for(let a=0;a<n;a++){if(!p(i))return i;let n=Math.max(r,i.retryAfterMs??0);n>0&&await new Promise(e=>setTimeout(e,n)),i=await y(e,t)}return i}async function y(e,t){let n=new AbortController,r,i=new Promise(i=>{r=setTimeout(()=>{n.abort(),i({authType:`probe_failed`,errorDetail:`probe timed out after ${t}ms`,reason:`probe_timeout`,url:e})},t)}),a=_(e,n.signal).catch(r=>({authType:`probe_failed`,errorDetail:n.signal.aborted?`probe timed out after ${t}ms`:u(r),reason:n.signal.aborted?`probe_timeout`:`network_error`,url:e}));try{return await Promise.race([a,i])}finally{r&&clearTimeout(r)}}async function b(){let e;try{e=await S()}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`probe: failed to read stdin: ${t}\n`),2}let t;try{t=JSON.parse(e)}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`probe: stdin was not valid JSON: ${t}\n`),2}if(!x(t))return process.stderr.write(`probe: invalid input — expected {"servers":[{"url":"..."}]}
2
2
  `),2;let n=await o(t);return process.stdout.write(`${JSON.stringify(n)}\n`),0}function x(e){if(!e||typeof e!=`object`)return!1;let t=e.servers;return Array.isArray(t)?t.every(e=>e&&typeof e==`object`&&typeof e.url==`string`):!1}async function S(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString(`utf8`)}export{b as runProbeCli};
3
- //# sourceMappingURL=cli-DQlVGyV_.js.map
3
+ //# sourceMappingURL=cli-C9BerLdo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-DQlVGyV_.js","names":["errorBody: string | undefined","retryAfterMs: number | undefined","initResponse: Response","authMetadata: Awaited<ReturnType<typeof discoverAuthServer>>[\"authMetadata\"]","authServerUrl: URL","clientMetadata: OAuthClientMetadata","dcr: Awaited<ReturnType<typeof attemptDcr>>","timerId: ReturnType<typeof setTimeout> | undefined","raw: string","parsed: unknown","chunks: Buffer[]"],"sources":["../src/probe/index.ts","../src/probe/cli.ts"],"sourcesContent":["import type { OAuthClientMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\n\nimport { AuthServerDiscoveryError, discoverAuthServer } from \"../auth/discovery.js\";\nimport { getDcrClientName, getDcrRedirectUris } from \"../auth/oauthFlow.js\";\nimport { findProviderForUrl } from \"../auth/providers.js\";\nimport { walkTransports } from \"../lib/transportDetection.js\";\n\nexport type AuthType =\n | \"oauth_dcr_not_supported\"\n | \"oauth_dcr\"\n | \"oauth_pre_registered\"\n | \"probe_failed\"\n | \"public\";\n\nexport interface ProbeInput {\n servers: Array<{ url: string }>;\n}\n\nexport interface ProbeOptions {\n /**\n * Maximum number of retries on transient pre-DCR network errors, on top of\n * the initial attempt. So `maxRetries=1` means up to 2 total attempts per\n * server. Defaults to 1.\n *\n * Retries fire only when the result is `network_error` AND no auth server\n * was discovered yet (i.e. POST initialize failed or returned a non-2xx\n * non-401 status). DCR network failures do NOT retry — they include the\n * discovered `authServer` in the result, which the retry filter excludes.\n * This prevents the rare case where a network blip after the DCR POST\n * was sent could cause duplicate orphan client registrations at the vendor.\n */\n maxRetries?: number;\n /** Per-server wall-clock timeout covering all HTTP calls for that server. */\n perServerTimeoutMs?: number;\n /** Delay between retry attempts. Defaults to 200ms. */\n retryDelayMs?: number;\n}\n\nexport interface ProbeOutput {\n results: ProbeResult[];\n}\n\nexport type ProbeReason =\n | \"auth_metadata_discovery_failed\"\n | \"dcr_rejected\"\n | \"dcr_success\"\n | \"network_error\"\n | \"no_auth_metadata\"\n | \"no_auth_required\"\n | \"no_registration_endpoint\"\n | \"pre_registered_provider\"\n | \"probe_timeout\";\n\nexport interface ProbeResult {\n authServer?: string;\n authType: AuthType;\n errorDetail?: string;\n httpStatus?: number;\n reason: ProbeReason;\n /**\n * For transient `dcr_rejected` results (429/5xx), the server's\n * `Retry-After` value in milliseconds, when provided. The retry wrapper\n * uses this as the inter-attempt delay; callers don't normally read it.\n */\n retryAfterMs?: number;\n url: string;\n}\n\n/**\n * The probe re-runs the same pre-browser steps as `performOAuthFlow` in\n * `oauthFlow.ts` — same SDK calls, same order — so we classify servers using\n * the exact code path the real OAuth flow would take. We stop just before the\n * browser-consent step (step 9+ in performOAuthFlow) because the probe runs\n * non-interactively at install time.\n *\n * Flow parity with performOAuthFlow:\n * - POST initialize (probe-specific: classify 200 vs 401 vs other)\n * - findProviderForUrl — same as performOAuthFlow step 2\n * - discoverOAuthProtectedResourceMetadata — same as step 3\n * - pick authorization_servers[0] with fallback — same as step 4\n * - discoverAuthorizationServerMetadata — same as step 5\n * - check registration_endpoint — same as step 7 precondition\n * - registerClient (SDK) — same as step 7\n * - return authType verdict (probe-only — OAuth flow would open browser here)\n *\n * authType mapping (kept alongside `reason` for callers that want diagnostics):\n * no_auth_required → public\n * pre_registered_provider → oauth_pre_registered\n * dcr_success → oauth_dcr\n * dcr_rejected → oauth_dcr_not_supported\n * no_registration_endpoint → oauth_dcr_not_supported\n * no_auth_metadata → oauth_dcr_not_supported\n * network_error → probe_failed\n */\n\nconst DCR_REDIRECT_URI = \"http://localhost:0/callback\";\nconst DEFAULT_PER_SERVER_TIMEOUT_MS = 15_000;\nconst DEFAULT_MAX_RETRIES = 1;\nconst DEFAULT_RETRY_DELAY_MS = 200;\n/**\n * Cap on `Retry-After` we'll honor before falling back to the default delay.\n * Prevents a misconfigured (or hostile) vendor from parking the install for\n * minutes/hours by setting `Retry-After: 3600`.\n */\nconst MAX_RETRY_AFTER_MS = 5_000;\n\nexport async function runProbeBatch(input: ProbeInput, options: ProbeOptions = {}): Promise<ProbeOutput> {\n const timeoutMs = options.perServerTimeoutMs ?? DEFAULT_PER_SERVER_TIMEOUT_MS;\n const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\n const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;\n\n const results = await Promise.all(\n input.servers.map((srv) => probeOneWithRetry(srv.url, timeoutMs, maxRetries, retryDelayMs))\n );\n\n return { results };\n}\n\n/**\n * Attempts DCR directly via fetch rather than SDK's `registerClient`.\n *\n * Reason we don't use the SDK here specifically: `registerClient` consumes the\n * response and throws, dropping the numeric HTTP status on success-with-bad-body\n * and on 4xx with a well-formed OAuth error body (e.g. Airtable). Probe needs\n * the status code for monitoring and to distinguish dcr_rejected from\n * network_error precisely. Everything else (discovery of resource and auth\n * server metadata) still goes through the SDK.\n *\n * Returns:\n * - { status, body } on 2xx with parseable JSON → caller classifies dcr_success\n * - { status, errorBody? } on non-2xx → caller classifies dcr_rejected\n * - throws on network failure/timeout → caller classifies network_error\n */\nasync function attemptDcr(\n registrationEndpoint: string,\n clientMetadata: OAuthClientMetadata,\n signal: AbortSignal\n): Promise<{\n body?: Record<string, unknown>;\n errorBody?: string;\n retryAfterMs?: number;\n status: number;\n}> {\n const res = await fetch(registrationEndpoint, {\n body: JSON.stringify(clientMetadata),\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n signal,\n });\n\n if (res.status === 200 || res.status === 201) {\n try {\n const body = (await res.json()) as Record<string, unknown>;\n // RFC 7591 §3.2.1 requires `client_id` in a successful registration\n // response. Some servers return a 2xx with a JSON error envelope or\n // a partial/malformed body; treating those as success would\n // false-positive `oauth_dcr` even though the OAuth flow can't\n // proceed. Require the mandatory field before classifying success.\n if (typeof body.client_id !== \"string\" || body.client_id.length === 0) {\n return { status: res.status };\n }\n return { body, status: res.status };\n } catch {\n // 2xx with unparseable body — caller treats as failure.\n return { status: res.status };\n }\n }\n\n // Non-2xx — try to surface the error body to errorDetail for humans.\n let errorBody: string | undefined;\n try {\n errorBody = (await res.text()).trim();\n } catch {\n // ignore\n }\n\n // Capture Retry-After (RFC 7231) on rate-limit / server-error responses so\n // probeOneWithRetry can wait the requested interval before re-attempting.\n // Anything outside the transient class (429 / 5xx) doesn't need this — we\n // won't retry those anyway.\n let retryAfterMs: number | undefined;\n if (res.status === 429 || res.status >= 500) {\n retryAfterMs = parseRetryAfter(res.headers.get(\"Retry-After\"));\n }\n\n return { errorBody, retryAfterMs, status: res.status };\n}\n\n/**\n * Performs the per-transport liveness/auth probe, falling back from Streamable\n * HTTP to SSE on 404/405 (the same priority order the runtime proxy uses via\n * `connectWithTransportFallback`). Returns the first response whose status is\n * not \"transport not supported\"; throws on any non-fallback error.\n *\n * The response body is cancelled before returning — the probe classifies on\n * `status` only and never reads body or headers. For SSE 200 responses this is\n * load-bearing: the event stream stays open indefinitely otherwise, leaking\n * connections at batch scale.\n */\nasync function attemptInitialize(url: string, signal: AbortSignal): Promise<Response> {\n const { result } = await walkTransports(async (transportType) => {\n const response =\n transportType === \"streamable-http\"\n ? await postInitialize(url, signal)\n : await getSseHandshake(url, signal);\n // Probe never reads body — cancel to avoid leaking SSE streams on 200.\n response.body?.cancel().catch(() => {\n /* already closed */\n });\n if (response.status === 404 || response.status === 405) {\n // Throw a status-bearing error so walkTransports' isTransportNotSupportedError\n // check matches and falls through to the next transport.\n throw Object.assign(new Error(`${transportType} returned ${response.status}`), {\n status: response.status,\n });\n }\n return response;\n });\n return result;\n}\n\nfunction clampRetryAfter(ms: number): number {\n if (ms <= 0) return 0;\n return Math.min(ms, MAX_RETRY_AFTER_MS);\n}\n\nfunction errMsg(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\n/** Parses an OAuth error body (RFC 6749) into a human-friendly one-liner. */\nfunction formatDcrErrorBody(body: string | undefined): string | undefined {\n if (!body) return undefined;\n try {\n const parsed = JSON.parse(body) as { error?: string; error_description?: string };\n if (parsed.error_description) return parsed.error_description;\n if (parsed.error) return parsed.error;\n } catch {\n // Non-JSON body — return as-is, capped to avoid dumping HTML pages.\n }\n return body.length > 200 ? `${body.slice(0, 200)}...` : body;\n}\n\nasync function getSseHandshake(url: string, signal: AbortSignal): Promise<Response> {\n return fetch(url, {\n headers: { Accept: \"text/event-stream\" },\n method: \"GET\",\n signal,\n });\n}\n\nfunction isRetryableResult(result: ProbeResult): boolean {\n // Pre-DCR network error — fetch threw before discovery finished.\n if (result.reason === \"network_error\" && !result.authServer) return true;\n // DCR returned a transient HTTP status — server responded but can't help yet.\n if (result.reason === \"dcr_rejected\" && isTransientStatus(result.httpStatus)) return true;\n return false;\n}\n\nfunction isTransientStatus(status: number | undefined): boolean {\n if (!status) return false;\n if (status === 429) return true;\n return status >= 500 && status < 600;\n}\n\n/**\n * Parses the Retry-After header (RFC 7231) in either of its two forms:\n * - delta-seconds: \"120\"\n * - HTTP-date: \"Wed, 21 Oct 2026 07:28:00 GMT\"\n *\n * Caps the result at MAX_RETRY_AFTER_MS so a misconfigured / malicious\n * server can't park our install for an hour. Returns undefined for\n * missing/unparseable values; callers fall back to the default delay.\n */\nfunction parseRetryAfter(header: null | string): number | undefined {\n if (!header) return undefined;\n const trimmed = header.trim();\n if (!trimmed) return undefined;\n\n const asNumber = Number(trimmed);\n if (Number.isFinite(asNumber)) {\n return clampRetryAfter(asNumber * 1000);\n }\n\n const asDate = Date.parse(trimmed);\n if (Number.isFinite(asDate)) {\n const ms = asDate - Date.now();\n return ms > 0 ? clampRetryAfter(ms) : 0;\n }\n\n return undefined;\n}\n\nasync function postInitialize(url: string, signal: AbortSignal): Promise<Response> {\n return fetch(url, {\n body: JSON.stringify({\n id: 1,\n jsonrpc: \"2.0\",\n method: \"initialize\",\n params: {\n capabilities: {},\n clientInfo: { name: \"mcp-gateway-probe\", version: \"1.0\" },\n protocolVersion: \"2024-11-05\",\n },\n }),\n headers: {\n Accept: \"application/json, text/event-stream\",\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n signal,\n });\n}\n\nasync function probeOne(url: string, signal: AbortSignal): Promise<ProbeResult> {\n const serverUrlObj = new URL(url);\n\n // Step 0: pre-configured OAuth provider — short-circuit before any network\n // call. OAUTH_PROVIDERS holds servers we've baked credentials into the\n // gateway for at build time; if a URL matches, we already know it needs\n // OAuth and we already have credentials, so probing the server itself\n // is wasted work.\n //\n // performOAuthFlow does this check at its step 2 (after starting a callback\n // server), but the probe never opens a browser, so we can hoist it earlier\n // and avoid the network calls oauthFlow's structure forces.\n if (findProviderForUrl(serverUrlObj)) {\n return { authType: \"oauth_pre_registered\", reason: \"pre_registered_provider\", url };\n }\n\n // Step 1: liveness/auth probe with transport fallback (Streamable HTTP → SSE,\n // matching the runtime proxy's priority order). Classify:\n // 200 → wrap (no_auth_required)\n // 401 → continue with auth discovery (same path performOAuthFlow takes)\n // else → skip (network_error)\n // attemptInitialize walks transports via walkTransports and falls through\n // 404/405 — so a server like cf-docs (POST /sse 404, GET /sse 200) classifies\n // as public on the SSE attempt rather than failing on the streamable-HTTP one.\n let initResponse: Response;\n try {\n initResponse = await attemptInitialize(url, signal);\n } catch (err) {\n return { authType: \"probe_failed\", errorDetail: errMsg(err), reason: \"network_error\", url };\n }\n if (initResponse.ok) {\n return { authType: \"public\", reason: \"no_auth_required\", url };\n }\n if (initResponse.status !== 401) {\n return {\n authType: \"probe_failed\",\n errorDetail: `initialize returned status ${initResponse.status}`,\n httpStatus: initResponse.status,\n reason: \"network_error\",\n url,\n };\n }\n\n // Steps 3-5: shared discovery with performOAuthFlow — see ../auth/discovery.ts.\n // The helper performs resource-metadata lookup, auth-server-URL selection, and\n // auth-server-metadata lookup in that order. It silences resource-metadata\n // errors (soft-fail) but throws AuthServerDiscoveryError when the auth-server\n // metadata call fails — preserving the computed authServerUrl on the error.\n let authMetadata: Awaited<ReturnType<typeof discoverAuthServer>>[\"authMetadata\"];\n let authServerUrl: URL;\n try {\n // Pass the per-server signal so a probeOneWithTimeout abort cancels the\n // SDK's well-known fetches too — otherwise orphaned requests outlive\n // the probe verdict and leak connections in batch runs.\n const discovered = await discoverAuthServer(serverUrlObj, { signal });\n authMetadata = discovered.authMetadata;\n authServerUrl = discovered.authServerUrl;\n } catch (err) {\n const authServer =\n err instanceof AuthServerDiscoveryError ? err.authServerUrl.toString() : undefined;\n // Thrown errors here are transport failures (DNS/timeout/5xx) on the\n // auth-server metadata fetch, NOT the \"metadata is genuinely absent\"\n // case. Folding them into oauth_dcr_not_supported would let the\n // server-side cache persist a transient outage as a permanent\n // negative verdict. Surface as probe_failed instead so the scanner\n // filter drops it from the cache write (transient state stays\n // transient). The definitive metadata-absent path lives in the\n // !authMetadata branch below.\n return {\n authServer,\n authType: \"probe_failed\",\n errorDetail: errMsg(err),\n reason: \"auth_metadata_discovery_failed\",\n url,\n };\n }\n if (!authMetadata) {\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr_not_supported\",\n reason: \"no_auth_metadata\",\n url,\n };\n }\n\n // Step 7 precondition: registration_endpoint present?\n // (performOAuthFlow throws here; probe classifies as oauth_dcr_not_supported instead.)\n if (!authMetadata.registration_endpoint) {\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr_not_supported\",\n reason: \"no_registration_endpoint\",\n url,\n };\n }\n\n // Step 7: DCR. Same body/method as performOAuthFlow, but attemptDcr gives us\n // the raw status code so we can distinguish dcr_rejected (4xx/5xx) from\n // network_error (fetch throw) and report httpStatus for monitoring.\n //\n // client_name is sourced from the same `CLIENT_APP_NAME` env the runtime\n // OAuth flow reads (see performOAuthFlow / getDcrClientName) so that\n // allowlist-style DCR endpoints (e.g. Figma) give the probe the same\n // verdict the runtime flow would produce for this agent. Without this,\n // probe would always send \"MCP Gateway\" and false-classify Figma as\n // oauth_dcr_not_supported even though a Cursor/Code/Copilot install\n // would succeed.\n const clientMetadata: OAuthClientMetadata = {\n client_name: getDcrClientName(),\n grant_types: [\"authorization_code\", \"refresh_token\"],\n // Per-(agent, server-host) decoy URI may be prepended at index 0 to pass\n // allowlist-style DCR gates (see DECOY_REDIRECT_URI_BY_APP_AND_HOST in\n // auth/oauthFlow.ts). For most pairs this resolves to [DCR_REDIRECT_URI],\n // preserving the pre-existing probe shape exactly.\n redirect_uris: getDcrRedirectUris(serverUrlObj, DCR_REDIRECT_URI),\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n };\n let dcr: Awaited<ReturnType<typeof attemptDcr>>;\n try {\n dcr = await attemptDcr(authMetadata.registration_endpoint, clientMetadata, signal);\n } catch (err) {\n // fetch itself threw — network layer failure, not a policy decision\n // from the auth server.\n return {\n authServer: authServerUrl.toString(),\n authType: \"probe_failed\",\n errorDetail: errMsg(err),\n reason: \"network_error\",\n url,\n };\n }\n\n if (dcr.status !== 200 && dcr.status !== 201) {\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr_not_supported\",\n errorDetail: formatDcrErrorBody(dcr.errorBody),\n httpStatus: dcr.status,\n reason: \"dcr_rejected\",\n retryAfterMs: dcr.retryAfterMs,\n url,\n };\n }\n if (!dcr.body) {\n // 2xx but body didn't parse — treat as rejection rather than silently wrap.\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr_not_supported\",\n errorDetail: `DCR returned ${dcr.status} with unparseable body`,\n httpStatus: dcr.status,\n reason: \"dcr_rejected\",\n url,\n };\n }\n\n // NOTE: performOAuthFlow would open the browser and complete the flow here.\n // The probe stops at successful DCR.\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr\",\n reason: \"dcr_success\",\n url,\n };\n}\n\n/**\n * Wraps `probeOneWithTimeout` with retry-on-transient-error.\n *\n * Retries up to `maxRetries` times when the result is transient. Two\n * categories of transient are recognized:\n *\n * 1. Pre-DCR network error — `reason === \"network_error\" && !authServer`.\n * The fetch threw or returned non-401/non-2xx before discovery\n * finished. No registration request reached any vendor; retrying is\n * structurally safe (no orphan multiplication).\n *\n * 2. DCR transient — `reason === \"dcr_rejected\" && (httpStatus === 429\n * || httpStatus >= 500)`. The vendor responded definitively that they\n * can't help right now (rate-limited or server error). Because we got\n * a complete response, the server explicitly did NOT create a\n * registration; retrying is also safe and may succeed once the\n * transient condition clears.\n *\n * Notably NOT retried:\n * - DCR network failures (`network_error` WITH `authServer`) — fetch\n * threw mid-flight; the request may have arrived at the vendor.\n * - DCR 4xx (other than 429) — definitive policy refusal.\n * - `no_auth_metadata`, `no_registration_endpoint` — definitive answers.\n *\n * For DCR transients, the actual delay is `max(retryDelayMs, retryAfterMs)`\n * if the server provided a `Retry-After` header (capped to MAX_RETRY_AFTER_MS).\n */\nasync function probeOneWithRetry(\n url: string,\n timeoutMs: number,\n maxRetries: number,\n retryDelayMs: number\n): Promise<ProbeResult> {\n let result = await probeOneWithTimeout(url, timeoutMs);\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n if (!isRetryableResult(result)) return result;\n const delay = Math.max(retryDelayMs, result.retryAfterMs ?? 0);\n if (delay > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n }\n result = await probeOneWithTimeout(url, timeoutMs);\n }\n return result;\n}\n\nasync function probeOneWithTimeout(url: string, timeoutMs: number): Promise<ProbeResult> {\n const controller = new AbortController();\n let timerId: ReturnType<typeof setTimeout> | undefined;\n\n // Race the probe against a wall-clock timeout. AbortSignal alone isn't\n // enough — some fetch implementations (or test mocks) may ignore it. This\n // guarantees we always return within timeoutMs.\n const timeoutPromise = new Promise<ProbeResult>((resolve) => {\n timerId = setTimeout(() => {\n controller.abort();\n // Distinct reason \"probe_timeout\" — NOT \"network_error\". The\n // wall-clock timeout fires from outside probeOne, so we don't\n // know which phase aborted: discovery, registration POST, or\n // anything in between. If the timeout struck after the\n // registration POST went through, retrying would create a second\n // DCR client_id. Marking timeouts non-retryable (see\n // isRetryableResult) errs on the side of one orphan probe over\n // duplicate DCR registrations.\n resolve({\n authType: \"probe_failed\",\n errorDetail: `probe timed out after ${timeoutMs}ms`,\n reason: \"probe_timeout\",\n url,\n });\n }, timeoutMs);\n });\n\n const probePromise = probeOne(url, controller.signal).catch((err) => ({\n authType: \"probe_failed\" as const,\n errorDetail: controller.signal.aborted ? `probe timed out after ${timeoutMs}ms` : errMsg(err),\n // controller.signal.aborted means the wall-clock timeoutPromise\n // fired and aborted us mid-flight. Same retry-safety reasoning as\n // the timeoutPromise branch — surface as probe_timeout so we\n // don't reissue DCR.\n reason: controller.signal.aborted ? (\"probe_timeout\" as const) : (\"network_error\" as const),\n url,\n }));\n\n try {\n return await Promise.race([probePromise, timeoutPromise]);\n } finally {\n if (timerId) clearTimeout(timerId);\n }\n}\n","import type { ProbeInput } from \"./index.js\";\n\nimport { runProbeBatch } from \"./index.js\";\n\nconst EXIT_OK = 0;\nconst EXIT_BAD_INPUT = 2;\n\n/**\n * Entry point for the `mcp-gateway probe` subcommand.\n *\n * Reads a JSON batch of server URLs from stdin, runs the DCR/auth probe for\n * each in parallel, and writes the aggregated result JSON to stdout.\n *\n * Intended to be invoked by the scanner during install to decide which remote\n * MCP servers are safe to wrap vs. leave alone.\n */\nexport async function runProbeCli(): Promise<number> {\n let raw: string;\n try {\n raw = await readStdin();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`probe: failed to read stdin: ${msg}\\n`);\n return EXIT_BAD_INPUT;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`probe: stdin was not valid JSON: ${msg}\\n`);\n return EXIT_BAD_INPUT;\n }\n\n if (!isValidInput(parsed)) {\n process.stderr.write(`probe: invalid input — expected {\"servers\":[{\"url\":\"...\"}]}\\n`);\n return EXIT_BAD_INPUT;\n }\n\n const output = await runProbeBatch(parsed);\n process.stdout.write(`${JSON.stringify(output)}\\n`);\n return EXIT_OK;\n}\n\nfunction isValidInput(value: unknown): value is ProbeInput {\n if (!value || typeof value !== \"object\") return false;\n const servers = (value as { servers?: unknown }).servers;\n if (!Array.isArray(servers)) return false;\n return servers.every((s) => s && typeof s === \"object\" && typeof (s as { url?: unknown }).url === \"string\");\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli-C9BerLdo.js","names":["errorBody: string | undefined","retryAfterMs: number | undefined","initResponse: Response","authMetadata: Awaited<ReturnType<typeof discoverAuthServer>>[\"authMetadata\"]","authServerUrl: URL","clientMetadata: OAuthClientMetadata","dcr: Awaited<ReturnType<typeof attemptDcr>>","timerId: ReturnType<typeof setTimeout> | undefined","raw: string","parsed: unknown","chunks: Buffer[]"],"sources":["../src/probe/index.ts","../src/probe/cli.ts"],"sourcesContent":["import type { OAuthClientMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\n\nimport { AuthServerDiscoveryError, discoverAuthServer } from \"../auth/discovery.js\";\nimport { getDcrClientName, getDcrRedirectUris } from \"../auth/oauthFlow.js\";\nimport { findProviderForUrl } from \"../auth/providers.js\";\nimport { walkTransports } from \"../lib/transportDetection.js\";\n\nexport type AuthType =\n | \"oauth_dcr_not_supported\"\n | \"oauth_dcr\"\n | \"oauth_pre_registered\"\n | \"probe_failed\"\n | \"public\";\n\nexport interface ProbeInput {\n servers: Array<{ url: string }>;\n}\n\nexport interface ProbeOptions {\n /**\n * Maximum number of retries on transient pre-DCR network errors, on top of\n * the initial attempt. So `maxRetries=1` means up to 2 total attempts per\n * server. Defaults to 1.\n *\n * Retries fire only when the result is `network_error` AND no auth server\n * was discovered yet (i.e. POST initialize failed or returned a non-2xx\n * non-401 status). DCR network failures do NOT retry — they include the\n * discovered `authServer` in the result, which the retry filter excludes.\n * This prevents the rare case where a network blip after the DCR POST\n * was sent could cause duplicate orphan client registrations at the vendor.\n */\n maxRetries?: number;\n /** Per-server wall-clock timeout covering all HTTP calls for that server. */\n perServerTimeoutMs?: number;\n /** Delay between retry attempts. Defaults to 200ms. */\n retryDelayMs?: number;\n}\n\nexport interface ProbeOutput {\n results: ProbeResult[];\n}\n\nexport type ProbeReason =\n | \"auth_metadata_discovery_failed\"\n | \"dcr_rejected\"\n | \"dcr_success\"\n | \"network_error\"\n | \"no_auth_metadata\"\n | \"no_auth_required\"\n | \"no_registration_endpoint\"\n | \"pre_registered_provider\"\n | \"probe_timeout\";\n\nexport interface ProbeResult {\n authServer?: string;\n authType: AuthType;\n errorDetail?: string;\n httpStatus?: number;\n reason: ProbeReason;\n /**\n * For transient `dcr_rejected` results (429/5xx), the server's\n * `Retry-After` value in milliseconds, when provided. The retry wrapper\n * uses this as the inter-attempt delay; callers don't normally read it.\n */\n retryAfterMs?: number;\n url: string;\n}\n\n/**\n * The probe re-runs the same pre-browser steps as `performOAuthFlow` in\n * `oauthFlow.ts` — same SDK calls, same order — so we classify servers using\n * the exact code path the real OAuth flow would take. We stop just before the\n * browser-consent step (step 9+ in performOAuthFlow) because the probe runs\n * non-interactively at install time.\n *\n * Flow parity with performOAuthFlow:\n * - POST initialize (probe-specific: classify 200 vs 401 vs other)\n * - findProviderForUrl — same as performOAuthFlow step 2\n * - discoverOAuthProtectedResourceMetadata — same as step 3\n * - pick authorization_servers[0] with fallback — same as step 4\n * - discoverAuthorizationServerMetadata — same as step 5\n * - check registration_endpoint — same as step 7 precondition\n * - registerClient (SDK) — same as step 7\n * - return authType verdict (probe-only — OAuth flow would open browser here)\n *\n * authType mapping (kept alongside `reason` for callers that want diagnostics):\n * no_auth_required → public\n * pre_registered_provider → oauth_pre_registered\n * dcr_success → oauth_dcr\n * dcr_rejected → oauth_dcr_not_supported\n * no_registration_endpoint → oauth_dcr_not_supported\n * no_auth_metadata → oauth_dcr_not_supported\n * network_error → probe_failed\n */\n\nconst DCR_REDIRECT_URI = \"http://localhost:0/callback\";\nconst DEFAULT_PER_SERVER_TIMEOUT_MS = 15_000;\nconst DEFAULT_MAX_RETRIES = 1;\nconst DEFAULT_RETRY_DELAY_MS = 200;\n/**\n * Cap on `Retry-After` we'll honor before falling back to the default delay.\n * Prevents a misconfigured (or hostile) vendor from parking the install for\n * minutes/hours by setting `Retry-After: 3600`.\n */\nconst MAX_RETRY_AFTER_MS = 5_000;\n\nexport async function runProbeBatch(input: ProbeInput, options: ProbeOptions = {}): Promise<ProbeOutput> {\n const timeoutMs = options.perServerTimeoutMs ?? DEFAULT_PER_SERVER_TIMEOUT_MS;\n const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\n const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;\n\n const results = await Promise.all(\n input.servers.map((srv) => probeOneWithRetry(srv.url, timeoutMs, maxRetries, retryDelayMs))\n );\n\n return { results };\n}\n\n/**\n * Attempts DCR directly via fetch rather than SDK's `registerClient`.\n *\n * Reason we don't use the SDK here specifically: `registerClient` consumes the\n * response and throws, dropping the numeric HTTP status on success-with-bad-body\n * and on 4xx with a well-formed OAuth error body (e.g. Airtable). Probe needs\n * the status code for monitoring and to distinguish dcr_rejected from\n * network_error precisely. Everything else (discovery of resource and auth\n * server metadata) still goes through the SDK.\n *\n * Returns:\n * - { status, body } on 2xx with parseable JSON → caller classifies dcr_success\n * - { status, errorBody? } on non-2xx → caller classifies dcr_rejected\n * - throws on network failure/timeout → caller classifies network_error\n */\nasync function attemptDcr(\n registrationEndpoint: string,\n clientMetadata: OAuthClientMetadata,\n signal: AbortSignal\n): Promise<{\n body?: Record<string, unknown>;\n errorBody?: string;\n retryAfterMs?: number;\n status: number;\n}> {\n const res = await fetch(registrationEndpoint, {\n body: JSON.stringify(clientMetadata),\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n signal,\n });\n\n if (res.status === 200 || res.status === 201) {\n try {\n const body = (await res.json()) as Record<string, unknown>;\n // RFC 7591 §3.2.1 requires `client_id` in a successful registration\n // response. Some servers return a 2xx with a JSON error envelope or\n // a partial/malformed body; treating those as success would\n // false-positive `oauth_dcr` even though the OAuth flow can't\n // proceed. Require the mandatory field before classifying success.\n if (typeof body.client_id !== \"string\" || body.client_id.length === 0) {\n return { status: res.status };\n }\n return { body, status: res.status };\n } catch {\n // 2xx with unparseable body — caller treats as failure.\n return { status: res.status };\n }\n }\n\n // Non-2xx — try to surface the error body to errorDetail for humans.\n let errorBody: string | undefined;\n try {\n errorBody = (await res.text()).trim();\n } catch {\n // ignore\n }\n\n // Capture Retry-After (RFC 7231) on rate-limit / server-error responses so\n // probeOneWithRetry can wait the requested interval before re-attempting.\n // Anything outside the transient class (429 / 5xx) doesn't need this — we\n // won't retry those anyway.\n let retryAfterMs: number | undefined;\n if (res.status === 429 || res.status >= 500) {\n retryAfterMs = parseRetryAfter(res.headers.get(\"Retry-After\"));\n }\n\n return { errorBody, retryAfterMs, status: res.status };\n}\n\n/**\n * Performs the per-transport liveness/auth probe, falling back from Streamable\n * HTTP to SSE on 404/405 (the same priority order the runtime proxy uses via\n * `connectWithTransportFallback`). Returns the first response whose status is\n * not \"transport not supported\"; throws on any non-fallback error.\n *\n * The response body is cancelled before returning — the probe classifies on\n * `status` only and never reads body or headers. For SSE 200 responses this is\n * load-bearing: the event stream stays open indefinitely otherwise, leaking\n * connections at batch scale.\n */\nasync function attemptInitialize(url: string, signal: AbortSignal): Promise<Response> {\n const { result } = await walkTransports(async (transportType) => {\n const response =\n transportType === \"streamable-http\"\n ? await postInitialize(url, signal)\n : await getSseHandshake(url, signal);\n // Probe never reads body — cancel to avoid leaking SSE streams on 200.\n response.body?.cancel().catch(() => {\n /* already closed */\n });\n if (response.status === 404 || response.status === 405) {\n // Throw a status-bearing error so walkTransports' isTransportNotSupportedError\n // check matches and falls through to the next transport.\n throw Object.assign(new Error(`${transportType} returned ${response.status}`), {\n status: response.status,\n });\n }\n return response;\n });\n return result;\n}\n\nfunction clampRetryAfter(ms: number): number {\n if (ms <= 0) return 0;\n return Math.min(ms, MAX_RETRY_AFTER_MS);\n}\n\nfunction errMsg(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\n/** Parses an OAuth error body (RFC 6749) into a human-friendly one-liner. */\nfunction formatDcrErrorBody(body: string | undefined): string | undefined {\n if (!body) return undefined;\n try {\n const parsed = JSON.parse(body) as { error?: string; error_description?: string };\n if (parsed.error_description) return parsed.error_description;\n if (parsed.error) return parsed.error;\n } catch {\n // Non-JSON body — return as-is, capped to avoid dumping HTML pages.\n }\n return body.length > 200 ? `${body.slice(0, 200)}...` : body;\n}\n\nasync function getSseHandshake(url: string, signal: AbortSignal): Promise<Response> {\n return fetch(url, {\n headers: { Accept: \"text/event-stream\" },\n method: \"GET\",\n signal,\n });\n}\n\nfunction isRetryableResult(result: ProbeResult): boolean {\n // Pre-DCR network error — fetch threw before discovery finished.\n if (result.reason === \"network_error\" && !result.authServer) return true;\n // DCR returned a transient HTTP status — server responded but can't help yet.\n if (result.reason === \"dcr_rejected\" && isTransientStatus(result.httpStatus)) return true;\n return false;\n}\n\nfunction isTransientStatus(status: number | undefined): boolean {\n if (!status) return false;\n if (status === 429) return true;\n return status >= 500 && status < 600;\n}\n\n/**\n * Parses the Retry-After header (RFC 7231) in either of its two forms:\n * - delta-seconds: \"120\"\n * - HTTP-date: \"Wed, 21 Oct 2026 07:28:00 GMT\"\n *\n * Caps the result at MAX_RETRY_AFTER_MS so a misconfigured / malicious\n * server can't park our install for an hour. Returns undefined for\n * missing/unparseable values; callers fall back to the default delay.\n */\nfunction parseRetryAfter(header: null | string): number | undefined {\n if (!header) return undefined;\n const trimmed = header.trim();\n if (!trimmed) return undefined;\n\n const asNumber = Number(trimmed);\n if (Number.isFinite(asNumber)) {\n return clampRetryAfter(asNumber * 1000);\n }\n\n const asDate = Date.parse(trimmed);\n if (Number.isFinite(asDate)) {\n const ms = asDate - Date.now();\n return ms > 0 ? clampRetryAfter(ms) : 0;\n }\n\n return undefined;\n}\n\nasync function postInitialize(url: string, signal: AbortSignal): Promise<Response> {\n return fetch(url, {\n body: JSON.stringify({\n id: 1,\n jsonrpc: \"2.0\",\n method: \"initialize\",\n params: {\n capabilities: {},\n clientInfo: { name: \"mcp-gateway-probe\", version: \"1.0\" },\n protocolVersion: \"2024-11-05\",\n },\n }),\n headers: {\n Accept: \"application/json, text/event-stream\",\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n signal,\n });\n}\n\nasync function probeOne(url: string, signal: AbortSignal): Promise<ProbeResult> {\n const serverUrlObj = new URL(url);\n\n // Step 0: pre-configured OAuth provider — short-circuit before any network\n // call. OAUTH_PROVIDERS holds servers we've baked credentials into the\n // gateway for at build time; if a URL matches, we already know it needs\n // OAuth and we already have credentials, so probing the server itself\n // is wasted work.\n //\n // performOAuthFlow does this check at its step 2 (after starting a callback\n // server), but the probe never opens a browser, so we can hoist it earlier\n // and avoid the network calls oauthFlow's structure forces.\n if (findProviderForUrl(serverUrlObj)) {\n return { authType: \"oauth_pre_registered\", reason: \"pre_registered_provider\", url };\n }\n\n // Step 1: liveness/auth probe with transport fallback (Streamable HTTP → SSE,\n // matching the runtime proxy's priority order). Classify:\n // 200 → wrap (no_auth_required)\n // 401 → continue with auth discovery (same path performOAuthFlow takes)\n // else → skip (network_error)\n // attemptInitialize walks transports via walkTransports and falls through\n // 404/405 — so a server like cf-docs (POST /sse 404, GET /sse 200) classifies\n // as public on the SSE attempt rather than failing on the streamable-HTTP one.\n let initResponse: Response;\n try {\n initResponse = await attemptInitialize(url, signal);\n } catch (err) {\n return { authType: \"probe_failed\", errorDetail: errMsg(err), reason: \"network_error\", url };\n }\n if (initResponse.ok) {\n return { authType: \"public\", reason: \"no_auth_required\", url };\n }\n if (initResponse.status !== 401) {\n return {\n authType: \"probe_failed\",\n errorDetail: `initialize returned status ${initResponse.status}`,\n httpStatus: initResponse.status,\n reason: \"network_error\",\n url,\n };\n }\n\n // Steps 3-5: shared discovery with performOAuthFlow — see ../auth/discovery.ts.\n // The helper performs resource-metadata lookup, auth-server-URL selection, and\n // auth-server-metadata lookup in that order. It silences resource-metadata\n // errors (soft-fail) but throws AuthServerDiscoveryError when the auth-server\n // metadata call fails — preserving the computed authServerUrl on the error.\n let authMetadata: Awaited<ReturnType<typeof discoverAuthServer>>[\"authMetadata\"];\n let authServerUrl: URL;\n try {\n // Pass the per-server signal so a probeOneWithTimeout abort cancels the\n // SDK's well-known fetches too — otherwise orphaned requests outlive\n // the probe verdict and leak connections in batch runs.\n const discovered = await discoverAuthServer(serverUrlObj, { signal });\n authMetadata = discovered.authMetadata;\n authServerUrl = discovered.authServerUrl;\n } catch (err) {\n const authServer =\n err instanceof AuthServerDiscoveryError ? err.authServerUrl.toString() : undefined;\n // Thrown errors here are transport failures (DNS/timeout/5xx) on the\n // auth-server metadata fetch, NOT the \"metadata is genuinely absent\"\n // case. Folding them into oauth_dcr_not_supported would let the\n // server-side cache persist a transient outage as a permanent\n // negative verdict. Surface as probe_failed instead so the scanner\n // filter drops it from the cache write (transient state stays\n // transient). The definitive metadata-absent path lives in the\n // !authMetadata branch below.\n return {\n authServer,\n authType: \"probe_failed\",\n errorDetail: errMsg(err),\n reason: \"auth_metadata_discovery_failed\",\n url,\n };\n }\n if (!authMetadata) {\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr_not_supported\",\n reason: \"no_auth_metadata\",\n url,\n };\n }\n\n // Step 7 precondition: registration_endpoint present?\n // (performOAuthFlow throws here; probe classifies as oauth_dcr_not_supported instead.)\n if (!authMetadata.registration_endpoint) {\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr_not_supported\",\n reason: \"no_registration_endpoint\",\n url,\n };\n }\n\n // Step 7: DCR. Same body/method as performOAuthFlow, but attemptDcr gives us\n // the raw status code so we can distinguish dcr_rejected (4xx/5xx) from\n // network_error (fetch throw) and report httpStatus for monitoring.\n //\n // client_name is sourced from the same `CLIENT_APP_NAME` env the runtime\n // OAuth flow reads (see performOAuthFlow / getDcrClientName) so that\n // allowlist-style DCR endpoints (e.g. Figma) give the probe the same\n // verdict the runtime flow would produce for this agent. Without this,\n // probe would always send \"MCP Gateway\" and false-classify Figma as\n // oauth_dcr_not_supported even though a Cursor/Code/Copilot install\n // would succeed.\n const clientMetadata: OAuthClientMetadata = {\n client_name: getDcrClientName(),\n grant_types: [\"authorization_code\", \"refresh_token\"],\n // Per-(agent, server-host) decoy URI may be prepended at index 0 to pass\n // allowlist-style DCR gates (see DECOY_REDIRECT_URI_BY_APP_AND_HOST in\n // auth/oauthFlow.ts). For most pairs this resolves to [DCR_REDIRECT_URI],\n // preserving the pre-existing probe shape exactly.\n redirect_uris: getDcrRedirectUris(serverUrlObj, DCR_REDIRECT_URI),\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n };\n let dcr: Awaited<ReturnType<typeof attemptDcr>>;\n try {\n dcr = await attemptDcr(authMetadata.registration_endpoint, clientMetadata, signal);\n } catch (err) {\n // fetch itself threw — network layer failure, not a policy decision\n // from the auth server.\n return {\n authServer: authServerUrl.toString(),\n authType: \"probe_failed\",\n errorDetail: errMsg(err),\n reason: \"network_error\",\n url,\n };\n }\n\n if (dcr.status !== 200 && dcr.status !== 201) {\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr_not_supported\",\n errorDetail: formatDcrErrorBody(dcr.errorBody),\n httpStatus: dcr.status,\n reason: \"dcr_rejected\",\n retryAfterMs: dcr.retryAfterMs,\n url,\n };\n }\n if (!dcr.body) {\n // 2xx but body didn't parse — treat as rejection rather than silently wrap.\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr_not_supported\",\n errorDetail: `DCR returned ${dcr.status} with unparseable body`,\n httpStatus: dcr.status,\n reason: \"dcr_rejected\",\n url,\n };\n }\n\n // NOTE: performOAuthFlow would open the browser and complete the flow here.\n // The probe stops at successful DCR.\n return {\n authServer: authServerUrl.toString(),\n authType: \"oauth_dcr\",\n reason: \"dcr_success\",\n url,\n };\n}\n\n/**\n * Wraps `probeOneWithTimeout` with retry-on-transient-error.\n *\n * Retries up to `maxRetries` times when the result is transient. Two\n * categories of transient are recognized:\n *\n * 1. Pre-DCR network error — `reason === \"network_error\" && !authServer`.\n * The fetch threw or returned non-401/non-2xx before discovery\n * finished. No registration request reached any vendor; retrying is\n * structurally safe (no orphan multiplication).\n *\n * 2. DCR transient — `reason === \"dcr_rejected\" && (httpStatus === 429\n * || httpStatus >= 500)`. The vendor responded definitively that they\n * can't help right now (rate-limited or server error). Because we got\n * a complete response, the server explicitly did NOT create a\n * registration; retrying is also safe and may succeed once the\n * transient condition clears.\n *\n * Notably NOT retried:\n * - DCR network failures (`network_error` WITH `authServer`) — fetch\n * threw mid-flight; the request may have arrived at the vendor.\n * - DCR 4xx (other than 429) — definitive policy refusal.\n * - `no_auth_metadata`, `no_registration_endpoint` — definitive answers.\n *\n * For DCR transients, the actual delay is `max(retryDelayMs, retryAfterMs)`\n * if the server provided a `Retry-After` header (capped to MAX_RETRY_AFTER_MS).\n */\nasync function probeOneWithRetry(\n url: string,\n timeoutMs: number,\n maxRetries: number,\n retryDelayMs: number\n): Promise<ProbeResult> {\n let result = await probeOneWithTimeout(url, timeoutMs);\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n if (!isRetryableResult(result)) return result;\n const delay = Math.max(retryDelayMs, result.retryAfterMs ?? 0);\n if (delay > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n }\n result = await probeOneWithTimeout(url, timeoutMs);\n }\n return result;\n}\n\nasync function probeOneWithTimeout(url: string, timeoutMs: number): Promise<ProbeResult> {\n const controller = new AbortController();\n let timerId: ReturnType<typeof setTimeout> | undefined;\n\n // Race the probe against a wall-clock timeout. AbortSignal alone isn't\n // enough — some fetch implementations (or test mocks) may ignore it. This\n // guarantees we always return within timeoutMs.\n const timeoutPromise = new Promise<ProbeResult>((resolve) => {\n timerId = setTimeout(() => {\n controller.abort();\n // Distinct reason \"probe_timeout\" — NOT \"network_error\". The\n // wall-clock timeout fires from outside probeOne, so we don't\n // know which phase aborted: discovery, registration POST, or\n // anything in between. If the timeout struck after the\n // registration POST went through, retrying would create a second\n // DCR client_id. Marking timeouts non-retryable (see\n // isRetryableResult) errs on the side of one orphan probe over\n // duplicate DCR registrations.\n resolve({\n authType: \"probe_failed\",\n errorDetail: `probe timed out after ${timeoutMs}ms`,\n reason: \"probe_timeout\",\n url,\n });\n }, timeoutMs);\n });\n\n const probePromise = probeOne(url, controller.signal).catch((err) => ({\n authType: \"probe_failed\" as const,\n errorDetail: controller.signal.aborted ? `probe timed out after ${timeoutMs}ms` : errMsg(err),\n // controller.signal.aborted means the wall-clock timeoutPromise\n // fired and aborted us mid-flight. Same retry-safety reasoning as\n // the timeoutPromise branch — surface as probe_timeout so we\n // don't reissue DCR.\n reason: controller.signal.aborted ? (\"probe_timeout\" as const) : (\"network_error\" as const),\n url,\n }));\n\n try {\n return await Promise.race([probePromise, timeoutPromise]);\n } finally {\n if (timerId) clearTimeout(timerId);\n }\n}\n","import type { ProbeInput } from \"./index.js\";\n\nimport { runProbeBatch } from \"./index.js\";\n\nconst EXIT_OK = 0;\nconst EXIT_BAD_INPUT = 2;\n\n/**\n * Entry point for the `mcp-gateway probe` subcommand.\n *\n * Reads a JSON batch of server URLs from stdin, runs the DCR/auth probe for\n * each in parallel, and writes the aggregated result JSON to stdout.\n *\n * Intended to be invoked by the scanner during install to decide which remote\n * MCP servers are safe to wrap vs. leave alone.\n */\nexport async function runProbeCli(): Promise<number> {\n let raw: string;\n try {\n raw = await readStdin();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`probe: failed to read stdin: ${msg}\\n`);\n return EXIT_BAD_INPUT;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`probe: stdin was not valid JSON: ${msg}\\n`);\n return EXIT_BAD_INPUT;\n }\n\n if (!isValidInput(parsed)) {\n process.stderr.write(`probe: invalid input — expected {\"servers\":[{\"url\":\"...\"}]}\\n`);\n return EXIT_BAD_INPUT;\n }\n\n const output = await runProbeBatch(parsed);\n process.stdout.write(`${JSON.stringify(output)}\\n`);\n return EXIT_OK;\n}\n\nfunction isValidInput(value: unknown): value is ProbeInput {\n if (!value || typeof value !== \"object\") return false;\n const servers = (value as { servers?: unknown }).servers;\n if (!Array.isArray(servers)) return false;\n return servers.every((s) => s && typeof s === \"object\" && typeof (s as { url?: unknown }).url === \"string\");\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- import{ACCESS_CONTROL_HEADERS as e,ACCESS_CONTROL_TIMEOUT_MS as t,ACCESS_CONTROL_URL as n,APP_VERSION as r,CLIENT_APP_NAME as i,DEBUG_MODE as a,LOG_DIR as o,LOG_INGEST_ENABLED as s,LOG_INGEST_TIMEOUT_MS as c,LOG_INGEST_URL as l,MIRROR_URL as u,OAUTH_DIR as d,OAUTH_PROVIDERS_TIMEOUT_MS as f,OAUTH_PROVIDERS_URL as p,PROXY_COMMAND as m,SCANNER_API_KEY as h,SCANNER_FAIL_OPEN as g,SCANNER_HEADERS as _,SCANNER_TIMEOUT_MS as v,SCANNER_URL as y,SESSION_ID as b,config as x,deriveAccessControlUrl as S,deriveLogIngestUrl as C}from"./env-BU-k04bk.js";export{x as config};
1
+ import{ACCESS_CONTROL_HEADERS as e,ACCESS_CONTROL_TIMEOUT_MS as t,ACCESS_CONTROL_URL as n,APP_VERSION as r,CLIENT_APP_NAME as i,DEBUG_MODE as a,LOG_DIR as o,LOG_INGEST_ENABLED as s,LOG_INGEST_TIMEOUT_MS as c,LOG_INGEST_URL as l,MIRROR_URL as u,OAUTH_DIR as d,OAUTH_PROVIDERS_TIMEOUT_MS as f,OAUTH_PROVIDERS_URL as p,PROXY_COMMAND as m,SCANNER_API_KEY as h,SCANNER_FAIL_OPEN as g,SCANNER_HEADERS as _,SCANNER_TIMEOUT_MS as v,SCANNER_URL as y,SESSION_ID as b,config as x,deriveAccessControlUrl as S,deriveLogIngestUrl as C}from"./env-_7CCeXgw.js";export{x as config};
@@ -1,2 +1,2 @@
1
- import{randomUUID as e}from"crypto";import{join as t}from"node:path";import n from"env-var";import{homedir as r}from"node:os";import"dotenv/config";const i={APP_VERSION:`1.0.66`},a=n.get,o=i.APP_VERSION,s=e=>{let t={};if(e){let n=e.split(`,`);for(let e of n){let[n,...r]=e.split(`:`);n&&r.length>0&&(t[n.trim()]=r.join(`:`).trim())}}return t},c=e=>{try{let t=new URL(e),n=t.pathname.split(`/`).filter(Boolean)[0]===`ingest`?`/ingest`:``;return`${t.protocol}//${t.host}${n}/endpoint-logs`}catch{return null}},l=/\/guard\/evaluate\/v1(\/?)$/,u=e=>{try{let t=new URL(e),n=t.pathname.replace(l,`/access-control/authorize$1`);return n===t.pathname?(console.warn(`[mcp-gateway] Warning: SCANNER_URL does not contain expected path "/guard/evaluate/v1". Access control URL derivation skipped. Current path: "${t.pathname}". Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`),null):(t.pathname=n,t.toString())}catch(e){return console.warn(`[mcp-gateway] Warning: Failed to parse SCANNER_URL as valid URL: ${e instanceof Error?e.message:String(e)}. Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`),null}},d=e(),f=a(`MCP_GATEWAY_DEBUG`).default(`false`).asBool(),p=a(`MCP_GATEWAY_SCANNER_URL`).default(``).asString()||null,m=a(`MCP_GATEWAY_SCANNER_API_KEY`).default(``).asString()||void 0,h=a(`MCP_GATEWAY_MIRROR_URL`).default(``).asString()||null,g=(()=>{let e=a(`MCP_GATEWAY_SCANNER_HEADERS`).required(!1).asString();return e?s(e):{}})(),_=a(`MCP_GATEWAY_SCANNER_TIMEOUT_MS`).default(`20000`).asIntPositive(),v=a(`MCP_GATEWAY_SCANNER_FAIL_OPEN`).default(`true`).asBool(),y=a(`MCP_GATEWAY_COMMAND`).default(`mcp-gateway`).asString(),b=a(`CLIENT_APP_NAME`).default(``).asString(),x=a(`MCP_GATEWAY_LOG_DIR`).default(t(r(),`.onyx`,`mcp-gateway`,`logs`)).asString(),S=a(`MCP_GATEWAY_OAUTH_DIR`).default(t(r(),`.onyx`,`mcp-gateway`,`oauth`)).asString(),C=(()=>a(`MCP_GATEWAY_ACCESS_CONTROL_URL`).default(``).asString()||(p?u(p):null))(),w=(()=>{let e=a(`MCP_GATEWAY_ACCESS_CONTROL_HEADERS`).required(!1).asString();return e?s(e):{}})(),T=a(`MCP_GATEWAY_ACCESS_CONTROL_TIMEOUT_MS`).default(`3000`).asIntPositive(),E=a(`MCP_GATEWAY_OAUTH_PROVIDERS_URL`).default(``).asString()||null,D=a(`MCP_GATEWAY_OAUTH_PROVIDERS_TIMEOUT_MS`).default(`5000`).asIntPositive(),O=a(`MCP_GATEWAY_LOG_INGEST_ENABLED`).default(`true`).asBool(),k=a(`MCP_GATEWAY_LOG_INGEST_TIMEOUT_MS`).default(`5000`).asIntPositive(),A=(()=>a(`MCP_GATEWAY_LOG_INGEST_URL`).default(``).asString()||(h?c(h):p?c(p):null))(),j={accessControl:{enabled:!!(C&&m),headers:w,timeoutMs:T,url:C},appVersion:o,clientAppName:b,debug:f,logDir:x,logIngest:{apiKey:m,enabled:O&&!!(A&&m),timeoutMs:k,url:A},oauthDir:S,oauthProviders:{apiKey:m,enabled:!!(E&&m),timeoutMs:D,url:E},proxyCommand:y,scanner:{apiKey:m,enabled:!!p,failOpen:v,headers:g,timeoutMs:_,url:p}};export{w as ACCESS_CONTROL_HEADERS,T as ACCESS_CONTROL_TIMEOUT_MS,C as ACCESS_CONTROL_URL,o as APP_VERSION,b as CLIENT_APP_NAME,f as DEBUG_MODE,x as LOG_DIR,O as LOG_INGEST_ENABLED,k as LOG_INGEST_TIMEOUT_MS,A as LOG_INGEST_URL,h as MIRROR_URL,S as OAUTH_DIR,D as OAUTH_PROVIDERS_TIMEOUT_MS,E as OAUTH_PROVIDERS_URL,y as PROXY_COMMAND,m as SCANNER_API_KEY,v as SCANNER_FAIL_OPEN,g as SCANNER_HEADERS,_ as SCANNER_TIMEOUT_MS,p as SCANNER_URL,d as SESSION_ID,j as config,u as deriveAccessControlUrl,c as deriveLogIngestUrl};
2
- //# sourceMappingURL=env-BU-k04bk.js.map
1
+ import{randomUUID as e}from"crypto";import{join as t}from"node:path";import n from"env-var";import{homedir as r}from"node:os";import"dotenv/config";const i={APP_VERSION:`1.0.67`},a=n.get,o=i.APP_VERSION,s=e=>{let t={};if(e){let n=e.split(`,`);for(let e of n){let[n,...r]=e.split(`:`);n&&r.length>0&&(t[n.trim()]=r.join(`:`).trim())}}return t},c=e=>{try{let t=new URL(e),n=t.pathname.split(`/`).filter(Boolean)[0]===`ingest`?`/ingest`:``;return`${t.protocol}//${t.host}${n}/endpoint-logs`}catch{return null}},l=/\/guard\/evaluate\/v1(\/?)$/,u=e=>{try{let t=new URL(e),n=t.pathname.replace(l,`/access-control/authorize$1`);return n===t.pathname?(console.warn(`[mcp-gateway] Warning: SCANNER_URL does not contain expected path "/guard/evaluate/v1". Access control URL derivation skipped. Current path: "${t.pathname}". Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`),null):(t.pathname=n,t.toString())}catch(e){return console.warn(`[mcp-gateway] Warning: Failed to parse SCANNER_URL as valid URL: ${e instanceof Error?e.message:String(e)}. Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`),null}},d=e(),f=a(`MCP_GATEWAY_DEBUG`).default(`false`).asBool(),p=a(`MCP_GATEWAY_SCANNER_URL`).default(``).asString()||null,m=a(`MCP_GATEWAY_SCANNER_API_KEY`).default(``).asString()||void 0,h=a(`MCP_GATEWAY_MIRROR_URL`).default(``).asString()||null,g=(()=>{let e=a(`MCP_GATEWAY_SCANNER_HEADERS`).required(!1).asString();return e?s(e):{}})(),_=a(`MCP_GATEWAY_SCANNER_TIMEOUT_MS`).default(`20000`).asIntPositive(),v=a(`MCP_GATEWAY_SCANNER_FAIL_OPEN`).default(`true`).asBool(),y=a(`MCP_GATEWAY_COMMAND`).default(`mcp-gateway`).asString(),b=a(`CLIENT_APP_NAME`).default(``).asString(),x=a(`MCP_GATEWAY_LOG_DIR`).default(t(r(),`.onyx`,`mcp-gateway`,`logs`)).asString(),S=a(`MCP_GATEWAY_OAUTH_DIR`).default(t(r(),`.onyx`,`mcp-gateway`,`oauth`)).asString(),C=(()=>a(`MCP_GATEWAY_ACCESS_CONTROL_URL`).default(``).asString()||(p?u(p):null))(),w=(()=>{let e=a(`MCP_GATEWAY_ACCESS_CONTROL_HEADERS`).required(!1).asString();return e?s(e):{}})(),T=a(`MCP_GATEWAY_ACCESS_CONTROL_TIMEOUT_MS`).default(`3000`).asIntPositive(),E=a(`MCP_GATEWAY_OAUTH_PROVIDERS_URL`).default(``).asString()||null,D=a(`MCP_GATEWAY_OAUTH_PROVIDERS_TIMEOUT_MS`).default(`5000`).asIntPositive(),O=a(`MCP_GATEWAY_LOG_INGEST_ENABLED`).default(`true`).asBool(),k=a(`MCP_GATEWAY_LOG_INGEST_TIMEOUT_MS`).default(`5000`).asIntPositive(),A=(()=>a(`MCP_GATEWAY_LOG_INGEST_URL`).default(``).asString()||(h?c(h):p?c(p):null))(),j={accessControl:{enabled:!!(C&&m),headers:w,timeoutMs:T,url:C},appVersion:o,clientAppName:b,debug:f,logDir:x,logIngest:{apiKey:m,enabled:O&&!!(A&&m),timeoutMs:k,url:A},oauthDir:S,oauthProviders:{apiKey:m,enabled:!!(E&&m),timeoutMs:D,url:E},proxyCommand:y,scanner:{apiKey:m,enabled:!!p,failOpen:v,headers:g,timeoutMs:_,url:p}};export{w as ACCESS_CONTROL_HEADERS,T as ACCESS_CONTROL_TIMEOUT_MS,C as ACCESS_CONTROL_URL,o as APP_VERSION,b as CLIENT_APP_NAME,f as DEBUG_MODE,x as LOG_DIR,O as LOG_INGEST_ENABLED,k as LOG_INGEST_TIMEOUT_MS,A as LOG_INGEST_URL,h as MIRROR_URL,S as OAUTH_DIR,D as OAUTH_PROVIDERS_TIMEOUT_MS,E as OAUTH_PROVIDERS_URL,y as PROXY_COMMAND,m as SCANNER_API_KEY,v as SCANNER_FAIL_OPEN,g as SCANNER_HEADERS,_ as SCANNER_TIMEOUT_MS,p as SCANNER_URL,d as SESSION_ID,j as config,u as deriveAccessControlUrl,c as deriveLogIngestUrl};
2
+ //# sourceMappingURL=env-_7CCeXgw.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"env-BU-k04bk.js","names":["BUILD_TIME_CONFIG: BuildTimeConfig","headers: Record<string, string>"],"sources":["../src/config/config.generated.ts","../src/config/env.ts"],"sourcesContent":["// THIS FILE IS AUTO-GENERATED - DO NOT EDIT MANUALLY\n// Generated at build time from package.json\n\nimport type { BuildTimeConfig } from \"./config.js\";\n\nexport const BUILD_TIME_CONFIG: BuildTimeConfig = {\n \"APP_VERSION\": \"1.0.66\"\n};\n","import { randomUUID } from \"crypto\";\nimport envVar from \"env-var\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport \"dotenv/config\";\n\nconst env = envVar.get;\n\nimport { BUILD_TIME_CONFIG } from \"./config.generated.js\";\n\nexport const APP_VERSION = BUILD_TIME_CONFIG.APP_VERSION;\n\n// Helper function to parse headers from environment variable\nconst parseHeaders = (headerString: string): Record<string, string> => {\n const headers: Record<string, string> = {};\n if (headerString) {\n const headerPairs = headerString.split(\",\");\n for (const pair of headerPairs) {\n const [key, ...valueParts] = pair.split(\":\");\n if (key && valueParts.length > 0) {\n headers[key.trim()] = valueParts.join(\":\").trim();\n }\n }\n }\n return headers;\n};\n\n// Helper function to derive log ingest URL from scanner URL\n// Extracts scheme and host, appends /endpoint-logs path\n// Preserves /ingest prefix if present (needed for local setups)\n// Exported for testing\nexport const deriveLogIngestUrl = (scannerUrl: string): null | string => {\n try {\n const url = new URL(scannerUrl);\n // Check if first path segment is /ingest - preserve it for local setups\n const pathParts = url.pathname.split(\"/\").filter(Boolean);\n const basePath = pathParts[0] === \"ingest\" ? \"/ingest\" : \"\";\n return `${url.protocol}//${url.host}${basePath}/endpoint-logs`;\n } catch {\n return null;\n }\n};\n\n// Helper function to derive access control URL from scanner URL.\n//\n// SCANNER_URL and ACCESS_CONTROL_URL share the same host in production\n// (https://ai-guard.<tenant>/...), so when ACCESS_CONTROL_URL isn't set\n// explicitly we can swap the scanner path suffix for /access-control/authorize.\n//\n// Uses an anchored regex so a SCANNER_URL whose path is /guard/evaluate/v1-extra\n// or /guard/evaluate/v10 is treated as a non-match (returns null) rather than\n// producing a malformed URL.\n//\n// Note: this same-host assumption does NOT hold for the OAuth providers\n// endpoint, which lives on a different host (api.<tenant>) than the scanner.\n// MCP_GATEWAY_OAUTH_PROVIDERS_URL must be set explicitly — it is wired\n// through CI distribute-scanner.yaml and the install-script ONYX_ENV_VARS\n// pipeline, so it always arrives as a concrete URL in production.\n//\n// Exported for testing.\nconst accessControlPathRegex = /\\/guard\\/evaluate\\/v1(\\/?)$/;\n\nexport const deriveAccessControlUrl = (scannerUrl: string): null | string => {\n try {\n const url = new URL(scannerUrl);\n const expectedPath = \"/guard/evaluate/v1\";\n const replaced = url.pathname.replace(\n accessControlPathRegex,\n \"/access-control/authorize$1\"\n );\n\n if (replaced === url.pathname) {\n // Warn about non-standard format (can't use logger due to circular dependency)\n console.warn(\n `[mcp-gateway] Warning: SCANNER_URL does not contain expected path \"${expectedPath}\". ` +\n `Access control URL derivation skipped. Current path: \"${url.pathname}\". ` +\n `Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`\n );\n return null;\n }\n\n url.pathname = replaced;\n return url.toString();\n } catch (error) {\n // Invalid URL format\n console.warn(\n `[mcp-gateway] Warning: Failed to parse SCANNER_URL as valid URL: ${error instanceof Error ? error.message : String(error)}. ` +\n `Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`\n );\n return null;\n }\n};\n\nexport const SESSION_ID = randomUUID();\n\nexport const DEBUG_MODE = env(\"MCP_GATEWAY_DEBUG\").default(\"false\").asBool();\n\nexport const SCANNER_URL = env(\"MCP_GATEWAY_SCANNER_URL\").default(\"\").asString() || null;\n\nexport const SCANNER_API_KEY = env(\"MCP_GATEWAY_SCANNER_API_KEY\").default(\"\").asString() || undefined;\n\nexport const MIRROR_URL = env(\"MCP_GATEWAY_MIRROR_URL\").default(\"\").asString() || null;\n\nexport const SCANNER_HEADERS = (() => {\n const runtimeHeaders = env(\"MCP_GATEWAY_SCANNER_HEADERS\").required(false).asString();\n if (runtimeHeaders) {\n return parseHeaders(runtimeHeaders);\n }\n return {};\n})();\n\nexport const SCANNER_TIMEOUT_MS = env(\"MCP_GATEWAY_SCANNER_TIMEOUT_MS\").default(\"20000\").asIntPositive();\n\nexport const SCANNER_FAIL_OPEN = env(\"MCP_GATEWAY_SCANNER_FAIL_OPEN\").default(\"true\").asBool();\n\nexport const PROXY_COMMAND = env(\"MCP_GATEWAY_COMMAND\").default(\"mcp-gateway\").asString();\n\nexport const CLIENT_APP_NAME = env(\"CLIENT_APP_NAME\").default(\"\").asString();\n\nexport const LOG_DIR = env(\"MCP_GATEWAY_LOG_DIR\")\n .default(join(homedir(), \".onyx\", \"mcp-gateway\", \"logs\"))\n .asString();\n\nexport const OAUTH_DIR = env(\"MCP_GATEWAY_OAUTH_DIR\")\n .default(join(homedir(), \".onyx\", \"mcp-gateway\", \"oauth\"))\n .asString();\n\nexport const ACCESS_CONTROL_URL = (() => {\n const explicitUrl = env(\"MCP_GATEWAY_ACCESS_CONTROL_URL\").default(\"\").asString();\n if (explicitUrl) {\n return explicitUrl;\n }\n // If not explicitly set, derive from scanner URL\n if (SCANNER_URL) {\n return deriveAccessControlUrl(SCANNER_URL);\n }\n return null;\n})();\n\nexport const ACCESS_CONTROL_HEADERS = (() => {\n const runtimeHeaders = env(\"MCP_GATEWAY_ACCESS_CONTROL_HEADERS\").required(false).asString();\n if (runtimeHeaders) {\n return parseHeaders(runtimeHeaders);\n }\n return {};\n})();\n\nexport const ACCESS_CONTROL_TIMEOUT_MS = env(\"MCP_GATEWAY_ACCESS_CONTROL_TIMEOUT_MS\").default(\"3000\").asIntPositive();\n\n// OAuth providers configuration (fetched from web extension service at startup).\n//\n// Set explicitly per-tenant via MCP_GATEWAY_OAUTH_PROVIDERS_URL or the\n// --oauth-providers-url CLI flag. Unlike SCANNER_URL/ACCESS_CONTROL_URL, the\n// OAuth providers endpoint lives on a different host (api.<tenant>) than the\n// scanner (ai-guard.<tenant>) — so we cannot derive it from SCANNER_URL and\n// must rely on the install pipeline to inject the concrete URL.\nexport const OAUTH_PROVIDERS_URL =\n env(\"MCP_GATEWAY_OAUTH_PROVIDERS_URL\").default(\"\").asString() || null;\n\nexport const OAUTH_PROVIDERS_TIMEOUT_MS = env(\"MCP_GATEWAY_OAUTH_PROVIDERS_TIMEOUT_MS\").default(\"5000\").asIntPositive();\n\n// Log ingest configuration (for Groundcover logging)\nexport const LOG_INGEST_ENABLED = env(\"MCP_GATEWAY_LOG_INGEST_ENABLED\").default(\"true\").asBool();\n\nexport const LOG_INGEST_TIMEOUT_MS = env(\"MCP_GATEWAY_LOG_INGEST_TIMEOUT_MS\").default(\"5000\").asIntPositive();\n\nexport const LOG_INGEST_URL = (() => {\n const explicitUrl = env(\"MCP_GATEWAY_LOG_INGEST_URL\").default(\"\").asString();\n if (explicitUrl) {\n return explicitUrl;\n }\n // Derive from mirror URL (on ingest.* host) since SCANNER_URL points to\n // ai-guard.* which doesn't have an /endpoint-logs route\n if (MIRROR_URL) {\n return deriveLogIngestUrl(MIRROR_URL);\n }\n if (SCANNER_URL) {\n return deriveLogIngestUrl(SCANNER_URL);\n }\n return null;\n})();\n\nexport const config = {\n accessControl: {\n enabled: Boolean(ACCESS_CONTROL_URL && SCANNER_API_KEY),\n headers: ACCESS_CONTROL_HEADERS,\n timeoutMs: ACCESS_CONTROL_TIMEOUT_MS,\n url: ACCESS_CONTROL_URL,\n },\n appVersion: APP_VERSION,\n clientAppName: CLIENT_APP_NAME,\n debug: DEBUG_MODE,\n logDir: LOG_DIR,\n logIngest: {\n apiKey: SCANNER_API_KEY,\n enabled: LOG_INGEST_ENABLED && Boolean(LOG_INGEST_URL && SCANNER_API_KEY),\n timeoutMs: LOG_INGEST_TIMEOUT_MS,\n url: LOG_INGEST_URL,\n },\n oauthDir: OAUTH_DIR,\n oauthProviders: {\n apiKey: SCANNER_API_KEY,\n enabled: Boolean(OAUTH_PROVIDERS_URL && SCANNER_API_KEY),\n timeoutMs: OAUTH_PROVIDERS_TIMEOUT_MS,\n url: OAUTH_PROVIDERS_URL,\n },\n proxyCommand: PROXY_COMMAND,\n scanner: {\n apiKey: SCANNER_API_KEY,\n enabled: Boolean(SCANNER_URL),\n failOpen: SCANNER_FAIL_OPEN,\n headers: SCANNER_HEADERS,\n timeoutMs: SCANNER_TIMEOUT_MS,\n url: SCANNER_URL,\n },\n} as const;\n\n// Note: Don't use the logger here to avoid circular dependency issues\n// The logger hasn't been initialized yet when this config file is imported\n// Configuration is logged to file by the logger once initialized\n"],"mappings":"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"}
1
+ {"version":3,"file":"env-_7CCeXgw.js","names":["BUILD_TIME_CONFIG: BuildTimeConfig","headers: Record<string, string>"],"sources":["../src/config/config.generated.ts","../src/config/env.ts"],"sourcesContent":["// THIS FILE IS AUTO-GENERATED - DO NOT EDIT MANUALLY\n// Generated at build time from package.json\n\nimport type { BuildTimeConfig } from \"./config.js\";\n\nexport const BUILD_TIME_CONFIG: BuildTimeConfig = {\n \"APP_VERSION\": \"1.0.67\"\n};\n","import { randomUUID } from \"crypto\";\nimport envVar from \"env-var\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport \"dotenv/config\";\n\nconst env = envVar.get;\n\nimport { BUILD_TIME_CONFIG } from \"./config.generated.js\";\n\nexport const APP_VERSION = BUILD_TIME_CONFIG.APP_VERSION;\n\n// Helper function to parse headers from environment variable\nconst parseHeaders = (headerString: string): Record<string, string> => {\n const headers: Record<string, string> = {};\n if (headerString) {\n const headerPairs = headerString.split(\",\");\n for (const pair of headerPairs) {\n const [key, ...valueParts] = pair.split(\":\");\n if (key && valueParts.length > 0) {\n headers[key.trim()] = valueParts.join(\":\").trim();\n }\n }\n }\n return headers;\n};\n\n// Helper function to derive log ingest URL from scanner URL\n// Extracts scheme and host, appends /endpoint-logs path\n// Preserves /ingest prefix if present (needed for local setups)\n// Exported for testing\nexport const deriveLogIngestUrl = (scannerUrl: string): null | string => {\n try {\n const url = new URL(scannerUrl);\n // Check if first path segment is /ingest - preserve it for local setups\n const pathParts = url.pathname.split(\"/\").filter(Boolean);\n const basePath = pathParts[0] === \"ingest\" ? \"/ingest\" : \"\";\n return `${url.protocol}//${url.host}${basePath}/endpoint-logs`;\n } catch {\n return null;\n }\n};\n\n// Helper function to derive access control URL from scanner URL.\n//\n// SCANNER_URL and ACCESS_CONTROL_URL share the same host in production\n// (https://ai-guard.<tenant>/...), so when ACCESS_CONTROL_URL isn't set\n// explicitly we can swap the scanner path suffix for /access-control/authorize.\n//\n// Uses an anchored regex so a SCANNER_URL whose path is /guard/evaluate/v1-extra\n// or /guard/evaluate/v10 is treated as a non-match (returns null) rather than\n// producing a malformed URL.\n//\n// Note: this same-host assumption does NOT hold for the OAuth providers\n// endpoint, which lives on a different host (api.<tenant>) than the scanner.\n// MCP_GATEWAY_OAUTH_PROVIDERS_URL must be set explicitly — it is wired\n// through CI distribute-scanner.yaml and the install-script ONYX_ENV_VARS\n// pipeline, so it always arrives as a concrete URL in production.\n//\n// Exported for testing.\nconst accessControlPathRegex = /\\/guard\\/evaluate\\/v1(\\/?)$/;\n\nexport const deriveAccessControlUrl = (scannerUrl: string): null | string => {\n try {\n const url = new URL(scannerUrl);\n const expectedPath = \"/guard/evaluate/v1\";\n const replaced = url.pathname.replace(\n accessControlPathRegex,\n \"/access-control/authorize$1\"\n );\n\n if (replaced === url.pathname) {\n // Warn about non-standard format (can't use logger due to circular dependency)\n console.warn(\n `[mcp-gateway] Warning: SCANNER_URL does not contain expected path \"${expectedPath}\". ` +\n `Access control URL derivation skipped. Current path: \"${url.pathname}\". ` +\n `Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`\n );\n return null;\n }\n\n url.pathname = replaced;\n return url.toString();\n } catch (error) {\n // Invalid URL format\n console.warn(\n `[mcp-gateway] Warning: Failed to parse SCANNER_URL as valid URL: ${error instanceof Error ? error.message : String(error)}. ` +\n `Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`\n );\n return null;\n }\n};\n\nexport const SESSION_ID = randomUUID();\n\nexport const DEBUG_MODE = env(\"MCP_GATEWAY_DEBUG\").default(\"false\").asBool();\n\nexport const SCANNER_URL = env(\"MCP_GATEWAY_SCANNER_URL\").default(\"\").asString() || null;\n\nexport const SCANNER_API_KEY = env(\"MCP_GATEWAY_SCANNER_API_KEY\").default(\"\").asString() || undefined;\n\nexport const MIRROR_URL = env(\"MCP_GATEWAY_MIRROR_URL\").default(\"\").asString() || null;\n\nexport const SCANNER_HEADERS = (() => {\n const runtimeHeaders = env(\"MCP_GATEWAY_SCANNER_HEADERS\").required(false).asString();\n if (runtimeHeaders) {\n return parseHeaders(runtimeHeaders);\n }\n return {};\n})();\n\nexport const SCANNER_TIMEOUT_MS = env(\"MCP_GATEWAY_SCANNER_TIMEOUT_MS\").default(\"20000\").asIntPositive();\n\nexport const SCANNER_FAIL_OPEN = env(\"MCP_GATEWAY_SCANNER_FAIL_OPEN\").default(\"true\").asBool();\n\nexport const PROXY_COMMAND = env(\"MCP_GATEWAY_COMMAND\").default(\"mcp-gateway\").asString();\n\nexport const CLIENT_APP_NAME = env(\"CLIENT_APP_NAME\").default(\"\").asString();\n\nexport const LOG_DIR = env(\"MCP_GATEWAY_LOG_DIR\")\n .default(join(homedir(), \".onyx\", \"mcp-gateway\", \"logs\"))\n .asString();\n\nexport const OAUTH_DIR = env(\"MCP_GATEWAY_OAUTH_DIR\")\n .default(join(homedir(), \".onyx\", \"mcp-gateway\", \"oauth\"))\n .asString();\n\nexport const ACCESS_CONTROL_URL = (() => {\n const explicitUrl = env(\"MCP_GATEWAY_ACCESS_CONTROL_URL\").default(\"\").asString();\n if (explicitUrl) {\n return explicitUrl;\n }\n // If not explicitly set, derive from scanner URL\n if (SCANNER_URL) {\n return deriveAccessControlUrl(SCANNER_URL);\n }\n return null;\n})();\n\nexport const ACCESS_CONTROL_HEADERS = (() => {\n const runtimeHeaders = env(\"MCP_GATEWAY_ACCESS_CONTROL_HEADERS\").required(false).asString();\n if (runtimeHeaders) {\n return parseHeaders(runtimeHeaders);\n }\n return {};\n})();\n\nexport const ACCESS_CONTROL_TIMEOUT_MS = env(\"MCP_GATEWAY_ACCESS_CONTROL_TIMEOUT_MS\").default(\"3000\").asIntPositive();\n\n// OAuth providers configuration (fetched from web extension service at startup).\n//\n// Set explicitly per-tenant via MCP_GATEWAY_OAUTH_PROVIDERS_URL or the\n// --oauth-providers-url CLI flag. Unlike SCANNER_URL/ACCESS_CONTROL_URL, the\n// OAuth providers endpoint lives on a different host (api.<tenant>) than the\n// scanner (ai-guard.<tenant>) — so we cannot derive it from SCANNER_URL and\n// must rely on the install pipeline to inject the concrete URL.\nexport const OAUTH_PROVIDERS_URL =\n env(\"MCP_GATEWAY_OAUTH_PROVIDERS_URL\").default(\"\").asString() || null;\n\nexport const OAUTH_PROVIDERS_TIMEOUT_MS = env(\"MCP_GATEWAY_OAUTH_PROVIDERS_TIMEOUT_MS\").default(\"5000\").asIntPositive();\n\n// Log ingest configuration (for Groundcover logging)\nexport const LOG_INGEST_ENABLED = env(\"MCP_GATEWAY_LOG_INGEST_ENABLED\").default(\"true\").asBool();\n\nexport const LOG_INGEST_TIMEOUT_MS = env(\"MCP_GATEWAY_LOG_INGEST_TIMEOUT_MS\").default(\"5000\").asIntPositive();\n\nexport const LOG_INGEST_URL = (() => {\n const explicitUrl = env(\"MCP_GATEWAY_LOG_INGEST_URL\").default(\"\").asString();\n if (explicitUrl) {\n return explicitUrl;\n }\n // Derive from mirror URL (on ingest.* host) since SCANNER_URL points to\n // ai-guard.* which doesn't have an /endpoint-logs route\n if (MIRROR_URL) {\n return deriveLogIngestUrl(MIRROR_URL);\n }\n if (SCANNER_URL) {\n return deriveLogIngestUrl(SCANNER_URL);\n }\n return null;\n})();\n\nexport const config = {\n accessControl: {\n enabled: Boolean(ACCESS_CONTROL_URL && SCANNER_API_KEY),\n headers: ACCESS_CONTROL_HEADERS,\n timeoutMs: ACCESS_CONTROL_TIMEOUT_MS,\n url: ACCESS_CONTROL_URL,\n },\n appVersion: APP_VERSION,\n clientAppName: CLIENT_APP_NAME,\n debug: DEBUG_MODE,\n logDir: LOG_DIR,\n logIngest: {\n apiKey: SCANNER_API_KEY,\n enabled: LOG_INGEST_ENABLED && Boolean(LOG_INGEST_URL && SCANNER_API_KEY),\n timeoutMs: LOG_INGEST_TIMEOUT_MS,\n url: LOG_INGEST_URL,\n },\n oauthDir: OAUTH_DIR,\n oauthProviders: {\n apiKey: SCANNER_API_KEY,\n enabled: Boolean(OAUTH_PROVIDERS_URL && SCANNER_API_KEY),\n timeoutMs: OAUTH_PROVIDERS_TIMEOUT_MS,\n url: OAUTH_PROVIDERS_URL,\n },\n proxyCommand: PROXY_COMMAND,\n scanner: {\n apiKey: SCANNER_API_KEY,\n enabled: Boolean(SCANNER_URL),\n failOpen: SCANNER_FAIL_OPEN,\n headers: SCANNER_HEADERS,\n timeoutMs: SCANNER_TIMEOUT_MS,\n url: SCANNER_URL,\n },\n} as const;\n\n// Note: Don't use the logger here to avoid circular dependency issues\n// The logger hasn't been initialized yet when this config file is imported\n// Configuration is logged to file by the logger once initialized\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{Client as e,InMemoryEventStore as t,Server as n,StdioServerTransport as r,proxyServer as i,startHTTPServer as a}from"./stdio-DLPm2NHB.js";import{SSEClientTransport as o,StreamableHTTPClientTransport as s,normalizeUrl as c}from"./normalizeUrl-fkFv5Mfb.js";import{config as l}from"./env-BU-k04bk.js";import"./logger-BwqGcO50.js";let u=function(e){return e.HTTPStream=`HTTPStream`,e.SSE=`SSE`,e}({});const d=async({initStdioServer:t,initStreamClient:a,serverType:d,transportOptions:f={},url:p})=>{let m=c(p),h;switch(d){case u.SSE:h=new o(new URL(m),f);break;default:h=new s(new URL(m),f)}let g=a?await a():new e({name:`mcp-gateway`,version:l.appVersion},{capabilities:{}});await g.connect(h);let _=g.getServerVersion(),v=g.getServerCapabilities(),y=t?await t():new n(_,{capabilities:v}),b=new r;return await y.connect(b),await i({authorizer:void 0,client:g,server:y,serverCapabilities:v}),y},f=(e,t)=>{let n=e.close.bind(e),r=e.onclose?.bind(e),i=e.onerror?.bind(e),a=e.onmessage?.bind(e),o=e.send.bind(e),s=e.start.bind(e);return e.close=async()=>(t({type:`close`}),n?.()),e.onclose=async()=>(t({type:`onclose`}),r?.()),e.onerror=async e=>(t({error:e,type:`onerror`}),i?.(e)),e.onmessage=async e=>(t({message:e,type:`onmessage`}),a?.(e)),e.send=async e=>(t({message:e,type:`send`}),o?.(e)),e.start=async()=>(t({type:`start`}),s?.()),e};export{t as InMemoryEventStore,u as ServerType,i as proxyServer,a as startHTTPServer,d as startStdioServer,f as tapTransport};
1
+ import{Client as e,InMemoryEventStore as t,Server as n,StdioServerTransport as r,proxyServer as i,startHTTPServer as a}from"./stdio-COjRVz1N.js";import{SSEClientTransport as o,StreamableHTTPClientTransport as s,normalizeUrl as c}from"./normalizeUrl-fkFv5Mfb.js";import{config as l}from"./env-_7CCeXgw.js";import"./logger-DN0aJNvI.js";let u=function(e){return e.HTTPStream=`HTTPStream`,e.SSE=`SSE`,e}({});const d=async({initStdioServer:t,initStreamClient:a,serverType:d,transportOptions:f={},url:p})=>{let m=c(p),h;switch(d){case u.SSE:h=new o(new URL(m),f);break;default:h=new s(new URL(m),f)}let g=a?await a():new e({name:`mcp-gateway`,version:l.appVersion},{capabilities:{}});await g.connect(h);let _=g.getServerVersion(),v=g.getServerCapabilities(),y=t?await t():new n(_,{capabilities:v}),b=new r;return await y.connect(b),await i({authorizer:void 0,client:g,server:y,serverCapabilities:v}),y},f=(e,t)=>{let n=e.close.bind(e),r=e.onclose?.bind(e),i=e.onerror?.bind(e),a=e.onmessage?.bind(e),o=e.send.bind(e),s=e.start.bind(e);return e.close=async()=>(t({type:`close`}),n?.()),e.onclose=async()=>(t({type:`onclose`}),r?.()),e.onerror=async e=>(t({error:e,type:`onerror`}),i?.(e)),e.onmessage=async e=>(t({message:e,type:`onmessage`}),a?.(e)),e.send=async e=>(t({message:e,type:`send`}),o?.(e)),e.start=async()=>(t({type:`start`}),s?.()),e};export{t as InMemoryEventStore,u as ServerType,i as proxyServer,a as startHTTPServer,d as startStdioServer,f as tapTransport};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
- import{__commonJSMin as e,__require as t,__toESM as n}from"./chunk-CrDKVgUD.js";import{config as r}from"./env-BU-k04bk.js";import{AsyncLocalStorage as i}from"node:async_hooks";import{randomUUID as a}from"node:crypto";import{chownSync as o,existsSync as s,mkdirSync as c}from"node:fs";import{join as l,sep as u}from"node:path";import d from"winston";import f from"winston-daily-rotate-file";import{arch as p,hostname as m,platform as h}from"node:os";import{chown as g}from"node:fs/promises";async function _(e){let t=b();if(!t)return;let n=y(e);if(!n){await g(e,t.uid,t.gid);return}for(let e of n)await g(e,t.uid,t.gid)}function v(e){let t=b();if(!t)return;let n=y(e);if(!n){o(e,t.uid,t.gid);return}for(let e of n)o(e,t.uid,t.gid)}function y(e){if(!e.startsWith(u))return;let t=e.split(u),n=t.indexOf(`.onyx`);if(n===-1)return;let r=[];for(let e=n;e<t.length;e++)r.push(t.slice(0,e+1).join(u));return r}function b(){if(typeof process.getuid!=`function`||process.getuid()!==0)return;let e=process.env.SUDO_UID,t=process.env.SUDO_GID;if(!e||!t)return;let n=parseInt(e,10),r=parseInt(t,10);if(!(isNaN(n)||isNaN(r)))return{gid:r,uid:n}}var x=e(((exports,n)=>{n.exports=t(`util`).deprecate})),ee=e(((exports,n)=>{n.exports=t(`stream`)})),te=e(((exports,t)=>{function n(e,t){var n=this,a=this._readableState&&this._readableState.destroyed,s=this._writableState&&this._writableState.destroyed;return a||s?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(o,this,e)):process.nextTick(o,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(e){!t&&e?n._writableState?n._writableState.errorEmitted?process.nextTick(i,n):(n._writableState.errorEmitted=!0,process.nextTick(r,n,e)):process.nextTick(r,n,e):t?(process.nextTick(i,n),t(e)):process.nextTick(i,n)}),this)}function r(e,t){o(e,t),i(e)}function i(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit(`close`)}function a(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function o(e,t){e.emit(`error`,t)}function s(e,t){var n=e._readableState,r=e._writableState;n&&n.autoDestroy||r&&r.autoDestroy?e.destroy(t):e.emit(`error`,t)}t.exports={destroy:n,undestroy:a,errorOrDestroy:s}})),S=e(((exports,t)=>{let n={};function r(e,t,r){r||=Error;function i(e,n,r){return typeof t==`string`?t:t(e,n,r)}class a extends r{constructor(e,t,n){super(i(e,t,n))}}a.prototype.name=r.name,a.prototype.code=e,n[e]=a}function i(e,t){if(Array.isArray(e)){let n=e.length;return e=e.map(e=>String(e)),n>2?`one of ${t} ${e.slice(0,n-1).join(`, `)}, or `+e[n-1]:n===2?`one of ${t} ${e[0]} or ${e[1]}`:`of ${t} ${e[0]}`}else return`of ${t} ${String(e)}`}function a(e,t,n){return e.substr(!n||n<0?0:+n,t.length)===t}function o(e,t,n){return(n===void 0||n>e.length)&&(n=e.length),e.substring(n-t.length,n)===t}function s(e,t,n){return typeof n!=`number`&&(n=0),n+t.length>e.length?!1:e.indexOf(t,n)!==-1}r(`ERR_INVALID_OPT_VALUE`,function(e,t){return`The value "`+t+`" is invalid for option "`+e+`"`},TypeError),r(`ERR_INVALID_ARG_TYPE`,function(e,t,n){let r;typeof t==`string`&&a(t,`not `)?(r=`must not be`,t=t.replace(/^not /,``)):r=`must be`;let c;if(o(e,` argument`))c=`The ${e} ${r} ${i(t,`type`)}`;else{let n=s(e,`.`)?`property`:`argument`;c=`The "${e}" ${n} ${r} ${i(t,`type`)}`}return c+=`. Received type ${typeof n}`,c},TypeError),r(`ERR_STREAM_PUSH_AFTER_EOF`,`stream.push() after EOF`),r(`ERR_METHOD_NOT_IMPLEMENTED`,function(e){return`The `+e+` method is not implemented`}),r(`ERR_STREAM_PREMATURE_CLOSE`,`Premature close`),r(`ERR_STREAM_DESTROYED`,function(e){return`Cannot call `+e+` after a stream was destroyed`}),r(`ERR_MULTIPLE_CALLBACK`,`Callback called multiple times`),r(`ERR_STREAM_CANNOT_PIPE`,`Cannot pipe, not readable`),r(`ERR_STREAM_WRITE_AFTER_END`,`write after end`),r(`ERR_STREAM_NULL_VALUES`,`May not write null values to stream`,TypeError),r(`ERR_UNKNOWN_ENCODING`,function(e){return`Unknown encoding: `+e},TypeError),r(`ERR_STREAM_UNSHIFT_AFTER_END_EVENT`,`stream.unshift() after end event`),t.exports.codes=n})),ne=e(((exports,t)=>{var n=S().codes.ERR_INVALID_OPT_VALUE;function r(e,t,n){return e.highWaterMark==null?t?e[n]:null:e.highWaterMark}function i(e,t,i,a){var o=r(t,a,i);if(o!=null){if(!(isFinite(o)&&Math.floor(o)===o)||o<0)throw new n(a?i:`highWaterMark`,o);return Math.floor(o)}return e.objectMode?16:16*1024}t.exports={getHighWaterMark:i}})),C=e(((exports,t)=>{typeof Object.create==`function`?t.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:t.exports=function(e,t){if(t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}}})),w=e(((exports,n)=>{try{var r=t(`util`);if(typeof r.inherits!=`function`)throw``;n.exports=r.inherits}catch{n.exports=C()}})),re=e(((exports,n)=>{function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?r(Object(n),!0).forEach(function(t){a(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function a(e,t,n){return t=l(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){if(!(e instanceof t))throw TypeError(`Cannot call a class as a function`)}function s(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,`value`in r&&(r.writable=!0),Object.defineProperty(e,l(r.key),r)}}function c(e,t,n){return t&&s(e.prototype,t),n&&s(e,n),Object.defineProperty(e,`prototype`,{writable:!1}),e}function l(e){var t=u(e,`string`);return typeof t==`symbol`?t:String(t)}function u(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var d=t(`buffer`),f=d.Buffer,p=t(`util`),m=p.inspect,h=m&&m.custom||`inspect`;function g(e,t,n){f.prototype.copy.call(e,t,n)}n.exports=function(){function e(){o(this,e),this.head=null,this.tail=null,this.length=0}return c(e,[{key:`push`,value:function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:`unshift`,value:function(e){var t={data:e,next:this.head};this.length===0&&(this.tail=t),this.head=t,++this.length}},{key:`shift`,value:function(){if(this.length!==0){var e=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,e}}},{key:`clear`,value:function(){this.head=this.tail=null,this.length=0}},{key:`join`,value:function(e){if(this.length===0)return``;for(var t=this.head,n=``+t.data;t=t.next;)n+=e+t.data;return n}},{key:`concat`,value:function(e){if(this.length===0)return f.alloc(0);for(var t=f.allocUnsafe(e>>>0),n=this.head,r=0;n;)g(n.data,t,r),r+=n.data.length,n=n.next;return t}},{key:`consume`,value:function(e,t){var n;return e<this.head.data.length?(n=this.head.data.slice(0,e),this.head.data=this.head.data.slice(e)):n=e===this.head.data.length?this.shift():t?this._getString(e):this._getBuffer(e),n}},{key:`first`,value:function(){return this.head.data}},{key:`_getString`,value:function(e){var t=this.head,n=1,r=t.data;for(e-=r.length;t=t.next;){var i=t.data,a=e>i.length?i.length:e;if(a===i.length?r+=i:r+=i.slice(0,e),e-=a,e===0){a===i.length?(++n,t.next?this.head=t.next:this.head=this.tail=null):(this.head=t,t.data=i.slice(a));break}++n}return this.length-=n,r}},{key:`_getBuffer`,value:function(e){var t=f.allocUnsafe(e),n=this.head,r=1;for(n.data.copy(t),e-=n.data.length;n=n.next;){var i=n.data,a=e>i.length?i.length:e;if(i.copy(t,t.length-e,0,a),e-=a,e===0){a===i.length?(++r,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=i.slice(a));break}++r}return this.length-=r,t}},{key:h,value:function(e,t){return m(this,i(i({},t),{},{depth:0,customInspect:!1}))}}]),e}()})),T=e(((exports,n)=>{
1
+ import{__commonJSMin as e,__require as t,__toESM as n}from"./chunk-CrDKVgUD.js";import{config as r}from"./env-_7CCeXgw.js";import{AsyncLocalStorage as i}from"node:async_hooks";import{randomUUID as a}from"node:crypto";import{chownSync as o,existsSync as s,mkdirSync as c}from"node:fs";import{join as l,sep as u}from"node:path";import d from"winston";import f from"winston-daily-rotate-file";import{arch as p,hostname as m,platform as h}from"node:os";import{chown as g}from"node:fs/promises";async function _(e){let t=b();if(!t)return;let n=y(e);if(!n){await g(e,t.uid,t.gid);return}for(let e of n)await g(e,t.uid,t.gid)}function v(e){let t=b();if(!t)return;let n=y(e);if(!n){o(e,t.uid,t.gid);return}for(let e of n)o(e,t.uid,t.gid)}function y(e){if(!e.startsWith(u))return;let t=e.split(u),n=t.indexOf(`.onyx`);if(n===-1)return;let r=[];for(let e=n;e<t.length;e++)r.push(t.slice(0,e+1).join(u));return r}function b(){if(typeof process.getuid!=`function`||process.getuid()!==0)return;let e=process.env.SUDO_UID,t=process.env.SUDO_GID;if(!e||!t)return;let n=parseInt(e,10),r=parseInt(t,10);if(!(isNaN(n)||isNaN(r)))return{gid:r,uid:n}}var x=e(((exports,n)=>{n.exports=t(`util`).deprecate})),ee=e(((exports,n)=>{n.exports=t(`stream`)})),te=e(((exports,t)=>{function n(e,t){var n=this,a=this._readableState&&this._readableState.destroyed,s=this._writableState&&this._writableState.destroyed;return a||s?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(o,this,e)):process.nextTick(o,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(e){!t&&e?n._writableState?n._writableState.errorEmitted?process.nextTick(i,n):(n._writableState.errorEmitted=!0,process.nextTick(r,n,e)):process.nextTick(r,n,e):t?(process.nextTick(i,n),t(e)):process.nextTick(i,n)}),this)}function r(e,t){o(e,t),i(e)}function i(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit(`close`)}function a(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function o(e,t){e.emit(`error`,t)}function s(e,t){var n=e._readableState,r=e._writableState;n&&n.autoDestroy||r&&r.autoDestroy?e.destroy(t):e.emit(`error`,t)}t.exports={destroy:n,undestroy:a,errorOrDestroy:s}})),S=e(((exports,t)=>{let n={};function r(e,t,r){r||=Error;function i(e,n,r){return typeof t==`string`?t:t(e,n,r)}class a extends r{constructor(e,t,n){super(i(e,t,n))}}a.prototype.name=r.name,a.prototype.code=e,n[e]=a}function i(e,t){if(Array.isArray(e)){let n=e.length;return e=e.map(e=>String(e)),n>2?`one of ${t} ${e.slice(0,n-1).join(`, `)}, or `+e[n-1]:n===2?`one of ${t} ${e[0]} or ${e[1]}`:`of ${t} ${e[0]}`}else return`of ${t} ${String(e)}`}function a(e,t,n){return e.substr(!n||n<0?0:+n,t.length)===t}function o(e,t,n){return(n===void 0||n>e.length)&&(n=e.length),e.substring(n-t.length,n)===t}function s(e,t,n){return typeof n!=`number`&&(n=0),n+t.length>e.length?!1:e.indexOf(t,n)!==-1}r(`ERR_INVALID_OPT_VALUE`,function(e,t){return`The value "`+t+`" is invalid for option "`+e+`"`},TypeError),r(`ERR_INVALID_ARG_TYPE`,function(e,t,n){let r;typeof t==`string`&&a(t,`not `)?(r=`must not be`,t=t.replace(/^not /,``)):r=`must be`;let c;if(o(e,` argument`))c=`The ${e} ${r} ${i(t,`type`)}`;else{let n=s(e,`.`)?`property`:`argument`;c=`The "${e}" ${n} ${r} ${i(t,`type`)}`}return c+=`. Received type ${typeof n}`,c},TypeError),r(`ERR_STREAM_PUSH_AFTER_EOF`,`stream.push() after EOF`),r(`ERR_METHOD_NOT_IMPLEMENTED`,function(e){return`The `+e+` method is not implemented`}),r(`ERR_STREAM_PREMATURE_CLOSE`,`Premature close`),r(`ERR_STREAM_DESTROYED`,function(e){return`Cannot call `+e+` after a stream was destroyed`}),r(`ERR_MULTIPLE_CALLBACK`,`Callback called multiple times`),r(`ERR_STREAM_CANNOT_PIPE`,`Cannot pipe, not readable`),r(`ERR_STREAM_WRITE_AFTER_END`,`write after end`),r(`ERR_STREAM_NULL_VALUES`,`May not write null values to stream`,TypeError),r(`ERR_UNKNOWN_ENCODING`,function(e){return`Unknown encoding: `+e},TypeError),r(`ERR_STREAM_UNSHIFT_AFTER_END_EVENT`,`stream.unshift() after end event`),t.exports.codes=n})),ne=e(((exports,t)=>{var n=S().codes.ERR_INVALID_OPT_VALUE;function r(e,t,n){return e.highWaterMark==null?t?e[n]:null:e.highWaterMark}function i(e,t,i,a){var o=r(t,a,i);if(o!=null){if(!(isFinite(o)&&Math.floor(o)===o)||o<0)throw new n(a?i:`highWaterMark`,o);return Math.floor(o)}return e.objectMode?16:16*1024}t.exports={getHighWaterMark:i}})),C=e(((exports,t)=>{typeof Object.create==`function`?t.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:t.exports=function(e,t){if(t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}}})),w=e(((exports,n)=>{try{var r=t(`util`);if(typeof r.inherits!=`function`)throw``;n.exports=r.inherits}catch{n.exports=C()}})),re=e(((exports,n)=>{function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?r(Object(n),!0).forEach(function(t){a(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function a(e,t,n){return t=l(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){if(!(e instanceof t))throw TypeError(`Cannot call a class as a function`)}function s(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,`value`in r&&(r.writable=!0),Object.defineProperty(e,l(r.key),r)}}function c(e,t,n){return t&&s(e.prototype,t),n&&s(e,n),Object.defineProperty(e,`prototype`,{writable:!1}),e}function l(e){var t=u(e,`string`);return typeof t==`symbol`?t:String(t)}function u(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var d=t(`buffer`),f=d.Buffer,p=t(`util`),m=p.inspect,h=m&&m.custom||`inspect`;function g(e,t,n){f.prototype.copy.call(e,t,n)}n.exports=function(){function e(){o(this,e),this.head=null,this.tail=null,this.length=0}return c(e,[{key:`push`,value:function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:`unshift`,value:function(e){var t={data:e,next:this.head};this.length===0&&(this.tail=t),this.head=t,++this.length}},{key:`shift`,value:function(){if(this.length!==0){var e=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,e}}},{key:`clear`,value:function(){this.head=this.tail=null,this.length=0}},{key:`join`,value:function(e){if(this.length===0)return``;for(var t=this.head,n=``+t.data;t=t.next;)n+=e+t.data;return n}},{key:`concat`,value:function(e){if(this.length===0)return f.alloc(0);for(var t=f.allocUnsafe(e>>>0),n=this.head,r=0;n;)g(n.data,t,r),r+=n.data.length,n=n.next;return t}},{key:`consume`,value:function(e,t){var n;return e<this.head.data.length?(n=this.head.data.slice(0,e),this.head.data=this.head.data.slice(e)):n=e===this.head.data.length?this.shift():t?this._getString(e):this._getBuffer(e),n}},{key:`first`,value:function(){return this.head.data}},{key:`_getString`,value:function(e){var t=this.head,n=1,r=t.data;for(e-=r.length;t=t.next;){var i=t.data,a=e>i.length?i.length:e;if(a===i.length?r+=i:r+=i.slice(0,e),e-=a,e===0){a===i.length?(++n,t.next?this.head=t.next:this.head=this.tail=null):(this.head=t,t.data=i.slice(a));break}++n}return this.length-=n,r}},{key:`_getBuffer`,value:function(e){var t=f.allocUnsafe(e),n=this.head,r=1;for(n.data.copy(t),e-=n.data.length;n=n.next;){var i=n.data,a=e>i.length?i.length:e;if(i.copy(t,t.length-e,0,a),e-=a,e===0){a===i.length?(++r,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=i.slice(a));break}++r}return this.length-=r,t}},{key:h,value:function(e,t){return m(this,i(i({},t),{},{depth:0,customInspect:!1}))}}]),e}()})),T=e(((exports,n)=>{
2
2
  /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
3
3
  var r=t(`buffer`),i=r.Buffer;function a(e,t){for(var n in e)t[n]=e[n]}i.from&&i.alloc&&i.allocUnsafe&&i.allocUnsafeSlow?n.exports=r:(a(r,exports),exports.Buffer=o);function o(e,t,n){return i(e,t,n)}o.prototype=Object.create(i.prototype),a(i,o),o.from=function(e,t,n){if(typeof e==`number`)throw TypeError(`Argument must not be a number`);return i(e,t,n)},o.alloc=function(e,t,n){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);var r=i(e);return t===void 0?r.fill(0):typeof n==`string`?r.fill(t,n):r.fill(t),r},o.allocUnsafe=function(e){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);return i(e)},o.allocUnsafeSlow=function(e){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);return r.SlowBuffer(e)}})),ie=e((exports=>{var t=T().Buffer,n=t.isEncoding||function(e){switch(e=``+e,e&&e.toLowerCase()){case`hex`:case`utf8`:case`utf-8`:case`ascii`:case`binary`:case`base64`:case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:case`raw`:return!0;default:return!1}};function r(e){if(!e)return`utf8`;for(var t;;)switch(e){case`utf8`:case`utf-8`:return`utf8`;case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return`utf16le`;case`latin1`:case`binary`:return`latin1`;case`base64`:case`ascii`:case`hex`:return e;default:if(t)return;e=(``+e).toLowerCase(),t=!0}}function i(e){var i=r(e);if(typeof i!=`string`&&(t.isEncoding===n||!n(e)))throw Error(`Unknown encoding: `+e);return i||e}exports.StringDecoder=a;function a(e){this.encoding=i(e);var n;switch(this.encoding){case`utf16le`:this.text=f,this.end=p,n=4;break;case`utf8`:this.fillLast=l,n=4;break;case`base64`:this.text=m,this.end=h,n=3;break;default:this.write=g,this.end=_;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=t.allocUnsafe(n)}a.prototype.write=function(e){if(e.length===0)return``;var t,n;if(this.lastNeed){if(t=this.fillLast(e),t===void 0)return``;n=this.lastNeed,this.lastNeed=0}else n=0;return n<e.length?t?t+this.text(e,n):this.text(e,n):t||``},a.prototype.end=d,a.prototype.text=u,a.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length};function o(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function s(e,t,n){var r=t.length-1;if(r<n)return 0;var i=o(t[r]);return i>=0?(i>0&&(e.lastNeed=i-1),i):--r<n||i===-2?0:(i=o(t[r]),i>=0?(i>0&&(e.lastNeed=i-2),i):--r<n||i===-2?0:(i=o(t[r]),i>=0?(i>0&&(i===2?i=0:e.lastNeed=i-3),i):0))}function c(e,t,n){if((t[0]&192)!=128)return e.lastNeed=0,`�`;if(e.lastNeed>1&&t.length>1){if((t[1]&192)!=128)return e.lastNeed=1,`�`;if(e.lastNeed>2&&t.length>2&&(t[2]&192)!=128)return e.lastNeed=2,`�`}}function l(e){var t=this.lastTotal-this.lastNeed,n=c(this,e,t);if(n!==void 0)return n;if(this.lastNeed<=e.length)return e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length}function u(e,t){var n=s(this,e,t);if(!this.lastNeed)return e.toString(`utf8`,t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString(`utf8`,t,r)}function d(e){var t=e&&e.length?this.write(e):``;return this.lastNeed?t+`�`:t}function f(e,t){if((e.length-t)%2==0){var n=e.toString(`utf16le`,t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString(`utf16le`,t,e.length-1)}function p(e){var t=e&&e.length?this.write(e):``;if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString(`utf16le`,0,n)}return t}function m(e,t){var n=(e.length-t)%3;return n===0?e.toString(`base64`,t):(this.lastNeed=3-n,this.lastTotal=3,n===1?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString(`base64`,t,e.length-n))}function h(e){var t=e&&e.length?this.write(e):``;return this.lastNeed?t+this.lastChar.toString(`base64`,0,3-this.lastNeed):t}function g(e){return e.toString(this.encoding)}function _(e){return e&&e.length?this.write(e):``}})),E=e(((exports,t)=>{var n=S().codes.ERR_STREAM_PREMATURE_CLOSE;function r(e){var t=!1;return function(){if(!t){t=!0;var n=[...arguments];e.apply(this,n)}}}function i(){}function a(e){return e.setHeader&&typeof e.abort==`function`}function o(e,t,s){if(typeof t==`function`)return o(e,null,t);t||={},s=r(s||i);var c=t.readable||t.readable!==!1&&e.readable,l=t.writable||t.writable!==!1&&e.writable,u=function(){e.writable||f()},d=e._writableState&&e._writableState.finished,f=function(){l=!1,d=!0,c||s.call(e)},p=e._readableState&&e._readableState.endEmitted,m=function(){c=!1,p=!0,l||s.call(e)},h=function(t){s.call(e,t)},g=function(){var t;if(c&&!p)return(!e._readableState||!e._readableState.ended)&&(t=new n),s.call(e,t);if(l&&!d)return(!e._writableState||!e._writableState.ended)&&(t=new n),s.call(e,t)},_=function(){e.req.on(`finish`,f)};return a(e)?(e.on(`complete`,f),e.on(`abort`,g),e.req?_():e.on(`request`,_)):l&&!e._writableState&&(e.on(`end`,u),e.on(`close`,u)),e.on(`end`,m),e.on(`finish`,f),t.error!==!1&&e.on(`error`,h),e.on(`close`,g),function(){e.removeListener(`complete`,f),e.removeListener(`abort`,g),e.removeListener(`request`,_),e.req&&e.req.removeListener(`finish`,f),e.removeListener(`end`,u),e.removeListener(`close`,u),e.removeListener(`finish`,f),e.removeListener(`end`,m),e.removeListener(`error`,h),e.removeListener(`close`,g)}}t.exports=o})),D=e(((exports,t)=>{var n;function r(e,t,n){return t=i(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e){var t=a(e,`string`);return typeof t==`symbol`?t:String(t)}function a(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var o=E(),s=Symbol(`lastResolve`),c=Symbol(`lastReject`),l=Symbol(`error`),u=Symbol(`ended`),d=Symbol(`lastPromise`),f=Symbol(`handlePromise`),p=Symbol(`stream`);function m(e,t){return{value:e,done:t}}function h(e){var t=e[s];if(t!==null){var n=e[p].read();n!==null&&(e[d]=null,e[s]=null,e[c]=null,t(m(n,!1)))}}function g(e){process.nextTick(h,e)}function _(e,t){return function(n,r){e.then(function(){if(t[u]){n(m(void 0,!0));return}t[f](n,r)},r)}}var v=Object.getPrototypeOf(function(){}),y=Object.setPrototypeOf((n={get stream(){return this[p]},next:function(){var e=this,t=this[l];if(t!==null)return Promise.reject(t);if(this[u])return Promise.resolve(m(void 0,!0));if(this[p].destroyed)return new Promise(function(t,n){process.nextTick(function(){e[l]?n(e[l]):t(m(void 0,!0))})});var n=this[d],r;if(n)r=new Promise(_(n,this));else{var i=this[p].read();if(i!==null)return Promise.resolve(m(i,!1));r=new Promise(this[f])}return this[d]=r,r}},r(n,Symbol.asyncIterator,function(){return this}),r(n,`return`,function(){var e=this;return new Promise(function(t,n){e[p].destroy(null,function(e){if(e){n(e);return}t(m(void 0,!0))})})}),n),v);t.exports=function(e){var t,n=Object.create(y,(t={},r(t,p,{value:e,writable:!0}),r(t,s,{value:null,writable:!0}),r(t,c,{value:null,writable:!0}),r(t,l,{value:null,writable:!0}),r(t,u,{value:e._readableState.endEmitted,writable:!0}),r(t,f,{value:function(e,t){var r=n[p].read();r?(n[d]=null,n[s]=null,n[c]=null,e(m(r,!1))):(n[s]=e,n[c]=t)},writable:!0}),t));return n[d]=null,o(e,function(e){if(e&&e.code!==`ERR_STREAM_PREMATURE_CLOSE`){var t=n[c];t!==null&&(n[d]=null,n[s]=null,n[c]=null,t(e)),n[l]=e;return}var r=n[s];r!==null&&(n[d]=null,n[s]=null,n[c]=null,r(m(void 0,!0))),n[u]=!0}),e.on(`readable`,g.bind(null,n)),n}})),O=e(((exports,t)=>{function n(e,t,n,r,i,a,o){try{var s=e[a](o),c=s.value}catch(e){n(e);return}s.done?t(c):Promise.resolve(c).then(r,i)}function r(e){return function(){var t=this,r=arguments;return new Promise(function(i,a){var o=e.apply(t,r);function s(e){n(o,i,a,s,c,`next`,e)}function c(e){n(o,i,a,s,c,`throw`,e)}s(void 0)})}}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?i(Object(n),!0).forEach(function(t){o(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function o(e,t,n){return t=s(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e){var t=c(e,`string`);return typeof t==`symbol`?t:String(t)}function c(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var l=S().codes.ERR_INVALID_ARG_TYPE;function u(e,t,n){var i;if(t&&typeof t.next==`function`)i=t;else if(t&&t[Symbol.asyncIterator])i=t[Symbol.asyncIterator]();else if(t&&t[Symbol.iterator])i=t[Symbol.iterator]();else throw new l(`iterable`,[`Iterable`],t);var o=new e(a({objectMode:!0},n)),s=!1;o._read=function(){s||(s=!0,c())};function c(){return u.apply(this,arguments)}function u(){return u=r(function*(){try{var e=yield i.next(),t=e.value;e.done?o.push(null):o.push(yield t)?c():s=!1}catch(e){o.destroy(e)}}),u.apply(this,arguments)}return o}t.exports=u})),k=e(((exports,n)=>{n.exports=N;var r;N.ReadableState=M,t(`events`).EventEmitter;var i=function(e,t){return e.listeners(t).length},a=ee(),o=t(`buffer`).Buffer,s=(typeof global<`u`?global:typeof window<`u`?window:typeof self<`u`?self:{}).Uint8Array||function(){};function c(e){return o.from(e)}function l(e){return o.isBuffer(e)||e instanceof s}var u=t(`util`),d=u&&u.debuglog?u.debuglog(`stream`):function(){},f=re(),p=te(),m=ne(),h=m.getHighWaterMark,g=S().codes,_=g.ERR_INVALID_ARG_TYPE,v=g.ERR_STREAM_PUSH_AFTER_EOF,y=g.ERR_METHOD_NOT_IMPLEMENTED,b=g.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,x,C,T;w()(N,a);var E=p.errorOrDestroy,k=[`error`,`close`,`destroy`,`pause`,`resume`];function j(e,t,n){if(typeof e.prependListener==`function`)return e.prependListener(t,n);!e._events||!e._events[t]?e.on(t,n):Array.isArray(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]}function M(e,t,n){r||=A(),e||={},typeof n!=`boolean`&&(n=t instanceof r),this.objectMode=!!e.objectMode,n&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=h(this,e,`readableHighWaterMark`,n),this.buffer=new f,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||`utf8`,this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(x||=ie().StringDecoder,this.decoder=new x(e.encoding),this.encoding=e.encoding)}function N(e){if(r||=A(),!(this instanceof N))return new N(e);var t=this instanceof r;this._readableState=new M(e,this,t),this.readable=!0,e&&(typeof e.read==`function`&&(this._read=e.read),typeof e.destroy==`function`&&(this._destroy=e.destroy)),a.call(this)}Object.defineProperty(N.prototype,`destroyed`,{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){this._readableState&&(this._readableState.destroyed=e)}}),N.prototype.destroy=p.destroy,N.prototype._undestroy=p.undestroy,N.prototype._destroy=function(e,t){t(e)},N.prototype.push=function(e,t){var n=this._readableState,r;return n.objectMode?r=!0:typeof e==`string`&&(t||=n.defaultEncoding,t!==n.encoding&&(e=o.from(e,t),t=``),r=!0),P(this,e,t,!1,r)},N.prototype.unshift=function(e){return P(this,e,null,!0,!1)};function P(e,t,n,r,i){d(`readableAddChunk`,t);var a=e._readableState;if(t===null)a.reading=!1,B(e,a);else{var s;if(i||(s=I(a,t)),s)E(e,s);else if(a.objectMode||t&&t.length>0)if(typeof t!=`string`&&!a.objectMode&&Object.getPrototypeOf(t)!==o.prototype&&(t=c(t)),r)a.endEmitted?E(e,new b):F(e,a,t,!0);else if(a.ended)E(e,new v);else if(a.destroyed)return!1;else a.reading=!1,a.decoder&&!n?(t=a.decoder.write(t),a.objectMode||t.length!==0?F(e,a,t,!1):U(e,a)):F(e,a,t,!1);else r||(a.reading=!1,U(e,a))}return!a.ended&&(a.length<a.highWaterMark||a.length===0)}function F(e,t,n,r){t.flowing&&t.length===0&&!t.sync?(t.awaitDrain=0,e.emit(`data`,n)):(t.length+=t.objectMode?1:n.length,r?t.buffer.unshift(n):t.buffer.push(n),t.needReadable&&V(e)),U(e,t)}function I(e,t){var n;return!l(t)&&typeof t!=`string`&&t!==void 0&&!e.objectMode&&(n=new _(`chunk`,[`string`,`Buffer`,`Uint8Array`],t)),n}N.prototype.isPaused=function(){return this._readableState.flowing===!1},N.prototype.setEncoding=function(e){x||=ie().StringDecoder;var t=new x(e);this._readableState.decoder=t,this._readableState.encoding=this._readableState.decoder.encoding;for(var n=this._readableState.buffer.head,r=``;n!==null;)r+=t.write(n.data),n=n.next;return this._readableState.buffer.clear(),r!==``&&this._readableState.buffer.push(r),this._readableState.length=r.length,this};var L=1073741824;function R(e){return e>=L?e=L:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function z(e,t){return e<=0||t.length===0&&t.ended?0:t.objectMode?1:e===e?(e>t.highWaterMark&&(t.highWaterMark=R(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0)):t.flowing&&t.length?t.buffer.head.data.length:t.length}N.prototype.read=function(e){d(`read`,e),e=parseInt(e,10);var t=this._readableState,n=e;if(e!==0&&(t.emittedReadable=!1),e===0&&t.needReadable&&((t.highWaterMark===0?t.length>0:t.length>=t.highWaterMark)||t.ended))return d(`read: emitReadable`,t.length,t.ended),t.length===0&&t.ended?Y(this):V(this),null;if(e=z(e,t),e===0&&t.ended)return t.length===0&&Y(this),null;var r=t.needReadable;d(`need readable`,r),(t.length===0||t.length-e<t.highWaterMark)&&(r=!0,d(`length less than watermark`,r)),t.ended||t.reading?(r=!1,d(`reading or ended`,r)):r&&(d(`do read`),t.reading=!0,t.sync=!0,t.length===0&&(t.needReadable=!0),this._read(t.highWaterMark),t.sync=!1,t.reading||(e=z(n,t)));var i=e>0?J(e,t):null;return i===null?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),t.length===0&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&Y(this)),i!==null&&this.emit(`data`,i),i};function B(e,t){if(d(`onEofChunk`),!t.ended){if(t.decoder){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,t.sync?V(e):(t.needReadable=!1,t.emittedReadable||(t.emittedReadable=!0,H(e)))}}function V(e){var t=e._readableState;d(`emitReadable`,t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(d(`emitReadable`,t.flowing),t.emittedReadable=!0,process.nextTick(H,e))}function H(e){var t=e._readableState;d(`emitReadable_`,t.destroyed,t.length,t.ended),!t.destroyed&&(t.length||t.ended)&&(e.emit(`readable`),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,q(e)}function U(e,t){t.readingMore||(t.readingMore=!0,process.nextTick(W,e,t))}function W(e,t){for(;!t.reading&&!t.ended&&(t.length<t.highWaterMark||t.flowing&&t.length===0);){var n=t.length;if(d(`maybeReadMore read 0`),e.read(0),n===t.length)break}t.readingMore=!1}N.prototype._read=function(e){E(this,new y(`_read()`))},N.prototype.pipe=function(e,t){var n=this,r=this._readableState;switch(r.pipesCount){case 0:r.pipes=e;break;case 1:r.pipes=[r.pipes,e];break;default:r.pipes.push(e);break}r.pipesCount+=1,d(`pipe count=%d opts=%j`,r.pipesCount,t);var a=(!t||t.end!==!1)&&e!==process.stdout&&e!==process.stderr?s:g;r.endEmitted?process.nextTick(a):n.once(`end`,a),e.on(`unpipe`,o);function o(e,t){d(`onunpipe`),e===n&&t&&t.hasUnpiped===!1&&(t.hasUnpiped=!0,u())}function s(){d(`onend`),e.end()}var c=G(n);e.on(`drain`,c);var l=!1;function u(){d(`cleanup`),e.removeListener(`close`,m),e.removeListener(`finish`,h),e.removeListener(`drain`,c),e.removeListener(`error`,p),e.removeListener(`unpipe`,o),n.removeListener(`end`,s),n.removeListener(`end`,g),n.removeListener(`data`,f),l=!0,r.awaitDrain&&(!e._writableState||e._writableState.needDrain)&&c()}n.on(`data`,f);function f(t){d(`ondata`);var i=e.write(t);d(`dest.write`,i),i===!1&&((r.pipesCount===1&&r.pipes===e||r.pipesCount>1&&ce(r.pipes,e)!==-1)&&!l&&(d(`false write response, pause`,r.awaitDrain),r.awaitDrain++),n.pause())}function p(t){d(`onerror`,t),g(),e.removeListener(`error`,p),i(e,`error`)===0&&E(e,t)}j(e,`error`,p);function m(){e.removeListener(`finish`,h),g()}e.once(`close`,m);function h(){d(`onfinish`),e.removeListener(`close`,m),g()}e.once(`finish`,h);function g(){d(`unpipe`),n.unpipe(e)}return e.emit(`pipe`,n),r.flowing||(d(`pipe resume`),n.resume()),e};function G(e){return function(){var t=e._readableState;d(`pipeOnDrain`,t.awaitDrain),t.awaitDrain&&t.awaitDrain--,t.awaitDrain===0&&i(e,`data`)&&(t.flowing=!0,q(e))}}N.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(t.pipesCount===0)return this;if(t.pipesCount===1)return e&&e!==t.pipes?this:(e||=t.pipes,t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit(`unpipe`,this,n),this);if(!e){var r=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var a=0;a<i;a++)r[a].emit(`unpipe`,this,{hasUnpiped:!1});return this}var o=ce(t.pipes,e);return o===-1?this:(t.pipes.splice(o,1),--t.pipesCount,t.pipesCount===1&&(t.pipes=t.pipes[0]),e.emit(`unpipe`,this,n),this)},N.prototype.on=function(e,t){var n=a.prototype.on.call(this,e,t),r=this._readableState;return e===`data`?(r.readableListening=this.listenerCount(`readable`)>0,r.flowing!==!1&&this.resume()):e===`readable`&&!r.endEmitted&&!r.readableListening&&(r.readableListening=r.needReadable=!0,r.flowing=!1,r.emittedReadable=!1,d(`on readable`,r.length,r.reading),r.length?V(this):r.reading||process.nextTick(ae,this)),n},N.prototype.addListener=N.prototype.on,N.prototype.removeListener=function(e,t){var n=a.prototype.removeListener.call(this,e,t);return e===`readable`&&process.nextTick(K,this),n},N.prototype.removeAllListeners=function(e){var t=a.prototype.removeAllListeners.apply(this,arguments);return(e===`readable`||e===void 0)&&process.nextTick(K,this),t};function K(e){var t=e._readableState;t.readableListening=e.listenerCount(`readable`)>0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount(`data`)>0&&e.resume()}function ae(e){d(`readable nexttick read 0`),e.read(0)}N.prototype.resume=function(){var e=this._readableState;return e.flowing||(d(`resume`),e.flowing=!e.readableListening,oe(this,e)),e.paused=!1,this};function oe(e,t){t.resumeScheduled||(t.resumeScheduled=!0,process.nextTick(se,e,t))}function se(e,t){d(`resume`,t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit(`resume`),q(e),t.flowing&&!t.reading&&e.read(0)}N.prototype.pause=function(){return d(`call pause flowing=%j`,this._readableState.flowing),this._readableState.flowing!==!1&&(d(`pause`),this._readableState.flowing=!1,this.emit(`pause`)),this._readableState.paused=!0,this};function q(e){var t=e._readableState;for(d(`flow`,t.flowing);t.flowing&&e.read()!==null;);}N.prototype.wrap=function(e){var t=this,n=this._readableState,r=!1;for(var i in e.on(`end`,function(){if(d(`wrapped end`),n.decoder&&!n.ended){var e=n.decoder.end();e&&e.length&&t.push(e)}t.push(null)}),e.on(`data`,function(i){d(`wrapped data`),n.decoder&&(i=n.decoder.write(i)),!(n.objectMode&&i==null)&&(!n.objectMode&&(!i||!i.length)||t.push(i)||(r=!0,e.pause()))}),e)this[i]===void 0&&typeof e[i]==`function`&&(this[i]=function(t){return function(){return e[t].apply(e,arguments)}}(i));for(var a=0;a<k.length;a++)e.on(k[a],this.emit.bind(this,k[a]));return this._read=function(t){d(`wrapped _read`,t),r&&(r=!1,e.resume())},this},typeof Symbol==`function`&&(N.prototype[Symbol.asyncIterator]=function(){return C===void 0&&(C=D()),C(this)}),Object.defineProperty(N.prototype,`readableHighWaterMark`,{enumerable:!1,get:function(){return this._readableState.highWaterMark}}),Object.defineProperty(N.prototype,`readableBuffer`,{enumerable:!1,get:function(){return this._readableState&&this._readableState.buffer}}),Object.defineProperty(N.prototype,`readableFlowing`,{enumerable:!1,get:function(){return this._readableState.flowing},set:function(e){this._readableState&&(this._readableState.flowing=e)}}),N._fromList=J,Object.defineProperty(N.prototype,`readableLength`,{enumerable:!1,get:function(){return this._readableState.length}});function J(e,t){if(t.length===0)return null;var n;return t.objectMode?n=t.buffer.shift():!e||e>=t.length?(n=t.decoder?t.buffer.join(``):t.buffer.length===1?t.buffer.first():t.buffer.concat(t.length),t.buffer.clear()):n=t.buffer.consume(e,t.decoder),n}function Y(e){var t=e._readableState;d(`endReadable`,t.endEmitted),t.endEmitted||(t.ended=!0,process.nextTick(X,t,e))}function X(e,t){if(d(`endReadableNT`,e.endEmitted,e.length),!e.endEmitted&&e.length===0&&(e.endEmitted=!0,t.readable=!1,t.emit(`end`),e.autoDestroy)){var n=t._writableState;(!n||n.autoDestroy&&n.finished)&&t.destroy()}}typeof Symbol==`function`&&(N.from=function(e,t){return T===void 0&&(T=O()),T(N,e,t)});function ce(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1}})),A=e(((exports,t)=>{var n=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};t.exports=c;var r=k(),i=j();w()(c,r);for(var a=n(i.prototype),o=0;o<a.length;o++){var s=a[o];c.prototype[s]||(c.prototype[s]=i.prototype[s])}function c(e){if(!(this instanceof c))return new c(e);r.call(this,e),i.call(this,e),this.allowHalfOpen=!0,e&&(e.readable===!1&&(this.readable=!1),e.writable===!1&&(this.writable=!1),e.allowHalfOpen===!1&&(this.allowHalfOpen=!1,this.once(`end`,l)))}Object.defineProperty(c.prototype,`writableHighWaterMark`,{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),Object.defineProperty(c.prototype,`writableBuffer`,{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}}),Object.defineProperty(c.prototype,`writableLength`,{enumerable:!1,get:function(){return this._writableState.length}});function l(){this._writableState.ended||process.nextTick(u,this)}function u(e){e.end()}Object.defineProperty(c.prototype,`destroyed`,{enumerable:!1,get:function(){return this._readableState===void 0||this._writableState===void 0?!1:this._readableState.destroyed&&this._writableState.destroyed},set:function(e){this._readableState===void 0||this._writableState===void 0||(this._readableState.destroyed=e,this._writableState.destroyed=e)}})})),j=e(((exports,n)=>{n.exports=O;function r(e){var t=this;this.next=null,this.entry=null,this.finish=function(){K(t,e)}}var i;O.WritableState=E;var a={deprecate:x()},o=ee(),s=t(`buffer`).Buffer,c=(typeof global<`u`?global:typeof window<`u`?window:typeof self<`u`?self:{}).Uint8Array||function(){};function l(e){return s.from(e)}function u(e){return s.isBuffer(e)||e instanceof c}var d=te(),f=ne(),p=f.getHighWaterMark,m=S().codes,h=m.ERR_INVALID_ARG_TYPE,g=m.ERR_METHOD_NOT_IMPLEMENTED,_=m.ERR_MULTIPLE_CALLBACK,v=m.ERR_STREAM_CANNOT_PIPE,y=m.ERR_STREAM_DESTROYED,b=m.ERR_STREAM_NULL_VALUES,C=m.ERR_STREAM_WRITE_AFTER_END,re=m.ERR_UNKNOWN_ENCODING,T=d.errorOrDestroy;w()(O,o);function ie(){}function E(e,t,n){i||=A(),e||={},typeof n!=`boolean`&&(n=t instanceof i),this.objectMode=!!e.objectMode,n&&(this.objectMode=this.objectMode||!!e.writableObjectMode),this.highWaterMark=p(this,e,`writableHighWaterMark`,n),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1,this.decodeStrings=e.decodeStrings!==!1,this.defaultEncoding=e.defaultEncoding||`utf8`,this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){L(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new r(this)}E.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},(function(){try{Object.defineProperty(E.prototype,`buffer`,{get:a.deprecate(function(){return this.getBuffer()},`_writableState.buffer is deprecated. Use _writableState.getBuffer instead.`,`DEP0003`)})}catch{}})();var D;typeof Symbol==`function`&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]==`function`?(D=Function.prototype[Symbol.hasInstance],Object.defineProperty(O,Symbol.hasInstance,{value:function(e){return D.call(this,e)?!0:this===O?e&&e._writableState instanceof E:!1}})):D=function(e){return e instanceof this};function O(e){i||=A();var t=this instanceof i;if(!t&&!D.call(O,this))return new O(e);this._writableState=new E(e,this,t),this.writable=!0,e&&(typeof e.write==`function`&&(this._write=e.write),typeof e.writev==`function`&&(this._writev=e.writev),typeof e.destroy==`function`&&(this._destroy=e.destroy),typeof e.final==`function`&&(this._final=e.final)),o.call(this)}O.prototype.pipe=function(){T(this,new v)};function k(e,t){var n=new C;T(e,n),process.nextTick(t,n)}function j(e,t,n,r){var i;return n===null?i=new b:typeof n!=`string`&&!t.objectMode&&(i=new h(`chunk`,[`string`,`Buffer`],n)),i?(T(e,i),process.nextTick(r,i),!1):!0}O.prototype.write=function(e,t,n){var r=this._writableState,i=!1,a=!r.objectMode&&u(e);return a&&!s.isBuffer(e)&&(e=l(e)),typeof t==`function`&&(n=t,t=null),a?t=`buffer`:t||=r.defaultEncoding,typeof n!=`function`&&(n=ie),r.ending?k(this,n):(a||j(this,r,e,n))&&(r.pendingcb++,i=N(this,r,a,e,t,n)),i},O.prototype.cork=function(){this._writableState.corked++},O.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&B(this,e))},O.prototype.setDefaultEncoding=function(e){if(typeof e==`string`&&(e=e.toLowerCase()),!([`hex`,`utf8`,`utf-8`,`ascii`,`binary`,`base64`,`ucs2`,`ucs-2`,`utf16le`,`utf-16le`,`raw`].indexOf((e+``).toLowerCase())>-1))throw new re(e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(O.prototype,`writableBuffer`,{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function M(e,t,n){return!e.objectMode&&e.decodeStrings!==!1&&typeof t==`string`&&(t=s.from(t,n)),t}Object.defineProperty(O.prototype,`writableHighWaterMark`,{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function N(e,t,n,r,i,a){if(!n){var o=M(t,r,i);r!==o&&(n=!0,i=`buffer`,r=o)}var s=t.objectMode?1:r.length;t.length+=s;var c=t.length<t.highWaterMark;if(c||(t.needDrain=!0),t.writing||t.corked){var l=t.lastBufferedRequest;t.lastBufferedRequest={chunk:r,encoding:i,isBuf:n,callback:a,next:null},l?l.next=t.lastBufferedRequest:t.bufferedRequest=t.lastBufferedRequest,t.bufferedRequestCount+=1}else P(e,t,!1,s,r,i,a);return c}function P(e,t,n,r,i,a,o){t.writelen=r,t.writecb=o,t.writing=!0,t.sync=!0,t.destroyed?t.onwrite(new y(`write`)):n?e._writev(i,t.onwrite):e._write(i,a,t.onwrite),t.sync=!1}function F(e,t,n,r,i){--t.pendingcb,n?(process.nextTick(i,r),process.nextTick(W,e,t),e._writableState.errorEmitted=!0,T(e,r)):(i(r),e._writableState.errorEmitted=!0,T(e,r),W(e,t))}function I(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}function L(e,t){var n=e._writableState,r=n.sync,i=n.writecb;if(typeof i!=`function`)throw new _;if(I(n),t)F(e,n,r,t,i);else{var a=V(n)||e.destroyed;!a&&!n.corked&&!n.bufferProcessing&&n.bufferedRequest&&B(e,n),r?process.nextTick(R,e,n,a,i):R(e,n,a,i)}}function R(e,t,n,r){n||z(e,t),t.pendingcb--,r(),W(e,t)}function z(e,t){t.length===0&&t.needDrain&&(t.needDrain=!1,e.emit(`drain`))}function B(e,t){t.bufferProcessing=!0;var n=t.bufferedRequest;if(e._writev&&n&&n.next){var i=t.bufferedRequestCount,a=Array(i),o=t.corkedRequestsFree;o.entry=n;for(var s=0,c=!0;n;)a[s]=n,n.isBuf||(c=!1),n=n.next,s+=1;a.allBuffers=c,P(e,t,!0,t.length,a,``,o.finish),t.pendingcb++,t.lastBufferedRequest=null,o.next?(t.corkedRequestsFree=o.next,o.next=null):t.corkedRequestsFree=new r(t),t.bufferedRequestCount=0}else{for(;n;){var l=n.chunk,u=n.encoding,d=n.callback,f=t.objectMode?1:l.length;if(P(e,t,!1,f,l,u,d),n=n.next,t.bufferedRequestCount--,t.writing)break}n===null&&(t.lastBufferedRequest=null)}t.bufferedRequest=n,t.bufferProcessing=!1}O.prototype._write=function(e,t,n){n(new g(`_write()`))},O.prototype._writev=null,O.prototype.end=function(e,t,n){var r=this._writableState;return typeof e==`function`?(n=e,e=null,t=null):typeof t==`function`&&(n=t,t=null),e!=null&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||G(this,r,n),this},Object.defineProperty(O.prototype,`writableLength`,{enumerable:!1,get:function(){return this._writableState.length}});function V(e){return e.ending&&e.length===0&&e.bufferedRequest===null&&!e.finished&&!e.writing}function H(e,t){e._final(function(n){t.pendingcb--,n&&T(e,n),t.prefinished=!0,e.emit(`prefinish`),W(e,t)})}function U(e,t){!t.prefinished&&!t.finalCalled&&(typeof e._final==`function`&&!t.destroyed?(t.pendingcb++,t.finalCalled=!0,process.nextTick(H,e,t)):(t.prefinished=!0,e.emit(`prefinish`)))}function W(e,t){var n=V(t);if(n&&(U(e,t),t.pendingcb===0&&(t.finished=!0,e.emit(`finish`),t.autoDestroy))){var r=e._readableState;(!r||r.autoDestroy&&r.endEmitted)&&e.destroy()}return n}function G(e,t,n){t.ending=!0,W(e,t),n&&(t.finished?process.nextTick(n):e.once(`finish`,n)),t.ended=!0,e.writable=!1}function K(e,t,n){var r=e.entry;for(e.entry=null;r;){var i=r.callback;t.pendingcb--,i(n),r=r.next}t.corkedRequestsFree.next=e}Object.defineProperty(O.prototype,`destroyed`,{enumerable:!1,get:function(){return this._writableState===void 0?!1:this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),O.prototype.destroy=d.destroy,O.prototype._undestroy=d.undestroy,O.prototype._destroy=function(e,t){t(e)}})),M=e((exports=>{exports.levels={error:0,warn:1,help:2,data:3,info:4,debug:5,prompt:6,verbose:7,input:8,silly:9},exports.colors={error:`red`,warn:`yellow`,help:`cyan`,data:`grey`,info:`green`,debug:`blue`,prompt:`grey`,verbose:`cyan`,input:`grey`,silly:`magenta`}})),N=e((exports=>{exports.levels={error:0,warn:1,info:2,http:3,verbose:4,debug:5,silly:6},exports.colors={error:`red`,warn:`yellow`,info:`green`,http:`green`,verbose:`cyan`,debug:`blue`,silly:`magenta`}})),P=e((exports=>{exports.levels={emerg:0,alert:1,crit:2,error:3,warning:4,notice:5,info:6,debug:7},exports.colors={emerg:`red`,alert:`yellow`,crit:`red`,error:`red`,warning:`red`,notice:`yellow`,info:`green`,debug:`blue`}})),F=e((exports=>{Object.defineProperty(exports,`cli`,{value:M()}),Object.defineProperty(exports,`npm`,{value:N()}),Object.defineProperty(exports,`syslog`,{value:P()})})),I=e((exports=>{Object.defineProperty(exports,`LEVEL`,{value:Symbol.for(`level`)}),Object.defineProperty(exports,`MESSAGE`,{value:Symbol.for(`message`)}),Object.defineProperty(exports,`SPLAT`,{value:Symbol.for(`splat`)}),Object.defineProperty(exports,`configs`,{value:F()})})),L=e(((exports,n)=>{let r=t(`util`),i=j(),{LEVEL:a}=I(),o=n.exports=function(e={}){i.call(this,{objectMode:!0,highWaterMark:e.highWaterMark}),this.format=e.format,this.level=e.level,this.handleExceptions=e.handleExceptions,this.handleRejections=e.handleRejections,this.silent=e.silent,e.log&&(this.log=e.log),e.logv&&(this.logv=e.logv),e.close&&(this.close=e.close),this.once(`pipe`,e=>{this.levels=e.levels,this.parent=e}),this.once(`unpipe`,e=>{e===this.parent&&(this.parent=null,this.close&&this.close())})};r.inherits(o,i),o.prototype._write=function(e,t,n){if(this.silent||e.exception===!0&&!this.handleExceptions)return n(null);let r=this.level||this.parent&&this.parent.level;if(!r||this.levels[r]>=this.levels[e[a]]){if(e&&!this.format)return this.log(e,n);let t,r;try{r=this.format.transform(Object.assign({},e),this.format.options)}catch(e){t=e}if(t||!r){if(n(),t)throw t;return}return this.log(r,n)}return this._writableState.sync=!1,n(null)},o.prototype._writev=function(e,t){if(this.logv){let n=e.filter(this._accept,this);return n.length?this.logv(n,t):t(null)}for(let n=0;n<e.length;n++){if(!this._accept(e[n]))continue;if(e[n].chunk&&!this.format){this.log(e[n].chunk,e[n].callback);continue}let r,i;try{i=this.format.transform(Object.assign({},e[n].chunk),this.format.options)}catch(e){r=e}if(r||!i){if(e[n].callback(),r)throw t(null),r}else this.log(i,e[n].callback)}return t(null)},o.prototype._accept=function(e){let t=e.chunk;if(this.silent)return!1;let n=this.level||this.parent&&this.parent.level;return!!((t.exception===!0||!n||this.levels[n]>=this.levels[t[a]])&&(this.handleExceptions||t.exception!==!0))},o.prototype._nop=function(){}})),R=e(((exports,n)=>{let r=t(`util`),{LEVEL:i}=I(),a=L(),o=n.exports=function(e={}){if(a.call(this,e),!e.transport||typeof e.transport.log!=`function`)throw Error(`Invalid transport, must be an object with a log method.`);this.transport=e.transport,this.level=this.level||e.transport.level,this.handleExceptions=this.handleExceptions||e.transport.handleExceptions,this._deprecated();function t(e){this.emit(`error`,e,this.transport)}this.transport.__winstonError||(this.transport.__winstonError=t.bind(this),this.transport.on(`error`,this.transport.__winstonError))};r.inherits(o,a),o.prototype._write=function(e,t,n){if(this.silent||e.exception===!0&&!this.handleExceptions)return n(null);(!this.level||this.levels[this.level]>=this.levels[e[i]])&&this.transport.log(e[i],e.message,e,this._nop),n(null)},o.prototype._writev=function(e,t){for(let t=0;t<e.length;t++)this._accept(e[t])&&(this.transport.log(e[t].chunk[i],e[t].chunk.message,e[t].chunk,this._nop),e[t].callback());return t(null)},o.prototype._deprecated=function(){console.error([`${this.transport.name} is a legacy winston transport. Consider upgrading: `,`- Upgrade docs: https://github.com/winstonjs/winston/blob/master/UPGRADE-3.0.md`].join(`
4
4
  `))},o.prototype.close=function(){this.transport.close&&this.transport.close(),this.transport.__winstonError&&(this.transport.removeListener(`error`,this.transport.__winstonError),this.transport.__winstonError=null)}})),z=n(e(((exports,t)=>{t.exports=L(),t.exports.LegacyTransportStream=R()}))(),1);const B=new Set([`apikey`,`auth`,`credential`,`key`,`password`,`secret`,`token`]);var V=class extends z.default{apiKey;extraAttributes;httpTimeout;ingestUrl;pendingRequests=new Set;constructor(e){super({}),this.apiKey=e.apiKey,this.ingestUrl=e.ingestUrl,this.httpTimeout=e.httpTimeout??5e3;let t=m()||`unknown`;this.extraAttributes={arch:p(),hostname:t,instance:`mcp-gateway-${t}`,os:h(),source:`onyx-mcp-gateway`,version:r.appVersion,workload:`mcp-gateway`}}async flush(e=5e3){let t=Array.from(this.pendingRequests);t.length!==0&&await Promise.race([Promise.all(t),new Promise(t=>setTimeout(t,e))])}log(e,t){setImmediate(()=>this.emit(`logged`,e));let n=this.enrichEntry(e),r=this.sendEntry(n);this.pendingRequests.add(r),r.finally(()=>this.pendingRequests.delete(r)),t()}enrichEntry(e){let t={...this.extraAttributes,level:(e.level||`info`).toUpperCase(),message:e.message||``,timestamp:e.timestamp||new Date().toISOString()};for(let[n,r]of Object.entries(e)){if([`level`,`message`,`timestamp`].includes(n))continue;B.has(n.toLowerCase())?t[n]=`[REDACTED]`:t[n]=U(r)}return t}async sendEntry(e){let t=new AbortController,n=setTimeout(()=>t.abort(),this.httpTimeout);try{let n=H(e);await(await fetch(this.ingestUrl,{body:n,headers:{apikey:this.apiKey,"Content-Type":`application/json`,"x-source-type":`endpoint-logs`},method:`POST`,signal:t.signal})).text()}catch{}finally{clearTimeout(n)}}};function H(e){try{return JSON.stringify(e)}catch(t){let n={_serializationError:!0,level:`ERROR`,message:`[Log entry could not be serialized]`,originalError:t instanceof Error?t.message:String(t),timestamp:new Date().toISOString()};if(e&&typeof e==`object`)for(let t of[`level`,`message`,`timestamp`,`source`,`workload`]){let r=e[t];typeof r==`string`&&(n[t]=r)}return JSON.stringify(n)}}function U(e,t=0,n=new WeakSet){if(t>10)return`[max depth exceeded]`;if(e==null)return e;let r=typeof e;if(r===`string`||r===`number`||r===`boolean`)return r===`number`&&(Number.isNaN(e)||!Number.isFinite(e))?String(e):e;if(r===`function`)return`[Function: ${e.name||`anonymous`}]`;if(r===`symbol`)return`[Symbol: ${e.description||``}]`;if(r===`bigint`)return String(e);if(r===`object`){if(n.has(e))return`[Circular]`;if(n.add(e),e instanceof Date)return e.toISOString();if(e instanceof Error)return{message:e.message,name:e.name,stack:e.stack};if(e instanceof RegExp)return e.toString();if(e instanceof Map){let r={};for(let[i,a]of e){let e=typeof i==`string`?i:String(i);r[e]=U(a,t+1,n)}return r}if(e instanceof Set)return Array.from(e).map(e=>U(e,t+1,n));if(Array.isArray(e))return e.map(e=>U(e,t+1,n));if(ArrayBuffer.isView(e)||e instanceof ArrayBuffer)return`[Binary Data]`;let r={},i;try{i=Object.keys(e)}catch{return`[Object with inaccessible keys]`}for(let a of i){if(B.has(a.toLowerCase())){r[a]=`[REDACTED]`;continue}try{let i=e[a];r[a]=U(i,t+1,n)}catch{r[a]=`[Unserializable]`}}return r}return`[Unknown Type]`}const W=a(),G=new i;function K(e,t){return G.run({traceId:e},t)}let ae=W;function oe(e){let t=e?.traceparent;if(t){let e=t.split(`-`);if(e.length>=2&&e[1])return e[1]}}function se(){return G.getStore()?.traceId??ae}function q(e){ae=e}const J=r.logDir,Y=r.debug?`debug`:`info`;let X=!1;try{s(J)||c(J,{recursive:!0}),X=!0;try{v(J)}catch{}}catch(e){let t=e instanceof Error?e.message:String(e),n=t.includes(`EACCES`)||t.includes(`permission denied`);console.error(`[mcp-gateway] WARNING: Failed to create log directory: ${J}`),console.error(`[mcp-gateway] Error: ${t}`),n&&(console.error(`[mcp-gateway] This appears to be a permission issue. Possible solutions:`),console.error(`[mcp-gateway] 1. Fix directory permissions: sudo chown -R $USER ~/.onyx`),console.error(`[mcp-gateway] 2. Use a different log directory: export MCP_GATEWAY_LOG_DIR=/tmp/mcp-gateway-logs`)),console.error(`[mcp-gateway] File logging will be disabled. The gateway will continue to function.`)}const ce=d.format.combine(d.format.timestamp(),d.format.errors({stack:!0}),d.format.json());let Z=null;const le=[];let ue=null;X&&(ue=new f({datePattern:`YYYY-MM-DD`,filename:l(J,`mcp-gateway-%DATE%.log`),format:ce,handleExceptions:!1,handleRejections:!1,level:Y,maxFiles:10,maxSize:`10m`}),le.push(ue));let Q=null;const de=r.logIngest.enabled&&r.logIngest.url&&r.logIngest.apiKey;de&&(Q=new V({apiKey:r.logIngest.apiKey,httpTimeout:r.logIngest.timeoutMs,ingestUrl:r.logIngest.url}),le.push(Q));const fe=d.format(e=>(e.traceId=se(),e)),$=d.createLogger({defaultMeta:{service:`mcp-gateway`,version:r.appVersion},format:d.format.combine(fe(),d.format.errors({stack:!0})),level:Y,transports:le}),pe=e=>{let[t,...n]=e;if(typeof t!=`string`)return{message:String(t??``),meta:void 0,sessionData:Z||void 0};if(n.length>0&&n[0]&&typeof n[0]==`object`&&`proxyType`in n[0]){let e=n[0],r=n[1];return{message:t,meta:r,sessionData:e}}let r=n[0];return{message:t,meta:r,sessionData:Z||void 0}},me={debug:(...e)=>{let{message:t,meta:n,sessionData:r}=pe(e);$.debug(t,{sessionData:r,...n})},error:(...e)=>{let{message:t,meta:n,sessionData:r}=pe(e);$.error(t,{sessionData:r,...n})},getSessionData:()=>Z,getTraceId:()=>se(),info:(...e)=>{let{message:t,meta:n,sessionData:r}=pe(e);$.info(t,{sessionData:r,...n})},setSessionData:e=>{Z=e,me.debug(`Session data set for logger`,e)},setTraceId:e=>{q(e),me.debug(`Trace ID updated for logger`,{traceId:e})},warn:(...e)=>{let{message:t,meta:n,sessionData:r}=pe(e);$.warn(t,{sessionData:r,...n})}};let he=null;const ge=e=>he||(he=(async()=>{let t=[];Q&&t.push(Q.flush(e)),ue?t.push(new Promise(t=>{let n=!1,r=()=>{n||(n=!0,t())};setTimeout(()=>{$.once(`finish`,r),$.once(`error`,r),$.end()},50).unref(),e&&e>0&&setTimeout(r,e).unref()})):t.push(new Promise(e=>setImmediate(e))),await Promise.all(t)})(),he);me.info(`MCP Gateway logger initialized`,{debug:r.debug,fileLoggingEnabled:X,ingestLoggingEnabled:de,logDir:J,logLevel:Y});export{_ as chownToRealUser,oe as extractTraceIdFromHeaders,ge as flushLogs,W as gatewayCorrelationId,me as logger,w as require_inherits,K as runWithTraceContextAsync};
5
- //# sourceMappingURL=logger-BwqGcO50.js.map
5
+ //# sourceMappingURL=logger-DN0aJNvI.js.map