@lensmcp/cluster 1.23.10 → 1.23.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/basic-ssl.js +1 -1
  2. package/build-scope-patterns.js +1 -1
  3. package/create-webpack-dev.js +1 -1
  4. package/create-webpack-prod.js +1 -1
  5. package/error-stack-release.js +1 -1
  6. package/executors/build/build.impl.js +1 -1
  7. package/executors/gateway/body-stall.js +1 -1
  8. package/executors/gateway/canonical-path.js +1 -1
  9. package/executors/gateway/client-ip.js +1 -1
  10. package/executors/gateway/gateway-errors.js +1 -1
  11. package/executors/gateway/gateway.impl.js +1 -1
  12. package/executors/gateway/gateway.lib.js +1 -1
  13. package/executors/gateway/health-check.js +1 -1
  14. package/executors/gateway/jwks-verify.js +1 -1
  15. package/executors/gateway/jwt-claims.js +1 -1
  16. package/executors/gateway/main.prod-gateway.js +2 -2
  17. package/executors/gateway/main.rollout.js +4 -4
  18. package/executors/gateway/manifest.js +1 -1
  19. package/executors/gateway/metrics.js +1 -1
  20. package/executors/gateway/otel-tracing.js +1 -1
  21. package/executors/gateway/prod-config.js +1 -1
  22. package/executors/gateway/prod-gateway.lib.js +1 -1
  23. package/executors/gateway/prod-runtime/access-log.js +1 -1
  24. package/executors/gateway/prod-runtime/app.js +1 -1
  25. package/executors/gateway/prod-runtime/auth.js +1 -1
  26. package/executors/gateway/prod-runtime/body-stall.js +1 -1
  27. package/executors/gateway/prod-runtime/cors.js +1 -1
  28. package/executors/gateway/prod-runtime/edge.js +1 -1
  29. package/executors/gateway/prod-runtime/handler.js +1 -1
  30. package/executors/gateway/prod-runtime/hooks.js +1 -1
  31. package/executors/gateway/prod-runtime/observability.js +1 -1
  32. package/executors/gateway/prod-runtime/rollout.js +1 -1
  33. package/executors/gateway/prod-runtime/routing.js +1 -1
  34. package/executors/gateway/prod-runtime/server.js +1 -1
  35. package/executors/gateway/prod-runtime/trust.js +1 -1
  36. package/executors/gateway/prod-runtime/upgrade.js +7 -7
  37. package/executors/gateway/prod-runtime/upstream.js +1 -1
  38. package/executors/gateway/providers-prod.js +1 -1
  39. package/executors/gateway/rate-limit.js +2 -2
  40. package/executors/gateway/registry-source.js +1 -1
  41. package/executors/gateway/rollout-ops.js +2 -2
  42. package/executors/gateway/runtime/auth.js +1 -1
  43. package/executors/gateway/runtime/chooser.js +9 -9
  44. package/executors/gateway/runtime/control.d.ts +15 -5
  45. package/executors/gateway/runtime/control.js +2 -2
  46. package/executors/gateway/runtime/dev-auth.js +1 -1
  47. package/executors/gateway/runtime/discovery.js +1 -1
  48. package/executors/gateway/runtime/edge.js +1 -1
  49. package/executors/gateway/runtime/handler.js +1 -1
  50. package/executors/gateway/runtime/hmr-reload.js +1 -1
  51. package/executors/gateway/runtime/hooks.js +1 -1
  52. package/executors/gateway/runtime/lens-children.js +1 -1
  53. package/executors/gateway/runtime/lifecycle.js +3 -3
  54. package/executors/gateway/runtime/observability.js +2 -2
  55. package/executors/gateway/runtime/pod-env.js +2 -2
  56. package/executors/gateway/runtime/pod-output.js +1 -1
  57. package/executors/gateway/runtime/pod-probe.js +1 -1
  58. package/executors/gateway/runtime/proxy.js +1 -1
  59. package/executors/gateway/runtime/route-registry.js +1 -1
  60. package/executors/gateway/runtime/scope.js +1 -1
  61. package/executors/gateway/runtime/server.js +2 -2
  62. package/executors/gateway/runtime/service-keys.js +1 -1
  63. package/executors/gateway/runtime/types.js +1 -1
  64. package/executors/gateway/runtime/upgrade.js +1 -1
  65. package/executors/gateway/runtime/workspace-log.js +1 -1
  66. package/executors/gateway/runtime/workspace-registry.js +1 -1
  67. package/executors/gateway/ssrf-guard.js +1 -1
  68. package/executors/serve/serve.impl.js +1 -1
  69. package/executors/trust/hostname.js +1 -1
  70. package/executors/trust/trust.impl.js +3 -3
  71. package/exit-reason.js +2 -2
  72. package/fork-ts-check-reporter.js +1 -1
  73. package/gateway.js +1 -1
  74. package/hot-swap-registries.js +1 -1
  75. package/index.js +1 -1
  76. package/main.devserver.js +8 -8
  77. package/package.json +4 -4
  78. package/process-name.js +1 -1
  79. package/redis-disconnect-fix.js +1 -1
  80. package/schema-first-instance.js +1 -1
  81. package/stdio-guard.js +1 -1
  82. package/swap-recycle.js +1 -1
  83. package/tsgo-check-plugin.js +4 -4
  84. package/typecheck-bus.js +3 -3
@@ -1 +1 @@
1
- "use strict";var x=Object.defineProperty;var i=(e,r)=>x(e,"name",{value:r,configurable:!0});var d=Object.defineProperty,c=i((e,r)=>d(e,"name",{value:r,configurable:!0}),"c"),p=Object.defineProperty,o=c((e,r)=>p(e,"name",{value:r,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.PREFLIGHT_METHODS_ROUTED=exports.PREFLIGHT_METHODS_NOROUTE=exports.corsPreflight=exports.cors=exports.isRoutedOrigin=exports.callerContextOf=exports.CALLER_CONTEXT=exports.CALLER_CONTEXT_HEADERS=exports.GATEWAY_OWNED_HEADERS=exports.sendError=exports.stampForwardingHeaders=exports.clientIpOf=exports.resolveClientIp=exports.CLIENT_IP=exports.rememberRawTarget=exports.rawTargetOf=exports.RAW_TARGET=exports.canonicalPath=exports.canonicalize=exports.ENCODED_STRUCTURE=void 0,exports.stripOwnedHeaders=stripOwnedHeaders;const gateway_errors_1=require("../gateway-errors"),client_ip_1=require("../client-ip"),manifest_1=require("../manifest");var canonical_path_1=require("../canonical-path");Object.defineProperty(exports,"ENCODED_STRUCTURE",{enumerable:!0,get:o(function(){return canonical_path_1.ENCODED_STRUCTURE},"get")}),Object.defineProperty(exports,"canonicalize",{enumerable:!0,get:o(function(){return canonical_path_1.canonicalize},"get")}),Object.defineProperty(exports,"canonicalPath",{enumerable:!0,get:o(function(){return canonical_path_1.canonicalPath},"get")}),Object.defineProperty(exports,"RAW_TARGET",{enumerable:!0,get:o(function(){return canonical_path_1.RAW_TARGET},"get")}),Object.defineProperty(exports,"rawTargetOf",{enumerable:!0,get:o(function(){return canonical_path_1.rawTargetOf},"get")}),Object.defineProperty(exports,"rememberRawTarget",{enumerable:!0,get:o(function(){return canonical_path_1.rememberRawTarget},"get")}),exports.CLIENT_IP=Symbol.for("lensmcp.gateway.clientIp");const FORWARDED=Symbol.for("lensmcp.gateway.forwarded"),peerOnly=(0,client_ip_1.createClientIpResolver)({}),resolverOf=o(e=>e.clientIp??peerOnly,"resolverOf"),peerOf=o(e=>e.socket?.remoteAddress??"","peerOf"),resolveClientIp=o((e,r)=>{const t=resolverOf(e).clientIpOf(r,peerOf(r));return r[exports.CLIENT_IP]=t,t},"resolveClientIp");exports.resolveClientIp=resolveClientIp;const clientIpOf=o(e=>e[exports.CLIENT_IP]??peerOf(e),"clientIpOf");exports.clientIpOf=clientIpOf;const stampForwardingHeaders=o((e,r)=>{const t=r;if(t[FORWARDED])return;t[FORWARDED]=!0;const s=peerOf(r);r.headers["x-forwarded-for"]=resolverOf(e).forwardedFor(r,s),r.headers["x-forwarded-proto"]=e.https?"https":"http";const n=r.headers.host;(resolverOf(e).trustProxyHops===0||!r.headers["x-forwarded-host"])&&(n?r.headers["x-forwarded-host"]=n:delete r.headers["x-forwarded-host"])},"stampForwardingHeaders");exports.stampForwardingHeaders=stampForwardingHeaders;const sendError=o((e,r,t,s,n,l,E)=>{const a=(0,gateway_errors_1.ensureRequestId)(r);return e.headersSent||e.writeHead(t,{"content-type":gateway_errors_1.GATEWAY_ERROR_CONTENT_TYPE,"x-request-id":a,...E??{}}),e.end((0,gateway_errors_1.gatewayErrorBody)(t,s,a,n,l)),a},"sendError");exports.sendError=sendError,exports.GATEWAY_OWNED_HEADERS=["x-internal-token","x-api-key-id","x-api-key-workspace","x-user-id","x-tenant-id","x-user-roles","x-user-permissions"],exports.CALLER_CONTEXT_HEADERS=["x-tenant-id","x-user-id"],exports.CALLER_CONTEXT=Symbol.for("lensmcp.gateway.callerContext");const CALLER_CONTEXT_VALUE=/^[\x21-\x2b\x2d-\x7e]{1,128}$/;function stripOwnedHeaders(e){const r={};for(const t of exports.CALLER_CONTEXT_HEADERS){const s=e.headers[t];typeof s=="string"&&CALLER_CONTEXT_VALUE.test(s)&&(r[t]=s)}e[exports.CALLER_CONTEXT]=r;for(const t of exports.GATEWAY_OWNED_HEADERS)delete e.headers[t]}i(stripOwnedHeaders,"stripOwnedHeaders"),c(stripOwnedHeaders,"stripOwnedHeaders"),o(stripOwnedHeaders,"stripOwnedHeaders");const callerContextOf=o(e=>e[exports.CALLER_CONTEXT]??{},"callerContextOf");exports.callerContextOf=callerContextOf;const isRoutedOrigin=o((e,r)=>{if(!e||e==="null")return!1;let t;try{t=new URL(e).hostname.toLowerCase()}catch{return!1}return t?t==="localhost"||t==="127.0.0.1"||t==="::1"?!0:r.some(s=>!!s.host&&(0,manifest_1.hostMatches)(s.host,t)):!1},"isRoutedOrigin");exports.isRoutedOrigin=isRoutedOrigin;const cors=o((e,r,t)=>{const s=e.headers.origin;typeof s!="string"||s===""||(r.setHeader("vary","Origin"),(0,exports.isRoutedOrigin)(s,t)&&(r.setHeader("access-control-allow-origin",s),r.setHeader("access-control-allow-credentials","true")))},"cors");exports.cors=cors;const corsPreflight=o((e,r,t,s)=>{(0,exports.cors)(e,r,s),r.writeHead(204,{"access-control-allow-methods":t,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),r.end()},"corsPreflight");exports.corsPreflight=corsPreflight,exports.PREFLIGHT_METHODS_NOROUTE="GET,HEAD,OPTIONS",exports.PREFLIGHT_METHODS_ROUTED="GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS";
1
+ "use strict";var d=Object.defineProperty;var c=(e,r)=>d(e,"name",{value:r,configurable:!0});var p=Object.defineProperty,o=c((e,r)=>p(e,"name",{value:r,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.PREFLIGHT_METHODS_ROUTED=exports.PREFLIGHT_METHODS_NOROUTE=exports.corsPreflight=exports.cors=exports.isRoutedOrigin=exports.callerContextOf=exports.CALLER_CONTEXT=exports.CALLER_CONTEXT_HEADERS=exports.GATEWAY_OWNED_HEADERS=exports.sendError=exports.stampForwardingHeaders=exports.clientIpOf=exports.resolveClientIp=exports.CLIENT_IP=exports.rememberRawTarget=exports.rawTargetOf=exports.RAW_TARGET=exports.canonicalPath=exports.canonicalize=exports.ENCODED_STRUCTURE=void 0,exports.stripOwnedHeaders=stripOwnedHeaders;const gateway_errors_1=require("../gateway-errors"),client_ip_1=require("../client-ip"),manifest_1=require("../manifest");var canonical_path_1=require("../canonical-path");Object.defineProperty(exports,"ENCODED_STRUCTURE",{enumerable:!0,get:o(function(){return canonical_path_1.ENCODED_STRUCTURE},"get")}),Object.defineProperty(exports,"canonicalize",{enumerable:!0,get:o(function(){return canonical_path_1.canonicalize},"get")}),Object.defineProperty(exports,"canonicalPath",{enumerable:!0,get:o(function(){return canonical_path_1.canonicalPath},"get")}),Object.defineProperty(exports,"RAW_TARGET",{enumerable:!0,get:o(function(){return canonical_path_1.RAW_TARGET},"get")}),Object.defineProperty(exports,"rawTargetOf",{enumerable:!0,get:o(function(){return canonical_path_1.rawTargetOf},"get")}),Object.defineProperty(exports,"rememberRawTarget",{enumerable:!0,get:o(function(){return canonical_path_1.rememberRawTarget},"get")}),exports.CLIENT_IP=Symbol.for("lensmcp.gateway.clientIp");const FORWARDED=Symbol.for("lensmcp.gateway.forwarded"),peerOnly=(0,client_ip_1.createClientIpResolver)({}),resolverOf=o(e=>e.clientIp??peerOnly,"resolverOf"),peerOf=o(e=>e.socket?.remoteAddress??"","peerOf"),resolveClientIp=o((e,r)=>{const t=resolverOf(e).clientIpOf(r,peerOf(r));return r[exports.CLIENT_IP]=t,t},"resolveClientIp");exports.resolveClientIp=resolveClientIp;const clientIpOf=o(e=>e[exports.CLIENT_IP]??peerOf(e),"clientIpOf");exports.clientIpOf=clientIpOf;const stampForwardingHeaders=o((e,r)=>{const t=r;if(t[FORWARDED])return;t[FORWARDED]=!0;const s=peerOf(r);r.headers["x-forwarded-for"]=resolverOf(e).forwardedFor(r,s),r.headers["x-forwarded-proto"]=e.https?"https":"http";const n=r.headers.host;(resolverOf(e).trustProxyHops===0||!r.headers["x-forwarded-host"])&&(n?r.headers["x-forwarded-host"]=n:delete r.headers["x-forwarded-host"])},"stampForwardingHeaders");exports.stampForwardingHeaders=stampForwardingHeaders;const sendError=o((e,r,t,s,n,i,l)=>{const a=(0,gateway_errors_1.ensureRequestId)(r);return e.headersSent||e.writeHead(t,{"content-type":gateway_errors_1.GATEWAY_ERROR_CONTENT_TYPE,"x-request-id":a,...l??{}}),e.end((0,gateway_errors_1.gatewayErrorBody)(t,s,a,n,i)),a},"sendError");exports.sendError=sendError,exports.GATEWAY_OWNED_HEADERS=["x-internal-token","x-api-key-id","x-api-key-workspace","x-user-id","x-tenant-id","x-user-roles","x-user-permissions"],exports.CALLER_CONTEXT_HEADERS=["x-tenant-id","x-user-id"],exports.CALLER_CONTEXT=Symbol.for("lensmcp.gateway.callerContext");const CALLER_CONTEXT_VALUE=/^[\x21-\x2b\x2d-\x7e]{1,128}$/;function stripOwnedHeaders(e){const r={};for(const t of exports.CALLER_CONTEXT_HEADERS){const s=e.headers[t];typeof s=="string"&&CALLER_CONTEXT_VALUE.test(s)&&(r[t]=s)}e[exports.CALLER_CONTEXT]=r;for(const t of exports.GATEWAY_OWNED_HEADERS)delete e.headers[t]}c(stripOwnedHeaders,"stripOwnedHeaders"),o(stripOwnedHeaders,"stripOwnedHeaders");const callerContextOf=o(e=>e[exports.CALLER_CONTEXT]??{},"callerContextOf");exports.callerContextOf=callerContextOf;const isRoutedOrigin=o((e,r)=>{if(!e||e==="null")return!1;let t;try{t=new URL(e).hostname.toLowerCase()}catch{return!1}return t?t==="localhost"||t==="127.0.0.1"||t==="::1"?!0:r.some(s=>!!s.host&&(0,manifest_1.hostMatches)(s.host,t)):!1},"isRoutedOrigin");exports.isRoutedOrigin=isRoutedOrigin;const cors=o((e,r,t)=>{const s=e.headers.origin;typeof s!="string"||s===""||(r.setHeader("vary","Origin"),(0,exports.isRoutedOrigin)(s,t)&&(r.setHeader("access-control-allow-origin",s),r.setHeader("access-control-allow-credentials","true")))},"cors");exports.cors=cors;const corsPreflight=o((e,r,t,s)=>{(0,exports.cors)(e,r,s),r.writeHead(204,{"access-control-allow-methods":t,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),r.end()},"corsPreflight");exports.corsPreflight=corsPreflight,exports.PREFLIGHT_METHODS_NOROUTE="GET,HEAD,OPTIONS",exports.PREFLIGHT_METHODS_ROUTED="GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS";
@@ -1 +1 @@
1
- "use strict";var j=Object.defineProperty;var y=(l,i)=>j(l,"name",{value:i,configurable:!0});var b=Object.defineProperty,w=y((l,i)=>b(l,"name",{value:i,configurable:!0}),"w"),S=Object.defineProperty,h=w((l,i)=>S(l,"name",{value:i,configurable:!0}),"h");Object.defineProperty(exports,"__esModule",{value:!0}),exports.createHandler=createHandler;const manifest_1=require("../manifest"),service_keys_1=require("./service-keys"),gateway_errors_1=require("../gateway-errors"),discovery_1=require("./discovery"),edge_1=require("./edge"),observability_1=require("./observability"),chooser_1=require("./chooser");function createHandler(l){const{rt:i,obs:p,auth:v,proxy:g,hooks:c}=l,_=h(e=>(e.headers.host||"").split(":")[0],"hostOf"),O=h((e,r)=>{if((0,edge_1.cors)(e,r,i.routes),e.method==="OPTIONS"){r.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_NOROUTE,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),r.end();return}const s=(e.headers.host||"").split(":")[0],t=i.routes.filter(o=>o.host&&(0,manifest_1.hostMatches)(o.host,s)&&o.prefix),a=(e.url??"/").split("?")[0];if((a==="/"||a==="/index.html"||a==="")&&i.routes.some(o=>o.host&&(0,manifest_1.hostMatches)(o.host,s)&&o.project===observability_1.LENS_DASHBOARD_PROJECT)){(0,chooser_1.serveChooser)(r,i.wsKey,e);return}if(t.length>0&&(a==="/health"||a==="/healthz")){const o=t.map(d=>({project:d.project,prefix:d.prefix,pods:d.pool?((0,discovery_1.pickSock)(d.pool,0),d.pool.socks.length):void 0,state:d.svc?.state??(d.target?"up":"unknown")})),f=o.every(d=>d.state!=="down"||!0);r.writeHead(f?200:503,{"content-type":"application/json"}),r.end(JSON.stringify({status:"ok",host:s,services:o},null,2));return}if(t.length>0&&a==="/.well-known/services"){r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({host:s,services:t.map(o=>({prefix:o.prefix,project:o.project,internal:!!o.internal}))},null,2));return}(0,edge_1.sendError)(r,e,404,"not_found",t.length>0?`No service mounted at ${a}. Mounted on ${s}: ${[...new Set(t.map(o=>o.prefix))].join(", ")} (+ /health, /.well-known/services)`:"No gateway route for this hostname.")},"handleNoRoute"),q=h(async(e,r)=>{if(!e.headers.host){const a=e.authority??e.headers[":authority"];a&&(e.headers.host=a)}(0,edge_1.stripOwnedHeaders)(e);const s=p.beginTrace(e);(0,gateway_errors_1.ensureRequestId)(e),s&&(p.traceStep(s,"received",{host:s.host,method:s.method,url:s.url}),e.__lensmcpTrace=s);const t=c.httpContext(e,r,s);try{const a=e.url??"/",o=(0,edge_1.canonicalize)(a);if(o===void 0){p.traceStep(s,"bad-path",{}),p.finishTrace(s,"gateway",400),(0,edge_1.sendError)(r,e,400,"bad_request","Bad Request");return}const f=o.policy,d=o.path+o.query;if(d!==a&&(0,edge_1.rememberRawTarget)(e,a),e.url=d,(0,edge_1.resolveClientIp)(i,e),c.has("onRequest")&&(await c.run("onRequest",t),t.responded()))return;const n=(0,manifest_1.matchRoute)(i.routes,_(e),f+o.query);if(!n){O(e,r);return}if(t.route=n,p.traceStep(s,"route-match",{project:n.project,...n.prefix?{prefix:n.prefix}:{},...n.host?{routeHost:n.host}:{},...n.internal?{internal:!0}:{}}),e.method==="OPTIONS"){(0,edge_1.cors)(e,r,i.routes),r.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_ROUTED,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),r.end();return}if((0,edge_1.cors)(e,r,i.routes),c.has("beforeAuth")&&(await c.run("beforeAuth",t),t.responded()))return;if(n.internal){const u=v.internal(e,n,s);if(!u.ok){p.finishTrace(s,n.project,u.status,void 0,n),(0,edge_1.sendError)(r,e,u.status,u.reason,u.detail);return}t.caller=u.caller}else{const u=v.public(e,n,s,f);if(!u.ok){p.finishTrace(s,n.project,u.status,void 0,n),(0,edge_1.sendError)(r,e,u.status,u.reason,u.detail);return}if(t.claims=u.claims,c.has("afterAuth")&&(await c.run("afterAuth",t),t.responded()))return}const m=n.pool?i.serviceKeys[(0,service_keys_1.serviceKeyId)(n.svc?.wsKey,n.project)]:void 0;if(m&&(e.headers["x-internal-token"]=m),(0,edge_1.stampForwardingHeaders)(i,e),c.has("beforeForward")&&(await c.run("beforeForward",t),t.responded()))return;c.has("onResponse")&&r.on("close",()=>{t.status=r.statusCode??0,c.run("onResponse",t)}),g.forward(n,e,r)}catch(a){t.error=a,console.error(`[gateway] ${new Date().toISOString()} pipeline error traceId=${(0,gateway_errors_1.ensureRequestId)(e)}: ${a?.stack??String(a)}`),c.has("onError")&&await c.run("onError",t),t.responded()||(0,edge_1.sendError)(r,e,500,"internal","Internal gateway error.")}},"runPipeline");return(e,r)=>{q(e,r)}}y(createHandler,"createHandler"),w(createHandler,"createHandler"),h(createHandler,"createHandler");
1
+ "use strict";var b=Object.defineProperty;var w=(p,i)=>b(p,"name",{value:i,configurable:!0});var S=Object.defineProperty,h=w((p,i)=>S(p,"name",{value:i,configurable:!0}),"h");Object.defineProperty(exports,"__esModule",{value:!0}),exports.createHandler=createHandler;const manifest_1=require("../manifest"),service_keys_1=require("./service-keys"),gateway_errors_1=require("../gateway-errors"),discovery_1=require("./discovery"),edge_1=require("./edge"),observability_1=require("./observability"),chooser_1=require("./chooser");function createHandler(p){const{rt:i,obs:d,auth:y,proxy:m,hooks:c}=p,g=h(e=>(e.headers.host||"").split(":")[0],"hostOf"),_=h((e,r)=>{if((0,edge_1.cors)(e,r,i.routes),e.method==="OPTIONS"){r.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_NOROUTE,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),r.end();return}const s=(e.headers.host||"").split(":")[0],t=i.routes.filter(o=>o.host&&(0,manifest_1.hostMatches)(o.host,s)&&o.prefix),n=(e.url??"/").split("?")[0];if((n==="/"||n==="/index.html"||n==="")&&i.routes.some(o=>o.host&&(0,manifest_1.hostMatches)(o.host,s)&&o.project===observability_1.LENS_DASHBOARD_PROJECT)){(0,chooser_1.serveChooser)(r,i.wsKey,e);return}if(t.length>0&&(n==="/health"||n==="/healthz")){const o=t.map(l=>({project:l.project,prefix:l.prefix,pods:l.pool?((0,discovery_1.pickSock)(l.pool,0),l.pool.socks.length):void 0,state:l.svc?.state??(l.target?"up":"unknown")})),f=o.every(l=>l.state!=="down"||!0);r.writeHead(f?200:503,{"content-type":"application/json"}),r.end(JSON.stringify({status:"ok",host:s,services:o},null,2));return}if(t.length>0&&n==="/.well-known/services"){r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({host:s,services:t.map(o=>({prefix:o.prefix,project:o.project,internal:!!o.internal}))},null,2));return}(0,edge_1.sendError)(r,e,404,"not_found",t.length>0?`No service mounted at ${n}. Mounted on ${s}: ${[...new Set(t.map(o=>o.prefix))].join(", ")} (+ /health, /.well-known/services)`:"No gateway route for this hostname.")},"handleNoRoute"),O=h(async(e,r)=>{if(!e.headers.host){const n=e.authority??e.headers[":authority"];n&&(e.headers.host=n)}(0,edge_1.stripOwnedHeaders)(e);const s=d.beginTrace(e);(0,gateway_errors_1.ensureRequestId)(e),s&&(d.traceStep(s,"received",{host:s.host,method:s.method,url:s.url}),e.__lensmcpTrace=s);const t=c.httpContext(e,r,s);try{const n=e.url??"/",o=(0,edge_1.canonicalize)(n);if(o===void 0){d.traceStep(s,"bad-path",{}),d.finishTrace(s,"gateway",400),(0,edge_1.sendError)(r,e,400,"bad_request","Bad Request");return}const f=o.policy,l=o.path+o.query;if(l!==n&&(0,edge_1.rememberRawTarget)(e,n),e.url=l,(0,edge_1.resolveClientIp)(i,e),c.has("onRequest")&&(await c.run("onRequest",t),t.responded()))return;const a=(0,manifest_1.matchRoute)(i.routes,g(e),f+o.query);if(!a){_(e,r);return}if(t.route=a,d.traceStep(s,"route-match",{project:a.project,...a.prefix?{prefix:a.prefix}:{},...a.host?{routeHost:a.host}:{},...a.internal?{internal:!0}:{}}),e.method==="OPTIONS"){(0,edge_1.cors)(e,r,i.routes),r.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_ROUTED,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),r.end();return}if((0,edge_1.cors)(e,r,i.routes),c.has("beforeAuth")&&(await c.run("beforeAuth",t),t.responded()))return;if(a.internal){const u=y.internal(e,a,s);if(!u.ok){d.finishTrace(s,a.project,u.status,void 0,a),(0,edge_1.sendError)(r,e,u.status,u.reason,u.detail);return}t.caller=u.caller}else{const u=y.public(e,a,s,f);if(!u.ok){d.finishTrace(s,a.project,u.status,void 0,a),(0,edge_1.sendError)(r,e,u.status,u.reason,u.detail);return}if(t.claims=u.claims,c.has("afterAuth")&&(await c.run("afterAuth",t),t.responded()))return}const v=a.pool?i.serviceKeys[(0,service_keys_1.serviceKeyId)(a.svc?.wsKey,a.project)]:void 0;if(v&&(e.headers["x-internal-token"]=v),(0,edge_1.stampForwardingHeaders)(i,e),c.has("beforeForward")&&(await c.run("beforeForward",t),t.responded()))return;c.has("onResponse")&&r.on("close",()=>{t.status=r.statusCode??0,c.run("onResponse",t)}),m.forward(a,e,r)}catch(n){t.error=n,console.error(`[gateway] ${new Date().toISOString()} pipeline error traceId=${(0,gateway_errors_1.ensureRequestId)(e)}: ${n?.stack??String(n)}`),c.has("onError")&&await c.run("onError",t),t.responded()||(0,edge_1.sendError)(r,e,500,"internal","Internal gateway error.")}},"runPipeline");return(e,r)=>{O(e,r)}}w(createHandler,"createHandler"),h(createHandler,"createHandler");
@@ -1 +1 @@
1
- "use strict";var u=Object.defineProperty;var i=(o,e)=>u(o,"name",{value:e,configurable:!0});var a=Object.defineProperty,l=i((o,e)=>a(o,"name",{value:e,configurable:!0}),"l"),c=Object.defineProperty,f=l((o,e)=>c(o,"name",{value:e,configurable:!0}),"f");Object.defineProperty(exports,"__esModule",{value:!0}),exports.VITE_FULL_RELOAD_PAYLOAD=void 0,exports.encodeWsTextFrame=encodeWsTextFrame,exports.registerHmrClient=registerHmrClient,exports.broadcastFullReload=broadcastFullReload,exports.VITE_FULL_RELOAD_PAYLOAD='{"type":"full-reload"}';function encodeWsTextFrame(o){const e=Buffer.from(o,"utf8"),r=e.length;if(r<126)return Buffer.concat([Buffer.from([129,r]),e]);if(r<=65535){const t=Buffer.alloc(4);return t[0]=129,t[1]=126,t.writeUInt16BE(r,2),Buffer.concat([t,e])}const n=Buffer.alloc(10);return n[0]=129,n[1]=127,n.writeBigUInt64BE(BigInt(r),2),Buffer.concat([n,e])}i(encodeWsTextFrame,"encodeWsTextFrame"),l(encodeWsTextFrame,"encodeWsTextFrame"),f(encodeWsTextFrame,"encodeWsTextFrame");function registerHmrClient(o,e,r){const n=o.hmrClients??=new Map;let t=n.get(e);t||n.set(e,t=new Set),t.add(r);const s=f(()=>{t.delete(r),t.size===0&&n.delete(e)},"drop");r.once("close",s),r.once("error",s)}i(registerHmrClient,"registerHmrClient"),l(registerHmrClient,"registerHmrClient"),f(registerHmrClient,"registerHmrClient");function broadcastFullReload(o,e){const r=o.hmrClients?.get(e);if(!r||r.size===0)return 0;const n=encodeWsTextFrame(exports.VITE_FULL_RELOAD_PAYLOAD);let t=0;for(const s of r)if(!s.destroyed)try{s.write(n),t+=1}catch{}return t}i(broadcastFullReload,"broadcastFullReload"),l(broadcastFullReload,"broadcastFullReload"),f(broadcastFullReload,"broadcastFullReload");
1
+ "use strict";var a=Object.defineProperty;var l=(n,e)=>a(n,"name",{value:e,configurable:!0});var c=Object.defineProperty,f=l((n,e)=>c(n,"name",{value:e,configurable:!0}),"f");Object.defineProperty(exports,"__esModule",{value:!0}),exports.VITE_FULL_RELOAD_PAYLOAD=void 0,exports.encodeWsTextFrame=encodeWsTextFrame,exports.registerHmrClient=registerHmrClient,exports.broadcastFullReload=broadcastFullReload,exports.VITE_FULL_RELOAD_PAYLOAD='{"type":"full-reload"}';function encodeWsTextFrame(n){const e=Buffer.from(n,"utf8"),t=e.length;if(t<126)return Buffer.concat([Buffer.from([129,t]),e]);if(t<=65535){const r=Buffer.alloc(4);return r[0]=129,r[1]=126,r.writeUInt16BE(t,2),Buffer.concat([r,e])}const o=Buffer.alloc(10);return o[0]=129,o[1]=127,o.writeBigUInt64BE(BigInt(t),2),Buffer.concat([o,e])}l(encodeWsTextFrame,"encodeWsTextFrame"),f(encodeWsTextFrame,"encodeWsTextFrame");function registerHmrClient(n,e,t){const o=n.hmrClients??=new Map;let r=o.get(e);r||o.set(e,r=new Set),r.add(t);const s=f(()=>{r.delete(t),r.size===0&&o.delete(e)},"drop");t.once("close",s),t.once("error",s)}l(registerHmrClient,"registerHmrClient"),f(registerHmrClient,"registerHmrClient");function broadcastFullReload(n,e){const t=n.hmrClients?.get(e);if(!t||t.size===0)return 0;const o=encodeWsTextFrame(exports.VITE_FULL_RELOAD_PAYLOAD);let r=0;for(const s of t)if(!s.destroyed)try{s.write(o),r+=1}catch{}return r}l(broadcastFullReload,"broadcastFullReload"),f(broadcastFullReload,"broadcastFullReload");
@@ -1 +1 @@
1
- "use strict";var p=Object.defineProperty;var c=(o,e)=>p(o,"name",{value:e,configurable:!0});var u=Object.defineProperty,i=c((o,e)=>u(o,"name",{value:e,configurable:!0}),"i"),a=Object.defineProperty,n=i((o,e)=>a(o,"name",{value:e,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.createHooks=createHooks;const edge_1=require("./edge"),TERMINAL_PHASES=new Set(["onResponse","onError"]);function createHooks(o){return{run:n(async(e,r)=>{const t=o[e];if(!t||t.length===0)return;const d=TERMINAL_PHASES.has(e);for(const s of t){if(!d&&r.responded())return;await s(r)}},"run"),has:n(e=>(o[e]?.length??0)>0,"has"),httpContext:n((e,r,t)=>({req:e,res:r,socket:void 0,trace:t,route:void 0,claims:void 0,caller:void 0,pod:void 0,error:void 0,status:void 0,sendError:n((d,s,v)=>(0,edge_1.sendError)(r,e,d,s,v),"sendError"),responded:n(()=>r.writableEnded||r.headersSent,"responded")}),"httpContext"),upgradeContext:n((e,r,t)=>({req:e,res:void 0,socket:r,trace:t,route:void 0,claims:void 0,caller:void 0,pod:void 0,error:void 0,status:void 0,sendError:n(()=>{try{r.destroy()}catch{}},"sendError"),responded:n(()=>r.destroyed,"responded")}),"upgradeContext")}}c(createHooks,"createHooks"),i(createHooks,"createHooks"),n(createHooks,"createHooks");
1
+ "use strict";var u=Object.defineProperty;var i=(t,e)=>u(t,"name",{value:e,configurable:!0});var a=Object.defineProperty,n=i((t,e)=>a(t,"name",{value:e,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.createHooks=createHooks;const edge_1=require("./edge"),TERMINAL_PHASES=new Set(["onResponse","onError"]);function createHooks(t){return{run:n(async(e,r)=>{const o=t[e];if(!o||o.length===0)return;const d=TERMINAL_PHASES.has(e);for(const s of o){if(!d&&r.responded())return;await s(r)}},"run"),has:n(e=>(t[e]?.length??0)>0,"has"),httpContext:n((e,r,o)=>({req:e,res:r,socket:void 0,trace:o,route:void 0,claims:void 0,caller:void 0,pod:void 0,error:void 0,status:void 0,sendError:n((d,s,c)=>(0,edge_1.sendError)(r,e,d,s,c),"sendError"),responded:n(()=>r.writableEnded||r.headersSent,"responded")}),"httpContext"),upgradeContext:n((e,r,o)=>({req:e,res:void 0,socket:r,trace:o,route:void 0,claims:void 0,caller:void 0,pod:void 0,error:void 0,status:void 0,sendError:n(()=>{try{r.destroy()}catch{}},"sendError"),responded:n(()=>r.destroyed,"responded")}),"upgradeContext")}}i(createHooks,"createHooks"),n(createHooks,"createHooks");
@@ -1 +1 @@
1
- "use strict";var $e=Object.defineProperty;var C=(r,E)=>$e(r,"name",{value:E,configurable:!0});var Re=Object.defineProperty,P=C((r,E)=>Re(r,"name",{value:E,configurable:!0}),"P"),Pe=Object.defineProperty,d=P((r,E)=>Pe(r,"name",{value:E,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.probePortFree=probePortFree,exports.probePortListening=probePortListening,exports.probeWatcherHealth=probeWatcherHealth,exports.waitForPortFree=waitForPortFree,exports.viteArgPort=viteArgPort,exports.describeChildExit=describeChildExit,exports.claimPort=claimPort,exports.createLensChildren=createLensChildren;const tslib_1=require("tslib"),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_child_process_1=require("node:child_process"),lens_frontend_1=require("@lensmcp/nx-plugin/lens-frontend"),hmr_reload_1=require("./hmr-reload"),process_name_1=require("../../../process-name"),pod_env_1=require("./pod-env"),scope_1=require("./scope"),workspace_registry_1=require("./workspace-registry"),lifecycle_1=require("./lifecycle"),types_1=require("./types"),observability_1=require("./observability"),HEAL_BASE_MS=1500,HEAL_MAX_MS=3e4,HEAL_HEALTHY_MS=2e4;function tryBind(r,E){return new Promise(u=>{const _=net.createServer();_.unref(),_.once("error",p=>{const f=p.code??"";u(f==="EADDRINUSE"||f==="EACCES"?"in-use":"unavailable")}),_.listen(E===void 0?{port:r}:{port:r,host:E},()=>_.close(()=>u("free")))})}C(tryBind,"tryBind"),P(tryBind,"tryBind"),d(tryBind,"tryBind");async function probePortFree(r){for(const E of[void 0,"0.0.0.0","127.0.0.1","::1"])if(await tryBind(r,E)==="in-use")return!1;return!0}C(probePortFree,"probePortFree"),P(probePortFree,"probePortFree"),d(probePortFree,"probePortFree");function probeConnect(r,E,u){return new Promise(_=>{let p=!1;const f=net.createConnection({host:r,port:E});f.unref();const M=setTimeout(()=>y(!1),u);M.unref?.();function y(D){p||(p=!0,clearTimeout(M),f.destroy(),_(D))}C(y,"v"),P(y,"P"),d(y,"finish"),f.once("connect",()=>y(!0)),f.once("error",()=>y(!1))})}C(probeConnect,"probeConnect"),P(probeConnect,"probeConnect"),d(probeConnect,"probeConnect");async function probePortListening(r,E=1e3){return await probeConnect("127.0.0.1",r,E)?!0:probeConnect("::1",r,E)}C(probePortListening,"probePortListening"),P(probePortListening,"probePortListening"),d(probePortListening,"probePortListening");async function probeWatcherHealth(r,E=1500){try{const u=new AbortController,_=setTimeout(()=>u.abort(),E);_.unref?.();try{const p=await fetch(`http://127.0.0.1:${r}/__lensmcp/watcher-health`,{signal:u.signal});if(!p.ok)return null;const f=await p.json();if(typeof f?.lastFsSetEventAt!="number")return null;const M=Array.isArray(f.recentEvents)?f.recentEvents.filter(y=>y&&typeof y.path=="string"&&typeof y.at=="number"&&typeof y.sequence=="number"&&["add","addDir","unlink","unlinkDir"].includes(y.kind)):[];return{schemaVersion:f.schemaVersion===2?2:1,ready:f.ready!==!1,sequence:typeof f.sequence=="number"?f.sequence:0,lastFsSetEventAt:f.lastFsSetEventAt,fsSetEvents:typeof f.fsSetEvents=="number"?f.fsSetEvents:0,recentEvents:M}}finally{clearTimeout(_)}}catch{return null}}C(probeWatcherHealth,"probeWatcherHealth"),P(probeWatcherHealth,"probeWatcherHealth"),d(probeWatcherHealth,"probeWatcherHealth");const sleepUnref=d(r=>new Promise(E=>{setTimeout(E,r).unref?.()}),"sleepUnref");async function waitForPortFree(r,E,u={}){const _=u.isPortFree??probePortFree,p=Math.max(1,u.intervalMs??types_1.PORT_FREE_POLL_MS),f=Date.now()+Math.max(0,E);for(;;){if(await _(r))return!0;const M=f-Date.now();if(M<=0)return!1;await sleepUnref(Math.min(p,M))}}C(waitForPortFree,"waitForPortFree"),P(waitForPortFree,"waitForPortFree"),d(waitForPortFree,"waitForPortFree");function viteArgPort(r){const E=d(u=>Number.isInteger(u)&&u>0&&u<65536?u:void 0,"valid");for(let u=0;u<r.length;u+=1){const _=r[u];if(_==="--port")return E(Number(r[u+1]));if(_.startsWith("--port="))return E(Number(_.slice(7)))}}C(viteArgPort,"viteArgPort"),P(viteArgPort,"viteArgPort"),d(viteArgPort,"viteArgPort");function describeChildExit(r){return r.signalCode?`killed by ${r.signalCode}`:r.exitCode===null?"exit status unknown":`exit code ${r.exitCode}`}C(describeChildExit,"describeChildExit"),P(describeChildExit,"describeChildExit"),d(describeChildExit,"describeChildExit");async function claimPort(r,E,u,_){let p=r;for(;E.has(p)||_?.has(p)||!await u(p);)p+=1;return E.add(p),p}C(claimPort,"claimPort"),P(claimPort,"claimPort"),d(claimPort,"claimPort");function createLensChildren(r,E,u,_){const{emit:p}=E,f=_?.isPortFree??probePortFree,M=(u.ports?.length?u.ports:[443]).join(","),y=_?.probeWatcherHealth??probeWatcherHealth,D=[],B=new Map,k=new Map,I=new Map,q=new Map,W=new Set;let j;const N=new Map,$=new Set,Z=new Set,V=new Set,A=new Set,L=new Map,F=new WeakMap,G=new Set,ee=d((e,s,n)=>{if(G.has(e))return;G.add(e);const t=setInterval(()=>{(async()=>{if(r.stopped()||$.has(e)){clearInterval(t),G.delete(e);return}await f(s)&&(clearInterval(t),G.delete(e),console.log(`[gateway] lens child ${e}: :${s} freed \u2014 respawning.`),n())})().catch(()=>{})},types_1.LENS_PARKED_PORT_REPROBE_MS);t.unref?.()},"parkUntilPortFree"),x=d(async(e,s,n)=>{const t=await claimPort(e,s,f,n?.reserved);return t!==e&&(n?.heldBy?console.log(`[gateway] handoff: :${e} is held by ${n.heldBy} \u2014 replacement on :${t}.`):console.warn(`[gateway] port ${e} is unavailable (another process holds it \u2014 an orphan from a crashed gateway?) \u2014 using ${t} instead.`)),t},"claimFreePort"),de=d((e,s,n)=>{const t=n?.LENSMCP_FRONTEND_KEY,o=Number(n?.LENSMCP_FRONTEND_GENERATION);if(!t||!Number.isFinite(o))return;const a=[...L.get(t)?.generations??[]].find(i=>i.generation===o);a&&(e.endsWith(":vite")?a.vite=s:e.endsWith(":browser-capture")&&(a.capture=s))},"attachRespawnedGenerationChild"),H=d(e=>{if(!(e.exitCode!==null||e.signalCode!==null)){Z.add(e);try{e.kill("SIGTERM")}catch{}setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{e.kill("SIGKILL")}catch{}},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}},"retireChild"),pe=d((e,s)=>{const n=N.get(e);!n||n===s||n.exitCode!==null||n.signalCode!==null||(console.warn(`[gateway] lens child ${e}: a replacement took the label \u2014 retiring the previous child (pid ${n.pid??"?"}).`),H(n))},"retireLabelHolder"),O=d((e,s,n,t,o=!1,a,i,l)=>{const h=Date.now(),c=(0,node_child_process_1.spawn)(s,n,{cwd:i??r.root,env:{...(0,pod_env_1.podBaseEnv)(process.env,r.root,i??r.root),...t??{},LENSMCP_PARENT_PID:String(process.pid)},stdio:"inherit"});D.push(c),pe(e,c),N.set(e,c),de(e,c,t);const S=e==="vite"||e.endsWith(":vite"),b=typeof t?.LENSMCP_EVENT_FILE=="string"?t.LENSMCP_EVENT_FILE:void 0,v=b&&b!==r.eventFile?b:void 0,w=S?viteArgPort(n):l;S&&k.set(c,{key:t?.LENSMCP_FRONTEND_KEY??`${i??r.root}:${t?.LENSMCP_PROJECT??"app"}`,project:t?.LENSMCP_PROJECT??"app",workspaceRoot:i??r.root,spawnedAt:h,port:w,probeFails:0,listening:!1,generation:Number(t?.LENSMCP_FRONTEND_GENERATION??0),role:t?.LENSMCP_FRONTEND_ROLE==="replacement"?"replacement":"active",...v?{bus:v}:{}});const g=e==="lens-mcp"?"lens-mcp":e==="lens-dashboard"||e.startsWith("lens-dashboard:")?"lens-dashboard":void 0;return g&&w!==void 0&&(p("info",`lens child starting: ${g} (:${w})`,`cluster-lens-child:${g}`,{kind:"lens-child-starting",project:g,label:e,pid:c.pid,port:w},void 0,v),(async()=>{const m=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!r.stopped()&&Date.now()<m;){if(c.exitCode!==null||c.signalCode!==null||$.has(e))return;if(await probePortListening(w,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){p("info",`lens child up: ${g} (:${w})`,`cluster-lens-child:${g}`,{kind:"lens-child-up",project:g,label:e,pid:c.pid,port:w},void 0,v);return}await sleepUnref(150)}})().catch(()=>{})),c.on("exit",(m,Y)=>{const ae=D.indexOf(c);ae>=0&&D.splice(ae,1),N.get(e)===c&&N.delete(e);const T=k.get(c);if(k.delete(c),Z.delete(c))return;const Le=$.delete(e);if(r.stopped()||Le||(g?p("warning",`lens child exited: ${g}`,`cluster-lens-child:${g}`,{kind:"lens-child-exit",project:g,label:e,pid:c.pid,code:m,signal:Y},void 0,v):T&&p("warning",`lens frontend exited: ${T.project}`,`cluster-lens-child:${T.project}`,{kind:"lens-child-exit",project:T.project,label:e,pid:c.pid,code:m,signal:Y,generation:T.generation,port:T.port,ranMs:Date.now()-h},void 0,v),T&&fe(c,T)))return;const ie=Date.now()-h,R=B.get(e)??{attempts:0,portConflicts:0};(async()=>{const Ce=w!==void 0&&!await f(w),le=(0,lifecycle_1.isPortConflictExit)({code:m,signal:Y,ranMs:ie,portHeld:Ce},{fastFailMs:types_1.CHILD_START_FAIL_MS});if(le&&R.portConflicts<types_1.MAX_PORT_CONFLICT_RETRIES)R.portConflicts+=1,B.set(e,R),console.warn(`[gateway] lens child ${e} lost the :${w} bind race (EADDRINUSE, code=${m}); waiting for the port, then retrying (port-retry ${R.portConflicts}/${types_1.MAX_PORT_CONFLICT_RETRIES}; crash budget untouched).`);else if(le){R.portConflicts=0,B.set(e,R),console.warn(`[gateway] lens child ${e}: :${w} persistently held after ${types_1.MAX_PORT_CONFLICT_RETRIES} bind races \u2014 another server owns it (an external/shared daemon?). Parking; re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s, will respawn if it frees.`),p("warning",`lens child parked: ${e} (:${w} held externally)`,`cluster-lens-child:${e}`,{kind:"lens-child-parked",label:e,port:w}),ee(e,w,()=>O(e,s,n,t,o,a,i,l));return}else{R.portConflicts=0,ie>=HEAL_HEALTHY_MS&&(R.attempts=0);const ce=Math.min(HEAL_MAX_MS,HEAL_BASE_MS*2**R.attempts);R.attempts+=1,B.set(e,R),console.warn(`[gateway] lens child ${e} exited (code=${m} sig=${Y}); auto-healing in ${Math.round(ce/1e3)}s (attempt ${R.attempts}).`),await sleepUnref(ce)}r.stopped()||$.has(e)||(w!==void 0&&!await waitForPortFree(w,types_1.PORT_FREE_WAIT_MS,{isPortFree:f,intervalMs:types_1.PORT_FREE_POLL_MS})&&console.warn(`[gateway] lens child ${e}: :${w} still held after ${Math.round(types_1.PORT_FREE_WAIT_MS/1e3)}s \u2014 spawning anyway.`),!(r.stopped()||$.has(e))&&O(e,s,n,t,o,a,i,l))})().catch(()=>{})}),c},"spawnManagedChild"),te=d(e=>{const s=`${e.wsKey}:${e.project}`,n=L.get(s);if(n)return n;const t={key:s,...e,sourceDirs:e.frontend.sourceRoots?.length?e.frontend.sourceRoots:[e.projectRoot],generation:0,state:"starting",generations:new Set,disposed:!1};L.set(s,t);for(const o of e.routes)o.lens&&(o.lens.workspaceKey??=e.wsKey,F.set(o.lens,t));return e.frontend.workspaceKey??=e.wsKey,F.set(e.frontend,t),t},"registerFrontend"),ue=d(e=>{if(!types_1.LENS_WATCH_SCOPE_ENABLED)return{};const s=path.resolve(e.projectRoot),n=e.sourceDirs.map(t=>path.resolve(t)).filter(t=>t!==s);return n.length>0?{LENSMCP_WATCH_DIRS:n.join(path.delimiter)}:{}},"lensWatchScopeEnv"),oe=d((e,s,n)=>{const t=++e.generation,o=`${e.key}:g${t}:`,a=`${o}vite`,i=`${o}browser-capture`;$.delete(a),$.delete(i);const l=d((S,b,v,w,g,m)=>O(S,b,v,w,g,m,e.workspaceRoot),"spawnInRoot"),h=(0,lens_frontend_1.spawnLensFrontend)({projectRoot:e.projectRoot,workspaceRoot:e.workspaceRoot,project:e.project,eventFile:e.eventFile,port:s,chrome:!0,headless:!0,viteEnv:{LENSMCP_PROJECT:e.project,LENSMCP_FRONTEND_KEY:e.key,LENSMCP_FRONTEND_GENERATION:String(t),LENSMCP_FRONTEND_ROLE:n,...ue(e),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false"},labelPrefix:o,log:d(S=>console.log(S),"log")},l),c={ownerKey:e.key,generation:t,port:s,labelPrefix:o,vite:h?.vite??N.get(a),capture:N.get(i)};return e.generations.add(c),c},"spawnFrontendGeneration"),K=d((e,s)=>{if(!e)return;L.get(e.ownerKey)?.generations.delete(e);const n=[[`${e.labelPrefix}browser-capture`,e.capture],[`${e.labelPrefix}vite`,e.vite]];for(const[t,o]of n)$.add(t),o&&H(o);s&&A.delete(e.port)},"terminateGeneration"),Ee=d(async e=>{const s=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!r.stopped()&&Date.now()<s;){const n=e.vite;if(!n||n.exitCode!==null||n.signalCode!==null)return!1;if(await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){const t=await y(e.port);if(!t||t.ready)return!0}await sleepUnref(150)}return!1},"waitForGenerationReady"),U=d(async e=>{const s=e?.vite;return!!(e&&s&&s.exitCode===null&&s.signalCode===null&&await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)))},"generationIsServing"),z=d(e=>!e.disposed&&!r.stopped()&&L.get(e.key)===e,"frontendIsCurrent"),X=d((e,s)=>{if(!z(e))return Promise.resolve(!1);if(e.replacement)return e.replacement;const n=e.active;e.state=n?"replacing":"starting",e.reason=s,e.startedAt=Date.now();const t=(async()=>{let o,a;const i=Date.now();try{const l=new Set;for(const g of L.values())g!==e&&l.add(g.desiredPort);const h=n&&n.port===e.desiredPort?`g${n.generation}`:void 0,c=await x(e.desiredPort,A,{reserved:l,heldBy:h});if(a=c,!z(e))return A.delete(c),!1;o=oe(e,c,"replacement"),e.candidate=o;const S=await U(n);console.log(`[gateway] lens handoff start: ${e.key} g${n?.generation??0}\u2192g${o.generation} :${n?.port??"down"}\u2192:${c} reason=${s}`),p("info",`lens handoff starting: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-start",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,oldPort:n?.port,newPort:c,oldServing:S},void 0,e.eventFile===r.eventFile?void 0:e.eventFile);const b=await Ee(o);if(!z(e))return K(o,!0),e.candidate=void 0,!1;if(!b){K(o,!0),e.candidate=void 0;const g=await U(n);return e.state=g?"ready":"failed",g&&(e.reason=void 0,e.startedAt=void 0),console.error(`[gateway] lens handoff failed: ${e.key} g${o.generation} did not become ready within ${types_1.LENS_REPLACEMENT_READY_MS}ms; ${e.state==="ready"?"old generation kept serving":"no active generation"}.`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,port:c,durationMs:Date.now()-i,oldKept:g},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),!1}for(const g of e.routes)g.target=`http://localhost:${o.port}`,g.lens&&(g.lens.port=o.port);e.frontend.port=o.port,e.active=o,e.candidate=void 0,e.state="ready",e.reason=void 0,e.startedAt=void 0;const v=o.vite?k.get(o.vite):void 0;v&&(v.role="active",v.listening=!0);const w=(0,hmr_reload_1.broadcastFullReload)(r,e.key);if(console.log(`[gateway] lens handoff ready: ${e.key} g${o.generation} :${o.port} in ${Date.now()-i}ms; draining g${n?.generation??0}${w>0?`; reloading ${w} tab(s)`:""}.`),p("info",`lens handoff complete: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-complete",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,oldPort:n?.port,newPort:o.port,durationMs:Date.now()-i,reloadedTabs:w},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),n){const g=`${n.labelPrefix}browser-capture`;$.add(g),n.capture&&H(n.capture),setTimeout(()=>K(n,!0),types_1.LENS_REPLACEMENT_DRAIN_MS).unref?.()}return!0}catch(l){K(o,!0),!o&&a!==void 0&&A.delete(a),e.candidate=void 0;const h=await U(n);e.state=h?"ready":"failed",h&&(e.reason=void 0,e.startedAt=void 0);const c=l.message;return console.error(`[gateway] lens handoff failed: ${e.key}: ${c}`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:s,generation:o?.generation??e.generation,port:o?.port??a,durationMs:Date.now()-i,oldKept:h,error:c},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),!1}finally{e.replacement=void 0}})();return e.replacement=t,t},"rollFrontend"),ne=d((e,s)=>{e.active=oe(e,s,"active"),e.state="starting",e.startedAt=Date.now()},"spawnInitialFrontend"),fe=d((e,s)=>{const n=L.get(s.key);return!n||types_1.LENS_RESTART_MODE==="in-place"?!1:(n.candidate?.vite===e||n.active?.vite!==e||(n.state="starting",n.reason="child-exit",n.startedAt=Date.now(),console.warn(`[gateway] lens frontend exited: ${n.key} g${s.generation} :${s.port} (${describeChildExit(e)}); starting an alternate-port replacement.`),X(n,"child-exit")),!0)},"handleManagedViteExit");r.lensSupervisor=types_1.LENS_RESTART_MODE==="rolling"?{status(e){const s=F.get(e);return s?{state:s.state,generation:s.candidate?.generation??s.active?.generation??s.generation,reason:s.reason,startedAt:s.startedAt}:void 0},recover(e,s){const n=F.get(e);return n?X(n,s):Promise.resolve(!1)}}:void 0;let J=!1,re=0;const he=d(()=>{J||Date.now()-re<types_1.POD_STALE_SCAN_MS||(J=!0,re=Date.now(),(async()=>{for(const e of[...L.values()]){if(r.stopped())return;const s=Date.now(),n=(0,scope_1.readSourceSetOptions)(e.workspaceRoot),t=await(0,lifecycle_1.sourceSetSnapshot)(e.workspaceRoot,e.sourceDirs,n.exclude,{ignoreTests:n.ignoreTests});if(L.get(e.key)!==e)continue;const o=e.sourceSnapshot,a=e.sourceScanStartedAt;if(e.sourceSnapshot=t,e.sourceScanStartedAt=s,!o)continue;const i=Date.now(),l=(0,lifecycle_1.diffSourceSets)(o,t,i,(0,lifecycle_1.sourceChangeWindowMs)(i,a,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS));l&&(e.sourceChange=l,p("info",`source file set changed for ${e.key}`,`cluster-lens-app:${e.project}`,{kind:"source-set-changed",scoped:!0,wsKey:e.wsKey,project:e.project,added:l.added,removed:l.removed,truncated:l.truncated},void 0,e.eventFile===r.eventFile?void 0:e.eventFile))}})().catch(()=>{}).finally(()=>{J=!1}))},"scanFrontendSourceSets");let Q=!1;const ge=d(async(e,s)=>{if(!Q){Q=!0;try{for(const[n,t]of[...k]){if(r.stopped())return;if(t.port===void 0||n.exitCode!==null||n.signalCode!==null)continue;if(await probePortListening(t.port,types_1.LENS_PROBE_TIMEOUT_MS)){if(t.probeFails=0,!t.listening){t.listening=!0;const l=L.get(t.key);l?.active?.vite===n&&(l.state="ready",l.reason=void 0),p("info",`lens app up: ${t.project} (vite :${t.port} listening)`,`cluster-lens-app:${t.project}`,{kind:"service-up",project:t.project,port:t.port},void 0,t.bus)}continue}const o=t.listening?e.graceMs:Math.max(e.graceMs,e.neverListenedGraceMs);if(Date.now()-t.spawnedAt<o){t.probeFails=0;continue}if(!s)continue;t.probeFails+=1;const a=(0,lifecycle_1.lensChildWedged)({spawnedAt:t.spawnedAt,probeFails:t.probeFails,hasListened:t.listening},I.get(t.key)??0,Date.now(),e);if(!a)continue;const i=t.listening?"its listener VANISHED (was up, now refusing)":`it NEVER bound within the ${Math.round(o/1e3)}s boot allowance`;I.set(t.key,Date.now()),t.probeFails=0,t.listening=!1,console.error(`[gateway] wedge recycle: lens app ${t.project} is ALIVE but NOT LISTENING on :${t.port} after ${Math.max(2,e.failureThreshold)} probes \u2014 ${i} \u2014 SIGKILL; a fresh vite is coming.`),p("warning",`wedge recycle: ${t.project} (${a})`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:a,port:t.port},void 0,t.bus);try{n.kill("SIGKILL")}catch{}}}finally{Q=!1}}},"probeLensChildren"),we=d(()=>{if(j||!types_1.POD_RECYCLE_ENABLED&&!types_1.LENS_PROBE_ENABLED)return;const e={graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};j=setInterval(()=>{if(r.stopped()||k.size===0||(se(),!types_1.POD_RECYCLE_ENABLED))return;he();const s=Date.now();for(const[n,t]of k){const o=L.get(t.key),a=o?.sourceChange?.changedAt??0,i=I.get(t.key)??0;(0,lifecycle_1.lensFrontendStale)(t.spawnedAt,i,a,s,e)&&((q.get(t.key)??0)>=a||W.has(t.key)||(W.add(t.key),(async()=>{try{const l=o?.sourceChange,h=l&&!l.truncated?[...l.added,...l.removed].map(v=>path.resolve(t.workspaceRoot,v)):[],c=types_1.LENS_WATCHER_PROBE_ENABLED&&t.port!==void 0?(0,lifecycle_1.lensWatcherVerdict)(await y(t.port),a,l?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,h):"unknown";if(c==="heard"){q.set(t.key,a),console.log(`[gateway] stale source set: lens app ${t.project} watcher CONFIRMED the change \u2014 no recycle, HMR intact.`),p("info",`stale check: ${t.project} watcher confirmed \u2014 no recycle`,`cluster-lens-app:${t.project}`,{kind:"pod-stale-verified",project:t.project},void 0,t.bus);return}if(c==="unknown"&&types_1.LENS_WATCHER_UNVERIFIED==="keep"){console.log(`[gateway] stale source set: lens app ${t.project} unverifiable (no watcher testimony) \u2014 keeping it (LENSMCP_LENS_WATCHER_UNVERIFIED=keep).`);return}if(n.exitCode!==null||n.signalCode!==null)return;I.set(t.key,Date.now());const S=L.get(t.key);if(types_1.LENS_RESTART_MODE==="rolling"&&S){console.log(`[gateway] stale refresh: lens app ${t.key} (stale-source-set) \u2014 watcher ${c==="missed"?"missed the exact path change":"unverifiable"}; preparing a standby without dropping traffic.`),p("warning",`stale refresh: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-refresh",wsKey:S.wsKey,project:t.project,reason:"stale-source-set",watcher:c,added:l?.added,removed:l?.removed},void 0,t.bus),await X(S,"stale-source-set");return}t.listening=!1,console.log(`[gateway] zombie recycle: lens app ${t.project} (stale-source-set) \u2014 watcher ${c==="missed"?"SILENT across the change":"unverifiable"}; restarting it`),p("warning",`zombie recycle: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:"stale-source-set",watcher:c},void 0,t.bus);const b=(0,hmr_reload_1.broadcastFullReload)(r,t.key);b>0&&console.log(`[gateway] \u2192 told ${b} open tab(s) to reload (stale optimize-dep generation)`);try{n.kill("SIGTERM")}catch{}setTimeout(()=>{if(n.exitCode===null&&n.signalCode===null){console.log(`[gateway] zombie recycle: lens app ${t.project} ignored SIGTERM for ${Math.round(types_1.LENS_RECYCLE_KILL_GRACE_MS/1e3)}s \u2014 escalating to SIGKILL.`);try{n.kill("SIGKILL")}catch{}}},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}finally{W.delete(t.key)}})()))}},Math.min(types_1.POD_STALE_SCAN_MS,15e3)),j.unref?.()},"startLensSweeper"),_e=d(async()=>{const e=[...new Map(r.routes.filter(t=>t.lens).map(t=>[t.project,t.lens])).values()],s=u.dashboard!==!1,n=u.mcp!==!1&&e.length>0;if(s){const t=(0,lens_frontend_1.findDashboardBundle)(r.root);if(!t)console.warn("[gateway] lens dashboard bundle not found \u2014 skipping. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/dashboard.js`), or `yarn nx build @lensmcp/lensmcp-mcp` in-repo.");else{const o=(0,scope_1.readLensScope)(r.root),a=await x(u.dashboardPort??o.dashboardPort,V),i=u.lensHost??"lensmcp.local",l=o.basePath;r.registry.appendRoutes(r.wsKey,[{host:i,prefix:l,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),r.rebuildRoutes(),(0,workspace_registry_1.registerWorkspace)({key:o.key,root:r.root,base:l,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] starting lens dashboard \u2192 http://localhost:${a} (routed at https://${i}${l}/)`),p("info",`lens dashboard up: ${i}${l} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:i,port:a,base:l}),O("lens-dashboard",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"dashboard")),[t],{LENSMCP_EVENT_FILE:r.eventFile,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:l,LENSMCP_GATEWAY_PORTS:M},!1,void 0,void 0,a)}}if(n){const t=(0,lens_frontend_1.findMcpBundle)(r.root);if(!t)console.warn("[gateway] MCP server bundle not found \u2014 skipping (lens apps will still publish to the bus; an external `lensmcp mcp` can read it). Install: `npm i -D lensmcp`.");else{const o=(0,scope_1.readLensScope)(r.root),a=Number(process.env.LENSMCP_PORT??o.mcpHttpPort),i=d(()=>{console.log(`[gateway] starting lens MCP server on 127.0.0.1:${a} (${t})`),O("lens-mcp",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"mcp")),[t],{LENSMCP_EVENT_FILE:r.eventFile,LENSMCP_PROCESS_ROLE:"mcp",LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:String(a),LENSMCP_WORKSPACE_KEY:o.key,LENSMCP_WORKSPACE_ROOT:r.root},!1,void 0,void 0,a)},"spawnMcp");await f(a)?i():(console.warn(`[gateway] lens MCP port :${a} is already served \u2014 an external lensmcp server (a shared daemon?) owns this workspace's MCP; not spawning a second. Re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s; will take over if it frees.`),p("info",`lens MCP served externally on :${a} \u2014 gateway parked its own`,"cluster-lens-child:lens-mcp",{kind:"lens-child-up",project:"lens-mcp",label:"lens-mcp",port:a,external:!0}),ee("lens-mcp",a,i))}}for(const t of e){if(t.started)continue;t.started=!0;const o=t.port,a=(r.registry.get(r.wsKey)?.routes??r.routes).filter(h=>h.lens?.project===t.project),i=await x(t.port,A);for(const h of a)h.lens&&(h.lens.port=i),h.target=`http://localhost:${i}`;t.port=i;const l=te({wsKey:r.wsKey,project:t.project,workspaceRoot:r.root,projectRoot:t.projectRoot,eventFile:r.eventFile,routes:a,frontend:t,desiredPort:o});try{ne(l,i),p("info",`lens app started: ${t.project} (vite :${t.port})`,`cluster-lens-app:${t.project}`,{kind:"lens-app-up",project:t.project,port:t.port})}catch(h){A.delete(i),l.state="failed",console.error(`[gateway] lens app ${t.project}: ${h.message}`)}}we()},"bootSingletonsAndApps"),Se=d(async e=>{if(u.dashboard===!1)return;const s=(0,lens_frontend_1.findDashboardBundle)(r.root);if(!s)return;const n=(0,scope_1.readLensScope)(e.root),t=u.lensHost??"lensmcp.local",o=n.basePath,a=await x(n.dashboardPort,V),i=`lens-dashboard:${e.wsKey}`,l=path.join(e.root,".lensmcp","events.jsonl");return $.delete(i),r.registry.appendRoutes(e.wsKey,[{host:t,prefix:o,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),(0,workspace_registry_1.registerWorkspace)({key:e.wsKey,root:e.root,base:o,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] hosting dashboard for workspace '${e.wsKey}' \u2192 http://localhost:${a} (routed at https://${t}${o}/)`),p("info",`lens dashboard up: ${t}${o} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:t,port:a,base:o}),O(i,(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",e.wsKey,"dashboard")),[s],{LENSMCP_EVENT_FILE:l,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:o,LENSMCP_WS_KEY:e.wsKey,LENSMCP_GATEWAY_PORTS:M},!1,void 0,e.root,a),()=>{$.add(i),V.delete(a),(0,workspace_registry_1.unregisterWorkspace)(e.wsKey);const h=N.get(i);h&&H(h),N.delete(i)}},"hostWorkspaceDashboard"),ye=d(async e=>{const s=new Map;for(const o of e.routes){if(!o.lens)continue;const a=s.get(o.lens.project)??[];a.push(o),s.set(o.lens.project,a)}if(s.size===0)return()=>{};const n=path.join(e.root,".lensmcp","events.jsonl"),t=[];for(const[o,a]of s){const i=a[0].lens;if(i.started)continue;const l=await x(i.port,A),h=i.port;for(const S of a)S.lens.started=!0,S.lens.port=l,S.target=`http://localhost:${l}`;const c=te({wsKey:e.wsKey,project:o,workspaceRoot:e.root,projectRoot:i.projectRoot,eventFile:n,routes:a,frontend:i,desiredPort:h});t.push(c),console.log(`[gateway] hosting lens app '${o}' of '${e.wsKey}' \u2192 vite :${l}`);try{ne(c,l),p("info",`lens app started: ${e.wsKey}/${o} (vite :${l})`,`cluster-lens-app:${e.wsKey}:${o}`,{kind:"lens-app-up",project:o,port:l},void 0,n)}catch(S){A.delete(l),c.state="failed",console.error(`[gateway] lens app ${e.wsKey}/${o}: ${S.message}`)}}return()=>{for(const o of t){o.disposed=!0;for(const a of[...o.generations])K(a,!0);for(const a of o.routes)a.lens&&F.delete(a.lens);F.delete(o.frontend),I.delete(o.key),q.delete(o.key),W.delete(o.key),L.delete(o.key)}}},"hostWorkspaceApps"),ve=d(async(e=2500)=>{j&&(clearInterval(j),j=void 0);const s=[...D];for(const o of s)try{o.kill("SIGTERM")}catch{}const n=d(o=>o.exitCode===null&&o.signalCode===null,"alive"),t=Date.now()+e;for(;Date.now()<t&&s.some(n);)await new Promise(o=>setTimeout(o,100));for(const o of s)if(n(o))try{o.kill("SIGKILL")}catch{}},"reapAll"),se=d(()=>ge({graceMs:types_1.LENS_PROBE_GRACE_MS,failureThreshold:types_1.LENS_PROBE_FAILS,cooldownMs:types_1.LENS_PROBE_COOLDOWN_MS,neverListenedGraceMs:types_1.LENS_PROBE_BOOT_GRACE_MS},types_1.LENS_PROBE_ENABLED),"probeLensFrontends");return{spawnManagedChild:O,bootSingletonsAndApps:_e,hostWorkspaceDashboard:Se,hostWorkspaceApps:ye,probeLensFrontends:se,reapAll:ve}}C(createLensChildren,"createLensChildren"),P(createLensChildren,"createLensChildren"),d(createLensChildren,"createLensChildren");
1
+ "use strict";var Re=Object.defineProperty;var P=(r,E)=>Re(r,"name",{value:E,configurable:!0});var Pe=Object.defineProperty,d=P((r,E)=>Pe(r,"name",{value:E,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.probePortFree=probePortFree,exports.probePortListening=probePortListening,exports.probeWatcherHealth=probeWatcherHealth,exports.waitForPortFree=waitForPortFree,exports.viteArgPort=viteArgPort,exports.describeChildExit=describeChildExit,exports.claimPort=claimPort,exports.createLensChildren=createLensChildren;const tslib_1=require("tslib"),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_child_process_1=require("node:child_process"),lens_frontend_1=require("@lensmcp/nx-plugin/lens-frontend"),hmr_reload_1=require("./hmr-reload"),process_name_1=require("../../../process-name"),pod_env_1=require("./pod-env"),scope_1=require("./scope"),workspace_registry_1=require("./workspace-registry"),lifecycle_1=require("./lifecycle"),types_1=require("./types"),observability_1=require("./observability"),HEAL_BASE_MS=1500,HEAL_MAX_MS=3e4,HEAL_HEALTHY_MS=2e4;function tryBind(r,E){return new Promise(u=>{const _=net.createServer();_.unref(),_.once("error",p=>{const f=p.code??"";u(f==="EADDRINUSE"||f==="EACCES"?"in-use":"unavailable")}),_.listen(E===void 0?{port:r}:{port:r,host:E},()=>_.close(()=>u("free")))})}P(tryBind,"tryBind"),d(tryBind,"tryBind");async function probePortFree(r){for(const E of[void 0,"0.0.0.0","127.0.0.1","::1"])if(await tryBind(r,E)==="in-use")return!1;return!0}P(probePortFree,"probePortFree"),d(probePortFree,"probePortFree");function probeConnect(r,E,u){return new Promise(_=>{let p=!1;const f=net.createConnection({host:r,port:E});f.unref();const C=setTimeout(()=>v(!1),u);C.unref?.();function v(O){p||(p=!0,clearTimeout(C),f.destroy(),_(O))}P(v,"P"),d(v,"finish"),f.once("connect",()=>v(!0)),f.once("error",()=>v(!1))})}P(probeConnect,"probeConnect"),d(probeConnect,"probeConnect");async function probePortListening(r,E=1e3){return await probeConnect("127.0.0.1",r,E)?!0:probeConnect("::1",r,E)}P(probePortListening,"probePortListening"),d(probePortListening,"probePortListening");async function probeWatcherHealth(r,E=1500){try{const u=new AbortController,_=setTimeout(()=>u.abort(),E);_.unref?.();try{const p=await fetch(`http://127.0.0.1:${r}/__lensmcp/watcher-health`,{signal:u.signal});if(!p.ok)return null;const f=await p.json();if(typeof f?.lastFsSetEventAt!="number")return null;const C=Array.isArray(f.recentEvents)?f.recentEvents.filter(v=>v&&typeof v.path=="string"&&typeof v.at=="number"&&typeof v.sequence=="number"&&["add","addDir","unlink","unlinkDir"].includes(v.kind)):[];return{schemaVersion:f.schemaVersion===2?2:1,ready:f.ready!==!1,sequence:typeof f.sequence=="number"?f.sequence:0,lastFsSetEventAt:f.lastFsSetEventAt,fsSetEvents:typeof f.fsSetEvents=="number"?f.fsSetEvents:0,recentEvents:C}}finally{clearTimeout(_)}}catch{return null}}P(probeWatcherHealth,"probeWatcherHealth"),d(probeWatcherHealth,"probeWatcherHealth");const sleepUnref=d(r=>new Promise(E=>{setTimeout(E,r).unref?.()}),"sleepUnref");async function waitForPortFree(r,E,u={}){const _=u.isPortFree??probePortFree,p=Math.max(1,u.intervalMs??types_1.PORT_FREE_POLL_MS),f=Date.now()+Math.max(0,E);for(;;){if(await _(r))return!0;const C=f-Date.now();if(C<=0)return!1;await sleepUnref(Math.min(p,C))}}P(waitForPortFree,"waitForPortFree"),d(waitForPortFree,"waitForPortFree");function viteArgPort(r){const E=d(u=>Number.isInteger(u)&&u>0&&u<65536?u:void 0,"valid");for(let u=0;u<r.length;u+=1){const _=r[u];if(_==="--port")return E(Number(r[u+1]));if(_.startsWith("--port="))return E(Number(_.slice(7)))}}P(viteArgPort,"viteArgPort"),d(viteArgPort,"viteArgPort");function describeChildExit(r){return r.signalCode?`killed by ${r.signalCode}`:r.exitCode===null?"exit status unknown":`exit code ${r.exitCode}`}P(describeChildExit,"describeChildExit"),d(describeChildExit,"describeChildExit");async function claimPort(r,E,u,_){let p=r;for(;E.has(p)||_?.has(p)||!await u(p);)p+=1;return E.add(p),p}P(claimPort,"claimPort"),d(claimPort,"claimPort");function createLensChildren(r,E,u,_){const{emit:p}=E,f=_?.isPortFree??probePortFree,C=(u.ports?.length?u.ports:[443]).join(","),v=_?.probeWatcherHealth??probeWatcherHealth,O=[],K=new Map,T=new Map,F=new Map,Y=new Map,B=new Set;let D;const m=new Map,$=new Set,Q=new Set,q=new Set,N=new Set,L=new Map,j=new WeakMap,W=new Set,Z=d((e,s,n)=>{if(W.has(e))return;W.add(e);const t=setInterval(()=>{(async()=>{if(r.stopped()||$.has(e)){clearInterval(t),W.delete(e);return}await f(s)&&(clearInterval(t),W.delete(e),console.log(`[gateway] lens child ${e}: :${s} freed \u2014 respawning.`),n())})().catch(()=>{})},types_1.LENS_PARKED_PORT_REPROBE_MS);t.unref?.()},"parkUntilPortFree"),I=d(async(e,s,n)=>{const t=await claimPort(e,s,f,n?.reserved);return t!==e&&(n?.heldBy?console.log(`[gateway] handoff: :${e} is held by ${n.heldBy} \u2014 replacement on :${t}.`):console.warn(`[gateway] port ${e} is unavailable (another process holds it \u2014 an orphan from a crashed gateway?) \u2014 using ${t} instead.`)),t},"claimFreePort"),ce=d((e,s,n)=>{const t=n?.LENSMCP_FRONTEND_KEY,o=Number(n?.LENSMCP_FRONTEND_GENERATION);if(!t||!Number.isFinite(o))return;const a=[...L.get(t)?.generations??[]].find(i=>i.generation===o);a&&(e.endsWith(":vite")?a.vite=s:e.endsWith(":browser-capture")&&(a.capture=s))},"attachRespawnedGenerationChild"),G=d(e=>{if(!(e.exitCode!==null||e.signalCode!==null)){Q.add(e);try{e.kill("SIGTERM")}catch{}setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{e.kill("SIGKILL")}catch{}},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}},"retireChild"),de=d((e,s)=>{const n=m.get(e);!n||n===s||n.exitCode!==null||n.signalCode!==null||(console.warn(`[gateway] lens child ${e}: a replacement took the label \u2014 retiring the previous child (pid ${n.pid??"?"}).`),G(n))},"retireLabelHolder"),k=d((e,s,n,t,o=!1,a,i,l)=>{const h=Date.now(),c=(0,node_child_process_1.spawn)(s,n,{cwd:i??r.root,env:{...(0,pod_env_1.podBaseEnv)(process.env,r.root,i??r.root),...t??{},LENSMCP_PARENT_PID:String(process.pid)},stdio:"inherit"});O.push(c),de(e,c),m.set(e,c),ce(e,c,t);const S=e==="vite"||e.endsWith(":vite"),M=typeof t?.LENSMCP_EVENT_FILE=="string"?t.LENSMCP_EVENT_FILE:void 0,y=M&&M!==r.eventFile?M:void 0,w=S?viteArgPort(n):l;S&&T.set(c,{key:t?.LENSMCP_FRONTEND_KEY??`${i??r.root}:${t?.LENSMCP_PROJECT??"app"}`,project:t?.LENSMCP_PROJECT??"app",workspaceRoot:i??r.root,spawnedAt:h,port:w,probeFails:0,listening:!1,generation:Number(t?.LENSMCP_FRONTEND_GENERATION??0),role:t?.LENSMCP_FRONTEND_ROLE==="replacement"?"replacement":"active",...y?{bus:y}:{}});const g=e==="lens-mcp"?"lens-mcp":e==="lens-dashboard"||e.startsWith("lens-dashboard:")?"lens-dashboard":void 0;return g&&w!==void 0&&(p("info",`lens child starting: ${g} (:${w})`,`cluster-lens-child:${g}`,{kind:"lens-child-starting",project:g,label:e,pid:c.pid,port:w},void 0,y),(async()=>{const b=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!r.stopped()&&Date.now()<b;){if(c.exitCode!==null||c.signalCode!==null||$.has(e))return;if(await probePortListening(w,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){p("info",`lens child up: ${g} (:${w})`,`cluster-lens-child:${g}`,{kind:"lens-child-up",project:g,label:e,pid:c.pid,port:w},void 0,y);return}await sleepUnref(150)}})().catch(()=>{})),c.on("exit",(b,H)=>{const se=O.indexOf(c);se>=0&&O.splice(se,1),m.get(e)===c&&m.delete(e);const A=T.get(c);if(T.delete(c),Q.delete(c))return;const ve=$.delete(e);if(r.stopped()||ve||(g?p("warning",`lens child exited: ${g}`,`cluster-lens-child:${g}`,{kind:"lens-child-exit",project:g,label:e,pid:c.pid,code:b,signal:H},void 0,y):A&&p("warning",`lens frontend exited: ${A.project}`,`cluster-lens-child:${A.project}`,{kind:"lens-child-exit",project:A.project,label:e,pid:c.pid,code:b,signal:H,generation:A.generation,port:A.port,ranMs:Date.now()-h},void 0,y),A&&Ee(c,A)))return;const ae=Date.now()-h,R=K.get(e)??{attempts:0,portConflicts:0};(async()=>{const Le=w!==void 0&&!await f(w),ie=(0,lifecycle_1.isPortConflictExit)({code:b,signal:H,ranMs:ae,portHeld:Le},{fastFailMs:types_1.CHILD_START_FAIL_MS});if(ie&&R.portConflicts<types_1.MAX_PORT_CONFLICT_RETRIES)R.portConflicts+=1,K.set(e,R),console.warn(`[gateway] lens child ${e} lost the :${w} bind race (EADDRINUSE, code=${b}); waiting for the port, then retrying (port-retry ${R.portConflicts}/${types_1.MAX_PORT_CONFLICT_RETRIES}; crash budget untouched).`);else if(ie){R.portConflicts=0,K.set(e,R),console.warn(`[gateway] lens child ${e}: :${w} persistently held after ${types_1.MAX_PORT_CONFLICT_RETRIES} bind races \u2014 another server owns it (an external/shared daemon?). Parking; re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s, will respawn if it frees.`),p("warning",`lens child parked: ${e} (:${w} held externally)`,`cluster-lens-child:${e}`,{kind:"lens-child-parked",label:e,port:w}),Z(e,w,()=>k(e,s,n,t,o,a,i,l));return}else{R.portConflicts=0,ae>=HEAL_HEALTHY_MS&&(R.attempts=0);const le=Math.min(HEAL_MAX_MS,HEAL_BASE_MS*2**R.attempts);R.attempts+=1,K.set(e,R),console.warn(`[gateway] lens child ${e} exited (code=${b} sig=${H}); auto-healing in ${Math.round(le/1e3)}s (attempt ${R.attempts}).`),await sleepUnref(le)}r.stopped()||$.has(e)||(w!==void 0&&!await waitForPortFree(w,types_1.PORT_FREE_WAIT_MS,{isPortFree:f,intervalMs:types_1.PORT_FREE_POLL_MS})&&console.warn(`[gateway] lens child ${e}: :${w} still held after ${Math.round(types_1.PORT_FREE_WAIT_MS/1e3)}s \u2014 spawning anyway.`),!(r.stopped()||$.has(e))&&k(e,s,n,t,o,a,i,l))})().catch(()=>{})}),c},"spawnManagedChild"),ee=d(e=>{const s=`${e.wsKey}:${e.project}`,n=L.get(s);if(n)return n;const t={key:s,...e,sourceDirs:e.frontend.sourceRoots?.length?e.frontend.sourceRoots:[e.projectRoot],generation:0,state:"starting",generations:new Set,disposed:!1};L.set(s,t);for(const o of e.routes)o.lens&&(o.lens.workspaceKey??=e.wsKey,j.set(o.lens,t));return e.frontend.workspaceKey??=e.wsKey,j.set(e.frontend,t),t},"registerFrontend"),pe=d(e=>{if(!types_1.LENS_WATCH_SCOPE_ENABLED)return{};const s=path.resolve(e.projectRoot),n=e.sourceDirs.map(t=>path.resolve(t)).filter(t=>t!==s);return n.length>0?{LENSMCP_WATCH_DIRS:n.join(path.delimiter)}:{}},"lensWatchScopeEnv"),te=d((e,s,n)=>{const t=++e.generation,o=`${e.key}:g${t}:`,a=`${o}vite`,i=`${o}browser-capture`;$.delete(a),$.delete(i);const l=d((S,M,y,w,g,b)=>k(S,M,y,w,g,b,e.workspaceRoot),"spawnInRoot"),h=(0,lens_frontend_1.spawnLensFrontend)({projectRoot:e.projectRoot,workspaceRoot:e.workspaceRoot,project:e.project,eventFile:e.eventFile,port:s,chrome:!0,headless:!0,viteEnv:{LENSMCP_PROJECT:e.project,LENSMCP_FRONTEND_KEY:e.key,LENSMCP_FRONTEND_GENERATION:String(t),LENSMCP_FRONTEND_ROLE:n,...pe(e),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false"},labelPrefix:o,log:d(S=>console.log(S),"log")},l),c={ownerKey:e.key,generation:t,port:s,labelPrefix:o,vite:h?.vite??m.get(a),capture:m.get(i)};return e.generations.add(c),c},"spawnFrontendGeneration"),x=d((e,s)=>{if(!e)return;L.get(e.ownerKey)?.generations.delete(e);const n=[[`${e.labelPrefix}browser-capture`,e.capture],[`${e.labelPrefix}vite`,e.vite]];for(const[t,o]of n)$.add(t),o&&G(o);s&&N.delete(e.port)},"terminateGeneration"),ue=d(async e=>{const s=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!r.stopped()&&Date.now()<s;){const n=e.vite;if(!n||n.exitCode!==null||n.signalCode!==null)return!1;if(await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){const t=await v(e.port);if(!t||t.ready)return!0}await sleepUnref(150)}return!1},"waitForGenerationReady"),V=d(async e=>{const s=e?.vite;return!!(e&&s&&s.exitCode===null&&s.signalCode===null&&await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)))},"generationIsServing"),U=d(e=>!e.disposed&&!r.stopped()&&L.get(e.key)===e,"frontendIsCurrent"),z=d((e,s)=>{if(!U(e))return Promise.resolve(!1);if(e.replacement)return e.replacement;const n=e.active;e.state=n?"replacing":"starting",e.reason=s,e.startedAt=Date.now();const t=(async()=>{let o,a;const i=Date.now();try{const l=new Set;for(const g of L.values())g!==e&&l.add(g.desiredPort);const h=n&&n.port===e.desiredPort?`g${n.generation}`:void 0,c=await I(e.desiredPort,N,{reserved:l,heldBy:h});if(a=c,!U(e))return N.delete(c),!1;o=te(e,c,"replacement"),e.candidate=o;const S=await V(n);console.log(`[gateway] lens handoff start: ${e.key} g${n?.generation??0}\u2192g${o.generation} :${n?.port??"down"}\u2192:${c} reason=${s}`),p("info",`lens handoff starting: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-start",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,oldPort:n?.port,newPort:c,oldServing:S},void 0,e.eventFile===r.eventFile?void 0:e.eventFile);const M=await ue(o);if(!U(e))return x(o,!0),e.candidate=void 0,!1;if(!M){x(o,!0),e.candidate=void 0;const g=await V(n);return e.state=g?"ready":"failed",g&&(e.reason=void 0,e.startedAt=void 0),console.error(`[gateway] lens handoff failed: ${e.key} g${o.generation} did not become ready within ${types_1.LENS_REPLACEMENT_READY_MS}ms; ${e.state==="ready"?"old generation kept serving":"no active generation"}.`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,port:c,durationMs:Date.now()-i,oldKept:g},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),!1}for(const g of e.routes)g.target=`http://localhost:${o.port}`,g.lens&&(g.lens.port=o.port);e.frontend.port=o.port,e.active=o,e.candidate=void 0,e.state="ready",e.reason=void 0,e.startedAt=void 0;const y=o.vite?T.get(o.vite):void 0;y&&(y.role="active",y.listening=!0);const w=(0,hmr_reload_1.broadcastFullReload)(r,e.key);if(console.log(`[gateway] lens handoff ready: ${e.key} g${o.generation} :${o.port} in ${Date.now()-i}ms; draining g${n?.generation??0}${w>0?`; reloading ${w} tab(s)`:""}.`),p("info",`lens handoff complete: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-complete",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,oldPort:n?.port,newPort:o.port,durationMs:Date.now()-i,reloadedTabs:w},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),n){const g=`${n.labelPrefix}browser-capture`;$.add(g),n.capture&&G(n.capture),setTimeout(()=>x(n,!0),types_1.LENS_REPLACEMENT_DRAIN_MS).unref?.()}return!0}catch(l){x(o,!0),!o&&a!==void 0&&N.delete(a),e.candidate=void 0;const h=await V(n);e.state=h?"ready":"failed",h&&(e.reason=void 0,e.startedAt=void 0);const c=l.message;return console.error(`[gateway] lens handoff failed: ${e.key}: ${c}`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:s,generation:o?.generation??e.generation,port:o?.port??a,durationMs:Date.now()-i,oldKept:h,error:c},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),!1}finally{e.replacement=void 0}})();return e.replacement=t,t},"rollFrontend"),oe=d((e,s)=>{e.active=te(e,s,"active"),e.state="starting",e.startedAt=Date.now()},"spawnInitialFrontend"),Ee=d((e,s)=>{const n=L.get(s.key);return!n||types_1.LENS_RESTART_MODE==="in-place"?!1:(n.candidate?.vite===e||n.active?.vite!==e||(n.state="starting",n.reason="child-exit",n.startedAt=Date.now(),console.warn(`[gateway] lens frontend exited: ${n.key} g${s.generation} :${s.port} (${describeChildExit(e)}); starting an alternate-port replacement.`),z(n,"child-exit")),!0)},"handleManagedViteExit");r.lensSupervisor=types_1.LENS_RESTART_MODE==="rolling"?{status(e){const s=j.get(e);return s?{state:s.state,generation:s.candidate?.generation??s.active?.generation??s.generation,reason:s.reason,startedAt:s.startedAt}:void 0},recover(e,s){const n=j.get(e);return n?z(n,s):Promise.resolve(!1)}}:void 0;let X=!1,ne=0;const fe=d(()=>{X||Date.now()-ne<types_1.POD_STALE_SCAN_MS||(X=!0,ne=Date.now(),(async()=>{for(const e of[...L.values()]){if(r.stopped())return;const s=Date.now(),n=(0,scope_1.readSourceSetOptions)(e.workspaceRoot),t=await(0,lifecycle_1.sourceSetSnapshot)(e.workspaceRoot,e.sourceDirs,n.exclude,{ignoreTests:n.ignoreTests});if(L.get(e.key)!==e)continue;const o=e.sourceSnapshot,a=e.sourceScanStartedAt;if(e.sourceSnapshot=t,e.sourceScanStartedAt=s,!o)continue;const i=Date.now(),l=(0,lifecycle_1.diffSourceSets)(o,t,i,(0,lifecycle_1.sourceChangeWindowMs)(i,a,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS));l&&(e.sourceChange=l,p("info",`source file set changed for ${e.key}`,`cluster-lens-app:${e.project}`,{kind:"source-set-changed",scoped:!0,wsKey:e.wsKey,project:e.project,added:l.added,removed:l.removed,truncated:l.truncated},void 0,e.eventFile===r.eventFile?void 0:e.eventFile))}})().catch(()=>{}).finally(()=>{X=!1}))},"scanFrontendSourceSets");let J=!1;const he=d(async(e,s)=>{if(!J){J=!0;try{for(const[n,t]of[...T]){if(r.stopped())return;if(t.port===void 0||n.exitCode!==null||n.signalCode!==null)continue;if(await probePortListening(t.port,types_1.LENS_PROBE_TIMEOUT_MS)){if(t.probeFails=0,!t.listening){t.listening=!0;const l=L.get(t.key);l?.active?.vite===n&&(l.state="ready",l.reason=void 0),p("info",`lens app up: ${t.project} (vite :${t.port} listening)`,`cluster-lens-app:${t.project}`,{kind:"service-up",project:t.project,port:t.port},void 0,t.bus)}continue}const o=t.listening?e.graceMs:Math.max(e.graceMs,e.neverListenedGraceMs);if(Date.now()-t.spawnedAt<o){t.probeFails=0;continue}if(!s)continue;t.probeFails+=1;const a=(0,lifecycle_1.lensChildWedged)({spawnedAt:t.spawnedAt,probeFails:t.probeFails,hasListened:t.listening},F.get(t.key)??0,Date.now(),e);if(!a)continue;const i=t.listening?"its listener VANISHED (was up, now refusing)":`it NEVER bound within the ${Math.round(o/1e3)}s boot allowance`;F.set(t.key,Date.now()),t.probeFails=0,t.listening=!1,console.error(`[gateway] wedge recycle: lens app ${t.project} is ALIVE but NOT LISTENING on :${t.port} after ${Math.max(2,e.failureThreshold)} probes \u2014 ${i} \u2014 SIGKILL; a fresh vite is coming.`),p("warning",`wedge recycle: ${t.project} (${a})`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:a,port:t.port},void 0,t.bus);try{n.kill("SIGKILL")}catch{}}}finally{J=!1}}},"probeLensChildren"),ge=d(()=>{if(D||!types_1.POD_RECYCLE_ENABLED&&!types_1.LENS_PROBE_ENABLED)return;const e={graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};D=setInterval(()=>{if(r.stopped()||T.size===0||(re(),!types_1.POD_RECYCLE_ENABLED))return;fe();const s=Date.now();for(const[n,t]of T){const o=L.get(t.key),a=o?.sourceChange?.changedAt??0,i=F.get(t.key)??0;(0,lifecycle_1.lensFrontendStale)(t.spawnedAt,i,a,s,e)&&((Y.get(t.key)??0)>=a||B.has(t.key)||(B.add(t.key),(async()=>{try{const l=o?.sourceChange,h=l&&!l.truncated?[...l.added,...l.removed].map(y=>path.resolve(t.workspaceRoot,y)):[],c=types_1.LENS_WATCHER_PROBE_ENABLED&&t.port!==void 0?(0,lifecycle_1.lensWatcherVerdict)(await v(t.port),a,l?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,h):"unknown";if(c==="heard"){Y.set(t.key,a),console.log(`[gateway] stale source set: lens app ${t.project} watcher CONFIRMED the change \u2014 no recycle, HMR intact.`),p("info",`stale check: ${t.project} watcher confirmed \u2014 no recycle`,`cluster-lens-app:${t.project}`,{kind:"pod-stale-verified",project:t.project},void 0,t.bus);return}if(c==="unknown"&&types_1.LENS_WATCHER_UNVERIFIED==="keep"){console.log(`[gateway] stale source set: lens app ${t.project} unverifiable (no watcher testimony) \u2014 keeping it (LENSMCP_LENS_WATCHER_UNVERIFIED=keep).`);return}if(n.exitCode!==null||n.signalCode!==null)return;F.set(t.key,Date.now());const S=L.get(t.key);if(types_1.LENS_RESTART_MODE==="rolling"&&S){console.log(`[gateway] stale refresh: lens app ${t.key} (stale-source-set) \u2014 watcher ${c==="missed"?"missed the exact path change":"unverifiable"}; preparing a standby without dropping traffic.`),p("warning",`stale refresh: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-refresh",wsKey:S.wsKey,project:t.project,reason:"stale-source-set",watcher:c,added:l?.added,removed:l?.removed},void 0,t.bus),await z(S,"stale-source-set");return}t.listening=!1,console.log(`[gateway] zombie recycle: lens app ${t.project} (stale-source-set) \u2014 watcher ${c==="missed"?"SILENT across the change":"unverifiable"}; restarting it`),p("warning",`zombie recycle: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:"stale-source-set",watcher:c},void 0,t.bus);const M=(0,hmr_reload_1.broadcastFullReload)(r,t.key);M>0&&console.log(`[gateway] \u2192 told ${M} open tab(s) to reload (stale optimize-dep generation)`);try{n.kill("SIGTERM")}catch{}setTimeout(()=>{if(n.exitCode===null&&n.signalCode===null){console.log(`[gateway] zombie recycle: lens app ${t.project} ignored SIGTERM for ${Math.round(types_1.LENS_RECYCLE_KILL_GRACE_MS/1e3)}s \u2014 escalating to SIGKILL.`);try{n.kill("SIGKILL")}catch{}}},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}finally{B.delete(t.key)}})()))}},Math.min(types_1.POD_STALE_SCAN_MS,15e3)),D.unref?.()},"startLensSweeper"),we=d(async()=>{const e=[...new Map(r.routes.filter(t=>t.lens).map(t=>[t.project,t.lens])).values()],s=u.dashboard!==!1,n=u.mcp!==!1&&e.length>0;if(s){const t=(0,lens_frontend_1.findDashboardBundle)(r.root);if(!t)console.warn("[gateway] lens dashboard bundle not found \u2014 skipping. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/dashboard.js`), or `yarn nx build @lensmcp/lensmcp-mcp` in-repo.");else{const o=(0,scope_1.readLensScope)(r.root),a=await I(u.dashboardPort??o.dashboardPort,q),i=u.lensHost??"lensmcp.local",l=o.basePath;r.registry.appendRoutes(r.wsKey,[{host:i,prefix:l,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),r.rebuildRoutes(),(0,workspace_registry_1.registerWorkspace)({key:o.key,root:r.root,base:l,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] starting lens dashboard \u2192 http://localhost:${a} (routed at https://${i}${l}/)`),p("info",`lens dashboard up: ${i}${l} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:i,port:a,base:l}),k("lens-dashboard",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"dashboard")),[t],{LENSMCP_EVENT_FILE:r.eventFile,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:l,LENSMCP_GATEWAY_PORTS:C},!1,void 0,void 0,a)}}if(n){const t=(0,lens_frontend_1.findMcpBundle)(r.root);if(!t)console.warn("[gateway] MCP server bundle not found \u2014 skipping (lens apps will still publish to the bus; an external `lensmcp mcp` can read it). Install: `npm i -D lensmcp`.");else{const o=(0,scope_1.readLensScope)(r.root),a=Number(process.env.LENSMCP_PORT??o.mcpHttpPort),i=d(()=>{console.log(`[gateway] starting lens MCP server on 127.0.0.1:${a} (${t})`),k("lens-mcp",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"mcp")),[t],{LENSMCP_EVENT_FILE:r.eventFile,LENSMCP_PROCESS_ROLE:"mcp",LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:String(a),LENSMCP_WORKSPACE_KEY:o.key,LENSMCP_WORKSPACE_ROOT:r.root},!1,void 0,void 0,a)},"spawnMcp");await f(a)?i():(console.warn(`[gateway] lens MCP port :${a} is already served \u2014 an external lensmcp server (a shared daemon?) owns this workspace's MCP; not spawning a second. Re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s; will take over if it frees.`),p("info",`lens MCP served externally on :${a} \u2014 gateway parked its own`,"cluster-lens-child:lens-mcp",{kind:"lens-child-up",project:"lens-mcp",label:"lens-mcp",port:a,external:!0}),Z("lens-mcp",a,i))}}for(const t of e){if(t.started)continue;t.started=!0;const o=t.port,a=(r.registry.get(r.wsKey)?.routes??r.routes).filter(h=>h.lens?.project===t.project),i=await I(t.port,N);for(const h of a)h.lens&&(h.lens.port=i),h.target=`http://localhost:${i}`;t.port=i;const l=ee({wsKey:r.wsKey,project:t.project,workspaceRoot:r.root,projectRoot:t.projectRoot,eventFile:r.eventFile,routes:a,frontend:t,desiredPort:o});try{oe(l,i),p("info",`lens app started: ${t.project} (vite :${t.port})`,`cluster-lens-app:${t.project}`,{kind:"lens-app-up",project:t.project,port:t.port})}catch(h){N.delete(i),l.state="failed",console.error(`[gateway] lens app ${t.project}: ${h.message}`)}}ge()},"bootSingletonsAndApps"),_e=d(async e=>{if(u.dashboard===!1)return;const s=(0,lens_frontend_1.findDashboardBundle)(r.root);if(!s)return;const n=(0,scope_1.readLensScope)(e.root),t=u.lensHost??"lensmcp.local",o=n.basePath,a=await I(n.dashboardPort,q),i=`lens-dashboard:${e.wsKey}`,l=path.join(e.root,".lensmcp","events.jsonl");return $.delete(i),r.registry.appendRoutes(e.wsKey,[{host:t,prefix:o,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),(0,workspace_registry_1.registerWorkspace)({key:e.wsKey,root:e.root,base:o,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] hosting dashboard for workspace '${e.wsKey}' \u2192 http://localhost:${a} (routed at https://${t}${o}/)`),p("info",`lens dashboard up: ${t}${o} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:t,port:a,base:o}),k(i,(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",e.wsKey,"dashboard")),[s],{LENSMCP_EVENT_FILE:l,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:o,LENSMCP_WS_KEY:e.wsKey,LENSMCP_GATEWAY_PORTS:C},!1,void 0,e.root,a),()=>{$.add(i),q.delete(a),(0,workspace_registry_1.unregisterWorkspace)(e.wsKey);const h=m.get(i);h&&G(h),m.delete(i)}},"hostWorkspaceDashboard"),Se=d(async e=>{const s=new Map;for(const o of e.routes){if(!o.lens)continue;const a=s.get(o.lens.project)??[];a.push(o),s.set(o.lens.project,a)}if(s.size===0)return()=>{};const n=path.join(e.root,".lensmcp","events.jsonl"),t=[];for(const[o,a]of s){const i=a[0].lens;if(i.started)continue;const l=await I(i.port,N),h=i.port;for(const S of a)S.lens.started=!0,S.lens.port=l,S.target=`http://localhost:${l}`;const c=ee({wsKey:e.wsKey,project:o,workspaceRoot:e.root,projectRoot:i.projectRoot,eventFile:n,routes:a,frontend:i,desiredPort:h});t.push(c),console.log(`[gateway] hosting lens app '${o}' of '${e.wsKey}' \u2192 vite :${l}`);try{oe(c,l),p("info",`lens app started: ${e.wsKey}/${o} (vite :${l})`,`cluster-lens-app:${e.wsKey}:${o}`,{kind:"lens-app-up",project:o,port:l},void 0,n)}catch(S){N.delete(l),c.state="failed",console.error(`[gateway] lens app ${e.wsKey}/${o}: ${S.message}`)}}return()=>{for(const o of t){o.disposed=!0;for(const a of[...o.generations])x(a,!0);for(const a of o.routes)a.lens&&j.delete(a.lens);j.delete(o.frontend),F.delete(o.key),Y.delete(o.key),B.delete(o.key),L.delete(o.key)}}},"hostWorkspaceApps"),ye=d(async(e=2500)=>{D&&(clearInterval(D),D=void 0);const s=[...O];for(const o of s)try{o.kill("SIGTERM")}catch{}const n=d(o=>o.exitCode===null&&o.signalCode===null,"alive"),t=Date.now()+e;for(;Date.now()<t&&s.some(n);)await new Promise(o=>setTimeout(o,100));for(const o of s)if(n(o))try{o.kill("SIGKILL")}catch{}},"reapAll"),re=d(()=>he({graceMs:types_1.LENS_PROBE_GRACE_MS,failureThreshold:types_1.LENS_PROBE_FAILS,cooldownMs:types_1.LENS_PROBE_COOLDOWN_MS,neverListenedGraceMs:types_1.LENS_PROBE_BOOT_GRACE_MS},types_1.LENS_PROBE_ENABLED),"probeLensFrontends");return{spawnManagedChild:k,bootSingletonsAndApps:we,hostWorkspaceDashboard:_e,hostWorkspaceApps:Se,probeLensFrontends:re,reapAll:ye}}P(createLensChildren,"createLensChildren"),d(createLensChildren,"createLensChildren");
@@ -1,3 +1,3 @@
1
- "use strict";var Se=Object.defineProperty;var y=(t,n)=>Se(t,"name",{value:n,configurable:!0});var ge=Object.defineProperty,v=y((t,n)=>ge(t,"name",{value:n,configurable:!0}),"v"),fe=Object.defineProperty,i=v((t,n)=>fe(t,"name",{value:n,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isTestSourcePath=isTestSourcePath,exports.sourceSetSnapshot=sourceSetSnapshot,exports.sourceSetSignature=sourceSetSignature,exports.diffSourceSets=diffSourceSets,exports.sourceChangeWindowMs=sourceChangeWindowMs,exports.sourceScopeDirs=sourceScopeDirs,exports.podRecycleReason=podRecycleReason,exports.lensFrontendStale=lensFrontendStale,exports.lensWatcherVerdict=lensWatcherVerdict,exports.podWatcherVerdict=podWatcherVerdict,exports.lensChildWedged=lensChildWedged,exports.isPortConflictExit=isPortConflictExit,exports.createServiceLayer=createServiceLayer,exports.chooseStalePodKillTarget=chooseStalePodKillTarget;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),node_crypto_1=require("node:crypto"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),path=tslib_1.__importStar(require("node:path")),node_util_1=require("node:util"),discovery_1=require("./discovery"),scope_1=require("./scope"),pod_env_1=require("./pod-env"),pod_probe_1=require("./pod-probe"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),pod_output_1=require("./pod-output"),types_1=require("./types"),exit_reason_1=require("../../../exit-reason"),process_name_1=require("../../../process-name");function eastWestEnv(t,n){const a={},l=t.serviceKeys[(0,service_keys_1.serviceKeyId)(n.wsKey,n.project)];if(l&&(a.LENSMCP_SERVICE_KEY=l),t.https){const f=require("../../../basic-ssl").caCertPath();fs.existsSync(f)&&(a.NODE_EXTRA_CA_CERTS=f)}return a}y(eastWestEnv,"eastWestEnv"),v(eastWestEnv,"eastWestEnv"),i(eastWestEnv,"eastWestEnv");const sleep=i(t=>new Promise(n=>setTimeout(n,t)),"sleep"),SRC_EXCLUDE=new Set(["node_modules","dist","tmp","coverage","build","out","target"]),SRC_EXT=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".css",".scss",".sass",".less",".json",".html",".htm",".vue",".svelte",".mdx"]),SCAN_FILE_CAP=1e5;function fnv1a(t){let n=2166136261;for(let a=0;a<t.length;a+=1)n^=t.charCodeAt(a),n=Math.imul(n,16777619);return n>>>0}y(fnv1a,"fnv1a"),v(fnv1a,"fnv1a"),i(fnv1a,"fnv1a");const execFileP=(0,node_util_1.promisify)(node_child_process_1.execFile);async function gitIgnoredPaths(t){try{const{stdout:n}=await execFileP("git",["ls-files","--others","--directory","--ignored","--exclude-standard","-z"],{cwd:t,maxBuffer:33554432,timeout:1e4,windowsHide:!0});return new Set(n.split("\0").filter(Boolean))}catch{return new Set}}y(gitIgnoredPaths,"gitIgnoredPaths"),v(gitIgnoredPaths,"gitIgnoredPaths"),i(gitIgnoredPaths,"gitIgnoredPaths");const TEST_FILE_RE=/\.(spec|test|e2e|e2e-spec|stories)\.[cm]?[jt]sx?$/,TEST_DIR_SEGMENTS=new Set(["__tests__","__mocks__","__snapshots__"]);function isTestSourcePath(t){const n=t.split("/"),a=n[n.length-1]??"";if(TEST_FILE_RE.test(a))return!0;for(let l=0;l<n.length-1;l+=1)if(TEST_DIR_SEGMENTS.has(n[l]))return!0;return!1}y(isTestSourcePath,"isTestSourcePath"),v(isTestSourcePath,"isTestSourcePath"),i(isTestSourcePath,"isTestSourcePath");async function sourceSetSnapshot(t,n,a,l){const f=l?.ignoreTests??!0;let S=0,E=0,_=!1;const h=new Set,W=await gitIgnoredPaths(t),g=i(x=>path.relative(t,x).split(path.sep).join("/"),"rel"),R=i(async(x,X=!0)=>{if(S>=SCAN_FILE_CAP){_=!0;return}let P;try{P=await fs.promises.readdir(x,{withFileTypes:!0})}catch{return}for(const G of P){if(S>=SCAN_FILE_CAP){_=!0;return}const b=G.name,B=path.join(x,b);if(G.isDirectory()){if(!X||b.startsWith(".")||SRC_EXCLUDE.has(b)||a?.has(b)||b.endsWith("-devserver")||W.has(`${g(B)}/`))continue;await R(B)}else if(G.isFile()){const H=b.lastIndexOf(".");if(H<=0||!SRC_EXT.has(b.slice(H)))continue;const L=g(B);if(W.has(L)||f&&isTestSourcePath(L)||h.has(L))continue;h.add(L),S+=1,E^=fnv1a(L)}}},"walk");if(n&&n.length>0){await R(t,!1);for(const x of n)await R(x)}else await R(t);return{signature:`${S}:${(E>>>0).toString(36)}`,paths:h,truncated:_}}y(sourceSetSnapshot,"sourceSetSnapshot"),v(sourceSetSnapshot,"sourceSetSnapshot"),i(sourceSetSnapshot,"sourceSetSnapshot");async function sourceSetSignature(t,n,a,l){return(await sourceSetSnapshot(t,n,a,l)).signature}y(sourceSetSignature,"sourceSetSignature"),v(sourceSetSignature,"sourceSetSignature"),i(sourceSetSignature,"sourceSetSignature");const SOURCE_DIFF_PATH_CAP=128;function diffSourceSets(t,n,a,l){if(t.paths.size===n.paths.size){let _=!0;for(const h of t.paths)if(!n.paths.has(h)){_=!1;break}if(_)return null}const f=[],S=[];let E=t.truncated||n.truncated;for(const _ of n.paths)t.paths.has(_)||(f.length+S.length<SOURCE_DIFF_PATH_CAP?f.push(_):E=!0);for(const _ of t.paths)n.paths.has(_)||(f.length+S.length<SOURCE_DIFF_PATH_CAP?S.push(_):E=!0);return{changedAt:a,added:f,removed:S,truncated:E,...l!==void 0?{windowMs:l}:{}}}y(diffSourceSets,"diffSourceSets"),v(diffSourceSets,"diffSourceSets"),i(diffSourceSets,"diffSourceSets");function sourceChangeWindowMs(t,n,a,l){const f=n&&n>0?t-n:a;return Math.max(f,a)+l}y(sourceChangeWindowMs,"sourceChangeWindowMs"),v(sourceChangeWindowMs,"sourceChangeWindowMs"),i(sourceChangeWindowMs,"sourceChangeWindowMs");function sourceScopeDirs(t,n,a,l,f){const S=i(h=>{const W=path.relative(t,h).split(path.sep).filter(Boolean);return W.length===0||W[0].startsWith("..")?"":W[0]},"bucketOf")(n);if(!S)return[];const E=new Set(a.filter(Boolean)),_=new Set([S]);for(const h of l)h.startsWith(".")||SRC_EXCLUDE.has(h)||f?.has(h)||h.endsWith("-devserver")||E.has(h)||_.add(h);return[..._].sort().map(h=>path.join(t,h))}y(sourceScopeDirs,"sourceScopeDirs"),v(sourceScopeDirs,"sourceScopeDirs"),i(sourceScopeDirs,"sourceScopeDirs");function podRecycleReason(t,n,a,l){return!t.proc||t.state!=="up"||t.spawnAt==null||t.inflight>0||(t.activeWork??0)>0||n-t.lastUsed<l.settleMs||t.lastStaleRecycleAt!=null&&n-t.lastStaleRecycleAt<l.cooldownMs?null:a>0&&a-t.spawnAt>l.graceMs?"stale-source-set":l.maxAgeMs>0&&n-t.spawnAt>l.maxAgeMs?"max-age":null}y(podRecycleReason,"podRecycleReason"),v(podRecycleReason,"podRecycleReason"),i(podRecycleReason,"podRecycleReason");function lensFrontendStale(t,n,a,l,f){return!(l-n<f.cooldownMs||a<=0||a-t<=f.graceMs||l-a<f.settleMs)}y(lensFrontendStale,"lensFrontendStale"),v(lensFrontendStale,"lensFrontendStale"),i(lensFrontendStale,"lensFrontendStale");function lensWatcherVerdict(t,n,a,l=[]){if(!t)return"unknown";if("schemaVersion"in t&&t.schemaVersion>=2&&l.length>0){const f=n-a,S=new Set(t.recentEvents.filter(E=>E.at>=f).map(E=>path.resolve(E.path)));return l.every(E=>S.has(path.resolve(E)))?"heard":"missed"}return t.lastFsSetEventAt>=n-a?"heard":"missed"}y(lensWatcherVerdict,"lensWatcherVerdict"),v(lensWatcherVerdict,"lensWatcherVerdict"),i(lensWatcherVerdict,"lensWatcherVerdict");function podWatcherVerdict(t,n,a){if(!t)return"unknown";if(t.degraded)return"degraded";const l=n-a;return t.lastWatchRunAt>=l||t.lastBuildAt>=l?"heard":"silent"}y(podWatcherVerdict,"podWatcherVerdict"),v(podWatcherVerdict,"podWatcherVerdict"),i(podWatcherVerdict,"podWatcherVerdict");function lensChildWedged(t,n,a,l){const f=t.hasListened?l.graceMs:Math.max(l.graceMs,l.neverListenedGraceMs);return a-t.spawnedAt<f||a-n<l.cooldownMs||t.probeFails<Math.max(2,l.failureThreshold)?null:"wedged-no-listener"}y(lensChildWedged,"lensChildWedged"),v(lensChildWedged,"lensChildWedged"),i(lensChildWedged,"lensChildWedged");function isPortConflictExit(t,n){return t.signal||t.code===null||t.code===0||t.ranMs>n.fastFailMs?!1:t.portHeld}y(isPortConflictExit,"isPortConflictExit"),v(isPortConflictExit,"isPortConflictExit"),i(isPortConflictExit,"isPortConflictExit");function createServiceLayer(t,n,a={}){const l=a.spawnProcess??node_child_process_1.spawn,f=a.probeAlive??pod_probe_1.probePodAlive,S=a.killTree??((e,o="SIGTERM")=>{try{process.kill(-e.pid,o)}catch{try{e.kill(o)}catch{}}}),E=a.rollReadyMs??types_1.POD_ROLL_READY_MS,_=a.rollPollMs??750,{emit:h}=n,W=i(e=>e.wsKey===t.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl"),"serviceBus"),g=i((e,o,s,r,c)=>h(o,s,r,{wsKey:e.wsKey,...c},void 0,W(e)),"emitSvc"),R=i(e=>(e.scannedAt=0,(0,discovery_1.pickSock)(e,t.scanTtlMs)?e.socks.length:0),"scanNow"),x=i((e,o)=>{let s;try{s=(0,node_child_process_1.execFileSync)("ps",["ax","-ww","-o","pid=,pgid=,command="],{encoding:"utf8",timeout:5e3})}catch{return 0}const r=e.proc?.pid;let c=0;for(const d of s.split(`
2
- `)){const u=d.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!u)continue;const m=Number(u[1]),I=Number(u[2]),k=u[3];if(k.includes(`run ${o}`)&&/\bnx(\.js)?\b/.test(k)&&!(k.includes("/node_modules/nx/")&&!k.includes(e.root))&&!(m===process.pid||m===r)&&!(r!==void 0&&I===r)){try{process.kill(-I,"SIGKILL")}catch{try{process.kill(m,"SIGKILL")}catch{}}c+=1}}return c>0&&(console.log(`[gateway] ${o}: reaped ${c} stale runner tree(s) \u2014 a foreign generation held the nx task lock`),g(e,"warning",`stale-runner reap: ${e.project} (${c} foreign tree(s))`,`cluster-service:${e.project}`,{kind:"stale-runner-reap",project:e.project,reaped:c})),c},"reapForeignRunners"),X=i((e,o,s)=>{const r=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,c=Math.max(1,e.decl.minPods??1),d=path.join(e.root,"node_modules","nx","dist","bin","nx.js"),u=(0,process_name_1.namedExecPath)((0,process_name_1.processName)(e.wsKey||path.basename(e.root),e.project,"nx")),[m,I]=fs.existsSync(d)?[u,[d,"run",r,`--childCount=${c}`]]:["yarn",["nx","run",r,`--childCount=${c}`]],k=l(m,I,{cwd:e.root,detached:!0,env:{...(0,pod_env_1.podBaseEnv)(process.env,t.root,e.root),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false",...e.wsKey?{LENSMCP_WS_KEY:e.wsKey}:{},LENSMCP_EVENT_FILE:e.wsKey===t.wsKey?t.eventFile:path.join(e.root,".lensmcp","events.jsonl"),LENSMCP_GATEWAY_PID:String(process.pid),LENSMCP_POD_GENERATION:String(o),...eastWestEnv(t,e)},stdio:["ignore","pipe","pipe"]});s==="active"&&(e.lastErrors=[],e.buildFailed=!1,e.faults=new pod_output_1.PodFaults);const D=i(w=>{const j=w.toString();for(const K of j.split(`
3
- `)){const p=(0,pod_output_1.classifyPodLine)(K),{clean:$,broken:A,healthy:T}=p,J=$;if(A){e.lastErrors.push($),e.lastErrors.length>12&&e.lastErrors.shift(),e.buildFailed=!0;const C=Date.now();($!==e.lastErrorEmitSig||C-(e.lastErrorEmitAt??0)>=types_1.SERVICE_ERROR_THROTTLE_MS)&&(e.lastErrorEmitSig=$,e.lastErrorEmitAt=C,g(e,"error",`service error: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-error",project:e.project,line:$,fault:p.fault}))}T&&(e.buildFailed=!1);const O=(e.faults??=new pod_output_1.PodFaults).observe(p);if(O){e.lastErrorEmitSig=void 0;const C=O.open.length===0;g(e,"info",`${C?"service recovered":`${O.closed.join(" + ")} recovered`}: ${e.project}`,`cluster-service:${e.project}`,{kind:C?"service-recovered":"service-fault-closed",project:e.project,line:$,closed:O.closed,open:O.open})}!e.lockBlockedAt&&/Waiting for .+ in another nx process/.test(J)&&(e.lockBlockedAt=Date.now(),console.log(`[gateway] ${r}: spawn blocked by a stale nx runner \u2014 breaking the lock + respawning`),g(e,"warning",`nx task lock: ${e.project} blocked by a stale runner \u2014 auto-breaking`,`cluster-service:${e.project}`,{kind:"nx-lock-break",project:e.project}),setTimeout(()=>{t.stopped()||!e.lockBlockedAt||(N(e,"parked on a foreign nx task lock \u2014 recycling",{announce:!1}),x(e,r),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&P(e)},1500).unref?.())},250).unref?.())}},"sniff"),M=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0;return k.stdout?.on("data",w=>{if(t.stopped())return;D(w);const j=`[${e.project}] ${w}`;process.stdout.write(j),M?.(j)}),k.stderr?.on("data",w=>{if(t.stopped())return;D(w);const j=`[${e.project}] ${w}`;process.stderr.write(j),M?.(j)}),k.on("exit",(w,j)=>{if(e.proc!==k||(e.proc=void 0,e.state="down",t.stopped()))return;const K=(0,exit_reason_1.describeExit)(w,j);if(console.log(`[gateway] ${r} exited (${w??"no code"}${j?`, ${j}`:""}${e.inflight?`, ${e.inflight} request(s) in flight`:""})${K?` \u2014 ${K}`:""}`),g(e,w===0?"info":"warning",`service down: ${e.project} (exit ${w})`,`cluster-service:${e.project}`,{kind:"service-down",project:e.project,code:w,...j?{signal:j}:{}}),w===0||e.buildFailed)return;const p=Date.now();if(e.restarts=(e.restarts??[]).filter(A=>p-A<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){g(e,"error",`service crash-looping: ${e.project} \u2014 ${types_1.SERVICE_MAX_RESTARTS}+ restarts/min, not auto-respawning (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project});return}e.restarts.push(p);const $=Math.min(8e3,500*2**(e.restarts.length-1));setTimeout(()=>{t.stopped()||e.proc||e.state!=="down"||(console.log(`[gateway] self-heal: respawning ${e.project} (restart ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS})`),g(e,"info",`self-heal: respawning ${e.project}`,`cluster-service:${e.project}`,{kind:"service-respawn",project:e.project,attempt:e.restarts.length}),P(e))},$)}),k},"launchServiceProcess"),P=i(e=>{if(t.stopped())return;const o=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,s=Math.max(1,e.decl.minPods??1);a.reapForeign!==!1&&x(e,o),e.lockBlockedAt=void 0,console.log(`[gateway] starting ${o} (pods=${s})\u2026`),g(e,"info",`service starting: ${e.project} (${s} pod${s>1?"s":""})`,`cluster-service:${e.project}`,{kind:"service-starting",project:e.project,pods:s}),e.state="starting",e.spawnAt=Date.now(),e.generation=(e.generation??0)+1,e.proc=X(e,e.generation,"active")},"spawnService"),G=i(async e=>{const o=e.pool.socks[0];if(!o)return;const s=await(0,pod_probe_1.probePodAlive)(o,void 0,t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)]);s&&(e.activeWork=s.activeWork,s.watcher&&(e.watcher=s.watcher))},"refreshActiveWork"),b=i(e=>{try{const o=Number(fs.readFileSync(`${e}.owner`,"utf8").trim());return Number.isInteger(o)&&o>1?o:void 0}catch{return}},"readOwnerSidecar"),B=i(async e=>{const o=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];if(!o)return[];const s=(0,node_crypto_1.createHash)("sha256").update(o).digest("hex").slice(0,8),r=[];for(const c of e.pool.socks){const d=await(0,pod_probe_1.probePodAlive)(c,void 0,o);d&&(!d.keyFingerprint||d.keyFingerprint!==s)&&r.push({sock:c,pid:d.pid})}return r},"staleAdoptedSocks"),H=i((e,o)=>{const s=o.map(r=>r.sock);for(const{sock:r,pid:c}of o){const d=chooseStalePodKillTarget(c,b(r),process.pid);if(d!==void 0)try{process.kill(d,"SIGTERM")}catch{}try{fs.unlinkSync(r)}catch{}try{fs.unlinkSync(`${r}.owner`)}catch{}}e.pool.socks=e.pool.socks.filter(r=>!s.includes(r)),e.pool.idx=-1,e.pool.scannedAt=0},"evictStaleAdopted"),L=i((e,o)=>{if(e.state==="up")return!1;e.state="up";const s=e.pool.socks.length;return g(e,"info",`service up: ${e.project} (${s} pods, ${o})`,`cluster-service:${e.project}`,{kind:"service-up",project:e.project,pods:s,adopted:o==="adopted"}),!0},"markUp"),se=i(async e=>{if(R(e.pool)>0){const r=await B(e);if(r.length>0&&(console.error(`[gateway] ${e.project}: ${r.length} adopted pod(s) hold a foreign east-west key \u2014 evicting instead of adopting.`),g(e,"warning",`stale adoption: ${e.project} (foreign east-west key)`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:"stale-adoption",pods:r.length}),e.proc&&N(e,"stale adoption (foreign east-west key)"),H(e,r)),e.pool.socks.length>0)return L(e,"adopted"),!0}if(t.stopped())return!1;e.state!=="starting"&&!e.proc&&P(e);const o=Date.now()+t.startupTimeoutMs,s=Date.now()+12e3;for(;!t.stopped()&&Date.now()<o;){if(await sleep(Math.min(700,t.startupTimeoutMs/4)),e.buildFailed&&Date.now()>s)return!1;if(R(e.pool)>0){e.state="up",e.buildFailed=!1;const r=e.spawnAt?Date.now()-e.spawnAt:void 0;return console.log(`[gateway] ${e.project} up (${e.pool.socks.length} pods${r?`, cold start ${r}ms`:""})`),g(e,"info",`cold start: ${e.project} (${e.pool.socks.length} pods, ${r??"?"}ms)`,`cluster-service:${e.project}`,{kind:"cold-start",project:e.project,pods:e.pool.socks.length,durationMs:r}),!0}if(e.state==="down")return!1}return!1},"ensureUp"),ne=i(e=>{const o=e.decl.maxPods??e.decl.minPods??1,s=e.pool.socks.length,r=e.decl.adminUrl??(e.decl.port?`http://localhost:${e.decl.port}`:void 0);if(!r||s===0||s>=o||e.inflight<=s||Date.now()-e.lastScaleAt<5e3)return;e.lastScaleAt=Date.now();const c=(r.startsWith("https")?require("node:https"):http).request(`${r}/webpack/scale`,{method:"POST",rejectUnauthorized:!1},d=>d.resume());c.on("error",()=>{}),c.end(JSON.stringify({pods:s+1})),console.log(`[gateway] autoscale ${e.project}: ${s} \u2192 ${s+1} pods (inflight ${e.inflight})`),g(e,"info",`autoscale: ${e.project} ${s} \u2192 ${s+1} pods`,`cluster-service:${e.project}`,{kind:"autoscale",project:e.project,from:s,to:s+1,inflight:e.inflight})},"scaleUp"),N=i((e,o,s)=>{if(!e.proc)return;console.log(`[gateway] ${e.project} ${o} \u2014 scaling to zero.`),s?.announce!==!1&&g(e,"info",`idle kill: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"idle-kill",project:e.project,why:o});const r=e.proc;try{r.stdout?.removeAllListeners("data"),r.stderr?.removeAllListeners("data"),r.removeAllListeners("exit")}catch{}S(r,"SIGTERM"),e.proc=void 0,e.state="down",setTimeout(()=>{Q(e),e.pool.socks=[],e.pool.scannedAt=0},1200).unref?.()},"killSpawned"),Q=i(e=>{try{for(const o of fs.readdirSync(e.pool.dir)){if(!o.endsWith(".sock"))continue;const s=path.join(e.pool.dir,o);try{const r=Number(fs.readFileSync(`${s}.owner`,"utf8").trim());if(Number.isFinite(r)&&r>0)try{process.kill(r,0);continue}catch{}}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(`${s}.owner`)}catch{}}}catch{}},"sweepDeadOwnerSocks"),oe=i((e,o)=>{if(e.rolling)return e.rolling;const s=e.proc;if(!s||t.stopped())return Promise.resolve(!1);const r=e.generation??0,c=r+1,d=Date.now();e.lastStaleRecycleAt=d,console.log(`[gateway] pod handoff start: ${e.project} g${r}\u2192g${c} reason=${o} \u2014 standby spawning, old generation keeps serving.`),g(e,"info",`pod handoff starting: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"pod-handoff-start",project:e.project,reason:o,generation:c,fromGeneration:r});const u=X(e,c,"standby"),m=(async()=>{const I=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],k=d+E;let D;for(;!t.stopped()&&Date.now()<k&&!(u.exitCode!==null||u.signalCode!==null);){R(e.pool);for(const M of e.pool.socks)if((await f(M,void 0,I))?.podGeneration===c){D=M;break}if(D)break;await sleep(_)}if(!D||t.stopped()){const M=t.stopped()?"gateway stopping":u.exitCode!==null||u.signalCode!==null?`standby exited (${u.exitCode??u.signalCode})`:`standby not ready within ${Math.round(E/1e3)}s`;try{u.stdout?.removeAllListeners("data"),u.stderr?.removeAllListeners("data")}catch{}return S(u,"SIGTERM"),console.error(`[gateway] pod handoff failed: ${e.project} g${c}: ${M} \u2014 old generation g${r} kept serving.`),g(e,"warning",`pod handoff failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-failed",project:e.project,reason:o,generation:c,error:M,durationMs:Date.now()-d}),setTimeout(()=>Q(e),1200).unref?.(),!1}if(e.proc!==s)return S(u,"SIGTERM"),!1;e.proc=u,e.generation=c,e.spawnAt=d,e.state="up",e.watcher=void 0,e.staleVerifiedAt=void 0,e.staleKeptAt=void 0,e.buildFailed=!1,e.lastErrors=[];try{s.stdout?.removeAllListeners("data"),s.stderr?.removeAllListeners("data"),s.removeAllListeners("exit")}catch{}return S(s,"SIGTERM"),setTimeout(()=>{Q(e),e.pool.scannedAt=0},1200).unref?.(),console.log(`[gateway] pod handoff ready: ${e.project} g${c} answered on ${path.basename(D)} in ${Date.now()-d}ms; retiring g${r}.`),g(e,"info",`pod handoff complete: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-complete",project:e.project,reason:o,generation:c,fromGeneration:r,durationMs:Date.now()-d}),!0})().finally(()=>{e.rolling=void 0});return e.rolling=m,m},"rollPod"),ce=i(e=>{const o=Date.now();if(e.restarts=(e.restarts??[]).filter(s=>o-s<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){g(e,"error",`service crash-looping: ${e.project} \u2014 wedged ${types_1.SERVICE_MAX_RESTARTS}+\xD7/min, not auto-recycling (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project}),N(e,"wedged (crash-loop cap) \u2014 leaving down for the next request",{announce:!1});return}e.restarts.push(o),console.log(`[gateway] self-heal: recycling WEDGED ${e.project} (live parent, 0 live pods; ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS}; ${e.inflight??0} request(s) in flight \u2014 jobs held by the dead pod keep their locks until they expire)`),g(e,"warning",`self-heal: recycling wedged ${e.project} (0 live pods)`,`cluster-service:${e.project}`,{kind:"service-recycle",project:e.project,attempt:e.restarts.length}),N(e,"wedged: 0 live pods \u2014 recycling",{announce:!1}),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&P(e)},1500).unref?.()},"recycleWedged"),ie={maxAgeMs:types_1.POD_MAX_AGE_MS,graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};let Z;const U=new Map,re=new Map;let ee=!1,te=0,z=0;const ae=i(()=>{const e=t.projectRoots??{},o=new Set(t.services.map(r=>r.project));for(const r of t.routes)r.lens&&o.add(r.lens.project);const s=new Set;for(const r of o){const c=e[r];if(!c)continue;const d=path.relative(t.root,c).split(path.sep).filter(Boolean)[0];d&&!d.startsWith("..")&&s.add(d)}return[...s]},"managedBuckets"),le=i((e,o,s,r)=>{const c=t.projectSourceRoots?.[e];if(c?.length)return c;const d=t.projectRoots?.[e];if(!d)return;const u=sourceScopeDirs(t.root,d,s,o,r);return u.length>0?u:void 0},"scopeFor"),de=i(()=>{if(ee||Date.now()-te<types_1.POD_STALE_SCAN_MS)return;ee=!0,te=Date.now();const e=te;(async()=>{const o=(0,scope_1.readSourceSetOptions)(t.root),s=o.exclude,r={ignoreTests:o.ignoreTests},c=await sourceSetSnapshot(t.root,void 0,s,r),d=Date.now(),u=sourceChangeWindowMs(d,z,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS),m=Z?diffSourceSets(Z,c,d,u):null;if(m&&(t.sourceSetChangedAt=d,t.sourceSetChange=m,h("info","source file set changed \u2014 stale pods recycle when idle","cluster-gateway",{kind:"source-set-changed",added:m.added,removed:m.removed,truncated:m.truncated})),Z=c,!t.projectRoots){z=e;return}let I;try{I=(await fs.promises.readdir(t.root,{withFileTypes:!0})).filter(p=>p.isDirectory()).map(p=>p.name)}catch{return}const k=ae(),D=new Set(t.services.map(p=>p.project));for(const p of t.routes)p.lens&&D.add(p.lens.project);const M=new Map;for(const p of D){const $=le(p,I,k,s);if(!$)continue;const A=$.join("|"),T=M.get(A)??{dirs:$,projects:[]};T.projects.push(p),M.set(A,T)}const w=Date.now(),j=sourceChangeWindowMs(w,z,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS);z=e;const K=i((p,$,A)=>{t.sourceSetChangedFor??=new Map,t.sourceSetChangesFor??=new Map;for(const T of p)t.sourceSetChangedFor.set(T,$),t.sourceSetChangesFor.set(T,A)},"stampScoped");for(const[p,{dirs:$,projects:A}]of M){const T=await sourceSetSnapshot(t.root,$,s,r),J=U.get(p);U.set(p,T);const O=new Map;for(const q of A){const F=re.get(q);if(F===void 0||F===p)continue;const V=O.get(F)??[];V.push(q),O.set(F,V)}for(const q of A)re.set(q,p);for(const[q,F]of O){const V=U.get(q),Y=V?diffSourceSets(V,T,w,j):m;Y&&(K(F,V?w:d,Y),h("info",`source file set changed \u2014 ${F.join(", ")}'s watch scope was re-keyed`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,rescoped:!0,projects:F,added:Y.added,removed:Y.removed,truncated:Y.truncated}))}if(!J)continue;const C=diffSourceSets(J,T,w,j);C&&(K(A,w,C),h("info",`source file set changed in ${A.join(", ")}'s scope`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,projects:A,added:C.added,removed:C.removed,truncated:C.truncated}))}for(const p of[...U.keys()])M.has(p)||U.delete(p)})().catch(()=>{}).finally(()=>{ee=!1})},"maybeScanSourceSet"),pe=i((e,o)=>{const s=(t.sourceSetChangesFor?.get(e.project)??t.sourceSetChange)?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,r=podWatcherVerdict(e.watcher,o,s),c=i(d=>(e.staleKeptAt!==o&&(e.staleKeptAt=o,console.log(`[gateway] stale source set: pod ${e.project} ${d} \u2014 no recycle.`)),!1),"keep");return r==="heard"?(e.staleVerifiedAt=o,g(e,"info",`stale check: ${e.project} watcher confirmed \u2014 no recycle`,`cluster-service:${e.project}`,{kind:"pod-stale-verified",project:e.project,watcher:r}),c(`watcher CONFIRMED alive across the change (last build ${new Date(e.watcher?.lastBuildAt??0).toISOString()})`)):r==="degraded"?(console.log(`[gateway] stale source set: pod ${e.project} watcher DEGRADED (${e.watcher?.degraded}) \u2014 recycling.`),!0):r==="silent"?types_1.POD_WATCHER_SILENT==="keep"?c("watcher alive but quiet across the change \u2014 keeping it (LENSMCP_POD_WATCHER_SILENT=keep; a live watcher cannot miss an add it will need)"):!0:types_1.POD_WATCHER_UNVERIFIED==="keep"?c("unverifiable (no watcher testimony \u2014 older devserver bundle?) \u2014 keeping it (LENSMCP_POD_WATCHER_UNVERIFIED=keep)"):!0},"podStaleRecycleAllowed"),ue=i((e,o)=>{if(e.lastStaleRecycleAt=Date.now(),types_1.POD_RECYCLE_MODE==="rolling"&&e.proc){oe(e,o);return}console.log(`[gateway] zombie recycle: ${e.project} (${o}) \u2014 stale fs view; fresh pod incoming`),g(e,"warning",`zombie recycle: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:o});const s=!!e.decl.eager;N(e,`${o} \u2014 recycling stale pod`,{announce:!1}),s&&setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&P(e)},1500).unref?.()},"recyclePod"),he=i(()=>{const e=setInterval(()=>{we().catch(o=>console.error("[gateway] sweep error:",o))},t.sweepMs);return e.unref(),e},"startSweeper"),we=i(async()=>{{if(t.stopped())return;types_1.POD_RECYCLE_ENABLED&&de();for(const e of t.services){if(t.stopped()||!e.proc){e.wedgedSince=void 0;continue}const o=e.decl.idleKillSec;if(o&&e.inflight===0&&Date.now()-e.lastUsed>o*1e3){N(e,`idle ${o}s`),e.wedgedSince=void 0;continue}const s=e.state==="starting"&&e.spawnAt!==void 0&&Date.now()-e.spawnAt<t.startupTimeoutMs,r=R(e.pool)>0;if(r||s){if(e.wedgedSince=void 0,r&&L(e,"observed"),r&&!s&&types_1.POD_RECYCLE_ENABLED){const c=t.sourceSetChangedFor?.get(e.project)??t.sourceSetChangedAt??0;await G(e);const d=(e.staleVerifiedAt??0)>=c&&c>0,u=podRecycleReason(e,Date.now(),d?0:c,ie);if(u==="stale-source-set"&&!pe(e,c))continue;u&&ue(e,u)}continue}e.wedgedSince??=Date.now(),Date.now()-e.wedgedSince>types_1.WEDGE_RECYCLE_GRACE_MS&&(e.wedgedSince=void 0,ce(e))}}},"sweepOnce");return{scanNow:R,spawnService:P,ensureUp:se,scaleUp:ne,killSpawned:N,markUp:L,startSweeper:he,rollPod:oe}}y(createServiceLayer,"createServiceLayer"),v(createServiceLayer,"createServiceLayer"),i(createServiceLayer,"createServiceLayer");function chooseStalePodKillTarget(t,n,a){if(!(t===void 0||!Number.isInteger(t)||t<=1)&&!(n!==void 0&&n!==t)&&t!==a)return t}y(chooseStalePodKillTarget,"chooseStalePodKillTarget"),v(chooseStalePodKillTarget,"chooseStalePodKillTarget"),i(chooseStalePodKillTarget,"chooseStalePodKillTarget");
1
+ "use strict";var ge=Object.defineProperty;var v=(t,n)=>ge(t,"name",{value:n,configurable:!0});var fe=Object.defineProperty,i=v((t,n)=>fe(t,"name",{value:n,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isTestSourcePath=isTestSourcePath,exports.sourceSetSnapshot=sourceSetSnapshot,exports.sourceSetSignature=sourceSetSignature,exports.diffSourceSets=diffSourceSets,exports.sourceChangeWindowMs=sourceChangeWindowMs,exports.sourceScopeDirs=sourceScopeDirs,exports.podRecycleReason=podRecycleReason,exports.lensFrontendStale=lensFrontendStale,exports.lensWatcherVerdict=lensWatcherVerdict,exports.podWatcherVerdict=podWatcherVerdict,exports.lensChildWedged=lensChildWedged,exports.isPortConflictExit=isPortConflictExit,exports.createServiceLayer=createServiceLayer,exports.chooseStalePodKillTarget=chooseStalePodKillTarget;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),node_crypto_1=require("node:crypto"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),path=tslib_1.__importStar(require("node:path")),node_util_1=require("node:util"),discovery_1=require("./discovery"),scope_1=require("./scope"),pod_env_1=require("./pod-env"),pod_probe_1=require("./pod-probe"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),pod_output_1=require("./pod-output"),types_1=require("./types"),exit_reason_1=require("../../../exit-reason"),process_name_1=require("../../../process-name");function eastWestEnv(t,n){const a={},l=t.serviceKeys[(0,service_keys_1.serviceKeyId)(n.wsKey,n.project)];if(l&&(a.LENSMCP_SERVICE_KEY=l),t.https){const f=require("../../../basic-ssl").caCertPath();fs.existsSync(f)&&(a.NODE_EXTRA_CA_CERTS=f)}return a}v(eastWestEnv,"eastWestEnv"),i(eastWestEnv,"eastWestEnv");const sleep=i(t=>new Promise(n=>setTimeout(n,t)),"sleep"),SRC_EXCLUDE=new Set(["node_modules","dist","tmp","coverage","build","out","target"]),SRC_EXT=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".css",".scss",".sass",".less",".json",".html",".htm",".vue",".svelte",".mdx"]),SCAN_FILE_CAP=1e5;function fnv1a(t){let n=2166136261;for(let a=0;a<t.length;a+=1)n^=t.charCodeAt(a),n=Math.imul(n,16777619);return n>>>0}v(fnv1a,"fnv1a"),i(fnv1a,"fnv1a");const execFileP=(0,node_util_1.promisify)(node_child_process_1.execFile);async function gitIgnoredPaths(t){try{const{stdout:n}=await execFileP("git",["ls-files","--others","--directory","--ignored","--exclude-standard","-z"],{cwd:t,maxBuffer:33554432,timeout:1e4,windowsHide:!0});return new Set(n.split("\0").filter(Boolean))}catch{return new Set}}v(gitIgnoredPaths,"gitIgnoredPaths"),i(gitIgnoredPaths,"gitIgnoredPaths");const TEST_FILE_RE=/\.(spec|test|e2e|e2e-spec|stories)\.[cm]?[jt]sx?$/,TEST_DIR_SEGMENTS=new Set(["__tests__","__mocks__","__snapshots__"]);function isTestSourcePath(t){const n=t.split("/"),a=n[n.length-1]??"";if(TEST_FILE_RE.test(a))return!0;for(let l=0;l<n.length-1;l+=1)if(TEST_DIR_SEGMENTS.has(n[l]))return!0;return!1}v(isTestSourcePath,"isTestSourcePath"),i(isTestSourcePath,"isTestSourcePath");async function sourceSetSnapshot(t,n,a,l){const f=l?.ignoreTests??!0;let S=0,y=0,E=!1;const g=new Set,O=await gitIgnoredPaths(t),h=i(D=>path.relative(t,D).split(path.sep).join("/"),"rel"),C=i(async(D,X=!0)=>{if(S>=SCAN_FILE_CAP){E=!0;return}let x;try{x=await fs.promises.readdir(D,{withFileTypes:!0})}catch{return}for(const V of x){if(S>=SCAN_FILE_CAP){E=!0;return}const P=V.name,G=path.join(D,P);if(V.isDirectory()){if(!X||P.startsWith(".")||SRC_EXCLUDE.has(P)||a?.has(P)||P.endsWith("-devserver")||O.has(`${h(G)}/`))continue;await C(G)}else if(V.isFile()){const Y=P.lastIndexOf(".");if(Y<=0||!SRC_EXT.has(P.slice(Y)))continue;const b=h(G);if(O.has(b)||f&&isTestSourcePath(b)||g.has(b))continue;g.add(b),S+=1,y^=fnv1a(b)}}},"walk");if(n&&n.length>0){await C(t,!1);for(const D of n)await C(D)}else await C(t);return{signature:`${S}:${(y>>>0).toString(36)}`,paths:g,truncated:E}}v(sourceSetSnapshot,"sourceSetSnapshot"),i(sourceSetSnapshot,"sourceSetSnapshot");async function sourceSetSignature(t,n,a,l){return(await sourceSetSnapshot(t,n,a,l)).signature}v(sourceSetSignature,"sourceSetSignature"),i(sourceSetSignature,"sourceSetSignature");const SOURCE_DIFF_PATH_CAP=128;function diffSourceSets(t,n,a,l){if(t.paths.size===n.paths.size){let E=!0;for(const g of t.paths)if(!n.paths.has(g)){E=!1;break}if(E)return null}const f=[],S=[];let y=t.truncated||n.truncated;for(const E of n.paths)t.paths.has(E)||(f.length+S.length<SOURCE_DIFF_PATH_CAP?f.push(E):y=!0);for(const E of t.paths)n.paths.has(E)||(f.length+S.length<SOURCE_DIFF_PATH_CAP?S.push(E):y=!0);return{changedAt:a,added:f,removed:S,truncated:y,...l!==void 0?{windowMs:l}:{}}}v(diffSourceSets,"diffSourceSets"),i(diffSourceSets,"diffSourceSets");function sourceChangeWindowMs(t,n,a,l){const f=n&&n>0?t-n:a;return Math.max(f,a)+l}v(sourceChangeWindowMs,"sourceChangeWindowMs"),i(sourceChangeWindowMs,"sourceChangeWindowMs");function sourceScopeDirs(t,n,a,l,f){const S=i(g=>{const O=path.relative(t,g).split(path.sep).filter(Boolean);return O.length===0||O[0].startsWith("..")?"":O[0]},"bucketOf")(n);if(!S)return[];const y=new Set(a.filter(Boolean)),E=new Set([S]);for(const g of l)g.startsWith(".")||SRC_EXCLUDE.has(g)||f?.has(g)||g.endsWith("-devserver")||y.has(g)||E.add(g);return[...E].sort().map(g=>path.join(t,g))}v(sourceScopeDirs,"sourceScopeDirs"),i(sourceScopeDirs,"sourceScopeDirs");function podRecycleReason(t,n,a,l){return!t.proc||t.state!=="up"||t.spawnAt==null||t.inflight>0||(t.activeWork??0)>0||n-t.lastUsed<l.settleMs||t.lastStaleRecycleAt!=null&&n-t.lastStaleRecycleAt<l.cooldownMs?null:a>0&&a-t.spawnAt>l.graceMs?"stale-source-set":l.maxAgeMs>0&&n-t.spawnAt>l.maxAgeMs?"max-age":null}v(podRecycleReason,"podRecycleReason"),i(podRecycleReason,"podRecycleReason");function lensFrontendStale(t,n,a,l,f){return!(l-n<f.cooldownMs||a<=0||a-t<=f.graceMs||l-a<f.settleMs)}v(lensFrontendStale,"lensFrontendStale"),i(lensFrontendStale,"lensFrontendStale");function lensWatcherVerdict(t,n,a,l=[]){if(!t)return"unknown";if("schemaVersion"in t&&t.schemaVersion>=2&&l.length>0){const f=n-a,S=new Set(t.recentEvents.filter(y=>y.at>=f).map(y=>path.resolve(y.path)));return l.every(y=>S.has(path.resolve(y)))?"heard":"missed"}return t.lastFsSetEventAt>=n-a?"heard":"missed"}v(lensWatcherVerdict,"lensWatcherVerdict"),i(lensWatcherVerdict,"lensWatcherVerdict");function podWatcherVerdict(t,n,a){if(!t)return"unknown";if(t.degraded)return"degraded";const l=n-a;return t.lastWatchRunAt>=l||t.lastBuildAt>=l?"heard":"silent"}v(podWatcherVerdict,"podWatcherVerdict"),i(podWatcherVerdict,"podWatcherVerdict");function lensChildWedged(t,n,a,l){const f=t.hasListened?l.graceMs:Math.max(l.graceMs,l.neverListenedGraceMs);return a-t.spawnedAt<f||a-n<l.cooldownMs||t.probeFails<Math.max(2,l.failureThreshold)?null:"wedged-no-listener"}v(lensChildWedged,"lensChildWedged"),i(lensChildWedged,"lensChildWedged");function isPortConflictExit(t,n){return t.signal||t.code===null||t.code===0||t.ranMs>n.fastFailMs?!1:t.portHeld}v(isPortConflictExit,"isPortConflictExit"),i(isPortConflictExit,"isPortConflictExit");function createServiceLayer(t,n,a={}){const l=a.spawnProcess??node_child_process_1.spawn,f=a.probeAlive??pod_probe_1.probePodAlive,S=a.killTree??((e,o="SIGTERM")=>{try{process.kill(-e.pid,o)}catch{try{e.kill(o)}catch{}}}),y=a.rollReadyMs??types_1.POD_ROLL_READY_MS,E=a.rollPollMs??750,{emit:g}=n,O=i(e=>e.wsKey===t.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl"),"serviceBus"),h=i((e,o,s,r,c)=>g(o,s,r,{wsKey:e.wsKey,...c},void 0,O(e)),"emitSvc"),C=i(e=>(e.scannedAt=0,(0,discovery_1.pickSock)(e,t.scanTtlMs)?e.socks.length:0),"scanNow"),D=i((e,o)=>{let s;try{s=(0,node_child_process_1.execFileSync)("ps",["ax","-ww","-o","pid=,pgid=,command="],{encoding:"utf8",timeout:5e3})}catch{return 0}const r=e.proc?.pid;let c=0;for(const d of s.split(`
2
+ `)){const u=d.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!u)continue;const $=Number(u[1]),L=Number(u[2]),m=u[3];if(m.includes(`run ${o}`)&&/\bnx(\.js)?\b/.test(m)&&!(m.includes("/node_modules/nx/")&&!m.includes(e.root))&&!($===process.pid||$===r)&&!(r!==void 0&&L===r)){try{process.kill(-L,"SIGKILL")}catch{try{process.kill($,"SIGKILL")}catch{}}c+=1}}return c>0&&(console.log(`[gateway] ${o}: reaped ${c} stale runner tree(s) \u2014 a foreign generation held the nx task lock`),h(e,"warning",`stale-runner reap: ${e.project} (${c} foreign tree(s))`,`cluster-service:${e.project}`,{kind:"stale-runner-reap",project:e.project,reaped:c})),c},"reapForeignRunners"),X=i((e,o,s)=>{const r=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,c=Math.max(1,e.decl.minPods??1),d=path.join(e.root,"node_modules","nx","dist","bin","nx.js"),u=(0,process_name_1.namedExecPath)((0,process_name_1.processName)(e.wsKey||path.basename(e.root),e.project,"nx")),[$,L]=fs.existsSync(d)?[u,[d,"run",r,`--childCount=${c}`]]:["yarn",["nx","run",r,`--childCount=${c}`]],m=l($,L,{cwd:e.root,detached:!0,env:{...(0,pod_env_1.podBaseEnv)(process.env,t.root,e.root),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false",...e.wsKey?{LENSMCP_WS_KEY:e.wsKey}:{},LENSMCP_EVENT_FILE:e.wsKey===t.wsKey?t.eventFile:path.join(e.root,".lensmcp","events.jsonl"),LENSMCP_GATEWAY_PID:String(process.pid),LENSMCP_POD_GENERATION:String(o),...eastWestEnv(t,e)},stdio:["ignore","pipe","pipe"]});s==="active"&&(e.lastErrors=[],e.buildFailed=!1,e.faults=new pod_output_1.PodFaults);const R=i(w=>{const _=w.toString();for(const N of _.split(`
3
+ `)){const p=(0,pod_output_1.classifyPodLine)(N),{clean:j,broken:k,healthy:M}=p,z=j;if(k){e.lastErrors.push(j),e.lastErrors.length>12&&e.lastErrors.shift(),e.buildFailed=!0;const T=Date.now();(j!==e.lastErrorEmitSig||T-(e.lastErrorEmitAt??0)>=types_1.SERVICE_ERROR_THROTTLE_MS)&&(e.lastErrorEmitSig=j,e.lastErrorEmitAt=T,h(e,"error",`service error: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-error",project:e.project,line:j,fault:p.fault}))}M&&(e.buildFailed=!1);const I=(e.faults??=new pod_output_1.PodFaults).observe(p);if(I){e.lastErrorEmitSig=void 0;const T=I.open.length===0;h(e,"info",`${T?"service recovered":`${I.closed.join(" + ")} recovered`}: ${e.project}`,`cluster-service:${e.project}`,{kind:T?"service-recovered":"service-fault-closed",project:e.project,line:j,closed:I.closed,open:I.open})}!e.lockBlockedAt&&/Waiting for .+ in another nx process/.test(z)&&(e.lockBlockedAt=Date.now(),console.log(`[gateway] ${r}: spawn blocked by a stale nx runner \u2014 breaking the lock + respawning`),h(e,"warning",`nx task lock: ${e.project} blocked by a stale runner \u2014 auto-breaking`,`cluster-service:${e.project}`,{kind:"nx-lock-break",project:e.project}),setTimeout(()=>{t.stopped()||!e.lockBlockedAt||(W(e,"parked on a foreign nx task lock \u2014 recycling",{announce:!1}),D(e,r),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&x(e)},1500).unref?.())},250).unref?.())}},"sniff"),A=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0;return m.stdout?.on("data",w=>{if(t.stopped())return;R(w);const _=`[${e.project}] ${w}`;process.stdout.write(_),A?.(_)}),m.stderr?.on("data",w=>{if(t.stopped())return;R(w);const _=`[${e.project}] ${w}`;process.stderr.write(_),A?.(_)}),m.on("exit",(w,_)=>{if(e.proc!==m||(e.proc=void 0,e.state="down",t.stopped()))return;const N=(0,exit_reason_1.describeExit)(w,_);if(console.log(`[gateway] ${r} exited (${w??"no code"}${_?`, ${_}`:""}${e.inflight?`, ${e.inflight} request(s) in flight`:""})${N?` \u2014 ${N}`:""}`),h(e,w===0?"info":"warning",`service down: ${e.project} (exit ${w})`,`cluster-service:${e.project}`,{kind:"service-down",project:e.project,code:w,..._?{signal:_}:{}}),w===0||e.buildFailed)return;const p=Date.now();if(e.restarts=(e.restarts??[]).filter(k=>p-k<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){h(e,"error",`service crash-looping: ${e.project} \u2014 ${types_1.SERVICE_MAX_RESTARTS}+ restarts/min, not auto-respawning (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project});return}e.restarts.push(p);const j=Math.min(8e3,500*2**(e.restarts.length-1));setTimeout(()=>{t.stopped()||e.proc||e.state!=="down"||(console.log(`[gateway] self-heal: respawning ${e.project} (restart ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS})`),h(e,"info",`self-heal: respawning ${e.project}`,`cluster-service:${e.project}`,{kind:"service-respawn",project:e.project,attempt:e.restarts.length}),x(e))},j)}),m},"launchServiceProcess"),x=i(e=>{if(t.stopped())return;const o=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,s=Math.max(1,e.decl.minPods??1);a.reapForeign!==!1&&D(e,o),e.lockBlockedAt=void 0,console.log(`[gateway] starting ${o} (pods=${s})\u2026`),h(e,"info",`service starting: ${e.project} (${s} pod${s>1?"s":""})`,`cluster-service:${e.project}`,{kind:"service-starting",project:e.project,pods:s}),e.state="starting",e.spawnAt=Date.now(),e.generation=(e.generation??0)+1,e.proc=X(e,e.generation,"active")},"spawnService"),V=i(async e=>{const o=e.pool.socks[0];if(!o)return;const s=await(0,pod_probe_1.probePodAlive)(o,void 0,t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)]);s&&(e.activeWork=s.activeWork,s.watcher&&(e.watcher=s.watcher))},"refreshActiveWork"),P=i(e=>{try{const o=Number(fs.readFileSync(`${e}.owner`,"utf8").trim());return Number.isInteger(o)&&o>1?o:void 0}catch{return}},"readOwnerSidecar"),G=i(async e=>{const o=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];if(!o)return[];const s=(0,node_crypto_1.createHash)("sha256").update(o).digest("hex").slice(0,8),r=[];for(const c of e.pool.socks){const d=await(0,pod_probe_1.probePodAlive)(c,void 0,o);d&&(!d.keyFingerprint||d.keyFingerprint!==s)&&r.push({sock:c,pid:d.pid})}return r},"staleAdoptedSocks"),Y=i((e,o)=>{const s=o.map(r=>r.sock);for(const{sock:r,pid:c}of o){const d=chooseStalePodKillTarget(c,P(r),process.pid);if(d!==void 0)try{process.kill(d,"SIGTERM")}catch{}try{fs.unlinkSync(r)}catch{}try{fs.unlinkSync(`${r}.owner`)}catch{}}e.pool.socks=e.pool.socks.filter(r=>!s.includes(r)),e.pool.idx=-1,e.pool.scannedAt=0},"evictStaleAdopted"),b=i((e,o)=>{if(e.state==="up")return!1;e.state="up";const s=e.pool.socks.length;return h(e,"info",`service up: ${e.project} (${s} pods, ${o})`,`cluster-service:${e.project}`,{kind:"service-up",project:e.project,pods:s,adopted:o==="adopted"}),!0},"markUp"),re=i(async e=>{if(C(e.pool)>0){const r=await G(e);if(r.length>0&&(console.error(`[gateway] ${e.project}: ${r.length} adopted pod(s) hold a foreign east-west key \u2014 evicting instead of adopting.`),h(e,"warning",`stale adoption: ${e.project} (foreign east-west key)`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:"stale-adoption",pods:r.length}),e.proc&&W(e,"stale adoption (foreign east-west key)"),Y(e,r)),e.pool.socks.length>0)return b(e,"adopted"),!0}if(t.stopped())return!1;e.state!=="starting"&&!e.proc&&x(e);const o=Date.now()+t.startupTimeoutMs,s=Date.now()+12e3;for(;!t.stopped()&&Date.now()<o;){if(await sleep(Math.min(700,t.startupTimeoutMs/4)),e.buildFailed&&Date.now()>s)return!1;if(C(e.pool)>0){e.state="up",e.buildFailed=!1;const r=e.spawnAt?Date.now()-e.spawnAt:void 0;return console.log(`[gateway] ${e.project} up (${e.pool.socks.length} pods${r?`, cold start ${r}ms`:""})`),h(e,"info",`cold start: ${e.project} (${e.pool.socks.length} pods, ${r??"?"}ms)`,`cluster-service:${e.project}`,{kind:"cold-start",project:e.project,pods:e.pool.socks.length,durationMs:r}),!0}if(e.state==="down")return!1}return!1},"ensureUp"),se=i(e=>{const o=e.decl.maxPods??e.decl.minPods??1,s=e.pool.socks.length,r=e.decl.adminUrl??(e.decl.port?`http://localhost:${e.decl.port}`:void 0);if(!r||s===0||s>=o||e.inflight<=s||Date.now()-e.lastScaleAt<5e3)return;e.lastScaleAt=Date.now();const c=(r.startsWith("https")?require("node:https"):http).request(`${r}/webpack/scale`,{method:"POST",rejectUnauthorized:!1},d=>d.resume());c.on("error",()=>{}),c.end(JSON.stringify({pods:s+1})),console.log(`[gateway] autoscale ${e.project}: ${s} \u2192 ${s+1} pods (inflight ${e.inflight})`),h(e,"info",`autoscale: ${e.project} ${s} \u2192 ${s+1} pods`,`cluster-service:${e.project}`,{kind:"autoscale",project:e.project,from:s,to:s+1,inflight:e.inflight})},"scaleUp"),W=i((e,o,s)=>{if(!e.proc)return;console.log(`[gateway] ${e.project} ${o} \u2014 scaling to zero.`),s?.announce!==!1&&h(e,"info",`idle kill: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"idle-kill",project:e.project,why:o});const r=e.proc;try{r.stdout?.removeAllListeners("data"),r.stderr?.removeAllListeners("data"),r.removeAllListeners("exit")}catch{}S(r,"SIGTERM"),e.proc=void 0,e.state="down",setTimeout(()=>{J(e),e.pool.socks=[],e.pool.scannedAt=0},1200).unref?.()},"killSpawned"),J=i(e=>{try{for(const o of fs.readdirSync(e.pool.dir)){if(!o.endsWith(".sock"))continue;const s=path.join(e.pool.dir,o);try{const r=Number(fs.readFileSync(`${s}.owner`,"utf8").trim());if(Number.isFinite(r)&&r>0)try{process.kill(r,0);continue}catch{}}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(`${s}.owner`)}catch{}}}catch{}},"sweepDeadOwnerSocks"),te=i((e,o)=>{if(e.rolling)return e.rolling;const s=e.proc;if(!s||t.stopped())return Promise.resolve(!1);const r=e.generation??0,c=r+1,d=Date.now();e.lastStaleRecycleAt=d,console.log(`[gateway] pod handoff start: ${e.project} g${r}\u2192g${c} reason=${o} \u2014 standby spawning, old generation keeps serving.`),h(e,"info",`pod handoff starting: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"pod-handoff-start",project:e.project,reason:o,generation:c,fromGeneration:r});const u=X(e,c,"standby"),$=(async()=>{const L=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],m=d+y;let R;for(;!t.stopped()&&Date.now()<m&&!(u.exitCode!==null||u.signalCode!==null);){C(e.pool);for(const A of e.pool.socks)if((await f(A,void 0,L))?.podGeneration===c){R=A;break}if(R)break;await sleep(E)}if(!R||t.stopped()){const A=t.stopped()?"gateway stopping":u.exitCode!==null||u.signalCode!==null?`standby exited (${u.exitCode??u.signalCode})`:`standby not ready within ${Math.round(y/1e3)}s`;try{u.stdout?.removeAllListeners("data"),u.stderr?.removeAllListeners("data")}catch{}return S(u,"SIGTERM"),console.error(`[gateway] pod handoff failed: ${e.project} g${c}: ${A} \u2014 old generation g${r} kept serving.`),h(e,"warning",`pod handoff failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-failed",project:e.project,reason:o,generation:c,error:A,durationMs:Date.now()-d}),setTimeout(()=>J(e),1200).unref?.(),!1}if(e.proc!==s)return S(u,"SIGTERM"),!1;e.proc=u,e.generation=c,e.spawnAt=d,e.state="up",e.watcher=void 0,e.staleVerifiedAt=void 0,e.staleKeptAt=void 0,e.buildFailed=!1,e.lastErrors=[];try{s.stdout?.removeAllListeners("data"),s.stderr?.removeAllListeners("data"),s.removeAllListeners("exit")}catch{}return S(s,"SIGTERM"),setTimeout(()=>{J(e),e.pool.scannedAt=0},1200).unref?.(),console.log(`[gateway] pod handoff ready: ${e.project} g${c} answered on ${path.basename(R)} in ${Date.now()-d}ms; retiring g${r}.`),h(e,"info",`pod handoff complete: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-complete",project:e.project,reason:o,generation:c,fromGeneration:r,durationMs:Date.now()-d}),!0})().finally(()=>{e.rolling=void 0});return e.rolling=$,$},"rollPod"),ne=i(e=>{const o=Date.now();if(e.restarts=(e.restarts??[]).filter(s=>o-s<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){h(e,"error",`service crash-looping: ${e.project} \u2014 wedged ${types_1.SERVICE_MAX_RESTARTS}+\xD7/min, not auto-recycling (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project}),W(e,"wedged (crash-loop cap) \u2014 leaving down for the next request",{announce:!1});return}e.restarts.push(o),console.log(`[gateway] self-heal: recycling WEDGED ${e.project} (live parent, 0 live pods; ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS}; ${e.inflight??0} request(s) in flight \u2014 jobs held by the dead pod keep their locks until they expire)`),h(e,"warning",`self-heal: recycling wedged ${e.project} (0 live pods)`,`cluster-service:${e.project}`,{kind:"service-recycle",project:e.project,attempt:e.restarts.length}),W(e,"wedged: 0 live pods \u2014 recycling",{announce:!1}),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&x(e)},1500).unref?.()},"recycleWedged"),ce={maxAgeMs:types_1.POD_MAX_AGE_MS,graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};let Q;const B=new Map,oe=new Map;let Z=!1,ee=0,H=0;const ie=i(()=>{const e=t.projectRoots??{},o=new Set(t.services.map(r=>r.project));for(const r of t.routes)r.lens&&o.add(r.lens.project);const s=new Set;for(const r of o){const c=e[r];if(!c)continue;const d=path.relative(t.root,c).split(path.sep).filter(Boolean)[0];d&&!d.startsWith("..")&&s.add(d)}return[...s]},"managedBuckets"),ae=i((e,o,s,r)=>{const c=t.projectSourceRoots?.[e];if(c?.length)return c;const d=t.projectRoots?.[e];if(!d)return;const u=sourceScopeDirs(t.root,d,s,o,r);return u.length>0?u:void 0},"scopeFor"),le=i(()=>{if(Z||Date.now()-ee<types_1.POD_STALE_SCAN_MS)return;Z=!0,ee=Date.now();const e=ee;(async()=>{const o=(0,scope_1.readSourceSetOptions)(t.root),s=o.exclude,r={ignoreTests:o.ignoreTests},c=await sourceSetSnapshot(t.root,void 0,s,r),d=Date.now(),u=sourceChangeWindowMs(d,H,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS),$=Q?diffSourceSets(Q,c,d,u):null;if($&&(t.sourceSetChangedAt=d,t.sourceSetChange=$,g("info","source file set changed \u2014 stale pods recycle when idle","cluster-gateway",{kind:"source-set-changed",added:$.added,removed:$.removed,truncated:$.truncated})),Q=c,!t.projectRoots){H=e;return}let L;try{L=(await fs.promises.readdir(t.root,{withFileTypes:!0})).filter(p=>p.isDirectory()).map(p=>p.name)}catch{return}const m=ie(),R=new Set(t.services.map(p=>p.project));for(const p of t.routes)p.lens&&R.add(p.lens.project);const A=new Map;for(const p of R){const j=ae(p,L,m,s);if(!j)continue;const k=j.join("|"),M=A.get(k)??{dirs:j,projects:[]};M.projects.push(p),A.set(k,M)}const w=Date.now(),_=sourceChangeWindowMs(w,H,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS);H=e;const N=i((p,j,k)=>{t.sourceSetChangedFor??=new Map,t.sourceSetChangesFor??=new Map;for(const M of p)t.sourceSetChangedFor.set(M,j),t.sourceSetChangesFor.set(M,k)},"stampScoped");for(const[p,{dirs:j,projects:k}]of A){const M=await sourceSetSnapshot(t.root,j,s,r),z=B.get(p);B.set(p,M);const I=new Map;for(const K of k){const F=oe.get(K);if(F===void 0||F===p)continue;const q=I.get(F)??[];q.push(K),I.set(F,q)}for(const K of k)oe.set(K,p);for(const[K,F]of I){const q=B.get(K),U=q?diffSourceSets(q,M,w,_):$;U&&(N(F,q?w:d,U),g("info",`source file set changed \u2014 ${F.join(", ")}'s watch scope was re-keyed`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,rescoped:!0,projects:F,added:U.added,removed:U.removed,truncated:U.truncated}))}if(!z)continue;const T=diffSourceSets(z,M,w,_);T&&(N(k,w,T),g("info",`source file set changed in ${k.join(", ")}'s scope`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,projects:k,added:T.added,removed:T.removed,truncated:T.truncated}))}for(const p of[...B.keys()])A.has(p)||B.delete(p)})().catch(()=>{}).finally(()=>{Z=!1})},"maybeScanSourceSet"),de=i((e,o)=>{const s=(t.sourceSetChangesFor?.get(e.project)??t.sourceSetChange)?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,r=podWatcherVerdict(e.watcher,o,s),c=i(d=>(e.staleKeptAt!==o&&(e.staleKeptAt=o,console.log(`[gateway] stale source set: pod ${e.project} ${d} \u2014 no recycle.`)),!1),"keep");return r==="heard"?(e.staleVerifiedAt=o,h(e,"info",`stale check: ${e.project} watcher confirmed \u2014 no recycle`,`cluster-service:${e.project}`,{kind:"pod-stale-verified",project:e.project,watcher:r}),c(`watcher CONFIRMED alive across the change (last build ${new Date(e.watcher?.lastBuildAt??0).toISOString()})`)):r==="degraded"?(console.log(`[gateway] stale source set: pod ${e.project} watcher DEGRADED (${e.watcher?.degraded}) \u2014 recycling.`),!0):r==="silent"?types_1.POD_WATCHER_SILENT==="keep"?c("watcher alive but quiet across the change \u2014 keeping it (LENSMCP_POD_WATCHER_SILENT=keep; a live watcher cannot miss an add it will need)"):!0:types_1.POD_WATCHER_UNVERIFIED==="keep"?c("unverifiable (no watcher testimony \u2014 older devserver bundle?) \u2014 keeping it (LENSMCP_POD_WATCHER_UNVERIFIED=keep)"):!0},"podStaleRecycleAllowed"),pe=i((e,o)=>{if(e.lastStaleRecycleAt=Date.now(),types_1.POD_RECYCLE_MODE==="rolling"&&e.proc){te(e,o);return}console.log(`[gateway] zombie recycle: ${e.project} (${o}) \u2014 stale fs view; fresh pod incoming`),h(e,"warning",`zombie recycle: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:o});const s=!!e.decl.eager;W(e,`${o} \u2014 recycling stale pod`,{announce:!1}),s&&setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&x(e)},1500).unref?.()},"recyclePod"),ue=i(()=>{const e=setInterval(()=>{he().catch(o=>console.error("[gateway] sweep error:",o))},t.sweepMs);return e.unref(),e},"startSweeper"),he=i(async()=>{{if(t.stopped())return;types_1.POD_RECYCLE_ENABLED&&le();for(const e of t.services){if(t.stopped()||!e.proc){e.wedgedSince=void 0;continue}const o=e.decl.idleKillSec;if(o&&e.inflight===0&&Date.now()-e.lastUsed>o*1e3){W(e,`idle ${o}s`),e.wedgedSince=void 0;continue}const s=e.state==="starting"&&e.spawnAt!==void 0&&Date.now()-e.spawnAt<t.startupTimeoutMs,r=C(e.pool)>0;if(r||s){if(e.wedgedSince=void 0,r&&b(e,"observed"),r&&!s&&types_1.POD_RECYCLE_ENABLED){const c=t.sourceSetChangedFor?.get(e.project)??t.sourceSetChangedAt??0;await V(e);const d=(e.staleVerifiedAt??0)>=c&&c>0,u=podRecycleReason(e,Date.now(),d?0:c,ce);if(u==="stale-source-set"&&!de(e,c))continue;u&&pe(e,u)}continue}e.wedgedSince??=Date.now(),Date.now()-e.wedgedSince>types_1.WEDGE_RECYCLE_GRACE_MS&&(e.wedgedSince=void 0,ne(e))}}},"sweepOnce");return{scanNow:C,spawnService:x,ensureUp:re,scaleUp:se,killSpawned:W,markUp:b,startSweeper:ue,rollPod:te}}v(createServiceLayer,"createServiceLayer"),i(createServiceLayer,"createServiceLayer");function chooseStalePodKillTarget(t,n,a){if(!(t===void 0||!Number.isInteger(t)||t<=1)&&!(n!==void 0&&n!==t)&&t!==a)return t}v(chooseStalePodKillTarget,"chooseStalePodKillTarget"),i(chooseStalePodKillTarget,"chooseStalePodKillTarget");
@@ -1,2 +1,2 @@
1
- "use strict";var D=Object.defineProperty;var f=(t,a)=>D(t,"name",{value:a,configurable:!0});var _=Object.defineProperty,h=f((t,a)=>_(t,"name",{value:a,configurable:!0}),"h"),S=Object.defineProperty,n=h((t,a)=>S(t,"name",{value:a,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.EDGE_DURATION_SAMPLES=exports.LENS_DASHBOARD_PROJECT=void 0,exports.createObservability=createObservability;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),redact_1=require("@lensmcp/core/redact"),busHygiene=(()=>{try{return require("@lensmcp/node-instrumentation")}catch{return}})();exports.LENS_DASHBOARD_PROJECT="(lens-dashboard)",exports.EDGE_DURATION_SAMPLES=64;function ownerOf(t){return t?.svc?{root:t.svc.root,wsKey:t.svc.wsKey}:t?.lens?{...t.lens.workspaceRoot?{root:t.lens.workspaceRoot}:{},...t.lens.workspaceKey?{wsKey:t.lens.workspaceKey}:{}}:{}}f(ownerOf,"ownerOf"),h(ownerOf,"ownerOf"),n(ownerOf,"ownerOf");function busFileFor(t,a){const{root:u}=ownerOf(t);if(!u)return;const l=path.join(u,".lensmcp","events.jsonl");return l===a?void 0:l}f(busFileFor,"busFileFor"),h(busFileFor,"busFileFor"),n(busFileFor,"busFileFor");const hdr=n(t=>typeof t=="string"&&t!==""?t:Array.isArray(t)?t[0]:void 0,"hdr");function createObservability(t,a){const u=n(()=>Date.now().toString(36)+Math.random().toString(36).slice(2,12),"eid"),l=busHygiene?.createEventFloodGuard({burst:30,perSec:5}),w=n((e,r,s,i,d,c)=>{const o=c??t;try{const p=l?l.admit(s):{ok:!0,suppressed:0};if(!p.ok)return;fs.mkdirSync(path.dirname(o),{recursive:!0});const g=i&&(0,redact_1.redactDeep)(i),m=JSON.stringify({id:u(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:e,context:(0,redact_1.redactDeep)({sessionId:"pending",...d}),fingerprint:s,title:(0,redact_1.safeTitle)(r),raw:p.suppressed>0?{...g,floodSuppressed:p.suppressed}:g})+`
2
- `;busHygiene?.maybeRotateEventFile(o,m.length),fs.appendFileSync(o,m)}catch{}},"emit"),E=n(e=>{const r=hdr(e.headers["x-lensmcp-flow-id"]);let s=hdr(e.headers["x-request-id"]);if(!(!r&&!s&&!hdr(e.headers.traceparent)))return s||(s=u(),e.headers["x-request-id"]=s),{startedAt:Date.now(),method:(e.method??"GET").toUpperCase(),host:(e.headers.host||"").split(":")[0],url:e.url??"/",steps:[],...r?{flowId:r}:{},...s?{requestId:s}:{},...hdr(e.headers["x-lensmcp-parent-request-id"])?{parentRequestId:hdr(e.headers["x-lensmcp-parent-request-id"])}:{},...hdr(e.headers["x-lensmcp-origin-node-id"])?{originNodeId:hdr(e.headers["x-lensmcp-origin-node-id"])}:{}}},"beginTrace"),b=n((e,r,s)=>{e&&e.steps.push({step:r,atMs:Date.now()-e.startedAt,...s})},"traceStep"),v=n((e,r,s,i,d)=>{if(!e||e.done||(e.done=!0,r===exports.LENS_DASHBOARD_PROJECT&&s<500))return;const c=Date.now()-e.startedAt;w(s>=500?"error":"info",`gateway ${e.method} ${e.host}${e.url} \u2192 ${s} (${c}ms)`,`gateway-request:${r}`,{kind:"gateway-request",project:r,host:e.host,method:e.method,url:e.url,status:s,durationMs:c,startedAt:e.startedAt,steps:e.steps,...ownerOf(d).wsKey?{wsKey:ownerOf(d).wsKey}:{},...i},{...e.flowId?{flowId:e.flowId}:{},...e.requestId?{requestId:e.requestId}:{},...e.parentRequestId?{parentRequestId:e.parentRequestId}:{},...e.originNodeId?{originNodeId:e.originNodeId}:{}},busFileFor(d,t))},"finishTrace"),y=new Map;return{emit:w,eid:u,beginTrace:E,traceStep:b,finishTrace:v,recordEdge:n((e,r,s,i)=>{if(e.project===exports.LENS_DASHBOARD_PROJECT&&s<500&&s!==0)return;const d=e.host??"(default)",c=(i?i+"\u21D2":"")+d+"\u2192"+e.project,o=y.get(c)??{host:d,project:e.project,caller:i,count:0,totalMs:0,errors:0,durations:[],...busFileFor(e,t)?{busFile:busFileFor(e,t)}:{},...ownerOf(e).wsKey?{wsKey:ownerOf(e).wsKey}:{}};if(o.count+=1,o.totalMs+=r,o.durations.length<exports.EDGE_DURATION_SAMPLES)o.durations.push(Math.round(r));else{const p=Math.floor(Math.random()*o.count);p<exports.EDGE_DURATION_SAMPLES&&(o.durations[p]=Math.round(r))}(s>=500||s===0)&&(o.errors+=1),y.set(c,o)},"recordEdge"),startEdgeFlusher:n(()=>{const e=setInterval(()=>{for(const r of y.values()){const s=Math.round(r.totalMs/r.count);w(r.errors?"warning":"info",`traffic ${r.host} \u2192 ${r.project}: ${r.count} req, ~${s}ms${r.errors?`, ${r.errors} errors`:""}`,`gateway-traffic:${r.host}->${r.project}`,{kind:"gateway-traffic",host:r.host,project:r.project,caller:r.caller,count:r.count,avgMs:s,errors:r.errors,durationsMs:r.durations,...r.wsKey?{wsKey:r.wsKey}:{}},void 0,r.busFile)}y.clear()},a.trafficFlushMs);return e.unref(),e},"startEdgeFlusher")}}f(createObservability,"createObservability"),h(createObservability,"createObservability"),n(createObservability,"createObservability");
1
+ "use strict";var _=Object.defineProperty;var h=(t,d)=>_(t,"name",{value:d,configurable:!0});var S=Object.defineProperty,n=h((t,d)=>S(t,"name",{value:d,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.EDGE_DURATION_SAMPLES=exports.LENS_DASHBOARD_PROJECT=void 0,exports.createObservability=createObservability;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),redact_1=require("@lensmcp/core/redact"),busHygiene=(()=>{try{return require("@lensmcp/node-instrumentation")}catch{return}})();exports.LENS_DASHBOARD_PROJECT="(lens-dashboard)",exports.EDGE_DURATION_SAMPLES=64;function ownerOf(t){return t?.svc?{root:t.svc.root,wsKey:t.svc.wsKey}:t?.lens?{...t.lens.workspaceRoot?{root:t.lens.workspaceRoot}:{},...t.lens.workspaceKey?{wsKey:t.lens.workspaceKey}:{}}:{}}h(ownerOf,"ownerOf"),n(ownerOf,"ownerOf");function busFileFor(t,d){const{root:u}=ownerOf(t);if(!u)return;const l=path.join(u,".lensmcp","events.jsonl");return l===d?void 0:l}h(busFileFor,"busFileFor"),n(busFileFor,"busFileFor");const hdr=n(t=>typeof t=="string"&&t!==""?t:Array.isArray(t)?t[0]:void 0,"hdr");function createObservability(t,d){const u=n(()=>Date.now().toString(36)+Math.random().toString(36).slice(2,12),"eid"),l=busHygiene?.createEventFloodGuard({burst:30,perSec:5}),w=n((e,r,s,a,i,c)=>{const o=c??t;try{const p=l?l.admit(s):{ok:!0,suppressed:0};if(!p.ok)return;fs.mkdirSync(path.dirname(o),{recursive:!0});const y=a&&(0,redact_1.redactDeep)(a),g=JSON.stringify({id:u(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:e,context:(0,redact_1.redactDeep)({sessionId:"pending",...i}),fingerprint:s,title:(0,redact_1.safeTitle)(r),raw:p.suppressed>0?{...y,floodSuppressed:p.suppressed}:y})+`
2
+ `;busHygiene?.maybeRotateEventFile(o,g.length),fs.appendFileSync(o,g)}catch{}},"emit"),m=n(e=>{const r=hdr(e.headers["x-lensmcp-flow-id"]);let s=hdr(e.headers["x-request-id"]);if(!(!r&&!s&&!hdr(e.headers.traceparent)))return s||(s=u(),e.headers["x-request-id"]=s),{startedAt:Date.now(),method:(e.method??"GET").toUpperCase(),host:(e.headers.host||"").split(":")[0],url:e.url??"/",steps:[],...r?{flowId:r}:{},...s?{requestId:s}:{},...hdr(e.headers["x-lensmcp-parent-request-id"])?{parentRequestId:hdr(e.headers["x-lensmcp-parent-request-id"])}:{},...hdr(e.headers["x-lensmcp-origin-node-id"])?{originNodeId:hdr(e.headers["x-lensmcp-origin-node-id"])}:{}}},"beginTrace"),E=n((e,r,s)=>{e&&e.steps.push({step:r,atMs:Date.now()-e.startedAt,...s})},"traceStep"),D=n((e,r,s,a,i)=>{if(!e||e.done||(e.done=!0,r===exports.LENS_DASHBOARD_PROJECT&&s<500))return;const c=Date.now()-e.startedAt;w(s>=500?"error":"info",`gateway ${e.method} ${e.host}${e.url} \u2192 ${s} (${c}ms)`,`gateway-request:${r}`,{kind:"gateway-request",project:r,host:e.host,method:e.method,url:e.url,status:s,durationMs:c,startedAt:e.startedAt,steps:e.steps,...ownerOf(i).wsKey?{wsKey:ownerOf(i).wsKey}:{},...a},{...e.flowId?{flowId:e.flowId}:{},...e.requestId?{requestId:e.requestId}:{},...e.parentRequestId?{parentRequestId:e.parentRequestId}:{},...e.originNodeId?{originNodeId:e.originNodeId}:{}},busFileFor(i,t))},"finishTrace"),f=new Map;return{emit:w,eid:u,beginTrace:m,traceStep:E,finishTrace:D,recordEdge:n((e,r,s,a)=>{if(e.project===exports.LENS_DASHBOARD_PROJECT&&s<500&&s!==0)return;const i=e.host??"(default)",c=(a?a+"\u21D2":"")+i+"\u2192"+e.project,o=f.get(c)??{host:i,project:e.project,caller:a,count:0,totalMs:0,errors:0,durations:[],...busFileFor(e,t)?{busFile:busFileFor(e,t)}:{},...ownerOf(e).wsKey?{wsKey:ownerOf(e).wsKey}:{}};if(o.count+=1,o.totalMs+=r,o.durations.length<exports.EDGE_DURATION_SAMPLES)o.durations.push(Math.round(r));else{const p=Math.floor(Math.random()*o.count);p<exports.EDGE_DURATION_SAMPLES&&(o.durations[p]=Math.round(r))}(s>=500||s===0)&&(o.errors+=1),f.set(c,o)},"recordEdge"),startEdgeFlusher:n(()=>{const e=setInterval(()=>{for(const r of f.values()){const s=Math.round(r.totalMs/r.count);w(r.errors?"warning":"info",`traffic ${r.host} \u2192 ${r.project}: ${r.count} req, ~${s}ms${r.errors?`, ${r.errors} errors`:""}`,`gateway-traffic:${r.host}->${r.project}`,{kind:"gateway-traffic",host:r.host,project:r.project,caller:r.caller,count:r.count,avgMs:s,errors:r.errors,durationsMs:r.durations,...r.wsKey?{wsKey:r.wsKey}:{}},void 0,r.busFile)}f.clear()},d.trafficFlushMs);return e.unref(),e},"startEdgeFlusher")}}h(createObservability,"createObservability"),n(createObservability,"createObservability");
@@ -1,2 +1,2 @@
1
- "use strict";var i=Object.defineProperty;var E=(t,e)=>i(t,"name",{value:e,configurable:!0});var p=Object.defineProperty,a=E((t,e)=>p(t,"name",{value:e,configurable:!0}),"a"),c=Object.defineProperty,s=a((t,e)=>c(t,"name",{value:e,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.FOREIGN_POD_ENV_DENYLIST=exports.WORKSPACE_DOTENV_FILES=void 0,exports.parseDotenvKeys=parseDotenvKeys,exports.workspaceDotenvKeys=workspaceDotenvKeys,exports.scrubEnv=scrubEnv,exports.podBaseEnv=podBaseEnv;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.WORKSPACE_DOTENV_FILES=[".env",".env.local",".local.env"],exports.FOREIGN_POD_ENV_DENYLIST=["PG_URL","REDIS_URL","DATABASE_URL","POSTGRES_URL"];function parseDotenvKeys(t){const e=new Set;for(const o of t.split(`
2
- `)){const r=o.trim();if(!r||r.startsWith("#"))continue;const n=r.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/);n&&e.add(n[1])}return e}E(parseDotenvKeys,"parseDotenvKeys"),a(parseDotenvKeys,"parseDotenvKeys"),s(parseDotenvKeys,"parseDotenvKeys");function workspaceDotenvKeys(t){const e=new Set;for(const o of exports.WORKSPACE_DOTENV_FILES){let r;try{r=fs.readFileSync(path.join(t,o),"utf8")}catch{continue}for(const n of parseDotenvKeys(r))e.add(n)}return e}E(workspaceDotenvKeys,"workspaceDotenvKeys"),a(workspaceDotenvKeys,"workspaceDotenvKeys"),s(workspaceDotenvKeys,"workspaceDotenvKeys");function scrubEnv(t,e){const o={};for(const[r,n]of Object.entries(t))e.has(r)||exports.FOREIGN_POD_ENV_DENYLIST.includes(r)||(o[r]=n);return o}E(scrubEnv,"scrubEnv"),a(scrubEnv,"scrubEnv"),s(scrubEnv,"scrubEnv");function podBaseEnv(t,e,o){return path.resolve(o)===path.resolve(e)?t:scrubEnv(t,workspaceDotenvKeys(e))}E(podBaseEnv,"podBaseEnv"),a(podBaseEnv,"podBaseEnv"),s(podBaseEnv,"podBaseEnv");
1
+ "use strict";var p=Object.defineProperty;var a=(o,e)=>p(o,"name",{value:e,configurable:!0});var c=Object.defineProperty,s=a((o,e)=>c(o,"name",{value:e,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.FOREIGN_POD_ENV_DENYLIST=exports.WORKSPACE_DOTENV_FILES=void 0,exports.parseDotenvKeys=parseDotenvKeys,exports.workspaceDotenvKeys=workspaceDotenvKeys,exports.scrubEnv=scrubEnv,exports.podBaseEnv=podBaseEnv;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.WORKSPACE_DOTENV_FILES=[".env",".env.local",".local.env"],exports.FOREIGN_POD_ENV_DENYLIST=["PG_URL","REDIS_URL","DATABASE_URL","POSTGRES_URL"];function parseDotenvKeys(o){const e=new Set;for(const r of o.split(`
2
+ `)){const t=r.trim();if(!t||t.startsWith("#"))continue;const n=t.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/);n&&e.add(n[1])}return e}a(parseDotenvKeys,"parseDotenvKeys"),s(parseDotenvKeys,"parseDotenvKeys");function workspaceDotenvKeys(o){const e=new Set;for(const r of exports.WORKSPACE_DOTENV_FILES){let t;try{t=fs.readFileSync(path.join(o,r),"utf8")}catch{continue}for(const n of parseDotenvKeys(t))e.add(n)}return e}a(workspaceDotenvKeys,"workspaceDotenvKeys"),s(workspaceDotenvKeys,"workspaceDotenvKeys");function scrubEnv(o,e){const r={};for(const[t,n]of Object.entries(o))e.has(t)||exports.FOREIGN_POD_ENV_DENYLIST.includes(t)||(r[t]=n);return r}a(scrubEnv,"scrubEnv"),s(scrubEnv,"scrubEnv");function podBaseEnv(o,e,r){return path.resolve(r)===path.resolve(e)?o:scrubEnv(o,workspaceDotenvKeys(e))}a(podBaseEnv,"podBaseEnv"),s(podBaseEnv,"podBaseEnv");
@@ -1 +1 @@
1
- "use strict";var c=Object.defineProperty;var a=(t,e)=>c(t,"name",{value:e,configurable:!0});var i=Object.defineProperty,l=a((t,e)=>i(t,"name",{value:e,configurable:!0}),"l"),d=Object.defineProperty,r=l((t,e)=>d(t,"name",{value:e,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.PodFaults=void 0,exports.classifyPodLine=classifyPodLine;const ANSI_SGR=/\x1b\[[0-9;]*m/g,OPENS=[["build",/ERROR in |Module not found/],["types",/error TS\d+|Found [1-9]\d* errors?/],["process",/Unhandled 'error' event|EADDRINUSE/]],CLOSES=[["build",/compiled successfully/],["types",/No typescript errors found|Found 0 errors|\[tsgo\] .+: types clean/],["process",/Child#\d+ (ready|hot-swapped)/]];function classifyPodLine(t){const e=t.replace(ANSI_SGR,"").trim(),s=OPENS.find(([,o])=>o.test(e))?.[0],n=s?[]:CLOSES.filter(([,o])=>o.test(e)).map(([o])=>o);return{clean:e,broken:s!==void 0,healthy:n.length>0,...s?{fault:s}:{},closes:n}}a(classifyPodLine,"classifyPodLine"),l(classifyPodLine,"classifyPodLine"),r(classifyPodLine,"classifyPodLine");class PodFaults{static{a(this,"PodFaults")}static{l(this,"PodFaults")}static{r(this,"PodFaults")}constructor(){this.open=new Set}observe(e){if(e.fault){this.open.add(e.fault);return}const s=e.closes.filter(n=>this.open.delete(n));return s.length?{closed:s,open:[...this.open]}:void 0}}exports.PodFaults=PodFaults;
1
+ "use strict";var i=Object.defineProperty;var l=(s,e)=>i(s,"name",{value:e,configurable:!0});var d=Object.defineProperty,r=l((s,e)=>d(s,"name",{value:e,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.PodFaults=void 0,exports.classifyPodLine=classifyPodLine;const ANSI_SGR=/\x1b\[[0-9;]*m/g,OPENS=[["build",/ERROR in |Module not found/],["types",/error TS\d+|Found [1-9]\d* errors?/],["process",/Unhandled 'error' event|EADDRINUSE/]],CLOSES=[["build",/compiled successfully/],["types",/No typescript errors found|Found 0 errors|\[tsgo\] .+: types clean/],["process",/Child#\d+ (ready|hot-swapped)/]];function classifyPodLine(s){const e=s.replace(ANSI_SGR,"").trim(),t=OPENS.find(([,o])=>o.test(e))?.[0],n=t?[]:CLOSES.filter(([,o])=>o.test(e)).map(([o])=>o);return{clean:e,broken:t!==void 0,healthy:n.length>0,...t?{fault:t}:{},closes:n}}l(classifyPodLine,"classifyPodLine"),r(classifyPodLine,"classifyPodLine");class PodFaults{static{l(this,"PodFaults")}static{r(this,"PodFaults")}constructor(){this.open=new Set}observe(e){if(e.fault){this.open.add(e.fault);return}const t=e.closes.filter(n=>this.open.delete(n));return t.length?{closed:t,open:[...this.open]}:void 0}}exports.PodFaults=PodFaults;
@@ -1 +1 @@
1
- "use strict";var m=Object.defineProperty;var d=(t,e)=>m(t,"name",{value:e,configurable:!0});var h=Object.defineProperty,p=d((t,e)=>h(t,"name",{value:e,configurable:!0}),"p"),f=Object.defineProperty,u=p((t,e)=>f(t,"name",{value:e,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.parsePodWatcherTestimony=parsePodWatcherTestimony,exports.probePodAlive=probePodAlive,exports.podConnectionVerdict=podConnectionVerdict,exports.podSocketAccepts=podSocketAccepts;const tslib_1=require("tslib"),http=tslib_1.__importStar(require("node:http")),net=tslib_1.__importStar(require("node:net")),types_1=require("./types");function parsePodWatcherTestimony(t){if(!t||typeof t!="object")return;const e=t;if(e.schemaVersion!==1)return;const c=u(r=>typeof r=="number"&&Number.isFinite(r)?r:0,"num"),n=e.degraded;return{schemaVersion:1,lastWatchRunAt:c(e.lastWatchRunAt),lastBuildAt:c(e.lastBuildAt),buildsSinceSpawn:c(e.buildsSinceSpawn),degraded:typeof n=="string"&&n?n:n===!0?"degraded":!1,recentPaths:Array.isArray(e.recentPaths)?e.recentPaths.filter(r=>typeof r=="string").slice(-32):[]}}d(parsePodWatcherTestimony,"parsePodWatcherTestimony"),p(parsePodWatcherTestimony,"parsePodWatcherTestimony"),u(parsePodWatcherTestimony,"parsePodWatcherTestimony");async function probePodAlive(t,e=types_1.POD_ALIVE_PROBE_TIMEOUT_MS,c){return new Promise(n=>{let r=!1;const i=u(a=>{r||(r=!0,n(a))},"finish");let s;try{s=http.request({socketPath:t,path:types_1.POD_ALIVE_PATH,method:"GET",timeout:e,agent:!1,...c?{headers:{"x-internal-token":c}}:{}},a=>{if(a.statusCode!==200){a.resume(),i(void 0);return}let l="";a.setEncoding("utf8"),a.on("data",o=>{l+=o}),a.on("end",()=>{try{const o=JSON.parse(l);i(o.ok===!0?{inflight:Number(o.inflight??0),activeWork:Number(o.activeWork??0),swapping:o.swapping===!0,...typeof o.pid=="number"?{pid:o.pid}:{},...typeof o.keyFingerprint=="string"?{keyFingerprint:o.keyFingerprint}:{},...(()=>{const y=parsePodWatcherTestimony(o.watcher);return y?{watcher:y}:{}})(),...typeof o.podGeneration=="number"&&Number.isFinite(o.podGeneration)?{podGeneration:o.podGeneration}:{}}:void 0)}catch{i(void 0)}})})}catch{i(void 0);return}s.on("timeout",()=>{s.destroy(),i(void 0)}),s.on("error",()=>i(void 0)),s.end()})}d(probePodAlive,"probePodAlive"),p(probePodAlive,"probePodAlive"),u(probePodAlive,"probePodAlive");async function podConnectionVerdict(t,e,c=types_1.POD_ALIVE_PROBE_TIMEOUT_MS){const n=e.code??"";return n==="ECONNREFUSED"||n==="ENOENT"?"gone":await podSocketAccepts(t,c)?"alive":"gone"}d(podConnectionVerdict,"podConnectionVerdict"),p(podConnectionVerdict,"podConnectionVerdict"),u(podConnectionVerdict,"podConnectionVerdict");function podSocketAccepts(t,e=types_1.POD_ALIVE_PROBE_TIMEOUT_MS){return new Promise(c=>{let n=!1,r;const i=u(a=>{n||(n=!0,clearTimeout(s),r?.destroy(),c(a))},"finish"),s=setTimeout(()=>i(!1),e);s.unref?.();try{r=net.connect({path:t}),r.once("connect",()=>i(!0)),r.once("error",()=>i(!1))}catch{i(!1)}})}d(podSocketAccepts,"podSocketAccepts"),p(podSocketAccepts,"podSocketAccepts"),u(podSocketAccepts,"podSocketAccepts");
1
+ "use strict";var h=Object.defineProperty;var p=(r,e)=>h(r,"name",{value:e,configurable:!0});var f=Object.defineProperty,u=p((r,e)=>f(r,"name",{value:e,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.parsePodWatcherTestimony=parsePodWatcherTestimony,exports.probePodAlive=probePodAlive,exports.podConnectionVerdict=podConnectionVerdict,exports.podSocketAccepts=podSocketAccepts;const tslib_1=require("tslib"),http=tslib_1.__importStar(require("node:http")),net=tslib_1.__importStar(require("node:net")),types_1=require("./types");function parsePodWatcherTestimony(r){if(!r||typeof r!="object")return;const e=r;if(e.schemaVersion!==1)return;const c=u(n=>typeof n=="number"&&Number.isFinite(n)?n:0,"num"),o=e.degraded;return{schemaVersion:1,lastWatchRunAt:c(e.lastWatchRunAt),lastBuildAt:c(e.lastBuildAt),buildsSinceSpawn:c(e.buildsSinceSpawn),degraded:typeof o=="string"&&o?o:o===!0?"degraded":!1,recentPaths:Array.isArray(e.recentPaths)?e.recentPaths.filter(n=>typeof n=="string").slice(-32):[]}}p(parsePodWatcherTestimony,"parsePodWatcherTestimony"),u(parsePodWatcherTestimony,"parsePodWatcherTestimony");async function probePodAlive(r,e=types_1.POD_ALIVE_PROBE_TIMEOUT_MS,c){return new Promise(o=>{let n=!1;const i=u(s=>{n||(n=!0,o(s))},"finish");let a;try{a=http.request({socketPath:r,path:types_1.POD_ALIVE_PATH,method:"GET",timeout:e,agent:!1,...c?{headers:{"x-internal-token":c}}:{}},s=>{if(s.statusCode!==200){s.resume(),i(void 0);return}let d="";s.setEncoding("utf8"),s.on("data",t=>{d+=t}),s.on("end",()=>{try{const t=JSON.parse(d);i(t.ok===!0?{inflight:Number(t.inflight??0),activeWork:Number(t.activeWork??0),swapping:t.swapping===!0,...typeof t.pid=="number"?{pid:t.pid}:{},...typeof t.keyFingerprint=="string"?{keyFingerprint:t.keyFingerprint}:{},...(()=>{const l=parsePodWatcherTestimony(t.watcher);return l?{watcher:l}:{}})(),...typeof t.podGeneration=="number"&&Number.isFinite(t.podGeneration)?{podGeneration:t.podGeneration}:{}}:void 0)}catch{i(void 0)}})})}catch{i(void 0);return}a.on("timeout",()=>{a.destroy(),i(void 0)}),a.on("error",()=>i(void 0)),a.end()})}p(probePodAlive,"probePodAlive"),u(probePodAlive,"probePodAlive");async function podConnectionVerdict(r,e,c=types_1.POD_ALIVE_PROBE_TIMEOUT_MS){const o=e.code??"";return o==="ECONNREFUSED"||o==="ENOENT"?"gone":await podSocketAccepts(r,c)?"alive":"gone"}p(podConnectionVerdict,"podConnectionVerdict"),u(podConnectionVerdict,"podConnectionVerdict");function podSocketAccepts(r,e=types_1.POD_ALIVE_PROBE_TIMEOUT_MS){return new Promise(c=>{let o=!1,n;const i=u(s=>{o||(o=!0,clearTimeout(a),n?.destroy(),c(s))},"finish"),a=setTimeout(()=>i(!1),e);a.unref?.();try{n=net.connect({path:r}),n.once("connect",()=>i(!0)),n.once("error",()=>i(!1))}catch{i(!1)}})}p(podSocketAccepts,"podSocketAccepts"),u(podSocketAccepts,"podSocketAccepts");
@@ -1 +1 @@
1
- "use strict";var Y=Object.defineProperty;var M=(t,a)=>Y(t,"name",{value:a,configurable:!0});var G=Object.defineProperty,P=M((t,a)=>G(t,"name",{value:a,configurable:!0}),"P"),K=Object.defineProperty,s=P((t,a)=>K(t,"name",{value:a,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isReplayableRequest=isReplayableRequest,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"),service_keys_1=require("./service-keys");function isConnError(t){const a=t.code??"";return a==="ECONNREFUSED"||a==="ECONNRESET"||a==="ETIMEDOUT"||a==="EPIPE"||a==="EHOSTUNREACH"||a==="ENOENT"||/ECONNREFUSED|ECONNRESET|socket hang up|EPIPE/i.test(t.message)}M(isConnError,"isConnError"),P(isConnError,"isConnError"),s(isConnError,"isConnError");const IDEMPOTENT_METHODS=new Set(["GET","HEAD","OPTIONS","PUT","DELETE","TRACE"]);function isReplayableRequest(t){if(!IDEMPOTENT_METHODS.has((t.method??"GET").toUpperCase())||t.headers["transfer-encoding"]!==void 0)return!1;const a=t.headers["content-length"];return!(a!==void 0&&String(a).trim()!=="0")}M(isReplayableRequest,"isReplayableRequest"),P(isReplayableRequest,"isReplayableRequest"),s(isReplayableRequest,"isReplayableRequest");function edgeGone(t,a){return a.headersSent||a.writableEnded||a.destroyed===!0||t.aborted===!0}M(edgeGone,"edgeGone"),P(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"],httpProxy=require("http-proxy");function declaredFirstByteMs(t){const a=Number(t);return Number.isFinite(a)&&a>0?a:types_1.POD_RESPONSE_TIMEOUT_MS}M(declaredFirstByteMs,"declaredFirstByteMs"),P(declaredFirstByteMs,"declaredFirstByteMs"),s(declaredFirstByteMs,"declaredFirstByteMs");function armFirstByteGuard(t){let a,w=0,x=!1,U=!1;const j=s(R=>{a=setTimeout(q,R),a.unref?.()},"arm"),q=s(()=>{if(!(x||!t.pending())){if(w+=t.firstByteMs,t.ceilingMs<=0||w>=t.ceilingMs){t.onWedged(`no response within ${w}ms (wedged socket) \u2014 evicted + respawning`);return}(0,pod_probe_1.probePodAlive)(t.socketPath,void 0,t.serviceKey).then(R=>{if(!(x||!t.pending())){if(!R){t.onWedged(`no response within ${w}ms and no answer on ${types_1.POD_ALIVE_PATH} (wedged socket) \u2014 evicted + respawning`);return}U||(U=!0,t.onSlow(w,R)),j(Math.max(t.firstByteMs,types_1.POD_ALIVE_PROBE_TIMEOUT_MS))}})}},"onDeadline");return j(t.firstByteMs),{clear:s(()=>{x=!0,a&&clearTimeout(a)},"clear")}}M(armFirstByteGuard,"armFirstByteGuard"),P(armFirstByteGuard,"armFirstByteGuard"),s(armFirstByteGuard,"armFirstByteGuard");function createProxy(t,a,w){const{recordEdge:x,finishTrace:U,traceStep:j,emit:q}=a,R=s(async e=>{if(!e.lens||!t.lensSupervisor)return"unsupported";let o;const r=new Promise(p=>{o=setTimeout(()=>p("timeout"),types_1.LENS_REQUEST_RECOVERY_WAIT_MS),o.unref?.()}),u=t.lensSupervisor.recover(e.lens,"proxy-connection").then(p=>p?"ready":"failed").catch(()=>"failed"),h=await Promise.race([u,r]);o&&clearTimeout(o);const m=t.lensSupervisor.status(e.lens);return h==="failed"&&(!m||m.state==="ready")?"unsupported":h},"waitForManagedRecovery"),C=s((e,o,r,u,h,m)=>{if(r.headersSent||r.writableEnded||r.destroyed){r.destroyed||r.destroy();return}const p=e.lens?t.lensSupervisor?.status(e.lens):void 0,E=m==="timeout"||p?.state==="starting"||p?.state==="replacing",_=(0,gateway_errors_1.ensureRequestId)(o),d=e.lens?{project:e.project,reason:p?.reason??"connection-failure",generation:p?.generation??0,...E?{retryAfterMs:2e3}:{}}:void 0,n=E?503:502,i=E?"starting":"unavailable";console.error(`[gateway] ${new Date().toISOString()} upstream-error traceId=${_} project=${e.project} target=${String(u)} state=${p?.state??"unmanaged"} generation=${p?.generation??0}: ${h.message}`),q("warning",`upstream unavailable: ${e.project}`,`cluster-upstream:${e.project}`,{kind:"upstream-error",traceId:_,project:e.project,target:String(u),state:p?.state??"unmanaged",generation:p?.generation,error:h.message}),(0,edge_1.sendError)(r,o,n,i,E?`Upstream ${e.project} is restarting.`:`Upstream ${e.project} unavailable.`,d,E?{"retry-after":"2"}:void 0)},"sendTerminalUpstreamError"),D=(0,body_stall_1.createBodyStallGuard)(t.bodyStallMs??types_1.BODY_STALL_MS),I={keepAlive:!0,keepAliveMsecs:3e4,maxSockets:1024,maxFreeSockets:256},A=new http.Agent(I),L=new(require("node:https")).Agent(I),N=s(e=>typeof e=="string"&&e.startsWith("https:")?L:A,"agentForTarget"),O=httpProxy.createProxyServer({xfwd:!1,secure:!1,proxyTimeout:12e4,agent:A}),B=s((e,o,r)=>{const u=s(()=>{r()||e.destroyed||e.destroy()},"onEdgeClose");o.once("close",u),e.once("close",()=>o.removeListener("close",u))},"propagateEdgeCancel");O.on("proxyReq",(e,o,r)=>{for(const u of UPSTREAM_CONNECTION_HEADERS)e.removeHeader(u);e.setHeader("connection","keep-alive"),B(e,r,()=>r.writableEnded)}),O.on("proxyRes",(e,o,r)=>{const u=o.__lensmcpPod;u&&(e.headers["x-lensmcp-pod"]=u),delete e.headers["x-powered-by"],e.headers.server="LensMCP",r&&B(e,r,()=>r.writableEnded),r&&D.armResponse(r)});const W=s((e,o,r,u)=>{(0,edge_1.stampForwardingHeaders)(t,o),D.arm(o);const h={},m=o.method==="GET"||o.method==="HEAD"||o.method==="OPTIONS";for(const[c,y]of Object.entries(o.headers))y===void 0||c.startsWith(":")||HOP_BY_HOP.has(c)||m&&(c==="content-length"||c==="transfer-encoding")||(h[c]=y);let p=http,E;if(typeof e=="object")E={socketPath:e.socketPath,path:o.url,method:o.method,headers:h,agent:A};else{const c=new URL(e),y=c.protocol==="https:";p=y?require("node:https"):http,h.host=c.host,E={protocol:c.protocol,hostname:c.hostname,port:c.port||(y?443:80),path:o.url,method:o.method,headers:h,agent:N(e)}}const _=r;_.__lensmcpErrContained||(_.__lensmcpErrContained=!0,r.on("error",()=>{}));let d;const n=s(()=>{r.writableEnded||g.destroy()},"onReqGone"),i=s(()=>{d&&!d.destroyed&&d.destroy()},"onEdgeClose"),l=s(()=>{o.removeListener("error",n),o.removeListener("aborted",n),o.removeListener("close",n),r.removeListener("close",i)},"detach"),g=p.request(E,c=>{if(d=c,u.onResponse(),r.headersSent||r.writableEnded||r.destroyed){c.destroy();return}const y={};for(const[v,f]of Object.entries(c.headers))f===void 0||HOP_BY_HOP.has(v)||(y[v]=f);delete y["x-powered-by"],y.server="LensMCP";const k=o.__lensmcpPod;k&&(y["x-lensmcp-pod"]=k);try{r.writeHead(c.statusCode??502,y)}catch(v){console.error("[gateway] h2 relay: bad response header, resetting stream:",v.message),c.destroy(),r.destroyed||r.destroy(v);return}c.pipe(r),D.armResponse(r);const b=s(()=>{!r.writableEnded&&!r.destroyed&&r.destroy()},"abortEdge");c.once("error",b),c.once("close",b),r.on("close",i)});g.once("error",c=>u.onError(c)),g.once("close",l),o.on("error",n),o.on("aborted",n),o.on("close",n),m?g.end():o.pipe(g)},"pipeUpstream"),H=s(async(e,o,r)=>{const u=o.__lensmcpTrace;if(e.pool){const d=e.svc;d&&(d.lastUsed=Date.now(),d.inflight+=1,r.on("close",()=>{d.inflight-=1,d.lastUsed=Date.now()}));let n=(0,discovery_1.pickSock)(e.pool,t.scanTtlMs);if(!n&&d&&(j(u,"cold-start",{project:e.project}),await w.ensureUp(d)&&(n=(0,discovery_1.pickSock)(e.pool,t.scanTtlMs))),d&&n&&w.markUp(d,"observed"),d&&w.scaleUp(d),!n){const f=d?.lastErrors?.length?` Service errors: ${d.lastErrors.join("; ")}`:"";(0,edge_1.sendError)(r,o,503,"unavailable",`Service ${e.project} is not reachable (no pods in ${e.pool.dir}).${f} The watcher recovers and the next request retries automatically.`);return}const i=path.basename(n,".sock");o.__lensmcpPod=i,j(u,"pod-select",{pod:i,pods:e.pool.socks.length,strategy:"round-robin"});let l=!1;const g=s(f=>{e.pool.socks=e.pool.socks.filter(S=>S!==n),e.pool.idx=-1;try{fs.unlinkSync(n)}catch{}console.error(`[gateway] pod ${i} of ${e.project}: ${f}`)},"evictPod"),c=armFirstByteGuard({socketPath:n,serviceKey:t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.svc?.wsKey,e.project)],firstByteMs:declaredFirstByteMs(e.svc?.decl?.firstByteMs),ceilingMs:types_1.POD_SLOW_FIRST_BYTE_MS,pending:s(()=>!l&&!r.headersSent&&!r.writableEnded,"pending"),onWedged:s(f=>{l=!0,g(f),(0,edge_1.sendError)(r,o,502,"unavailable",`Pod ${i} of ${e.project} was unresponsive \u2014 evicted, retry.`)},"onWedged"),onSlow:s((f,S)=>{console.log(`[gateway] pod ${i} of ${e.project}: slow first byte, pod alive (${f}ms, ${S.inflight} in-flight, ${S.activeWork} background) \u2014 waiting, not evicting. Set cluster.firstByteMs on ${e.project} to size this route's budget.`)},"onSlow")});r.on("close",()=>c.clear());const y=n,k=isReplayableRequest(o);let b=0;const v=s(()=>{b+=1,W({socketPath:y},o,r,{onResponse:s(()=>{c.clear(),l=!0},"onResponse"),onError:s(f=>{if(!l){if(edgeGone(o,r)){c.clear(),l=!0;return}(0,pod_probe_1.podConnectionVerdict)(y,f).then(S=>{if(!l){if(S==="alive"&&b<2&&k&&!edgeGone(o,r)){console.log(`[gateway] pod ${i} of ${e.project}: ${f.message} on one connection, the pod still accepts \u2014 sending the ${o.method} again on a fresh one`),v();return}if(c.clear(),l=!0,S==="gone"){g(f.message),(0,edge_1.sendError)(r,o,502,"unavailable",`Pod ${i} of ${e.project} unavailable \u2014 retry.`);return}console.error(`[gateway] pod ${i} of ${e.project}: ${f.message} on one connection \u2014 the pod still accepts connections, so it stays in the pool`),(0,edge_1.sendError)(r,o,502,"unavailable",`Pod ${i} of ${e.project} dropped the connection \u2014 retry.`)}})}},"onError")})},"sendToPod");v();return}const h=Date.now()+types_1.UPSTREAM_HEAL_WINDOW_MS;let m=0,p=!1;const E=isReplayableRequest(o),_=s(()=>{if(edgeGone(o,r))return;const d=e.target;W(d,o,r,{onResponse:s(()=>{},"onResponse"),onError:s(n=>{if(isConnError(n)&&(m+=1),e.lens&&isConnError(n)&&E&&m>=2&&!p&&!edgeGone(o,r)){p=!0,R(e).then(i=>{if(!edgeGone(o,r)){if(i==="ready"){_();return}if(i==="unsupported"&&Date.now()<h){setTimeout(_,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}C(e,o,r,e.target,n,i)}});return}if(isConnError(n)&&E&&Date.now()<h&&!edgeGone(o,r)){setTimeout(_,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}if(r.headersSent||r.writableEnded||r.destroyed){r.destroyed||r.destroy();return}C(e,o,r,d,n)},"onError")})},"tryTcp");_()},"forwardNative");return{proxy:O,forward:s(async(e,o,r)=>{const u=Date.now(),h=o.__lensmcpTrace;if(r.on("close",()=>{x(e,Date.now()-u,r.statusCode??0,o.__lensmcpCaller),U(h,e.project,r.statusCode??0,{...o.__lensmcpPod?{pod:o.__lensmcpPod}:{},...o.__lensmcpCaller?{caller:o.__lensmcpCaller}:{}},e)}),e.prependPrefix&&!o.url?.startsWith(e.prependPrefix)&&(o.url=e.prependPrefix+(o.url??"/")),(0,edge_1.stampForwardingHeaders)(t,o),D.arm(o),(o.httpVersionMajor??1)>=2){await H(e,o,r);return}if(e.pool){const n=e.svc;n&&(n.lastUsed=Date.now(),n.inflight+=1,r.on("close",()=>{n.inflight-=1,n.lastUsed=Date.now()}));let i=(0,discovery_1.pickSock)(e.pool,t.scanTtlMs);if(!i&&n&&(j(h,"cold-start",{project:e.project}),await w.ensureUp(n)&&(i=(0,discovery_1.pickSock)(e.pool,t.scanTtlMs))),n&&i&&w.markUp(n,"observed"),n&&w.scaleUp(n),!i){const T=n?.lastErrors?.length?` Service errors: ${n.lastErrors.join("; ")}`:"";(0,edge_1.sendError)(r,o,503,"unavailable",`Service ${e.project} is not reachable (no pods in ${e.pool.dir}).${T} The watcher recovers and the next request retries automatically.`);return}const l=path.basename(i,".sock");o.__lensmcpPod=l,j(h,"pod-select",{pod:l,pods:e.pool.socks.length,strategy:"round-robin"});let g=!1;const c=s(T=>{e.pool.socks=e.pool.socks.filter($=>$!==i),e.pool.idx=-1;try{fs.unlinkSync(i)}catch{}console.error(`[gateway] pod ${l} of ${e.project}: ${T}`)},"evictPod"),y=armFirstByteGuard({socketPath:i,serviceKey:t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.svc?.wsKey,e.project)],firstByteMs:declaredFirstByteMs(e.svc?.decl?.firstByteMs),ceilingMs:types_1.POD_SLOW_FIRST_BYTE_MS,pending:s(()=>!g&&!r.headersSent&&!r.writableEnded,"pending"),onWedged:s(T=>{g=!0,c(T),(0,edge_1.sendError)(r,o,502,"unavailable",`Pod ${l} of ${e.project} was unresponsive \u2014 evicted, retry.`)},"onWedged"),onSlow:s((T,$)=>{console.log(`[gateway] pod ${l} of ${e.project}: slow first byte, pod alive (${T}ms, ${$.inflight} in-flight, ${$.activeWork} background) \u2014 waiting, not evicting. Set cluster.firstByteMs on ${e.project} to size this route's budget.`)},"onSlow")});r.on("close",()=>y.clear());const k=Math.max(12e4,types_1.POD_SLOW_FIRST_BYTE_MS+6e4),b=i,v=isReplayableRequest(o);let f=0;const S=s(()=>{f+=1;const T=Date.now();O.web(o,r,{target:{socketPath:b},agent:A,proxyTimeout:k},$=>{if(!g){if(edgeGone(o,r)){y.clear(),g=!0;return}(0,pod_probe_1.podConnectionVerdict)(b,$).then(F=>{if(g)return;const V=Date.now()-T>=k-250;if(F==="alive"&&f<2&&v&&!V&&!edgeGone(o,r)){console.log(`[gateway] pod ${l} of ${e.project}: ${$.message} on one connection, the pod still accepts \u2014 sending the ${o.method} again on a fresh one`),S();return}if(y.clear(),g=!0,F==="gone"){c($.message),(0,edge_1.sendError)(r,o,502,"unavailable",`Pod ${l} of ${e.project} unavailable \u2014 retry.`);return}console.error(`[gateway] pod ${l} of ${e.project}: ${$.message} on one connection \u2014 the pod still accepts connections, so it stays in the pool`),(0,edge_1.sendError)(r,o,502,"unavailable",`Pod ${l} of ${e.project} dropped the connection \u2014 retry.`)})}})},"sendToPod");S();return}const m=Date.now()+types_1.UPSTREAM_HEAL_WINDOW_MS;let p=0,E=!1;const _=isReplayableRequest(o),d=s(()=>{if(edgeGone(o,r))return;const n=e.target,i={target:n,autoRewrite:typeof n=="string",changeOrigin:!0,agent:N(n)};O.web(o,r,i,l=>{if(isConnError(l)&&(p+=1),e.lens&&isConnError(l)&&_&&p>=2&&!E&&!edgeGone(o,r)){E=!0,R(e).then(g=>{if(!edgeGone(o,r)){if(g==="ready"){d();return}if(g==="unsupported"&&Date.now()<m){setTimeout(d,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}C(e,o,r,e.target,l,g)}});return}if(isConnError(l)&&_&&Date.now()<m&&!edgeGone(o,r)){setTimeout(d,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}r.destroyed||C(e,o,r,n,l)})},"tryTcp");d()},"forward"),agentForTarget:N,destroyAgents:s(()=>{D.stop(),A.destroy(),L.destroy()},"destroyAgents"),closeProxy:s(()=>{try{O.close?.()}catch{}},"closeProxy")}}M(createProxy,"createProxy"),P(createProxy,"createProxy"),s(createProxy,"createProxy");
1
+ "use strict";var G=Object.defineProperty;var P=(n,c)=>G(n,"name",{value:c,configurable:!0});var K=Object.defineProperty,s=P((n,c)=>K(n,"name",{value:c,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isReplayableRequest=isReplayableRequest,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"),service_keys_1=require("./service-keys");function isConnError(n){const c=n.code??"";return c==="ECONNREFUSED"||c==="ECONNRESET"||c==="ETIMEDOUT"||c==="EPIPE"||c==="EHOSTUNREACH"||c==="ENOENT"||/ECONNREFUSED|ECONNRESET|socket hang up|EPIPE/i.test(n.message)}P(isConnError,"isConnError"),s(isConnError,"isConnError");const IDEMPOTENT_METHODS=new Set(["GET","HEAD","OPTIONS","PUT","DELETE","TRACE"]);function isReplayableRequest(n){if(!IDEMPOTENT_METHODS.has((n.method??"GET").toUpperCase())||n.headers["transfer-encoding"]!==void 0)return!1;const c=n.headers["content-length"];return!(c!==void 0&&String(c).trim()!=="0")}P(isReplayableRequest,"isReplayableRequest"),s(isReplayableRequest,"isReplayableRequest");function edgeGone(n,c){return c.headersSent||c.writableEnded||c.destroyed===!0||n.aborted===!0}P(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"],httpProxy=require("http-proxy");function declaredFirstByteMs(n){const c=Number(n);return Number.isFinite(c)&&c>0?c:types_1.POD_RESPONSE_TIMEOUT_MS}P(declaredFirstByteMs,"declaredFirstByteMs"),s(declaredFirstByteMs,"declaredFirstByteMs");function armFirstByteGuard(n){let c,v=0,O=!1,A=!1;const M=s(k=>{c=setTimeout(C,k),c.unref?.()},"arm"),C=s(()=>{if(!(O||!n.pending())){if(v+=n.firstByteMs,n.ceilingMs<=0||v>=n.ceilingMs){n.onWedged(`no response within ${v}ms (wedged socket) \u2014 evicted + respawning`);return}(0,pod_probe_1.probePodAlive)(n.socketPath,void 0,n.serviceKey).then(k=>{if(!(O||!n.pending())){if(!k){n.onWedged(`no response within ${v}ms and no answer on ${types_1.POD_ALIVE_PATH} (wedged socket) \u2014 evicted + respawning`);return}A||(A=!0,n.onSlow(v,k)),M(Math.max(n.firstByteMs,types_1.POD_ALIVE_PROBE_TIMEOUT_MS))}})}},"onDeadline");return M(n.firstByteMs),{clear:s(()=>{O=!0,c&&clearTimeout(c)},"clear")}}P(armFirstByteGuard,"armFirstByteGuard"),s(armFirstByteGuard,"armFirstByteGuard");function createProxy(n,c,v){const{recordEdge:O,finishTrace:A,traceStep:M,emit:C}=c,k=s(async e=>{if(!e.lens||!n.lensSupervisor)return"unsupported";let r;const t=new Promise(p=>{r=setTimeout(()=>p("timeout"),types_1.LENS_REQUEST_RECOVERY_WAIT_MS),r.unref?.()}),u=n.lensSupervisor.recover(e.lens,"proxy-connection").then(p=>p?"ready":"failed").catch(()=>"failed"),h=await Promise.race([u,t]);r&&clearTimeout(r);const m=n.lensSupervisor.status(e.lens);return h==="failed"&&(!m||m.state==="ready")?"unsupported":h},"waitForManagedRecovery"),U=s((e,r,t,u,h,m)=>{if(t.headersSent||t.writableEnded||t.destroyed){t.destroyed||t.destroy();return}const p=e.lens?n.lensSupervisor?.status(e.lens):void 0,E=m==="timeout"||p?.state==="starting"||p?.state==="replacing",_=(0,gateway_errors_1.ensureRequestId)(r),d=e.lens?{project:e.project,reason:p?.reason??"connection-failure",generation:p?.generation??0,...E?{retryAfterMs:2e3}:{}}:void 0,o=E?503:502,a=E?"starting":"unavailable";console.error(`[gateway] ${new Date().toISOString()} upstream-error traceId=${_} project=${e.project} target=${String(u)} state=${p?.state??"unmanaged"} generation=${p?.generation??0}: ${h.message}`),C("warning",`upstream unavailable: ${e.project}`,`cluster-upstream:${e.project}`,{kind:"upstream-error",traceId:_,project:e.project,target:String(u),state:p?.state??"unmanaged",generation:p?.generation,error:h.message}),(0,edge_1.sendError)(t,r,o,a,E?`Upstream ${e.project} is restarting.`:`Upstream ${e.project} unavailable.`,d,E?{"retry-after":"2"}:void 0)},"sendTerminalUpstreamError"),x=(0,body_stall_1.createBodyStallGuard)(n.bodyStallMs??types_1.BODY_STALL_MS),I={keepAlive:!0,keepAliveMsecs:3e4,maxSockets:1024,maxFreeSockets:256},D=new http.Agent(I),q=new(require("node:https")).Agent(I),N=s(e=>typeof e=="string"&&e.startsWith("https:")?q:D,"agentForTarget"),R=httpProxy.createProxyServer({xfwd:!1,secure:!1,proxyTimeout:12e4,agent:D}),L=s((e,r,t)=>{const u=s(()=>{t()||e.destroyed||e.destroy()},"onEdgeClose");r.once("close",u),e.once("close",()=>r.removeListener("close",u))},"propagateEdgeCancel");R.on("proxyReq",(e,r,t)=>{for(const u of UPSTREAM_CONNECTION_HEADERS)e.removeHeader(u);e.setHeader("connection","keep-alive"),L(e,t,()=>t.writableEnded)}),R.on("proxyRes",(e,r,t)=>{const u=r.__lensmcpPod;u&&(e.headers["x-lensmcp-pod"]=u),delete e.headers["x-powered-by"],e.headers.server="LensMCP",t&&L(e,t,()=>t.writableEnded),t&&x.armResponse(t)});const B=s((e,r,t,u)=>{(0,edge_1.stampForwardingHeaders)(n,r),x.arm(r);const h={},m=r.method==="GET"||r.method==="HEAD"||r.method==="OPTIONS";for(const[i,y]of Object.entries(r.headers))y===void 0||i.startsWith(":")||HOP_BY_HOP.has(i)||m&&(i==="content-length"||i==="transfer-encoding")||(h[i]=y);let p=http,E;if(typeof e=="object")E={socketPath:e.socketPath,path:r.url,method:r.method,headers:h,agent:D};else{const i=new URL(e),y=i.protocol==="https:";p=y?require("node:https"):http,h.host=i.host,E={protocol:i.protocol,hostname:i.hostname,port:i.port||(y?443:80),path:r.url,method:r.method,headers:h,agent:N(e)}}const _=t;_.__lensmcpErrContained||(_.__lensmcpErrContained=!0,t.on("error",()=>{}));let d;const o=s(()=>{t.writableEnded||g.destroy()},"onReqGone"),a=s(()=>{d&&!d.destroyed&&d.destroy()},"onEdgeClose"),l=s(()=>{r.removeListener("error",o),r.removeListener("aborted",o),r.removeListener("close",o),t.removeListener("close",a)},"detach"),g=p.request(E,i=>{if(d=i,u.onResponse(),t.headersSent||t.writableEnded||t.destroyed){i.destroy();return}const y={};for(const[w,f]of Object.entries(i.headers))f===void 0||HOP_BY_HOP.has(w)||(y[w]=f);delete y["x-powered-by"],y.server="LensMCP";const j=r.__lensmcpPod;j&&(y["x-lensmcp-pod"]=j);try{t.writeHead(i.statusCode??502,y)}catch(w){console.error("[gateway] h2 relay: bad response header, resetting stream:",w.message),i.destroy(),t.destroyed||t.destroy(w);return}i.pipe(t),x.armResponse(t);const $=s(()=>{!t.writableEnded&&!t.destroyed&&t.destroy()},"abortEdge");i.once("error",$),i.once("close",$),t.on("close",a)});g.once("error",i=>u.onError(i)),g.once("close",l),r.on("error",o),r.on("aborted",o),r.on("close",o),m?g.end():r.pipe(g)},"pipeUpstream"),W=s(async(e,r,t)=>{const u=r.__lensmcpTrace;if(e.pool){const d=e.svc;d&&(d.lastUsed=Date.now(),d.inflight+=1,t.on("close",()=>{d.inflight-=1,d.lastUsed=Date.now()}));let o=(0,discovery_1.pickSock)(e.pool,n.scanTtlMs);if(!o&&d&&(M(u,"cold-start",{project:e.project}),await v.ensureUp(d)&&(o=(0,discovery_1.pickSock)(e.pool,n.scanTtlMs))),d&&o&&v.markUp(d,"observed"),d&&v.scaleUp(d),!o){const f=d?.lastErrors?.length?` Service errors: ${d.lastErrors.join("; ")}`:"";(0,edge_1.sendError)(t,r,503,"unavailable",`Service ${e.project} is not reachable (no pods in ${e.pool.dir}).${f} The watcher recovers and the next request retries automatically.`);return}const a=path.basename(o,".sock");r.__lensmcpPod=a,M(u,"pod-select",{pod:a,pods:e.pool.socks.length,strategy:"round-robin"});let l=!1;const g=s(f=>{e.pool.socks=e.pool.socks.filter(S=>S!==o),e.pool.idx=-1;try{fs.unlinkSync(o)}catch{}console.error(`[gateway] pod ${a} of ${e.project}: ${f}`)},"evictPod"),i=armFirstByteGuard({socketPath:o,serviceKey:n.serviceKeys[(0,service_keys_1.serviceKeyId)(e.svc?.wsKey,e.project)],firstByteMs:declaredFirstByteMs(e.svc?.decl?.firstByteMs),ceilingMs:types_1.POD_SLOW_FIRST_BYTE_MS,pending:s(()=>!l&&!t.headersSent&&!t.writableEnded,"pending"),onWedged:s(f=>{l=!0,g(f),(0,edge_1.sendError)(t,r,502,"unavailable",`Pod ${a} of ${e.project} was unresponsive \u2014 evicted, retry.`)},"onWedged"),onSlow:s((f,S)=>{console.log(`[gateway] pod ${a} of ${e.project}: slow first byte, pod alive (${f}ms, ${S.inflight} in-flight, ${S.activeWork} background) \u2014 waiting, not evicting. Set cluster.firstByteMs on ${e.project} to size this route's budget.`)},"onSlow")});t.on("close",()=>i.clear());const y=o,j=isReplayableRequest(r);let $=0;const w=s(()=>{$+=1,B({socketPath:y},r,t,{onResponse:s(()=>{i.clear(),l=!0},"onResponse"),onError:s(f=>{if(!l){if(edgeGone(r,t)){i.clear(),l=!0;return}(0,pod_probe_1.podConnectionVerdict)(y,f).then(S=>{if(!l){if(S==="alive"&&$<2&&j&&!edgeGone(r,t)){console.log(`[gateway] pod ${a} of ${e.project}: ${f.message} on one connection, the pod still accepts \u2014 sending the ${r.method} again on a fresh one`),w();return}if(i.clear(),l=!0,S==="gone"){g(f.message),(0,edge_1.sendError)(t,r,502,"unavailable",`Pod ${a} of ${e.project} unavailable \u2014 retry.`);return}console.error(`[gateway] pod ${a} of ${e.project}: ${f.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.`)}})}},"onError")})},"sendToPod");w();return}const h=Date.now()+types_1.UPSTREAM_HEAL_WINDOW_MS;let m=0,p=!1;const E=isReplayableRequest(r),_=s(()=>{if(edgeGone(r,t))return;const d=e.target;B(d,r,t,{onResponse:s(()=>{},"onResponse"),onError:s(o=>{if(isConnError(o)&&(m+=1),e.lens&&isConnError(o)&&E&&m>=2&&!p&&!edgeGone(r,t)){p=!0,k(e).then(a=>{if(!edgeGone(r,t)){if(a==="ready"){_();return}if(a==="unsupported"&&Date.now()<h){setTimeout(_,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}U(e,r,t,e.target,o,a)}});return}if(isConnError(o)&&E&&Date.now()<h&&!edgeGone(r,t)){setTimeout(_,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}if(t.headersSent||t.writableEnded||t.destroyed){t.destroyed||t.destroy();return}U(e,r,t,d,o)},"onError")})},"tryTcp");_()},"forwardNative");return{proxy:R,forward:s(async(e,r,t)=>{const u=Date.now(),h=r.__lensmcpTrace;if(t.on("close",()=>{O(e,Date.now()-u,t.statusCode??0,r.__lensmcpCaller),A(h,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)(n,r),x.arm(r),(r.httpVersionMajor??1)>=2){await W(e,r,t);return}if(e.pool){const o=e.svc;o&&(o.lastUsed=Date.now(),o.inflight+=1,t.on("close",()=>{o.inflight-=1,o.lastUsed=Date.now()}));let a=(0,discovery_1.pickSock)(e.pool,n.scanTtlMs);if(!a&&o&&(M(h,"cold-start",{project:e.project}),await v.ensureUp(o)&&(a=(0,discovery_1.pickSock)(e.pool,n.scanTtlMs))),o&&a&&v.markUp(o,"observed"),o&&v.scaleUp(o),!a){const T=o?.lastErrors?.length?` Service errors: ${o.lastErrors.join("; ")}`:"";(0,edge_1.sendError)(t,r,503,"unavailable",`Service ${e.project} is not reachable (no pods in ${e.pool.dir}).${T} The watcher recovers and the next request retries automatically.`);return}const l=path.basename(a,".sock");r.__lensmcpPod=l,M(h,"pod-select",{pod:l,pods:e.pool.socks.length,strategy:"round-robin"});let g=!1;const i=s(T=>{e.pool.socks=e.pool.socks.filter(b=>b!==a),e.pool.idx=-1;try{fs.unlinkSync(a)}catch{}console.error(`[gateway] pod ${l} of ${e.project}: ${T}`)},"evictPod"),y=armFirstByteGuard({socketPath:a,serviceKey:n.serviceKeys[(0,service_keys_1.serviceKeyId)(e.svc?.wsKey,e.project)],firstByteMs:declaredFirstByteMs(e.svc?.decl?.firstByteMs),ceilingMs:types_1.POD_SLOW_FIRST_BYTE_MS,pending:s(()=>!g&&!t.headersSent&&!t.writableEnded,"pending"),onWedged:s(T=>{g=!0,i(T),(0,edge_1.sendError)(t,r,502,"unavailable",`Pod ${l} of ${e.project} was unresponsive \u2014 evicted, retry.`)},"onWedged"),onSlow:s((T,b)=>{console.log(`[gateway] pod ${l} of ${e.project}: slow first byte, pod alive (${T}ms, ${b.inflight} in-flight, ${b.activeWork} background) \u2014 waiting, not evicting. Set cluster.firstByteMs on ${e.project} to size this route's budget.`)},"onSlow")});t.on("close",()=>y.clear());const j=Math.max(12e4,types_1.POD_SLOW_FIRST_BYTE_MS+6e4),$=a,w=isReplayableRequest(r);let f=0;const S=s(()=>{f+=1;const T=Date.now();R.web(r,t,{target:{socketPath:$},agent:D,proxyTimeout:j},b=>{if(!g){if(edgeGone(r,t)){y.clear(),g=!0;return}(0,pod_probe_1.podConnectionVerdict)($,b).then(H=>{if(g)return;const F=Date.now()-T>=j-250;if(H==="alive"&&f<2&&w&&!F&&!edgeGone(r,t)){console.log(`[gateway] pod ${l} of ${e.project}: ${b.message} on one connection, the pod still accepts \u2014 sending the ${r.method} again on a fresh one`),S();return}if(y.clear(),g=!0,H==="gone"){i(b.message),(0,edge_1.sendError)(t,r,502,"unavailable",`Pod ${l} of ${e.project} unavailable \u2014 retry.`);return}console.error(`[gateway] pod ${l} of ${e.project}: ${b.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 ${l} of ${e.project} dropped the connection \u2014 retry.`)})}})},"sendToPod");S();return}const m=Date.now()+types_1.UPSTREAM_HEAL_WINDOW_MS;let p=0,E=!1;const _=isReplayableRequest(r),d=s(()=>{if(edgeGone(r,t))return;const o=e.target,a={target:o,autoRewrite:typeof o=="string",changeOrigin:!0,agent:N(o)};R.web(r,t,a,l=>{if(isConnError(l)&&(p+=1),e.lens&&isConnError(l)&&_&&p>=2&&!E&&!edgeGone(r,t)){E=!0,k(e).then(g=>{if(!edgeGone(r,t)){if(g==="ready"){d();return}if(g==="unsupported"&&Date.now()<m){setTimeout(d,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}U(e,r,t,e.target,l,g)}});return}if(isConnError(l)&&_&&Date.now()<m&&!edgeGone(r,t)){setTimeout(d,types_1.UPSTREAM_HEAL_STEP_MS).unref?.();return}t.destroyed||U(e,r,t,o,l)})},"tryTcp");d()},"forward"),agentForTarget:N,destroyAgents:s(()=>{x.stop(),D.destroy(),q.destroy()},"destroyAgents"),closeProxy:s(()=>{try{R.close?.()}catch{}},"closeProxy")}}P(createProxy,"createProxy"),s(createProxy,"createProxy");
@@ -1 +1 @@
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
+ "use strict";var u=Object.defineProperty;var n=(t,e)=>u(t,"name",{value:e,configurable:!0});var 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{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 a=this.fragments.get(e);a&&a.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)}n(rebuildRoutesInPlace,"rebuildRoutesInPlace"),r(rebuildRoutesInPlace,"rebuildRoutesInPlace");