@lensmcp/cluster 1.25.11 → 1.25.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/basic-ssl.js +1 -1
- package/build-host.js +1 -1
- package/build-scope-patterns.js +1 -1
- package/bundle-parent.js +1 -1
- package/checkout-cache.js +1 -1
- package/create-webpack-dev.js +1 -1
- package/create-webpack-prod.js +1 -1
- package/dev-devtool.js +1 -1
- package/devserver-notifier.js +1 -1
- package/devserver-transport.js +1 -1
- package/error-stack-release.js +1 -1
- package/executors/build/build.impl.js +1 -1
- package/executors/gateway/body-stall.js +1 -1
- package/executors/gateway/canonical-path.js +1 -1
- package/executors/gateway/client-ip.js +1 -1
- package/executors/gateway/gateway-errors.js +1 -1
- package/executors/gateway/gateway.impl.js +1 -1
- package/executors/gateway/gateway.lib.js +1 -1
- package/executors/gateway/health-check.js +1 -1
- package/executors/gateway/jwks-verify.js +1 -1
- package/executors/gateway/jwt-claims.js +1 -1
- package/executors/gateway/main.prod-gateway.js +2 -2
- package/executors/gateway/main.rollout.js +4 -4
- package/executors/gateway/manifest.js +1 -1
- package/executors/gateway/metrics.js +1 -1
- package/executors/gateway/otel-tracing.js +1 -1
- package/executors/gateway/prod-config.js +1 -1
- package/executors/gateway/prod-gateway.lib.js +1 -1
- package/executors/gateway/prod-runtime/access-log.js +1 -1
- package/executors/gateway/prod-runtime/app.js +1 -1
- package/executors/gateway/prod-runtime/auth.js +1 -1
- package/executors/gateway/prod-runtime/body-stall.js +1 -1
- package/executors/gateway/prod-runtime/cors.js +1 -1
- package/executors/gateway/prod-runtime/edge.js +1 -1
- package/executors/gateway/prod-runtime/handler.js +1 -1
- package/executors/gateway/prod-runtime/hooks.js +1 -1
- package/executors/gateway/prod-runtime/observability.js +1 -1
- package/executors/gateway/prod-runtime/rollout.js +1 -1
- package/executors/gateway/prod-runtime/routing.js +1 -1
- package/executors/gateway/prod-runtime/server.js +1 -1
- package/executors/gateway/prod-runtime/trust.js +1 -1
- package/executors/gateway/prod-runtime/upgrade.js +7 -7
- package/executors/gateway/prod-runtime/upstream.js +1 -1
- package/executors/gateway/providers-prod.js +1 -1
- package/executors/gateway/rate-limit.js +2 -2
- package/executors/gateway/registry-source.js +1 -1
- package/executors/gateway/rollout-ops.js +2 -2
- package/executors/gateway/runtime/act.js +1 -1
- package/executors/gateway/runtime/auth.js +1 -1
- package/executors/gateway/runtime/chooser.js +12 -12
- package/executors/gateway/runtime/control.js +2 -2
- package/executors/gateway/runtime/dev-auth.js +1 -1
- package/executors/gateway/runtime/discovery.js +1 -1
- package/executors/gateway/runtime/edge.js +1 -1
- package/executors/gateway/runtime/guest-graph.js +2 -2
- package/executors/gateway/runtime/guest-replay.js +2 -2
- package/executors/gateway/runtime/handler.js +1 -1
- package/executors/gateway/runtime/hmr-reload.js +1 -1
- package/executors/gateway/runtime/hooks.js +1 -1
- package/executors/gateway/runtime/instance.js +2 -2
- package/executors/gateway/runtime/lens-children.js +1 -1
- package/executors/gateway/runtime/lifecycle.js +3 -3
- package/executors/gateway/runtime/observability.js +2 -2
- package/executors/gateway/runtime/own-log.js +4 -4
- package/executors/gateway/runtime/pod-env.js +2 -2
- package/executors/gateway/runtime/pod-output.js +1 -1
- package/executors/gateway/runtime/pod-probe.js +1 -1
- package/executors/gateway/runtime/process-names.js +1 -1
- package/executors/gateway/runtime/project-graph-store.js +1 -1
- package/executors/gateway/runtime/proxy.js +1 -1
- package/executors/gateway/runtime/registration-guards.js +1 -1
- package/executors/gateway/runtime/route-registry.js +1 -1
- package/executors/gateway/runtime/scope.js +1 -1
- package/executors/gateway/runtime/serve-launch.js +3 -3
- package/executors/gateway/runtime/server.js +2 -2
- package/executors/gateway/runtime/service-keys.js +1 -1
- package/executors/gateway/runtime/shared-build.js +4 -4
- package/executors/gateway/runtime/source-poller.js +1 -1
- package/executors/gateway/runtime/types.d.ts +2 -2
- package/executors/gateway/runtime/types.js +1 -1
- package/executors/gateway/runtime/upgrade.js +1 -1
- package/executors/gateway/runtime/workspace-log.js +1 -1
- package/executors/gateway/runtime/workspace-middleware.js +1 -1
- package/executors/gateway/runtime/workspace-registry.js +1 -1
- package/executors/gateway/ssrf-guard.js +1 -1
- package/executors/serve/serve.impl.js +1 -1
- package/executors/trust/hostname.js +1 -1
- package/executors/trust/trust.impl.js +3 -3
- package/exit-reason.js +2 -2
- package/fork-ts-check-reporter.js +1 -1
- package/gateway.js +1 -1
- package/gc-notice.js +1 -1
- package/graph-snapshot.js +1 -1
- package/handoff-retire.js +1 -1
- package/heap-snapshot.js +1 -1
- package/hot-swap-registries.js +1 -1
- package/index.js +1 -1
- package/inspector-secret.js +1 -1
- package/main.devserver.js +11 -11
- package/notice-generation.js +1 -1
- package/package.json +4 -4
- package/perf/heavy-barrel-import.js +1 -1
- package/perf/perf-config.js +1 -1
- package/perf/perf-rule-events.js +2 -2
- package/perf/perf-rules-analysis.js +1 -1
- package/perf/perf-rules-plugin.js +1 -1
- package/perf/source-scan.js +5 -5
- package/perf/workspace-libraries.js +2 -2
- package/pod-memory-events.js +2 -2
- package/pod-memory.js +1 -1
- package/pod-sock.js +1 -1
- package/process-name.js +1 -1
- package/redis-disconnect-fix.js +1 -1
- package/schema-first-instance.js +1 -1
- package/serve-runner.js +1 -1
- package/service-build-events.js +1 -1
- package/shared-build/attach.js +2 -2
- package/shared-build/host.js +3 -3
- package/shared-build/protocol.js +1 -1
- package/shared-build/shared-compilation.js +3 -3
- package/shared-build/signature.js +1 -1
- package/stdio-guard.js +1 -1
- package/swap-mode.js +1 -1
- package/swap-recycle.js +1 -1
- package/tsgo-check-plugin.js +4 -4
- package/typecheck-bus.js +3 -3
- package/typecheck-queue.js +1 -1
- package/worker-supervisor.js +2 -2
- package/workspace-paths.js +1 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)[0]})`}return helpersByRoot.set(e,s),s}
|
|
3
|
-
`)[0]})`)}const
|
|
1
|
+
"use strict";var T=Object.defineProperty;var u=(e,r)=>T(e,"name",{value:r,configurable:!0});var h=Object.defineProperty,i=u((e,r)=>h(e,"name",{value:r,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.RUNNER_ROOT_FLAG=exports.SERVE_RUNNER_ROLE=exports.SERVE_RUNNER_EXECUTOR=void 0,exports.serveRunnerEnabled=serveRunnerEnabled,exports.serveRunnerScript=serveRunnerScript,exports.serveRunnerArgs=serveRunnerArgs,exports.isServeRunnerCommand=isServeRunnerCommand,exports.isServeRunnerCommandOf=isServeRunnerCommandOf,exports.loadNxHelpers=loadNxHelpers,exports.nxExecutorEnv=nxExecutorEnv,exports.planServeLaunch=planServeLaunch;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),node_module_1=require("node:module"),path=tslib_1.__importStar(require("node:path"));exports.SERVE_RUNNER_EXECUTOR="@lensmcp/cluster:serve",exports.SERVE_RUNNER_ROLE="serve",exports.RUNNER_ROOT_FLAG="--workspace-root=";function serveRunnerEnabled(e=process.env){const r=(e.LENSMCP_SERVE_RUNNER??"").trim().toLowerCase();return!["0","off","false","no","nx"].includes(r)}u(serveRunnerEnabled,"serveRunnerEnabled"),i(serveRunnerEnabled,"serveRunnerEnabled");function serveRunnerScript(e=path.join(__dirname,"../../..")){const r=path.join(e,"serve-runner.js");if(fs.existsSync(r))return{path:r,execArgv:[]};const s=path.join(e,"serve-runner.ts");if(fs.existsSync(s))try{return{path:s,execArgv:["--require",require.resolve("@swc-node/register")]}}catch{return}}u(serveRunnerScript,"serveRunnerScript"),i(serveRunnerScript,"serveRunnerScript");function serveRunnerArgs(e,r,s){return["run",e,`--childCount=${r}`,`${exports.RUNNER_ROOT_FLAG}${s}`]}u(serveRunnerArgs,"serveRunnerArgs"),i(serveRunnerArgs,"serveRunnerArgs");function isServeRunnerCommand(e){return/\bserve-runner\.(js|ts)\b/.test(e)&&e.includes(` ${exports.RUNNER_ROOT_FLAG}`)}u(isServeRunnerCommand,"isServeRunnerCommand"),i(isServeRunnerCommand,"isServeRunnerCommand");function isServeRunnerCommandOf(e,r){return isServeRunnerCommand(e)&&e.trimEnd().endsWith(` ${exports.RUNNER_ROOT_FLAG}${r.replace(/\/+$/,"")}`)}u(isServeRunnerCommandOf,"isServeRunnerCommandOf"),i(isServeRunnerCommandOf,"isServeRunnerCommandOf");const helpersByRoot=new Map;function loadNxHelpers(e){const r=helpersByRoot.get(e);if(r)return r;let s;try{const o=(0,node_module_1.createRequire)(path.join(e,"package.json")),_=o("nx/package.json").version,t=o("nx/src/tasks-runner/task-env"),n=o("nx/src/tasks-runner/create-task-graph"),a=o("nx/src/config/nx-json"),p=o("nx/src/utils/cache-directory"),c=o.resolve("nx/src/command-line/run/run"),d=[["getEnvFilesForTask",t.getEnvFilesForTask],["loadAndExpandDotEnvFile",t.loadAndExpandDotEnvFile],["unloadDotEnvFile",t.unloadDotEnvFile],["createTaskGraph",n.createTaskGraph],["readNxJson",a.readNxJson],["workspaceDataDirectoryForWorkspace",p.workspaceDataDirectoryForWorkspace]].filter(([,R])=>typeof R!="function").map(([R])=>R);s=d.length>0?`nx ${_} has no ${d.join(", ")}`:{version:_,runModule:c,createTaskGraph:n.createTaskGraph,getEnvFilesForTask:t.getEnvFilesForTask,loadAndExpandDotEnvFile:t.loadAndExpandDotEnvFile,unloadDotEnvFile:t.unloadDotEnvFile,readNxJson:a.readNxJson,workspaceDataDirectoryForWorkspace:p.workspaceDataDirectoryForWorkspace}}catch(o){s=`cannot load the workspace's nx (${o.message.split(`
|
|
2
|
+
`)[0]})`}return helpersByRoot.set(e,s),s}u(loadNxHelpers,"loadNxHelpers"),i(loadNxHelpers,"loadNxHelpers");const ROOT_DOTENV_LOAD=[".local.env",".env.local",".env"],ROOT_DOTENV_UNLOAD=[".env",".local.env",".env.local"];function nxExecutorEnv(e,r,s,o,_){const t={...s};t.FORCE_COLOR==="0"&&(t.NO_COLOR="1",delete t.FORCE_COLOR),e.loadAndExpandDotEnvFile(ROOT_DOTENV_LOAD.map(a=>path.join(r,a)),t),t.NX_CLI_SET="true",t.NX_VERBOSE_LOGGING=String(t.NX_VERBOSE_LOGGING==="true"),t.NX_TUI="false",t.NX_LOAD_DOT_ENV_FILES!=="false"&&(t.NX_LOAD_DOT_ENV_FILES="true");const n={...t};for(const a of ROOT_DOTENV_UNLOAD)e.unloadDotEnvFile(path.join(r,a),n);t.NX_LOAD_DOT_ENV_FILES==="true"&&e.loadAndExpandDotEnvFile(e.getEnvFilesForTask(o,_).map(a=>path.join(r,a)),n),n.FORCE_COLOR=t.FORCE_COLOR===void 0?"true":t.FORCE_COLOR,n.NX_WORKSPACE_ROOT=r,n.NX_TASK_TARGET_PROJECT=o.target.project,n.NX_TASK_TARGET_TARGET=o.target.target,o.target.configuration?n.NX_TASK_TARGET_CONFIGURATION=o.target.configuration:delete n.NX_TASK_TARGET_CONFIGURATION,n.LERNA_PACKAGE_NAME=o.target.project,n.NX_TUI="false",o.target.target==="test"&&(n.NX_TERMINAL_CAPTURE_STDERR="true");for(const a of["NX_TASK_HASH","NX_SKIP_NX_CACHE","NX_TERMINAL_OUTPUT_PATH","NX_STREAM_OUTPUT","NX_PREFIX_OUTPUT","NX_SET_CLI"])delete n[a];return(t.NX_SKIP_NX_CACHE==="true"||t.NX_DISABLE_NX_CACHE==="true")&&(n.NX_SKIP_NX_CACHE="true"),n.NX_FORKED_TASK_EXECUTOR="true",{env:n,isVerbose:t.NX_VERBOSE_LOGGING==="true"}}u(nxExecutorEnv,"nxExecutorEnv"),i(nxExecutorEnv,"nxExecutorEnv");function inferredBy(e,r,s){const o=e.sourceMaps?.[r],_=new Set([path.posix.join(r,"project.json"),path.posix.join(r,"package.json"),"nx.json"]),t=`targets.${s}`;let n=!1;for(const[a,[p,c]]of Object.entries(o??{}))if(!(a!==t&&!a.startsWith(`${t}.`))&&(n=!0,!p||!_.has(p)))return`${c}${p?` (from ${p})`:""}`;return n?void 0:"a source the project graph does not record"}u(inferredBy,"inferredBy"),i(inferredBy,"inferredBy");function planServeLaunch(e){const r=i(E=>({kind:"nx",reason:E}),"nx");if(!serveRunnerEnabled(e.gatewayEnv??process.env))return r("LENSMCP_SERVE_RUNNER is off");if(!e.stores)return r("the gateway was started without an Nx project graph");const s=e.stores.get(e.root);if(!s)return r("a workspace registered into this gateway that it holds no project graph for");const o=s.current();if(!o)return s.refreshIfStale(),r(`no project graph${s.lastError()?` (${s.lastError()})`:""}`);const _=s.staleReason();if(_)return s.refreshIfStale(),r(_);const t=o.projectGraph.nodes[e.project],n=t?.data.targets?.[e.target];if(!t||!n)return r(`${e.project}:${e.target} is not in the project graph`);if(n.executor!==exports.SERVE_RUNNER_EXECUTOR)return r(`its executor is ${n.executor??"(none)"}, not ${exports.SERVE_RUNNER_EXECUTOR}`);if(!o.sourceMaps)return r("this nx reports no source maps, so the gateway cannot tell a declared target from an inferred one");const a=inferredBy(o,t.data.root,e.target);if(a)return r(`part of the target is inferred by ${a}`);const p=e.gatewayEnv??process.env;if(e.baseEnv.NX_CACHE_PROJECT_GRAPH==="false"||p.NX_CACHE_PROJECT_GRAPH==="false")return r("NX_CACHE_PROJECT_GRAPH=false \u2014 the executor reads nx's graph cache");const c=loadNxHelpers(e.root);if(typeof c=="string")return r(c);const d=e.script??serveRunnerScript();if(!d)return r("serve-runner.js is missing from @lensmcp/cluster");if(!fs.existsSync(path.join(c.workspaceDataDirectoryForWorkspace(e.root),"project-graph.json")))return r("nx has no project-graph cache on disk for the executor to read");const R={childCount:e.childCount,__overrides_unparsed__:[`--childCount=${e.childCount}`]};let N;try{N=c.createTaskGraph(o.projectGraph,{},[e.project],[e.target],void 0,R)}catch(E){return r(`nx could not build its task graph (${E.message.split(`
|
|
3
|
+
`)[0]})`)}const l=Object.values(N.tasks).find(E=>E.target.project===e.project&&E.target.target===e.target);if(!l)return r(`nx's task graph has no ${e.project}:${e.target}`);const f=Object.keys(N.tasks).filter(E=>E!==l.id);if(f.length>0)return r(`dependsOn: nx would run ${f.join(", ")} first`);const v=new Set(c.readNxJson(e.root).sync?.disabledTaskSyncGenerators??[]),O=(n.syncGenerators??[]).filter(E=>!v.has(E));if(O.length>0)return r(`sync generators nx would run first: ${O.join(", ")}`);l.startTime=Date.now();const{env:x,isVerbose:g}=nxExecutorEnv(c,e.root,e.baseEnv,l,o.projectGraph);return{kind:"runner",taskId:l.id,env:x,script:d,message:{nxRunModule:c.runModule,targetDescription:l.target,overrides:l.overrides,isVerbose:g,taskGraph:N}}}u(planServeLaunch,"planServeLaunch"),i(planServeLaunch,"planServeLaunch");
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var me=Object.defineProperty;var v=(r,t)=>me(r,"name",{value:t,configurable:!0});var ge=Object.defineProperty,A=v((r,t)=>ge(r,"name",{value:t,configurable:!0}),"A"),he=Object.defineProperty,n=A((r,t)=>he(r,"name",{value:t,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT=exports.GATEWAY_MAX_H2_STREAMS_DEFAULT=exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT=exports.GATEWAY_MAX_CONNECTIONS_DEFAULT=exports.BENIGN_SOCKET_ERRNOS=void 0,exports.buildEdgeVerifierPool=buildEdgeVerifierPool,exports.classifyClientError=classifyClientError,exports.createClientErrorLogGate=createClientErrorLogGate,exports.retirePreviousWorkspace=retirePreviousWorkspace,exports.resolveMaxConnections=resolveMaxConnections,exports.h2BudgetFromEnv=h2BudgetFromEnv,exports.createH2Governor=createH2Governor,exports.startGateway=startGateway;const tslib_1=require("tslib"),http=tslib_1.__importStar(require("node:http")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),scope_1=require("./scope"),route_registry_1=require("./route-registry"),act_1=require("./act"),control_1=require("./control"),workspace_middleware_1=require("./workspace-middleware"),workspace_registry_1=require("./workspace-registry"),service_keys_1=require("./service-keys"),source_poller_1=require("./source-poller"),client_ip_1=require("../client-ip"),workspace_log_1=require("./workspace-log"),own_log_1=require("./own-log"),observability_1=require("./observability"),lifecycle_1=require("./lifecycle"),process_names_1=require("./process-names"),project_graph_store_1=require("./project-graph-store"),serve_launch_1=require("./serve-launch"),process_name_1=require("../../../process-name"),protocol_1=require("../../../shared-build/protocol"),lens_children_1=require("./lens-children"),proxy_1=require("./proxy"),auth_1=require("./auth"),hooks_1=require("./hooks"),handler_1=require("./handler"),upgrade_1=require("./upgrade"),jwks_verify_1=require("../jwks-verify"),types_1=require("./types");function insecureLocalFetch(r,t){return new Promise((u,m)=>{const a=(r.startsWith("https:")?require("node:https"):require("node:http")).request(r,{method:"GET",headers:t?.headers,rejectUnauthorized:!1},w=>{const _=[];w.on("data",g=>_.push(g)),w.on("end",()=>{const g=w.statusCode??0,l=Buffer.concat(_).toString("utf8");u({ok:g>=200&&g<300,status:g,json:n(async()=>JSON.parse(l),"json")})})});a.on("error",m),a.end()})}v(insecureLocalFetch,"insecureLocalFetch"),A(insecureLocalFetch,"insecureLocalFetch"),n(insecureLocalFetch,"insecureLocalFetch");function buildEdgeVerifierPool(r){const t=process.env.LENSMCP_GW_JWKS_URL,u=process.env.LENSMCP_GW_JWT_ISS,m=new Map;let a;const w=n((_,g)=>{console.log(`[gateway] edge JWT: verifying via JWKS ${_}${g}`);const l=(0,jwks_verify_1.createJwksVerifier)({jwksUrl:_,...u?{issuer:u}:{},fetchImpl:insecureLocalFetch});return l.refresh().catch(s=>console.warn("[gateway] edge JWKS warm failed (will retry):",s.message)),l},"make");return{for(_){if(t)return a??=w(t,"");const g=_.split(":")[0].toLowerCase();let l;for(const d of r()){const S=d.host;if(typeof S!="string"||!/^auth\./.test(S)||S.startsWith("internal."))continue;const T=S.slice(5);(g===T||g.endsWith(`.${T}`))&&(!l||T.length>l.length)&&(l=T)}if(!l)return;let s=m.get(l);return s||(s=w(`https://auth.${l}/jwks.json`,` (auto-derived for apex ${l})`),m.set(l,s)),s},stop(){a?.stop();for(const _ of m.values())_.stop()}}}v(buildEdgeVerifierPool,"buildEdgeVerifierPool"),A(buildEdgeVerifierPool,"buildEdgeVerifierPool"),n(buildEdgeVerifierPool,"buildEdgeVerifierPool"),exports.BENIGN_SOCKET_ERRNOS=new Set(["ECONNRESET","EPIPE","ETIMEDOUT","ECONNABORTED","ECANCELED"]);function classifyClientError(r,t){return r&&exports.BENIGN_SOCKET_ERRNOS.has(r)?{status:null,report:!1,cause:"client-abort"}:r==="HPE_INVALID_EOF_STATE"?{status:null,report:!1,cause:"truncated-at-eof"}:r==="ERR_HTTP_REQUEST_TIMEOUT"?{status:408,report:!0,cause:"request-timeout"}:r==="HPE_HEADER_OVERFLOW"?{status:431,report:!0,cause:"header-overflow"}:r?.startsWith("HPE_")?{status:400,report:!0,cause:"parse-error"}:{status:400,report:!0,cause:r??t??"unknown"}}v(classifyClientError,"classifyClientError"),A(classifyClientError,"classifyClientError"),n(classifyClientError,"classifyClientError");const CLIENT_ERROR_REASON={400:"Bad Request",408:"Request Timeout",431:"Request Header Fields Too Large"};function createClientErrorLogGate(r=1e4){const t=new Map;return u=>{const m=Date.now(),a=t.get(u)??0;return m-a<r?!1:(t.set(u,m),!0)}}v(createClientErrorLogGate,"createClientErrorLogGate"),A(createClientErrorLogGate,"createClientErrorLogGate"),n(createClientErrorLogGate,"createClientErrorLogGate");function guardInboundSocket(r){r.on("error",t=>{exports.BENIGN_SOCKET_ERRNOS.has(t.code??"")||console.warn(`[gateway] inbound socket error (${t.code??t.message}) \u2014 dropping this connection only`),r.destroy()})}v(guardInboundSocket,"guardInboundSocket"),A(guardInboundSocket,"guardInboundSocket"),n(guardInboundSocket,"guardInboundSocket");function retirePreviousWorkspace(r,t,u){const m=r.get(t);if(!m)return!1;r.delete(t),u==="re-registered"&&console.log(`[gateway] workspace '${t}' re-registered \u2014 retiring the children of its previous registration first.`);try{m()}catch(a){console.warn(`[gateway] could not fully retire the previous registration of '${t}' (${u}): ${a.message}`)}return!0}v(retirePreviousWorkspace,"retirePreviousWorkspace"),A(retirePreviousWorkspace,"retirePreviousWorkspace"),n(retirePreviousWorkspace,"retirePreviousWorkspace"),exports.GATEWAY_MAX_CONNECTIONS_DEFAULT=512,exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT=64,exports.GATEWAY_MAX_H2_STREAMS_DEFAULT=4096,exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT=3e5;function parseBudget(r,t){if(r===void 0||r.trim()==="")return t;const u=Number(r);return!Number.isFinite(u)||u<0?t:Math.floor(u)}v(parseBudget,"parseBudget"),A(parseBudget,"parseBudget"),n(parseBudget,"parseBudget");function resolveMaxConnections(r){return parseBudget(r,exports.GATEWAY_MAX_CONNECTIONS_DEFAULT)}v(resolveMaxConnections,"resolveMaxConnections"),A(resolveMaxConnections,"resolveMaxConnections"),n(resolveMaxConnections,"resolveMaxConnections");function h2BudgetFromEnv(r=process.env){return{maxSessions:parseBudget(r.LENSMCP_MAX_H2_SESSIONS,exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT),maxStreams:parseBudget(r.LENSMCP_MAX_H2_STREAMS,exports.GATEWAY_MAX_H2_STREAMS_DEFAULT),idleSessionMs:parseBudget(r.LENSMCP_H2_IDLE_MS,exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT)}}v(h2BudgetFromEnv,"h2BudgetFromEnv"),A(h2BudgetFromEnv,"h2BudgetFromEnv"),n(h2BudgetFromEnv,"h2BudgetFromEnv");function createH2Governor(r,t){const{NGHTTP2_ENHANCE_YOUR_CALM:u,NGHTTP2_REFUSED_STREAM:m}=require("node:http2").constants,a=new Map;let w=0;const _=n(s=>{s.idle&&(clearTimeout(s.idle),s.idle=void 0)},"disarm"),g=n((s,d)=>{_(d),!(r.idleSessionMs<=0||d.open>0)&&(d.idle=setTimeout(()=>{s.destroyed||s.closed||(t("session-reclaimed",{idleMs:r.idleSessionMs,sessions:a.size}),a.delete(s),s.close())},r.idleSessionMs),d.idle.unref?.())},"arm"),l=n(()=>{for(const[s,d]of a)if(!(d.open>0||s.destroyed))return _(d),a.delete(s),t("session-reclaimed",{reason:"cap",sessions:a.size+1,maxSessions:r.maxSessions}),s.close(),!0;return!1},"reclaimOldestIdle");return{admitSession(s){if(r.maxSessions>0&&a.size>=r.maxSessions&&!l()){t("session-refused",{sessions:a.size,maxSessions:r.maxSessions,streams:w});try{s.goaway(u)}catch{}try{s.close()}catch{}return!1}const d={open:0};return a.set(s,d),g(s,d),s.once("close",()=>{_(d),a.delete(s)}),!0},admitStream(s,d){const S=a.get(s);if(!S)return!0;if(r.maxStreams>0&&w>=r.maxStreams){t("stream-refused",{streams:w,maxStreams:r.maxStreams,sessions:a.size});try{d.close(m)}catch{}return!1}return w+=1,S.open+=1,_(S),d.once("close",()=>{w=Math.max(0,w-1),S.open=Math.max(0,S.open-1),S.open===0&&a.has(s)&&g(s,S)}),!0},dispose(){for(const s of a.values())_(s);a.clear()}}}v(createH2Governor,"createH2Governor"),A(createH2Governor,"createH2Governor"),n(createH2Governor,"createH2Governor");async function startGateway(r,t){const u=r.https!==!1,m=r.ports?.length?r.ports:[443],a=r.scanTtlMs??1500,w=r.startupTimeoutMs??12e4,_=r.sweepMs??1e4,g=r.trafficFlushMs??5e3;let l=!1;const s=process.env.LENSMCP_EVENT_FILE??path.join(t.root,".lensmcp","events.jsonl"),d=(0,own_log_1.startOwnLogRotation)(t.root),S=(0,scope_1.readLensScope)(t.root),T=S.key,k=S.sockNs!==T?S.sockNs:void 0,V=t.projectsConfigurations?.projects??{},J=(0,discovery_1.projectSourceRoots)(t.root,V,t.projectDependencies),{routes:j,services:P,instance:z}=(0,discovery_1.discoverRoutes)(t.root,V,void 0,T,J,k,S.instance);if(j.length===0)throw new Error("[gateway] no project declares a `cluster` field \u2014 nothing to route.");const q=new route_registry_1.RouteRegistry;q.register({wsKey:T,...k?{sockNs:k}:{},root:t.root,routes:j,services:P,...z?{instance:z}:{}});const R=[];let Q=n(()=>{},"refreshCert");const Z=n(()=>{(0,route_registry_1.rebuildRoutesInPlace)(R,q),Q()},"rebuildRoutes");Z();const{serviceKeys:ie,keyToProject:ce,keyToWorkspace:le}=(0,service_keys_1.loadServiceKeys)(t.root,P,T),ue=(0,client_ip_1.createClientIpResolver)({...(0,client_ip_1.clientIpOptionsFromEnv)(),...r.trustProxyHops!==void 0?{trustProxyHops:r.trustProxyHops}:{},...r.clientIpHeader?{clientIpHeader:r.clientIpHeader}:{},...r.clientIpTrustedProxies?{clientIpTrustedProxies:r.clientIpTrustedProxies}:{}}),E={root:t.root,wsKey:T,...k?{sockNs:k}:{},eventFile:s,routes:R,registry:q,rebuildRoutes:Z,services:P,serviceKeys:ie,keyToProject:ce,keyToWorkspace:le,clientIp:ue,bodyStallMs:r.bodyStallMs??types_1.BODY_STALL_MS,scanTtlMs:a,startupTimeoutMs:w,sweepMs:_,trafficFlushMs:g,https:u,projectRoots:Object.fromEntries(Object.entries(t.projectsConfigurations?.projects??{}).map(([e,o])=>[e,path.resolve(t.root,o.root)])),projectSourceRoots:J,...t.projectGraphStore?{graphStores:(0,project_graph_store_1.createProjectGraphStores)(t.projectGraphStore)}:{},...r.sharedCompiler!==void 0?{sharedCompiler:r.sharedCompiler}:{},stopped:n(()=>l,"stopped")};(0,process_name_1.prelinkProcessNames)((0,process_names_1.gatewayProcessNames)(P,{runner:(0,serve_launch_1.serveRunnerEnabled)()&&!!t.projectGraphStore,sharedBuild:(0,protocol_1.sharedCompilerEnabled)(process.env,r.sharedCompiler),label:T||path.basename(t.root),lens:{key:T,dashboard:r.dashboard!==!1,mcp:r.mcp!==!1&&j.some(e=>!!e.lens)}}));const f=(0,observability_1.createObservability)(s,{trafficFlushMs:g}),de=createClientErrorLogGate(),b=h2BudgetFromEnv(),pe=createClientErrorLogGate(3e4),W=createH2Governor(b,(e,o)=>{pe(e)&&console.warn(`[gateway] h2 aggregate budget: ${e} (${JSON.stringify(o)}). These are the FRONT DOOR's ceilings, not an upstream's \u2014 raise/disable with LENSMCP_MAX_H2_SESSIONS / LENSMCP_MAX_H2_STREAMS / LENSMCP_H2_IDLE_MS / LENSMCP_MAX_CONNECTIONS (0 = unbounded).`),f.emit(e==="session-reclaimed"?"info":"warning",`h2 aggregate budget: ${e}`,`gateway-h2-budget:${e}`,{kind:"h2-aggregate-budget",event:e,project:"gateway",...o})}),M=(0,lifecycle_1.createServiceLayer)(E,f),L=(0,lens_children_1.createLensChildren)(E,f,r),F=new Map;let D;if(r.middleware){const e=require(path.resolve(t.root,r.middleware));D=e.default??e}const K=(0,workspace_middleware_1.createWorkspaceMiddleware)({ownerKey:T,...D?{owner:D}:{},policy:(0,workspace_middleware_1.guestMiddlewarePolicy)()}),O=process.env.LENSMCP_GW_ACT==="0"?void 0:(0,act_1.createActStore)({dir:path.join(path.dirname((0,control_1.controlSocketPath)()),"identities")});let I;try{I=(0,control_1.startControlServer)({rt:E,killService:n((e,o)=>M.killSpawned(e,o),"killService"),restartService:n((e,o)=>M.restartService(e,o),"restartService"),...O?{act:O}:{},onRegister:n(async e=>{retirePreviousWorkspace(F,e.wsKey,"re-registered"),K.set(e.wsKey,e.root,e.middleware);const o=await L.hostWorkspaceDashboard(e),h=await L.hostWorkspaceApps(e);F.set(e.wsKey,()=>{try{o?.()}finally{h()}})},"onRegister"),onUnregister:n(e=>{retirePreviousWorkspace(F,e.wsKey,"unregistered"),K.drop(e.wsKey),M.stopBuildHost(e.root)},"onUnregister")})}catch(e){console.warn("[gateway] control plane failed to start (multi-workspace register disabled):",e.message)}const H=(0,proxy_1.createProxy)(E,f,M),ee=buildEdgeVerifierPool(()=>E.routes),re=(0,auth_1.createEdgeAuth)(E,f,ee,O),_e=n(e=>{const o=e.route?.wsKey,h=K.for(o);if(h)try{const i=o?E.registry.get(o):void 0;h(e.req,{...o?{wsKey:o}:{},...i?{root:i.root}:{},env:i?.instance?.env??{}})}catch(i){f.traceStep(e.trace,"auth",{mode:"middleware",ok:!1,reason:i.message}),e.route&&f.finishTrace(e.trace,e.route.project,401),e.sendError(401,"unauthorized",`Gateway middleware rejected the request: ${i.message}`)}},"builtinMiddleware"),te=r.hooks??{},oe=(0,hooks_1.createHooks)({...te,afterAuth:[_e,...te.afterAuth??[]]}),se=(0,handler_1.createHandler)({rt:E,obs:f,auth:re,proxy:H,hooks:oe}),ne=(0,upgrade_1.createUpgrade)({rt:E,auth:re,proxy:H,hooks:oe,obs:f}),Se=f.startEdgeFlusher(),Ee=M.startSweeper(),ae=(0,source_poller_1.createSourcePoller)({services:n(()=>E.registry.allServices(),"services"),serviceKey:n(e=>E.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],"serviceKey"),emit:n((e,o,h,i,p)=>f.emit(o,h,i,{wsKey:e.wsKey,...p},void 0,e.wsKey===E.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl")),"emit"),scanTtlMs:a,stopped:n(()=>l,"stopped")});(0,source_poller_1.sourcesEnabled)()&&ae.start(),await L.bootSingletonsAndApps();for(const e of P)e.decl.eager&&M.ensureUp(e);let x,U,$;if(u){const e=require("../../../basic-ssl"),o=(0,service_keys_1.gatewayCacheDir)(t.root);$=n(()=>e.getCertificateSync(o,"gateway",E.routes.map(h=>h.host).filter(h=>!!h)),"mintCert"),x=$(),U=e.caCertPath()}const B=[],G=[],Y=r.maxConnections??resolveMaxConnections(process.env.LENSMCP_MAX_CONNECTIONS);for(const e of m){const o=x?require("node:http2").createSecureServer({key:x,cert:x,allowHTTP1:!0,maxSessionMemory:512,settings:{maxConcurrentStreams:512},peerMaxConcurrentStreams:512,streamResetBurst:r.h2ResetBurst??types_1.GATEWAY_H2_RESET_BURST,streamResetRate:r.h2ResetRate??types_1.GATEWAY_H2_RESET_RATE},(i,p)=>se(i,p)):http.createServer(se);o.on("upgrade",ne),o.on("error",i=>console.error(`[gateway] port ${e}: ${i.code}`)),o.on("connection",guardInboundSocket),o.on("secureConnection",guardInboundSocket),o.on("tlsClientError",(i,p)=>p.destroy()),o.on("clientError",(i,p)=>{const c=i,y=classifyClientError(c.code,c.message);if(y.report&&de(y.cause)){const N=p.remoteAddress??"unknown",C=y.status===null?"dropped":String(y.status);console.warn(`[gateway] inbound H1 clientError from ${N}: ${y.cause} (${c.code??c.message}${c.bytesParsed!==void 0?`, bytesParsed=${c.bytesParsed}`:""}) \u2192 ${C}. This status is the GATEWAY's, not the upstream service's.`),f.emit("warning",`inbound clientError: ${y.cause} \u2192 ${C}`,`gateway-client-error:${y.cause}`,{kind:"gateway-client-error",cause:y.cause,code:c.code??null,status:y.status,peer:N,bytesParsed:c.bytesParsed??null})}y.status!==null&&p.writable&&p.end(`HTTP/1.1 ${y.status} ${CLIENT_ERROR_REASON[y.status]}\r
|
|
1
|
+
"use strict";var ge=Object.defineProperty;var A=(s,r)=>ge(s,"name",{value:r,configurable:!0});var he=Object.defineProperty,n=A((s,r)=>he(s,"name",{value:r,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT=exports.GATEWAY_MAX_H2_STREAMS_DEFAULT=exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT=exports.GATEWAY_MAX_CONNECTIONS_DEFAULT=exports.BENIGN_SOCKET_ERRNOS=void 0,exports.buildEdgeVerifierPool=buildEdgeVerifierPool,exports.classifyClientError=classifyClientError,exports.createClientErrorLogGate=createClientErrorLogGate,exports.retirePreviousWorkspace=retirePreviousWorkspace,exports.resolveMaxConnections=resolveMaxConnections,exports.h2BudgetFromEnv=h2BudgetFromEnv,exports.createH2Governor=createH2Governor,exports.startGateway=startGateway;const tslib_1=require("tslib"),http=tslib_1.__importStar(require("node:http")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),scope_1=require("./scope"),route_registry_1=require("./route-registry"),act_1=require("./act"),control_1=require("./control"),workspace_middleware_1=require("./workspace-middleware"),workspace_registry_1=require("./workspace-registry"),service_keys_1=require("./service-keys"),source_poller_1=require("./source-poller"),client_ip_1=require("../client-ip"),workspace_log_1=require("./workspace-log"),own_log_1=require("./own-log"),observability_1=require("./observability"),lifecycle_1=require("./lifecycle"),process_names_1=require("./process-names"),project_graph_store_1=require("./project-graph-store"),serve_launch_1=require("./serve-launch"),process_name_1=require("../../../process-name"),protocol_1=require("../../../shared-build/protocol"),lens_children_1=require("./lens-children"),proxy_1=require("./proxy"),auth_1=require("./auth"),hooks_1=require("./hooks"),handler_1=require("./handler"),upgrade_1=require("./upgrade"),jwks_verify_1=require("../jwks-verify"),types_1=require("./types");function insecureLocalFetch(s,r){return new Promise((u,m)=>{const a=(s.startsWith("https:")?require("node:https"):require("node:http")).request(s,{method:"GET",headers:r?.headers,rejectUnauthorized:!1},w=>{const _=[];w.on("data",g=>_.push(g)),w.on("end",()=>{const g=w.statusCode??0,l=Buffer.concat(_).toString("utf8");u({ok:g>=200&&g<300,status:g,json:n(async()=>JSON.parse(l),"json")})})});a.on("error",m),a.end()})}A(insecureLocalFetch,"insecureLocalFetch"),n(insecureLocalFetch,"insecureLocalFetch");function buildEdgeVerifierPool(s){const r=process.env.LENSMCP_GW_JWKS_URL,u=process.env.LENSMCP_GW_JWT_ISS,m=new Map;let a;const w=n((_,g)=>{console.log(`[gateway] edge JWT: verifying via JWKS ${_}${g}`);const l=(0,jwks_verify_1.createJwksVerifier)({jwksUrl:_,...u?{issuer:u}:{},fetchImpl:insecureLocalFetch});return l.refresh().catch(o=>console.warn("[gateway] edge JWKS warm failed (will retry):",o.message)),l},"make");return{for(_){if(r)return a??=w(r,"");const g=_.split(":")[0].toLowerCase();let l;for(const d of s()){const S=d.host;if(typeof S!="string"||!/^auth\./.test(S)||S.startsWith("internal."))continue;const T=S.slice(5);(g===T||g.endsWith(`.${T}`))&&(!l||T.length>l.length)&&(l=T)}if(!l)return;let o=m.get(l);return o||(o=w(`https://auth.${l}/jwks.json`,` (auto-derived for apex ${l})`),m.set(l,o)),o},stop(){a?.stop();for(const _ of m.values())_.stop()}}}A(buildEdgeVerifierPool,"buildEdgeVerifierPool"),n(buildEdgeVerifierPool,"buildEdgeVerifierPool"),exports.BENIGN_SOCKET_ERRNOS=new Set(["ECONNRESET","EPIPE","ETIMEDOUT","ECONNABORTED","ECANCELED"]);function classifyClientError(s,r){return s&&exports.BENIGN_SOCKET_ERRNOS.has(s)?{status:null,report:!1,cause:"client-abort"}:s==="HPE_INVALID_EOF_STATE"?{status:null,report:!1,cause:"truncated-at-eof"}:s==="ERR_HTTP_REQUEST_TIMEOUT"?{status:408,report:!0,cause:"request-timeout"}:s==="HPE_HEADER_OVERFLOW"?{status:431,report:!0,cause:"header-overflow"}:s?.startsWith("HPE_")?{status:400,report:!0,cause:"parse-error"}:{status:400,report:!0,cause:s??r??"unknown"}}A(classifyClientError,"classifyClientError"),n(classifyClientError,"classifyClientError");const CLIENT_ERROR_REASON={400:"Bad Request",408:"Request Timeout",431:"Request Header Fields Too Large"};function createClientErrorLogGate(s=1e4){const r=new Map;return u=>{const m=Date.now(),a=r.get(u)??0;return m-a<s?!1:(r.set(u,m),!0)}}A(createClientErrorLogGate,"createClientErrorLogGate"),n(createClientErrorLogGate,"createClientErrorLogGate");function guardInboundSocket(s){s.on("error",r=>{exports.BENIGN_SOCKET_ERRNOS.has(r.code??"")||console.warn(`[gateway] inbound socket error (${r.code??r.message}) \u2014 dropping this connection only`),s.destroy()})}A(guardInboundSocket,"guardInboundSocket"),n(guardInboundSocket,"guardInboundSocket");function retirePreviousWorkspace(s,r,u){const m=s.get(r);if(!m)return!1;s.delete(r),u==="re-registered"&&console.log(`[gateway] workspace '${r}' re-registered \u2014 retiring the children of its previous registration first.`);try{m()}catch(a){console.warn(`[gateway] could not fully retire the previous registration of '${r}' (${u}): ${a.message}`)}return!0}A(retirePreviousWorkspace,"retirePreviousWorkspace"),n(retirePreviousWorkspace,"retirePreviousWorkspace"),exports.GATEWAY_MAX_CONNECTIONS_DEFAULT=512,exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT=64,exports.GATEWAY_MAX_H2_STREAMS_DEFAULT=4096,exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT=3e5;function parseBudget(s,r){if(s===void 0||s.trim()==="")return r;const u=Number(s);return!Number.isFinite(u)||u<0?r:Math.floor(u)}A(parseBudget,"parseBudget"),n(parseBudget,"parseBudget");function resolveMaxConnections(s){return parseBudget(s,exports.GATEWAY_MAX_CONNECTIONS_DEFAULT)}A(resolveMaxConnections,"resolveMaxConnections"),n(resolveMaxConnections,"resolveMaxConnections");function h2BudgetFromEnv(s=process.env){return{maxSessions:parseBudget(s.LENSMCP_MAX_H2_SESSIONS,exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT),maxStreams:parseBudget(s.LENSMCP_MAX_H2_STREAMS,exports.GATEWAY_MAX_H2_STREAMS_DEFAULT),idleSessionMs:parseBudget(s.LENSMCP_H2_IDLE_MS,exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT)}}A(h2BudgetFromEnv,"h2BudgetFromEnv"),n(h2BudgetFromEnv,"h2BudgetFromEnv");function createH2Governor(s,r){const{NGHTTP2_ENHANCE_YOUR_CALM:u,NGHTTP2_REFUSED_STREAM:m}=require("node:http2").constants,a=new Map;let w=0;const _=n(o=>{o.idle&&(clearTimeout(o.idle),o.idle=void 0)},"disarm"),g=n((o,d)=>{_(d),!(s.idleSessionMs<=0||d.open>0)&&(d.idle=setTimeout(()=>{o.destroyed||o.closed||(r("session-reclaimed",{idleMs:s.idleSessionMs,sessions:a.size}),a.delete(o),o.close())},s.idleSessionMs),d.idle.unref?.())},"arm"),l=n(()=>{for(const[o,d]of a)if(!(d.open>0||o.destroyed))return _(d),a.delete(o),r("session-reclaimed",{reason:"cap",sessions:a.size+1,maxSessions:s.maxSessions}),o.close(),!0;return!1},"reclaimOldestIdle");return{admitSession(o){if(s.maxSessions>0&&a.size>=s.maxSessions&&!l()){r("session-refused",{sessions:a.size,maxSessions:s.maxSessions,streams:w});try{o.goaway(u)}catch{}try{o.close()}catch{}return!1}const d={open:0};return a.set(o,d),g(o,d),o.once("close",()=>{_(d),a.delete(o)}),!0},admitStream(o,d){const S=a.get(o);if(!S)return!0;if(s.maxStreams>0&&w>=s.maxStreams){r("stream-refused",{streams:w,maxStreams:s.maxStreams,sessions:a.size});try{d.close(m)}catch{}return!1}return w+=1,S.open+=1,_(S),d.once("close",()=>{w=Math.max(0,w-1),S.open=Math.max(0,S.open-1),S.open===0&&a.has(o)&&g(o,S)}),!0},dispose(){for(const o of a.values())_(o);a.clear()}}}A(createH2Governor,"createH2Governor"),n(createH2Governor,"createH2Governor");async function startGateway(s,r){const u=s.https!==!1,m=s.ports?.length?s.ports:[443],a=s.scanTtlMs??1500,w=s.startupTimeoutMs??12e4,_=s.sweepMs??1e4,g=s.trafficFlushMs??5e3;let l=!1;const o=process.env.LENSMCP_EVENT_FILE??path.join(r.root,".lensmcp","events.jsonl"),d=(0,own_log_1.startOwnLogRotation)(r.root),S=(0,scope_1.readLensScope)(r.root),T=S.key,x=S.sockNs!==T?S.sockNs:void 0,X=r.projectsConfigurations?.projects??{},J=(0,discovery_1.projectSourceRoots)(r.root,X,r.projectDependencies),{routes:G,services:N,instance:V}=(0,discovery_1.discoverRoutes)(r.root,X,void 0,T,J,x,S.instance);if(G.length===0)throw new Error("[gateway] no project declares a `cluster` field \u2014 nothing to route.");const j=new route_registry_1.RouteRegistry;j.register({wsKey:T,...x?{sockNs:x}:{},root:r.root,routes:G,services:N,...V?{instance:V}:{}});const R=[];let z=n(()=>{},"refreshCert");const Q=n(()=>{(0,route_registry_1.rebuildRoutesInPlace)(R,j),z()},"rebuildRoutes");Q();const{serviceKeys:ae,keyToProject:ie,keyToWorkspace:ce}=(0,service_keys_1.loadServiceKeys)(r.root,N,T),le=(0,client_ip_1.createClientIpResolver)({...(0,client_ip_1.clientIpOptionsFromEnv)(),...s.trustProxyHops!==void 0?{trustProxyHops:s.trustProxyHops}:{},...s.clientIpHeader?{clientIpHeader:s.clientIpHeader}:{},...s.clientIpTrustedProxies?{clientIpTrustedProxies:s.clientIpTrustedProxies}:{}}),E={root:r.root,wsKey:T,...x?{sockNs:x}:{},eventFile:o,routes:R,registry:j,rebuildRoutes:Q,services:N,serviceKeys:ae,keyToProject:ie,keyToWorkspace:ce,clientIp:le,bodyStallMs:s.bodyStallMs??types_1.BODY_STALL_MS,scanTtlMs:a,startupTimeoutMs:w,sweepMs:_,trafficFlushMs:g,https:u,projectRoots:Object.fromEntries(Object.entries(r.projectsConfigurations?.projects??{}).map(([e,t])=>[e,path.resolve(r.root,t.root)])),projectSourceRoots:J,...r.projectGraphStore?{graphStores:(0,project_graph_store_1.createProjectGraphStores)(r.projectGraphStore)}:{},...s.sharedCompiler!==void 0?{sharedCompiler:s.sharedCompiler}:{},stopped:n(()=>l,"stopped")};(0,process_name_1.prelinkProcessNames)((0,process_names_1.gatewayProcessNames)(N,{runner:(0,serve_launch_1.serveRunnerEnabled)()&&!!r.projectGraphStore,sharedBuild:(0,protocol_1.sharedCompilerEnabled)(process.env,s.sharedCompiler),label:T||path.basename(r.root),lens:{key:T,dashboard:s.dashboard!==!1,mcp:s.mcp!==!1&&G.some(e=>!!e.lens)}}));const f=(0,observability_1.createObservability)(o,{trafficFlushMs:g}),ue=createClientErrorLogGate(),k=h2BudgetFromEnv(),de=createClientErrorLogGate(3e4),q=createH2Governor(k,(e,t)=>{de(e)&&console.warn(`[gateway] h2 aggregate budget: ${e} (${JSON.stringify(t)}). These are the FRONT DOOR's ceilings, not an upstream's \u2014 raise/disable with LENSMCP_MAX_H2_SESSIONS / LENSMCP_MAX_H2_STREAMS / LENSMCP_H2_IDLE_MS / LENSMCP_MAX_CONNECTIONS (0 = unbounded).`),f.emit(e==="session-reclaimed"?"info":"warning",`h2 aggregate budget: ${e}`,`gateway-h2-budget:${e}`,{kind:"h2-aggregate-budget",event:e,project:"gateway",...t})}),v=(0,lifecycle_1.createServiceLayer)(E,f),L=(0,lens_children_1.createLensChildren)(E,f,s),W=new Map;let D;if(s.middleware){const e=require(path.resolve(r.root,s.middleware));D=e.default??e}const K=(0,workspace_middleware_1.createWorkspaceMiddleware)({ownerKey:T,...D?{owner:D}:{},policy:(0,workspace_middleware_1.guestMiddlewarePolicy)()}),O=process.env.LENSMCP_GW_ACT==="0"?void 0:(0,act_1.createActStore)({dir:path.join(path.dirname((0,control_1.controlSocketPath)()),"identities")});let b;try{b=(0,control_1.startControlServer)({rt:E,killService:n((e,t)=>v.killSpawned(e,t),"killService"),restartService:n((e,t)=>v.restartService(e,t),"restartService"),...O?{act:O}:{},onRegister:n(async e=>{retirePreviousWorkspace(W,e.wsKey,"re-registered"),K.set(e.wsKey,e.root,e.middleware);const t=await L.hostWorkspaceDashboard(e),h=await L.hostWorkspaceApps(e);W.set(e.wsKey,()=>{try{t?.()}finally{h()}})},"onRegister"),onUnregister:n(e=>{retirePreviousWorkspace(W,e.wsKey,"unregistered"),K.drop(e.wsKey),v.stopBuildHost(e.root)},"onUnregister")})}catch(e){console.warn("[gateway] control plane failed to start (multi-workspace register disabled):",e.message)}const I=(0,proxy_1.createProxy)(E,f,v),Z=buildEdgeVerifierPool(()=>E.routes),ee=(0,auth_1.createEdgeAuth)(E,f,Z,O),pe=n(e=>{const t=e.route?.wsKey,h=K.for(t);if(h)try{const i=t?E.registry.get(t):void 0;h(e.req,{...t?{wsKey:t}:{},...i?{root:i.root}:{},env:i?.instance?.env??{}})}catch(i){f.traceStep(e.trace,"auth",{mode:"middleware",ok:!1,reason:i.message}),e.route&&f.finishTrace(e.trace,e.route.project,401),e.sendError(401,"unauthorized",`Gateway middleware rejected the request: ${i.message}`)}},"builtinMiddleware"),se=s.hooks??{},re=(0,hooks_1.createHooks)({...se,afterAuth:[pe,...se.afterAuth??[]]}),te=(0,handler_1.createHandler)({rt:E,obs:f,auth:ee,proxy:I,hooks:re}),oe=(0,upgrade_1.createUpgrade)({rt:E,auth:ee,proxy:I,hooks:re,obs:f}),_e=f.startEdgeFlusher(),Se=v.startSweeper(),ne=(0,source_poller_1.createSourcePoller)({services:n(()=>E.registry.allServices(),"services"),serviceKey:n(e=>E.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],"serviceKey"),emit:n((e,t,h,i,p)=>f.emit(t,h,i,{wsKey:e.wsKey,...p},void 0,e.wsKey===E.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl")),"emit"),scanTtlMs:a,stopped:n(()=>l,"stopped")});(0,source_poller_1.sourcesEnabled)()&&ne.start(),await L.bootSingletonsAndApps();for(const e of N)e.decl.eager&&v.ensureUp(e);let P,F,H;if(u){const e=require("../../../basic-ssl"),t=(0,service_keys_1.gatewayCacheDir)(r.root);H=n(()=>e.getCertificateSync(t,"gateway",E.routes.map(h=>h.host).filter(h=>!!h)),"mintCert"),P=H(),F=e.caCertPath()}const U=[],$=[],Y=s.maxConnections??resolveMaxConnections(process.env.LENSMCP_MAX_CONNECTIONS);for(const e of m){const t=P?require("node:http2").createSecureServer({key:P,cert:P,allowHTTP1:!0,maxSessionMemory:512,settings:{maxConcurrentStreams:512},peerMaxConcurrentStreams:512,streamResetBurst:s.h2ResetBurst??types_1.GATEWAY_H2_RESET_BURST,streamResetRate:s.h2ResetRate??types_1.GATEWAY_H2_RESET_RATE},(i,p)=>te(i,p)):http.createServer(te);t.on("upgrade",oe),t.on("error",i=>console.error(`[gateway] port ${e}: ${i.code}`)),t.on("connection",guardInboundSocket),t.on("secureConnection",guardInboundSocket),t.on("tlsClientError",(i,p)=>p.destroy()),t.on("clientError",(i,p)=>{const c=i,y=classifyClientError(c.code,c.message);if(y.report&&ue(y.cause)){const C=p.remoteAddress??"unknown",M=y.status===null?"dropped":String(y.status);console.warn(`[gateway] inbound H1 clientError from ${C}: ${y.cause} (${c.code??c.message}${c.bytesParsed!==void 0?`, bytesParsed=${c.bytesParsed}`:""}) \u2192 ${M}. This status is the GATEWAY's, not the upstream service's.`),f.emit("warning",`inbound clientError: ${y.cause} \u2192 ${M}`,`gateway-client-error:${y.cause}`,{kind:"gateway-client-error",cause:y.cause,code:c.code??null,status:y.status,peer:C,bytesParsed:c.bytesParsed??null})}y.status!==null&&p.writable&&p.end(`HTTP/1.1 ${y.status} ${CLIENT_ERROR_REASON[y.status]}\r
|
|
2
2
|
\r
|
|
3
|
-
`),p.destroy()}),
|
|
3
|
+
`),p.destroy()}),t.keepAliveTimeout=types_1.GATEWAY_KEEPALIVE_TIMEOUT_MS,t.headersTimeout=s.headersTimeoutMs??types_1.GATEWAY_HEADERS_TIMEOUT_MS,Y>0&&(t.maxConnections=Y);const h=s.connectionsCheckingIntervalMs??types_1.GATEWAY_CONN_CHECK_MS;if(h>0&&(t.connectionsCheckingInterval=h),P!=null){const i=t,{NGHTTP2_CANCEL:p}=require("node:http2").constants;i.on("session",c=>{if(!q.admitSession(c)){c.on("error",()=>{});return}let y=0,C=0;c.on("stream",M=>{q.admitStream(c,M)&&M.once("close",()=>{c.destroyed?C+=1:M.rstCode===p&&(y+=1)})}),c.once("close",()=>{C!==0&&(console.warn(`[gateway] h2 session closed with ${C} stream(s) in flight after ${y} client reset(s) \u2014 every in-flight fetch on that connection failed at once (ERR_HTTP2_PROTOCOL_ERROR in the browser). Reset budget: LENSMCP_H2_RESET_BURST/LENSMCP_H2_RESET_RATE (issues/closed/foodguard-14).`),f.emit("warning",`h2 session lost with ${C} stream(s) in flight`,"gateway-h2-session-lost",{kind:"h2-session-lost",project:"gateway",inflight:C,clientResets:y}))}),c.on("error",M=>{const Ee=M.code??M.message;console.warn(`[gateway] h2 session error (${Ee}) \u2014 dropping this session only`),c.destroyed||c.destroy()})}),i.on("sessionError",c=>{console.warn(`[gateway] h2 sessionError: ${c.code??c.message}`)})}await new Promise(i=>{t.listen(e,()=>{const p=t.address()?.port??e;$.push(p),console.log(`[gateway] Listening on ${P?"https":"http"}://localhost:${p}`),i()})}),U.push(t)}H&&(z=n(()=>{const e=H();for(const t of U)t.setSecureContext?.({key:e,cert:e})},"refreshCert")),console.log("[gateway] Routes:");for(const e of R){const t=e.pool?`pods@${e.pool.dir}`:e.target;console.log(`[gateway] ${e.host??"(default)"} \u2192 ${t}${e.prependPrefix?` (+${e.prependPrefix})`:""}${e.internal?" [internal: no middleware]":""} [${e.project}]`)}F&&console.log(`[gateway] CA: ${F} \u2014 one-time setup via the trust executor.`);const B=n(e=>e>0?String(e):"unbounded","unbounded");return console.log(`[gateway] front-door budget: \u2264${B(Y)} connections, \u2264${B(k.maxSessions)} h2 sessions (each \u2264512 MB session memory, \u2264512 streams), \u2264${B(k.maxStreams)} open streams in total, idle h2 session reclaimed after ${k.idleSessionMs>0?`${Math.round(k.idleSessionMs/1e3)}s`:"never"}. Override: LENSMCP_MAX_CONNECTIONS / LENSMCP_MAX_H2_SESSIONS / LENSMCP_MAX_H2_STREAMS / LENSMCP_H2_IDLE_MS (0 = unbounded).`),f.emit("info",`gateway up: ${R.length} routes on ${$.join("/")}`,"cluster-gateway",{kind:"gateway-up",project:"gateway",ports:$,routes:R.map(e=>({host:e.host??"(default)",project:e.project,mode:e.pool?"pods":"tcp",internal:!!e.internal,prependPrefix:e.prependPrefix}))}),b&&process.env.LENSMCP_GUEST_REPLAY!=="0"&&b.replay().catch(e=>console.warn("[gateway] guest replay failed:",e.message)),{ports:$,routes:R,services:N,stop:n(async()=>{if(!l){l=!0,clearInterval(_e),clearInterval(Se),ne.stop(),f.emit("info","gateway down","cluster-gateway",{kind:"gateway-down",project:"gateway"}),Z.stop(),b?.close(),O?.flush(),(0,workspace_registry_1.unregisterWorkspace)(T);for(const e of N)v.killSpawned(e,"gateway shutdown");v.stopRetiringTrees(),await v.stopBuildHost(),await L.reapAll(),oe.closeTunnels(),await Promise.all(U.map(e=>new Promise(t=>{let h=!1;const i=n(()=>{h||(h=!0,t())},"done"),p=e;e.close(()=>i());try{p.closeIdleConnections?.()}catch{}setTimeout(()=>{try{p.closeAllConnections?.()}catch{}i()},types_1.GATEWAY_STOP_GRACE_MS).unref?.()}))),I.closeProxy(),I.destroyAgents(),q.dispose(),(0,workspace_log_1.closeWorkspaceLogs)(),d()}},"stop"),...E.lensSupervisor?{lensSupervisor:E.lensSupervisor}:{},...E.graphStores?{graphStores:E.graphStores}:{}}}A(startGateway,"startGateway"),n(startGateway,"startGateway");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var l=Object.defineProperty;var a=(e,c)=>l(e,"name",{value:c,configurable:!0});var h=Object.defineProperty,y=a((e,c)=>h(e,"name",{value:c,configurable:!0}),"y");Object.defineProperty(exports,"__esModule",{value:!0}),exports.gatewayCacheDir=gatewayCacheDir,exports.serviceKeyId=serviceKeyId,exports.loadServiceKeys=loadServiceKeys,exports.adoptServiceKeys=adoptServiceKeys;const tslib_1=require("tslib"),node_crypto_1=require("node:crypto"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),checkout_cache_1=require("../../../checkout-cache");function gatewayCacheDir(e){return(0,checkout_cache_1.checkoutCacheDir)(e,"davnx-webpack")}a(gatewayCacheDir,"gatewayCacheDir"),y(gatewayCacheDir,"gatewayCacheDir");function serviceKeyId(e,c){return`${e??""} ${c}`}a(serviceKeyId,"serviceKeyId"),y(serviceKeyId,"serviceKeyId");function loadServiceKeys(e,c,p,k){const n=gatewayCacheDir(e),v=path.join(n,"service-keys.json");let r={};try{r=JSON.parse(fs.readFileSync(v,"utf8"))}catch{}let u=!1;const d=[];for(const[o,f]of Object.entries(r))k?.(f)&&(r[o]=(0,node_crypto_1.randomBytes)(16).toString("hex"),u=!0,d.push(o));for(const o of c)r[o.project]||(r[o.project]=(0,node_crypto_1.randomBytes)(16).toString("hex"),u=!0);if(u)try{fs.mkdirSync(n,{recursive:!0}),fs.writeFileSync(v,JSON.stringify(r,null,2))}catch{}const t=p??c[0]?.wsKey,s={};for(const[o,f]of Object.entries(r))s[serviceKeyId(t,o)]=f;const i=new Map(Object.entries(r).map(([o,f])=>[f,o])),j=new Map(t?Object.values(r).map(o=>[o,t]):[]);return{serviceKeys:s,keyToProject:i,keyToWorkspace:j,byProject:r,regenerated:d}}a(loadServiceKeys,"loadServiceKeys"),y(loadServiceKeys,"loadServiceKeys");function adoptServiceKeys(e,c,p,k){const n=k??p[0]?.wsKey,v=y(t=>{const s=e.keyToWorkspace?.get(t);return s!==void 0&&s!==n},"taken"),{byProject:r,regenerated:u}=loadServiceKeys(c,p,n,v),d=[];for(const t of p){const s=serviceKeyId(t.wsKey??n,t.project),i=r[t.project];if(!i||e.serviceKeys[s]===i)continue;e.serviceKeys[s]=i,e.keyToProject.set(i,t.project);const j=t.wsKey??n;j&&e.keyToWorkspace?.set(i,j),d.push(t.project)}return{added:d,regenerated:u}}a(adoptServiceKeys,"adoptServiceKeys"),y(adoptServiceKeys,"adoptServiceKeys");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)){const
|
|
3
|
-
`))
|
|
4
|
-
`)},"relayOut");return
|
|
1
|
+
"use strict";var A=Object.defineProperty;var y=(r,o)=>A(r,"name",{value:o,configurable:!0});var j=Object.defineProperty,i=y((r,o)=>j(r,"name",{value:o,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.HOST_MAX_RESTARTS=void 0,exports.buildHostScript=buildHostScript,exports.workspaceBuildHostScript=workspaceBuildHostScript,exports.createSharedBuildRelay=createSharedBuildRelay;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),node_module_1=require("node:module"),path=tslib_1.__importStar(require("node:path")),process_name_1=require("../../../process-name"),protocol_1=require("../../../shared-build/protocol"),pod_env_1=require("./pod-env"),registration_guards_1=require("./registration-guards");exports.HOST_MAX_RESTARTS=3;const CRASH_WINDOW_MS=6e4;function buildHostScript(r=path.join(__dirname,"../../..")){const o=path.join(r,"build-host.js");if(fs.existsSync(o))return{path:o,execArgv:[]};const u=path.join(r,"build-host.ts");if(fs.existsSync(u))try{return{path:u,execArgv:["--require",require.resolve("@swc-node/register")]}}catch{return}}y(buildHostScript,"buildHostScript"),i(buildHostScript,"buildHostScript");function workspaceBuildHostScript(r){try{return{path:(0,node_module_1.createRequire)(path.join(r,"package.json")).resolve("@lensmcp/cluster/build-host.js"),execArgv:[]}}catch{return}}y(workspaceBuildHostScript,"workspaceBuildHostScript"),i(workspaceBuildHostScript,"workspaceBuildHostScript");function createSharedBuildRelay(r,o={}){const u=o.script===void 0?buildHostScript():o.script??void 0,_=o.scriptFor??workspaceBuildHostScript,h=new Map,f=new WeakMap,d=(0,registration_guards_1.canonicalRoot)(r.root),v=i(e=>{const a=(0,registration_guards_1.canonicalRoot)(e.root);let n=h.get(a);return n||(n=a===d?createWorkspaceRelay(r,{root:r.root,...r.wsKey?{wsKey:r.wsKey}:{},...r.sockNs?{sockNs:r.sockNs}:{},eventFile:r.eventFile},u,o):createWorkspaceRelay(r,{root:e.root,...e.wsKey?{wsKey:e.wsKey}:{},...e.sockNs?{sockNs:e.sockNs}:{},eventFile:path.join(e.root,".lensmcp","events.jsonl")},_(e.root),o),h.set(a,n)),n},"relayFor");return{offeredTo:i(e=>(0,protocol_1.sharedCompilerEnabled)(o.gatewayEnv??process.env,r.sharedCompiler)&&v(e).offered(),"offeredTo"),attach(e,a,n){const S=v(e);f.set(n,S),S.attach(`${e.project}#g${a}`,n)},detach:i(e=>f.get(e)?.detach(e),"detach"),hostPid:i((e=r.root)=>h.get((0,registration_guards_1.canonicalRoot)(e))?.hostPid(),"hostPid"),release(e){const a=(0,registration_guards_1.canonicalRoot)(e),n=h.get(a);return h.delete(a),n?.stop()??Promise.resolve()},async stop(){const e=[...h.values()];h.clear(),await Promise.all(e.map(a=>a.stop()))}}}y(createSharedBuildRelay,"createSharedBuildRelay"),i(createSharedBuildRelay,"createSharedBuildRelay");function createWorkspaceRelay(r,o,u,_){const h=_.spawnProcess??node_child_process_1.spawn,f=_.log??(t=>console.log(t)),d=new Map,v=new WeakMap;let e,a=[],n,S=!1;const E=(0,registration_guards_1.canonicalRoot)(o.root)===(0,registration_guards_1.canonicalRoot)(r.root)?"this workspace":`'${o.wsKey??path.basename(o.root)}'`,b=i((t,s)=>{if(!t.connected)return;const c={channel:protocol_1.SHARED_BUILD_CHANNEL,event:s};try{t.send(c,void 0,void 0,()=>{})}catch{}},"toRunner"),R=i(t=>{if(e?.connected)try{e.send(t,void 0,void 0,()=>{})}catch{}},"toHost"),x=i(()=>{if(_.reapStale===!1)return;let t;try{t=(0,node_child_process_1.execFileSync)("ps",["ax","-ww","-o","pid=,pgid=,command="],{encoding:"utf8",timeout:5e3})}catch{return}for(const s of t.split(`
|
|
2
|
+
`)){const c=s.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!c||!(0,protocol_1.isBuildHostCommandOf)(c[3],o.root))continue;const l=Number(c[1]),p=Number(c[2]);if(!(l===e?.pid||l===process.pid)){try{process.kill(-p,"SIGKILL")}catch{try{process.kill(l,"SIGKILL")}catch{}}f(`[gateway] reaped a stale build host (pid ${l}) of ${E}`)}}},"reapStaleHosts"),N=i(()=>{if(e||S||n||!u)return e;x();const t=o.wsKey||path.basename(o.root),s={...(0,pod_env_1.podBaseEnv)(process.env,r.root,o.root),NX_DAEMON:"false",NODE_ENV:"development",NX_WORKSPACE_ROOT:o.root,...o.wsKey?{LENSMCP_WS_KEY:o.wsKey}:{},...o.sockNs?{LENSMCP_SOCK_NS:o.sockNs}:{},LENSMCP_EVENT_FILE:o.eventFile,LENSMCP_GATEWAY_PID:String(process.pid)},c=h((0,process_name_1.namedExecPath)((0,process_name_1.processName)(t,protocol_1.BUILD_HOST_ROLE)),[...u.execArgv,u.path,...(0,protocol_1.buildHostArgs)(o.root)],{cwd:o.root,detached:!0,env:s,stdio:["ignore","pipe","pipe","ipc"]});e=c,f(`[gateway] build host starting (one compilation for the services of ${E} \u2014 LENSMCP_SHARED_COMPILER)`);const l=i(p=>m=>{if(!r.stopped())for(const g of m.toString().split(`
|
|
3
|
+
`))g.trim()&&p.write(`[build] ${g}
|
|
4
|
+
`)},"relayOut");return c.stdout?.on("data",l(process.stdout)),c.stderr?.on("data",l(process.stderr)),c.on("message",p=>{if(p?.type==="member"){const m=d.get(p.member);m&&b(m.proc,p.event)}}),c.on("exit",(p,m)=>{if(e===c&&(e=void 0),S||r.stopped())return;const g=Date.now();if(a=[...a.filter(w=>g-w<CRASH_WINDOW_MS),g],a.length>=exports.HOST_MAX_RESTARTS){n=`the build host exited ${a.length} times in a minute (last: ${p??m})`,f(`[gateway] ${n} \u2014 every service compiles on its own from now on`);for(const w of d.values())b(w.proc,{type:"refused",reason:n});d.clear();return}if(d.size!==0&&(f(`[gateway] build host exited (${p??m}) \u2014 restarting it for ${d.size} service tree(s)`),N()))for(const[w,{join:P}]of d)R({type:"join",member:w,join:P})}),c},"start"),k=i(t=>{const s=v.get(t);!s||d.get(s)?.proc!==t||(d.delete(s),R({type:"leave",member:s}))},"detach");return{offered:i(()=>!!u&&!n,"offered"),attach:i((t,s)=>{v.set(s,t),s.on("message",c=>{if((0,protocol_1.isRunnerJoinMessage)(c)){if(n||!N()){b(s,{type:"refused",reason:n??"the build host could not be started"});return}d.set(t,{proc:s,join:c.join}),R({type:"join",member:t,join:c.join})}}),s.once("exit",()=>k(s))},"attach"),detach:k,hostPid:i(()=>e?.pid,"hostPid"),stop(){S=!0,d.clear();const t=e;return e=void 0,!t||t.exitCode!==null||t.signalCode!==null?Promise.resolve():new Promise(s=>{const c=i(()=>{clearTimeout(l),s()},"done");t.once("exit",c);try{process.kill(-t.pid,"SIGTERM")}catch{try{t.kill("SIGTERM")}catch{}}const l=setTimeout(()=>{try{process.kill(-t.pid,"SIGKILL")}catch{try{t.kill("SIGKILL")}catch{}}s()},6e3);l.unref?.()})}}}y(createWorkspaceRelay,"createWorkspaceRelay"),i(createWorkspaceRelay,"createWorkspaceRelay");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var k=Object.defineProperty;var b=(e,t)=>k(e,"name",{value:t,configurable:!0});var C=Object.defineProperty,g=b((e,t)=>C(e,"name",{value:t,configurable:!0}),"g"),U=Object.defineProperty,u=g((e,t)=>U(e,"name",{value:t,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.sourceSame=exports.sourceFull=exports.sourceStaleAfterMs=exports.SOURCE_BACKOFF_MAX_MS=exports.SOURCE_DECLARATION_REPORT_MS=exports.SOURCE_NOT_RUNNING_REPORT_MS=exports.SOURCE_MAX_PER_SERVICE=exports.SOURCE_MAX_GROUPS=exports.SOURCE_MAX_BYTES=exports.SOURCE_ERROR_MAX=exports.LOOP_MAX_INTERVAL_SEC=exports.SOURCE_FULL_REPORT_MS=exports.TRAFFIC_DEFAULT_RATE_LIMITED=exports.TRAFFIC_DEFAULT_P95_MS=exports.TRAFFIC_DEFAULT_FAILURE_PCT=exports.STORE_DEFAULT_ORPHAN_MIN=exports.STORE_DEFAULT_ERROR_RATE_PCT=exports.STORE_DEFAULT_QUOTA_PCT=exports.LOOP_DEFAULT_IDLE_MIN=exports.QUEUE_DEFAULT_STALLED_MIN=exports.QUEUE_DEFAULT_OLDEST_WAIT_MIN=exports.SOURCE_MIN_INTERVAL_SEC=exports.SOURCE_DEFAULT_INTERVAL_SEC=exports.TRAFFIC_DIRECTIONS=exports.LOOP_OUTCOMES=exports.SOURCE_SNAPSHOT_FIELD=exports.TRAFFIC_WIRE_SCHEMA=exports.STORE_WIRE_SCHEMA=exports.LOOP_WIRE_SCHEMA=exports.QUEUE_WIRE_SCHEMA=exports.SOURCE_KINDS_READ=exports.SOURCE_KINDS=exports.sourcesConcurrency=exports.sourcesTimeoutMs=exports.sourcesEnabled=void 0,exports.sourceBackoffMs=sourceBackoffMs,exports.parseSourceDecls=parseSourceDecls,exports.parseQueueSnapshot=parseQueueSnapshot,exports.parseLoopSnapshot=parseLoopSnapshot,exports.parseStoreSnapshot=parseStoreSnapshot,exports.parseTrafficSnapshot=parseTrafficSnapshot,exports.sourceDigest=sourceDigest,exports.keepQueueSnapshot=keepQueueSnapshot,exports.keepLoopSnapshot=keepLoopSnapshot,exports.keepStoreSnapshot=keepStoreSnapshot,exports.keepTrafficSnapshot=keepTrafficSnapshot,exports.buildSourcePollRaw=buildSourcePollRaw,exports.buildSourceDeclarationRaw=buildSourceDeclarationRaw,exports.sourcePollTitle=sourcePollTitle,exports.requestOverSocket=requestOverSocket,exports.createSourcePoller=createSourcePoller;const tslib_1=require("tslib"),node_crypto_1=require("node:crypto"),http=tslib_1.__importStar(require("node:http")),discovery_1=require("./discovery"),readEnv=u(e=>process.env[e],"readEnv"),envInt=u((e,t,s)=>{const n=Number(readEnv(e));return Number.isInteger(n)&&n>=s?n:t},"envInt"),sourcesEnabled=u(()=>readEnv("LENSMCP_SOURCES")!=="0","sourcesEnabled");exports.sourcesEnabled=sourcesEnabled;const sourcesTimeoutMs=u(()=>envInt("LENSMCP_SOURCES_TIMEOUT_MS",3e3,100),"sourcesTimeoutMs");exports.sourcesTimeoutMs=sourcesTimeoutMs;const sourcesConcurrency=u(()=>envInt("LENSMCP_SOURCES_CONCURRENCY",4,1),"sourcesConcurrency");exports.sourcesConcurrency=sourcesConcurrency,exports.SOURCE_KINDS=["queue","loop","store","traffic"],exports.SOURCE_KINDS_READ=["queue","loop","store","traffic"],exports.QUEUE_WIRE_SCHEMA="lensmcp.queue/v1",exports.LOOP_WIRE_SCHEMA="lensmcp.loop/v1",exports.STORE_WIRE_SCHEMA="lensmcp.store/v1",exports.TRAFFIC_WIRE_SCHEMA="lensmcp.traffic/v1",exports.SOURCE_SNAPSHOT_FIELD={queue:"snapshot",loop:"loop",store:"store",traffic:"traffic"},exports.LOOP_OUTCOMES=["ok","failed","skipped"],exports.TRAFFIC_DIRECTIONS=["inbound","outbound"],exports.SOURCE_DEFAULT_INTERVAL_SEC=10,exports.SOURCE_MIN_INTERVAL_SEC=2,exports.QUEUE_DEFAULT_OLDEST_WAIT_MIN=10,exports.QUEUE_DEFAULT_STALLED_MIN=15,exports.LOOP_DEFAULT_IDLE_MIN=10,exports.STORE_DEFAULT_QUOTA_PCT=90,exports.STORE_DEFAULT_ERROR_RATE_PCT=5,exports.STORE_DEFAULT_ORPHAN_MIN=60,exports.TRAFFIC_DEFAULT_FAILURE_PCT=5,exports.TRAFFIC_DEFAULT_P95_MS=2e3,exports.TRAFFIC_DEFAULT_RATE_LIMITED=1,exports.SOURCE_FULL_REPORT_MS=6e4,exports.LOOP_MAX_INTERVAL_SEC=86400,exports.SOURCE_ERROR_MAX=500,exports.SOURCE_MAX_BYTES=256*1024,exports.SOURCE_MAX_GROUPS=500,exports.SOURCE_MAX_PER_SERVICE=16,exports.SOURCE_NOT_RUNNING_REPORT_MS=6e4,exports.SOURCE_DECLARATION_REPORT_MS=5*6e4,exports.SOURCE_BACKOFF_MAX_MS=6e4;const sourceStaleAfterMs=u(e=>Math.max(3e4,3*Math.max(0,e)),"sourceStaleAfterMs");exports.sourceStaleAfterMs=sourceStaleAfterMs;function sourceBackoffMs(e,t){return t<=1?e:Math.min(e*2**Math.min(t-1,10),Math.max(e,exports.SOURCE_BACKOFF_MAX_MS))}b(sourceBackoffMs,"sourceBackoffMs"),g(sourceBackoffMs,"sourceBackoffMs"),u(sourceBackoffMs,"sourceBackoffMs");const isPolled=u(e=>e.path!==void 0,"isPolled"),ENTRY_KEYS={queue:["kind","name","path","intervalSec","thresholds"],loop:["kind","name","path","intervalSec","thresholds","feeds"],store:["kind","name","path","intervalSec","thresholds"],traffic:["kind","name","path","intervalSec","thresholds"]},finite=u(e=>typeof e=="number"&&Number.isFinite(e),"finite"),MINUTES={ok:u(e=>finite(e)&&e>0&&e<=10080,"ok"),must:"must be minutes, more than 0 and at most 10080"},PERCENT={ok:u(e=>finite(e)&&e>0&&e<=100,"ok"),must:"must be a percent, more than 0 and at most 100"},MILLISECONDS={ok:u(e=>finite(e)&&e>0&&e<=6e5,"ok"),must:"must be milliseconds, more than 0 and at most 600000"},COUNT={ok:u(e=>Number.isInteger(e)&&e>=1&&e<=1e6,"ok"),must:"must be a count, a whole number from 1 to 1000000"},THRESHOLDS={queue:{oldestWaitMin:{def:exports.QUEUE_DEFAULT_OLDEST_WAIT_MIN,...MINUTES},stalledMin:{def:exports.QUEUE_DEFAULT_STALLED_MIN,...MINUTES}},loop:{idleMin:{def:exports.LOOP_DEFAULT_IDLE_MIN,...MINUTES}},store:{quotaPct:{def:exports.STORE_DEFAULT_QUOTA_PCT,...PERCENT},errorRatePct:{def:exports.STORE_DEFAULT_ERROR_RATE_PCT,...PERCENT},orphanMin:{def:exports.STORE_DEFAULT_ORPHAN_MIN,...MINUTES}},traffic:{failurePct:{def:exports.TRAFFIC_DEFAULT_FAILURE_PCT,...PERCENT},p95Ms:{def:exports.TRAFFIC_DEFAULT_P95_MS,...MILLISECONDS},rateLimited:{def:exports.TRAFFIC_DEFAULT_RATE_LIMITED,...COUNT}}},PATH_RE=/^\/(?!\/)[^\s#\u0000-\u001f\u007f]{0,511}$/,NAME_RE=/^[^\u0000-\u001f\u007f]{1,100}$/,isObj=u(e=>typeof e=="object"&&e!==null&&!Array.isArray(e),"isObj");function parseSourceDecls(e){const t=[],s=[],n=[];if(e===void 0)return{sources:t,problems:s};if(!Array.isArray(e))return{sources:t,problems:["`sources` is not a list of { kind, name, path } entries \u2014 no source is read"]};e.forEach((i,l)=>{const S=`sources[${l}]`;if(!isObj(i)){s.push(`${S} is not an object \u2014 not read`);return}const d=typeof i.name=="string"&&i.name.trim()?`${S} "${i.name}"`:S,r=i.kind;if(typeof r!="string"||!exports.SOURCE_KINDS_READ.includes(r)){s.push(`${d}: kind ${JSON.stringify(r??null)} is not a source kind (${exports.SOURCE_KINDS.join(", ")}) \u2014 not read`);return}const a=r,p=Object.keys(i).filter(_=>!ENTRY_KEYS[a].includes(_));if(p.length){s.push(`${d}: unknown key${p.length===1?"":"s"} ${p.map(_=>JSON.stringify(_)).join(", ")} for a ${a} source (known: ${ENTRY_KEYS[a].join(", ")}) \u2014 not read`);return}const R=i.name;if(typeof R!="string"||!R.trim()||!NAME_RE.test(R)){s.push(`${S}: name ${JSON.stringify(R??null)} must be 1\u2013100 characters, not blank \u2014 not read`);return}if(t.some(_=>_.name===R)){s.push(`${d}: the name is declared twice on this service \u2014 read once`);return}const h=i.path;if(h===void 0&&a!=="traffic"&&a!=="loop"){s.push(`${d}: a ${a} source needs a path \u2014 the route on the service that answers "lensmcp.${a}/v1" (only a loop or a traffic source may go without one, as push-only) \u2014 not read`);return}if(h!==void 0&&(typeof h!="string"||!PATH_RE.test(h)||h.split("?")[0].split("/").includes(".."))){s.push(`${d}: path ${JSON.stringify(h)} must be a route on the service, starting with "/" (e.g. "/api/dev/lens/backlog") \u2014 not read`);return}const m=i.intervalSec;if(m!==void 0&&!(typeof m=="number"&&Number.isInteger(m)&&m>=exports.SOURCE_MIN_INTERVAL_SEC&&m<=3600)){s.push(`${d}: intervalSec ${JSON.stringify(m)} must be a whole number of seconds from ${exports.SOURCE_MIN_INTERVAL_SEC} to 3600 \u2014 not read`);return}const A=i.thresholds;if(A!==void 0&&!isObj(A)){s.push(`${d}: thresholds must be an object \u2014 not read`);return}const I=isObj(A)?A:{},x=THRESHOLDS[a],o=Object.keys(x),c=Object.keys(I).filter(_=>!o.includes(_));if(c.length){s.push(`${d}: unknown threshold${c.length===1?"":"s"} ${c.map(_=>JSON.stringify(_)).join(", ")} for a ${a} source (known: ${o.join(", ")}) \u2014 not read`);return}const f=o.find(_=>I[_]!==void 0&&!x[_].ok(I[_]));if(f){s.push(`${d}: thresholds.${f} ${JSON.stringify(I[f])} ${x[f].must} \u2014 not read`);return}if(t.length>=exports.SOURCE_MAX_PER_SERVICE){s.push(`${d}: more than ${exports.SOURCE_MAX_PER_SERVICE} sources on one service \u2014 not read`);return}const O={};for(const _ of o)O[_]=I[_]??x[_].def;const E={kind:a,name:R,...h!==void 0?{path:h}:{},intervalSec:m??exports.SOURCE_DEFAULT_INTERVAL_SEC,thresholds:O};t.push(E),a==="loop"&&i.feeds!==void 0&&n.push({decl:E,label:d,feeds:i.feeds})});for(const{decl:i,label:l,feeds:S}of n)typeof S!="string"||!S.trim()?s.push(`${l}: feeds ${JSON.stringify(S)} must be the name of a queue source on this service \u2014 read without it`):t.some(d=>d.kind==="queue"&&d.name===S)?i.feeds=S:s.push(`${l}: feeds ${JSON.stringify(S)} names no queue source on this service \u2014 read without it`);return{sources:t,problems:s}}b(parseSourceDecls,"parseSourceDecls"),g(parseSourceDecls,"parseSourceDecls"),u(parseSourceDecls,"parseSourceDecls");const ISO_RE=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})$/,isIso=u(e=>typeof e=="string"&&ISO_RE.test(e)&&!Number.isNaN(Date.parse(e)),"isIso"),isCount=u(e=>typeof e=="number"&&Number.isSafeInteger(e)&&e>=0,"isCount"),notSchema=u((e,t)=>`schema is ${e===void 0?"absent":JSON.stringify(e).slice(0,60)}, not "${t}"`,"notSchema"),keyWrong=u((e,t,s)=>{if(typeof e!="string"||e.length===0||e.length>200)return`${t}.key must be a string of 1\u2013200 characters`;if(s.has(e))return`${t}.key ${JSON.stringify(e)} appears twice`;s.add(e)},"keyWrong"),labelsWrong=u((e,t)=>{if(e===void 0)return;if(!isObj(e))return`${t}.labels must be an object of strings`;const s=Object.entries(e);if(s.length>16)return`${t}.labels has more than 16 entries`;for(const[n,i]of s)if(n.length===0||n.length>64||typeof i!="string"||i.length>200)return`${t}.labels.${n.slice(0,64)} must be a string of at most 200 characters`},"labelsWrong"),overCap=u((e,t)=>`${e} ${t} \u2014 at most ${exports.SOURCE_MAX_GROUPS}; cap them and say \`truncated: { ${t}: <dropped> }\``,"overCap");function parseQueueSnapshot(e){const t=u(d=>({ok:!1,reason:d}),"fail");if(!isObj(e))return t("the snapshot is not a JSON object");if(e.schema!==exports.QUEUE_WIRE_SCHEMA)return t(notSchema(e.schema,exports.QUEUE_WIRE_SCHEMA));const s=e.at;if(!isIso(s))return t("`at` is not an ISO time");const n=e.truncated;if(n!==void 0&&!(isObj(n)&&isCount(n.groups)))return t("`truncated` must be { groups: <how many were dropped> }, or absent");const i=e.groups;if(!Array.isArray(i))return t("`groups` is not a list");if(i.length>exports.SOURCE_MAX_GROUPS)return t(overCap(i.length,"groups"));const l=new Set,S=[];for(let d=0;d<i.length;d++){const r=i[d],a=`groups[${d}]`;if(!isObj(r))return t(`${a} is not an object`);const p=keyWrong(r.key,a,l);if(p)return t(p);if(!isCount(r.pending))return t(`${a}.pending must be a whole number \u2265 0`);for(const A of["inFlight","failed","completedInWindow"])if(r[A]!==void 0&&!isCount(r[A]))return t(`${a}.${A} must be a whole number \u2265 0, or absent`);const R=r.oldestPendingAt;if(R!=null&&!isIso(R))return t(`${a}.oldestPendingAt must be an ISO time, null, or absent`);const h=r.labels,m=labelsWrong(h,a);if(m)return t(m);S.push({key:r.key,...h!==void 0?{labels:h}:{},pending:r.pending,...r.inFlight!==void 0?{inFlight:r.inFlight}:{},...r.failed!==void 0?{failed:r.failed}:{},...R!==void 0?{oldestPendingAt:R}:{},...r.completedInWindow!==void 0?{completedInWindow:r.completedInWindow}:{}})}return{ok:!0,at:s,groups:S,...n!==void 0?{truncated:{groups:n.groups}}:{}}}b(parseQueueSnapshot,"parseQueueSnapshot"),g(parseQueueSnapshot,"parseQueueSnapshot"),u(parseQueueSnapshot,"parseQueueSnapshot");const LOOP_COUNTS=["lastDurationMs","lastItems","runsInWindow","itemsInWindow","failuresInWindow","windowSec"],cutText=u((e,t)=>{if(e.length<=t)return e;const s=t-1,n=e.charCodeAt(s-1);return`${e.slice(0,n>=55296&&n<=56319?s-1:s)}\u2026`},"cutText");function parseLoopSnapshot(e){const t=u(a=>({ok:!1,reason:a}),"fail");if(!isObj(e))return t("the snapshot is not a JSON object");if(e.schema!==exports.LOOP_WIRE_SCHEMA)return t(notSchema(e.schema,exports.LOOP_WIRE_SCHEMA));const s=e.at;if(!isIso(s))return t("`at` is not an ISO time");const n=e.intervalSec;if(!(typeof n=="number"&&Number.isFinite(n)&&n>0&&n<=exports.LOOP_MAX_INTERVAL_SEC))return t(`\`intervalSec\` must be the loop's own period in seconds, more than 0 and at most ${exports.LOOP_MAX_INTERVAL_SEC}`);const i=e.lastRunAt;if(i===void 0)return t("`lastRunAt` is absent \u2014 say null if the loop has not run since the service started");if(i!==null&&!isIso(i))return t("`lastRunAt` must be an ISO time, or null if the loop has not run since the service started");for(const a of LOOP_COUNTS)if(e[a]!==void 0&&!isCount(e[a]))return t(`\`${a}\` must be a whole number \u2265 0, or absent`);const l=e.lastOutcome;if(l!==void 0&&!exports.LOOP_OUTCOMES.includes(l))return t(`\`lastOutcome\` must be ${exports.LOOP_OUTCOMES.join(", ")}, or absent`);const S=e.nextRunAt;if(S!=null&&!isIso(S))return t("`nextRunAt` must be an ISO time, null, or absent");const d=e.lastError;if(d!==void 0&&typeof d!="string")return t("`lastError` must be a string, or absent");const r=u(a=>e[a]!==void 0?{[a]:e[a]}:{},"count");return{ok:!0,loop:{at:s,intervalSec:n,lastRunAt:i,...r("lastDurationMs"),...l!==void 0?{lastOutcome:l}:{},...r("lastItems"),...S!==void 0?{nextRunAt:S}:{},...r("runsInWindow"),...r("itemsInWindow"),...r("failuresInWindow"),...r("windowSec"),...d!==void 0?{lastError:cutText(d,exports.SOURCE_ERROR_MAX)}:{}}}}b(parseLoopSnapshot,"parseLoopSnapshot"),g(parseLoopSnapshot,"parseLoopSnapshot"),u(parseLoopSnapshot,"parseLoopSnapshot");const STORE_COUNTS=["opsInWindow","writesInWindow","deletesInWindow","errorsInWindow","windowSec"];function parseStoreSnapshot(e){const t=u(p=>({ok:!1,reason:p}),"fail");if(!isObj(e))return t("the snapshot is not a JSON object");if(e.schema!==exports.STORE_WIRE_SCHEMA)return t(notSchema(e.schema,exports.STORE_WIRE_SCHEMA));const s=e.at;if(!isIso(s))return t("`at` is not an ISO time");for(const p of["objects","bytes"])if(!isCount(e[p]))return t(`\`${p}\` must be a whole number \u2265 0`);const n=e.quotaBytes;if(n!=null&&!isCount(n))return t("`quotaBytes` must be a whole number \u2265 0, null when it has no quota, or absent");for(const p of STORE_COUNTS)if(e[p]!==void 0&&!isCount(e[p]))return t(`\`${p}\` must be a whole number \u2265 0, or absent`);const i=e.lastWriteAt;if(i!=null&&!isIso(i))return t("`lastWriteAt` must be an ISO time, null, or absent");const l=e.lastError;if(l!==void 0&&typeof l!="string")return t("`lastError` must be a string, or absent");const S=e.truncated;if(S!==void 0&&!(isObj(S)&&isCount(S.groups)))return t("`truncated` must be { groups: <how many were dropped> }, or absent");const d=e.groups;let r;if(d!==void 0){if(!Array.isArray(d))return t("`groups` must be a list, or absent");if(d.length>exports.SOURCE_MAX_GROUPS)return t(overCap(d.length,"groups"));const p=new Set;r=[];for(let R=0;R<d.length;R++){const h=d[R],m=`groups[${R}]`;if(!isObj(h))return t(`${m} is not an object`);const A=keyWrong(h.key,m,p);if(A)return t(A);for(const o of["objects","bytes"])if(!isCount(h[o]))return t(`${m}.${o} must be a whole number \u2265 0`);const I=h.labels,x=labelsWrong(I,m);if(x)return t(x);r.push({key:h.key,...I!==void 0?{labels:I}:{},objects:h.objects,bytes:h.bytes})}}const a=u(p=>e[p]!==void 0?{[p]:e[p]}:{},"count");return{ok:!0,store:{at:s,objects:e.objects,bytes:e.bytes,...n!==void 0?{quotaBytes:n}:{},...a("opsInWindow"),...a("writesInWindow"),...a("deletesInWindow"),...a("errorsInWindow"),...a("windowSec"),...i!==void 0?{lastWriteAt:i}:{},...l!==void 0?{lastError:cutText(l,exports.SOURCE_ERROR_MAX)}:{},...r?{groups:r}:{},...S!==void 0?{truncated:{groups:S.groups}}:{}}}}b(parseStoreSnapshot,"parseStoreSnapshot"),g(parseStoreSnapshot,"parseStoreSnapshot"),u(parseStoreSnapshot,"parseStoreSnapshot");const TRAFFIC_COUNTS=["messagesInWindow","failuresInWindow","rateLimitedInWindow"];function parseTrafficSnapshot(e){const t=u(r=>({ok:!1,reason:r}),"fail");if(!isObj(e))return t("the snapshot is not a JSON object");if(e.schema!==exports.TRAFFIC_WIRE_SCHEMA)return t(notSchema(e.schema,exports.TRAFFIC_WIRE_SCHEMA));const s=e.at;if(!isIso(s))return t("`at` is not an ISO time");const n=e.windowSec;if(n!==void 0&&!isCount(n))return t("`windowSec` must be a whole number \u2265 0, or absent");const i=e.truncated;if(i!==void 0&&!(isObj(i)&&isCount(i.channels)))return t("`truncated` must be { channels: <how many were dropped> }, or absent");const l=e.channels;if(!Array.isArray(l))return t("`channels` is not a list");if(l.length>exports.SOURCE_MAX_GROUPS)return t(overCap(l.length,"channels"));const S=new Set,d=[];for(let r=0;r<l.length;r++){const a=l[r],p=`channels[${r}]`;if(!isObj(a))return t(`${p} is not an object`);const R=keyWrong(a.key,p,S);if(R)return t(R);const h=a.direction;if(h!==void 0&&!exports.TRAFFIC_DIRECTIONS.includes(h))return t(`${p}.direction must be ${exports.TRAFFIC_DIRECTIONS.join(", ")}, or absent`);const m=a.counterpart;if(m!==void 0&&!(typeof m=="string"&&m.length>0&&m.length<=200))return t(`${p}.counterpart must be a string of 1\u2013200 characters, or absent`);for(const O of TRAFFIC_COUNTS)if(a[O]!==void 0&&!isCount(a[O]))return t(`${p}.${O} must be a whole number \u2265 0, or absent`);const A=a.p95Ms;if(A!==void 0&&!(finite(A)&&A>=0))return t(`${p}.p95Ms must be milliseconds \u2265 0, or absent`);const I=a.lastAt;if(I!=null&&!isIso(I))return t(`${p}.lastAt must be an ISO time, null, or absent`);const x=a.lastError;if(x!==void 0&&typeof x!="string")return t(`${p}.lastError must be a string, or absent`);const o=a.labels,c=labelsWrong(o,p);if(c)return t(c);const f=u(O=>a[O]!==void 0?{[O]:a[O]}:{},"count");d.push({key:a.key,...o!==void 0?{labels:o}:{},...h!==void 0?{direction:h}:{},...m!==void 0?{counterpart:m}:{},...f("messagesInWindow"),...f("failuresInWindow"),...f("rateLimitedInWindow"),...A!==void 0?{p95Ms:A}:{},...I!==void 0?{lastAt:I}:{},...x!==void 0?{lastError:cutText(x,exports.SOURCE_ERROR_MAX)}:{}})}return{ok:!0,traffic:{at:s,...n!==void 0?{windowSec:n}:{},channels:d,...i!==void 0?{truncated:{channels:i.channels}}:{}}}}b(parseTrafficSnapshot,"parseTrafficSnapshot"),g(parseTrafficSnapshot,"parseTrafficSnapshot"),u(parseTrafficSnapshot,"parseTrafficSnapshot");const sourceFull=u((e,t)=>({[exports.SOURCE_SNAPSHOT_FIELD[e]]:t}),"sourceFull");exports.sourceFull=sourceFull;const declRaw=u(e=>({sourceKind:e.kind,name:e.name,...e.path!==void 0?{path:e.path}:{},intervalSec:e.intervalSec,thresholds:{...e.thresholds},...e.feeds!==void 0?{feeds:e.feeds}:{}}),"declRaw"),canonical=u(e=>{if(Array.isArray(e))return e.map(canonical);if(!isObj(e))return e;const t={};for(const s of Object.keys(e).sort())t[s]=canonical(e[s]);return t},"canonical");function sourceDigest(e){return(0,node_crypto_1.createHash)("sha1").update(JSON.stringify(canonical(e))??"null").digest("hex").slice(0,16)}b(sourceDigest,"sourceDigest"),g(sourceDigest,"sourceDigest"),u(sourceDigest,"sourceDigest");const oldestOf=u(e=>e.pending>0&&e.oldestPendingAt?Date.parse(e.oldestPendingAt):Number.POSITIVE_INFINITY,"oldestOf");function keepQueueSnapshot(e,t,s,n){const i={groups:t.length,pending:0,inFlight:0,failed:0};let l;for(const r of t)i.pending+=r.pending,i.inFlight+=r.inFlight??0,i.failed+=r.failed??0,r.completedInWindow!==void 0&&(l=(l??0)+r.completedInWindow);l!==void 0&&(i.completedInWindow=l);const S=[...t].sort((r,a)=>oldestOf(r)-oldestOf(a)||a.pending-r.pending||(r.key<a.key?-1:r.key>a.key?1:0)).map(({key:r,...a})=>({group:r,...a})),d=n?{groups:n.groups}:void 0;return{at:e,receivedAt:s,totals:i,groups:S,...d?{truncated:d}:{},digest:sourceDigest({groups:S,truncated:d??null})}}b(keepQueueSnapshot,"keepQueueSnapshot"),g(keepQueueSnapshot,"keepQueueSnapshot"),u(keepQueueSnapshot,"keepQueueSnapshot");function keepLoopSnapshot(e,t){const{at:s,...n}=e;return{at:s,receivedAt:t,digest:sourceDigest(n),...n}}b(keepLoopSnapshot,"keepLoopSnapshot"),g(keepLoopSnapshot,"keepLoopSnapshot"),u(keepLoopSnapshot,"keepLoopSnapshot");const byKey=u((e,t)=>e<t?-1:e>t?1:0,"byKey");function keepStoreSnapshot(e,t){const{at:s,groups:n,truncated:i,...l}=e,S=n?[...n].sort((r,a)=>a.bytes-r.bytes||a.objects-r.objects||byKey(r.key,a.key)).map(({key:r,...a})=>({group:r,...a})):void 0,d={...l,...S?{groups:S}:{},...i?{truncated:{groups:i.groups}}:{}};return{at:s,receivedAt:t,digest:sourceDigest(d),...d}}b(keepStoreSnapshot,"keepStoreSnapshot"),g(keepStoreSnapshot,"keepStoreSnapshot"),u(keepStoreSnapshot,"keepStoreSnapshot");const messagesOf=u(e=>e.messagesInWindow??-1,"messagesOf");function keepTrafficSnapshot(e,t){const{at:s,channels:n,truncated:i,...l}=e,S=[...n].sort((r,a)=>messagesOf(a)-messagesOf(r)||byKey(r.key,a.key)).map(({key:r,...a})=>({channel:r,...a})),d={...l,channels:S,...i?{truncated:{channels:i.channels}}:{}};return{at:s,receivedAt:t,digest:sourceDigest(d),...d}}b(keepTrafficSnapshot,"keepTrafficSnapshot"),g(keepTrafficSnapshot,"keepTrafficSnapshot"),u(keepTrafficSnapshot,"keepTrafficSnapshot");const sourceSame=u(e=>({digest:e.digest,at:e.at,receivedAt:e.receivedAt}),"sourceSame");exports.sourceSame=sourceSame;function buildSourcePollRaw(e,t,s,n,i,l){return{kind:"source-poll",provenance:"reported",project:e,...declRaw(t),state:s.state,...s.detail!==void 0?{detail:s.detail}:{},...s.status!==void 0?{status:s.status}:{},polledAt:s.polledAt,...s.durationMs!==void 0?{durationMs:s.durationMs}:{},reportEveryMs:n,...i>0?{failures:i}:{},...l??{}}}b(buildSourcePollRaw,"buildSourcePollRaw"),g(buildSourcePollRaw,"buildSourcePollRaw"),u(buildSourcePollRaw,"buildSourcePollRaw");function buildSourceDeclarationRaw(e,t){return{kind:"source-declaration",project:e,sources:t.sources.map(declRaw),problems:[...t.problems]}}b(buildSourceDeclarationRaw,"buildSourceDeclarationRaw"),g(buildSourceDeclarationRaw,"buildSourceDeclarationRaw"),u(buildSourceDeclarationRaw,"buildSourceDeclarationRaw");const span=u(e=>{const t=Math.round(e/6e4);return e<6e4?`${Math.max(0,Math.round(e/1e3))}s`:t<120?`${t}m`:`${Math.floor(t/60)}h${t%60?` ${t%60}m`:""}`},"span"),loopWords=u(e=>`${e.lastRunAt===null?"has not run since the service started":`last run ${span(Math.max(0,Date.parse(e.at)-Date.parse(e.lastRunAt)))} before it was measured`}${e.lastOutcome?`, ${e.lastOutcome}`:""}${e.lastItems!==void 0?`, ${e.lastItems} item${e.lastItems===1?"":"s"}`:""}`,"loopWords"),plural=u((e,t)=>`${e} ${t}${e===1?"":"s"}`,"plural"),byteSize=u(e=>{const t=["B","kB","MB","GB","TB","PB"];let s=e,n=0;for(;s>=999.5&&n<t.length-1;)s/=1e3,n+=1;return n===0?`${e} B`:`${s<9.95?s.toFixed(1):Math.round(s)} ${t[n]}`},"byteSize"),storeWords=u(e=>{const t=typeof e.quotaBytes=="number"&&e.quotaBytes>0?` of ${byteSize(e.quotaBytes)} (${Math.round(e.bytes/e.quotaBytes*1e3)/10}%)`:"",s=e.errorsInWindow?`, ${plural(e.errorsInWindow,"error")}${e.windowSec?` in ${span(e.windowSec*1e3)}`:""}`:"";return`${plural(e.objects,"object")}, ${byteSize(e.bytes)}${t}${s}`},"storeWords"),trafficWords=u(e=>{let t,s=0,n=0;for(const l of e.channels)l.messagesInWindow!==void 0&&(t=(t??0)+l.messagesInWindow),s+=l.failuresInWindow??0,n+=l.rateLimitedInWindow??0;const i=t!==void 0?`, ${plural(t,"message")}${e.windowSec?` in ${span(e.windowSec*1e3)}`:""}`:"";return`${plural(e.channels.length,"channel")}${i}${s?`, ${s} failed`:""}${n?`, ${n} rate-limited`:""}`},"trafficWords");function sourcePollTitle(e,t){const s=`${e.sourceKind} ${e.project}/${e.name} (reported)`,n=t??e[exports.SOURCE_SNAPSHOT_FIELD[e.sourceKind]];if(e.state!=="current"||!n)return`${s}: ${e.state}${e.detail?` \u2014 ${e.detail}`:""}`;if(e.sourceKind==="loop")return`${s}: ${loopWords(n)}`;if(e.sourceKind==="store")return`${s}: ${storeWords(n)}`;if(e.sourceKind==="traffic")return`${s}: ${trafficWords(n)}`;const i=n,l=i.groups.find(d=>d.pending>0&&d.oldestPendingAt),S=l?.oldestPendingAt?Date.parse(i.at)-Date.parse(l.oldestPendingAt):void 0;return`${s}: ${i.totals.pending} pending in ${i.totals.groups} group${i.totals.groups===1?"":"s"}${S!==void 0?`, oldest waiting ${span(Math.max(0,S))}`:""}`}b(sourcePollTitle,"sourcePollTitle"),g(sourcePollTitle,"sourcePollTitle"),u(sourcePollTitle,"sourcePollTitle");function requestOverSocket(e,t,s,n,i=exports.SOURCE_MAX_BYTES){return new Promise(l=>{let S=!1,d;const r=u(p=>{S||(S=!0,clearTimeout(a),l(p))},"finish"),a=setTimeout(()=>{r({ok:!1,code:"ETIMEDOUT",message:`no answer within ${n} ms`}),d?.destroy()},n);a.unref?.();try{d=http.request({socketPath:e,path:t,method:"GET",agent:!1,headers:s},p=>{const R=[];let h=0;p.on("data",m=>{if(!S){if(h+=m.length,h>i){r({ok:!0,status:p.statusCode??0,body:"",truncated:!0}),p.destroy();return}R.push(m)}}),p.on("end",()=>r({ok:!0,status:p.statusCode??0,body:Buffer.concat(R).toString("utf8"),truncated:!1})),p.on("error",m=>r({ok:!1,code:m.code??"ERESPONSE",message:m.message}))}),d.on("error",p=>r({ok:!1,code:p.code??"EREQUEST",message:p.message})),d.end()}catch(p){r({ok:!1,code:p.code??"EREQUEST",message:p.message})}})}b(requestOverSocket,"requestOverSocket"),g(requestOverSocket,"requestOverSocket"),u(requestOverSocket,"requestOverSocket");const snippet=u(e=>e.replace(/\s+/g," ").trim().slice(0,160),"snippet");function readSnapshot(e,t,s){let n;try{n=JSON.parse(t)}catch{return{ok:!1,reason:`not JSON: ${snippet(t)||"(an empty body)"}`}}if(e==="loop"){const l=parseLoopSnapshot(n);return l.ok===!0?{ok:!0,kept:keepLoopSnapshot(l.loop,s)}:l}if(e==="store"){const l=parseStoreSnapshot(n);return l.ok===!0?{ok:!0,kept:keepStoreSnapshot(l.store,s)}:l}if(e==="traffic"){const l=parseTrafficSnapshot(n);return l.ok===!0?{ok:!0,kept:keepTrafficSnapshot(l.traffic,s)}:l}const i=parseQueueSnapshot(n);return i.ok===!0?{ok:!0,kept:keepQueueSnapshot(i.at,i.groups,s,i.truncated)}:i}b(readSnapshot,"readSnapshot"),g(readSnapshot,"readSnapshot"),u(readSnapshot,"readSnapshot");function createSourcePoller(e){const t=e.now??Date.now,s=e.timeoutMs??(0,exports.sourcesTimeoutMs)(),n=Math.max(1,e.maxConcurrent??(0,exports.sourcesConcurrency)()),i=e.socketOf??(o=>(0,discovery_1.pickSock)(o.pool,e.scanTtlMs??1500)),l=e.request??requestOverSocket,S=e.log??(o=>console.warn(o)),d=new WeakMap,r=new Map;let a=0,p;const R=u(o=>{const c=o.decl;let f=d.get(c);if(!f){f=parseSourceDecls(o.decl.sources),d.set(c,f);for(const E of f.problems)S(`[gateway] ${o.project}: cluster.sources \u2014 ${E}`)}const O=t();return(f.reportedAt===void 0||O-f.reportedAt>=exports.SOURCE_DECLARATION_REPORT_MS)&&(f.reportedAt=O,e.emit(o,f.problems.length?"warning":"info",f.problems.length?`sources ${o.project}: ${f.problems.length} cluster.sources entr${f.problems.length===1?"y":"ies"} not read \u2014 ${f.problems[0]}`:`sources ${o.project}: reads ${f.sources.map(E=>`${E.kind} "${E.name}"${isPolled(E)?"":" (push-only)"}`).join(", ")}`,`source-declaration:${o.wsKey}:${o.project}`,buildSourceDeclarationRaw(o.project,f))),f},"declarationOf"),h=u(o=>{if(o.state==="starting")return{notRunning:"it is starting \u2014 read once it is up"};const c=i(o);return c?{socket:c}:{notRunning:o.state==="up"?"it has no live pod socket \u2014 no pod runs it now":"it is scaled to zero \u2014 the lens does not start a service to read a source"}},"reach"),m=u((o,c)=>{const f=o.good;if(f)return o.full&&o.full.digest===f.digest&&c-o.full.at<exports.SOURCE_FULL_REPORT_MS?{same:(0,exports.sourceSame)(f)}:(o.full={digest:f.digest,at:c},(0,exports.sourceFull)(o.decl.kind,f))},"carried"),A=u((o,c)=>{const f=o.last;if(!f)return;const O=t();if(!c&&o.reportedAt!==void 0&&O-o.reportedAt<o.reportEveryMs)return;o.reportedAt=O;const E=buildSourcePollRaw(o.svc.project,o.decl,f,o.reportEveryMs,o.failures,m(o,O)),_=f.state==="unreachable"||f.state==="refused"||f.state==="malformed";e.emit(o.svc,_?"warning":"info",sourcePollTitle(E,o.good),`source:${o.svc.wsKey}:${o.svc.project}:${o.decl.name}`,E)},"report"),I=u(async o=>{const c=t(),f=o.decl.intervalSec*1e3;o.inFlight=!0,a+=1;const O=o.last?.state;try{const E=h(o.svc);if("notRunning"in E){o.last={state:"not-running",detail:E.notRunning,polledAt:c},o.failures=0,o.nextAt=c+f,o.reportEveryMs=exports.SOURCE_NOT_RUNNING_REPORT_MS,A(o,O!=="not-running");return}const _=e.serviceKey(o.svc),T=await l(E.socket,o.decl.path,{accept:"application/json","x-lensmcp-probe":`source:${o.decl.kind}`,..._?{"x-internal-token":_}:{}},s,exports.SOURCE_MAX_BYTES),$=Math.max(0,t()-c);if(T.ok===!1){const v=T.code==="ECONNREFUSED"||T.code==="ENOENT";o.last=v&&o.svc.state!=="up"?{state:"not-running",detail:`nothing listens on its pod socket \u2014 the service is ${o.svc.state}`,polledAt:c,durationMs:$}:{state:"unreachable",detail:T.code==="ETIMEDOUT"?T.message:`${T.code}: ${snippet(T.message)}`,polledAt:c,durationMs:$}}else if(T.status<200||T.status>299){const v=snippet(T.body);o.last={state:"refused",status:T.status,detail:`HTTP ${T.status}${v?`: ${v}`:""}`,polledAt:c,durationMs:$}}else if(T.truncated)o.last={state:"malformed",detail:`the snapshot is larger than ${exports.SOURCE_MAX_BYTES/1024} KiB`,polledAt:c,durationMs:$};else{const v=readSnapshot(o.decl.kind,T.body,t());v.ok===!0?(o.good=v.kept,o.last={state:"current",polledAt:c,durationMs:$}):o.last={state:"malformed",detail:v.reason,polledAt:c,durationMs:$}}const M=o.last.state==="unreachable"||o.last.state==="refused"||o.last.state==="malformed";o.failures=M?o.failures+1:0;const y=M?sourceBackoffMs(f,o.failures):f;o.nextAt=c+y,o.reportEveryMs=o.last.state==="not-running"?exports.SOURCE_NOT_RUNNING_REPORT_MS:y,A(o,o.last.state!=="not-running"||O!=="not-running")}catch(E){o.last={state:"unreachable",detail:`the poll failed: ${snippet(E?.message??String(E))}`,polledAt:c},o.failures+=1,o.nextAt=c+sourceBackoffMs(f,o.failures),o.reportEveryMs=o.nextAt-c,A(o,!0)}finally{o.inFlight=!1,a-=1}},"pollOne"),x=u(async()=>{if(e.stopped?.())return;const o=new Set;for(const E of e.services())if(E.decl.sources!==void 0)for(const _ of R(E).sources){if(!isPolled(_))continue;const T=`${E.wsKey} ${E.project} ${_.kind} ${_.name}`;o.add(T);const $=r.get(T);$?($.svc!==E||$.decl!==_)&&($.svc=E,$.decl=_):r.set(T,{svc:E,decl:_,nextAt:0,inFlight:!1,failures:0,reportEveryMs:_.intervalSec*1e3})}for(const[E,_]of[...r.entries()])!o.has(E)&&!_.inFlight&&r.delete(E);const c=t(),f=[...r.values()].filter(E=>!E.inFlight&&c>=E.nextAt).sort((E,_)=>E.nextAt-_.nextAt),O=[];for(const E of f){if(a>=n)break;O.push(I(E))}await Promise.all(O)},"tick");return{tick:x,start(o=1e3){return p&&clearInterval(p),p=setInterval(()=>{x().catch(c=>console.error("[gateway] source poll error:",c))},o),p.unref(),p},stop(){p&&clearInterval(p),p=void 0},snapshot(){const o=t();return[...r.values()].map(c=>{const f=c.last!==void 0&&o-c.last.polledAt>(0,exports.sourceStaleAfterMs)(c.reportEveryMs);return{wsKey:c.svc.wsKey,project:c.svc.project,name:c.decl.name,kind:c.decl.kind,path:c.decl.path,state:c.last?f?"stale":c.last.state:"never-polled",...c.last?.detail!==void 0?{detail:c.last.detail}:{},...c.last?.status!==void 0?{status:c.last.status}:{},...c.last?{polledAt:c.last.polledAt}:{},failures:c.failures,nextAt:c.nextAt,...c.good?{...(0,exports.sourceFull)(c.decl.kind,c.good),ageMs:Math.max(0,o-c.good.receivedAt)}:{}}})}}}b(createSourcePoller,"createSourcePoller"),g(createSourcePoller,"createSourcePoller"),u(createSourcePoller,"createSourcePoller");
|
|
1
|
+
"use strict";var C=Object.defineProperty;var g=(e,t)=>C(e,"name",{value:t,configurable:!0});var U=Object.defineProperty,u=g((e,t)=>U(e,"name",{value:t,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.sourceSame=exports.sourceFull=exports.sourceStaleAfterMs=exports.SOURCE_BACKOFF_MAX_MS=exports.SOURCE_DECLARATION_REPORT_MS=exports.SOURCE_NOT_RUNNING_REPORT_MS=exports.SOURCE_MAX_PER_SERVICE=exports.SOURCE_MAX_GROUPS=exports.SOURCE_MAX_BYTES=exports.SOURCE_ERROR_MAX=exports.LOOP_MAX_INTERVAL_SEC=exports.SOURCE_FULL_REPORT_MS=exports.TRAFFIC_DEFAULT_RATE_LIMITED=exports.TRAFFIC_DEFAULT_P95_MS=exports.TRAFFIC_DEFAULT_FAILURE_PCT=exports.STORE_DEFAULT_ORPHAN_MIN=exports.STORE_DEFAULT_ERROR_RATE_PCT=exports.STORE_DEFAULT_QUOTA_PCT=exports.LOOP_DEFAULT_IDLE_MIN=exports.QUEUE_DEFAULT_STALLED_MIN=exports.QUEUE_DEFAULT_OLDEST_WAIT_MIN=exports.SOURCE_MIN_INTERVAL_SEC=exports.SOURCE_DEFAULT_INTERVAL_SEC=exports.TRAFFIC_DIRECTIONS=exports.LOOP_OUTCOMES=exports.SOURCE_SNAPSHOT_FIELD=exports.TRAFFIC_WIRE_SCHEMA=exports.STORE_WIRE_SCHEMA=exports.LOOP_WIRE_SCHEMA=exports.QUEUE_WIRE_SCHEMA=exports.SOURCE_KINDS_READ=exports.SOURCE_KINDS=exports.sourcesConcurrency=exports.sourcesTimeoutMs=exports.sourcesEnabled=void 0,exports.sourceBackoffMs=sourceBackoffMs,exports.parseSourceDecls=parseSourceDecls,exports.parseQueueSnapshot=parseQueueSnapshot,exports.parseLoopSnapshot=parseLoopSnapshot,exports.parseStoreSnapshot=parseStoreSnapshot,exports.parseTrafficSnapshot=parseTrafficSnapshot,exports.sourceDigest=sourceDigest,exports.keepQueueSnapshot=keepQueueSnapshot,exports.keepLoopSnapshot=keepLoopSnapshot,exports.keepStoreSnapshot=keepStoreSnapshot,exports.keepTrafficSnapshot=keepTrafficSnapshot,exports.buildSourcePollRaw=buildSourcePollRaw,exports.buildSourceDeclarationRaw=buildSourceDeclarationRaw,exports.sourcePollTitle=sourcePollTitle,exports.requestOverSocket=requestOverSocket,exports.createSourcePoller=createSourcePoller;const tslib_1=require("tslib"),node_crypto_1=require("node:crypto"),http=tslib_1.__importStar(require("node:http")),discovery_1=require("./discovery"),readEnv=u(e=>process.env[e],"readEnv"),envInt=u((e,t,o)=>{const n=Number(readEnv(e));return Number.isInteger(n)&&n>=o?n:t},"envInt"),sourcesEnabled=u(()=>readEnv("LENSMCP_SOURCES")!=="0","sourcesEnabled");exports.sourcesEnabled=sourcesEnabled;const sourcesTimeoutMs=u(()=>envInt("LENSMCP_SOURCES_TIMEOUT_MS",3e3,100),"sourcesTimeoutMs");exports.sourcesTimeoutMs=sourcesTimeoutMs;const sourcesConcurrency=u(()=>envInt("LENSMCP_SOURCES_CONCURRENCY",4,1),"sourcesConcurrency");exports.sourcesConcurrency=sourcesConcurrency,exports.SOURCE_KINDS=["queue","loop","store","traffic"],exports.SOURCE_KINDS_READ=["queue","loop","store","traffic"],exports.QUEUE_WIRE_SCHEMA="lensmcp.queue/v1",exports.LOOP_WIRE_SCHEMA="lensmcp.loop/v1",exports.STORE_WIRE_SCHEMA="lensmcp.store/v1",exports.TRAFFIC_WIRE_SCHEMA="lensmcp.traffic/v1",exports.SOURCE_SNAPSHOT_FIELD={queue:"snapshot",loop:"loop",store:"store",traffic:"traffic"},exports.LOOP_OUTCOMES=["ok","failed","skipped"],exports.TRAFFIC_DIRECTIONS=["inbound","outbound"],exports.SOURCE_DEFAULT_INTERVAL_SEC=10,exports.SOURCE_MIN_INTERVAL_SEC=2,exports.QUEUE_DEFAULT_OLDEST_WAIT_MIN=10,exports.QUEUE_DEFAULT_STALLED_MIN=15,exports.LOOP_DEFAULT_IDLE_MIN=10,exports.STORE_DEFAULT_QUOTA_PCT=90,exports.STORE_DEFAULT_ERROR_RATE_PCT=5,exports.STORE_DEFAULT_ORPHAN_MIN=60,exports.TRAFFIC_DEFAULT_FAILURE_PCT=5,exports.TRAFFIC_DEFAULT_P95_MS=2e3,exports.TRAFFIC_DEFAULT_RATE_LIMITED=1,exports.SOURCE_FULL_REPORT_MS=6e4,exports.LOOP_MAX_INTERVAL_SEC=86400,exports.SOURCE_ERROR_MAX=500,exports.SOURCE_MAX_BYTES=256*1024,exports.SOURCE_MAX_GROUPS=500,exports.SOURCE_MAX_PER_SERVICE=16,exports.SOURCE_NOT_RUNNING_REPORT_MS=6e4,exports.SOURCE_DECLARATION_REPORT_MS=5*6e4,exports.SOURCE_BACKOFF_MAX_MS=6e4;const sourceStaleAfterMs=u(e=>Math.max(3e4,3*Math.max(0,e)),"sourceStaleAfterMs");exports.sourceStaleAfterMs=sourceStaleAfterMs;function sourceBackoffMs(e,t){return t<=1?e:Math.min(e*2**Math.min(t-1,10),Math.max(e,exports.SOURCE_BACKOFF_MAX_MS))}g(sourceBackoffMs,"sourceBackoffMs"),u(sourceBackoffMs,"sourceBackoffMs");const isPolled=u(e=>e.path!==void 0,"isPolled"),ENTRY_KEYS={queue:["kind","name","path","intervalSec","thresholds"],loop:["kind","name","path","intervalSec","thresholds","feeds"],store:["kind","name","path","intervalSec","thresholds"],traffic:["kind","name","path","intervalSec","thresholds"]},finite=u(e=>typeof e=="number"&&Number.isFinite(e),"finite"),MINUTES={ok:u(e=>finite(e)&&e>0&&e<=10080,"ok"),must:"must be minutes, more than 0 and at most 10080"},PERCENT={ok:u(e=>finite(e)&&e>0&&e<=100,"ok"),must:"must be a percent, more than 0 and at most 100"},MILLISECONDS={ok:u(e=>finite(e)&&e>0&&e<=6e5,"ok"),must:"must be milliseconds, more than 0 and at most 600000"},COUNT={ok:u(e=>Number.isInteger(e)&&e>=1&&e<=1e6,"ok"),must:"must be a count, a whole number from 1 to 1000000"},THRESHOLDS={queue:{oldestWaitMin:{def:exports.QUEUE_DEFAULT_OLDEST_WAIT_MIN,...MINUTES},stalledMin:{def:exports.QUEUE_DEFAULT_STALLED_MIN,...MINUTES}},loop:{idleMin:{def:exports.LOOP_DEFAULT_IDLE_MIN,...MINUTES}},store:{quotaPct:{def:exports.STORE_DEFAULT_QUOTA_PCT,...PERCENT},errorRatePct:{def:exports.STORE_DEFAULT_ERROR_RATE_PCT,...PERCENT},orphanMin:{def:exports.STORE_DEFAULT_ORPHAN_MIN,...MINUTES}},traffic:{failurePct:{def:exports.TRAFFIC_DEFAULT_FAILURE_PCT,...PERCENT},p95Ms:{def:exports.TRAFFIC_DEFAULT_P95_MS,...MILLISECONDS},rateLimited:{def:exports.TRAFFIC_DEFAULT_RATE_LIMITED,...COUNT}}},PATH_RE=/^\/(?!\/)[^\s#\u0000-\u001f\u007f]{0,511}$/,NAME_RE=/^[^\u0000-\u001f\u007f]{1,100}$/,isObj=u(e=>typeof e=="object"&&e!==null&&!Array.isArray(e),"isObj");function parseSourceDecls(e){const t=[],o=[],n=[];if(e===void 0)return{sources:t,problems:o};if(!Array.isArray(e))return{sources:t,problems:["`sources` is not a list of { kind, name, path } entries \u2014 no source is read"]};e.forEach((i,l)=>{const E=`sources[${l}]`;if(!isObj(i)){o.push(`${E} is not an object \u2014 not read`);return}const d=typeof i.name=="string"&&i.name.trim()?`${E} "${i.name}"`:E,r=i.kind;if(typeof r!="string"||!exports.SOURCE_KINDS_READ.includes(r)){o.push(`${d}: kind ${JSON.stringify(r??null)} is not a source kind (${exports.SOURCE_KINDS.join(", ")}) \u2014 not read`);return}const a=r,p=Object.keys(i).filter(_=>!ENTRY_KEYS[a].includes(_));if(p.length){o.push(`${d}: unknown key${p.length===1?"":"s"} ${p.map(_=>JSON.stringify(_)).join(", ")} for a ${a} source (known: ${ENTRY_KEYS[a].join(", ")}) \u2014 not read`);return}const R=i.name;if(typeof R!="string"||!R.trim()||!NAME_RE.test(R)){o.push(`${E}: name ${JSON.stringify(R??null)} must be 1\u2013100 characters, not blank \u2014 not read`);return}if(t.some(_=>_.name===R)){o.push(`${d}: the name is declared twice on this service \u2014 read once`);return}const h=i.path;if(h===void 0&&a!=="traffic"&&a!=="loop"){o.push(`${d}: a ${a} source needs a path \u2014 the route on the service that answers "lensmcp.${a}/v1" (only a loop or a traffic source may go without one, as push-only) \u2014 not read`);return}if(h!==void 0&&(typeof h!="string"||!PATH_RE.test(h)||h.split("?")[0].split("/").includes(".."))){o.push(`${d}: path ${JSON.stringify(h)} must be a route on the service, starting with "/" (e.g. "/api/dev/lens/backlog") \u2014 not read`);return}const m=i.intervalSec;if(m!==void 0&&!(typeof m=="number"&&Number.isInteger(m)&&m>=exports.SOURCE_MIN_INTERVAL_SEC&&m<=3600)){o.push(`${d}: intervalSec ${JSON.stringify(m)} must be a whole number of seconds from ${exports.SOURCE_MIN_INTERVAL_SEC} to 3600 \u2014 not read`);return}const A=i.thresholds;if(A!==void 0&&!isObj(A)){o.push(`${d}: thresholds must be an object \u2014 not read`);return}const b=isObj(A)?A:{},I=THRESHOLDS[a],s=Object.keys(I),c=Object.keys(b).filter(_=>!s.includes(_));if(c.length){o.push(`${d}: unknown threshold${c.length===1?"":"s"} ${c.map(_=>JSON.stringify(_)).join(", ")} for a ${a} source (known: ${s.join(", ")}) \u2014 not read`);return}const f=s.find(_=>b[_]!==void 0&&!I[_].ok(b[_]));if(f){o.push(`${d}: thresholds.${f} ${JSON.stringify(b[f])} ${I[f].must} \u2014 not read`);return}if(t.length>=exports.SOURCE_MAX_PER_SERVICE){o.push(`${d}: more than ${exports.SOURCE_MAX_PER_SERVICE} sources on one service \u2014 not read`);return}const O={};for(const _ of s)O[_]=b[_]??I[_].def;const S={kind:a,name:R,...h!==void 0?{path:h}:{},intervalSec:m??exports.SOURCE_DEFAULT_INTERVAL_SEC,thresholds:O};t.push(S),a==="loop"&&i.feeds!==void 0&&n.push({decl:S,label:d,feeds:i.feeds})});for(const{decl:i,label:l,feeds:E}of n)typeof E!="string"||!E.trim()?o.push(`${l}: feeds ${JSON.stringify(E)} must be the name of a queue source on this service \u2014 read without it`):t.some(d=>d.kind==="queue"&&d.name===E)?i.feeds=E:o.push(`${l}: feeds ${JSON.stringify(E)} names no queue source on this service \u2014 read without it`);return{sources:t,problems:o}}g(parseSourceDecls,"parseSourceDecls"),u(parseSourceDecls,"parseSourceDecls");const ISO_RE=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})$/,isIso=u(e=>typeof e=="string"&&ISO_RE.test(e)&&!Number.isNaN(Date.parse(e)),"isIso"),isCount=u(e=>typeof e=="number"&&Number.isSafeInteger(e)&&e>=0,"isCount"),notSchema=u((e,t)=>`schema is ${e===void 0?"absent":JSON.stringify(e).slice(0,60)}, not "${t}"`,"notSchema"),keyWrong=u((e,t,o)=>{if(typeof e!="string"||e.length===0||e.length>200)return`${t}.key must be a string of 1\u2013200 characters`;if(o.has(e))return`${t}.key ${JSON.stringify(e)} appears twice`;o.add(e)},"keyWrong"),labelsWrong=u((e,t)=>{if(e===void 0)return;if(!isObj(e))return`${t}.labels must be an object of strings`;const o=Object.entries(e);if(o.length>16)return`${t}.labels has more than 16 entries`;for(const[n,i]of o)if(n.length===0||n.length>64||typeof i!="string"||i.length>200)return`${t}.labels.${n.slice(0,64)} must be a string of at most 200 characters`},"labelsWrong"),overCap=u((e,t)=>`${e} ${t} \u2014 at most ${exports.SOURCE_MAX_GROUPS}; cap them and say \`truncated: { ${t}: <dropped> }\``,"overCap");function parseQueueSnapshot(e){const t=u(d=>({ok:!1,reason:d}),"fail");if(!isObj(e))return t("the snapshot is not a JSON object");if(e.schema!==exports.QUEUE_WIRE_SCHEMA)return t(notSchema(e.schema,exports.QUEUE_WIRE_SCHEMA));const o=e.at;if(!isIso(o))return t("`at` is not an ISO time");const n=e.truncated;if(n!==void 0&&!(isObj(n)&&isCount(n.groups)))return t("`truncated` must be { groups: <how many were dropped> }, or absent");const i=e.groups;if(!Array.isArray(i))return t("`groups` is not a list");if(i.length>exports.SOURCE_MAX_GROUPS)return t(overCap(i.length,"groups"));const l=new Set,E=[];for(let d=0;d<i.length;d++){const r=i[d],a=`groups[${d}]`;if(!isObj(r))return t(`${a} is not an object`);const p=keyWrong(r.key,a,l);if(p)return t(p);if(!isCount(r.pending))return t(`${a}.pending must be a whole number \u2265 0`);for(const A of["inFlight","failed","completedInWindow"])if(r[A]!==void 0&&!isCount(r[A]))return t(`${a}.${A} must be a whole number \u2265 0, or absent`);const R=r.oldestPendingAt;if(R!=null&&!isIso(R))return t(`${a}.oldestPendingAt must be an ISO time, null, or absent`);const h=r.labels,m=labelsWrong(h,a);if(m)return t(m);E.push({key:r.key,...h!==void 0?{labels:h}:{},pending:r.pending,...r.inFlight!==void 0?{inFlight:r.inFlight}:{},...r.failed!==void 0?{failed:r.failed}:{},...R!==void 0?{oldestPendingAt:R}:{},...r.completedInWindow!==void 0?{completedInWindow:r.completedInWindow}:{}})}return{ok:!0,at:o,groups:E,...n!==void 0?{truncated:{groups:n.groups}}:{}}}g(parseQueueSnapshot,"parseQueueSnapshot"),u(parseQueueSnapshot,"parseQueueSnapshot");const LOOP_COUNTS=["lastDurationMs","lastItems","runsInWindow","itemsInWindow","failuresInWindow","windowSec"],cutText=u((e,t)=>{if(e.length<=t)return e;const o=t-1,n=e.charCodeAt(o-1);return`${e.slice(0,n>=55296&&n<=56319?o-1:o)}\u2026`},"cutText");function parseLoopSnapshot(e){const t=u(a=>({ok:!1,reason:a}),"fail");if(!isObj(e))return t("the snapshot is not a JSON object");if(e.schema!==exports.LOOP_WIRE_SCHEMA)return t(notSchema(e.schema,exports.LOOP_WIRE_SCHEMA));const o=e.at;if(!isIso(o))return t("`at` is not an ISO time");const n=e.intervalSec;if(!(typeof n=="number"&&Number.isFinite(n)&&n>0&&n<=exports.LOOP_MAX_INTERVAL_SEC))return t(`\`intervalSec\` must be the loop's own period in seconds, more than 0 and at most ${exports.LOOP_MAX_INTERVAL_SEC}`);const i=e.lastRunAt;if(i===void 0)return t("`lastRunAt` is absent \u2014 say null if the loop has not run since the service started");if(i!==null&&!isIso(i))return t("`lastRunAt` must be an ISO time, or null if the loop has not run since the service started");for(const a of LOOP_COUNTS)if(e[a]!==void 0&&!isCount(e[a]))return t(`\`${a}\` must be a whole number \u2265 0, or absent`);const l=e.lastOutcome;if(l!==void 0&&!exports.LOOP_OUTCOMES.includes(l))return t(`\`lastOutcome\` must be ${exports.LOOP_OUTCOMES.join(", ")}, or absent`);const E=e.nextRunAt;if(E!=null&&!isIso(E))return t("`nextRunAt` must be an ISO time, null, or absent");const d=e.lastError;if(d!==void 0&&typeof d!="string")return t("`lastError` must be a string, or absent");const r=u(a=>e[a]!==void 0?{[a]:e[a]}:{},"count");return{ok:!0,loop:{at:o,intervalSec:n,lastRunAt:i,...r("lastDurationMs"),...l!==void 0?{lastOutcome:l}:{},...r("lastItems"),...E!==void 0?{nextRunAt:E}:{},...r("runsInWindow"),...r("itemsInWindow"),...r("failuresInWindow"),...r("windowSec"),...d!==void 0?{lastError:cutText(d,exports.SOURCE_ERROR_MAX)}:{}}}}g(parseLoopSnapshot,"parseLoopSnapshot"),u(parseLoopSnapshot,"parseLoopSnapshot");const STORE_COUNTS=["opsInWindow","writesInWindow","deletesInWindow","errorsInWindow","windowSec"];function parseStoreSnapshot(e){const t=u(p=>({ok:!1,reason:p}),"fail");if(!isObj(e))return t("the snapshot is not a JSON object");if(e.schema!==exports.STORE_WIRE_SCHEMA)return t(notSchema(e.schema,exports.STORE_WIRE_SCHEMA));const o=e.at;if(!isIso(o))return t("`at` is not an ISO time");for(const p of["objects","bytes"])if(!isCount(e[p]))return t(`\`${p}\` must be a whole number \u2265 0`);const n=e.quotaBytes;if(n!=null&&!isCount(n))return t("`quotaBytes` must be a whole number \u2265 0, null when it has no quota, or absent");for(const p of STORE_COUNTS)if(e[p]!==void 0&&!isCount(e[p]))return t(`\`${p}\` must be a whole number \u2265 0, or absent`);const i=e.lastWriteAt;if(i!=null&&!isIso(i))return t("`lastWriteAt` must be an ISO time, null, or absent");const l=e.lastError;if(l!==void 0&&typeof l!="string")return t("`lastError` must be a string, or absent");const E=e.truncated;if(E!==void 0&&!(isObj(E)&&isCount(E.groups)))return t("`truncated` must be { groups: <how many were dropped> }, or absent");const d=e.groups;let r;if(d!==void 0){if(!Array.isArray(d))return t("`groups` must be a list, or absent");if(d.length>exports.SOURCE_MAX_GROUPS)return t(overCap(d.length,"groups"));const p=new Set;r=[];for(let R=0;R<d.length;R++){const h=d[R],m=`groups[${R}]`;if(!isObj(h))return t(`${m} is not an object`);const A=keyWrong(h.key,m,p);if(A)return t(A);for(const s of["objects","bytes"])if(!isCount(h[s]))return t(`${m}.${s} must be a whole number \u2265 0`);const b=h.labels,I=labelsWrong(b,m);if(I)return t(I);r.push({key:h.key,...b!==void 0?{labels:b}:{},objects:h.objects,bytes:h.bytes})}}const a=u(p=>e[p]!==void 0?{[p]:e[p]}:{},"count");return{ok:!0,store:{at:o,objects:e.objects,bytes:e.bytes,...n!==void 0?{quotaBytes:n}:{},...a("opsInWindow"),...a("writesInWindow"),...a("deletesInWindow"),...a("errorsInWindow"),...a("windowSec"),...i!==void 0?{lastWriteAt:i}:{},...l!==void 0?{lastError:cutText(l,exports.SOURCE_ERROR_MAX)}:{},...r?{groups:r}:{},...E!==void 0?{truncated:{groups:E.groups}}:{}}}}g(parseStoreSnapshot,"parseStoreSnapshot"),u(parseStoreSnapshot,"parseStoreSnapshot");const TRAFFIC_COUNTS=["messagesInWindow","failuresInWindow","rateLimitedInWindow"];function parseTrafficSnapshot(e){const t=u(r=>({ok:!1,reason:r}),"fail");if(!isObj(e))return t("the snapshot is not a JSON object");if(e.schema!==exports.TRAFFIC_WIRE_SCHEMA)return t(notSchema(e.schema,exports.TRAFFIC_WIRE_SCHEMA));const o=e.at;if(!isIso(o))return t("`at` is not an ISO time");const n=e.windowSec;if(n!==void 0&&!isCount(n))return t("`windowSec` must be a whole number \u2265 0, or absent");const i=e.truncated;if(i!==void 0&&!(isObj(i)&&isCount(i.channels)))return t("`truncated` must be { channels: <how many were dropped> }, or absent");const l=e.channels;if(!Array.isArray(l))return t("`channels` is not a list");if(l.length>exports.SOURCE_MAX_GROUPS)return t(overCap(l.length,"channels"));const E=new Set,d=[];for(let r=0;r<l.length;r++){const a=l[r],p=`channels[${r}]`;if(!isObj(a))return t(`${p} is not an object`);const R=keyWrong(a.key,p,E);if(R)return t(R);const h=a.direction;if(h!==void 0&&!exports.TRAFFIC_DIRECTIONS.includes(h))return t(`${p}.direction must be ${exports.TRAFFIC_DIRECTIONS.join(", ")}, or absent`);const m=a.counterpart;if(m!==void 0&&!(typeof m=="string"&&m.length>0&&m.length<=200))return t(`${p}.counterpart must be a string of 1\u2013200 characters, or absent`);for(const O of TRAFFIC_COUNTS)if(a[O]!==void 0&&!isCount(a[O]))return t(`${p}.${O} must be a whole number \u2265 0, or absent`);const A=a.p95Ms;if(A!==void 0&&!(finite(A)&&A>=0))return t(`${p}.p95Ms must be milliseconds \u2265 0, or absent`);const b=a.lastAt;if(b!=null&&!isIso(b))return t(`${p}.lastAt must be an ISO time, null, or absent`);const I=a.lastError;if(I!==void 0&&typeof I!="string")return t(`${p}.lastError must be a string, or absent`);const s=a.labels,c=labelsWrong(s,p);if(c)return t(c);const f=u(O=>a[O]!==void 0?{[O]:a[O]}:{},"count");d.push({key:a.key,...s!==void 0?{labels:s}:{},...h!==void 0?{direction:h}:{},...m!==void 0?{counterpart:m}:{},...f("messagesInWindow"),...f("failuresInWindow"),...f("rateLimitedInWindow"),...A!==void 0?{p95Ms:A}:{},...b!==void 0?{lastAt:b}:{},...I!==void 0?{lastError:cutText(I,exports.SOURCE_ERROR_MAX)}:{}})}return{ok:!0,traffic:{at:o,...n!==void 0?{windowSec:n}:{},channels:d,...i!==void 0?{truncated:{channels:i.channels}}:{}}}}g(parseTrafficSnapshot,"parseTrafficSnapshot"),u(parseTrafficSnapshot,"parseTrafficSnapshot");const sourceFull=u((e,t)=>({[exports.SOURCE_SNAPSHOT_FIELD[e]]:t}),"sourceFull");exports.sourceFull=sourceFull;const declRaw=u(e=>({sourceKind:e.kind,name:e.name,...e.path!==void 0?{path:e.path}:{},intervalSec:e.intervalSec,thresholds:{...e.thresholds},...e.feeds!==void 0?{feeds:e.feeds}:{}}),"declRaw"),canonical=u(e=>{if(Array.isArray(e))return e.map(canonical);if(!isObj(e))return e;const t={};for(const o of Object.keys(e).sort())t[o]=canonical(e[o]);return t},"canonical");function sourceDigest(e){return(0,node_crypto_1.createHash)("sha1").update(JSON.stringify(canonical(e))??"null").digest("hex").slice(0,16)}g(sourceDigest,"sourceDigest"),u(sourceDigest,"sourceDigest");const oldestOf=u(e=>e.pending>0&&e.oldestPendingAt?Date.parse(e.oldestPendingAt):Number.POSITIVE_INFINITY,"oldestOf");function keepQueueSnapshot(e,t,o,n){const i={groups:t.length,pending:0,inFlight:0,failed:0};let l;for(const r of t)i.pending+=r.pending,i.inFlight+=r.inFlight??0,i.failed+=r.failed??0,r.completedInWindow!==void 0&&(l=(l??0)+r.completedInWindow);l!==void 0&&(i.completedInWindow=l);const E=[...t].sort((r,a)=>oldestOf(r)-oldestOf(a)||a.pending-r.pending||(r.key<a.key?-1:r.key>a.key?1:0)).map(({key:r,...a})=>({group:r,...a})),d=n?{groups:n.groups}:void 0;return{at:e,receivedAt:o,totals:i,groups:E,...d?{truncated:d}:{},digest:sourceDigest({groups:E,truncated:d??null})}}g(keepQueueSnapshot,"keepQueueSnapshot"),u(keepQueueSnapshot,"keepQueueSnapshot");function keepLoopSnapshot(e,t){const{at:o,...n}=e;return{at:o,receivedAt:t,digest:sourceDigest(n),...n}}g(keepLoopSnapshot,"keepLoopSnapshot"),u(keepLoopSnapshot,"keepLoopSnapshot");const byKey=u((e,t)=>e<t?-1:e>t?1:0,"byKey");function keepStoreSnapshot(e,t){const{at:o,groups:n,truncated:i,...l}=e,E=n?[...n].sort((r,a)=>a.bytes-r.bytes||a.objects-r.objects||byKey(r.key,a.key)).map(({key:r,...a})=>({group:r,...a})):void 0,d={...l,...E?{groups:E}:{},...i?{truncated:{groups:i.groups}}:{}};return{at:o,receivedAt:t,digest:sourceDigest(d),...d}}g(keepStoreSnapshot,"keepStoreSnapshot"),u(keepStoreSnapshot,"keepStoreSnapshot");const messagesOf=u(e=>e.messagesInWindow??-1,"messagesOf");function keepTrafficSnapshot(e,t){const{at:o,channels:n,truncated:i,...l}=e,E=[...n].sort((r,a)=>messagesOf(a)-messagesOf(r)||byKey(r.key,a.key)).map(({key:r,...a})=>({channel:r,...a})),d={...l,channels:E,...i?{truncated:{channels:i.channels}}:{}};return{at:o,receivedAt:t,digest:sourceDigest(d),...d}}g(keepTrafficSnapshot,"keepTrafficSnapshot"),u(keepTrafficSnapshot,"keepTrafficSnapshot");const sourceSame=u(e=>({digest:e.digest,at:e.at,receivedAt:e.receivedAt}),"sourceSame");exports.sourceSame=sourceSame;function buildSourcePollRaw(e,t,o,n,i,l){return{kind:"source-poll",provenance:"reported",project:e,...declRaw(t),state:o.state,...o.detail!==void 0?{detail:o.detail}:{},...o.status!==void 0?{status:o.status}:{},polledAt:o.polledAt,...o.durationMs!==void 0?{durationMs:o.durationMs}:{},reportEveryMs:n,...i>0?{failures:i}:{},...l??{}}}g(buildSourcePollRaw,"buildSourcePollRaw"),u(buildSourcePollRaw,"buildSourcePollRaw");function buildSourceDeclarationRaw(e,t){return{kind:"source-declaration",project:e,sources:t.sources.map(declRaw),problems:[...t.problems]}}g(buildSourceDeclarationRaw,"buildSourceDeclarationRaw"),u(buildSourceDeclarationRaw,"buildSourceDeclarationRaw");const span=u(e=>{const t=Math.round(e/6e4);return e<6e4?`${Math.max(0,Math.round(e/1e3))}s`:t<120?`${t}m`:`${Math.floor(t/60)}h${t%60?` ${t%60}m`:""}`},"span"),loopWords=u(e=>`${e.lastRunAt===null?"has not run since the service started":`last run ${span(Math.max(0,Date.parse(e.at)-Date.parse(e.lastRunAt)))} before it was measured`}${e.lastOutcome?`, ${e.lastOutcome}`:""}${e.lastItems!==void 0?`, ${e.lastItems} item${e.lastItems===1?"":"s"}`:""}`,"loopWords"),plural=u((e,t)=>`${e} ${t}${e===1?"":"s"}`,"plural"),byteSize=u(e=>{const t=["B","kB","MB","GB","TB","PB"];let o=e,n=0;for(;o>=999.5&&n<t.length-1;)o/=1e3,n+=1;return n===0?`${e} B`:`${o<9.95?o.toFixed(1):Math.round(o)} ${t[n]}`},"byteSize"),storeWords=u(e=>{const t=typeof e.quotaBytes=="number"&&e.quotaBytes>0?` of ${byteSize(e.quotaBytes)} (${Math.round(e.bytes/e.quotaBytes*1e3)/10}%)`:"",o=e.errorsInWindow?`, ${plural(e.errorsInWindow,"error")}${e.windowSec?` in ${span(e.windowSec*1e3)}`:""}`:"";return`${plural(e.objects,"object")}, ${byteSize(e.bytes)}${t}${o}`},"storeWords"),trafficWords=u(e=>{let t,o=0,n=0;for(const l of e.channels)l.messagesInWindow!==void 0&&(t=(t??0)+l.messagesInWindow),o+=l.failuresInWindow??0,n+=l.rateLimitedInWindow??0;const i=t!==void 0?`, ${plural(t,"message")}${e.windowSec?` in ${span(e.windowSec*1e3)}`:""}`:"";return`${plural(e.channels.length,"channel")}${i}${o?`, ${o} failed`:""}${n?`, ${n} rate-limited`:""}`},"trafficWords");function sourcePollTitle(e,t){const o=`${e.sourceKind} ${e.project}/${e.name} (reported)`,n=t??e[exports.SOURCE_SNAPSHOT_FIELD[e.sourceKind]];if(e.state!=="current"||!n)return`${o}: ${e.state}${e.detail?` \u2014 ${e.detail}`:""}`;if(e.sourceKind==="loop")return`${o}: ${loopWords(n)}`;if(e.sourceKind==="store")return`${o}: ${storeWords(n)}`;if(e.sourceKind==="traffic")return`${o}: ${trafficWords(n)}`;const i=n,l=i.groups.find(d=>d.pending>0&&d.oldestPendingAt),E=l?.oldestPendingAt?Date.parse(i.at)-Date.parse(l.oldestPendingAt):void 0;return`${o}: ${i.totals.pending} pending in ${i.totals.groups} group${i.totals.groups===1?"":"s"}${E!==void 0?`, oldest waiting ${span(Math.max(0,E))}`:""}`}g(sourcePollTitle,"sourcePollTitle"),u(sourcePollTitle,"sourcePollTitle");function requestOverSocket(e,t,o,n,i=exports.SOURCE_MAX_BYTES){return new Promise(l=>{let E=!1,d;const r=u(p=>{E||(E=!0,clearTimeout(a),l(p))},"finish"),a=setTimeout(()=>{r({ok:!1,code:"ETIMEDOUT",message:`no answer within ${n} ms`}),d?.destroy()},n);a.unref?.();try{d=http.request({socketPath:e,path:t,method:"GET",agent:!1,headers:o},p=>{const R=[];let h=0;p.on("data",m=>{if(!E){if(h+=m.length,h>i){r({ok:!0,status:p.statusCode??0,body:"",truncated:!0}),p.destroy();return}R.push(m)}}),p.on("end",()=>r({ok:!0,status:p.statusCode??0,body:Buffer.concat(R).toString("utf8"),truncated:!1})),p.on("error",m=>r({ok:!1,code:m.code??"ERESPONSE",message:m.message}))}),d.on("error",p=>r({ok:!1,code:p.code??"EREQUEST",message:p.message})),d.end()}catch(p){r({ok:!1,code:p.code??"EREQUEST",message:p.message})}})}g(requestOverSocket,"requestOverSocket"),u(requestOverSocket,"requestOverSocket");const snippet=u(e=>e.replace(/\s+/g," ").trim().slice(0,160),"snippet");function readSnapshot(e,t,o){let n;try{n=JSON.parse(t)}catch{return{ok:!1,reason:`not JSON: ${snippet(t)||"(an empty body)"}`}}if(e==="loop"){const l=parseLoopSnapshot(n);return l.ok===!0?{ok:!0,kept:keepLoopSnapshot(l.loop,o)}:l}if(e==="store"){const l=parseStoreSnapshot(n);return l.ok===!0?{ok:!0,kept:keepStoreSnapshot(l.store,o)}:l}if(e==="traffic"){const l=parseTrafficSnapshot(n);return l.ok===!0?{ok:!0,kept:keepTrafficSnapshot(l.traffic,o)}:l}const i=parseQueueSnapshot(n);return i.ok===!0?{ok:!0,kept:keepQueueSnapshot(i.at,i.groups,o,i.truncated)}:i}g(readSnapshot,"readSnapshot"),u(readSnapshot,"readSnapshot");function createSourcePoller(e){const t=e.now??Date.now,o=e.timeoutMs??(0,exports.sourcesTimeoutMs)(),n=Math.max(1,e.maxConcurrent??(0,exports.sourcesConcurrency)()),i=e.socketOf??(s=>(0,discovery_1.pickSock)(s.pool,e.scanTtlMs??1500)),l=e.request??requestOverSocket,E=e.log??(s=>console.warn(s)),d=new WeakMap,r=new Map;let a=0,p;const R=u(s=>{const c=s.decl;let f=d.get(c);if(!f){f=parseSourceDecls(s.decl.sources),d.set(c,f);for(const S of f.problems)E(`[gateway] ${s.project}: cluster.sources \u2014 ${S}`)}const O=t();return(f.reportedAt===void 0||O-f.reportedAt>=exports.SOURCE_DECLARATION_REPORT_MS)&&(f.reportedAt=O,e.emit(s,f.problems.length?"warning":"info",f.problems.length?`sources ${s.project}: ${f.problems.length} cluster.sources entr${f.problems.length===1?"y":"ies"} not read \u2014 ${f.problems[0]}`:`sources ${s.project}: reads ${f.sources.map(S=>`${S.kind} "${S.name}"${isPolled(S)?"":" (push-only)"}`).join(", ")}`,`source-declaration:${s.wsKey}:${s.project}`,buildSourceDeclarationRaw(s.project,f))),f},"declarationOf"),h=u(s=>{if(s.state==="starting")return{notRunning:"it is starting \u2014 read once it is up"};const c=i(s);return c?{socket:c}:{notRunning:s.state==="up"?"it has no live pod socket \u2014 no pod runs it now":"it is scaled to zero \u2014 the lens does not start a service to read a source"}},"reach"),m=u((s,c)=>{const f=s.good;if(f)return s.full&&s.full.digest===f.digest&&c-s.full.at<exports.SOURCE_FULL_REPORT_MS?{same:(0,exports.sourceSame)(f)}:(s.full={digest:f.digest,at:c},(0,exports.sourceFull)(s.decl.kind,f))},"carried"),A=u((s,c)=>{const f=s.last;if(!f)return;const O=t();if(!c&&s.reportedAt!==void 0&&O-s.reportedAt<s.reportEveryMs)return;s.reportedAt=O;const S=buildSourcePollRaw(s.svc.project,s.decl,f,s.reportEveryMs,s.failures,m(s,O)),_=f.state==="unreachable"||f.state==="refused"||f.state==="malformed";e.emit(s.svc,_?"warning":"info",sourcePollTitle(S,s.good),`source:${s.svc.wsKey}:${s.svc.project}:${s.decl.name}`,S)},"report"),b=u(async s=>{const c=t(),f=s.decl.intervalSec*1e3;s.inFlight=!0,a+=1;const O=s.last?.state;try{const S=h(s.svc);if("notRunning"in S){s.last={state:"not-running",detail:S.notRunning,polledAt:c},s.failures=0,s.nextAt=c+f,s.reportEveryMs=exports.SOURCE_NOT_RUNNING_REPORT_MS,A(s,O!=="not-running");return}const _=e.serviceKey(s.svc),T=await l(S.socket,s.decl.path,{accept:"application/json","x-lensmcp-probe":`source:${s.decl.kind}`,..._?{"x-internal-token":_}:{}},o,exports.SOURCE_MAX_BYTES),x=Math.max(0,t()-c);if(T.ok===!1){const $=T.code==="ECONNREFUSED"||T.code==="ENOENT";s.last=$&&s.svc.state!=="up"?{state:"not-running",detail:`nothing listens on its pod socket \u2014 the service is ${s.svc.state}`,polledAt:c,durationMs:x}:{state:"unreachable",detail:T.code==="ETIMEDOUT"?T.message:`${T.code}: ${snippet(T.message)}`,polledAt:c,durationMs:x}}else if(T.status<200||T.status>299){const $=snippet(T.body);s.last={state:"refused",status:T.status,detail:`HTTP ${T.status}${$?`: ${$}`:""}`,polledAt:c,durationMs:x}}else if(T.truncated)s.last={state:"malformed",detail:`the snapshot is larger than ${exports.SOURCE_MAX_BYTES/1024} KiB`,polledAt:c,durationMs:x};else{const $=readSnapshot(s.decl.kind,T.body,t());$.ok===!0?(s.good=$.kept,s.last={state:"current",polledAt:c,durationMs:x}):s.last={state:"malformed",detail:$.reason,polledAt:c,durationMs:x}}const v=s.last.state==="unreachable"||s.last.state==="refused"||s.last.state==="malformed";s.failures=v?s.failures+1:0;const M=v?sourceBackoffMs(f,s.failures):f;s.nextAt=c+M,s.reportEveryMs=s.last.state==="not-running"?exports.SOURCE_NOT_RUNNING_REPORT_MS:M,A(s,s.last.state!=="not-running"||O!=="not-running")}catch(S){s.last={state:"unreachable",detail:`the poll failed: ${snippet(S?.message??String(S))}`,polledAt:c},s.failures+=1,s.nextAt=c+sourceBackoffMs(f,s.failures),s.reportEveryMs=s.nextAt-c,A(s,!0)}finally{s.inFlight=!1,a-=1}},"pollOne"),I=u(async()=>{if(e.stopped?.())return;const s=new Set;for(const S of e.services())if(S.decl.sources!==void 0)for(const _ of R(S).sources){if(!isPolled(_))continue;const T=`${S.wsKey} ${S.project} ${_.kind} ${_.name}`;s.add(T);const x=r.get(T);x?(x.svc!==S||x.decl!==_)&&(x.svc=S,x.decl=_):r.set(T,{svc:S,decl:_,nextAt:0,inFlight:!1,failures:0,reportEveryMs:_.intervalSec*1e3})}for(const[S,_]of[...r.entries()])!s.has(S)&&!_.inFlight&&r.delete(S);const c=t(),f=[...r.values()].filter(S=>!S.inFlight&&c>=S.nextAt).sort((S,_)=>S.nextAt-_.nextAt),O=[];for(const S of f){if(a>=n)break;O.push(b(S))}await Promise.all(O)},"tick");return{tick:I,start(s=1e3){return p&&clearInterval(p),p=setInterval(()=>{I().catch(c=>console.error("[gateway] source poll error:",c))},s),p.unref(),p},stop(){p&&clearInterval(p),p=void 0},snapshot(){const s=t();return[...r.values()].map(c=>{const f=c.last!==void 0&&s-c.last.polledAt>(0,exports.sourceStaleAfterMs)(c.reportEveryMs);return{wsKey:c.svc.wsKey,project:c.svc.project,name:c.decl.name,kind:c.decl.kind,path:c.decl.path,state:c.last?f?"stale":c.last.state:"never-polled",...c.last?.detail!==void 0?{detail:c.last.detail}:{},...c.last?.status!==void 0?{status:c.last.status}:{},...c.last?{polledAt:c.last.polledAt}:{},failures:c.failures,nextAt:c.nextAt,...c.good?{...(0,exports.sourceFull)(c.decl.kind,c.good),ageMs:Math.max(0,s-c.good.receivedAt)}:{}}})}}}g(createSourcePoller,"createSourcePoller"),u(createSourcePoller,"createSourcePoller");
|
|
@@ -105,7 +105,7 @@ export interface ClusterProjectDecl {
|
|
|
105
105
|
* }] }`. A `traffic` entry WITHOUT a `path` is push-only: declared, never polled — the lens counts the `inbound` /
|
|
106
106
|
* `outbound` events the app pushes. The dev gateway reads every other entry from a RUNNING pod every `intervalSec`
|
|
107
107
|
* (default 10, at least 2) over the pod's socket — never waking a service scaled to zero — and the lens shows it,
|
|
108
|
-
* labelled REPORTED (`
|
|
108
|
+
* labelled REPORTED (`observe_sources`, `source_get`, `process://sources`, the dashboard's Data views), judged against
|
|
109
109
|
* each kind's `thresholds` (every one filled with its default): a queue's `oldestWaitMin` (10) and `stalledMin` (15)
|
|
110
110
|
* and a loop's `idleMin` (10), in minutes; a store's `quotaPct` (90) and `errorRatePct` (5), percents, and
|
|
111
111
|
* `orphanMin` (60), minutes; a traffic source's `failurePct` (5), a percent, `p95Ms` (2000), milliseconds, and
|
|
@@ -270,7 +270,7 @@ export interface LensFrontendSupervisor {
|
|
|
270
270
|
recover(frontend: LensFrontend, reason: string): Promise<boolean>;
|
|
271
271
|
}
|
|
272
272
|
/**
|
|
273
|
-
* A restart someone asked for — an agent's `
|
|
273
|
+
* A restart someone asked for — an agent's `service_restart`, `lensmcp restart <service>` — of ONE service of one
|
|
274
274
|
* workspace or worktree. A fresh tree re-reads what the service reads when it starts: its config files, its env, its
|
|
275
275
|
* bundle; a hot swap re-reads only what the new bundle reads again.
|
|
276
276
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var O=Object.defineProperty;var e=(_,E)=>O(_,"name",{value:E,configurable:!0});var M=Object.defineProperty,R=e((_,E)=>M(_,"name",{value:E,configurable:!0}),"R");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_H2_RESET_RATE=exports.GATEWAY_H2_RESET_BURST=exports.BODY_STALL_MS=exports.GATEWAY_CONN_CHECK_MS=exports.GATEWAY_MAX_CONNECTIONS=exports.GATEWAY_STOP_GRACE_MS=exports.GATEWAY_HEADERS_TIMEOUT_MS=exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=exports.LENS_REQUEST_RECOVERY_WAIT_MS=exports.LENS_REPLACEMENT_DRAIN_MS=exports.LENS_REPLACEMENT_READY_MS=exports.LENS_RESTART_MODE=exports.LENS_RECYCLE_KILL_GRACE_MS=exports.LENS_PARKED_PORT_REPROBE_MS=exports.MAX_PORT_CONFLICT_RETRIES=exports.CHILD_START_FAIL_MS=exports.PORT_FREE_POLL_MS=exports.PORT_FREE_WAIT_MS=exports.LENS_PROBE_BOOT_GRACE_MS=exports.LENS_PROBE_COOLDOWN_MS=exports.LENS_PROBE_TIMEOUT_MS=exports.LENS_PROBE_FAILS=exports.LENS_PROBE_GRACE_MS=exports.MAX_COLD_STARTS=exports.POD_MAX_CONCURRENT_ROLLS=exports.POD_ROLL_READY_MS=exports.POD_RECYCLE_MODE=exports.POD_WATCHER_SILENT=exports.POD_WATCHER_UNVERIFIED=exports.LENS_WATCH_SCOPE_ENABLED=exports.LENS_WATCHER_UNVERIFIED=exports.LENS_WATCHER_PROBE_ENABLED=exports.LENS_PROBE_ENABLED=exports.POD_STALE_RECYCLE_COOLDOWN_MS=exports.POD_STALE_SCAN_MS=exports.POD_RECYCLE_SETTLE_MS=exports.POD_STALE_GRACE_MS=exports.POD_MAX_AGE_MS=exports.POD_RECYCLE_ENABLED=exports.WEDGE_RECYCLE_GRACE_MS=exports.POD_ALIVE_PATH=exports.POD_WEDGE_CONFIRM_MS=exports.POD_ALIVE_PROBE_TIMEOUT_MS=exports.POD_SLOW_FIRST_BYTE_MS=exports.POD_RESPONSE_TIMEOUT_MS=exports.UPSTREAM_HEAL_STEP_MS=exports.UPSTREAM_HEAL_WINDOW_MS=exports.SERVICE_RESTART_WINDOW_MS=exports.SERVICE_MAX_RESTARTS=exports.SERVICE_ERROR_THROTTLE_MS=void 0;const tslib_1=require("tslib"),os=tslib_1.__importStar(require("node:os"));function envInt(_,E,L=!1){const S=Number(process.env[_]);return!Number.isFinite(S)||S<0?E:S===0?L?0:E:S}e(envInt,"envInt"),R(envInt,"envInt"),exports.SERVICE_ERROR_THROTTLE_MS=5e3,exports.SERVICE_MAX_RESTARTS=5,exports.SERVICE_RESTART_WINDOW_MS=6e4,exports.UPSTREAM_HEAL_WINDOW_MS=8e3,exports.UPSTREAM_HEAL_STEP_MS=300,exports.POD_RESPONSE_TIMEOUT_MS=(()=>{const _=Number(process.env.LENSMCP_POD_RESPONSE_TIMEOUT_MS);return Number.isFinite(_)&&_>0?_:3e4})(),exports.POD_SLOW_FIRST_BYTE_MS=envInt("LENSMCP_POD_SLOW_FIRST_BYTE_MS",10*6e4,!0),exports.POD_ALIVE_PROBE_TIMEOUT_MS=envInt("LENSMCP_POD_ALIVE_PROBE_TIMEOUT_MS",1e3),exports.POD_WEDGE_CONFIRM_MS=envInt("LENSMCP_POD_WEDGE_CONFIRM_MS",1e4,!0),exports.POD_ALIVE_PATH="/__lensmcp/alive",exports.WEDGE_RECYCLE_GRACE_MS=(()=>{const _=Number(process.env.LENSMCP_WEDGE_RECYCLE_GRACE_MS);return Number.isFinite(_)&&_>0?_:15e3})(),exports.POD_RECYCLE_ENABLED=process.env.LENSMCP_POD_RECYCLE!=="0",exports.POD_MAX_AGE_MS=envInt("LENSMCP_POD_MAX_AGE_MS",240*6e4,!0),exports.POD_STALE_GRACE_MS=envInt("LENSMCP_POD_STALE_GRACE_MS",1e4),exports.POD_RECYCLE_SETTLE_MS=envInt("LENSMCP_POD_RECYCLE_SETTLE_MS",8e3),exports.POD_STALE_SCAN_MS=envInt("LENSMCP_POD_STALE_SCAN_MS",3e4),exports.POD_STALE_RECYCLE_COOLDOWN_MS=envInt("LENSMCP_POD_STALE_RECYCLE_COOLDOWN_MS",6e4),exports.LENS_PROBE_ENABLED=process.env.LENSMCP_LENS_PROBE!=="0",exports.LENS_WATCHER_PROBE_ENABLED=process.env.LENSMCP_LENS_WATCHER_PROBE!=="0",exports.LENS_WATCHER_UNVERIFIED=process.env.LENSMCP_LENS_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.LENS_WATCH_SCOPE_ENABLED=process.env.LENSMCP_LENS_WATCH_SCOPE!=="0",exports.POD_WATCHER_UNVERIFIED=process.env.LENSMCP_POD_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.POD_WATCHER_SILENT=process.env.LENSMCP_POD_WATCHER_SILENT==="recycle"?"recycle":"keep",exports.POD_RECYCLE_MODE=process.env.LENSMCP_POD_RECYCLE_MODE==="in-place"?"in-place":"rolling",exports.POD_ROLL_READY_MS=envInt("LENSMCP_POD_ROLL_READY_MS",18e4),exports.POD_MAX_CONCURRENT_ROLLS=envInt("LENSMCP_POD_MAX_CONCURRENT_ROLLS",2,!0),exports.MAX_COLD_STARTS=envInt("LENSMCP_MAX_COLD_STARTS",Math.max(2,Math.floor(os.availableParallelism()/2)),!0),exports.LENS_PROBE_GRACE_MS=envInt("LENSMCP_LENS_PROBE_GRACE_MS",45e3),exports.LENS_PROBE_FAILS=envInt("LENSMCP_LENS_PROBE_FAILS",2),exports.LENS_PROBE_TIMEOUT_MS=envInt("LENSMCP_LENS_PROBE_TIMEOUT_MS",1e3),exports.LENS_PROBE_COOLDOWN_MS=envInt("LENSMCP_LENS_PROBE_COOLDOWN_MS",3e4),exports.LENS_PROBE_BOOT_GRACE_MS=envInt("LENSMCP_LENS_PROBE_BOOT_GRACE_MS",24e4),exports.PORT_FREE_WAIT_MS=envInt("LENSMCP_PORT_FREE_WAIT_MS",1e4),exports.PORT_FREE_POLL_MS=envInt("LENSMCP_PORT_FREE_POLL_MS",250),exports.CHILD_START_FAIL_MS=envInt("LENSMCP_CHILD_START_FAIL_MS",1e4),exports.MAX_PORT_CONFLICT_RETRIES=envInt("LENSMCP_MAX_PORT_CONFLICT_RETRIES",5),exports.LENS_PARKED_PORT_REPROBE_MS=envInt("LENSMCP_PARKED_PORT_REPROBE_MS",3e5),exports.LENS_RECYCLE_KILL_GRACE_MS=envInt("LENSMCP_RECYCLE_KILL_GRACE_MS",5e3),exports.LENS_RESTART_MODE=process.env.LENSMCP_LENS_RESTART_MODE==="in-place"?"in-place":"rolling",exports.LENS_REPLACEMENT_READY_MS=envInt("LENSMCP_LENS_REPLACEMENT_READY_MS",3e4),exports.LENS_REPLACEMENT_DRAIN_MS=envInt("LENSMCP_LENS_REPLACEMENT_DRAIN_MS",2e3,!0),exports.LENS_REQUEST_RECOVERY_WAIT_MS=envInt("LENSMCP_LENS_REQUEST_RECOVERY_WAIT_MS",15e3),exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=envInt("LENSMCP_KEEPALIVE_TIMEOUT_MS",76e3),exports.GATEWAY_HEADERS_TIMEOUT_MS=envInt("LENSMCP_HEADERS_TIMEOUT_MS",6e4),exports.GATEWAY_STOP_GRACE_MS=envInt("LENSMCP_STOP_GRACE_MS",3e3),exports.GATEWAY_MAX_CONNECTIONS=envInt("LENSMCP_MAX_CONNECTIONS",0,!0),exports.GATEWAY_CONN_CHECK_MS=envInt("LENSMCP_CONN_CHECK_MS",0,!0),exports.BODY_STALL_MS=envInt("LENSMCP_BODY_STALL_MS",6e4,!0),exports.GATEWAY_H2_RESET_BURST=envInt("LENSMCP_H2_RESET_BURST",1e5),exports.GATEWAY_H2_RESET_RATE=envInt("LENSMCP_H2_RESET_RATE",1e4);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var K=Object.defineProperty;var w=(c,s)=>K(c,"name",{value:s,configurable:!0});var M=Object.defineProperty,u=w((c,s)=>M(c,"name",{value:s,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.LENS_HMR_REFUSAL_REPORT_MS=void 0,exports.createUpgrade=createUpgrade;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),manifest_1=require("../manifest"),discovery_1=require("./discovery"),edge_1=require("./edge"),hmr_reload_1=require("./hmr-reload"),service_keys_1=require("./service-keys");exports.LENS_HMR_REFUSAL_REPORT_MS=1e4;function accountUpgrade(c,s){const i=c.svc;if(!i||s.destroyed)return;i.inflight+=1,i.lastUsed=Date.now();let d=!1;s.once("close",()=>{d||(d=!0,i.inflight-=1,i.lastUsed=Date.now())})}w(accountUpgrade,"accountUpgrade"),u(accountUpgrade,"accountUpgrade");function createUpgrade(c){const{rt:s,auth:i,proxy:d,hooks:p,obs:b}=c,y=new Set,_=u(e=>{e.destroyed||(y.add(e),e.once("close",()=>y.delete(e)))},"track");d.proxy.on?.("open",_);const v=new WeakMap,k=new Map,m=u((e,r)=>{const n=Date.now();n-(k.get(e.frontendKey)??0)<exports.LENS_HMR_REFUSAL_REPORT_MS||(k.set(e.frontendKey,n),console.warn(`[gateway] lens HMR socket refused: ${e.frontendKey} at ${e.target} answered ${r} for a tab on ${e.host} \u2014 that tab loads but gets no hot updates; the lens runtime reloads it once if it had a socket before.`),b?.emit("warning",`lens HMR socket refused: ${e.frontendKey} (${r})`,`cluster-lens-hmr-refused:${e.frontendKey}`,{kind:"lens-hmr-refused",frontendKey:e.frontendKey,host:e.host,target:e.target,answer:r},void 0,e.busFile))},"reportRefusal");d.proxy.on?.("proxyReqWs",(e,r)=>{const n=v.get(r);if(!n)return;const a=e;a.once("upgrade",()=>{n.answered=!0}),a.once("response",g=>{n.answered=!0,m(n,`HTTP ${g.statusCode??"?"}`)})});const S=u(async(e,r,n)=>{(0,edge_1.stripOwnedHeaders)(e);const a=(0,edge_1.canonicalize)(e.url??"/");if(a===void 0){r.destroy();return}e.url=a.path+a.query;const g=(e.headers.host||"").split(":")[0],t=(0,manifest_1.matchRoute)(s.routes,g,a.policy+a.query);if(!t){r.destroy();return}(0,edge_1.resolveClientIp)(s,e);const l=p.upgradeContext(e,r,void 0);if(l.route=t,t.internal){const o=i.internal(e,t,void 0);if(!o.ok){r.destroy();return}l.caller=o.caller}else{const o=i.public(e,t,void 0,a.policy);if(!o.ok){r.destroy();return}if(l.claims=o.claims,p.has("afterAuth")&&(await p.run("afterAuth",l),l.responded()))return}const x=t.pool?s.serviceKeys[(0,service_keys_1.serviceKeyId)(t.svc?.wsKey,t.project)]:void 0;if(x&&(e.headers["x-internal-token"]=x),t.prependPrefix&&!e.url?.startsWith(t.prependPrefix)&&(e.url=t.prependPrefix+(e.url??"/")),(0,edge_1.stampForwardingHeaders)(s,e),p.has("onUpgrade")&&(await p.run("onUpgrade",l),l.responded()))return;const h=t.pool?(()=>{const o=(0,discovery_1.pickSock)(t.pool,s.scanTtlMs);return o?{socketPath:o}:void 0})():t.target;if(!h){r.destroy();return}if(t.lens&&String(e.headers["sec-websocket-protocol"]??"").split(",").map(o=>o.trim()).includes("vite-hmr")){const o=t.lens.workspaceKey?`${t.lens.workspaceKey}:${t.lens.project}`:t.lens.project;(0,hmr_reload_1.registerHmrClient)(s,o,r);const f=!t.lens.workspaceRoot||path.resolve(t.lens.workspaceRoot)===path.resolve(s.root??"");v.set(e,{frontendKey:o,host:g,target:String(h),answered:!1,...f?{}:{busFile:path.join(t.lens.workspaceRoot,".lensmcp","events.jsonl")}})}accountUpgrade(t,r),d.proxy.ws(e,r,n,{target:h,changeOrigin:!t.pool,agent:d.agentForTarget(h)},o=>{const f=v.get(e);f&&!f.answered&&m(f,o?.code??o?.message??"an error"),r.destroy()})},"run"),R=u(((e,r,n)=>{r.on("error",()=>r.destroy()),_(r),S(e,r,n).catch(()=>r.destroy())}),"listener");return R.closeTunnels=()=>{const e=[...y];for(const r of e)r.destroy();return y.clear(),e.length},R}w(createUpgrade,"createUpgrade"),u(createUpgrade,"createUpgrade");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var a=Object.defineProperty;var r=(e,t)=>a(e,"name",{value:t,configurable:!0});var s=Object.defineProperty,n=r((e,t)=>s(e,"name",{value:t,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.workspaceLogWriter=workspaceLogWriter,exports.closeWorkspaceLogs=closeWorkspaceLogs;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),inspector_secret_1=require("../../../inspector-secret"),fds=new Map,written=new Map,MAX_BYTES=50*1024*1024,CHECK_EVERY=1024*1024;function ensurePrivateDir(e){fs.mkdirSync(e,{recursive:!0,mode:448});try{const t=fs.statSync(e);(t.mode&63)!==0&&(typeof process.getuid!="function"||t.uid===process.getuid())&&fs.chmodSync(e,448)}catch{}}r(ensurePrivateDir,"ensurePrivateDir"),n(ensurePrivateDir,"ensurePrivateDir");function ownerOnly(e){try{fs.chmodSync(e,384)}catch{}}r(ownerOnly,"ownerOnly"),n(ownerOnly,"ownerOnly");function ensureFd(e){const t=fds.get(e);if(t!==void 0)return t;try{ensurePrivateDir(path.dirname(e));const o=fs.openSync(e,"a",384);return ownerOnly(e),fds.set(e,o),written.set(e,0),o}catch{return}}r(ensureFd,"ensureFd"),n(ensureFd,"ensureFd");function closeFd(e){const t=fds.get(e);if(fds.delete(e),written.delete(e),t!==void 0)try{fs.closeSync(t)}catch{}}r(closeFd,"closeFd"),n(closeFd,"closeFd");function rotateIfHuge(e){try{if(fs.statSync(e).size<=MAX_BYTES)return}catch{return}closeFd(e);try{fs.renameSync(e,`${e}.1`)}catch{}ownerOnly(`${e}.1`)}r(rotateIfHuge,"rotateIfHuge"),n(rotateIfHuge,"rotateIfHuge");function workspaceLogWriter(e){const t=path.join(e,".lensmcp","gateway.log");if(ensureFd(t)!==void 0)return o=>{const c=ensureFd(t);if(c===void 0)return;try{fs.writeSync(c,(0,inspector_secret_1.redactInspectorUrls)(o))}catch{closeFd(t);return}const i=(written.get(t)??0)+o.length;i>=CHECK_EVERY?(written.set(t,0),rotateIfHuge(t)):written.set(t,i)}}r(workspaceLogWriter,"workspaceLogWriter"),n(workspaceLogWriter,"workspaceLogWriter");function closeWorkspaceLogs(){for(const e of[...fds.keys()])closeFd(e)}r(closeWorkspaceLogs,"closeWorkspaceLogs"),n(closeWorkspaceLogs,"closeWorkspaceLogs");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var w=Object.defineProperty;var a=(r,t)=>w(r,"name",{value:t,configurable:!0});var c=Object.defineProperty,i=a((r,t)=>c(r,"name",{value:t,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.guestMiddlewarePolicy=guestMiddlewarePolicy,exports.findGatewayMiddleware=findGatewayMiddleware,exports.loadMiddleware=loadMiddleware,exports.createWorkspaceMiddleware=createWorkspaceMiddleware;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));function guestMiddlewarePolicy(r=process.env){const t=r.LENSMCP_GUEST_MIDDLEWARE;return t==="owner"||t==="none"?t:"own"}a(guestMiddlewarePolicy,"guestMiddlewarePolicy"),i(guestMiddlewarePolicy,"guestMiddlewarePolicy");function findGatewayMiddleware(r,t){for(const n of Object.values(t)){let o;try{o=JSON.parse(fs.readFileSync(path.join(r,n.root,"project.json"),"utf8"))}catch{continue}for(const e of Object.values(o.targets??{}))if(e?.executor==="@lensmcp/cluster:gateway"&&typeof e.options?.middleware=="string"&&e.options.middleware)return e.options.middleware}}a(findGatewayMiddleware,"findGatewayMiddleware"),i(findGatewayMiddleware,"findGatewayMiddleware");function loadMiddleware(r){const t=require.resolve(r);delete require.cache[t];const n=require(t),o=n.default??n;if(typeof o!="function")throw new Error(`${r} exports no function`);return o}a(loadMiddleware,"loadMiddleware"),i(loadMiddleware,"loadMiddleware");function createWorkspaceMiddleware(r){const t=r.policy??"own",n=r.load??loadMiddleware,o=new Map;return{set(e,l,s){if(e===r.ownerKey)return;if(!s){o.set(e,void 0);return}const d=path.resolve(l,s);try{o.set(e,n(d)),t==="own"&&console.log(`[gateway] '${e}' routes run its own middleware: ${d}`)}catch(u){o.set(e,void 0),console.warn(`[gateway] could not load '${e}''s middleware ${d} (${u.message}) \u2014 its routes run with NO middleware until it registers again`)}},drop(e){o.delete(e)},for(e){if(e===void 0||e===r.ownerKey||t==="owner")return r.owner;if(t!=="none")return o.get(e)}}}a(createWorkspaceMiddleware,"createWorkspaceMiddleware"),i(createWorkspaceMiddleware,"createWorkspaceMiddleware");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var p=Object.defineProperty;var i=(e,r)=>p(e,"name",{value:r,configurable:!0});var c=Object.defineProperty,s=i((e,r)=>c(e,"name",{value:r,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.processStamp=processStamp,exports.registryPath=registryPath,exports.readWorkspaces=readWorkspaces,exports.registerWorkspace=registerWorkspace,exports.unregisterWorkspace=unregisterWorkspace,exports.isWorkspaceLive=isWorkspaceLive;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path"));function processStamp(e){if(!e||e<=0||process.platform==="win32")return"";try{return(0,node_child_process_1.execFileSync)("ps",["-p",String(e),"-o","lstart="],{encoding:"utf8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{return""}}i(processStamp,"processStamp"),s(processStamp,"processStamp");function registryPath(){const e=process.env.LENSMCP_HOME||os.homedir();return path.join(e,".lensmcp","workspaces.json")}i(registryPath,"registryPath"),s(registryPath,"registryPath");function readWorkspaces(e=registryPath()){try{const r=JSON.parse(fs.readFileSync(e,"utf8"));return Array.isArray(r)?r.filter(t=>!!t&&typeof t.key=="string"&&typeof t.base=="string"):[]}catch{return[]}}i(readWorkspaces,"readWorkspaces"),s(readWorkspaces,"readWorkspaces");function writeWorkspaces(e,r=registryPath()){try{fs.mkdirSync(path.dirname(r),{recursive:!0}),fs.writeFileSync(r,JSON.stringify(e,null,2))}catch{}}i(writeWorkspaces,"writeWorkspaces"),s(writeWorkspaces,"writeWorkspaces");function registerWorkspace(e,r=registryPath()){const t=readWorkspaces(r).filter(o=>o.key!==e.key);t.push(e),t.sort((o,n)=>o.key.localeCompare(n.key)),writeWorkspaces(t,r)}i(registerWorkspace,"registerWorkspace"),s(registerWorkspace,"registerWorkspace");function unregisterWorkspace(e,r=registryPath()){writeWorkspaces(readWorkspaces(r).filter(t=>t.key!==e),r)}i(unregisterWorkspace,"unregisterWorkspace"),s(unregisterWorkspace,"unregisterWorkspace");function isWorkspaceLive(e){if(!e.pid||e.pid<=0)return!1;try{process.kill(e.pid,0)}catch(t){if(t.code!=="EPERM")return!1}if(!e.procStamp)return!0;const r=processStamp(e.pid);return r===""?!0:r===e.procStamp}i(isWorkspaceLive,"isWorkspaceLive"),s(isWorkspaceLive,"isWorkspaceLive");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var h=Object.defineProperty;var l=(e,t)=>h(e,"name",{value:t,configurable:!0});var u=Object.defineProperty,i=l((e,t)=>u(e,"name",{value:t,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.SsrfBlockedError=void 0,exports.isBlockedAddress=isBlockedAddress,exports.assertFetchableUrl=assertFetchableUrl,exports.safeFetch=safeFetch,exports.pinnedLookup=pinnedLookup;const node_net_1=require("node:net"),promises_1=require("node:dns/promises");class SsrfBlockedError extends Error{static{l(this,"SsrfBlockedError")}static{i(this,"SsrfBlockedError")}constructor(t,o,s,r){super(`SSRF guard blocked ${o??"request"}: ${t}${s?` (${s})`:""}`,r!==void 0?{cause:r}:void 0),this.name="SsrfBlockedError",this.reason=t,this.url=o,this.address=s}}exports.SsrfBlockedError=SsrfBlockedError;function buildDefaultBlockList(){const e=new node_net_1.BlockList;return e.addSubnet("0.0.0.0",8,"ipv4"),e.addSubnet("10.0.0.0",8,"ipv4"),e.addSubnet("100.64.0.0",10,"ipv4"),e.addSubnet("127.0.0.0",8,"ipv4"),e.addSubnet("169.254.0.0",16,"ipv4"),e.addSubnet("172.16.0.0",12,"ipv4"),e.addSubnet("192.0.0.0",24,"ipv4"),e.addSubnet("192.168.0.0",16,"ipv4"),e.addSubnet("198.18.0.0",15,"ipv4"),e.addSubnet("240.0.0.0",4,"ipv4"),e.addAddress("::","ipv6"),e.addAddress("::1","ipv6"),e.addSubnet("fc00::",7,"ipv6"),e.addSubnet("fe80::",10,"ipv6"),e}l(buildDefaultBlockList,"buildDefaultBlockList"),i(buildDefaultBlockList,"buildDefaultBlockList");const DEFAULT_BLOCK_LIST=buildDefaultBlockList();function isBlockedAddress(e,t=DEFAULT_BLOCK_LIST){const o=(0,node_net_1.isIP)(e);return o===0?!0:t.check(e,o===6?"ipv6":"ipv4")}l(isBlockedAddress,"isBlockedAddress"),i(isBlockedAddress,"isBlockedAddress");const stripBrackets=i(e=>e.startsWith("[")&&e.endsWith("]")?e.slice(1,-1):e,"stripBrackets"),defaultResolve=i(async e=>(await(0,promises_1.lookup)(e,{all:!0,verbatim:!0})).map(t=>t.address),"defaultResolve");async function assertFetchableUrl(e,t={}){const o=t.allowedProtocols??["http:","https:"];let s;try{s=new URL(e)}catch{throw new SsrfBlockedError("malformed-url",String(e))}if(!o.includes(s.protocol))throw new SsrfBlockedError(`scheme-not-allowed:${s.protocol}`,s.href);if(s.username!==""||s.password!=="")throw new SsrfBlockedError("embedded-credentials",s.href);const r=stripBrackets(s.hostname);if(r==="")throw new SsrfBlockedError("missing-host",s.href);if(t.allowPrivate)return{url:s,hostname:r,addresses:(0,node_net_1.isIP)(r)?[r]:[]};const d=t.blockList??DEFAULT_BLOCK_LIST;if((0,node_net_1.isIP)(r)!==0){if(isBlockedAddress(r,d))throw new SsrfBlockedError("blocked-address",s.href,r);return{url:s,hostname:r,addresses:[r]}}const c=t.resolve??defaultResolve;let a;try{a=await c(r)}catch(n){throw new SsrfBlockedError("dns-resolution-failed",s.href,void 0,n)}if(a.length===0)throw new SsrfBlockedError("dns-no-records",s.href);for(const n of a)if(isBlockedAddress(n,d))throw new SsrfBlockedError("blocked-resolved-address",s.href,n);return{url:s,hostname:r,addresses:a}}l(assertFetchableUrl,"assertFetchableUrl"),i(assertFetchableUrl,"assertFetchableUrl");async function safeFetch(e,t={},o={}){const s=o.fetchImpl??globalThis.fetch,r=o.maxRedirects??5;let d=e;for(let c=0;;c++){const{url:a}=await assertFetchableUrl(d,o),n=await s(a,{...t,redirect:"manual"}),f=n.headers.get("location");if(n.status>=300&&n.status<400&&f){if(c>=r)throw new SsrfBlockedError("too-many-redirects",a.href);d=new URL(f,a).href;continue}return n}}l(safeFetch,"safeFetch"),i(safeFetch,"safeFetch");function pinnedLookup(e){const t=e.map(o=>({address:o,family:(0,node_net_1.isIP)(o)===6?6:4}));return(o,s,r)=>{const d=typeof s=="function"?s:r,c=typeof s=="object"&&s!==null&&s.all===!0;if(t.length===0){d(new Error(`SSRF guard: no pinned address for ${o}`));return}c?d(null,t):d(null,t[0].address,t[0].family)}}l(pinnedLookup,"pinnedLookup"),i(pinnedLookup,"pinnedLookup");
|