@lensmcp/cluster 1.25.34 → 1.25.35
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/child-process-env.js +1 -1
- package/compile-retry.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-host.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/hosted-dashboard.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 +3 -3
- package/executors/gateway/runtime/orphan-reaper.js +2 -2
- package/executors/gateway/runtime/own-log.js +6 -6
- 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 +3 -3
- package/executors/gateway/runtime/source-poller.js +1 -1
- package/executors/gateway/runtime/types.js +1 -1
- package/executors/gateway/runtime/upgrade.js +1 -1
- package/executors/gateway/runtime/warm-start.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/serve/stop-on-signal.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 +2 -2
- 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-guard.js +1 -1
- package/worker-retire.js +1 -1
- package/worker-supervisor.js +2 -2
- package/workspace-paths.js +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var P=Object.defineProperty;var a=(r,e)=>P(r,"name",{value:e,configurable:!0});var m=Object.defineProperty,s=a((r,e)=>m(r,"name",{value:e,configurable:!0}),"s"),g=Object.defineProperty,o=s((r,e)=>g(r,"name",{value:e,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.createProjectGraphStores=createProjectGraphStores,exports.statSignature=statSignature,exports.filesystemNow=filesystemNow,exports.declaringFiles=declaringFiles,exports.computeProjectGraphInProcess=computeProjectGraphInProcess,exports.createProjectGraphStore=createProjectGraphStore;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),node_module_1=require("node:module"),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),registration_guards_1=require("./registration-guards");function createProjectGraphStores(...r){const e=new Map,n=o(t=>{e.set((0,registration_guards_1.canonicalRoot)(t.root),t)},"set");for(const t of r)n(t);return{get:o(t=>e.get((0,registration_guards_1.canonicalRoot)(t)),"get"),all:o(()=>[...e.values()],"all"),set:n,delete:o(t=>{e.delete((0,registration_guards_1.canonicalRoot)(t))},"delete")}}a(createProjectGraphStores,"createProjectGraphStores"),s(createProjectGraphStores,"createProjectGraphStores"),o(createProjectGraphStores,"createProjectGraphStores");function statSignature(r){const e=fs.statSync(r,{throwIfNoEntry:!1});return e?`${e.mtimeMs}:${e.size}:${e.ino}`:"-"}a(statSignature,"statSignature"),s(statSignature,"statSignature"),o(statSignature,"statSignature");const CHANGED_DURING_COMPUTE="?";function filesystemNow(){const r=path.join(os.tmpdir(),`lensmcp-graph-clock-${process.pid}`);try{fs.writeFileSync(r,"");const e=fs.statSync(r).mtimeMs;return fs.unlinkSync(r),e}catch{return Date.now()}}a(filesystemNow,"filesystemNow"),s(filesystemNow,"filesystemNow"),o(filesystemNow,"filesystemNow");function modifiedAfter(r,e){const n=fs.statSync(r,{throwIfNoEntry:!1});return!!n&&n.mtimeMs>e}a(modifiedAfter,"modifiedAfter"),s(modifiedAfter,"modifiedAfter"),o(modifiedAfter,"modifiedAfter");function declaringFiles(r,e){const n=[path.join(r,"nx.json")];for(const t of Object.values(e.nodes)){const i=path.join(r,t.data.root);n.push(path.join(i,"project.json"),path.join(i,"package.json"))}return[...new Set(n)]}a(declaringFiles,"declaringFiles"),s(declaringFiles,"declaringFiles"),o(declaringFiles,"declaringFiles");async function computeProjectGraphInProcess(r){const e=(0,node_module_1.createRequire)(path.join(r,"package.json"))("nx/src/project-graph/project-graph");return e.createProjectGraphAndSourceMapsAsync?e.createProjectGraphAndSourceMapsAsync():{projectGraph:await e.createProjectGraphAsync()}}a(computeProjectGraphInProcess,"computeProjectGraphInProcess"),s(computeProjectGraphInProcess,"computeProjectGraphInProcess"),o(computeProjectGraphInProcess,"computeProjectGraphInProcess");function createProjectGraphStore(r,e,n={}){let t=n.seed,i,u=n.seed?void 0:n.error,d=0;const j=o(()=>{if(!t)return"no project graph yet";for(const[l,h]of t.files)if(statSignature(l)!==h)return`${path.relative(r,l)} changed since the gateway read the project graph`},"staleReason"),y=o(()=>(i??=(async()=>{const l=Date.now(),h=filesystemNow(),S=new Map;if(t)for(const c of t.files.keys())S.set(c,statSignature(c));try{const c=await e(),p=new Map;for(const f of declaringFiles(r,c.projectGraph))p.set(f,S.get(f)??(modifiedAfter(f,h)?CHANGED_DURING_COMPUTE:statSignature(f)));t={root:r,startedAt:l,files:p,...c},u=void 0,d=0,n.onRefreshed?.(t)}catch(c){const p=c?.message??String(c);p!==u&&console.warn(`[gateway] project graph refresh failed for ${r} (its services start through \`nx run\` until it succeeds): ${p}`),u=p,d=Date.now()+(n.retryAfterFailureMs??0)}return t})().finally(()=>{i=void 0}),i),"refresh");return{root:r,current:o(()=>t,"current"),staleReason:j,refresh:y,refreshIfStale:o(()=>{i||Date.now()<d||!j()||y()},"refreshIfStale"),lastError:o(()=>u,"lastError")}}a(createProjectGraphStore,"createProjectGraphStore"),s(createProjectGraphStore,"createProjectGraphStore"),o(createProjectGraphStore,"createProjectGraphStore");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var ee=Object.defineProperty;var D=(o,c)=>ee(o,"name",{value:c,configurable:!0});var Z=Object.defineProperty,s=D((o,c)=>Z(o,"name",{value:c,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isReplayableRequest=isReplayableRequest,exports.upstreamOpen=upstreamOpen,exports.wedgedMessage=wedgedMessage,exports.createProxy=createProxy;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),edge_1=require("./edge"),gateway_errors_1=require("../gateway-errors"),body_stall_1=require("../body-stall"),types_1=require("./types"),pod_probe_1=require("./pod-probe"),gc_notice_1=require("../../../gc-notice"),service_keys_1=require("./service-keys");function isConnError(o){const c=o.code??"";return c==="ECONNREFUSED"||c==="ECONNRESET"||c==="ETIMEDOUT"||c==="EPIPE"||c==="EHOSTUNREACH"||c==="ENOENT"||/ECONNREFUSED|ECONNRESET|socket hang up|EPIPE/i.test(o.message)}D(isConnError,"isConnError"),s(isConnError,"isConnError");const IDEMPOTENT_METHODS=new Set(["GET","HEAD","OPTIONS","PUT","DELETE","TRACE"]);function isReplayableRequest(o){if(!IDEMPOTENT_METHODS.has((o.method??"GET").toUpperCase())||o.headers["transfer-encoding"]!==void 0)return!1;const c=o.headers["content-length"];return!(c!==void 0&&String(c).trim()!=="0")}D(isReplayableRequest,"isReplayableRequest"),s(isReplayableRequest,"isReplayableRequest");function edgeGone(o,c){return c.headersSent||c.writableEnded||c.destroyed===!0||o.aborted===!0}D(edgeGone,"edgeGone"),s(edgeGone,"edgeGone");const HOP_BY_HOP=new Set(["connection","keep-alive","proxy-connection","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),UPSTREAM_CONNECTION_HEADERS=["connection","keep-alive","proxy-connection"];function returnRequestId(o,c){if(o["x-request-id"]!==void 0)return;const u=c.headers["x-request-id"],q=Array.isArray(u)?u[0]:u;typeof q=="string"&&q!==""&&(o["x-request-id"]=q)}D(returnRequestId,"returnRequestId"),s(returnRequestId,"returnRequestId");const httpProxy=require("http-proxy");function declaredFirstByteMs(o){const c=Number(o);return Number.isFinite(c)&&c>0?c:types_1.POD_RESPONSE_TIMEOUT_MS}D(declaredFirstByteMs,"declaredFirstByteMs"),s(declaredFirstByteMs,"declaredFirstByteMs");const secs=s(o=>`${(o/1e3).toFixed(1)}s`,"secs"),upstreams=new WeakMap;function upstreamOpen(o){const c=upstreams.get(o),u=c?.socket;return!!c&&!c.destroyed&&!!u&&!u.destroyed}D(upstreamOpen,"upstreamOpen"),s(upstreamOpen,"upstreamOpen");function wedgedMessage(o,c,u){const q=u.failure==="gone"?"its process is gone":u.failure==="silent"?`it did not answer its liveness check for ${secs(u.silentMs)}`:"it gave no liveness answer";return`Pod ${o} of ${c} sent no response for ${secs(u.heldMs)} and ${q} \u2014 taken out of rotation, and the service is being restarted, so work it was still doing for this request may have been cut short. Retry if the call is safe to repeat.`}D(wedgedMessage,"wedgedMessage"),s(wedgedMessage,"wedgedMessage");function armFirstByteGuard(o){let c,u=!1,q=!1,V=!1,k,x=0,E=(0,body_stall_1.requestBodyArriving)(o.req)?void 0:Date.now();const N=s(()=>{E??=Date.now()},"onBodyEnd");E===void 0&&o.req.once("end",N);const H=s(()=>(E===void 0&&!(0,body_stall_1.requestBodyArriving)(o.req)&&(E=Date.now()),E===void 0?0:Date.now()-E),"heldMs"),A=s(T=>{c=setTimeout(C,T),c.unref?.()},"arm"),C=s(()=>{if(u||!o.pending())return;const T=H();if(o.ceilingMs<=0){if(E!==void 0&&T>=o.firstByteMs){o.onWedged(`no response within ${T}ms (wedged socket) \u2014 evicted + respawning`,{heldMs:T,silentMs:0,probes:0,failure:"deadline"});return}A(E===void 0?o.firstByteMs:o.firstByteMs-T);return}(0,pod_probe_1.probePodAliveVerdict)(o.socketPath,void 0,o.serviceKey).then(({alive:L,failure:b})=>{if(u||!o.pending())return;const j=H();if(!L){if(b==="gone"&&o.upstreamOpen?.()){if(j>=o.ceilingMs){o.onCeiling(`retiring (its socket is gone) and no response within ${j}ms (ceiling ${o.ceilingMs}ms) \u2014 giving up on this request, pod kept`);return}V||(V=!0,o.onRetiring?.(j)),A(Math.max(o.firstByteMs,types_1.POD_ALIVE_PROBE_TIMEOUT_MS));return}if(x+=1,b==="silent"&&(0,gc_notice_1.inAnnouncedGc)(o.socketPath)){k=void 0,A(types_1.POD_ALIVE_PROBE_TIMEOUT_MS);return}if(b==="silent"&&types_1.POD_WEDGE_CONFIRM_MS>0&&(k??=Date.now(),Date.now()-k<types_1.POD_WEDGE_CONFIRM_MS)){A(types_1.POD_ALIVE_PROBE_TIMEOUT_MS);return}const B=k===void 0?0:Date.now()-k,I=b==="gone"?"its socket no longer accepts (the pod process is gone)":b==="silent"?`nothing answered on ${types_1.POD_ALIVE_PATH} for ${B}ms (${x} probe${x===1?"":"s"})`:`no liveness answer on ${types_1.POD_ALIVE_PATH}`;o.onWedged(`no response within ${j}ms and ${I} (wedged socket) \u2014 evicted + respawning`,{heldMs:j,silentMs:B,probes:x,failure:b??"no-route"});return}if(k=void 0,j>=o.ceilingMs){o.onCeiling(`alive on ${types_1.POD_ALIVE_PATH} but no response within ${j}ms (ceiling ${o.ceilingMs}ms) \u2014 giving up on this request, pod kept`,L);return}!q&&E!==void 0&&(q=!0,o.onSlow(j,L)),A(Math.max(o.firstByteMs,types_1.POD_ALIVE_PROBE_TIMEOUT_MS))})},"onDeadline");return A(o.firstByteMs),{clear:s(()=>{u=!0,c&&clearTimeout(c),o.req.removeListener("end",N)},"clear")}}D(armFirstByteGuard,"armFirstByteGuard"),s(armFirstByteGuard,"armFirstByteGuard");function createProxy(o,c,u){const{recordEdge:q,finishTrace:V,traceStep:k,emit:x}=c,E=s((e,r,t,d)=>{const g=d.kind==="pod-evicted";x(g?"error":"warning",`${g?"pod evicted":"request given up"}: ${e.project} (${t}) \u2014 ${d.status}`,`cluster-pod-incident:${e.project}`,{kind:d.kind,project:e.project,pod:t,status:d.status,reason:d.reason,traceId:(0,gateway_errors_1.ensureRequestId)(r),method:r.method,path:(r.url??"").split("?")[0],...d.detail??{}})},"reportPodIncident"),N=s(async(e,r)=>{const t=e.pool;if(!t)return;t.scannedAt=0;let d=(0,discovery_1.pickSock)(t,o.scanTtlMs);return!d&&e.svc&&(k(r,"cold-start",{project:e.project}),await u.ensureUp(e.svc)&&(t.scannedAt=0,d=(0,discovery_1.pickSock)(t,o.scanTtlMs))),d},"anotherPod"),H=s((e,r,t,d,g)=>{console.log(`[gateway] pod ${t} of ${e.project} is gone \u2014 its ${r.method} was not answered, sending it to ${d}`),x("info",`request moved to another pod: ${e.project} (${t} \u2192 ${d})`,`cluster-pod-moved:${e.project}`,{kind:"pod-gone-rerouted",project:e.project,pod:t,to:d,reason:g,traceId:(0,gateway_errors_1.ensureRequestId)(r),method:r.method,path:(r.url??"").split("?")[0]})},"reportPodMoved"),A=s(async e=>{if(!e.lens||!o.lensSupervisor)return"unsupported";let r;const t=new Promise(f=>{r=setTimeout(()=>f("timeout"),types_1.LENS_REQUEST_RECOVERY_WAIT_MS),r.unref?.()}),d=o.lensSupervisor.recover(e.lens,"proxy-connection").then(f=>f?"ready":"failed").catch(()=>"failed"),g=await Promise.race([d,t]);r&&clearTimeout(r);const S=o.lensSupervisor.status(e.lens);return g==="failed"&&(!S||S.state==="ready")?"unsupported":g},"waitForManagedRecovery"),C=s((e,r,t,d,g,S)=>{if(t.headersSent||t.writableEnded||t.destroyed){t.destroyed||t.destroy();return}const f=e.lens?o.lensSupervisor?.status(e.lens):void 0,$=S==="timeout"||f?.state==="starting"||f?.state==="replacing",P=(0,gateway_errors_1.ensureRequestId)(r),l=e.lens?{project:e.project,reason:f?.reason??"connection-failure",generation:f?.generation??0,...$?{retryAfterMs:2e3}:{}}:void 0,i=$?503:502,y=$?"starting":"unavailable";console.error(`[gateway] ${new Date().toISOString()} upstream-error traceId=${P} project=${e.project} target=${String(d)} state=${f?.state??"unmanaged"} generation=${f?.generation??0}: ${g.message}`),x("warning",`upstream unavailable: ${e.project}`,`cluster-upstream:${e.project}`,{kind:"upstream-error",traceId:P,project:e.project,target:String(d),state:f?.state??"unmanaged",generation:f?.generation,error:g.message}),(0,edge_1.sendError)(t,r,i,y,$?`Upstream ${e.project} is restarting.`:`Upstream ${e.project} unavailable.`,l,$?{"retry-after":"2"}:void 0)},"sendTerminalUpstreamError"),T=(0,body_stall_1.createBodyStallGuard)(o.bodyStallMs??types_1.BODY_STALL_MS),L={keepAlive:!0,keepAliveMsecs:3e4,maxSockets:1024,maxFreeSockets:256},b=new http.Agent(L),j=new(require("node:https")).Agent(L),B=s(e=>typeof e=="string"&&e.startsWith("https:")?j:b,"agentForTarget"),I=httpProxy.createProxyServer({xfwd:!1,secure:!1,proxyTimeout:12e4,agent:b}),Y=s((e,r,t)=>{const d=s(()=>{t()||e.destroyed||e.destroy()},"onEdgeClose");r.once("close",d),e.once("close",()=>r.removeListener("close",d))},"propagateEdgeCancel");I.on("proxyReq",(e,r,t)=>{upstreams.set(r,e);for(const d of UPSTREAM_CONNECTION_HEADERS)e.removeHeader(d);e.setHeader("connection","keep-alive"),Y(e,t,()=>t.writableEnded)}),I.on("proxyRes",(e,r,t)=>{const d=r.__lensmcpPod;d&&(e.headers["x-lensmcp-pod"]=d),delete e.headers["x-powered-by"],e.headers.server="LensMCP",returnRequestId(e.headers,r),t&&Y(e,t,()=>t.writableEnded),t&&T.armResponse(t)});const Q=s((e,r,t,d)=>{(0,edge_1.stampForwardingHeaders)(o,r),T.arm(r);const g={},S=r.method==="GET"||r.method==="HEAD"||r.method==="OPTIONS";for(const[n,a]of Object.entries(r.headers))a===void 0||n.startsWith(":")||HOP_BY_HOP.has(n)||S&&(n==="content-length"||n==="transfer-encoding")||(g[n]=a);let f=http,$;if(typeof e=="object")$={socketPath:e.socketPath,path:r.url,method:r.method,headers:g,agent:b};else{const n=new URL(e),a=n.protocol==="https:";f=a?require("node:https"):http,g.host=n.host,$={protocol:n.protocol,hostname:n.hostname,port:n.port||(a?443:80),path:r.url,method:r.method,headers:g,agent:B(e)}}const P=t;P.__lensmcpErrContained||(P.__lensmcpErrContained=!0,t.on("error",()=>{}));let l;const i=s(()=>{t.writableEnded||p.destroy()},"onReqGone"),y=s(()=>{l&&!l.destroyed&&l.destroy()},"onEdgeClose"),_=s(()=>{r.removeListener("error",i),r.removeListener("aborted",i),r.removeListener("close",i),t.removeListener("close",y)},"detach"),p=f.request($,n=>{if(l=n,d.onResponse(),t.headersSent||t.writableEnded||t.destroyed){n.destroy();return}const a={};for(const[O,U]of Object.entries(n.headers))U===void 0||HOP_BY_HOP.has(O)||(a[O]=U);delete a["x-powered-by"],a.server="LensMCP",returnRequestId(a,r);const w=r.__lensmcpPod;w&&(a["x-lensmcp-pod"]=w);try{t.writeHead(n.statusCode??502,a)}catch(O){console.error("[gateway] h2 relay: bad response header, resetting stream:",O.message),n.destroy(),t.destroyed||t.destroy(O);return}n.pipe(t),T.armResponse(t);const R=s(()=>{!t.writableEnded&&!t.destroyed&&t.destroy()},"abortEdge");n.once("error",R),n.once("close",R),t.on("close",y)});p.once("error",n=>d.onError(n)),upstreams.set(r,p),p.once("close",_),r.on("error",i),r.on("aborted",i),r.on("close",i),S?p.end():r.pipe(p)},"pipeUpstream"),X=s(async(e,r,t)=>{const d=r.__lensmcpTrace;if(e.pool){const l=e.svc;l&&(l.lastUsed=Date.now(),l.inflight+=1,t.on("close",()=>{l.inflight-=1,l.lastUsed=Date.now()}));let i=(0,discovery_1.pickSock)(e.pool,o.scanTtlMs);if(!i&&l&&(k(d,"cold-start",{project:e.project}),await u.ensureUp(l)&&(i=(0,discovery_1.pickSock)(e.pool,o.scanTtlMs))),l&&i&&u.markUp(l,"observed"),l&&u.scaleUp(l),!i){const _=l?.lastErrors?.length?` Service errors: ${l.lastErrors.join("; ")}`:"";(0,edge_1.sendError)(t,r,503,"unavailable",`Service ${e.project} is not reachable (no pods in ${e.pool.dir}).${_} The watcher recovers and the next request retries automatically.`);return}const y=s((_,p)=>{const n=path.basename(_,".sock");r.__lensmcpPod=n,k(d,"pod-select",{pod:n,pods:e.pool.socks.length,strategy:"round-robin",...p?{movedFrom:p}:{}});let a=!1;const w=s((h,M="unlink")=>{if(e.pool.socks=e.pool.socks.filter(m=>m!==_),e.pool.idx=-1,M==="unlink")try{fs.unlinkSync(_)}catch{}console.error(`[gateway] pod ${n} of ${e.project}: ${h}`)},"evictPod"),R=armFirstByteGuard({socketPath:_,serviceKey:o.serviceKeys[(0,service_keys_1.serviceKeyId)(e.svc?.wsKey,e.project)],req:r,firstByteMs:declaredFirstByteMs(e.svc?.decl?.firstByteMs),ceilingMs:types_1.POD_SLOW_FIRST_BYTE_MS,pending:s(()=>!a&&!t.headersSent&&!t.writableEnded,"pending"),upstreamOpen:s(()=>upstreamOpen(r),"upstreamOpen"),onRetiring:s(h=>{console.log(`[gateway] pod ${n} of ${e.project}: retiring (its socket is gone) but still holds this ${r.method} after ${h}ms \u2014 waiting for it, not evicting`)},"onRetiring"),onWedged:s((h,M)=>{a=!0,w(h),E(e,r,n,{kind:"pod-evicted",status:502,reason:h,detail:M}),(0,edge_1.sendError)(t,r,502,"unavailable",wedgedMessage(n,e.project,M))},"onWedged"),onCeiling:s(h=>{a=!0,w(h,"keep"),E(e,r,n,{kind:"request-gave-up",status:504,reason:h}),(0,edge_1.sendError)(t,r,504,"unavailable",`Pod ${n} of ${e.project} did not answer in time \u2014 retry, or raise cluster.firstByteMs. The pod was kept: the request may still complete there.`)},"onCeiling"),onSlow:s((h,M)=>{console.log(`[gateway] pod ${n} of ${e.project}: slow first byte, pod alive (${h}ms, ${M.inflight} in-flight, ${M.activeWork} background) \u2014 waiting, not evicting. Set cluster.firstByteMs on ${e.project} to size this route's budget.`)},"onSlow")});t.on("close",()=>R.clear());const O=_,U=isReplayableRequest(r);let W=0;const F=s(()=>{W+=1,Q({socketPath:O},r,t,{onResponse:s(()=>{R.clear(),a=!0},"onResponse"),onError:s(h=>{if(!a){if(edgeGone(r,t)){R.clear(),a=!0;return}(0,pod_probe_1.podConnectionVerdict)(O,h).then(M=>{if(!a){if(M==="alive"&&W<2&&U&&!edgeGone(r,t)){console.log(`[gateway] pod ${n} of ${e.project}: ${h.message} on one connection, the pod still accepts \u2014 sending the ${r.method} again on a fresh one`),F();return}if(R.clear(),a=!0,M==="gone"){w(h.message);const m=s(()=>{E(e,r,n,{kind:"pod-evicted",status:502,reason:`${h.message} \u2014 its socket no longer accepts (the pod process is gone)${p?`; the request had already been moved here from ${p}`:""}`}),(0,edge_1.sendError)(t,r,502,"unavailable",`Pod ${n} of ${e.project} is gone (${h.message}) \u2014 retry.`)},"giveUp");if(p||!U){m();return}N(e,d).then(v=>{if(!edgeGone(r,t)){if(!v){m();return}H(e,r,n,path.basename(v,".sock"),h.message),y(v,n)}},m);return}console.error(`[gateway] pod ${n} of ${e.project}: ${h.message} on one connection \u2014 the pod still accepts connections, so it stays in the pool`),(0,edge_1.sendError)(t,r,502,"unavailable",`Pod ${n} of ${e.project} dropped the connection \u2014 retry.`)}})}},"onError")})},"sendToPod");F()},"onPod");y(i);return}const g=Date.now()+types_1.UPSTREAM_HEAL_WINDOW_MS;let S=0,f=!1;const $=isReplayableRequest(r),P=s(()=>{if(edgeGone(r,t))return;const l=e.target;Q(l,r,t,{onResponse:s(()=>{},"onResponse"),onError:s(i=>{if(isConnError(i)&&(S+=1),e.lens&&isConnError(i)&&$&&S>=2&&!f&&!edgeGone(r,t)){f=!0,A(e).then(y=>{if(!edgeGone(r,t)){if(y==="ready"){P();return}if(y==="unsupported"&&Date.now()<g){setTimeout(P,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}C(e,r,t,e.target,i,y)}});return}if(isConnError(i)&&$&&Date.now()<g&&!edgeGone(r,t)){setTimeout(P,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}if(t.headersSent||t.writableEnded||t.destroyed){t.destroyed||t.destroy();return}C(e,r,t,l,i)},"onError")})},"tryTcp");P()},"forwardNative");return{proxy:I,forward:s(async(e,r,t)=>{const d=Date.now(),g=r.__lensmcpTrace;if(t.on("close",()=>{q(e,Date.now()-d,t.statusCode??0,r.__lensmcpCaller),V(g,e.project,t.statusCode??0,{...r.__lensmcpPod?{pod:r.__lensmcpPod}:{},...r.__lensmcpCaller?{caller:r.__lensmcpCaller}:{}},e)}),e.prependPrefix&&!r.url?.startsWith(e.prependPrefix)&&(r.url=e.prependPrefix+(r.url??"/")),(0,edge_1.stampForwardingHeaders)(o,r),T.arm(r),(r.httpVersionMajor??1)>=2){await X(e,r,t);return}if(e.pool){const i=e.svc;i&&(i.lastUsed=Date.now(),i.inflight+=1,t.on("close",()=>{i.inflight-=1,i.lastUsed=Date.now()}));let y=(0,discovery_1.pickSock)(e.pool,o.scanTtlMs);if(!y&&i&&(k(g,"cold-start",{project:e.project}),await u.ensureUp(i)&&(y=(0,discovery_1.pickSock)(e.pool,o.scanTtlMs))),i&&y&&u.markUp(i,"observed"),i&&u.scaleUp(i),!y){const p=i?.lastErrors?.length?` Service errors: ${i.lastErrors.join("; ")}`:"";(0,edge_1.sendError)(t,r,503,"unavailable",`Service ${e.project} is not reachable (no pods in ${e.pool.dir}).${p} The watcher recovers and the next request retries automatically.`);return}const _=s((p,n)=>{const a=path.basename(p,".sock");r.__lensmcpPod=a,k(g,"pod-select",{pod:a,pods:e.pool.socks.length,strategy:"round-robin",...n?{movedFrom:n}:{}});let w=!1;const R=s((m,v="unlink")=>{if(e.pool.socks=e.pool.socks.filter(G=>G!==p),e.pool.idx=-1,v==="unlink")try{fs.unlinkSync(p)}catch{}console.error(`[gateway] pod ${a} of ${e.project}: ${m}`)},"evictPod"),O=armFirstByteGuard({socketPath:p,serviceKey:o.serviceKeys[(0,service_keys_1.serviceKeyId)(e.svc?.wsKey,e.project)],req:r,firstByteMs:declaredFirstByteMs(e.svc?.decl?.firstByteMs),ceilingMs:types_1.POD_SLOW_FIRST_BYTE_MS,pending:s(()=>!w&&!t.headersSent&&!t.writableEnded,"pending"),upstreamOpen:s(()=>upstreamOpen(r),"upstreamOpen"),onRetiring:s(m=>{console.log(`[gateway] pod ${a} of ${e.project}: retiring (its socket is gone) but still holds this ${r.method} after ${m}ms \u2014 waiting for it, not evicting`)},"onRetiring"),onWedged:s((m,v)=>{w=!0,R(m),E(e,r,a,{kind:"pod-evicted",status:502,reason:m,detail:v}),(0,edge_1.sendError)(t,r,502,"unavailable",wedgedMessage(a,e.project,v))},"onWedged"),onCeiling:s(m=>{w=!0,R(m,"keep"),E(e,r,a,{kind:"request-gave-up",status:504,reason:m}),(0,edge_1.sendError)(t,r,504,"unavailable",`Pod ${a} of ${e.project} did not answer in time \u2014 retry, or raise cluster.firstByteMs. The pod was kept: the request may still complete there.`)},"onCeiling"),onSlow:s((m,v)=>{console.log(`[gateway] pod ${a} of ${e.project}: slow first byte, pod alive (${m}ms, ${v.inflight} in-flight, ${v.activeWork} background) \u2014 waiting, not evicting. Set cluster.firstByteMs on ${e.project} to size this route's budget.`)},"onSlow")});t.on("close",()=>O.clear());const U=Math.max(12e4,types_1.POD_SLOW_FIRST_BYTE_MS+6e4),W=p,F=isReplayableRequest(r);let h=0;const M=s(()=>{h+=1;const m=Date.now();I.web(r,t,{target:{socketPath:W},agent:b,proxyTimeout:U},v=>{if(!w){if(edgeGone(r,t)){O.clear(),w=!0;return}(0,pod_probe_1.podConnectionVerdict)(W,v).then(G=>{if(w)return;const J=Date.now()-m>=U-250;if(G==="alive"&&h<2&&F&&!J&&!edgeGone(r,t)){console.log(`[gateway] pod ${a} of ${e.project}: ${v.message} on one connection, the pod still accepts \u2014 sending the ${r.method} again on a fresh one`),M();return}if(O.clear(),w=!0,G==="gone"){R(v.message);const K=s(()=>{E(e,r,a,{kind:"pod-evicted",status:502,reason:`${v.message} \u2014 its socket no longer accepts (the pod process is gone)${n?`; the request had already been moved here from ${n}`:""}`}),(0,edge_1.sendError)(t,r,502,"unavailable",`Pod ${a} of ${e.project} is gone (${v.message}) \u2014 retry.`)},"giveUp");if(n||!F||J){K();return}N(e,g).then(z=>{if(!edgeGone(r,t)){if(!z){K();return}H(e,r,a,path.basename(z,".sock"),v.message),_(z,a)}},K);return}console.error(`[gateway] pod ${a} of ${e.project}: ${v.message} on one connection \u2014 the pod still accepts connections, so it stays in the pool`),(0,edge_1.sendError)(t,r,502,"unavailable",`Pod ${a} of ${e.project} dropped the connection \u2014 retry.`)})}})},"sendToPod");M()},"onPod");_(y);return}const S=Date.now()+types_1.UPSTREAM_HEAL_WINDOW_MS;let f=0,$=!1;const P=isReplayableRequest(r),l=s(()=>{if(edgeGone(r,t))return;const i=e.target,y={target:i,autoRewrite:typeof i=="string",changeOrigin:!0,agent:B(i)};I.web(r,t,y,_=>{if(isConnError(_)&&(f+=1),e.lens&&isConnError(_)&&P&&f>=2&&!$&&!edgeGone(r,t)){$=!0,A(e).then(p=>{if(!edgeGone(r,t)){if(p==="ready"){l();return}if(p==="unsupported"&&Date.now()<S){setTimeout(l,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}C(e,r,t,e.target,_,p)}});return}if(isConnError(_)&&P&&Date.now()<S&&!edgeGone(r,t)){setTimeout(l,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}t.destroyed||C(e,r,t,i,_)})},"tryTcp");l()},"forward"),agentForTarget:B,destroyAgents:s(()=>{T.stop(),b.destroy(),j.destroy()},"destroyAgents"),closeProxy:s(()=>{try{I.close?.()}catch{}},"closeProxy")}}D(createProxy,"createProxy"),s(createProxy,"createProxy");
|
|
1
|
+
"use strict";var oe=Object.defineProperty;var q=(r,a)=>oe(r,"name",{value:a,configurable:!0});var ee=Object.defineProperty,D=q((r,a)=>ee(r,"name",{value:a,configurable:!0}),"D"),Z=Object.defineProperty,s=D((r,a)=>Z(r,"name",{value:a,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isReplayableRequest=isReplayableRequest,exports.upstreamOpen=upstreamOpen,exports.wedgedMessage=wedgedMessage,exports.createProxy=createProxy;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),edge_1=require("./edge"),gateway_errors_1=require("../gateway-errors"),body_stall_1=require("../body-stall"),types_1=require("./types"),pod_probe_1=require("./pod-probe"),gc_notice_1=require("../../../gc-notice"),service_keys_1=require("./service-keys");function isConnError(r){const a=r.code??"";return a==="ECONNREFUSED"||a==="ECONNRESET"||a==="ETIMEDOUT"||a==="EPIPE"||a==="EHOSTUNREACH"||a==="ENOENT"||/ECONNREFUSED|ECONNRESET|socket hang up|EPIPE/i.test(r.message)}q(isConnError,"isConnError"),D(isConnError,"isConnError"),s(isConnError,"isConnError");const IDEMPOTENT_METHODS=new Set(["GET","HEAD","OPTIONS","PUT","DELETE","TRACE"]);function isReplayableRequest(r){if(!IDEMPOTENT_METHODS.has((r.method??"GET").toUpperCase())||r.headers["transfer-encoding"]!==void 0)return!1;const a=r.headers["content-length"];return!(a!==void 0&&String(a).trim()!=="0")}q(isReplayableRequest,"isReplayableRequest"),D(isReplayableRequest,"isReplayableRequest"),s(isReplayableRequest,"isReplayableRequest");function edgeGone(r,a){return a.headersSent||a.writableEnded||a.destroyed===!0||r.aborted===!0}q(edgeGone,"edgeGone"),D(edgeGone,"edgeGone"),s(edgeGone,"edgeGone");const HOP_BY_HOP=new Set(["connection","keep-alive","proxy-connection","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),UPSTREAM_CONNECTION_HEADERS=["connection","keep-alive","proxy-connection"];function returnRequestId(r,a){if(r["x-request-id"]!==void 0)return;const u=a.headers["x-request-id"],x=Array.isArray(u)?u[0]:u;typeof x=="string"&&x!==""&&(r["x-request-id"]=x)}q(returnRequestId,"returnRequestId"),D(returnRequestId,"returnRequestId"),s(returnRequestId,"returnRequestId");const httpProxy=require("http-proxy");function declaredFirstByteMs(r){const a=Number(r);return Number.isFinite(a)&&a>0?a:types_1.POD_RESPONSE_TIMEOUT_MS}q(declaredFirstByteMs,"declaredFirstByteMs"),D(declaredFirstByteMs,"declaredFirstByteMs"),s(declaredFirstByteMs,"declaredFirstByteMs");const secs=s(r=>`${(r/1e3).toFixed(1)}s`,"secs"),upstreams=new WeakMap;function upstreamOpen(r){const a=upstreams.get(r),u=a?.socket;return!!a&&!a.destroyed&&!!u&&!u.destroyed}q(upstreamOpen,"upstreamOpen"),D(upstreamOpen,"upstreamOpen"),s(upstreamOpen,"upstreamOpen");function wedgedMessage(r,a,u){const x=u.failure==="gone"?"its process is gone":u.failure==="silent"?`it did not answer its liveness check for ${secs(u.silentMs)}`:"it gave no liveness answer";return`Pod ${r} of ${a} sent no response for ${secs(u.heldMs)} and ${x} \u2014 taken out of rotation, and the service is being restarted, so work it was still doing for this request may have been cut short. Retry if the call is safe to repeat.`}q(wedgedMessage,"wedgedMessage"),D(wedgedMessage,"wedgedMessage"),s(wedgedMessage,"wedgedMessage");function armFirstByteGuard(r){let a,u=!1,x=!1,G=!1,k,I=0,w=(0,body_stall_1.requestBodyArriving)(r.req)?void 0:Date.now();const F=s(()=>{w??=Date.now()},"onBodyEnd");w===void 0&&r.req.once("end",F);const H=s(()=>(w===void 0&&!(0,body_stall_1.requestBodyArriving)(r.req)&&(w=Date.now()),w===void 0?0:Date.now()-w),"heldMs"),A=s(T=>{a=setTimeout(B,T),a.unref?.()},"arm"),B=s(()=>{if(u||!r.pending())return;const T=H();if(r.ceilingMs<=0){if(w!==void 0&&T>=r.firstByteMs){r.onWedged(`no response within ${T}ms (wedged socket) \u2014 evicted + respawning`,{heldMs:T,silentMs:0,probes:0,failure:"deadline"});return}A(w===void 0?r.firstByteMs:r.firstByteMs-T);return}(0,pod_probe_1.probePodAliveVerdict)(r.socketPath,void 0,r.serviceKey).then(({alive:L,failure:b})=>{if(u||!r.pending())return;const R=H();if(!L){if(b==="gone"&&r.upstreamOpen?.()){if(R>=r.ceilingMs){r.onCeiling(`retiring (its socket is gone) and no response within ${R}ms (ceiling ${r.ceilingMs}ms) \u2014 giving up on this request, pod kept`);return}G||(G=!0,r.onRetiring?.(R)),A(Math.max(r.firstByteMs,types_1.POD_ALIVE_PROBE_TIMEOUT_MS));return}if(I+=1,b==="silent"&&(0,gc_notice_1.inAnnouncedGc)(r.socketPath)){k=void 0,A(types_1.POD_ALIVE_PROBE_TIMEOUT_MS);return}if(b==="silent"&&types_1.POD_WEDGE_CONFIRM_MS>0&&(k??=Date.now(),Date.now()-k<types_1.POD_WEDGE_CONFIRM_MS)){A(types_1.POD_ALIVE_PROBE_TIMEOUT_MS);return}const N=k===void 0?0:Date.now()-k,U=b==="gone"?"its socket no longer accepts (the pod process is gone)":b==="silent"?`nothing answered on ${types_1.POD_ALIVE_PATH} for ${N}ms (${I} probe${I===1?"":"s"})`:`no liveness answer on ${types_1.POD_ALIVE_PATH}`;r.onWedged(`no response within ${R}ms and ${U} (wedged socket) \u2014 evicted + respawning`,{heldMs:R,silentMs:N,probes:I,failure:b??"no-route"});return}if(k=void 0,R>=r.ceilingMs){r.onCeiling(`alive on ${types_1.POD_ALIVE_PATH} but no response within ${R}ms (ceiling ${r.ceilingMs}ms) \u2014 giving up on this request, pod kept`,L);return}!x&&w!==void 0&&(x=!0,r.onSlow(R,L)),A(Math.max(r.firstByteMs,types_1.POD_ALIVE_PROBE_TIMEOUT_MS))})},"onDeadline");return A(r.firstByteMs),{clear:s(()=>{u=!0,a&&clearTimeout(a),r.req.removeListener("end",F)},"clear")}}q(armFirstByteGuard,"armFirstByteGuard"),D(armFirstByteGuard,"armFirstByteGuard"),s(armFirstByteGuard,"armFirstByteGuard");function createProxy(r,a,u){const{recordEdge:x,finishTrace:G,traceStep:k,emit:I}=a,w=s((e,t,o,d)=>{const g=d.kind==="pod-evicted";I(g?"error":"warning",`${g?"pod evicted":"request given up"}: ${e.project} (${o}) \u2014 ${d.status}`,`cluster-pod-incident:${e.project}`,{kind:d.kind,project:e.project,pod:o,status:d.status,reason:d.reason,traceId:(0,gateway_errors_1.ensureRequestId)(t),method:t.method,path:(t.url??"").split("?")[0],...d.detail??{}})},"reportPodIncident"),F=s(async(e,t)=>{const o=e.pool;if(!o)return;o.scannedAt=0;let d=(0,discovery_1.pickSock)(o,r.scanTtlMs);return!d&&e.svc&&(k(t,"cold-start",{project:e.project}),await u.ensureUp(e.svc)&&(o.scannedAt=0,d=(0,discovery_1.pickSock)(o,r.scanTtlMs))),d},"anotherPod"),H=s((e,t,o,d,g)=>{console.log(`[gateway] pod ${o} of ${e.project} is gone \u2014 its ${t.method} was not answered, sending it to ${d}`),I("info",`request moved to another pod: ${e.project} (${o} \u2192 ${d})`,`cluster-pod-moved:${e.project}`,{kind:"pod-gone-rerouted",project:e.project,pod:o,to:d,reason:g,traceId:(0,gateway_errors_1.ensureRequestId)(t),method:t.method,path:(t.url??"").split("?")[0]})},"reportPodMoved"),A=s(async e=>{if(!e.lens||!r.lensSupervisor)return"unsupported";let t;const o=new Promise(y=>{t=setTimeout(()=>y("timeout"),types_1.LENS_REQUEST_RECOVERY_WAIT_MS),t.unref?.()}),d=r.lensSupervisor.recover(e.lens,"proxy-connection").then(y=>y?"ready":"failed").catch(()=>"failed"),g=await Promise.race([d,o]);t&&clearTimeout(t);const S=r.lensSupervisor.status(e.lens);return g==="failed"&&(!S||S.state==="ready")?"unsupported":g},"waitForManagedRecovery"),B=s((e,t,o,d,g,S)=>{if(o.headersSent||o.writableEnded||o.destroyed){o.destroyed||o.destroy();return}const y=e.lens?r.lensSupervisor?.status(e.lens):void 0,_=S==="timeout"||y?.state==="starting"||y?.state==="replacing",P=(0,gateway_errors_1.ensureRequestId)(t),l=e.lens?{project:e.project,reason:y?.reason??"connection-failure",generation:y?.generation??0,..._?{retryAfterMs:2e3}:{}}:void 0,i=_?503:502,h=_?"starting":"unavailable";console.error(`[gateway] ${new Date().toISOString()} upstream-error traceId=${P} project=${e.project} target=${String(d)} state=${y?.state??"unmanaged"} generation=${y?.generation??0}: ${g.message}`),I("warning",`upstream unavailable: ${e.project}`,`cluster-upstream:${e.project}`,{kind:"upstream-error",traceId:P,project:e.project,target:String(d),state:y?.state??"unmanaged",generation:y?.generation,error:g.message}),(0,edge_1.sendError)(o,t,i,h,_?`Upstream ${e.project} is restarting.`:`Upstream ${e.project} unavailable.`,l,_?{"retry-after":"2"}:void 0)},"sendTerminalUpstreamError"),T=(0,body_stall_1.createBodyStallGuard)(r.bodyStallMs??types_1.BODY_STALL_MS),L={keepAlive:!0,keepAliveMsecs:3e4,maxSockets:1024,maxFreeSockets:256},b=new http.Agent(L),R=new(require("node:https")).Agent(L),N=s(e=>typeof e=="string"&&e.startsWith("https:")?R:b,"agentForTarget"),U=httpProxy.createProxyServer({xfwd:!1,secure:!1,proxyTimeout:12e4,agent:b}),z=s((e,t,o)=>{const d=s(()=>{o()||e.destroyed||e.destroy()},"onEdgeClose");t.once("close",d),e.once("close",()=>t.removeListener("close",d))},"propagateEdgeCancel");U.on("proxyReq",(e,t,o)=>{upstreams.set(t,e);for(const d of UPSTREAM_CONNECTION_HEADERS)e.removeHeader(d);e.setHeader("connection","keep-alive"),z(e,o,()=>o.writableEnded)}),U.on("proxyRes",(e,t,o)=>{const d=t.__lensmcpPod;d&&(e.headers["x-lensmcp-pod"]=d),delete e.headers["x-powered-by"],e.headers.server="LensMCP",returnRequestId(e.headers,t),o&&z(e,o,()=>o.writableEnded),o&&T.armResponse(o)});const J=s((e,t,o,d)=>{(0,edge_1.stampForwardingHeaders)(r,t),T.arm(t);const g={},S=t.method==="GET"||t.method==="HEAD"||t.method==="OPTIONS";for(const[n,c]of Object.entries(t.headers))c===void 0||n.startsWith(":")||HOP_BY_HOP.has(n)||S&&(n==="content-length"||n==="transfer-encoding")||(g[n]=c);let y=http,_;if(typeof e=="object")_={socketPath:e.socketPath,path:t.url,method:t.method,headers:g,agent:b};else{const n=new URL(e),c=n.protocol==="https:";y=c?require("node:https"):http,g.host=n.host,_={protocol:n.protocol,hostname:n.hostname,port:n.port||(c?443:80),path:t.url,method:t.method,headers:g,agent:N(e)}}const P=o;P.__lensmcpErrContained||(P.__lensmcpErrContained=!0,o.on("error",()=>{}));let l;const i=s(()=>{o.writableEnded||p.destroy()},"onReqGone"),h=s(()=>{l&&!l.destroyed&&l.destroy()},"onEdgeClose"),v=s(()=>{t.removeListener("error",i),t.removeListener("aborted",i),t.removeListener("close",i),o.removeListener("close",h)},"detach"),p=y.request(_,n=>{if(l=n,d.onResponse(),o.headersSent||o.writableEnded||o.destroyed){n.destroy();return}const c={};for(const[O,C]of Object.entries(n.headers))C===void 0||HOP_BY_HOP.has(O)||(c[O]=C);delete c["x-powered-by"],c.server="LensMCP",returnRequestId(c,t);const $=t.__lensmcpPod;$&&(c["x-lensmcp-pod"]=$);try{o.writeHead(n.statusCode??502,c)}catch(O){console.error("[gateway] h2 relay: bad response header, resetting stream:",O.message),n.destroy(),o.destroyed||o.destroy(O);return}n.pipe(o),T.armResponse(o);const j=s(()=>{!o.writableEnded&&!o.destroyed&&o.destroy()},"abortEdge");n.once("error",j),n.once("close",j),o.on("close",h)});p.once("error",n=>d.onError(n)),upstreams.set(t,p),p.once("close",v),t.on("error",i),t.on("aborted",i),t.on("close",i),S?p.end():t.pipe(p)},"pipeUpstream"),te=s(async(e,t,o)=>{const d=t.__lensmcpTrace;if(e.pool){const l=e.svc;l&&(l.lastUsed=Date.now(),l.inflight+=1,o.on("close",()=>{l.inflight-=1,l.lastUsed=Date.now()}));let i=(0,discovery_1.pickSock)(e.pool,r.scanTtlMs);if(!i&&l&&(k(d,"cold-start",{project:e.project}),await u.ensureUp(l)&&(i=(0,discovery_1.pickSock)(e.pool,r.scanTtlMs))),l&&i&&u.markUp(l,"observed"),l&&u.scaleUp(l),!i){const v=l?.lastErrors?.length?` Service errors: ${l.lastErrors.join("; ")}`:"";(0,edge_1.sendError)(o,t,503,"unavailable",`Service ${e.project} is not reachable (no pods in ${e.pool.dir}).${v} The watcher recovers and the next request retries automatically.`);return}const h=s((v,p)=>{const n=path.basename(v,".sock");t.__lensmcpPod=n,k(d,"pod-select",{pod:n,pods:e.pool.socks.length,strategy:"round-robin",...p?{movedFrom:p}:{}});let c=!1;const $=s((f,M="unlink")=>{if(e.pool.socks=e.pool.socks.filter(m=>m!==v),e.pool.idx=-1,M==="unlink")try{fs.unlinkSync(v)}catch{}console.error(`[gateway] pod ${n} of ${e.project}: ${f}`)},"evictPod"),j=armFirstByteGuard({socketPath:v,serviceKey:r.serviceKeys[(0,service_keys_1.serviceKeyId)(e.svc?.wsKey,e.project)],req:t,firstByteMs:declaredFirstByteMs(e.svc?.decl?.firstByteMs),ceilingMs:types_1.POD_SLOW_FIRST_BYTE_MS,pending:s(()=>!c&&!o.headersSent&&!o.writableEnded,"pending"),upstreamOpen:s(()=>upstreamOpen(t),"upstreamOpen"),onRetiring:s(f=>{console.log(`[gateway] pod ${n} of ${e.project}: retiring (its socket is gone) but still holds this ${t.method} after ${f}ms \u2014 waiting for it, not evicting`)},"onRetiring"),onWedged:s((f,M)=>{c=!0,$(f),w(e,t,n,{kind:"pod-evicted",status:502,reason:f,detail:M}),(0,edge_1.sendError)(o,t,502,"unavailable",wedgedMessage(n,e.project,M))},"onWedged"),onCeiling:s(f=>{c=!0,$(f,"keep"),w(e,t,n,{kind:"request-gave-up",status:504,reason:f}),(0,edge_1.sendError)(o,t,504,"unavailable",`Pod ${n} of ${e.project} did not answer in time \u2014 retry, or raise cluster.firstByteMs. The pod was kept: the request may still complete there.`)},"onCeiling"),onSlow:s((f,M)=>{console.log(`[gateway] pod ${n} of ${e.project}: slow first byte, pod alive (${f}ms, ${M.inflight} in-flight, ${M.activeWork} background) \u2014 waiting, not evicting. Set cluster.firstByteMs on ${e.project} to size this route's budget.`)},"onSlow")});o.on("close",()=>j.clear());const O=v,C=isReplayableRequest(t);let W=0;const V=s(()=>{W+=1,J({socketPath:O},t,o,{onResponse:s(()=>{j.clear(),c=!0},"onResponse"),onError:s(f=>{if(!c){if(edgeGone(t,o)){j.clear(),c=!0;return}(0,pod_probe_1.podConnectionVerdict)(O,f).then(M=>{if(!c){if(M==="alive"&&W<2&&C&&!edgeGone(t,o)){console.log(`[gateway] pod ${n} of ${e.project}: ${f.message} on one connection, the pod still accepts \u2014 sending the ${t.method} again on a fresh one`),V();return}if(j.clear(),c=!0,M==="gone"){$(f.message);const m=s(()=>{w(e,t,n,{kind:"pod-evicted",status:502,reason:`${f.message} \u2014 its socket no longer accepts (the pod process is gone)${p?`; the request had already been moved here from ${p}`:""}`}),(0,edge_1.sendError)(o,t,502,"unavailable",`Pod ${n} of ${e.project} is gone (${f.message}) \u2014 retry.`)},"giveUp");if(p||!C){m();return}F(e,d).then(E=>{if(!edgeGone(t,o)){if(!E){m();return}H(e,t,n,path.basename(E,".sock"),f.message),h(E,n)}},m);return}console.error(`[gateway] pod ${n} of ${e.project}: ${f.message} on one connection \u2014 the pod still accepts connections, so it stays in the pool`),(0,edge_1.sendError)(o,t,502,"unavailable",`Pod ${n} of ${e.project} dropped the connection \u2014 retry.`)}})}},"onError")})},"sendToPod");V()},"onPod");h(i);return}const g=Date.now()+types_1.UPSTREAM_HEAL_WINDOW_MS;let S=0,y=!1;const _=isReplayableRequest(t),P=s(()=>{if(edgeGone(t,o))return;const l=e.target;J(l,t,o,{onResponse:s(()=>{},"onResponse"),onError:s(i=>{if(isConnError(i)&&(S+=1),e.lens&&isConnError(i)&&_&&S>=2&&!y&&!edgeGone(t,o)){y=!0,A(e).then(h=>{if(!edgeGone(t,o)){if(h==="ready"){P();return}if(h==="unsupported"&&Date.now()<g){setTimeout(P,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}B(e,t,o,e.target,i,h)}});return}if(isConnError(i)&&_&&Date.now()<g&&!edgeGone(t,o)){setTimeout(P,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}if(o.headersSent||o.writableEnded||o.destroyed){o.destroyed||o.destroy();return}B(e,t,o,l,i)},"onError")})},"tryTcp");P()},"forwardNative");return{proxy:U,forward:s(async(e,t,o)=>{const d=Date.now(),g=t.__lensmcpTrace;if(o.on("close",()=>{x(e,Date.now()-d,o.statusCode??0,t.__lensmcpCaller),G(g,e.project,o.statusCode??0,{...t.__lensmcpPod?{pod:t.__lensmcpPod}:{},...t.__lensmcpCaller?{caller:t.__lensmcpCaller}:{}},e)}),e.prependPrefix&&!t.url?.startsWith(e.prependPrefix)&&(t.url=e.prependPrefix+(t.url??"/")),(0,edge_1.stampForwardingHeaders)(r,t),T.arm(t),(t.httpVersionMajor??1)>=2){await te(e,t,o);return}if(e.pool){const i=e.svc;i&&(i.lastUsed=Date.now(),i.inflight+=1,o.on("close",()=>{i.inflight-=1,i.lastUsed=Date.now()}));let h=(0,discovery_1.pickSock)(e.pool,r.scanTtlMs);if(!h&&i&&(k(g,"cold-start",{project:e.project}),await u.ensureUp(i)&&(h=(0,discovery_1.pickSock)(e.pool,r.scanTtlMs))),i&&h&&u.markUp(i,"observed"),i&&u.scaleUp(i),!h){const p=i?.lastErrors?.length?` Service errors: ${i.lastErrors.join("; ")}`:"";(0,edge_1.sendError)(o,t,503,"unavailable",`Service ${e.project} is not reachable (no pods in ${e.pool.dir}).${p} The watcher recovers and the next request retries automatically.`);return}const v=s((p,n)=>{const c=path.basename(p,".sock");t.__lensmcpPod=c,k(g,"pod-select",{pod:c,pods:e.pool.socks.length,strategy:"round-robin",...n?{movedFrom:n}:{}});let $=!1;const j=s((m,E="unlink")=>{if(e.pool.socks=e.pool.socks.filter(K=>K!==p),e.pool.idx=-1,E==="unlink")try{fs.unlinkSync(p)}catch{}console.error(`[gateway] pod ${c} of ${e.project}: ${m}`)},"evictPod"),O=armFirstByteGuard({socketPath:p,serviceKey:r.serviceKeys[(0,service_keys_1.serviceKeyId)(e.svc?.wsKey,e.project)],req:t,firstByteMs:declaredFirstByteMs(e.svc?.decl?.firstByteMs),ceilingMs:types_1.POD_SLOW_FIRST_BYTE_MS,pending:s(()=>!$&&!o.headersSent&&!o.writableEnded,"pending"),upstreamOpen:s(()=>upstreamOpen(t),"upstreamOpen"),onRetiring:s(m=>{console.log(`[gateway] pod ${c} of ${e.project}: retiring (its socket is gone) but still holds this ${t.method} after ${m}ms \u2014 waiting for it, not evicting`)},"onRetiring"),onWedged:s((m,E)=>{$=!0,j(m),w(e,t,c,{kind:"pod-evicted",status:502,reason:m,detail:E}),(0,edge_1.sendError)(o,t,502,"unavailable",wedgedMessage(c,e.project,E))},"onWedged"),onCeiling:s(m=>{$=!0,j(m,"keep"),w(e,t,c,{kind:"request-gave-up",status:504,reason:m}),(0,edge_1.sendError)(o,t,504,"unavailable",`Pod ${c} of ${e.project} did not answer in time \u2014 retry, or raise cluster.firstByteMs. The pod was kept: the request may still complete there.`)},"onCeiling"),onSlow:s((m,E)=>{console.log(`[gateway] pod ${c} of ${e.project}: slow first byte, pod alive (${m}ms, ${E.inflight} in-flight, ${E.activeWork} background) \u2014 waiting, not evicting. Set cluster.firstByteMs on ${e.project} to size this route's budget.`)},"onSlow")});o.on("close",()=>O.clear());const C=Math.max(12e4,types_1.POD_SLOW_FIRST_BYTE_MS+6e4),W=p,V=isReplayableRequest(t);let f=0;const M=s(()=>{f+=1;const m=Date.now();U.web(t,o,{target:{socketPath:W},agent:b,proxyTimeout:C},E=>{if(!$){if(edgeGone(t,o)){O.clear(),$=!0;return}(0,pod_probe_1.podConnectionVerdict)(W,E).then(K=>{if($)return;const X=Date.now()-m>=C-250;if(K==="alive"&&f<2&&V&&!X&&!edgeGone(t,o)){console.log(`[gateway] pod ${c} of ${e.project}: ${E.message} on one connection, the pod still accepts \u2014 sending the ${t.method} again on a fresh one`),M();return}if(O.clear(),$=!0,K==="gone"){j(E.message);const Y=s(()=>{w(e,t,c,{kind:"pod-evicted",status:502,reason:`${E.message} \u2014 its socket no longer accepts (the pod process is gone)${n?`; the request had already been moved here from ${n}`:""}`}),(0,edge_1.sendError)(o,t,502,"unavailable",`Pod ${c} of ${e.project} is gone (${E.message}) \u2014 retry.`)},"giveUp");if(n||!V||X){Y();return}F(e,g).then(Q=>{if(!edgeGone(t,o)){if(!Q){Y();return}H(e,t,c,path.basename(Q,".sock"),E.message),v(Q,c)}},Y);return}console.error(`[gateway] pod ${c} of ${e.project}: ${E.message} on one connection \u2014 the pod still accepts connections, so it stays in the pool`),(0,edge_1.sendError)(o,t,502,"unavailable",`Pod ${c} of ${e.project} dropped the connection \u2014 retry.`)})}})},"sendToPod");M()},"onPod");v(h);return}const S=Date.now()+types_1.UPSTREAM_HEAL_WINDOW_MS;let y=0,_=!1;const P=isReplayableRequest(t),l=s(()=>{if(edgeGone(t,o))return;const i=e.target,h={target:i,autoRewrite:typeof i=="string",changeOrigin:!0,agent:N(i)};U.web(t,o,h,v=>{if(isConnError(v)&&(y+=1),e.lens&&isConnError(v)&&P&&y>=2&&!_&&!edgeGone(t,o)){_=!0,A(e).then(p=>{if(!edgeGone(t,o)){if(p==="ready"){l();return}if(p==="unsupported"&&Date.now()<S){setTimeout(l,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}B(e,t,o,e.target,v,p)}});return}if(isConnError(v)&&P&&Date.now()<S&&!edgeGone(t,o)){setTimeout(l,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}o.destroyed||B(e,t,o,i,v)})},"tryTcp");l()},"forward"),agentForTarget:N,destroyAgents:s(()=>{T.stop(),b.destroy(),R.destroy()},"destroyAgents"),closeProxy:s(()=>{try{U.close?.()}catch{}},"closeProxy")}}q(createProxy,"createProxy"),D(createProxy,"createProxy"),s(createProxy,"createProxy");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var p=Object.defineProperty;var i=(e,t)=>p(e,"name",{value:t,configurable:!0});var d=Object.defineProperty,n=i((e,t)=>d(e,"name",{value:t,configurable:!0}),"n"),u=Object.defineProperty,r=n((e,t)=>u(e,"name",{value:t,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.sameRoot=void 0,exports.canonicalRoot=canonicalRoot,exports.hostConflicts=hostConflicts,exports.refuseRegistration=refuseRegistration,exports.refuseUnregistration=refuseUnregistration;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));function canonicalRoot(e){try{return fs.realpathSync(e)}catch{return path.resolve(e)}}i(canonicalRoot,"canonicalRoot"),n(canonicalRoot,"canonicalRoot"),r(canonicalRoot,"canonicalRoot");const sameRoot=r((e,t)=>canonicalRoot(e)===canonicalRoot(t),"sameRoot");exports.sameRoot=sameRoot;function claim(e){return e.host?`${e.host.toLowerCase()} ${e.prefix??""}`:e.apex?`* ${e.apex.toLowerCase()}`:void 0}i(claim,"claim"),n(claim,"claim"),r(claim,"claim");function hostConflicts(e,t){const s=[],o=new Set;for(const a of e.keys()){if(a===t.wsKey)continue;const c=e.get(a);if(!c)continue;const l=new Set(c.routes.map(claim));for(const h of t.routes){const f=claim(h);!f||!l.has(f)||o.has(f)||(o.add(f),s.push({host:h.host??`(default for ${h.apex})`,...h.prefix?{prefix:h.prefix}:{},heldBy:a,heldByRoot:c.root}))}}return s}i(hostConflicts,"hostConflicts"),n(hostConflicts,"hostConflicts"),r(hostConflicts,"hostConflicts");const describeConflict=r(e=>`${e.host}${e.prefix??""} (served by '${e.heldBy}')`,"describeConflict");function refuseRegistration(e,t){const s=e.get(t.wsKey);if(s&&!(0,exports.sameRoot)(s.root,t.root))return{error:"key-in-use",heldByRoot:s.root,message:`'${t.wsKey}' is already served from ${s.root}. ${t.root} is another checkout that derives the same key, and two checkouts cannot share a key or hosts behind one gateway: registering this one would replace the other's routes. To serve it beside the other under hosts of its own, run \`lensmcp instance start\` in ${t.root}; otherwise run \`lensmcp gateway stop\` in ${s.root} first.`};const o=hostConflicts(e,t);if(o.length>0){const a=o.slice(0,6).map(describeConflict).join(", "),c=o.length>6?`, and ${o.length-6} more`:"";return{error:"host-conflict",conflicts:o,message:`'${t.wsKey}' declares ${o.length===1?"a host":`${o.length} hosts`} another workspace already serves: ${a}${c}. The workspace registered first would win every request to ${o.length===1?"it":"them"}, so this registration is refused. Two workspaces behind one gateway need different hosts \u2014 for a second checkout of a workspace, \`lensmcp instance start\` in it serves it under hosts named after it.`}}}i(refuseRegistration,"refuseRegistration"),n(refuseRegistration,"refuseRegistration"),r(refuseRegistration,"refuseRegistration");function refuseUnregistration(e,t,s){const o=e.get(t.wsKey);if(o&&t.root&&!(0,exports.sameRoot)(o.root,t.root))return{error:"not-your-registration",heldByRoot:o.root,message:`'${t.wsKey}' is served from ${o.root}, not from ${t.root} \u2014 nothing of this checkout is registered, so nothing was removed.`};if(o&&s!==void 0&&t.wsKey===s)return{error:"daemon-workspace",heldByRoot:o.root,message:`'${t.wsKey}' is the workspace that owns the gateway \u2014 unregistering it would leave :443 serving without it. Stop the gateway instead: \`lensmcp gateway stop\` in ${o.root}.`}}i(refuseUnregistration,"refuseUnregistration"),n(refuseUnregistration,"refuseUnregistration"),r(refuseUnregistration,"refuseUnregistration");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var g=Object.defineProperty;var a=(t,e)=>g(t,"name",{value:e,configurable:!0});var u=Object.defineProperty,n=a((t,e)=>u(t,"name",{value:e,configurable:!0}),"n"),i=Object.defineProperty,r=n((t,e)=>i(t,"name",{value:e,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.RouteRegistry=void 0,exports.rebuildRoutesInPlace=rebuildRoutesInPlace;const manifest_1=require("../manifest");class RouteRegistry{static{a(this,"RouteRegistry")}static{n(this,"RouteRegistry")}static{r(this,"RouteRegistry")}constructor(){this.fragments=new Map}register(e){this.fragments.set(e.wsKey,e)}unregister(e){const s=this.fragments.get(e);return this.fragments.delete(e),s}has(e){return this.fragments.has(e)}get(e){return this.fragments.get(e)}keys(){return[...this.fragments.keys()]}size(){return this.fragments.size}appendRoutes(e,s){const o=this.fragments.get(e);o&&o.routes.push(...s)}allServices(){return[...this.fragments.values()].flatMap(e=>e.services)}merged(){const e=[...this.fragments.values()].flatMap(s=>s.routes);return(0,manifest_1.sortBySpecificity)(e),e}}exports.RouteRegistry=RouteRegistry;function rebuildRoutesInPlace(t,e){const s=e.merged();t.length=0,t.push(...s)}a(rebuildRoutesInPlace,"rebuildRoutesInPlace"),n(rebuildRoutesInPlace,"rebuildRoutesInPlace"),r(rebuildRoutesInPlace,"rebuildRoutesInPlace");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var d=Object.defineProperty;var i=(t,e)=>d(t,"name",{value:e,configurable:!0});var p=Object.defineProperty,c=i((t,e)=>p(t,"name",{value:e,configurable:!0}),"c"),a=Object.defineProperty,o=c((t,e)=>a(t,"name",{value:e,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.SOCK_NS_PATTERN=void 0,exports.baseDomainOf=baseDomainOf,exports.sockNamespace=sockNamespace,exports.readLensScope=readLensScope,exports.deriveMcpHttpPort=deriveMcpHttpPort,exports.readSourceSetExclude=readSourceSetExclude,exports.readSourceSetOptions=readSourceSetOptions,exports.lensKeyFrom=lensKeyFrom,exports.lensSlug=lensSlug;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),instance_1=require("./instance");function baseDomainOf(t){const e=t.filter(s=>!!s&&!s.startsWith("*."));if(e.length===0)return"local";const r=e.reduce((s,u)=>u.length<s.length?u:s);if(e.every(s=>s===r||s.endsWith("."+r)))return r;const n=r.split(".");return n.slice(-Math.min(n.length,3)).join(".")}i(baseDomainOf,"baseDomainOf"),c(baseDomainOf,"baseDomainOf"),o(baseDomainOf,"baseDomainOf");const BASE_PORTS={dashboard:4321,mcpHttp:4500};function hashToRange(t,e){let r=2166136261;for(let n=0;n<t.length;n++)r^=t.charCodeAt(n),r=Math.imul(r,16777619);return Math.abs(r|0)%e}i(hashToRange,"hashToRange"),c(hashToRange,"hashToRange"),o(hashToRange,"hashToRange"),exports.SOCK_NS_PATTERN=/^[a-z0-9][a-z0-9-]{0,31}$/;function sockNamespace(t,e){return typeof e=="string"&&exports.SOCK_NS_PATTERN.test(e)?e:t}i(sockNamespace,"sockNamespace"),c(sockNamespace,"sockNamespace"),o(sockNamespace,"sockNamespace");function readLensScope(t){try{const r=JSON.parse(fs.readFileSync(path.join(t,".lensmcp","config.json"),"utf8"));if(r&&typeof r.key=="string"){const n=(0,instance_1.parseInstanceDecl)(r.instance),s=n&&(0,instance_1.instanceKey)(n.baseKey,n.name)===r.key?n:void 0;return{key:r.key,dashboardPort:r.ports?.dashboard??BASE_PORTS.dashboard,mcpHttpPort:r.ports?.mcpHttp??deriveMcpHttpPort(r.key),basePath:r.dashboardBasePath??"/"+r.key,sockNs:sockNamespace(s?(0,instance_1.instanceSockNs)(r.key):r.key,r.sockNs),...s?{instance:s}:{}}}}catch{}const e=lensKeyFrom(t);return{key:e,dashboardPort:BASE_PORTS.dashboard,mcpHttpPort:deriveMcpHttpPort(e),basePath:"/"+e,sockNs:e}}i(readLensScope,"readLensScope"),c(readLensScope,"readLensScope"),o(readLensScope,"readLensScope");function deriveMcpHttpPort(t){return BASE_PORTS.mcpHttp+hashToRange(t,200)}i(deriveMcpHttpPort,"deriveMcpHttpPort"),c(deriveMcpHttpPort,"deriveMcpHttpPort"),o(deriveMcpHttpPort,"deriveMcpHttpPort");function readSourceSetExclude(t){return readSourceSetOptions(t).exclude}i(readSourceSetExclude,"readSourceSetExclude"),c(readSourceSetExclude,"readSourceSetExclude"),o(readSourceSetExclude,"readSourceSetExclude");function readSourceSetOptions(t){const e={exclude:new Set,ignoreTests:!0};try{const r=JSON.parse(fs.readFileSync(path.join(t,".lensmcp","config.json"),"utf8")),n=r?.sourceSet?.exclude;Array.isArray(n)&&(e.exclude=new Set(n.filter(s=>typeof s=="string"&&s.length>0&&!s.includes("/")))),r?.sourceSet?.ignoreTests===!1&&(e.ignoreTests=!1)}catch{}return e}i(readSourceSetOptions,"readSourceSetOptions"),c(readSourceSetOptions,"readSourceSetOptions"),o(readSourceSetOptions,"readSourceSetOptions");function lensKeyFrom(t){try{const e=JSON.parse(fs.readFileSync(path.join(t,"package.json"),"utf8"));if(e?.name)return lensSlug(e.name)}catch{}return lensSlug(path.basename(t))}i(lensKeyFrom,"lensKeyFrom"),c(lensKeyFrom,"lensKeyFrom"),o(lensKeyFrom,"lensKeyFrom");function lensSlug(t){return t.toLowerCase().replace(/^@[^/]+\//,"").replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)/g,"")||"workspace"}i(lensSlug,"lensSlug"),c(lensSlug,"lensSlug"),o(lensSlug,"lensSlug");
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
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,[
|
|
3
|
-
`)[0]})`)}const
|
|
1
|
+
"use strict";var A=Object.defineProperty;var E=(e,r)=>A(e,"name",{value:r,configurable:!0});var T=Object.defineProperty,u=E((e,r)=>T(e,"name",{value:r,configurable:!0}),"u"),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)}E(serveRunnerEnabled,"serveRunnerEnabled"),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}}E(serveRunnerScript,"serveRunnerScript"),u(serveRunnerScript,"serveRunnerScript"),i(serveRunnerScript,"serveRunnerScript");function serveRunnerArgs(e,r,s){return["run",e,`--childCount=${r}`,`${exports.RUNNER_ROOT_FLAG}${s}`]}E(serveRunnerArgs,"serveRunnerArgs"),u(serveRunnerArgs,"serveRunnerArgs"),i(serveRunnerArgs,"serveRunnerArgs");function isServeRunnerCommand(e){return/\bserve-runner\.(js|ts)\b/.test(e)&&e.includes(` ${exports.RUNNER_ROOT_FLAG}`)}E(isServeRunnerCommand,"isServeRunnerCommand"),u(isServeRunnerCommand,"isServeRunnerCommand"),i(isServeRunnerCommand,"isServeRunnerCommand");function isServeRunnerCommandOf(e,r){return isServeRunnerCommand(e)&&e.trimEnd().endsWith(` ${exports.RUNNER_ROOT_FLAG}${r.replace(/\/+$/,"")}`)}E(isServeRunnerCommandOf,"isServeRunnerCommandOf"),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"),l=o("nx/src/utils/cache-directory"),c=o.resolve("nx/src/command-line/run/run"),R=[["getEnvFilesForTask",t.getEnvFilesForTask],["loadAndExpandDotEnvFile",t.loadAndExpandDotEnvFile],["unloadDotEnvFile",t.unloadDotEnvFile],["createTaskGraph",n.createTaskGraph],["readNxJson",a.readNxJson],["workspaceDataDirectoryForWorkspace",l.workspaceDataDirectoryForWorkspace]].filter(([,N])=>typeof N!="function").map(([N])=>N);s=R.length>0?`nx ${_} has no ${R.join(", ")}`:{version:_,runModule:c,createTaskGraph:n.createTaskGraph,getEnvFilesForTask:t.getEnvFilesForTask,loadAndExpandDotEnvFile:t.loadAndExpandDotEnvFile,unloadDotEnvFile:t.unloadDotEnvFile,readNxJson:a.readNxJson,workspaceDataDirectoryForWorkspace:l.workspaceDataDirectoryForWorkspace}}catch(o){s=`cannot load the workspace's nx (${o.message.split(`
|
|
2
|
+
`)[0]})`}return helpersByRoot.set(e,s),s}E(loadNxHelpers,"loadNxHelpers"),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"}}E(nxExecutorEnv,"nxExecutorEnv"),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,[l,c]]of Object.entries(o??{}))if(!(a!==t&&!a.startsWith(`${t}.`))&&(n=!0,!l||!_.has(l)))return`${c}${l?` (from ${l})`:""}`;return n?void 0:"a source the project graph does not record"}E(inferredBy,"inferredBy"),u(inferredBy,"inferredBy"),i(inferredBy,"inferredBy");function planServeLaunch(e){const r=i(p=>({kind:"nx",reason:p}),"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 l=e.gatewayEnv??process.env;if(e.baseEnv.NX_CACHE_PROJECT_GRAPH==="false"||l.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 R=e.script??serveRunnerScript();if(!R)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 N={childCount:e.childCount,__overrides_unparsed__:[`--childCount=${e.childCount}`]};let v;try{v=c.createTaskGraph(o.projectGraph,{},[e.project],[e.target],void 0,N)}catch(p){return r(`nx could not build its task graph (${p.message.split(`
|
|
3
|
+
`)[0]})`)}const d=Object.values(v.tasks).find(p=>p.target.project===e.project&&p.target.target===e.target);if(!d)return r(`nx's task graph has no ${e.project}:${e.target}`);const f=Object.keys(v.tasks).filter(p=>p!==d.id);if(f.length>0)return r(`dependsOn: nx would run ${f.join(", ")} first`);const x=new Set(c.readNxJson(e.root).sync?.disabledTaskSyncGenerators??[]),O=(n.syncGenerators??[]).filter(p=>!x.has(p));if(O.length>0)return r(`sync generators nx would run first: ${O.join(", ")}`);d.startTime=Date.now();const{env:g,isVerbose:S}=nxExecutorEnv(c,e.root,e.baseEnv,d,o.projectGraph);return{kind:"runner",taskId:d.id,env:g,script:R,message:{nxRunModule:c.runModule,targetDescription:d.target,overrides:d.overrides,isVerbose:S,taskGraph:v}}}E(planServeLaunch,"planServeLaunch"),u(planServeLaunch,"planServeLaunch"),i(planServeLaunch,"planServeLaunch");
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var fe=Object.defineProperty;var T=(r,t)=>fe(r,"name",{value:t,configurable:!0});var ye=Object.defineProperty,o=T((r,t)=>ye(r,"name",{value:t,configurable:!0}),"o");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.edgeKeyWait=edgeKeyWait,exports.withBuiltinHooks=withBuiltinHooks,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"),manifest_1=require("../manifest"),edge_1=require("./edge"),warm_start_1=require("./warm-start"),types_1=require("./types");function insecureLocalFetch(r,t){return new Promise((i,c)=>{const a=(r.startsWith("https:")?require("node:https"):require("node:http")).request(r,{method:"GET",headers:t?.headers,rejectUnauthorized:!1},_=>{const y=[];_.on("data",h=>y.push(h)),_.on("error",c),_.on("end",()=>{const h=_.statusCode??0,v=Buffer.concat(y).toString("utf8");i({ok:h>=200&&h<300,status:h,json:o(async()=>JSON.parse(v),"json")})})});a.on("error",c),t?.signal?.addEventListener("abort",()=>a.destroy(new Error(`JWKS ${r} \u2192 aborted`)),{once:!0}),a.end()})}T(insecureLocalFetch,"insecureLocalFetch"),o(insecureLocalFetch,"insecureLocalFetch");function buildEdgeVerifierPool(r,t={}){const i=process.env.LENSMCP_GW_JWKS_URL,c=process.env.LENSMCP_GW_JWT_ISS,a=new Map;let _,y=!1;const h=o((s,l)=>{console.log(`[gateway] edge JWT: verifying via JWKS ${s}${l}`);const d=(0,jwks_verify_1.createJwksVerifier)({jwksUrl:s,...c?{issuer:c}:{},fetchImpl:t.fetchImpl??insecureLocalFetch});let E=!1;return d.warm({...t.warm,onError:o((M,x,b)=>{E=!0,x===1&&b!==void 0&&console.warn(`[gateway] edge JWKS ${s} not loaded yet (${M.message}) \u2014 retrying in the background`),b===void 0&&console.warn(`[gateway] edge JWKS ${s} still not loaded after ${x} attempts (${M.message}) \u2014 the first token that needs it fetches it`)},"onError")}).then(M=>{M&&E&&console.log(`[gateway] edge JWKS ${s} loaded`)}),d},"make"),v=o(s=>{let l=a.get(s);return l||(l=h(`https://auth.${s}/jwks.json`,` (auto-derived for apex ${s})`),a.set(s,l)),l},"forApex");return{for(s){if(i)return _??=h(i,"");const l=s.split(":")[0].toLowerCase();let d;for(const E of idpApexes(r()))(l===E||l.endsWith(`.${E}`))&&(!d||E.length>d.length)&&(d=E);return d?v(d):void 0},warm(){if(!y){if(i){_??=h(i,"");return}for(const s of idpApexes(r()))v(s)}},stop(){y=!0,_?.stop();for(const s of a.values())s.stop()}}}T(buildEdgeVerifierPool,"buildEdgeVerifierPool"),o(buildEdgeVerifierPool,"buildEdgeVerifierPool");function idpApexes(r){const t=new Set;for(const i of r){const c=i.host;typeof c!="string"||!/^auth\./.test(c)||c.startsWith("internal.")||t.add(c.slice(5))}return t}T(idpApexes,"idpApexes"),o(idpApexes,"idpApexes");function edgeKeyWait(r){return async t=>{const i=t.route;if(!i?.auth||i.internal)return;const{req:c}=t,a=Array.isArray(c.headers.authorization)?c.headers.authorization[0]:c.headers.authorization,_=String(a??"");if(!_.startsWith("Bearer "))return;const y=c.url??"/";if((0,manifest_1.authRuleFor)(i.auth,(0,edge_1.canonicalPath)(y)??y.split("?")[0],(c.method??"GET").toUpperCase()).mode!=="jwt")return;const h=String(c.headers.host??"").split(":")[0].toLowerCase();await r.for(h)?.awaitKey(_.slice(7))}}T(edgeKeyWait,"edgeKeyWait"),o(edgeKeyWait,"edgeKeyWait");function withBuiltinHooks(r,t){return{...r,beforeAuth:[...r.beforeAuth??[],t.keyWait],afterAuth:[t.middleware,...r.afterAuth??[]]}}T(withBuiltinHooks,"withBuiltinHooks"),o(withBuiltinHooks,"withBuiltinHooks"),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"}}T(classifyClientError,"classifyClientError"),o(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 i=>{const c=Date.now(),a=t.get(i)??0;return c-a<r?!1:(t.set(i,c),!0)}}T(createClientErrorLogGate,"createClientErrorLogGate"),o(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()})}T(guardInboundSocket,"guardInboundSocket"),o(guardInboundSocket,"guardInboundSocket");function retirePreviousWorkspace(r,t,i){const c=r.get(t);if(!c)return!1;r.delete(t),i==="re-registered"&&console.log(`[gateway] workspace '${t}' re-registered \u2014 retiring the children of its previous registration first.`);try{c()}catch(a){console.warn(`[gateway] could not fully retire the previous registration of '${t}' (${i}): ${a.message}`)}return!0}T(retirePreviousWorkspace,"retirePreviousWorkspace"),o(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 i=Number(r);return!Number.isFinite(i)||i<0?t:Math.floor(i)}T(parseBudget,"parseBudget"),o(parseBudget,"parseBudget");function resolveMaxConnections(r){return parseBudget(r,exports.GATEWAY_MAX_CONNECTIONS_DEFAULT)}T(resolveMaxConnections,"resolveMaxConnections"),o(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)}}T(h2BudgetFromEnv,"h2BudgetFromEnv"),o(h2BudgetFromEnv,"h2BudgetFromEnv");function createH2Governor(r,t){const{NGHTTP2_ENHANCE_YOUR_CALM:i,NGHTTP2_REFUSED_STREAM:c}=require("node:http2").constants,a=new Map;let _=0;const y=o(s=>{s.idle&&(clearTimeout(s.idle),s.idle=void 0)},"disarm"),h=o((s,l)=>{y(l),!(r.idleSessionMs<=0||l.open>0)&&(l.idle=setTimeout(()=>{s.destroyed||s.closed||(t("session-reclaimed",{idleMs:r.idleSessionMs,sessions:a.size}),a.delete(s),s.close())},r.idleSessionMs),l.idle.unref?.())},"arm"),v=o(()=>{for(const[s,l]of a)if(!(l.open>0||s.destroyed))return y(l),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&&!v()){t("session-refused",{sessions:a.size,maxSessions:r.maxSessions,streams:_});try{s.goaway(i)}catch{}try{s.close()}catch{}return!1}const l={open:0};return a.set(s,l),h(s,l),s.once("close",()=>{y(l),a.delete(s)}),!0},admitStream(s,l){const d=a.get(s);if(!d)return!0;if(r.maxStreams>0&&_>=r.maxStreams){t("stream-refused",{streams:_,maxStreams:r.maxStreams,sessions:a.size});try{l.close(c)}catch{}return!1}return _+=1,d.open+=1,y(d),l.once("close",()=>{_=Math.max(0,_-1),d.open=Math.max(0,d.open-1),d.open===0&&a.has(s)&&h(s,d)}),!0},dispose(){for(const s of a.values())y(s);a.clear()}}}T(createH2Governor,"createH2Governor"),o(createH2Governor,"createH2Governor");async function startGateway(r,t){const i=r.https!==!1,c=r.ports?.length?r.ports:[443],a=r.scanTtlMs??1500,_=r.startupTimeoutMs??12e4,y=r.sweepMs??1e4,h=r.trafficFlushMs??5e3;let v=!1;const s=process.env.LENSMCP_EVENT_FILE??path.join(t.root,".lensmcp","events.jsonl"),l=(0,own_log_1.startOwnLogRotation)(t.root),d=(0,scope_1.readLensScope)(t.root),E=d.key,M=d.sockNs!==E?d.sockNs:void 0,x=t.projectsConfigurations?.projects??{},b=(0,discovery_1.projectSourceRoots)(t.root,x,t.projectDependencies),{routes:j,services:P,instance:Q}=(0,discovery_1.discoverRoutes)(t.root,x,void 0,E,b,M,d.instance);if(j.length===0)throw new Error("[gateway] no project declares a `cluster` field \u2014 nothing to route.");const K=new route_registry_1.RouteRegistry;K.register({wsKey:E,...M?{sockNs:M}:{},root:t.root,routes:j,services:P,...Q?{instance:Q}:{}});const R=[];let Z=o(()=>{},"refreshCert"),U=o(()=>{},"warmEdgeVerifiers");const ee=o(()=>{(0,route_registry_1.rebuildRoutesInPlace)(R,K),Z(),U()},"rebuildRoutes");ee();const{serviceKeys:le,keyToProject:ue,keyToWorkspace:de}=(0,service_keys_1.loadServiceKeys)(t.root,P,E),pe=(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}:{}}),g={root:t.root,wsKey:E,...M?{sockNs:M}:{},eventFile:s,routes:R,registry:K,rebuildRoutes:ee,services:P,serviceKeys:le,keyToProject:ue,keyToWorkspace:de,clientIp:pe,bodyStallMs:r.bodyStallMs??types_1.BODY_STALL_MS,scanTtlMs:a,startupTimeoutMs:_,sweepMs:y,trafficFlushMs:h,https:i,projectRoots:Object.fromEntries(Object.entries(t.projectsConfigurations?.projects??{}).map(([e,n])=>[e,path.resolve(t.root,n.root)])),projectSourceRoots:b,...t.projectGraphStore?{graphStores:(0,project_graph_store_1.createProjectGraphStores)(t.projectGraphStore)}:{},...r.sharedCompiler!==void 0?{sharedCompiler:r.sharedCompiler}:{},stopped:o(()=>v,"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:E||path.basename(t.root),lens:{key:E,dashboard:r.dashboard!==!1,mcp:r.mcp!==!1&&j.some(e=>!!e.lens)}}));const m=(0,observability_1.createObservability)(s,{trafficFlushMs:h}),_e=createClientErrorLogGate(),L=h2BudgetFromEnv(),ge=createClientErrorLogGate(3e4),D=createH2Governor(L,(e,n)=>{ge(e)&&console.warn(`[gateway] h2 aggregate budget: ${e} (${JSON.stringify(n)}). 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).`),m.emit(e==="session-reclaimed"?"info":"warning",`h2 aggregate budget: ${e}`,`gateway-h2-budget:${e}`,{kind:"h2-aggregate-budget",event:e,project:"gateway",...n})}),A=(0,lifecycle_1.createServiceLayer)(g,m),O=(0,lens_children_1.createLensChildren)(g,m,r),F=new Map;let re=o(()=>{},"ownBooted");const Se=new Promise(e=>re=e),te=(0,warm_start_1.createWorktreeWarmer)({rt:g,obs:m,ready:Se,ensureUp:o(e=>A.ensureUp(e),"ensureUp")});let B;if(r.middleware){const e=require(path.resolve(t.root,r.middleware));B=e.default??e}const Y=(0,workspace_middleware_1.createWorkspaceMiddleware)({ownerKey:E,...B?{owner:B}:{},policy:(0,workspace_middleware_1.guestMiddlewarePolicy)()}),I=process.env.LENSMCP_GW_ACT==="0"?void 0:(0,act_1.createActStore)({dir:path.join(path.dirname((0,control_1.controlSocketPath)()),"identities")});let $;try{$=(0,control_1.startControlServer)({rt:g,killService:o((e,n)=>A.killSpawned(e,n),"killService"),restartService:o((e,n)=>A.restartService(e,n),"restartService"),ensureService:o(e=>A.ensureUp(e),"ensureService"),...I?{act:I}:{},onRegister:o(async e=>{retirePreviousWorkspace(F,e.wsKey,"re-registered"),Y.set(e.wsKey,e.root,e.middleware);const n=await O.hostWorkspaceDashboard(e),w=await O.hostWorkspaceApps(e);F.set(e.wsKey,()=>{try{n?.()}finally{w()}}),te.onRegister(e)},"onRegister"),onUnregister:o(e=>{te.onUnregister(e.wsKey),retirePreviousWorkspace(F,e.wsKey,"unregistered"),Y.drop(e.wsKey),A.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)(g,m,A),W=buildEdgeVerifierPool(()=>g.routes),se=(0,auth_1.createEdgeAuth)(g,m,W,I),he=o(e=>{const n=e.route?.wsKey,w=Y.for(n);if(w)try{const u=n?g.registry.get(n):void 0;w(e.req,{...n?{wsKey:n}:{},...u?{root:u.root}:{},env:u?.instance?.env??{}})}catch(u){m.traceStep(e.trace,"auth",{mode:"middleware",ok:!1,reason:u.message}),e.route&&m.finishTrace(e.trace,e.route.project,401),e.sendError(401,"unauthorized",`Gateway middleware rejected the request: ${u.message}`)}},"builtinMiddleware"),oe=(0,hooks_1.createHooks)(withBuiltinHooks(r.hooks??{},{keyWait:edgeKeyWait(W),middleware:he})),ne=(0,handler_1.createHandler)({rt:g,obs:m,auth:se,proxy:H,hooks:oe}),ae=(0,upgrade_1.createUpgrade)({rt:g,auth:se,proxy:H,hooks:oe,obs:m}),Ee=m.startEdgeFlusher(),me=A.startSweeper(),ie=(0,source_poller_1.createSourcePoller)({services:o(()=>g.registry.allServices(),"services"),serviceKey:o(e=>g.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],"serviceKey"),emit:o((e,n,w,u,S)=>m.emit(n,w,u,{wsKey:e.wsKey,...S},void 0,e.wsKey===g.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl")),"emit"),scanTtlMs:a,stopped:o(()=>v,"stopped")});(0,source_poller_1.sourcesEnabled)()&&ie.start(),await O.bootSingletonsAndApps();const ce=P.filter(e=>e.decl.eager).map(e=>A.ensureUp(e));Promise.allSettled(ce).then(()=>setTimeout(re,ce.length?2e4:0).unref());let k,X,q;if(i){const e=require("../../../basic-ssl"),n=(0,service_keys_1.gatewayCacheDir)(t.root);q=o(()=>e.getCertificateSync(n,"gateway",g.routes.map(w=>w.host).filter(w=>!!w)),"mintCert"),k=q(),X=e.caCertPath()}const J=[],G=[],z=r.maxConnections??resolveMaxConnections(process.env.LENSMCP_MAX_CONNECTIONS);for(const e of c){const n=k?require("node:http2").createSecureServer({key:k,cert:k,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},(u,S)=>ne(u,S)):http.createServer(ne);n.on("upgrade",ae),n.on("error",u=>console.error(`[gateway] port ${e}: ${u.code}`)),n.on("connection",guardInboundSocket),n.on("secureConnection",guardInboundSocket),n.on("tlsClientError",(u,S)=>S.destroy()),n.on("clientError",(u,S)=>{const p=u,f=classifyClientError(p.code,p.message);if(f.report&&_e(f.cause)){const N=S.remoteAddress??"unknown",C=f.status===null?"dropped":String(f.status);console.warn(`[gateway] inbound H1 clientError from ${N}: ${f.cause} (${p.code??p.message}${p.bytesParsed!==void 0?`, bytesParsed=${p.bytesParsed}`:""}) \u2192 ${C}. This status is the GATEWAY's, not the upstream service's.`),m.emit("warning",`inbound clientError: ${f.cause} \u2192 ${C}`,`gateway-client-error:${f.cause}`,{kind:"gateway-client-error",cause:f.cause,code:p.code??null,status:f.status,peer:N,bytesParsed:p.bytesParsed??null})}f.status!==null&&S.writable&&S.end(`HTTP/1.1 ${f.status} ${CLIENT_ERROR_REASON[f.status]}\r
|
|
1
|
+
"use strict";var ve=Object.defineProperty;var v=(r,t)=>ve(r,"name",{value:t,configurable:!0});var fe=Object.defineProperty,T=v((r,t)=>fe(r,"name",{value:t,configurable:!0}),"T"),ye=Object.defineProperty,o=T((r,t)=>ye(r,"name",{value:t,configurable:!0}),"o");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.edgeKeyWait=edgeKeyWait,exports.withBuiltinHooks=withBuiltinHooks,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"),manifest_1=require("../manifest"),edge_1=require("./edge"),warm_start_1=require("./warm-start"),types_1=require("./types");function insecureLocalFetch(r,t){return new Promise((i,c)=>{const a=(r.startsWith("https:")?require("node:https"):require("node:http")).request(r,{method:"GET",headers:t?.headers,rejectUnauthorized:!1},_=>{const y=[];_.on("data",S=>y.push(S)),_.on("error",c),_.on("end",()=>{const S=_.statusCode??0,M=Buffer.concat(y).toString("utf8");i({ok:S>=200&&S<300,status:S,json:o(async()=>JSON.parse(M),"json")})})});a.on("error",c),t?.signal?.addEventListener("abort",()=>a.destroy(new Error(`JWKS ${r} \u2192 aborted`)),{once:!0}),a.end()})}v(insecureLocalFetch,"insecureLocalFetch"),T(insecureLocalFetch,"insecureLocalFetch"),o(insecureLocalFetch,"insecureLocalFetch");function buildEdgeVerifierPool(r,t={}){const i=process.env.LENSMCP_GW_JWKS_URL,c=process.env.LENSMCP_GW_JWT_ISS,a=new Map;let _,y=!1;const S=o((s,l)=>{console.log(`[gateway] edge JWT: verifying via JWKS ${s}${l}`);const d=(0,jwks_verify_1.createJwksVerifier)({jwksUrl:s,...c?{issuer:c}:{},fetchImpl:t.fetchImpl??insecureLocalFetch});let E=!1;return d.warm({...t.warm,onError:o((C,b,L)=>{E=!0,b===1&&L!==void 0&&console.warn(`[gateway] edge JWKS ${s} not loaded yet (${C.message}) \u2014 retrying in the background`),L===void 0&&console.warn(`[gateway] edge JWKS ${s} still not loaded after ${b} attempts (${C.message}) \u2014 the first token that needs it fetches it`)},"onError")}).then(C=>{C&&E&&console.log(`[gateway] edge JWKS ${s} loaded`)}),d},"make"),M=o(s=>{let l=a.get(s);return l||(l=S(`https://auth.${s}/jwks.json`,` (auto-derived for apex ${s})`),a.set(s,l)),l},"forApex");return{for(s){if(i)return _??=S(i,"");const l=s.split(":")[0].toLowerCase();let d;for(const E of idpApexes(r()))(l===E||l.endsWith(`.${E}`))&&(!d||E.length>d.length)&&(d=E);return d?M(d):void 0},warm(){if(!y){if(i){_??=S(i,"");return}for(const s of idpApexes(r()))M(s)}},stop(){y=!0,_?.stop();for(const s of a.values())s.stop()}}}v(buildEdgeVerifierPool,"buildEdgeVerifierPool"),T(buildEdgeVerifierPool,"buildEdgeVerifierPool"),o(buildEdgeVerifierPool,"buildEdgeVerifierPool");function idpApexes(r){const t=new Set;for(const i of r){const c=i.host;typeof c!="string"||!/^auth\./.test(c)||c.startsWith("internal.")||t.add(c.slice(5))}return t}v(idpApexes,"idpApexes"),T(idpApexes,"idpApexes"),o(idpApexes,"idpApexes");function edgeKeyWait(r){return async t=>{const i=t.route;if(!i?.auth||i.internal)return;const{req:c}=t,a=Array.isArray(c.headers.authorization)?c.headers.authorization[0]:c.headers.authorization,_=String(a??"");if(!_.startsWith("Bearer "))return;const y=c.url??"/";if((0,manifest_1.authRuleFor)(i.auth,(0,edge_1.canonicalPath)(y)??y.split("?")[0],(c.method??"GET").toUpperCase()).mode!=="jwt")return;const S=String(c.headers.host??"").split(":")[0].toLowerCase();await r.for(S)?.awaitKey(_.slice(7))}}v(edgeKeyWait,"edgeKeyWait"),T(edgeKeyWait,"edgeKeyWait"),o(edgeKeyWait,"edgeKeyWait");function withBuiltinHooks(r,t){return{...r,beforeAuth:[...r.beforeAuth??[],t.keyWait],afterAuth:[t.middleware,...r.afterAuth??[]]}}v(withBuiltinHooks,"withBuiltinHooks"),T(withBuiltinHooks,"withBuiltinHooks"),o(withBuiltinHooks,"withBuiltinHooks"),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"),T(classifyClientError,"classifyClientError"),o(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 i=>{const c=Date.now(),a=t.get(i)??0;return c-a<r?!1:(t.set(i,c),!0)}}v(createClientErrorLogGate,"createClientErrorLogGate"),T(createClientErrorLogGate,"createClientErrorLogGate"),o(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"),T(guardInboundSocket,"guardInboundSocket"),o(guardInboundSocket,"guardInboundSocket");function retirePreviousWorkspace(r,t,i){const c=r.get(t);if(!c)return!1;r.delete(t),i==="re-registered"&&console.log(`[gateway] workspace '${t}' re-registered \u2014 retiring the children of its previous registration first.`);try{c()}catch(a){console.warn(`[gateway] could not fully retire the previous registration of '${t}' (${i}): ${a.message}`)}return!0}v(retirePreviousWorkspace,"retirePreviousWorkspace"),T(retirePreviousWorkspace,"retirePreviousWorkspace"),o(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 i=Number(r);return!Number.isFinite(i)||i<0?t:Math.floor(i)}v(parseBudget,"parseBudget"),T(parseBudget,"parseBudget"),o(parseBudget,"parseBudget");function resolveMaxConnections(r){return parseBudget(r,exports.GATEWAY_MAX_CONNECTIONS_DEFAULT)}v(resolveMaxConnections,"resolveMaxConnections"),T(resolveMaxConnections,"resolveMaxConnections"),o(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"),T(h2BudgetFromEnv,"h2BudgetFromEnv"),o(h2BudgetFromEnv,"h2BudgetFromEnv");function createH2Governor(r,t){const{NGHTTP2_ENHANCE_YOUR_CALM:i,NGHTTP2_REFUSED_STREAM:c}=require("node:http2").constants,a=new Map;let _=0;const y=o(s=>{s.idle&&(clearTimeout(s.idle),s.idle=void 0)},"disarm"),S=o((s,l)=>{y(l),!(r.idleSessionMs<=0||l.open>0)&&(l.idle=setTimeout(()=>{s.destroyed||s.closed||(t("session-reclaimed",{idleMs:r.idleSessionMs,sessions:a.size}),a.delete(s),s.close())},r.idleSessionMs),l.idle.unref?.())},"arm"),M=o(()=>{for(const[s,l]of a)if(!(l.open>0||s.destroyed))return y(l),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&&!M()){t("session-refused",{sessions:a.size,maxSessions:r.maxSessions,streams:_});try{s.goaway(i)}catch{}try{s.close()}catch{}return!1}const l={open:0};return a.set(s,l),S(s,l),s.once("close",()=>{y(l),a.delete(s)}),!0},admitStream(s,l){const d=a.get(s);if(!d)return!0;if(r.maxStreams>0&&_>=r.maxStreams){t("stream-refused",{streams:_,maxStreams:r.maxStreams,sessions:a.size});try{l.close(c)}catch{}return!1}return _+=1,d.open+=1,y(d),l.once("close",()=>{_=Math.max(0,_-1),d.open=Math.max(0,d.open-1),d.open===0&&a.has(s)&&S(s,d)}),!0},dispose(){for(const s of a.values())y(s);a.clear()}}}v(createH2Governor,"createH2Governor"),T(createH2Governor,"createH2Governor"),o(createH2Governor,"createH2Governor");async function startGateway(r,t){const i=r.https!==!1,c=r.ports?.length?r.ports:[443],a=r.scanTtlMs??1500,_=r.startupTimeoutMs??12e4,y=r.sweepMs??1e4,S=r.trafficFlushMs??5e3;let M=!1;const s=process.env.LENSMCP_EVENT_FILE??path.join(t.root,".lensmcp","events.jsonl"),l=(0,own_log_1.startOwnLogRotation)(t.root),d=(0,scope_1.readLensScope)(t.root),E=d.key,C=d.sockNs!==E?d.sockNs:void 0,b=t.projectsConfigurations?.projects??{},L=(0,discovery_1.projectSourceRoots)(t.root,b,t.projectDependencies),{routes:K,services:R,instance:Z}=(0,discovery_1.discoverRoutes)(t.root,b,void 0,E,L,C,d.instance);if(K.length===0)throw new Error("[gateway] no project declares a `cluster` field \u2014 nothing to route.");const U=new route_registry_1.RouteRegistry;U.register({wsKey:E,...C?{sockNs:C}:{},root:t.root,routes:K,services:R,...Z?{instance:Z}:{}});const k=[];let ee=o(()=>{},"refreshCert"),F=o(()=>{},"warmEdgeVerifiers");const re=o(()=>{(0,route_registry_1.rebuildRoutesInPlace)(k,U),ee(),F()},"rebuildRoutes");re();const{serviceKeys:ue,keyToProject:de,keyToWorkspace:pe}=(0,service_keys_1.loadServiceKeys)(t.root,R,E),_e=(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}:{}}),g={root:t.root,wsKey:E,...C?{sockNs:C}:{},eventFile:s,routes:k,registry:U,rebuildRoutes:re,services:R,serviceKeys:ue,keyToProject:de,keyToWorkspace:pe,clientIp:_e,bodyStallMs:r.bodyStallMs??types_1.BODY_STALL_MS,scanTtlMs:a,startupTimeoutMs:_,sweepMs:y,trafficFlushMs:S,https:i,projectRoots:Object.fromEntries(Object.entries(t.projectsConfigurations?.projects??{}).map(([e,n])=>[e,path.resolve(t.root,n.root)])),projectSourceRoots:L,...t.projectGraphStore?{graphStores:(0,project_graph_store_1.createProjectGraphStores)(t.projectGraphStore)}:{},...r.sharedCompiler!==void 0?{sharedCompiler:r.sharedCompiler}:{},stopped:o(()=>M,"stopped")};(0,process_name_1.prelinkProcessNames)((0,process_names_1.gatewayProcessNames)(R,{runner:(0,serve_launch_1.serveRunnerEnabled)()&&!!t.projectGraphStore,sharedBuild:(0,protocol_1.sharedCompilerEnabled)(process.env,r.sharedCompiler),label:E||path.basename(t.root),lens:{key:E,dashboard:r.dashboard!==!1,mcp:r.mcp!==!1&&K.some(e=>!!e.lens)}}));const w=(0,observability_1.createObservability)(s,{trafficFlushMs:S}),ge=createClientErrorLogGate(),O=h2BudgetFromEnv(),he=createClientErrorLogGate(3e4),D=createH2Governor(O,(e,n)=>{he(e)&&console.warn(`[gateway] h2 aggregate budget: ${e} (${JSON.stringify(n)}). 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).`),w.emit(e==="session-reclaimed"?"info":"warning",`h2 aggregate budget: ${e}`,`gateway-h2-budget:${e}`,{kind:"h2-aggregate-budget",event:e,project:"gateway",...n})}),A=(0,lifecycle_1.createServiceLayer)(g,w),I=(0,lens_children_1.createLensChildren)(g,w,r),B=new Map;let te=o(()=>{},"ownBooted");const Se=new Promise(e=>te=e),se=(0,warm_start_1.createWorktreeWarmer)({rt:g,obs:w,ready:Se,ensureUp:o(e=>A.ensureUp(e),"ensureUp")});let Y;if(r.middleware){const e=require(path.resolve(t.root,r.middleware));Y=e.default??e}const X=(0,workspace_middleware_1.createWorkspaceMiddleware)({ownerKey:E,...Y?{owner:Y}:{},policy:(0,workspace_middleware_1.guestMiddlewarePolicy)()}),$=process.env.LENSMCP_GW_ACT==="0"?void 0:(0,act_1.createActStore)({dir:path.join(path.dirname((0,control_1.controlSocketPath)()),"identities")});let H;try{H=(0,control_1.startControlServer)({rt:g,killService:o((e,n)=>A.killSpawned(e,n),"killService"),restartService:o((e,n)=>A.restartService(e,n),"restartService"),ensureService:o(e=>A.ensureUp(e),"ensureService"),...$?{act:$}:{},onRegister:o(async e=>{retirePreviousWorkspace(B,e.wsKey,"re-registered"),X.set(e.wsKey,e.root,e.middleware);const n=await I.hostWorkspaceDashboard(e),m=await I.hostWorkspaceApps(e);B.set(e.wsKey,()=>{try{n?.()}finally{m()}}),se.onRegister(e)},"onRegister"),onUnregister:o(e=>{se.onUnregister(e.wsKey),retirePreviousWorkspace(B,e.wsKey,"unregistered"),X.drop(e.wsKey),A.stopBuildHost(e.root)},"onUnregister")})}catch(e){console.warn("[gateway] control plane failed to start (multi-workspace register disabled):",e.message)}const W=(0,proxy_1.createProxy)(g,w,A),G=buildEdgeVerifierPool(()=>g.routes),oe=(0,auth_1.createEdgeAuth)(g,w,G,$),Ee=o(e=>{const n=e.route?.wsKey,m=X.for(n);if(m)try{const u=n?g.registry.get(n):void 0;m(e.req,{...n?{wsKey:n}:{},...u?{root:u.root}:{},env:u?.instance?.env??{}})}catch(u){w.traceStep(e.trace,"auth",{mode:"middleware",ok:!1,reason:u.message}),e.route&&w.finishTrace(e.trace,e.route.project,401),e.sendError(401,"unauthorized",`Gateway middleware rejected the request: ${u.message}`)}},"builtinMiddleware"),ne=(0,hooks_1.createHooks)(withBuiltinHooks(r.hooks??{},{keyWait:edgeKeyWait(G),middleware:Ee})),ae=(0,handler_1.createHandler)({rt:g,obs:w,auth:oe,proxy:W,hooks:ne}),ie=(0,upgrade_1.createUpgrade)({rt:g,auth:oe,proxy:W,hooks:ne,obs:w}),we=w.startEdgeFlusher(),me=A.startSweeper(),ce=(0,source_poller_1.createSourcePoller)({services:o(()=>g.registry.allServices(),"services"),serviceKey:o(e=>g.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],"serviceKey"),emit:o((e,n,m,u,h)=>w.emit(n,m,u,{wsKey:e.wsKey,...h},void 0,e.wsKey===g.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl")),"emit"),scanTtlMs:a,stopped:o(()=>M,"stopped")});(0,source_poller_1.sourcesEnabled)()&&ce.start(),await I.bootSingletonsAndApps();const le=R.filter(e=>e.decl.eager).map(e=>A.ensureUp(e));Promise.allSettled(le).then(()=>setTimeout(te,le.length?2e4:0).unref());let x,J,q;if(i){const e=require("../../../basic-ssl"),n=(0,service_keys_1.gatewayCacheDir)(t.root);q=o(()=>e.getCertificateSync(n,"gateway",g.routes.map(m=>m.host).filter(m=>!!m)),"mintCert"),x=q(),J=e.caCertPath()}const V=[],j=[],z=r.maxConnections??resolveMaxConnections(process.env.LENSMCP_MAX_CONNECTIONS);for(const e of c){const n=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},(u,h)=>ae(u,h)):http.createServer(ae);n.on("upgrade",ie),n.on("error",u=>console.error(`[gateway] port ${e}: ${u.code}`)),n.on("connection",guardInboundSocket),n.on("secureConnection",guardInboundSocket),n.on("tlsClientError",(u,h)=>h.destroy()),n.on("clientError",(u,h)=>{const p=u,f=classifyClientError(p.code,p.message);if(f.report&&ge(f.cause)){const P=h.remoteAddress??"unknown",N=f.status===null?"dropped":String(f.status);console.warn(`[gateway] inbound H1 clientError from ${P}: ${f.cause} (${p.code??p.message}${p.bytesParsed!==void 0?`, bytesParsed=${p.bytesParsed}`:""}) \u2192 ${N}. This status is the GATEWAY's, not the upstream service's.`),w.emit("warning",`inbound clientError: ${f.cause} \u2192 ${N}`,`gateway-client-error:${f.cause}`,{kind:"gateway-client-error",cause:f.cause,code:p.code??null,status:f.status,peer:P,bytesParsed:p.bytesParsed??null})}f.status!==null&&h.writable&&h.end(`HTTP/1.1 ${f.status} ${CLIENT_ERROR_REASON[f.status]}\r
|
|
2
2
|
\r
|
|
3
|
-
`),
|
|
3
|
+
`),h.destroy()}),n.keepAliveTimeout=types_1.GATEWAY_KEEPALIVE_TIMEOUT_MS,n.headersTimeout=r.headersTimeoutMs??types_1.GATEWAY_HEADERS_TIMEOUT_MS,z>0&&(n.maxConnections=z);const m=r.connectionsCheckingIntervalMs??types_1.GATEWAY_CONN_CHECK_MS;if(m>0&&(n.connectionsCheckingInterval=m),x!=null){const u=n,{NGHTTP2_CANCEL:h}=require("node:http2").constants;u.on("session",p=>{if(!D.admitSession(p)){p.on("error",()=>{});return}let f=0,P=0;p.on("stream",N=>{D.admitStream(p,N)&&N.once("close",()=>{p.destroyed?P+=1:N.rstCode===h&&(f+=1)})}),p.once("close",()=>{P!==0&&(console.warn(`[gateway] h2 session closed with ${P} stream(s) in flight after ${f} 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).`),w.emit("warning",`h2 session lost with ${P} stream(s) in flight`,"gateway-h2-session-lost",{kind:"h2-session-lost",project:"gateway",inflight:P,clientResets:f}))}),p.on("error",N=>{const Te=N.code??N.message;console.warn(`[gateway] h2 session error (${Te}) \u2014 dropping this session only`),p.destroyed||p.destroy()})}),u.on("sessionError",p=>{console.warn(`[gateway] h2 sessionError: ${p.code??p.message}`)})}await new Promise(u=>{n.listen(e,()=>{const h=n.address()?.port??e;j.push(h),console.log(`[gateway] Listening on ${x?"https":"http"}://localhost:${h}`),u()})}),V.push(n)}q&&(ee=o(()=>{const e=q();for(const n of V)n.setSecureContext?.({key:e,cert:e})},"refreshCert")),console.log("[gateway] Routes:");for(const e of k){const n=e.pool?`pods@${e.pool.dir}`:e.target;console.log(`[gateway] ${e.host??"(default)"} \u2192 ${n}${e.prependPrefix?` (+${e.prependPrefix})`:""}${e.internal?" [internal: no middleware]":""} [${e.project}]`)}J&&console.log(`[gateway] CA: ${J} \u2014 one-time setup via the trust executor.`),F=o(()=>G.warm(),"warmEdgeVerifiers"),F();const Q=o(e=>e>0?String(e):"unbounded","unbounded");return console.log(`[gateway] front-door budget: \u2264${Q(z)} connections, \u2264${Q(O.maxSessions)} h2 sessions (each \u2264512 MB session memory, \u2264512 streams), \u2264${Q(O.maxStreams)} open streams in total, idle h2 session reclaimed after ${O.idleSessionMs>0?`${Math.round(O.idleSessionMs/1e3)}s`:"never"}. Override: LENSMCP_MAX_CONNECTIONS / LENSMCP_MAX_H2_SESSIONS / LENSMCP_MAX_H2_STREAMS / LENSMCP_H2_IDLE_MS (0 = unbounded).`),w.emit("info",`gateway up: ${k.length} routes on ${j.join("/")}`,"cluster-gateway",{kind:"gateway-up",project:"gateway",ports:j,routes:k.map(e=>({host:e.host??"(default)",project:e.project,mode:e.pool?"pods":"tcp",internal:!!e.internal,prependPrefix:e.prependPrefix}))}),H&&process.env.LENSMCP_GUEST_REPLAY!=="0"&&H.replay().catch(e=>console.warn("[gateway] guest replay failed:",e.message)),{ports:j,routes:k,services:R,stop:o(async()=>{if(!M){M=!0,clearInterval(we),clearInterval(me),ce.stop(),w.emit("info","gateway down","cluster-gateway",{kind:"gateway-down",project:"gateway"}),G.stop(),H?.close(),$?.flush(),(0,workspace_registry_1.unregisterWorkspace)(E);for(const e of R)A.killSpawned(e,"gateway shutdown");A.stopRetiringTrees(),await A.stopBuildHost(),await A.finishDyingTrees(),await I.reapAll(),ie.closeTunnels(),await Promise.all(V.map(e=>new Promise(n=>{let m=!1;const u=o(()=>{m||(m=!0,n())},"done"),h=e;e.close(()=>u());try{h.closeIdleConnections?.()}catch{}setTimeout(()=>{try{h.closeAllConnections?.()}catch{}u()},types_1.GATEWAY_STOP_GRACE_MS).unref?.()}))),W.closeProxy(),W.destroyAgents(),D.dispose(),(0,workspace_log_1.closeWorkspaceLogs)(),l()}},"stop"),...g.lensSupervisor?{lensSupervisor:g.lensSupervisor}:{},...g.graphStores?{graphStores:g.graphStores}:{}}}v(startGateway,"startGateway"),T(startGateway,"startGateway"),o(startGateway,"startGateway");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var k=Object.defineProperty;var d=(e,r)=>k(e,"name",{value:r,configurable:!0});var l=Object.defineProperty,a=d((e,r)=>l(e,"name",{value:r,configurable:!0}),"a"),h=Object.defineProperty,y=a((e,r)=>h(e,"name",{value:r,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")}d(gatewayCacheDir,"gatewayCacheDir"),a(gatewayCacheDir,"gatewayCacheDir"),y(gatewayCacheDir,"gatewayCacheDir");function serviceKeyId(e,r){return`${e??""} ${r}`}d(serviceKeyId,"serviceKeyId"),a(serviceKeyId,"serviceKeyId"),y(serviceKeyId,"serviceKeyId");function loadServiceKeys(e,r,p,S){const n=gatewayCacheDir(e),j=path.join(n,"service-keys.json");let t={};try{t=JSON.parse(fs.readFileSync(j,"utf8"))}catch{}let u=!1;const v=[];for(const[c,f]of Object.entries(t))S?.(f)&&(t[c]=(0,node_crypto_1.randomBytes)(16).toString("hex"),u=!0,v.push(c));for(const c of r)t[c.project]||(t[c.project]=(0,node_crypto_1.randomBytes)(16).toString("hex"),u=!0);if(u)try{fs.mkdirSync(n,{recursive:!0}),fs.writeFileSync(j,JSON.stringify(t,null,2))}catch{}const o=p??r[0]?.wsKey,s={};for(const[c,f]of Object.entries(t))s[serviceKeyId(o,c)]=f;const i=new Map(Object.entries(t).map(([c,f])=>[f,c])),K=new Map(o?Object.values(t).map(c=>[c,o]):[]);return{serviceKeys:s,keyToProject:i,keyToWorkspace:K,byProject:t,regenerated:v}}d(loadServiceKeys,"loadServiceKeys"),a(loadServiceKeys,"loadServiceKeys"),y(loadServiceKeys,"loadServiceKeys");function adoptServiceKeys(e,r,p,S){const n=S??p[0]?.wsKey,j=y(o=>{const s=e.keyToWorkspace?.get(o);return s!==void 0&&s!==n},"taken"),{byProject:t,regenerated:u}=loadServiceKeys(r,p,n,j),v=[];for(const o of p){const s=serviceKeyId(o.wsKey??n,o.project),i=t[o.project];if(!i||e.serviceKeys[s]===i)continue;e.serviceKeys[s]=i,e.keyToProject.set(i,o.project);const K=o.wsKey??n;K&&e.keyToWorkspace?.set(i,K),v.push(o.project)}return{added:v,regenerated:u}}d(adoptServiceKeys,"adoptServiceKeys"),a(adoptServiceKeys,"adoptServiceKeys"),y(adoptServiceKeys,"adoptServiceKeys");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)){const n=i.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!n||!(0,protocol_1.isBuildHostCommandOf)(n[3],
|
|
1
|
+
"use strict";var C=Object.defineProperty;var E=(s,t)=>C(s,"name",{value:t,configurable:!0});var k=Object.defineProperty,y=E((s,t)=>k(s,"name",{value:t,configurable:!0}),"y"),j=Object.defineProperty,r=y((s,t)=>j(s,"name",{value:t,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.DEFAULT_BUILD_HOST_IDLE_SEC=exports.BUILD_HOST_IDLE_ENV=exports.HOST_MAX_RESTARTS=void 0,exports.buildHostIdleMs=buildHostIdleMs,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,HOST_STOP_GRACE_MS=6e3;exports.BUILD_HOST_IDLE_ENV="LENSMCP_BUILD_HOST_IDLE_SEC",exports.DEFAULT_BUILD_HOST_IDLE_SEC=300;function buildHostIdleMs(s=process.env){const t=s[exports.BUILD_HOST_IDLE_ENV]?.trim(),l=t?Number(t):NaN;return!Number.isFinite(l)||l<0?exports.DEFAULT_BUILD_HOST_IDLE_SEC*1e3:l>0?l*1e3:void 0}E(buildHostIdleMs,"buildHostIdleMs"),y(buildHostIdleMs,"buildHostIdleMs"),r(buildHostIdleMs,"buildHostIdleMs");function buildHostScript(s=path.join(__dirname,"../../..")){const t=path.join(s,"build-host.js");if(fs.existsSync(t))return{path:t,execArgv:[]};const l=path.join(s,"build-host.ts");if(fs.existsSync(l))try{return{path:l,execArgv:["--require",require.resolve("@swc-node/register")]}}catch{return}}E(buildHostScript,"buildHostScript"),y(buildHostScript,"buildHostScript"),r(buildHostScript,"buildHostScript");function workspaceBuildHostScript(s){try{return{path:(0,node_module_1.createRequire)(path.join(s,"package.json")).resolve("@lensmcp/cluster/build-host.js"),execArgv:[]}}catch{return}}E(workspaceBuildHostScript,"workspaceBuildHostScript"),y(workspaceBuildHostScript,"workspaceBuildHostScript"),r(workspaceBuildHostScript,"workspaceBuildHostScript");function createSharedBuildRelay(s,t={}){const l=t.script===void 0?buildHostScript():t.script??void 0,S=t.scriptFor??workspaceBuildHostScript,_=new Map,f=new WeakMap,c=(0,registration_guards_1.canonicalRoot)(s.root),w=r(e=>{const a=(0,registration_guards_1.canonicalRoot)(e.root);let d=_.get(a);return d||(d=a===c?createWorkspaceRelay(s,{root:s.root,...s.wsKey?{wsKey:s.wsKey}:{},...s.sockNs?{sockNs:s.sockNs}:{},eventFile:s.eventFile},l,t):createWorkspaceRelay(s,{root:e.root,...e.wsKey?{wsKey:e.wsKey}:{},...e.sockNs?{sockNs:e.sockNs}:{},eventFile:path.join(e.root,".lensmcp","events.jsonl")},S(e.root),t),_.set(a,d)),d},"relayFor");return{offeredTo:r(e=>(0,protocol_1.sharedCompilerEnabled)(t.gatewayEnv??process.env,s.sharedCompiler)&&w(e).offered(),"offeredTo"),attach(e,a,d){const g=w(e);f.set(d,g),g.attach(`${e.project}#g${a}`,d)},detach:r(e=>f.get(e)?.detach(e),"detach"),hostPid:r((e=s.root)=>_.get((0,registration_guards_1.canonicalRoot)(e))?.hostPid(),"hostPid"),release(e){const a=(0,registration_guards_1.canonicalRoot)(e),d=_.get(a);return _.delete(a),d?.stop()??Promise.resolve()},async stop(){const e=[..._.values()];_.clear(),await Promise.all(e.map(a=>a.stop()))}}}E(createSharedBuildRelay,"createSharedBuildRelay"),y(createSharedBuildRelay,"createSharedBuildRelay"),r(createSharedBuildRelay,"createSharedBuildRelay");function createWorkspaceRelay(s,t,l,S){const _=S.spawnProcess??node_child_process_1.spawn,f=S.log??(o=>console.log(o)),c=new Map,w=new WeakMap;let e,a,d;const g="idleMs"in S?S.idleMs:buildHostIdleMs(S.gatewayEnv??process.env);let I=[],h,b=!1;const H=(0,registration_guards_1.canonicalRoot)(t.root)===(0,registration_guards_1.canonicalRoot)(s.root)?"this workspace":`'${t.wsKey??path.basename(t.root)}'`,T=r((o,i)=>{if(!o.connected)return;const n={channel:protocol_1.SHARED_BUILD_CHANNEL,event:i};try{o.send(n,void 0,void 0,()=>{})}catch{}},"toRunner"),N=r(o=>{if(e?.connected)try{e.send(o,void 0,void 0,()=>{})}catch{}},"toHost"),P=r(()=>{if(S.reapStale===!1)return;let o;try{o=(0,node_child_process_1.execFileSync)("ps",["ax","-ww","-o","pid=,pgid=,command="],{encoding:"utf8",timeout:5e3})}catch{return}for(const i of o.split(`
|
|
2
|
+
`)){const n=i.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!n||!(0,protocol_1.isBuildHostCommandOf)(n[3],t.root))continue;const p=Number(n[1]),u=Number(n[2]);if(!(p===e?.pid||p===a?.pid||p===process.pid)){try{process.kill(-u,"SIGKILL")}catch{try{process.kill(p,"SIGKILL")}catch{}}f(`[gateway] reaped a stale build host (pid ${p}) of ${H}`)}}},"reapStaleHosts"),R=r(()=>{if(e||b||h||!l)return e;P();const o=t.wsKey||path.basename(t.root),i={...(0,pod_env_1.podBaseEnv)(process.env,s.root,t.root),NX_DAEMON:"false",NODE_ENV:"development",NX_WORKSPACE_ROOT:t.root,...t.wsKey?{LENSMCP_WS_KEY:t.wsKey}:{},...t.sockNs?{LENSMCP_SOCK_NS:t.sockNs}:{},LENSMCP_EVENT_FILE:t.eventFile,LENSMCP_GATEWAY_PID:String(process.pid)},n=_((0,process_name_1.namedExecPath)((0,process_name_1.processName)(o,protocol_1.BUILD_HOST_ROLE)),[...l.execArgv,l.path,...(0,protocol_1.buildHostArgs)(t.root)],{cwd:t.root,detached:!0,env:i,stdio:["ignore","pipe","pipe","ipc"]});e=n,f(`[gateway] build host starting (one compilation for the services of ${H} \u2014 LENSMCP_SHARED_COMPILER)`);const p=r(u=>m=>{if(!s.stopped())for(const L of m.toString().split(`
|
|
3
3
|
`))L.trim()&&u.write(`[build] ${L}
|
|
4
|
-
`)},"relayOut");return n.stdout?.on("data",p(process.stdout)),n.stderr?.on("data",p(process.stderr)),n.on("message",u=>{if(u?.type==="member"){const m=c.get(u.member);m&&T(m.proc,u.event)}}),n.on("exit",(u,m)=>{if(e===n&&(e=void 0),a===n){if(a=void 0,
|
|
4
|
+
`)},"relayOut");return n.stdout?.on("data",p(process.stdout)),n.stderr?.on("data",p(process.stderr)),n.on("message",u=>{if(u?.type==="member"){const m=c.get(u.member);m&&T(m.proc,u.event)}}),n.on("exit",(u,m)=>{if(e===n&&(e=void 0),a===n){if(a=void 0,b||s.stopped()||c.size===0)return;if(R())for(const[v,{join:M}]of c)N({type:"join",member:v,join:M});return}if(b||s.stopped())return;const L=Date.now();if(I=[...I.filter(v=>L-v<CRASH_WINDOW_MS),L],I.length>=exports.HOST_MAX_RESTARTS){h=`the build host exited ${I.length} times in a minute (last: ${u??m})`,f(`[gateway] ${h} \u2014 every service compiles on its own from now on`);for(const v of c.values())T(v.proc,{type:"refused",reason:h});c.clear();return}if(c.size!==0&&(f(`[gateway] build host exited (${u??m}) \u2014 restarting it for ${c.size} service tree(s)`),R()))for(const[v,{join:M}]of c)N({type:"join",member:v,join:M})}),n},"start"),O=r(o=>o.exitCode!==null||o.signalCode!==null?Promise.resolve():new Promise(i=>{const n=r(()=>{clearTimeout(p),i()},"done");o.once("exit",n);try{process.kill(-o.pid,"SIGTERM")}catch{try{o.kill("SIGTERM")}catch{}}const p=setTimeout(()=>{try{process.kill(-o.pid,"SIGKILL")}catch{try{o.kill("SIGKILL")}catch{}}i()},HOST_STOP_GRACE_MS);p.unref?.()}),"terminate"),x=r(()=>{d&&clearTimeout(d),d=void 0},"cancelIdle"),A=r(()=>{x(),!(g===void 0||b||!e)&&(d=setTimeout(()=>{d=void 0;const o=e;c.size>0||b||!o||(e=void 0,a=o,f(`[gateway] build host of ${H} stopped \u2014 no service of it has run for ${Math.round(g/1e3)}s (the next one starts it again)`),O(o))},g),d.unref?.())},"idleOut"),D=r(o=>{const i=w.get(o);!i||c.get(i)?.proc!==o||(c.delete(i),N({type:"leave",member:i}),c.size===0&&A())},"detach");return{offered:r(()=>!!l&&!h,"offered"),attach:r((o,i)=>{w.set(i,o),i.on("message",n=>{if((0,protocol_1.isRunnerJoinMessage)(n)){if(x(),a&&!h){c.set(o,{proc:i,join:n.join});return}if(h||!R()){T(i,{type:"refused",reason:h??"the build host could not be started"});return}c.set(o,{proc:i,join:n.join}),N({type:"join",member:o,join:n.join})}}),i.once("exit",()=>D(i))},"attach"),detach:D,hostPid:r(()=>e?.pid,"hostPid"),stop(){b=!0,x(),c.clear();const o=[e,a].filter(i=>!!i);return e=void 0,Promise.all(o.map(O)).then(()=>{})}}}E(createWorkspaceRelay,"createWorkspaceRelay"),y(createWorkspaceRelay,"createWorkspaceRelay"),r(createWorkspaceRelay,"createWorkspaceRelay");
|