@lensmcp/cluster 1.21.4 → 1.21.5

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.
@@ -1,3 +1,3 @@
1
- "use strict";var ne=Object.defineProperty;var S=(r,t)=>ne(r,"name",{value:t,configurable:!0});var oe=Object.defineProperty,n=S((r,t)=>oe(r,"name",{value:t,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.BENIGN_SOCKET_ERRNOS=void 0,exports.buildEdgeVerifierPool=buildEdgeVerifierPool,exports.classifyClientError=classifyClientError,exports.createClientErrorLogGate=createClientErrorLogGate,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"),control_1=require("./control"),workspace_registry_1=require("./workspace-registry"),service_keys_1=require("./service-keys"),client_ip_1=require("../client-ip"),workspace_log_1=require("./workspace-log"),observability_1=require("./observability"),lifecycle_1=require("./lifecycle"),lens_children_1=require("./lens-children"),proxy_1=require("./proxy"),auth_1=require("./auth"),hooks_1=require("./hooks"),handler_1=require("./handler"),upgrade_1=require("./upgrade"),jwks_verify_1=require("../jwks-verify"),types_1=require("./types");function insecureLocalFetch(r,t){return new Promise((h,w)=>{const f=(r.startsWith("https:")?require("node:https"):require("node:http")).request(r,{method:"GET",headers:t?.headers,rejectUnauthorized:!1},_=>{const u=[];_.on("data",l=>u.push(l)),_.on("end",()=>{const l=_.statusCode??0,a=Buffer.concat(u).toString("utf8");h({ok:l>=200&&l<300,status:l,json:n(async()=>JSON.parse(a),"json")})})});f.on("error",w),f.end()})}S(insecureLocalFetch,"insecureLocalFetch"),n(insecureLocalFetch,"insecureLocalFetch");function buildEdgeVerifierPool(r){const t=process.env.LENSMCP_GW_JWKS_URL,h=process.env.LENSMCP_GW_JWT_ISS,w=new Map;let f;const _=n((u,l)=>{console.log(`[gateway] edge JWT: verifying via JWKS ${u}${l}`);const a=(0,jwks_verify_1.createJwksVerifier)({jwksUrl:u,...h?{issuer:h}:{},fetchImpl:insecureLocalFetch});return a.refresh().catch(E=>console.warn("[gateway] edge JWKS warm failed (will retry):",E.message)),a},"make");return{for(u){if(t)return f??=_(t,"");const l=u.split(":")[0].toLowerCase();let a;for(const m of r()){const v=m.host;if(typeof v!="string"||!/^auth\./.test(v)||v.startsWith("internal."))continue;const T=v.slice(5);(l===T||l.endsWith(`.${T}`))&&(!a||T.length>a.length)&&(a=T)}if(!a)return;let E=w.get(a);return E||(E=_(`https://auth.${a}/jwks.json`,` (auto-derived for apex ${a})`),w.set(a,E)),E},stop(){f?.stop();for(const u of w.values())u.stop()}}}S(buildEdgeVerifierPool,"buildEdgeVerifierPool"),n(buildEdgeVerifierPool,"buildEdgeVerifierPool"),exports.BENIGN_SOCKET_ERRNOS=new Set(["ECONNRESET","EPIPE","ETIMEDOUT","ECONNABORTED","ECANCELED"]);function classifyClientError(r,t){return r&&exports.BENIGN_SOCKET_ERRNOS.has(r)?{status:null,report:!1,cause:"client-abort"}:r==="HPE_INVALID_EOF_STATE"?{status:null,report:!1,cause:"truncated-at-eof"}:r==="ERR_HTTP_REQUEST_TIMEOUT"?{status:408,report:!0,cause:"request-timeout"}:r==="HPE_HEADER_OVERFLOW"?{status:431,report:!0,cause:"header-overflow"}:r?.startsWith("HPE_")?{status:400,report:!0,cause:"parse-error"}:{status:400,report:!0,cause:r??t??"unknown"}}S(classifyClientError,"classifyClientError"),n(classifyClientError,"classifyClientError");const CLIENT_ERROR_REASON={400:"Bad Request",408:"Request Timeout",431:"Request Header Fields Too Large"};function createClientErrorLogGate(r=1e4){const t=new Map;return h=>{const w=Date.now(),f=t.get(h)??0;return w-f<r?!1:(t.set(h,w),!0)}}S(createClientErrorLogGate,"createClientErrorLogGate"),n(createClientErrorLogGate,"createClientErrorLogGate");function guardInboundSocket(r){r.on("error",t=>{exports.BENIGN_SOCKET_ERRNOS.has(t.code??"")||console.warn(`[gateway] inbound socket error (${t.code??t.message}) \u2014 dropping this connection only`),r.destroy()})}S(guardInboundSocket,"guardInboundSocket"),n(guardInboundSocket,"guardInboundSocket");async function startGateway(r,t){const h=r.https!==!1,w=r.ports?.length?r.ports:[443],f=r.scanTtlMs??1500,_=r.startupTimeoutMs??12e4,u=r.sweepMs??1e4,l=r.trafficFlushMs??5e3;let a=!1;const E=process.env.LENSMCP_EVENT_FILE??path.join(t.root,".lensmcp","events.jsonl"),m=(0,scope_1.readLensScope)(t.root).key,v=t.projectsConfigurations?.projects??{},T=(0,discovery_1.projectSourceRoots)(t.root,v,t.projectDependencies),{routes:L,services:k}=(0,discovery_1.discoverRoutes)(t.root,v,void 0,m,T);if(L.length===0)throw new Error("[gateway] no project declares a `cluster` field \u2014 nothing to route.");const q=new route_registry_1.RouteRegistry;q.register({wsKey:m,root:t.root,routes:L,services:k});const C=[];let W=n(()=>{},"refreshCert");const G=n(()=>{(0,route_registry_1.rebuildRoutesInPlace)(C,q),W()},"rebuildRoutes");G();const{serviceKeys:Y,keyToProject:z,keyToWorkspace:Q}=(0,service_keys_1.loadServiceKeys)(t.root,k,m),X=(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}:{}}),p={root:t.root,wsKey:m,eventFile:E,routes:C,registry:q,rebuildRoutes:G,services:k,serviceKeys:Y,keyToProject:z,keyToWorkspace:Q,clientIp:X,bodyStallMs:r.bodyStallMs??types_1.BODY_STALL_MS,scanTtlMs:f,startupTimeoutMs:_,sweepMs:u,trafficFlushMs:l,https:h,projectRoots:Object.fromEntries(Object.entries(t.projectsConfigurations?.projects??{}).map(([e,o])=>[e,path.resolve(t.root,o.root)])),projectSourceRoots:T,stopped:n(()=>a,"stopped")},d=(0,observability_1.createObservability)(E,{trafficFlushMs:l}),Z=createClientErrorLogGate(),b=(0,lifecycle_1.createServiceLayer)(p,d),A=(0,lens_children_1.createLensChildren)(p,d,r),x=new Map;let H;try{H=(0,control_1.startControlServer)({rt:p,killService:n((e,o)=>b.killSpawned(e,o),"killService"),onRegister:n(async e=>{const o=await A.hostWorkspaceDashboard(e),y=await A.hostWorkspaceApps(e);x.set(e.wsKey,()=>{o?.(),y()})},"onRegister"),onUnregister:n(e=>{x.get(e.wsKey)?.(),x.delete(e.wsKey)},"onUnregister")})}catch(e){console.warn("[gateway] control plane failed to start (multi-workspace register disabled):",e.message)}const I=(0,proxy_1.createProxy)(p,d,b),K=buildEdgeVerifierPool(()=>p.routes),F=(0,auth_1.createEdgeAuth)(p,d,K);let M;if(r.middleware){const e=require(path.resolve(t.root,r.middleware));M=e.default??e}const ee=n(e=>{if(M)try{M(e.req)}catch(o){d.traceStep(e.trace,"auth",{mode:"middleware",ok:!1,reason:o.message}),e.route&&d.finishTrace(e.trace,e.route.project,401),e.sendError(401,"unauthorized",`Gateway middleware rejected the request: ${o.message}`)}},"builtinMiddleware"),U=r.hooks??{},D=(0,hooks_1.createHooks)({...U,afterAuth:[ee,...U.afterAuth??[]]}),B=(0,handler_1.createHandler)({rt:p,obs:d,auth:F,proxy:I,hooks:D}),re=(0,upgrade_1.createUpgrade)({rt:p,auth:F,proxy:I,hooks:D}),te=d.startEdgeFlusher(),se=b.startSweeper();await A.bootSingletonsAndApps();for(const e of k)e.decl.eager&&b.ensureUp(e);let P,O,$;if(h){const e=require("../../../basic-ssl"),o=(0,service_keys_1.gatewayCacheDir)(t.root);$=n(()=>e.getCertificateSync(o,"gateway",p.routes.map(y=>y.host).filter(y=>!!y)),"mintCert"),P=$(),O=e.caCertPath()}const N=[],j=[];for(const e of w){const o=P?require("node:http2").createSecureServer({key:P,cert:P,allowHTTP1:!0,maxSessionMemory:512,settings:{maxConcurrentStreams:512},peerMaxConcurrentStreams:512},(i,s)=>B(i,s)):http.createServer(B);o.on("upgrade",re),o.on("error",i=>console.error(`[gateway] port ${e}: ${i.code}`)),o.on("connection",guardInboundSocket),o.on("secureConnection",guardInboundSocket),o.on("tlsClientError",(i,s)=>s.destroy()),o.on("clientError",(i,s)=>{const g=i,c=classifyClientError(g.code,g.message);if(c.report&&Z(c.cause)){const V=s.remoteAddress??"unknown",J=c.status===null?"dropped":String(c.status);console.warn(`[gateway] inbound H1 clientError from ${V}: ${c.cause} (${g.code??g.message}${g.bytesParsed!==void 0?`, bytesParsed=${g.bytesParsed}`:""}) \u2192 ${J}. This status is the GATEWAY's, not the upstream service's.`),d.emit("warning",`inbound clientError: ${c.cause} \u2192 ${J}`,`gateway-client-error:${c.cause}`,{kind:"gateway-client-error",cause:c.cause,code:g.code??null,status:c.status,peer:V,bytesParsed:g.bytesParsed??null})}c.status!==null&&s.writable&&s.end(`HTTP/1.1 ${c.status} ${CLIENT_ERROR_REASON[c.status]}\r
1
+ "use strict";var ae=Object.defineProperty;var m=(t,r)=>ae(t,"name",{value:r,configurable:!0});var ne=Object.defineProperty,n=m((t,r)=>ne(t,"name",{value:r,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.BENIGN_SOCKET_ERRNOS=void 0,exports.buildEdgeVerifierPool=buildEdgeVerifierPool,exports.classifyClientError=classifyClientError,exports.createClientErrorLogGate=createClientErrorLogGate,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"),control_1=require("./control"),workspace_registry_1=require("./workspace-registry"),service_keys_1=require("./service-keys"),client_ip_1=require("../client-ip"),workspace_log_1=require("./workspace-log"),observability_1=require("./observability"),lifecycle_1=require("./lifecycle"),lens_children_1=require("./lens-children"),proxy_1=require("./proxy"),auth_1=require("./auth"),hooks_1=require("./hooks"),handler_1=require("./handler"),upgrade_1=require("./upgrade"),jwks_verify_1=require("../jwks-verify"),types_1=require("./types");function insecureLocalFetch(t,r){return new Promise((g,w)=>{const E=(t.startsWith("https:")?require("node:https"):require("node:http")).request(t,{method:"GET",headers:r?.headers,rejectUnauthorized:!1},_=>{const d=[];_.on("data",l=>d.push(l)),_.on("end",()=>{const l=_.statusCode??0,a=Buffer.concat(d).toString("utf8");g({ok:l>=200&&l<300,status:l,json:n(async()=>JSON.parse(a),"json")})})});E.on("error",w),E.end()})}m(insecureLocalFetch,"insecureLocalFetch"),n(insecureLocalFetch,"insecureLocalFetch");function buildEdgeVerifierPool(t){const r=process.env.LENSMCP_GW_JWKS_URL,g=process.env.LENSMCP_GW_JWT_ISS,w=new Map;let E;const _=n((d,l)=>{console.log(`[gateway] edge JWT: verifying via JWKS ${d}${l}`);const a=(0,jwks_verify_1.createJwksVerifier)({jwksUrl:d,...g?{issuer:g}:{},fetchImpl:insecureLocalFetch});return a.refresh().catch(f=>console.warn("[gateway] edge JWKS warm failed (will retry):",f.message)),a},"make");return{for(d){if(r)return E??=_(r,"");const l=d.split(":")[0].toLowerCase();let a;for(const R of t()){const v=R.host;if(typeof v!="string"||!/^auth\./.test(v)||v.startsWith("internal."))continue;const C=v.slice(5);(l===C||l.endsWith(`.${C}`))&&(!a||C.length>a.length)&&(a=C)}if(!a)return;let f=w.get(a);return f||(f=_(`https://auth.${a}/jwks.json`,` (auto-derived for apex ${a})`),w.set(a,f)),f},stop(){E?.stop();for(const d of w.values())d.stop()}}}m(buildEdgeVerifierPool,"buildEdgeVerifierPool"),n(buildEdgeVerifierPool,"buildEdgeVerifierPool"),exports.BENIGN_SOCKET_ERRNOS=new Set(["ECONNRESET","EPIPE","ETIMEDOUT","ECONNABORTED","ECANCELED"]);function classifyClientError(t,r){return t&&exports.BENIGN_SOCKET_ERRNOS.has(t)?{status:null,report:!1,cause:"client-abort"}:t==="HPE_INVALID_EOF_STATE"?{status:null,report:!1,cause:"truncated-at-eof"}:t==="ERR_HTTP_REQUEST_TIMEOUT"?{status:408,report:!0,cause:"request-timeout"}:t==="HPE_HEADER_OVERFLOW"?{status:431,report:!0,cause:"header-overflow"}:t?.startsWith("HPE_")?{status:400,report:!0,cause:"parse-error"}:{status:400,report:!0,cause:t??r??"unknown"}}m(classifyClientError,"classifyClientError"),n(classifyClientError,"classifyClientError");const CLIENT_ERROR_REASON={400:"Bad Request",408:"Request Timeout",431:"Request Header Fields Too Large"};function createClientErrorLogGate(t=1e4){const r=new Map;return g=>{const w=Date.now(),E=r.get(g)??0;return w-E<t?!1:(r.set(g,w),!0)}}m(createClientErrorLogGate,"createClientErrorLogGate"),n(createClientErrorLogGate,"createClientErrorLogGate");function guardInboundSocket(t){t.on("error",r=>{exports.BENIGN_SOCKET_ERRNOS.has(r.code??"")||console.warn(`[gateway] inbound socket error (${r.code??r.message}) \u2014 dropping this connection only`),t.destroy()})}m(guardInboundSocket,"guardInboundSocket"),n(guardInboundSocket,"guardInboundSocket");async function startGateway(t,r){const g=t.https!==!1,w=t.ports?.length?t.ports:[443],E=t.scanTtlMs??1500,_=t.startupTimeoutMs??12e4,d=t.sweepMs??1e4,l=t.trafficFlushMs??5e3;let a=!1;const f=process.env.LENSMCP_EVENT_FILE??path.join(r.root,".lensmcp","events.jsonl"),R=(0,scope_1.readLensScope)(r.root).key,v=r.projectsConfigurations?.projects??{},C=(0,discovery_1.projectSourceRoots)(r.root,v,r.projectDependencies),{routes:H,services:k}=(0,discovery_1.discoverRoutes)(r.root,v,void 0,R,C);if(H.length===0)throw new Error("[gateway] no project declares a `cluster` field \u2014 nothing to route.");const I=new route_registry_1.RouteRegistry;I.register({wsKey:R,root:r.root,routes:H,services:k});const P=[];let G=n(()=>{},"refreshCert");const K=n(()=>{(0,route_registry_1.rebuildRoutesInPlace)(P,I),G()},"rebuildRoutes");K();const{serviceKeys:J,keyToProject:z,keyToWorkspace:Q}=(0,service_keys_1.loadServiceKeys)(r.root,k,R),X=(0,client_ip_1.createClientIpResolver)({...(0,client_ip_1.clientIpOptionsFromEnv)(),...t.trustProxyHops!==void 0?{trustProxyHops:t.trustProxyHops}:{},...t.clientIpHeader?{clientIpHeader:t.clientIpHeader}:{},...t.clientIpTrustedProxies?{clientIpTrustedProxies:t.clientIpTrustedProxies}:{}}),h={root:r.root,wsKey:R,eventFile:f,routes:P,registry:I,rebuildRoutes:K,services:k,serviceKeys:J,keyToProject:z,keyToWorkspace:Q,clientIp:X,bodyStallMs:t.bodyStallMs??types_1.BODY_STALL_MS,scanTtlMs:E,startupTimeoutMs:_,sweepMs:d,trafficFlushMs:l,https:g,projectRoots:Object.fromEntries(Object.entries(r.projectsConfigurations?.projects??{}).map(([e,o])=>[e,path.resolve(r.root,o.root)])),projectSourceRoots:C,stopped:n(()=>a,"stopped")},p=(0,observability_1.createObservability)(f,{trafficFlushMs:l}),Z=createClientErrorLogGate(),A=(0,lifecycle_1.createServiceLayer)(h,p),O=(0,lens_children_1.createLensChildren)(h,p,t),N=new Map;let U;try{U=(0,control_1.startControlServer)({rt:h,killService:n((e,o)=>A.killSpawned(e,o),"killService"),onRegister:n(async e=>{const o=await O.hostWorkspaceDashboard(e),y=await O.hostWorkspaceApps(e);N.set(e.wsKey,()=>{o?.(),y()})},"onRegister"),onUnregister:n(e=>{N.get(e.wsKey)?.(),N.delete(e.wsKey)},"onUnregister")})}catch(e){console.warn("[gateway] control plane failed to start (multi-workspace register disabled):",e.message)}const M=(0,proxy_1.createProxy)(h,p,A),B=buildEdgeVerifierPool(()=>h.routes),F=(0,auth_1.createEdgeAuth)(h,p,B);let x;if(t.middleware){const e=require(path.resolve(r.root,t.middleware));x=e.default??e}const ee=n(e=>{if(x)try{x(e.req)}catch(o){p.traceStep(e.trace,"auth",{mode:"middleware",ok:!1,reason:o.message}),e.route&&p.finishTrace(e.trace,e.route.project,401),e.sendError(401,"unauthorized",`Gateway middleware rejected the request: ${o.message}`)}},"builtinMiddleware"),D=t.hooks??{},Y=(0,hooks_1.createHooks)({...D,afterAuth:[ee,...D.afterAuth??[]]}),V=(0,handler_1.createHandler)({rt:h,obs:p,auth:F,proxy:M,hooks:Y}),te=(0,upgrade_1.createUpgrade)({rt:h,auth:F,proxy:M,hooks:Y}),re=p.startEdgeFlusher(),oe=A.startSweeper();await O.bootSingletonsAndApps();for(const e of k)e.decl.eager&&A.ensureUp(e);let b,L,j;if(g){const e=require("../../../basic-ssl"),o=(0,service_keys_1.gatewayCacheDir)(r.root);j=n(()=>e.getCertificateSync(o,"gateway",h.routes.map(y=>y.host).filter(y=>!!y)),"mintCert"),b=j(),L=e.caCertPath()}const W=[],q=[];for(const e of w){const o=b?require("node:http2").createSecureServer({key:b,cert:b,allowHTTP1:!0,maxSessionMemory:512,settings:{maxConcurrentStreams:512},peerMaxConcurrentStreams:512,streamResetBurst:t.h2ResetBurst??types_1.GATEWAY_H2_RESET_BURST,streamResetRate:t.h2ResetRate??types_1.GATEWAY_H2_RESET_RATE},(c,u)=>V(c,u)):http.createServer(V);o.on("upgrade",te),o.on("error",c=>console.error(`[gateway] port ${e}: ${c.code}`)),o.on("connection",guardInboundSocket),o.on("secureConnection",guardInboundSocket),o.on("tlsClientError",(c,u)=>u.destroy()),o.on("clientError",(c,u)=>{const s=c,i=classifyClientError(s.code,s.message);if(i.report&&Z(i.cause)){const S=u.remoteAddress??"unknown",T=i.status===null?"dropped":String(i.status);console.warn(`[gateway] inbound H1 clientError from ${S}: ${i.cause} (${s.code??s.message}${s.bytesParsed!==void 0?`, bytesParsed=${s.bytesParsed}`:""}) \u2192 ${T}. This status is the GATEWAY's, not the upstream service's.`),p.emit("warning",`inbound clientError: ${i.cause} \u2192 ${T}`,`gateway-client-error:${i.cause}`,{kind:"gateway-client-error",cause:i.cause,code:s.code??null,status:i.status,peer:S,bytesParsed:s.bytesParsed??null})}i.status!==null&&u.writable&&u.end(`HTTP/1.1 ${i.status} ${CLIENT_ERROR_REASON[i.status]}\r
2
2
  \r
3
- `),s.destroy()}),o.keepAliveTimeout=types_1.GATEWAY_KEEPALIVE_TIMEOUT_MS,o.headersTimeout=r.headersTimeoutMs??types_1.GATEWAY_HEADERS_TIMEOUT_MS;const y=r.maxConnections??types_1.GATEWAY_MAX_CONNECTIONS;y>0&&(o.maxConnections=y);const R=r.connectionsCheckingIntervalMs??types_1.GATEWAY_CONN_CHECK_MS;if(R>0&&(o.connectionsCheckingInterval=R),P!=null){const i=o;i.on("session",s=>{s.on("error",g=>{const c=g.code??g.message;console.warn(`[gateway] h2 session error (${c}) \u2014 dropping this session only`),s.destroyed||s.destroy()})}),i.on("sessionError",s=>{console.warn(`[gateway] h2 sessionError: ${s.code??s.message}`)})}await new Promise(i=>{o.listen(e,()=>{const s=o.address()?.port??e;j.push(s),console.log(`[gateway] Listening on ${P?"https":"http"}://localhost:${s}`),i()})}),N.push(o)}$&&(W=n(()=>{const e=$();for(const o of N)o.setSecureContext?.({key:e,cert:e})},"refreshCert")),console.log("[gateway] Routes:");for(const e of C){const o=e.pool?`pods@${e.pool.dir}`:e.target;console.log(`[gateway] ${e.host??"(default)"} \u2192 ${o}${e.prependPrefix?` (+${e.prependPrefix})`:""}${e.internal?" [internal: no middleware]":""} [${e.project}]`)}return O&&console.log(`[gateway] CA: ${O} \u2014 one-time setup via the trust executor.`),d.emit("info",`gateway up: ${C.length} routes on ${j.join("/")}`,"cluster-gateway",{kind:"gateway-up",project:"gateway",ports:j,routes:C.map(e=>({host:e.host??"(default)",project:e.project,mode:e.pool?"pods":"tcp",internal:!!e.internal,prependPrefix:e.prependPrefix}))}),{ports:j,routes:C,services:k,stop:n(async()=>{if(!a){a=!0,clearInterval(te),clearInterval(se),d.emit("info","gateway down","cluster-gateway",{kind:"gateway-down",project:"gateway"}),K.stop(),H?.close(),(0,workspace_registry_1.unregisterWorkspace)(m);for(const e of k)b.killSpawned(e,"gateway shutdown");await A.reapAll(),await Promise.all(N.map(e=>new Promise(o=>{let y=!1;const R=n(()=>{y||(y=!0,o())},"done"),i=e;e.close(()=>R());try{i.closeIdleConnections?.()}catch{}setTimeout(()=>{try{i.closeAllConnections?.()}catch{}R()},types_1.GATEWAY_STOP_GRACE_MS).unref?.()}))),I.closeProxy(),I.destroyAgents(),(0,workspace_log_1.closeWorkspaceLogs)()}},"stop"),...p.lensSupervisor?{lensSupervisor:p.lensSupervisor}:{}}}S(startGateway,"startGateway"),n(startGateway,"startGateway");
3
+ `),u.destroy()}),o.keepAliveTimeout=types_1.GATEWAY_KEEPALIVE_TIMEOUT_MS,o.headersTimeout=t.headersTimeoutMs??types_1.GATEWAY_HEADERS_TIMEOUT_MS;const y=t.maxConnections??types_1.GATEWAY_MAX_CONNECTIONS;y>0&&(o.maxConnections=y);const $=t.connectionsCheckingIntervalMs??types_1.GATEWAY_CONN_CHECK_MS;if($>0&&(o.connectionsCheckingInterval=$),b!=null){const c=o,{NGHTTP2_CANCEL:u}=require("node:http2").constants;c.on("session",s=>{let i=0,S=0;s.on("stream",T=>{T.once("close",()=>{s.destroyed?S+=1:T.rstCode===u&&(i+=1)})}),s.once("close",()=>{S!==0&&(console.warn(`[gateway] h2 session closed with ${S} stream(s) in flight after ${i} 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/foodguard/14).`),p.emit("warning",`h2 session lost with ${S} stream(s) in flight`,"gateway-h2-session-lost",{kind:"h2-session-lost",project:"gateway",inflight:S,clientResets:i}))}),s.on("error",T=>{const se=T.code??T.message;console.warn(`[gateway] h2 session error (${se}) \u2014 dropping this session only`),s.destroyed||s.destroy()})}),c.on("sessionError",s=>{console.warn(`[gateway] h2 sessionError: ${s.code??s.message}`)})}await new Promise(c=>{o.listen(e,()=>{const u=o.address()?.port??e;q.push(u),console.log(`[gateway] Listening on ${b?"https":"http"}://localhost:${u}`),c()})}),W.push(o)}j&&(G=n(()=>{const e=j();for(const o of W)o.setSecureContext?.({key:e,cert:e})},"refreshCert")),console.log("[gateway] Routes:");for(const e of P){const o=e.pool?`pods@${e.pool.dir}`:e.target;console.log(`[gateway] ${e.host??"(default)"} \u2192 ${o}${e.prependPrefix?` (+${e.prependPrefix})`:""}${e.internal?" [internal: no middleware]":""} [${e.project}]`)}return L&&console.log(`[gateway] CA: ${L} \u2014 one-time setup via the trust executor.`),p.emit("info",`gateway up: ${P.length} routes on ${q.join("/")}`,"cluster-gateway",{kind:"gateway-up",project:"gateway",ports:q,routes:P.map(e=>({host:e.host??"(default)",project:e.project,mode:e.pool?"pods":"tcp",internal:!!e.internal,prependPrefix:e.prependPrefix}))}),{ports:q,routes:P,services:k,stop:n(async()=>{if(!a){a=!0,clearInterval(re),clearInterval(oe),p.emit("info","gateway down","cluster-gateway",{kind:"gateway-down",project:"gateway"}),B.stop(),U?.close(),(0,workspace_registry_1.unregisterWorkspace)(R);for(const e of k)A.killSpawned(e,"gateway shutdown");await O.reapAll(),await Promise.all(W.map(e=>new Promise(o=>{let y=!1;const $=n(()=>{y||(y=!0,o())},"done"),c=e;e.close(()=>$());try{c.closeIdleConnections?.()}catch{}setTimeout(()=>{try{c.closeAllConnections?.()}catch{}$()},types_1.GATEWAY_STOP_GRACE_MS).unref?.()}))),M.closeProxy(),M.destroyAgents(),(0,workspace_log_1.closeWorkspaceLogs)()}},"stop"),...h.lensSupervisor?{lensSupervisor:h.lensSupervisor}:{}}}m(startGateway,"startGateway"),n(startGateway,"startGateway");
@@ -536,6 +536,21 @@ export declare const GATEWAY_CONN_CHECK_MS: number;
536
536
  * Override `LENSMCP_BODY_STALL_MS`. Default 60s.
537
537
  */
538
538
  export declare const BODY_STALL_MS: number;
539
+ /**
540
+ * The h2 front door's RST_STREAM budget, PER SESSION (issues/foodguard/14). nghttp2's Rapid-Reset mitigation
541
+ * (CVE-2023-44487) allows 1000 resets per session, refilling at 33/s, and CLOSES the session (GOAWAY
542
+ * INTERNAL_ERROR) on the next one — with NO 'error' event on the server side. A browser keeps ONE h2 session
543
+ * per origin for the life of the tab and cancels every in-flight stream on each navigation (a Vite dev page:
544
+ * hundreds of modules, plus the API fetches React StrictMode aborts), so the cancels ACCUMULATE across
545
+ * navigations until the budget is spent; then every in-flight module fails at once (`ERR_HTTP2_PROTOCOL_ERROR`
546
+ * ×N in the console) and the page boots into its blank/fallback state. Measured in foodguard 2026-09-07:
547
+ * 19 of 134 screens in one capture sweep; reproduced on round 3 of a 450-cancels-per-round probe. A dev
548
+ * front door serves one developer's browser, so the budget is sized far past any real navigation rate.
549
+ * Node enforces the limit only when BOTH values are set. Override `LENSMCP_H2_RESET_BURST` /
550
+ * `LENSMCP_H2_RESET_RATE` (resets per second).
551
+ */
552
+ export declare const GATEWAY_H2_RESET_BURST: number;
553
+ export declare const GATEWAY_H2_RESET_RATE: number;
539
554
  /** Test-tunable knobs on top of the user-facing schema. */
540
555
  export interface GatewayRuntimeOptions extends GatewayExecutorSchema {
541
556
  /** Traffic-edge flush period (ms). Default 5000. */
@@ -560,6 +575,11 @@ export interface GatewayRuntimeOptions extends GatewayExecutorSchema {
560
575
  connectionsCheckingIntervalMs?: number;
561
576
  /** Abort a transfer that has moved NOTHING for this long, either direction (`LENSMCP_BODY_STALL_MS`, default 60s; 0 off). */
562
577
  bodyStallMs?: number;
578
+ /** Per-session h2 RST_STREAM budget — burst (`LENSMCP_H2_RESET_BURST`, default 100k) and refill per second
579
+ * (`LENSMCP_H2_RESET_RATE`, default 10k). nghttp2's 1000 / 33 default tears a dev browser's session down
580
+ * after a few navigations (issues/foodguard/14). Both must be set for Node to apply either. */
581
+ h2ResetBurst?: number;
582
+ h2ResetRate?: number;
563
583
  /** Customer-supplied lifecycle hooks layered on top of the built-in pipeline. */
564
584
  hooks?: GatewayHooks;
565
585
  }
@@ -1 +1 @@
1
- "use strict";var O=Object.defineProperty;var e=(_,E)=>O(_,"name",{value:E,configurable:!0});var M=Object.defineProperty,L=e((_,E)=>M(_,"name",{value:E,configurable:!0}),"L");Object.defineProperty(exports,"__esModule",{value:!0}),exports.BODY_STALL_MS=exports.GATEWAY_CONN_CHECK_MS=exports.GATEWAY_MAX_CONNECTIONS=exports.GATEWAY_STOP_GRACE_MS=exports.GATEWAY_HEADERS_TIMEOUT_MS=exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=exports.LENS_REQUEST_RECOVERY_WAIT_MS=exports.LENS_REPLACEMENT_DRAIN_MS=exports.LENS_REPLACEMENT_READY_MS=exports.LENS_RESTART_MODE=exports.LENS_RECYCLE_KILL_GRACE_MS=exports.LENS_PARKED_PORT_REPROBE_MS=exports.MAX_PORT_CONFLICT_RETRIES=exports.CHILD_START_FAIL_MS=exports.PORT_FREE_POLL_MS=exports.PORT_FREE_WAIT_MS=exports.LENS_PROBE_BOOT_GRACE_MS=exports.LENS_PROBE_COOLDOWN_MS=exports.LENS_PROBE_TIMEOUT_MS=exports.LENS_PROBE_FAILS=exports.LENS_PROBE_GRACE_MS=exports.POD_ROLL_READY_MS=exports.POD_RECYCLE_MODE=exports.POD_WATCHER_SILENT=exports.POD_WATCHER_UNVERIFIED=exports.LENS_WATCH_SCOPE_ENABLED=exports.LENS_WATCHER_UNVERIFIED=exports.LENS_WATCHER_PROBE_ENABLED=exports.LENS_PROBE_ENABLED=exports.POD_STALE_RECYCLE_COOLDOWN_MS=exports.POD_STALE_SCAN_MS=exports.POD_RECYCLE_SETTLE_MS=exports.POD_STALE_GRACE_MS=exports.POD_MAX_AGE_MS=exports.POD_RECYCLE_ENABLED=exports.WEDGE_RECYCLE_GRACE_MS=exports.POD_ALIVE_PATH=exports.POD_ALIVE_PROBE_TIMEOUT_MS=exports.POD_SLOW_FIRST_BYTE_MS=exports.POD_RESPONSE_TIMEOUT_MS=exports.UPSTREAM_HEAL_STEP_MS=exports.UPSTREAM_HEAL_WINDOW_MS=exports.SERVICE_RESTART_WINDOW_MS=exports.SERVICE_MAX_RESTARTS=exports.SERVICE_ERROR_THROTTLE_MS=void 0;function envInt(_,E,R=!1){const S=Number(process.env[_]);return!Number.isFinite(S)||S<0?E:S===0?R?0:E:S}e(envInt,"envInt"),L(envInt,"envInt"),exports.SERVICE_ERROR_THROTTLE_MS=5e3,exports.SERVICE_MAX_RESTARTS=5,exports.SERVICE_RESTART_WINDOW_MS=6e4,exports.UPSTREAM_HEAL_WINDOW_MS=8e3,exports.UPSTREAM_HEAL_STEP_MS=300,exports.POD_RESPONSE_TIMEOUT_MS=(()=>{const _=Number(process.env.LENSMCP_POD_RESPONSE_TIMEOUT_MS);return Number.isFinite(_)&&_>0?_:3e4})(),exports.POD_SLOW_FIRST_BYTE_MS=envInt("LENSMCP_POD_SLOW_FIRST_BYTE_MS",10*6e4,!0),exports.POD_ALIVE_PROBE_TIMEOUT_MS=envInt("LENSMCP_POD_ALIVE_PROBE_TIMEOUT_MS",1e3),exports.POD_ALIVE_PATH="/__lensmcp/alive",exports.WEDGE_RECYCLE_GRACE_MS=(()=>{const _=Number(process.env.LENSMCP_WEDGE_RECYCLE_GRACE_MS);return Number.isFinite(_)&&_>0?_:15e3})(),exports.POD_RECYCLE_ENABLED=process.env.LENSMCP_POD_RECYCLE!=="0",exports.POD_MAX_AGE_MS=envInt("LENSMCP_POD_MAX_AGE_MS",240*6e4,!0),exports.POD_STALE_GRACE_MS=envInt("LENSMCP_POD_STALE_GRACE_MS",1e4),exports.POD_RECYCLE_SETTLE_MS=envInt("LENSMCP_POD_RECYCLE_SETTLE_MS",8e3),exports.POD_STALE_SCAN_MS=envInt("LENSMCP_POD_STALE_SCAN_MS",3e4),exports.POD_STALE_RECYCLE_COOLDOWN_MS=envInt("LENSMCP_POD_STALE_RECYCLE_COOLDOWN_MS",6e4),exports.LENS_PROBE_ENABLED=process.env.LENSMCP_LENS_PROBE!=="0",exports.LENS_WATCHER_PROBE_ENABLED=process.env.LENSMCP_LENS_WATCHER_PROBE!=="0",exports.LENS_WATCHER_UNVERIFIED=process.env.LENSMCP_LENS_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.LENS_WATCH_SCOPE_ENABLED=process.env.LENSMCP_LENS_WATCH_SCOPE!=="0",exports.POD_WATCHER_UNVERIFIED=process.env.LENSMCP_POD_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.POD_WATCHER_SILENT=process.env.LENSMCP_POD_WATCHER_SILENT==="recycle"?"recycle":"keep",exports.POD_RECYCLE_MODE=process.env.LENSMCP_POD_RECYCLE_MODE==="in-place"?"in-place":"rolling",exports.POD_ROLL_READY_MS=envInt("LENSMCP_POD_ROLL_READY_MS",18e4),exports.LENS_PROBE_GRACE_MS=envInt("LENSMCP_LENS_PROBE_GRACE_MS",45e3),exports.LENS_PROBE_FAILS=envInt("LENSMCP_LENS_PROBE_FAILS",2),exports.LENS_PROBE_TIMEOUT_MS=envInt("LENSMCP_LENS_PROBE_TIMEOUT_MS",1e3),exports.LENS_PROBE_COOLDOWN_MS=envInt("LENSMCP_LENS_PROBE_COOLDOWN_MS",3e4),exports.LENS_PROBE_BOOT_GRACE_MS=envInt("LENSMCP_LENS_PROBE_BOOT_GRACE_MS",24e4),exports.PORT_FREE_WAIT_MS=envInt("LENSMCP_PORT_FREE_WAIT_MS",1e4),exports.PORT_FREE_POLL_MS=envInt("LENSMCP_PORT_FREE_POLL_MS",250),exports.CHILD_START_FAIL_MS=envInt("LENSMCP_CHILD_START_FAIL_MS",1e4),exports.MAX_PORT_CONFLICT_RETRIES=envInt("LENSMCP_MAX_PORT_CONFLICT_RETRIES",5),exports.LENS_PARKED_PORT_REPROBE_MS=envInt("LENSMCP_PARKED_PORT_REPROBE_MS",3e5),exports.LENS_RECYCLE_KILL_GRACE_MS=envInt("LENSMCP_RECYCLE_KILL_GRACE_MS",5e3),exports.LENS_RESTART_MODE=process.env.LENSMCP_LENS_RESTART_MODE==="in-place"?"in-place":"rolling",exports.LENS_REPLACEMENT_READY_MS=envInt("LENSMCP_LENS_REPLACEMENT_READY_MS",3e4),exports.LENS_REPLACEMENT_DRAIN_MS=envInt("LENSMCP_LENS_REPLACEMENT_DRAIN_MS",2e3,!0),exports.LENS_REQUEST_RECOVERY_WAIT_MS=envInt("LENSMCP_LENS_REQUEST_RECOVERY_WAIT_MS",15e3),exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=envInt("LENSMCP_KEEPALIVE_TIMEOUT_MS",76e3),exports.GATEWAY_HEADERS_TIMEOUT_MS=envInt("LENSMCP_HEADERS_TIMEOUT_MS",6e4),exports.GATEWAY_STOP_GRACE_MS=envInt("LENSMCP_STOP_GRACE_MS",3e3),exports.GATEWAY_MAX_CONNECTIONS=envInt("LENSMCP_MAX_CONNECTIONS",0,!0),exports.GATEWAY_CONN_CHECK_MS=envInt("LENSMCP_CONN_CHECK_MS",0,!0),exports.BODY_STALL_MS=envInt("LENSMCP_BODY_STALL_MS",6e4,!0);
1
+ "use strict";var M=Object.defineProperty;var e=(_,E)=>M(_,"name",{value:E,configurable:!0});var T=Object.defineProperty,R=e((_,E)=>T(_,"name",{value:E,configurable:!0}),"R");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_H2_RESET_RATE=exports.GATEWAY_H2_RESET_BURST=exports.BODY_STALL_MS=exports.GATEWAY_CONN_CHECK_MS=exports.GATEWAY_MAX_CONNECTIONS=exports.GATEWAY_STOP_GRACE_MS=exports.GATEWAY_HEADERS_TIMEOUT_MS=exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=exports.LENS_REQUEST_RECOVERY_WAIT_MS=exports.LENS_REPLACEMENT_DRAIN_MS=exports.LENS_REPLACEMENT_READY_MS=exports.LENS_RESTART_MODE=exports.LENS_RECYCLE_KILL_GRACE_MS=exports.LENS_PARKED_PORT_REPROBE_MS=exports.MAX_PORT_CONFLICT_RETRIES=exports.CHILD_START_FAIL_MS=exports.PORT_FREE_POLL_MS=exports.PORT_FREE_WAIT_MS=exports.LENS_PROBE_BOOT_GRACE_MS=exports.LENS_PROBE_COOLDOWN_MS=exports.LENS_PROBE_TIMEOUT_MS=exports.LENS_PROBE_FAILS=exports.LENS_PROBE_GRACE_MS=exports.POD_ROLL_READY_MS=exports.POD_RECYCLE_MODE=exports.POD_WATCHER_SILENT=exports.POD_WATCHER_UNVERIFIED=exports.LENS_WATCH_SCOPE_ENABLED=exports.LENS_WATCHER_UNVERIFIED=exports.LENS_WATCHER_PROBE_ENABLED=exports.LENS_PROBE_ENABLED=exports.POD_STALE_RECYCLE_COOLDOWN_MS=exports.POD_STALE_SCAN_MS=exports.POD_RECYCLE_SETTLE_MS=exports.POD_STALE_GRACE_MS=exports.POD_MAX_AGE_MS=exports.POD_RECYCLE_ENABLED=exports.WEDGE_RECYCLE_GRACE_MS=exports.POD_ALIVE_PATH=exports.POD_ALIVE_PROBE_TIMEOUT_MS=exports.POD_SLOW_FIRST_BYTE_MS=exports.POD_RESPONSE_TIMEOUT_MS=exports.UPSTREAM_HEAL_STEP_MS=exports.UPSTREAM_HEAL_WINDOW_MS=exports.SERVICE_RESTART_WINDOW_MS=exports.SERVICE_MAX_RESTARTS=exports.SERVICE_ERROR_THROTTLE_MS=void 0;function envInt(_,E,L=!1){const S=Number(process.env[_]);return!Number.isFinite(S)||S<0?E:S===0?L?0:E:S}e(envInt,"envInt"),R(envInt,"envInt"),exports.SERVICE_ERROR_THROTTLE_MS=5e3,exports.SERVICE_MAX_RESTARTS=5,exports.SERVICE_RESTART_WINDOW_MS=6e4,exports.UPSTREAM_HEAL_WINDOW_MS=8e3,exports.UPSTREAM_HEAL_STEP_MS=300,exports.POD_RESPONSE_TIMEOUT_MS=(()=>{const _=Number(process.env.LENSMCP_POD_RESPONSE_TIMEOUT_MS);return Number.isFinite(_)&&_>0?_:3e4})(),exports.POD_SLOW_FIRST_BYTE_MS=envInt("LENSMCP_POD_SLOW_FIRST_BYTE_MS",10*6e4,!0),exports.POD_ALIVE_PROBE_TIMEOUT_MS=envInt("LENSMCP_POD_ALIVE_PROBE_TIMEOUT_MS",1e3),exports.POD_ALIVE_PATH="/__lensmcp/alive",exports.WEDGE_RECYCLE_GRACE_MS=(()=>{const _=Number(process.env.LENSMCP_WEDGE_RECYCLE_GRACE_MS);return Number.isFinite(_)&&_>0?_:15e3})(),exports.POD_RECYCLE_ENABLED=process.env.LENSMCP_POD_RECYCLE!=="0",exports.POD_MAX_AGE_MS=envInt("LENSMCP_POD_MAX_AGE_MS",240*6e4,!0),exports.POD_STALE_GRACE_MS=envInt("LENSMCP_POD_STALE_GRACE_MS",1e4),exports.POD_RECYCLE_SETTLE_MS=envInt("LENSMCP_POD_RECYCLE_SETTLE_MS",8e3),exports.POD_STALE_SCAN_MS=envInt("LENSMCP_POD_STALE_SCAN_MS",3e4),exports.POD_STALE_RECYCLE_COOLDOWN_MS=envInt("LENSMCP_POD_STALE_RECYCLE_COOLDOWN_MS",6e4),exports.LENS_PROBE_ENABLED=process.env.LENSMCP_LENS_PROBE!=="0",exports.LENS_WATCHER_PROBE_ENABLED=process.env.LENSMCP_LENS_WATCHER_PROBE!=="0",exports.LENS_WATCHER_UNVERIFIED=process.env.LENSMCP_LENS_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.LENS_WATCH_SCOPE_ENABLED=process.env.LENSMCP_LENS_WATCH_SCOPE!=="0",exports.POD_WATCHER_UNVERIFIED=process.env.LENSMCP_POD_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.POD_WATCHER_SILENT=process.env.LENSMCP_POD_WATCHER_SILENT==="recycle"?"recycle":"keep",exports.POD_RECYCLE_MODE=process.env.LENSMCP_POD_RECYCLE_MODE==="in-place"?"in-place":"rolling",exports.POD_ROLL_READY_MS=envInt("LENSMCP_POD_ROLL_READY_MS",18e4),exports.LENS_PROBE_GRACE_MS=envInt("LENSMCP_LENS_PROBE_GRACE_MS",45e3),exports.LENS_PROBE_FAILS=envInt("LENSMCP_LENS_PROBE_FAILS",2),exports.LENS_PROBE_TIMEOUT_MS=envInt("LENSMCP_LENS_PROBE_TIMEOUT_MS",1e3),exports.LENS_PROBE_COOLDOWN_MS=envInt("LENSMCP_LENS_PROBE_COOLDOWN_MS",3e4),exports.LENS_PROBE_BOOT_GRACE_MS=envInt("LENSMCP_LENS_PROBE_BOOT_GRACE_MS",24e4),exports.PORT_FREE_WAIT_MS=envInt("LENSMCP_PORT_FREE_WAIT_MS",1e4),exports.PORT_FREE_POLL_MS=envInt("LENSMCP_PORT_FREE_POLL_MS",250),exports.CHILD_START_FAIL_MS=envInt("LENSMCP_CHILD_START_FAIL_MS",1e4),exports.MAX_PORT_CONFLICT_RETRIES=envInt("LENSMCP_MAX_PORT_CONFLICT_RETRIES",5),exports.LENS_PARKED_PORT_REPROBE_MS=envInt("LENSMCP_PARKED_PORT_REPROBE_MS",3e5),exports.LENS_RECYCLE_KILL_GRACE_MS=envInt("LENSMCP_RECYCLE_KILL_GRACE_MS",5e3),exports.LENS_RESTART_MODE=process.env.LENSMCP_LENS_RESTART_MODE==="in-place"?"in-place":"rolling",exports.LENS_REPLACEMENT_READY_MS=envInt("LENSMCP_LENS_REPLACEMENT_READY_MS",3e4),exports.LENS_REPLACEMENT_DRAIN_MS=envInt("LENSMCP_LENS_REPLACEMENT_DRAIN_MS",2e3,!0),exports.LENS_REQUEST_RECOVERY_WAIT_MS=envInt("LENSMCP_LENS_REQUEST_RECOVERY_WAIT_MS",15e3),exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=envInt("LENSMCP_KEEPALIVE_TIMEOUT_MS",76e3),exports.GATEWAY_HEADERS_TIMEOUT_MS=envInt("LENSMCP_HEADERS_TIMEOUT_MS",6e4),exports.GATEWAY_STOP_GRACE_MS=envInt("LENSMCP_STOP_GRACE_MS",3e3),exports.GATEWAY_MAX_CONNECTIONS=envInt("LENSMCP_MAX_CONNECTIONS",0,!0),exports.GATEWAY_CONN_CHECK_MS=envInt("LENSMCP_CONN_CHECK_MS",0,!0),exports.BODY_STALL_MS=envInt("LENSMCP_BODY_STALL_MS",6e4,!0),exports.GATEWAY_H2_RESET_BURST=envInt("LENSMCP_H2_RESET_BURST",1e5),exports.GATEWAY_H2_RESET_RATE=envInt("LENSMCP_H2_RESET_RATE",1e4);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/cluster",
3
- "version": "1.21.4",
3
+ "version": "1.21.5",
4
4
  "description": "Run your Nx workspace as a local production cluster: pods on unix sockets with true HMR, one https gateway with per-project domains, scale-from-zero, autoscale, idle-kill, local-CA TLS — observed by the LensMCP lens.",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -57,9 +57,9 @@
57
57
  }
58
58
  },
59
59
  "dependencies": {
60
- "@lensmcp/core": "1.21.4",
61
- "@lensmcp/node-instrumentation": "1.21.4",
62
- "@lensmcp/nx-plugin": "1.21.4",
60
+ "@lensmcp/core": "1.21.5",
61
+ "@lensmcp/node-instrumentation": "1.21.5",
62
+ "@lensmcp/nx-plugin": "1.21.5",
63
63
  "fastify": "^5.0.0",
64
64
  "@fastify/reply-from": "^12.0.0",
65
65
  "@typescript/native-preview": "^7.0.0-dev.20260707.2",