@lensmcp/cluster 1.25.8 → 1.25.9

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 (128) hide show
  1. package/basic-ssl.js +1 -1
  2. package/build-host.js +1 -1
  3. package/build-scope-patterns.js +1 -1
  4. package/bundle-parent.js +1 -1
  5. package/checkout-cache.js +1 -1
  6. package/create-webpack-dev.js +1 -1
  7. package/create-webpack-prod.js +1 -1
  8. package/dev-devtool.js +1 -1
  9. package/devserver-notifier.js +1 -1
  10. package/devserver-transport.js +1 -1
  11. package/error-stack-release.js +1 -1
  12. package/executors/build/build.impl.js +1 -1
  13. package/executors/gateway/body-stall.js +1 -1
  14. package/executors/gateway/canonical-path.js +1 -1
  15. package/executors/gateway/client-ip.js +1 -1
  16. package/executors/gateway/gateway-errors.js +1 -1
  17. package/executors/gateway/gateway.impl.js +1 -1
  18. package/executors/gateway/gateway.lib.js +1 -1
  19. package/executors/gateway/health-check.js +1 -1
  20. package/executors/gateway/jwks-verify.js +1 -1
  21. package/executors/gateway/jwt-claims.js +1 -1
  22. package/executors/gateway/main.prod-gateway.js +2 -2
  23. package/executors/gateway/main.rollout.js +4 -4
  24. package/executors/gateway/manifest.js +1 -1
  25. package/executors/gateway/metrics.js +1 -1
  26. package/executors/gateway/otel-tracing.js +1 -1
  27. package/executors/gateway/prod-config.js +1 -1
  28. package/executors/gateway/prod-gateway.lib.js +1 -1
  29. package/executors/gateway/prod-runtime/access-log.js +1 -1
  30. package/executors/gateway/prod-runtime/app.js +1 -1
  31. package/executors/gateway/prod-runtime/auth.js +1 -1
  32. package/executors/gateway/prod-runtime/body-stall.js +1 -1
  33. package/executors/gateway/prod-runtime/cors.js +1 -1
  34. package/executors/gateway/prod-runtime/edge.js +1 -1
  35. package/executors/gateway/prod-runtime/handler.js +1 -1
  36. package/executors/gateway/prod-runtime/hooks.js +1 -1
  37. package/executors/gateway/prod-runtime/observability.js +1 -1
  38. package/executors/gateway/prod-runtime/rollout.js +1 -1
  39. package/executors/gateway/prod-runtime/routing.js +1 -1
  40. package/executors/gateway/prod-runtime/server.js +1 -1
  41. package/executors/gateway/prod-runtime/trust.js +1 -1
  42. package/executors/gateway/prod-runtime/upgrade.js +7 -7
  43. package/executors/gateway/prod-runtime/upstream.js +1 -1
  44. package/executors/gateway/providers-prod.js +1 -1
  45. package/executors/gateway/rate-limit.js +2 -2
  46. package/executors/gateway/registry-source.js +1 -1
  47. package/executors/gateway/rollout-ops.js +2 -2
  48. package/executors/gateway/runtime/act.js +1 -1
  49. package/executors/gateway/runtime/auth.js +1 -1
  50. package/executors/gateway/runtime/chooser.js +12 -12
  51. package/executors/gateway/runtime/control.js +2 -2
  52. package/executors/gateway/runtime/dev-auth.js +1 -1
  53. package/executors/gateway/runtime/discovery.js +1 -1
  54. package/executors/gateway/runtime/edge.js +1 -1
  55. package/executors/gateway/runtime/guest-graph.js +2 -2
  56. package/executors/gateway/runtime/guest-replay.js +2 -2
  57. package/executors/gateway/runtime/handler.js +1 -1
  58. package/executors/gateway/runtime/hmr-reload.js +1 -1
  59. package/executors/gateway/runtime/hooks.js +1 -1
  60. package/executors/gateway/runtime/instance.js +2 -2
  61. package/executors/gateway/runtime/lens-children.js +1 -1
  62. package/executors/gateway/runtime/lifecycle.js +3 -3
  63. package/executors/gateway/runtime/observability.js +2 -2
  64. package/executors/gateway/runtime/own-log.js +3 -3
  65. package/executors/gateway/runtime/pod-env.js +2 -2
  66. package/executors/gateway/runtime/pod-output.js +1 -1
  67. package/executors/gateway/runtime/pod-probe.js +1 -1
  68. package/executors/gateway/runtime/process-names.js +1 -1
  69. package/executors/gateway/runtime/project-graph-store.js +1 -1
  70. package/executors/gateway/runtime/proxy.js +1 -1
  71. package/executors/gateway/runtime/registration-guards.js +1 -1
  72. package/executors/gateway/runtime/route-registry.js +1 -1
  73. package/executors/gateway/runtime/scope.js +1 -1
  74. package/executors/gateway/runtime/serve-launch.js +3 -3
  75. package/executors/gateway/runtime/server.js +2 -2
  76. package/executors/gateway/runtime/service-keys.js +1 -1
  77. package/executors/gateway/runtime/shared-build.js +4 -4
  78. package/executors/gateway/runtime/source-poller.js +1 -1
  79. package/executors/gateway/runtime/types.js +1 -1
  80. package/executors/gateway/runtime/upgrade.js +1 -1
  81. package/executors/gateway/runtime/workspace-log.js +1 -1
  82. package/executors/gateway/runtime/workspace-middleware.js +1 -1
  83. package/executors/gateway/runtime/workspace-registry.js +1 -1
  84. package/executors/gateway/ssrf-guard.js +1 -1
  85. package/executors/serve/serve.impl.js +1 -1
  86. package/executors/trust/hostname.js +1 -1
  87. package/executors/trust/trust.impl.js +3 -3
  88. package/exit-reason.js +2 -2
  89. package/fork-ts-check-reporter.js +1 -1
  90. package/gateway.js +1 -1
  91. package/gc-notice.js +1 -1
  92. package/graph-snapshot.js +1 -1
  93. package/handoff-retire.js +1 -1
  94. package/heap-snapshot.js +1 -1
  95. package/hot-swap-registries.js +1 -1
  96. package/index.js +1 -1
  97. package/inspector-secret.js +1 -1
  98. package/main.devserver.js +11 -11
  99. package/notice-generation.js +1 -1
  100. package/package.json +4 -4
  101. package/perf/heavy-barrel-import.js +1 -1
  102. package/perf/perf-config.js +1 -1
  103. package/perf/perf-rule-events.js +2 -2
  104. package/perf/perf-rules-analysis.js +1 -1
  105. package/perf/perf-rules-plugin.js +1 -1
  106. package/perf/source-scan.js +5 -5
  107. package/perf/workspace-libraries.js +2 -2
  108. package/pod-memory-events.js +2 -2
  109. package/pod-memory.js +1 -1
  110. package/pod-sock.js +1 -1
  111. package/process-name.js +1 -1
  112. package/redis-disconnect-fix.js +1 -1
  113. package/schema-first-instance.js +1 -1
  114. package/serve-runner.js +1 -1
  115. package/service-build-events.js +1 -1
  116. package/shared-build/attach.js +2 -2
  117. package/shared-build/host.js +3 -3
  118. package/shared-build/protocol.js +1 -1
  119. package/shared-build/shared-compilation.js +3 -3
  120. package/shared-build/signature.js +1 -1
  121. package/stdio-guard.js +1 -1
  122. package/swap-mode.js +1 -1
  123. package/swap-recycle.js +1 -1
  124. package/tsgo-check-plugin.js +4 -4
  125. package/typecheck-bus.js +3 -3
  126. package/typecheck-queue.js +1 -1
  127. package/worker-supervisor.js +2 -2
  128. package/workspace-paths.js +1 -1
@@ -1,16 +1,16 @@
1
- "use strict";var m=Object.defineProperty;var l=(a,t)=>m(a,"name",{value:t,configurable:!0});var b=Object.defineProperty,i=l((a,t)=>b(a,"name",{value:t,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isLoopbackRequest=isLoopbackRequest,exports.displayRoot=displayRoot,exports.renderChooserPage=renderChooserPage,exports.serveChooser=serveChooser;const node_os_1=require("node:os"),workspace_registry_1=require("./workspace-registry"),esc=i(a=>a.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t]),"esc");function isLoopbackRequest(a){const t=a.socket?.remoteAddress;if(!t)return!1;const o=t.startsWith("::ffff:")?t.slice(7):t;return o==="::1"||o==="127.0.0.1"||/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(o)}l(isLoopbackRequest,"isLoopbackRequest"),i(isLoopbackRequest,"isLoopbackRequest");function displayRoot(a,t=(0,node_os_1.homedir)()){const o=a.replace(/\/+$/,"").split("/").filter(Boolean),c=o.slice(-2).join("/");if(!c)return"/";const p=t!==""&&(a===t||a.startsWith(`${t}/`)),s=o.length>2;return p?s?`~/\u2026/${c}`:`~/${c}`:s?`\u2026/${c}`:`/${c}`}l(displayRoot,"displayRoot"),i(displayRoot,"displayRoot");function renderChooserPage(a,t){const o=a.map(e=>({...e,live:e.key===t||(0,workspace_registry_1.isWorkspaceLive)(e)})).sort((e,n)=>Number(n.live)-Number(e.live)||e.key.localeCompare(n.key)),c=new Set(o.map(e=>e.key)),p=i(e=>!!e.instance&&c.has(e.instance.baseKey),"nested"),s=o.filter(e=>!p(e)),x=i(e=>o.filter(n=>n.instance?.baseKey===e),"worktreesOf"),f=i(e=>e.key===t?'<span class="badge here">running here</span>':e.live?'<span class="badge live">live</span>':'<span class="badge off">offline</span>',"badgeOf"),h=i(e=>{const n=x(e);if(n.length===0)return"";const d=n.map(r=>{const g=`<span class="wt-name">${esc(r.instance?.name??r.key)}</span> ${f(r)}<span class="wt-apex">${esc(r.instance?.apex??"")}</span>`;return r.live?`<a class="wt is-live" href="${esc(r.base)}/">${g}<span class="open">Open \u2192</span></a>`:`<div class="wt is-off">${g}</div>`}).join(`
1
+ "use strict";var y=Object.defineProperty;var p=(o,t)=>y(o,"name",{value:t,configurable:!0});var m=Object.defineProperty,l=p((o,t)=>m(o,"name",{value:t,configurable:!0}),"l"),b=Object.defineProperty,i=l((o,t)=>b(o,"name",{value:t,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isLoopbackRequest=isLoopbackRequest,exports.displayRoot=displayRoot,exports.renderChooserPage=renderChooserPage,exports.serveChooser=serveChooser;const node_os_1=require("node:os"),workspace_registry_1=require("./workspace-registry"),esc=i(o=>o.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t]),"esc");function isLoopbackRequest(o){const t=o.socket?.remoteAddress;if(!t)return!1;const a=t.startsWith("::ffff:")?t.slice(7):t;return a==="::1"||a==="127.0.0.1"||/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(a)}p(isLoopbackRequest,"isLoopbackRequest"),l(isLoopbackRequest,"isLoopbackRequest"),i(isLoopbackRequest,"isLoopbackRequest");function displayRoot(o,t=(0,node_os_1.homedir)()){const a=o.replace(/\/+$/,"").split("/").filter(Boolean),c=a.slice(-2).join("/");if(!c)return"/";const d=t!==""&&(o===t||o.startsWith(`${t}/`)),r=a.length>2;return d?r?`~/\u2026/${c}`:`~/${c}`:r?`\u2026/${c}`:`/${c}`}p(displayRoot,"displayRoot"),l(displayRoot,"displayRoot"),i(displayRoot,"displayRoot");function renderChooserPage(o,t){const a=o.map(e=>({...e,live:e.key===t||(0,workspace_registry_1.isWorkspaceLive)(e)})).sort((e,n)=>Number(n.live)-Number(e.live)||e.key.localeCompare(n.key)),c=new Set(a.map(e=>e.key)),d=i(e=>!!e.instance&&c.has(e.instance.baseKey),"nested"),r=a.filter(e=>!d(e)),h=i(e=>a.filter(n=>n.instance?.baseKey===e),"worktreesOf"),g=i(e=>e.key===t?'<span class="badge here">running here</span>':e.live?'<span class="badge live">live</span>':'<span class="badge off">offline</span>',"badgeOf"),u=i(e=>{const n=h(e);if(n.length===0)return"";const f=n.map(s=>{const x=`<span class="wt-name">${esc(s.instance?.name??s.key)}</span> ${g(s)}<span class="wt-apex">${esc(s.instance?.apex??"")}</span>`;return s.live?`<a class="wt is-live" href="${esc(s.base)}/">${x}<span class="open">Open \u2192</span></a>`:`<div class="wt is-off">${x}</div>`}).join(`
2
2
  `);return`
3
- <div class="worktrees"><div class="wt-head">Worktrees \xB7 ${n.filter(r=>r.live).length} running</div>
4
- ${d}
5
- </div>`},"worktreeList"),u=s.length===0?'<p class="empty">No workspaces registered yet. Start a gateway in a workspace (<code>lensmcp gateway start</code>) and it will appear here.</p>':s.map(e=>{const n=e.live?'<span class="open">Open dashboard \u2192</span>':'<span class="hint">start its gateway to open</span>',d=e.instance?`<div class="root">worktree <b>${esc(e.instance.name)}</b> of ${esc(e.instance.baseKey)} \xB7 ${esc(e.instance.apex)}</div>`:"",r=`<div class="card-main">
6
- <div class="key">${esc(e.key)} ${f(e)}</div>
7
- <div class="root">${esc(displayRoot(e.root))}</div>${d}
3
+ <div class="worktrees"><div class="wt-head">Worktrees \xB7 ${n.filter(s=>s.live).length} running</div>
4
+ ${f}
5
+ </div>`},"worktreeList"),v=r.length===0?'<p class="empty">No workspaces registered yet. Start a gateway in a workspace (<code>lensmcp gateway start</code>) and it will appear here.</p>':r.map(e=>{const n=e.live?'<span class="open">Open dashboard \u2192</span>':'<span class="hint">start its gateway to open</span>',f=e.instance?`<div class="root">worktree <b>${esc(e.instance.name)}</b> of ${esc(e.instance.baseKey)} \xB7 ${esc(e.instance.apex)}</div>`:"",s=`<div class="card-main">
6
+ <div class="key">${esc(e.key)} ${g(e)}</div>
7
+ <div class="root">${esc(displayRoot(e.root))}</div>${f}
8
8
  </div>
9
9
  <div class="card-action">${n}</div>`;return`<div class="group">${e.live?`<a class="card is-live" href="${esc(e.base)}/">
10
- ${r}
10
+ ${s}
11
11
  </a>`:`<div class="card is-off">
12
- ${r}
13
- </div>`}${h(e.key)}</div>`}).join(`
12
+ ${s}
13
+ </div>`}${u(e.key)}</div>`}).join(`
14
14
  `);return`<!doctype html>
15
15
  <html lang="en"><head>
16
16
  <meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
@@ -55,10 +55,10 @@
55
55
  <body><div class="wrap">
56
56
  <header>
57
57
  <h1>LensMCP workspaces</h1>
58
- <p class="sub">Pick a workspace to open its dashboard. ${s.filter(e=>e.live).length} live \xB7 ${s.length} known${o.length>s.length?` \xB7 ${o.length-s.length} worktree${o.length-s.length===1?"":"s"}`:""}.</p>
58
+ <p class="sub">Pick a workspace to open its dashboard. ${r.filter(e=>e.live).length} live \xB7 ${r.length} known${a.length>r.length?` \xB7 ${a.length-r.length} worktree${a.length-r.length===1?"":"s"}`:""}.</p>
59
59
  </header>
60
60
  <div class="list">
61
- ${u}
61
+ ${v}
62
62
  </div>
63
63
  <footer>Served by the gateway on <code>lensmcp.local</code>. This list updates as gateways start and stop.</footer>
64
- </div></body></html>`}l(renderChooserPage,"renderChooserPage"),i(renderChooserPage,"renderChooserPage");function serveChooser(a,t,o){if(o&&!isLoopbackRequest(o)){a.writeHead(404,{"content-type":"text/plain; charset=utf-8","cache-control":"no-store"}),a.end("not found");return}const c=renderChooserPage((0,workspace_registry_1.readWorkspaces)(),t);a.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),a.end(c)}l(serveChooser,"serveChooser"),i(serveChooser,"serveChooser");
64
+ </div></body></html>`}p(renderChooserPage,"renderChooserPage"),l(renderChooserPage,"renderChooserPage"),i(renderChooserPage,"renderChooserPage");function serveChooser(o,t,a){if(a&&!isLoopbackRequest(a)){o.writeHead(404,{"content-type":"text/plain; charset=utf-8","cache-control":"no-store"}),o.end("not found");return}const c=renderChooserPage((0,workspace_registry_1.readWorkspaces)(),t);o.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),o.end(c)}p(serveChooser,"serveChooser"),l(serveChooser,"serveChooser"),i(serveChooser,"serveChooser");
@@ -1,2 +1,2 @@
1
- "use strict";var b=Object.defineProperty;var g=(s,r)=>b(s,"name",{value:r,configurable:!0});var G=Object.defineProperty,u=g((s,r)=>G(s,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.clusterVersion=void 0,exports.instanceSummary=instanceSummary,exports.controlSocketPath=controlSocketPath,exports.versionAtLoad=versionAtLoad,exports.readClusterVersion=readClusterVersion,exports.ensureOwnerOnlyDir=ensureOwnerOnlyDir,exports.startControlServer=startControlServer;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),guest_graph_1=require("./guest-graph"),guest_replay_1=require("./guest-replay"),registration_guards_1=require("./registration-guards"),scope_1=require("./scope"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),workspace_middleware_1=require("./workspace-middleware");function instanceSummary(s){const r=s?.instance;return r?{instance:r.name,baseKey:r.baseKey,apex:r.apex,baseApex:r.baseApex,...r.frozen?{frozen:!0}:{}}:{}}g(instanceSummary,"instanceSummary"),u(instanceSummary,"instanceSummary");function controlSocketPath(){const s=process.env.LENSMCP_HOME||os.homedir();return path.join(s,".lensmcp","control.sock")}g(controlSocketPath,"controlSocketPath"),u(controlSocketPath,"controlSocketPath");const CONTROL_BODY_BYTES=1e6;class BodyTooLarge extends Error{static{g(this,"BodyTooLarge")}static{u(this,"BodyTooLarge")}constructor(r){super(`body too large (over ${r} bytes)`),this.limit=r}}exports.clusterVersion=versionAtLoad(()=>readClusterVersion(__dirname));function versionAtLoad(s){const r=s();return()=>r}g(versionAtLoad,"versionAtLoad"),u(versionAtLoad,"versionAtLoad");function readClusterVersion(s){let r=s;for(let w=0;w<6;w++){const h=path.join(r,"package.json");if(fs.existsSync(h))try{const l=JSON.parse(fs.readFileSync(h,"utf8"));if(l.name==="@lensmcp/cluster"&&typeof l.version=="string")return l.version}catch{}const a=path.dirname(r);if(a===r)break;r=a}}g(readClusterVersion,"readClusterVersion"),u(readClusterVersion,"readClusterVersion");function readJsonBody(s,r=CONTROL_BODY_BYTES){return new Promise((w,h)=>{const a=[];let l=0,k=!1;s.on("data",m=>{if(!k){if(l+=m.length,l>r){k=!0,a.length=0,h(new BodyTooLarge(r));return}a.push(m)}}),s.on("end",()=>{if(k)return;const m=Buffer.concat(a).toString("utf8");try{w({value:m?JSON.parse(m):{},bytes:l})}catch(S){h(S)}}),s.on("error",h)})}g(readJsonBody,"readJsonBody"),u(readJsonBody,"readJsonBody");function graphShare(s,r){return r-Buffer.byteLength(JSON.stringify({...s,projectGraph:null}))}g(graphShare,"graphShare"),u(graphShare,"graphShare");function graphVerdict(s){return s?s.refused===void 0?{forwarded:!0,accepted:!0}:{forwarded:!0,accepted:!1,reason:s.refused}:{forwarded:!1,accepted:!1}}g(graphVerdict,"graphVerdict"),u(graphVerdict,"graphVerdict");function ensureOwnerOnlyDir(s){try{fs.mkdirSync(s,{recursive:!0,mode:448})}catch{}try{const r=fs.lstatSync(s);return r.isDirectory()?((r.mode&63)!==0&&fs.chmodSync(s,448),!0):!1}catch{return!1}}g(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),u(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function startControlServer(s){const{rt:r}=s,w=controlSocketPath(),h=path.dirname(w);ensureOwnerOnlyDir(h)||console.warn(`[gateway] control home ${h} is not a usable owner-only directory \u2014 refusing to expose the control plane there.`);try{fs.unlinkSync(w)}catch{}const a=u((e,n,i)=>{e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(i))},"send"),l=u(async(e,n)=>{if(!e.wsKey||!e.root)return{status:400,json:{error:"wsKey and root are required"}};const i=e.projects??{},t=(0,discovery_1.projectSourceRoots)(e.root,i,e.projectDependencies),o=(0,scope_1.readLensScope)(e.root),c=o.key===e.wsKey,y=c&&o.sockNs!==e.wsKey?o.sockNs:void 0,{routes:d,services:p,instance:f}=(0,discovery_1.discoverRoutes)(e.root,i,void 0,e.wsKey,t,y,c?o.instance:void 0),O=(0,workspace_middleware_1.findGatewayMiddleware)(e.root,i),$={wsKey:e.wsKey,...y?{sockNs:y}:{},root:e.root,routes:d,services:p,...f?{instance:f}:{},...O?{middleware:O}:{}},j=(0,registration_guards_1.refuseRegistration)(r.registry,$);if(j)return console.warn(`[gateway] refused to register '${e.wsKey}' from ${e.root}: ${j.error}`),{status:409,json:j};try{const v=(0,service_keys_1.adoptServiceKeys)(r,e.root,p,e.wsKey);v.added.length>0&&console.log(`[gateway] adopted east-west keys for ${e.wsKey}: ${v.added.join(", ")}`),v.regenerated.length>0&&console.warn(`[gateway] ${e.root} carried another workspace's east-west keys (a copied key file) \u2014 new keys for ${e.wsKey}: ${v.regenerated.join(", ")}`)}catch(v){console.error(`[gateway] could not adopt east-west keys for ${e.wsKey}: ${v.message}`)}try{(0,workspace_log_1.workspaceLogWriter)(e.root)?.(`[gateway] ${new Date().toISOString()} this workspace ('${e.wsKey}') is served by the daemon at ${r.root} (pid ${process.pid}); its gateway-level log is ${path.join(r.root,".lensmcp","gateway.log")}. Pod output for this workspace follows here. Attach live with \`lensmcp logs <service>\`.
2
- `)}catch{}let K;if(r.graphStores){const v={root:e.root,daemonRoot:r.root,otherRoots:r.registry.keys().filter(_=>_!==e.wsKey).flatMap(_=>r.registry.get(_)?.root??[])};K=e.projectGraph===void 0?void 0:(0,guest_graph_1.admitForwardedGraph)(e.projectGraph,{...v,bytes:graphShare(e,n)}),K?.refused!==void 0&&console.warn(`[gateway] refused the project graph '${e.wsKey}' forwarded from ${e.root}: ${K.refused} \u2014 its services start through \`nx run\` until the gateway computes it`),(0,registration_guards_1.sameRoot)(e.root,r.root)||r.graphStores.set((0,guest_graph_1.createGuestGraphStore)({wsKey:e.wsKey,root:e.root,...K?{admission:K}:{},context:v}))}return r.registry.register($),await s.onRegister?.($),r.rebuildRoutes(),r.root&&!(0,registration_guards_1.sameRoot)(e.root,r.root)&&(0,guest_replay_1.recordGuest)({wsKey:e.wsKey,root:e.root,projects:i,...e.projectDependencies?{projectDependencies:e.projectDependencies}:{},daemonRoot:r.root,registeredAt:new Date().toISOString()}),{status:200,json:{ok:!0,wsKey:e.wsKey,routes:d.length,services:p.length,workspaces:r.registry.keys(),...r.graphStores?{projectGraph:graphVerdict(K)}:{}}}},"register"),k=u((e,n)=>{const i=r.registry.get(e);if(!i)return{error:`no workspace '${e}' is registered`,workspaces:r.registry.keys()};const t=i.services.find(o=>o.project===n);return t?{svc:t}:{error:`'${e}' has no service '${n}'`,services:i.services.map(o=>o.project)}},"findService"),m=u(e=>({wsKey:e.wsKey,service:e.project,state:e.state,...e.generation!==void 0?{generation:e.generation}:{},...e.restart?{restart:e.restart}:{}}),"restartView"),S=http.createServer((e,n)=>{(async()=>{try{const i=(e.url??"").split("?")[0];if(e.method==="GET"&&i==="/list")return a(n,200,{workspaces:r.registry.keys().map(t=>{const o=r.registry.get(t);return{key:t,root:o?.root,routes:o?.routes.length??0,services:o?.services.length??0,...instanceSummary(o)}})});if(e.method==="GET"&&i==="/status"){const t=(0,exports.clusterVersion)();return a(n,200,{daemon:{pid:process.pid,wsKey:r.wsKey,...t?{version:t}:{}},workspaces:r.registry.keys().map(o=>{const c=r.registry.get(o);return{key:o,root:c?.root,routes:c?.routes.length??0,services:c?.services.length??0,isDaemon:o===r.wsKey,...instanceSummary(c)}}),services:r.registry.allServices().map(o=>({project:o.project,wsKey:o.wsKey,host:o.decl.host,state:o.state,...o.generation!==void 0?{generation:o.generation}:{},...o.restart?{restart:o.restart}:{}}))})}if(e.method==="GET"&&i==="/instance-env"){const t=new URL(e.url??"/","http://control").searchParams.get("wsKey")??"",o=r.registry.get(t);return o?o.instance?a(n,200,{wsKey:t,root:o.root,...instanceSummary(o),env:o.instance.env}):a(n,404,{error:`'${t}' is not an instance`}):a(n,404,{error:`no workspace '${t}' is registered`})}if(i==="/restart"&&(e.method==="POST"||e.method==="GET")){const t=e.method==="GET"?Object.fromEntries(new URL(e.url??"/","http://control").searchParams):(await readJsonBody(e)).value??{},o=typeof t.wsKey=="string"?t.wsKey:"",c=typeof t.service=="string"?t.service:"";if(!o||!c)return a(n,400,{error:"wsKey and service are required"});const y=k(o,c);if("error"in y)return a(n,404,y);const d=y.svc;if(e.method==="GET")return a(n,200,m(d));if(!s.restartService)return a(n,501,{error:"this gateway cannot restart a service"});const p=typeof t.reason=="string"&&t.reason.trim()?t.reason.trim().slice(0,200):"asked for",f=s.restartService(d,{hard:t.hard===!0,reason:p});return"refused"in f?a(n,409,{error:f.refused,...m(d)}):a(n,202,{ok:!0,already:f.already,...m(d)})}if(e.method==="GET"&&i==="/identities"||e.method==="POST"&&i==="/act"){const t=e.method==="GET"?Object.fromEntries(new URL(e.url??"/","http://control").searchParams):(await readJsonBody(e)).value??{},o=typeof t.wsKey=="string"?t.wsKey:"";if(!o)return a(n,400,{error:"wsKey is required"});if(!r.registry.get(o)&&o!==r.wsKey)return a(n,404,{error:`no workspace '${o}' is registered`,workspaces:r.registry.keys()});if(!s.act)return a(n,501,{error:"acting as a signed-in user is turned off on this gateway (LENSMCP_GW_ACT=0)"});if(e.method==="GET")return a(n,200,{wsKey:o,identities:s.act.list(o)});const c=u(f=>typeof t[f]=="string"&&t[f].trim()?t[f].trim().slice(0,256):void 0,"pick"),y=c("user"),d=c("tenant"),p=s.act.mint(o,{...y?{user:y}:{},...d?{tenant:d}:{}});return"error"in p?a(n,404,{wsKey:o,...p}):a(n,200,{wsKey:o,...p})}if(e.method==="POST"&&i==="/register"){const{value:t,bytes:o}=await readJsonBody(e,CONTROL_BODY_BYTES+guest_graph_1.MAX_FORWARDED_GRAPH_BYTES),c=await l(t,o);return a(n,c.status,c.json)}if(e.method==="POST"&&i==="/unregister"){const t=(await readJsonBody(e)).value;if(!t.wsKey)return a(n,400,{error:"wsKey is required"});const o=(0,registration_guards_1.refuseUnregistration)(r.registry,{wsKey:t.wsKey,...t.root?{root:t.root}:{}},r.wsKey);if(o)return console.warn(`[gateway] refused to unregister '${t.wsKey}'${t.root?` for ${t.root}`:""}: ${o.error}`),a(n,409,o);const c=r.registry.unregister(t.wsKey);if(c){for(const y of c.services){const d=(0,service_keys_1.serviceKeyId)(y.wsKey??t.wsKey,y.project),p=r.serviceKeys[d];p&&(delete r.serviceKeys[d],r.keyToProject.delete(p),r.keyToWorkspace?.delete(p))}for(const y of c.services)s.killService(y,"workspace unregistered");r.graphStores?.delete(c.root),(0,guest_replay_1.forgetGuest)(t.wsKey),s.onUnregister?.(c)}return r.rebuildRoutes(),a(n,200,{ok:!0,removed:!!c,workspaces:r.registry.keys()})}a(n,404,{error:"not found"})}catch(i){if(i instanceof BodyTooLarge)return e.resume(),a(n,413,{error:i.message});a(n,500,{error:i.message})}})()});return S.listen(w,()=>{try{fs.chmodSync(w,384)}catch(e){console.warn(`[gateway] could not restrict ${w} to 0600:`,e.message)}}),{socketPath:w,async replay(){const{replay:e,gone:n}=(0,guest_replay_1.guestsToReplay)(r.root,(0,guest_replay_1.readGuests)()),i={replayed:[],refused:[],gone:n.map(t=>t.wsKey)};for(const t of n)(0,guest_replay_1.forgetGuest)(t.wsKey),console.log(`[gateway] not re-hosting '${t.wsKey}': ${t.root} is no longer a workspace \u2014 forgotten`);for(const t of e)if(!r.registry.has(t.wsKey))try{const o=await l({wsKey:t.wsKey,root:t.root,projects:t.projects,...t.projectDependencies?{projectDependencies:t.projectDependencies}:{}},0);o.status===200?(i.replayed.push(t.wsKey),console.log(`[gateway] re-hosted '${t.wsKey}' (${t.root}) \u2014 registered before this daemon restarted`)):(i.refused.push(t.wsKey),console.warn(`[gateway] could not re-host '${t.wsKey}' (${t.root}): ${JSON.stringify(o.json)} \u2014 \`lensmcp gateway start\` there`))}catch(o){i.refused.push(t.wsKey),console.warn(`[gateway] could not re-host '${t.wsKey}' (${t.root}): ${o.message}`)}return i},close:u(()=>{S.close();try{fs.unlinkSync(w)}catch{}},"close")}}g(startControlServer,"startControlServer"),u(startControlServer,"startControlServer");
1
+ "use strict";var P=Object.defineProperty;var l=(s,r)=>P(s,"name",{value:r,configurable:!0});var b=Object.defineProperty,g=l((s,r)=>b(s,"name",{value:r,configurable:!0}),"g"),G=Object.defineProperty,u=g((s,r)=>G(s,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.clusterVersion=void 0,exports.instanceSummary=instanceSummary,exports.controlSocketPath=controlSocketPath,exports.versionAtLoad=versionAtLoad,exports.readClusterVersion=readClusterVersion,exports.ensureOwnerOnlyDir=ensureOwnerOnlyDir,exports.startControlServer=startControlServer;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),guest_graph_1=require("./guest-graph"),guest_replay_1=require("./guest-replay"),registration_guards_1=require("./registration-guards"),scope_1=require("./scope"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),workspace_middleware_1=require("./workspace-middleware");function instanceSummary(s){const r=s?.instance;return r?{instance:r.name,baseKey:r.baseKey,apex:r.apex,baseApex:r.baseApex,...r.frozen?{frozen:!0}:{}}:{}}l(instanceSummary,"instanceSummary"),g(instanceSummary,"instanceSummary"),u(instanceSummary,"instanceSummary");function controlSocketPath(){const s=process.env.LENSMCP_HOME||os.homedir();return path.join(s,".lensmcp","control.sock")}l(controlSocketPath,"controlSocketPath"),g(controlSocketPath,"controlSocketPath"),u(controlSocketPath,"controlSocketPath");const CONTROL_BODY_BYTES=1e6;class BodyTooLarge extends Error{static{l(this,"BodyTooLarge")}static{g(this,"BodyTooLarge")}static{u(this,"BodyTooLarge")}constructor(r){super(`body too large (over ${r} bytes)`),this.limit=r}}exports.clusterVersion=versionAtLoad(()=>readClusterVersion(__dirname));function versionAtLoad(s){const r=s();return()=>r}l(versionAtLoad,"versionAtLoad"),g(versionAtLoad,"versionAtLoad"),u(versionAtLoad,"versionAtLoad");function readClusterVersion(s){let r=s;for(let w=0;w<6;w++){const m=path.join(r,"package.json");if(fs.existsSync(m))try{const f=JSON.parse(fs.readFileSync(m,"utf8"));if(f.name==="@lensmcp/cluster"&&typeof f.version=="string")return f.version}catch{}const a=path.dirname(r);if(a===r)break;r=a}}l(readClusterVersion,"readClusterVersion"),g(readClusterVersion,"readClusterVersion"),u(readClusterVersion,"readClusterVersion");function readJsonBody(s,r=CONTROL_BODY_BYTES){return new Promise((w,m)=>{const a=[];let f=0,S=!1;s.on("data",v=>{if(!S){if(f+=v.length,f>r){S=!0,a.length=0,m(new BodyTooLarge(r));return}a.push(v)}}),s.on("end",()=>{if(S)return;const v=Buffer.concat(a).toString("utf8");try{w({value:v?JSON.parse(v):{},bytes:f})}catch(j){m(j)}}),s.on("error",m)})}l(readJsonBody,"readJsonBody"),g(readJsonBody,"readJsonBody"),u(readJsonBody,"readJsonBody");function graphShare(s,r){return r-Buffer.byteLength(JSON.stringify({...s,projectGraph:null}))}l(graphShare,"graphShare"),g(graphShare,"graphShare"),u(graphShare,"graphShare");function graphVerdict(s){return s?s.refused===void 0?{forwarded:!0,accepted:!0}:{forwarded:!0,accepted:!1,reason:s.refused}:{forwarded:!1,accepted:!1}}l(graphVerdict,"graphVerdict"),g(graphVerdict,"graphVerdict"),u(graphVerdict,"graphVerdict");function ensureOwnerOnlyDir(s){try{fs.mkdirSync(s,{recursive:!0,mode:448})}catch{}try{const r=fs.lstatSync(s);return r.isDirectory()?((r.mode&63)!==0&&fs.chmodSync(s,448),!0):!1}catch{return!1}}l(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),g(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),u(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function startControlServer(s){const{rt:r}=s,w=controlSocketPath(),m=path.dirname(w);ensureOwnerOnlyDir(m)||console.warn(`[gateway] control home ${m} is not a usable owner-only directory \u2014 refusing to expose the control plane there.`);try{fs.unlinkSync(w)}catch{}const a=u((e,n,i)=>{e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(i))},"send"),f=u(async(e,n)=>{if(!e.wsKey||!e.root)return{status:400,json:{error:"wsKey and root are required"}};const i=e.projects??{},t=(0,discovery_1.projectSourceRoots)(e.root,i,e.projectDependencies),o=(0,scope_1.readLensScope)(e.root),c=o.key===e.wsKey,y=c&&o.sockNs!==e.wsKey?o.sockNs:void 0,{routes:d,services:p,instance:h}=(0,discovery_1.discoverRoutes)(e.root,i,void 0,e.wsKey,t,y,c?o.instance:void 0),T=(0,workspace_middleware_1.findGatewayMiddleware)(e.root,i),$={wsKey:e.wsKey,...y?{sockNs:y}:{},root:e.root,routes:d,services:p,...h?{instance:h}:{},...T?{middleware:T}:{}},_=(0,registration_guards_1.refuseRegistration)(r.registry,$);if(_)return console.warn(`[gateway] refused to register '${e.wsKey}' from ${e.root}: ${_.error}`),{status:409,json:_};try{const K=(0,service_keys_1.adoptServiceKeys)(r,e.root,p,e.wsKey);K.added.length>0&&console.log(`[gateway] adopted east-west keys for ${e.wsKey}: ${K.added.join(", ")}`),K.regenerated.length>0&&console.warn(`[gateway] ${e.root} carried another workspace's east-west keys (a copied key file) \u2014 new keys for ${e.wsKey}: ${K.regenerated.join(", ")}`)}catch(K){console.error(`[gateway] could not adopt east-west keys for ${e.wsKey}: ${K.message}`)}try{(0,workspace_log_1.workspaceLogWriter)(e.root)?.(`[gateway] ${new Date().toISOString()} this workspace ('${e.wsKey}') is served by the daemon at ${r.root} (pid ${process.pid}); its gateway-level log is ${path.join(r.root,".lensmcp","gateway.log")}. Pod output for this workspace follows here. Attach live with \`lensmcp logs <service>\`.
2
+ `)}catch{}let k;if(r.graphStores){const K={root:e.root,daemonRoot:r.root,otherRoots:r.registry.keys().filter(O=>O!==e.wsKey).flatMap(O=>r.registry.get(O)?.root??[])};k=e.projectGraph===void 0?void 0:(0,guest_graph_1.admitForwardedGraph)(e.projectGraph,{...K,bytes:graphShare(e,n)}),k?.refused!==void 0&&console.warn(`[gateway] refused the project graph '${e.wsKey}' forwarded from ${e.root}: ${k.refused} \u2014 its services start through \`nx run\` until the gateway computes it`),(0,registration_guards_1.sameRoot)(e.root,r.root)||r.graphStores.set((0,guest_graph_1.createGuestGraphStore)({wsKey:e.wsKey,root:e.root,...k?{admission:k}:{},context:K}))}return r.registry.register($),await s.onRegister?.($),r.rebuildRoutes(),r.root&&!(0,registration_guards_1.sameRoot)(e.root,r.root)&&(0,guest_replay_1.recordGuest)({wsKey:e.wsKey,root:e.root,projects:i,...e.projectDependencies?{projectDependencies:e.projectDependencies}:{},daemonRoot:r.root,registeredAt:new Date().toISOString()}),{status:200,json:{ok:!0,wsKey:e.wsKey,routes:d.length,services:p.length,workspaces:r.registry.keys(),...r.graphStores?{projectGraph:graphVerdict(k)}:{}}}},"register"),S=u((e,n)=>{const i=r.registry.get(e);if(!i)return{error:`no workspace '${e}' is registered`,workspaces:r.registry.keys()};const t=i.services.find(o=>o.project===n);return t?{svc:t}:{error:`'${e}' has no service '${n}'`,services:i.services.map(o=>o.project)}},"findService"),v=u(e=>({wsKey:e.wsKey,service:e.project,state:e.state,...e.generation!==void 0?{generation:e.generation}:{},...e.restart?{restart:e.restart}:{}}),"restartView"),j=http.createServer((e,n)=>{(async()=>{try{const i=(e.url??"").split("?")[0];if(e.method==="GET"&&i==="/list")return a(n,200,{workspaces:r.registry.keys().map(t=>{const o=r.registry.get(t);return{key:t,root:o?.root,routes:o?.routes.length??0,services:o?.services.length??0,...instanceSummary(o)}})});if(e.method==="GET"&&i==="/status"){const t=(0,exports.clusterVersion)();return a(n,200,{daemon:{pid:process.pid,wsKey:r.wsKey,...t?{version:t}:{}},workspaces:r.registry.keys().map(o=>{const c=r.registry.get(o);return{key:o,root:c?.root,routes:c?.routes.length??0,services:c?.services.length??0,isDaemon:o===r.wsKey,...instanceSummary(c)}}),services:r.registry.allServices().map(o=>({project:o.project,wsKey:o.wsKey,host:o.decl.host,state:o.state,...o.generation!==void 0?{generation:o.generation}:{},...o.restart?{restart:o.restart}:{}}))})}if(e.method==="GET"&&i==="/instance-env"){const t=new URL(e.url??"/","http://control").searchParams.get("wsKey")??"",o=r.registry.get(t);return o?o.instance?a(n,200,{wsKey:t,root:o.root,...instanceSummary(o),env:o.instance.env}):a(n,404,{error:`'${t}' is not an instance`}):a(n,404,{error:`no workspace '${t}' is registered`})}if(i==="/restart"&&(e.method==="POST"||e.method==="GET")){const t=e.method==="GET"?Object.fromEntries(new URL(e.url??"/","http://control").searchParams):(await readJsonBody(e)).value??{},o=typeof t.wsKey=="string"?t.wsKey:"",c=typeof t.service=="string"?t.service:"";if(!o||!c)return a(n,400,{error:"wsKey and service are required"});const y=S(o,c);if("error"in y)return a(n,404,y);const d=y.svc;if(e.method==="GET")return a(n,200,v(d));if(!s.restartService)return a(n,501,{error:"this gateway cannot restart a service"});const p=typeof t.reason=="string"&&t.reason.trim()?t.reason.trim().slice(0,200):"asked for",h=s.restartService(d,{hard:t.hard===!0,reason:p});return"refused"in h?a(n,409,{error:h.refused,...v(d)}):a(n,202,{ok:!0,already:h.already,...v(d)})}if(e.method==="GET"&&i==="/identities"||e.method==="POST"&&i==="/act"){const t=e.method==="GET"?Object.fromEntries(new URL(e.url??"/","http://control").searchParams):(await readJsonBody(e)).value??{},o=typeof t.wsKey=="string"?t.wsKey:"";if(!o)return a(n,400,{error:"wsKey is required"});if(!r.registry.get(o)&&o!==r.wsKey)return a(n,404,{error:`no workspace '${o}' is registered`,workspaces:r.registry.keys()});if(!s.act)return a(n,501,{error:"acting as a signed-in user is turned off on this gateway (LENSMCP_GW_ACT=0)"});if(e.method==="GET")return a(n,200,{wsKey:o,identities:s.act.list(o)});const c=u(h=>typeof t[h]=="string"&&t[h].trim()?t[h].trim().slice(0,256):void 0,"pick"),y=c("user"),d=c("tenant"),p=s.act.mint(o,{...y?{user:y}:{},...d?{tenant:d}:{}});return"error"in p?a(n,404,{wsKey:o,...p}):a(n,200,{wsKey:o,...p})}if(e.method==="POST"&&i==="/register"){const{value:t,bytes:o}=await readJsonBody(e,CONTROL_BODY_BYTES+guest_graph_1.MAX_FORWARDED_GRAPH_BYTES),c=await f(t,o);return a(n,c.status,c.json)}if(e.method==="POST"&&i==="/unregister"){const t=(await readJsonBody(e)).value;if(!t.wsKey)return a(n,400,{error:"wsKey is required"});const o=(0,registration_guards_1.refuseUnregistration)(r.registry,{wsKey:t.wsKey,...t.root?{root:t.root}:{}},r.wsKey);if(o)return console.warn(`[gateway] refused to unregister '${t.wsKey}'${t.root?` for ${t.root}`:""}: ${o.error}`),a(n,409,o);const c=r.registry.unregister(t.wsKey);if(c){for(const y of c.services){const d=(0,service_keys_1.serviceKeyId)(y.wsKey??t.wsKey,y.project),p=r.serviceKeys[d];p&&(delete r.serviceKeys[d],r.keyToProject.delete(p),r.keyToWorkspace?.delete(p))}for(const y of c.services)s.killService(y,"workspace unregistered");r.graphStores?.delete(c.root),(0,guest_replay_1.forgetGuest)(t.wsKey),s.onUnregister?.(c)}return r.rebuildRoutes(),a(n,200,{ok:!0,removed:!!c,workspaces:r.registry.keys()})}a(n,404,{error:"not found"})}catch(i){if(i instanceof BodyTooLarge)return e.resume(),a(n,413,{error:i.message});a(n,500,{error:i.message})}})()});return j.listen(w,()=>{try{fs.chmodSync(w,384)}catch(e){console.warn(`[gateway] could not restrict ${w} to 0600:`,e.message)}}),{socketPath:w,async replay(){const{replay:e,gone:n}=(0,guest_replay_1.guestsToReplay)(r.root,(0,guest_replay_1.readGuests)()),i={replayed:[],refused:[],gone:n.map(t=>t.wsKey)};for(const t of n)(0,guest_replay_1.forgetGuest)(t.wsKey),console.log(`[gateway] not re-hosting '${t.wsKey}': ${t.root} is no longer a workspace \u2014 forgotten`);for(const t of e)if(!r.registry.has(t.wsKey))try{const o=await f({wsKey:t.wsKey,root:t.root,projects:t.projects,...t.projectDependencies?{projectDependencies:t.projectDependencies}:{}},0);o.status===200?(i.replayed.push(t.wsKey),console.log(`[gateway] re-hosted '${t.wsKey}' (${t.root}) \u2014 registered before this daemon restarted`)):(i.refused.push(t.wsKey),console.warn(`[gateway] could not re-host '${t.wsKey}' (${t.root}): ${JSON.stringify(o.json)} \u2014 \`lensmcp gateway start\` there`))}catch(o){i.refused.push(t.wsKey),console.warn(`[gateway] could not re-host '${t.wsKey}' (${t.root}): ${o.message}`)}return i},close:u(()=>{j.close();try{fs.unlinkSync(w)}catch{}},"close")}}l(startControlServer,"startControlServer"),g(startControlServer,"startControlServer"),u(startControlServer,"startControlServer");
@@ -1 +1 @@
1
- "use strict";var h=Object.defineProperty;var a=(e,r)=>h(e,"name",{value:r,configurable:!0});var l=Object.defineProperty,u=a((e,r)=>l(e,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.devAttrs=void 0,exports.verifyDevJwt=verifyDevJwt,exports.stampIdentity=stampIdentity;const node_crypto_1=require("node:crypto"),edge_1=require("./edge");function bearerToken(e){const r=Array.isArray(e.headers.authorization)?e.headers.authorization[0]:e.headers.authorization,t=String(r??"");return t.startsWith("Bearer ")?t.slice(7):void 0}a(bearerToken,"bearerToken"),u(bearerToken,"bearerToken");function verifyDevJwt(e,r){const t=bearerToken(e);if(!t)return;const[s,n,f]=t.split(".");if(!s||!n||!f)return;if(r)return r.verify(t);let o;try{o=JSON.parse(Buffer.from(s,"base64url").toString()).alg}catch{return}if(typeof o=="string"&&o!=="HS256"){if(process.env.LENSMCP_GW_DEV_JWT_INSECURE_DECODE!=="1")return;try{const i=JSON.parse(Buffer.from(n,"base64url").toString());return typeof i.exp=="number"&&Date.now()/1e3>i.exp?void 0:i}catch{return}}const d=process.env.AUTH_JWT_SECRET??"tetros-dev-secret",y=(0,node_crypto_1.createHmac)("sha256",d).update(`${s}.${n}`).digest("base64url"),p=Buffer.from(f),c=Buffer.from(y);if(!(p.length!==c.length||!(0,node_crypto_1.timingSafeEqual)(p,c)))try{const i=JSON.parse(Buffer.from(n,"base64url").toString());return typeof i.exp=="number"&&Date.now()/1e3>i.exp?void 0:i}catch{return}}a(verifyDevJwt,"verifyDevJwt"),u(verifyDevJwt,"verifyDevJwt");function stampIdentity(e,r){const t=u((f,o)=>{o!=null&&o!==""&&(e.headers[f]=String(o))},"set");t("x-user-id",r.sub),t("x-tenant-id",r.tid);const s=r.roles;Array.isArray(s)&&s.length&&(e.headers["x-user-roles"]=s.map(String).join(","));const n=r.perms;Array.isArray(n)&&n.length&&(e.headers["x-user-permissions"]=n.map(String).join(","))}a(stampIdentity,"stampIdentity"),u(stampIdentity,"stampIdentity");const devAttrs=u((e,r,t)=>({...r,ip:(0,edge_1.clientIpOf)(e),method:(e.method??"GET").toUpperCase(),path:t??(0,edge_1.canonicalPath)(e.url??"/")??(e.url??"/").split("?")[0]}),"devAttrs");exports.devAttrs=devAttrs;
1
+ "use strict";var m=Object.defineProperty;var f=(e,r)=>m(e,"name",{value:r,configurable:!0});var h=Object.defineProperty,a=f((e,r)=>h(e,"name",{value:r,configurable:!0}),"a"),l=Object.defineProperty,u=a((e,r)=>l(e,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.devAttrs=void 0,exports.verifyDevJwt=verifyDevJwt,exports.stampIdentity=stampIdentity;const node_crypto_1=require("node:crypto"),edge_1=require("./edge");function bearerToken(e){const r=Array.isArray(e.headers.authorization)?e.headers.authorization[0]:e.headers.authorization,t=String(r??"");return t.startsWith("Bearer ")?t.slice(7):void 0}f(bearerToken,"bearerToken"),a(bearerToken,"bearerToken"),u(bearerToken,"bearerToken");function verifyDevJwt(e,r){const t=bearerToken(e);if(!t)return;const[s,n,p]=t.split(".");if(!s||!n||!p)return;if(r)return r.verify(t);let i;try{i=JSON.parse(Buffer.from(s,"base64url").toString()).alg}catch{return}if(typeof i=="string"&&i!=="HS256"){if(process.env.LENSMCP_GW_DEV_JWT_INSECURE_DECODE!=="1")return;try{const o=JSON.parse(Buffer.from(n,"base64url").toString());return typeof o.exp=="number"&&Date.now()/1e3>o.exp?void 0:o}catch{return}}const y=process.env.AUTH_JWT_SECRET??"tetros-dev-secret",v=(0,node_crypto_1.createHmac)("sha256",y).update(`${s}.${n}`).digest("base64url"),c=Buffer.from(p),d=Buffer.from(v);if(!(c.length!==d.length||!(0,node_crypto_1.timingSafeEqual)(c,d)))try{const o=JSON.parse(Buffer.from(n,"base64url").toString());return typeof o.exp=="number"&&Date.now()/1e3>o.exp?void 0:o}catch{return}}f(verifyDevJwt,"verifyDevJwt"),a(verifyDevJwt,"verifyDevJwt"),u(verifyDevJwt,"verifyDevJwt");function stampIdentity(e,r){const t=u((p,i)=>{i!=null&&i!==""&&(e.headers[p]=String(i))},"set");t("x-user-id",r.sub),t("x-tenant-id",r.tid);const s=r.roles;Array.isArray(s)&&s.length&&(e.headers["x-user-roles"]=s.map(String).join(","));const n=r.perms;Array.isArray(n)&&n.length&&(e.headers["x-user-permissions"]=n.map(String).join(","))}f(stampIdentity,"stampIdentity"),a(stampIdentity,"stampIdentity"),u(stampIdentity,"stampIdentity");const devAttrs=u((e,r,t)=>({...r,ip:(0,edge_1.clientIpOf)(e),method:(e.method??"GET").toUpperCase(),path:t??(0,edge_1.canonicalPath)(e.url??"/")??(e.url??"/").split("?")[0]}),"devAttrs");exports.devAttrs=devAttrs;
@@ -1 +1 @@
1
- "use strict";var A=Object.defineProperty;var h=(e,s)=>A(e,"name",{value:s,configurable:!0});var I=Object.defineProperty,p=h((e,s)=>I(e,"name",{value:s,configurable:!0}),"p");Object.defineProperty(exports,"__esModule",{value:!0}),exports.RETIRING_SUFFIX=void 0,exports.stopRoutingTo=stopRoutingTo,exports.pickSock=pickSock,exports.lensPortFromUpstream=lensPortFromUpstream,exports.rewriteInstanceDecls=rewriteInstanceDecls,exports.discoverRoutes=discoverRoutes,exports.projectSourceRoots=projectSourceRoots;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),manifest_1=require("../manifest"),pod_sock_1=require("../../../pod-sock"),instance_1=require("./instance"),scope_1=require("./scope");exports.RETIRING_SUFFIX=".retiring";function sockIdentity(e){try{const s=fs.statSync(e);return`${s.dev}:${s.ino}:${s.ctimeMs}`}catch{return}}h(sockIdentity,"sockIdentity"),p(sockIdentity,"sockIdentity");function stopRoutingTo(e,s=()=>!0){let a;try{a=fs.readdirSync(e.dir)}catch{a=[]}const r=a.filter(t=>(0,pod_sock_1.isPodSockName)(t)&&s(t)).map(t=>path.join(e.dir,t));if(r.length===0)return r;const l=e.retired??=new Map;for(const t of r){const d=sockIdentity(t);d!==void 0&&l.set(t,d)}const n=new Set(r);return e.socks=e.socks.filter(t=>!n.has(t)),e.idx=-1,r}h(stopRoutingTo,"stopRoutingTo"),p(stopRoutingTo,"stopRoutingTo");function stillRetired(e,s){const a=e.retired?.get(s);return a===void 0?!1:sockIdentity(s)===a?!0:(e.retired?.delete(s),!1)}h(stillRetired,"stillRetired"),p(stillRetired,"stillRetired");function pickSock(e,s=1500){const a=Date.now();if(a-e.scannedAt>s){try{const r=fs.readdirSync(e.dir),l=r.filter(t=>(0,pod_sock_1.isPodSockName)(t)&&!stillRetired(e,path.join(e.dir,t)));if(e.retired)for(const t of[...e.retired.keys()])r.includes(path.basename(t))||e.retired.delete(t);const n=l.filter(t=>!r.includes(t+exports.RETIRING_SUFFIX));e.socks=(n.length>0?n:l).map(t=>path.join(e.dir,t))}catch{e.socks=[]}e.scannedAt=a}if(e.socks.length!==0)return e.idx=(e.idx+1)%e.socks.length,e.socks[e.idx]}h(pickSock,"pickSock"),p(pickSock,"pickSock");function lensPortFromUpstream(e){if(!e)return;const s=/:(\d+)/.exec(e);return s?Number(s[1]):void 0}h(lensPortFromUpstream,"lensPortFromUpstream"),p(lensPortFromUpstream,"lensPortFromUpstream");function rewriteInstanceDecls(e,s){const a=e.flatMap(([,n])=>[...n.host?[n.host]:[],...typeof n.internalHost=="string"?[n.internalHost]:[]]),r=s.apex??(0,instance_1.commonApex)(a);if(!r)return console.warn(`[gateway] instance '${s.name}': the declared hosts share no apex \u2014 set \`instance.apex\` in .lensmcp/config.json; no host is served for it.`),{decls:e.map(([n,t])=>[n,{...t,host:void 0,internalHost:!1,default:!1}])};const l=[];for(const[n,t]of e){const d={...t};if(t.host){const c=(0,instance_1.rewriteHost)(t.host,r,s.name);c||console.warn(`[gateway] instance '${s.name}': ${n}'s host ${t.host} is outside ${r} \u2014 not served for the instance.`),d.host=c}if(typeof t.internalHost=="string"){const c=(0,instance_1.rewriteHost)(t.internalHost,r,s.name);c||console.warn(`[gateway] instance '${s.name}': ${n}'s internal host ${t.internalHost} is outside ${r} \u2014 not served for the instance.`),d.internalHost=c??!1}l.push([n,d])}return{decls:l,baseApex:r,apex:`${s.name}.${r}`}}h(rewriteInstanceDecls,"rewriteInstanceDecls"),p(rewriteInstanceDecls,"rewriteInstanceDecls");function discoverRoutes(e,s,a=os.tmpdir(),r="",l={},n=r,t){const d=n||r,c=p(i=>d?path.join(a,d,`${i}-devserver`):path.join(a,`${i}-devserver`),"sockDirFor"),u=[],g=[],_=[],H=[],S={};let y,w=[];const F=new Map;for(const[i,o]of Object.entries(s))try{const f=JSON.parse(fs.readFileSync(path.join(e,o.root,"project.json"),"utf8")),m=f.cluster??f.davnx;m&&(w.push([i,m]),F.set(i,o.root))}catch{continue}let v={};t&&({decls:w,...v}=rewriteInstanceDecls(w,t));for(const[i,o]of w){const f={root:F.get(i)};let m,j,k,R;if(!o.service&&o.sources!==void 0&&console.warn(`[gateway] ${i}: cluster.sources is read from pod (service) decls only \u2014 ignored.`),o.service)o.lens&&console.warn(`[gateway] ${i}: cluster.lens is ignored for pod (service) decls \u2014 backends are instrumented by serve-hmr.`),m={dir:c(o.service),socks:[],idx:-1,scannedAt:0},j={project:i,decl:o,root:e,wsKey:r,...d!==r?{sockNs:d}:{},pool:m,state:"down",lastUsed:Date.now(),inflight:0,lastScaleAt:0},g.push(j);else if(o.lens){const x=o.port??lensPortFromUpstream(o.upstream)??5173;k=`http://localhost:${x}`,R={project:i,...r?{workspaceKey:r}:{},workspaceRoot:e,projectRoot:path.join(e,f.root),port:x,...l[i]?.length?{sourceRoots:l[i]}:{}},_.push(R)}else if(k=o.upstream??(o.port?`http://localhost:${o.port}`:void 0),!k){console.warn(`[gateway] ${i}: no service/upstream/port \u2014 skipped.`);continue}const b={...r?{wsKey:r}:{},project:i,prependPrefix:o.prependPrefix,target:k,pool:m,svc:j,prefix:o.path,auth:o.auth,lens:R};if(o.host&&(u.push({...b,host:o.host}),H.push(o.host),S[i]={host:o.host},m&&o.internalHost!==!1)){const x=typeof o.internalHost=="string"?o.internalHost:`internal.${o.host}`;u.push({...b,host:x,internal:!0}),S[i]={host:o.host,internalHost:x}}o.default&&(y={...b,prefix:void 0})}y&&(y.apex=v.apex??(0,scope_1.baseDomainOf)(H),u.push(y));let $;if(t&&v.apex&&v.baseApex){const i={name:t.name,apex:v.apex,baseApex:v.baseApex},o=(0,instance_1.instanceEnv)(e,(0,instance_1.instanceBuiltinEnv)(i,S));$={...i,baseKey:t.baseKey,env:o,...t.frozen?{frozen:!0}:{}};for(const f of g)f.instanceEnv=o,t.frozen&&(f.frozen=!0);for(const f of _)f.env=o,t.frozen&&(f.frozen=!0)}return(0,manifest_1.sortBySpecificity)(u),{routes:u,services:g,...$?{instance:$}:{}}}h(discoverRoutes,"discoverRoutes"),p(discoverRoutes,"discoverRoutes");function projectSourceRoots(e,s,a={}){const r={};for(const l of Object.keys(s)){const n=new Set,t=p(c=>{if(!n.has(c)){n.add(c);for(const u of a[c]??[])t(u)}},"visit");t(l);const d=[...n].map(c=>s[c]?.root).filter(c=>typeof c=="string").map(c=>path.resolve(e,c)).filter(c=>{const u=path.relative(e,c);return u===""||u!==".."&&!u.startsWith(`..${path.sep}`)&&!path.isAbsolute(u)});r[l]=[...new Set(d)]}return r}h(projectSourceRoots,"projectSourceRoots"),p(projectSourceRoots,"projectSourceRoots");
1
+ "use strict";var q=Object.defineProperty;var m=(e,o)=>q(e,"name",{value:o,configurable:!0});var A=Object.defineProperty,h=m((e,o)=>A(e,"name",{value:o,configurable:!0}),"h"),I=Object.defineProperty,p=h((e,o)=>I(e,"name",{value:o,configurable:!0}),"p");Object.defineProperty(exports,"__esModule",{value:!0}),exports.RETIRING_SUFFIX=void 0,exports.stopRoutingTo=stopRoutingTo,exports.pickSock=pickSock,exports.lensPortFromUpstream=lensPortFromUpstream,exports.rewriteInstanceDecls=rewriteInstanceDecls,exports.discoverRoutes=discoverRoutes,exports.projectSourceRoots=projectSourceRoots;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),manifest_1=require("../manifest"),pod_sock_1=require("../../../pod-sock"),instance_1=require("./instance"),scope_1=require("./scope");exports.RETIRING_SUFFIX=".retiring";function sockIdentity(e){try{const o=fs.statSync(e);return`${o.dev}:${o.ino}:${o.ctimeMs}`}catch{return}}m(sockIdentity,"sockIdentity"),h(sockIdentity,"sockIdentity"),p(sockIdentity,"sockIdentity");function stopRoutingTo(e,o=()=>!0){let a;try{a=fs.readdirSync(e.dir)}catch{a=[]}const r=a.filter(t=>(0,pod_sock_1.isPodSockName)(t)&&o(t)).map(t=>path.join(e.dir,t));if(r.length===0)return r;const l=e.retired??=new Map;for(const t of r){const d=sockIdentity(t);d!==void 0&&l.set(t,d)}const n=new Set(r);return e.socks=e.socks.filter(t=>!n.has(t)),e.idx=-1,r}m(stopRoutingTo,"stopRoutingTo"),h(stopRoutingTo,"stopRoutingTo"),p(stopRoutingTo,"stopRoutingTo");function stillRetired(e,o){const a=e.retired?.get(o);return a===void 0?!1:sockIdentity(o)===a?!0:(e.retired?.delete(o),!1)}m(stillRetired,"stillRetired"),h(stillRetired,"stillRetired"),p(stillRetired,"stillRetired");function pickSock(e,o=1500){const a=Date.now();if(a-e.scannedAt>o){try{const r=fs.readdirSync(e.dir),l=r.filter(t=>(0,pod_sock_1.isPodSockName)(t)&&!stillRetired(e,path.join(e.dir,t)));if(e.retired)for(const t of[...e.retired.keys()])r.includes(path.basename(t))||e.retired.delete(t);const n=l.filter(t=>!r.includes(t+exports.RETIRING_SUFFIX));e.socks=(n.length>0?n:l).map(t=>path.join(e.dir,t))}catch{e.socks=[]}e.scannedAt=a}if(e.socks.length!==0)return e.idx=(e.idx+1)%e.socks.length,e.socks[e.idx]}m(pickSock,"pickSock"),h(pickSock,"pickSock"),p(pickSock,"pickSock");function lensPortFromUpstream(e){if(!e)return;const o=/:(\d+)/.exec(e);return o?Number(o[1]):void 0}m(lensPortFromUpstream,"lensPortFromUpstream"),h(lensPortFromUpstream,"lensPortFromUpstream"),p(lensPortFromUpstream,"lensPortFromUpstream");function rewriteInstanceDecls(e,o){const a=e.flatMap(([,n])=>[...n.host?[n.host]:[],...typeof n.internalHost=="string"?[n.internalHost]:[]]),r=o.apex??(0,instance_1.commonApex)(a);if(!r)return console.warn(`[gateway] instance '${o.name}': the declared hosts share no apex \u2014 set \`instance.apex\` in .lensmcp/config.json; no host is served for it.`),{decls:e.map(([n,t])=>[n,{...t,host:void 0,internalHost:!1,default:!1}])};const l=[];for(const[n,t]of e){const d={...t};if(t.host){const c=(0,instance_1.rewriteHost)(t.host,r,o.name);c||console.warn(`[gateway] instance '${o.name}': ${n}'s host ${t.host} is outside ${r} \u2014 not served for the instance.`),d.host=c}if(typeof t.internalHost=="string"){const c=(0,instance_1.rewriteHost)(t.internalHost,r,o.name);c||console.warn(`[gateway] instance '${o.name}': ${n}'s internal host ${t.internalHost} is outside ${r} \u2014 not served for the instance.`),d.internalHost=c??!1}l.push([n,d])}return{decls:l,baseApex:r,apex:`${o.name}.${r}`}}m(rewriteInstanceDecls,"rewriteInstanceDecls"),h(rewriteInstanceDecls,"rewriteInstanceDecls"),p(rewriteInstanceDecls,"rewriteInstanceDecls");function discoverRoutes(e,o,a=os.tmpdir(),r="",l={},n=r,t){const d=n||r,c=p(i=>d?path.join(a,d,`${i}-devserver`):path.join(a,`${i}-devserver`),"sockDirFor"),u=[],S=[],H=[],F=[],R={};let k,w=[];const P=new Map;for(const[i,s]of Object.entries(o))try{const f=JSON.parse(fs.readFileSync(path.join(e,s.root,"project.json"),"utf8")),v=f.cluster??f.davnx;v&&(w.push([i,v]),P.set(i,s.root))}catch{continue}let x={};t&&({decls:w,...x}=rewriteInstanceDecls(w,t));for(const[i,s]of w){const f={root:P.get(i)};let v,$,g,b;if(!s.service&&s.sources!==void 0&&console.warn(`[gateway] ${i}: cluster.sources is read from pod (service) decls only \u2014 ignored.`),s.service)s.lens&&console.warn(`[gateway] ${i}: cluster.lens is ignored for pod (service) decls \u2014 backends are instrumented by serve-hmr.`),v={dir:c(s.service),socks:[],idx:-1,scannedAt:0},$={project:i,decl:s,root:e,wsKey:r,...d!==r?{sockNs:d}:{},pool:v,state:"down",lastUsed:Date.now(),inflight:0,lastScaleAt:0},S.push($);else if(s.lens){const y=s.port??lensPortFromUpstream(s.upstream)??5173;g=`http://localhost:${y}`,b={project:i,...r?{workspaceKey:r}:{},workspaceRoot:e,projectRoot:path.join(e,f.root),port:y,...l[i]?.length?{sourceRoots:l[i]}:{}},H.push(b)}else if(g=s.upstream??(s.port?`http://localhost:${s.port}`:void 0),!g){console.warn(`[gateway] ${i}: no service/upstream/port \u2014 skipped.`);continue}const _={...r?{wsKey:r}:{},project:i,prependPrefix:s.prependPrefix,target:g,pool:v,svc:$,prefix:s.path,auth:s.auth,lens:b};if(s.host&&(u.push({..._,host:s.host}),F.push(s.host),R[i]={host:s.host},v&&s.internalHost!==!1)){const y=typeof s.internalHost=="string"?s.internalHost:`internal.${s.host}`;u.push({..._,host:y,internal:!0}),R[i]={host:s.host,internalHost:y}}s.default&&(k={..._,prefix:void 0})}k&&(k.apex=x.apex??(0,scope_1.baseDomainOf)(F),u.push(k));let j;if(t&&x.apex&&x.baseApex){const i={name:t.name,apex:x.apex,baseApex:x.baseApex},s=(0,instance_1.instanceEnv)(e,(0,instance_1.instanceBuiltinEnv)(i,R));j={...i,baseKey:t.baseKey,env:s,...t.frozen?{frozen:!0}:{}};for(const f of S)f.instanceEnv=s,t.frozen&&(f.frozen=!0);for(const f of H)f.env=s,t.frozen&&(f.frozen=!0)}return(0,manifest_1.sortBySpecificity)(u),{routes:u,services:S,...j?{instance:j}:{}}}m(discoverRoutes,"discoverRoutes"),h(discoverRoutes,"discoverRoutes"),p(discoverRoutes,"discoverRoutes");function projectSourceRoots(e,o,a={}){const r={};for(const l of Object.keys(o)){const n=new Set,t=p(c=>{if(!n.has(c)){n.add(c);for(const u of a[c]??[])t(u)}},"visit");t(l);const d=[...n].map(c=>o[c]?.root).filter(c=>typeof c=="string").map(c=>path.resolve(e,c)).filter(c=>{const u=path.relative(e,c);return u===""||u!==".."&&!u.startsWith(`..${path.sep}`)&&!path.isAbsolute(u)});r[l]=[...new Set(d)]}return r}m(projectSourceRoots,"projectSourceRoots"),h(projectSourceRoots,"projectSourceRoots"),p(projectSourceRoots,"projectSourceRoots");
@@ -1 +1 @@
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.claimedCallerIdOf=exports.CLAIMED_CALLER_ID=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"),act_1=require("./act");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",act_1.ACT_HEADER],exports.CALLER_CONTEXT_HEADERS=["x-tenant-id","x-user-id"],exports.CALLER_CONTEXT=Symbol.for("lensmcp.gateway.callerContext"),exports.CLAIMED_CALLER_ID=Symbol.for("lensmcp.gateway.claimedCallerId");const CALLER_ID_VALUE=/^[a-z0-9][a-z0-9._-]{0,63}$/i,CALLER_CONTEXT_VALUE=/^[\x21-\x2b\x2d-\x7e]{1,128}$/;function stripOwnedHeaders(e){const r={};for(const s of exports.CALLER_CONTEXT_HEADERS){const n=e.headers[s];typeof n=="string"&&CALLER_CONTEXT_VALUE.test(n)&&(r[s]=n)}e[exports.CALLER_CONTEXT]=r;const t=e.headers["x-api-key-id"];typeof t=="string"&&CALLER_ID_VALUE.test(t)&&(e[exports.CLAIMED_CALLER_ID]=t),(0,act_1.setActTicketAside)(e);for(const s of exports.GATEWAY_OWNED_HEADERS)delete e.headers[s]}c(stripOwnedHeaders,"stripOwnedHeaders"),o(stripOwnedHeaders,"stripOwnedHeaders");const claimedCallerIdOf=o(e=>e[exports.CLAIMED_CALLER_ID],"claimedCallerIdOf");exports.claimedCallerIdOf=claimedCallerIdOf;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 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.claimedCallerIdOf=exports.CLAIMED_CALLER_ID=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"),act_1=require("./act");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",act_1.ACT_HEADER],exports.CALLER_CONTEXT_HEADERS=["x-tenant-id","x-user-id"],exports.CALLER_CONTEXT=Symbol.for("lensmcp.gateway.callerContext"),exports.CLAIMED_CALLER_ID=Symbol.for("lensmcp.gateway.claimedCallerId");const CALLER_ID_VALUE=/^[a-z0-9][a-z0-9._-]{0,63}$/i,CALLER_CONTEXT_VALUE=/^[\x21-\x2b\x2d-\x7e]{1,128}$/;function stripOwnedHeaders(e){const r={};for(const s of exports.CALLER_CONTEXT_HEADERS){const n=e.headers[s];typeof n=="string"&&CALLER_CONTEXT_VALUE.test(n)&&(r[s]=n)}e[exports.CALLER_CONTEXT]=r;const t=e.headers["x-api-key-id"];typeof t=="string"&&CALLER_ID_VALUE.test(t)&&(e[exports.CLAIMED_CALLER_ID]=t),(0,act_1.setActTicketAside)(e);for(const s of exports.GATEWAY_OWNED_HEADERS)delete e.headers[s]}i(stripOwnedHeaders,"stripOwnedHeaders"),c(stripOwnedHeaders,"stripOwnedHeaders"),o(stripOwnedHeaders,"stripOwnedHeaders");const claimedCallerIdOf=o(e=>e[exports.CLAIMED_CALLER_ID],"claimedCallerIdOf");exports.claimedCallerIdOf=claimedCallerIdOf;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,2 +1,2 @@
1
- "use strict";var _=Object.defineProperty;var u=(e,r)=>_(e,"name",{value:r,configurable:!0});var l=Object.defineProperty,f=u((e,r)=>l(e,"name",{value:r,configurable:!0}),"f");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GUEST_GRAPH_RETRY_MS=exports.MAX_FORWARDED_PROJECTS=exports.MAX_FORWARDED_GRAPH_BYTES=exports.FORWARDED_GRAPH_FORMAT=void 0,exports.ownedByThisUser=ownedByThisUser,exports.admitForwardedGraph=admitForwardedGraph,exports.compactSourceMaps=compactSourceMaps,exports.projectsOnly=projectsOnly,exports.snapshotWorkspaceGraph=snapshotWorkspaceGraph,exports.graphSnapshotScript=graphSnapshotScript,exports.guestGraphEnv=guestGraphEnv,exports.forwardedGraphInChild=forwardedGraphInChild,exports.createGuestGraphStore=createGuestGraphStore;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),pod_env_1=require("./pod-env"),project_graph_store_1=require("./project-graph-store"),registration_guards_1=require("./registration-guards");exports.FORWARDED_GRAPH_FORMAT=1,exports.MAX_FORWARDED_GRAPH_BYTES=8*1024*1024,exports.MAX_FORWARDED_PROJECTS=2e4,exports.GUEST_GRAPH_RETRY_MS=6e4;const GUEST_GRAPH_TIMEOUT_MS=12e4,SIGNATURE=/^(?:-|\?|\d+(?:\.\d+)?:\d+:\d+)$/;function megabytes(e){return`${(e/(1024*1024)).toFixed(1)} MB`}u(megabytes,"megabytes"),f(megabytes,"megabytes");const isRecord=f(e=>!!e&&typeof e=="object"&&!Array.isArray(e),"isRecord");function insideWorkspace(e){return e===""||path.isAbsolute(e)||/^[a-zA-Z]:/.test(e)?!1:!path.posix.normalize(e.replace(/\\/g,"/")).split("/").includes("..")}u(insideWorkspace,"insideWorkspace"),f(insideWorkspace,"insideWorkspace");function ownedByThisUser(e){const r=fs.statSync(e,{throwIfNoEntry:!1});if(!r?.isDirectory())return!1;if(typeof process.getuid!="function")return!0;const t=process.getuid();return r.uid===t||t===0&&r.uid===Number(process.env.SUDO_UID)}u(ownedByThisUser,"ownedByThisUser"),f(ownedByThisUser,"ownedByThisUser");function relativeDeclaringFiles(e,r){return(0,project_graph_store_1.declaringFiles)(e,r).map(t=>path.relative(e,t).split(path.sep).join("/"))}u(relativeDeclaringFiles,"relativeDeclaringFiles"),f(relativeDeclaringFiles,"relativeDeclaringFiles");function shapeProblem(e){if(!isRecord(e)||!isRecord(e.nodes)||!isRecord(e.dependencies))return"it has no `nodes` and `dependencies`";const r=e.nodes,t=Object.keys(r);if(t.length>exports.MAX_FORWARDED_PROJECTS)return`it names ${t.length} projects (at most ${exports.MAX_FORWARDED_PROJECTS})`;for(const o of t){const s=r[o];if(!isRecord(s)||s.name!==o||typeof s.type!="string"||!isRecord(s.data))return`project '${o}' is not a project node`;const n=s.data.root;if(typeof n!="string"||!insideWorkspace(n))return`project '${o}' has a root outside the workspace (${String(n)})`;const p=s.data.targets;if(p!==void 0&&(!isRecord(p)||!Object.values(p).every(isRecord)))return`project '${o}' has malformed targets`}for(const[o,s]of Object.entries(e.dependencies)){if(!(o in r)||!Array.isArray(s))return`the dependencies of '${o}' are not a known project's`;for(const n of s)if(!isRecord(n)||n.source!==o||typeof n.target!="string"||!(n.target in r)||typeof n.type!="string")return`a dependency of '${o}' is malformed`}}u(shapeProblem,"shapeProblem"),f(shapeProblem,"shapeProblem");function sourceMapsProblem(e){if(e!==void 0){if(!isRecord(e))return"its source maps are not a map";for(const[r,t]of Object.entries(e)){if(!isRecord(t))return`the source map of ${r} is malformed`;for(const o of Object.values(t))if(!Array.isArray(o)||o.length!==2||o[0]!==null&&typeof o[0]!="string"||typeof o[1]!="string")return`the source map of ${r} is malformed`}}}u(sourceMapsProblem,"sourceMapsProblem"),f(sourceMapsProblem,"sourceMapsProblem");function admitForwardedGraph(e,r){const t=f(a=>({refused:a}),"refuse");if(r.bytes>exports.MAX_FORWARDED_GRAPH_BYTES)return t(`${megabytes(r.bytes)} is over the ${megabytes(exports.MAX_FORWARDED_GRAPH_BYTES)} limit`);if(!isRecord(e))return t("it is not a project graph");if(e.format!==exports.FORWARDED_GRAPH_FORMAT)return t(`its format is ${String(e.format)}, and this gateway reads ${exports.FORWARDED_GRAPH_FORMAT}`);const o=e.root;if(typeof o!="string"||!path.isAbsolute(o))return t("it does not say which workspace it describes");if(!(0,registration_guards_1.sameRoot)(o,r.root))return t(`it describes ${o}, not the registering workspace ${r.root}`);if((0,registration_guards_1.sameRoot)(r.root,r.daemonRoot))return t(`${r.root} is the gateway's own workspace \u2014 the gateway reads that graph itself`);if(r.otherRoots.some(a=>(0,registration_guards_1.sameRoot)(a,r.root)))return t(`${r.root} is registered under another key`);if(!ownedByThisUser(r.root))return t(`${r.root} is not a directory this user owns`);const s=e.startedAt;if(typeof s!="number"||!Number.isFinite(s))return t("it does not say when it was computed");const n=shapeProblem(e.projectGraph)??sourceMapsProblem(e.sourceMaps);if(n)return t(n);const p=e.projectGraph,i=e.files;if(!isRecord(i))return t("it carries no fingerprint of its declaring files");const c=(0,registration_guards_1.canonicalRoot)(r.root),h=relativeDeclaringFiles(c,p),d=Object.keys(i),g=h.filter(a=>!(a in i));return g.length>0||d.length!==h.length?t(`its fingerprint does not cover exactly the files that declare it${g.length>0?` (no ${g[0]})`:""}`):Object.values(i).every(a=>typeof a=="string"&&SIGNATURE.test(a))?{snapshot:{root:c,startedAt:s,files:new Map(h.map(a=>[path.join(c,a),i[a]])),projectGraph:{nodes:p.nodes,dependencies:p.dependencies,externalNodes:{}},...e.sourceMaps!==void 0?{sourceMaps:e.sourceMaps}:{}}}:t("its fingerprint is malformed")}u(admitForwardedGraph,"admitForwardedGraph"),f(admitForwardedGraph,"admitForwardedGraph");function compactSourceMaps(e,r){const t={};for(const o of Object.values(e.nodes)){const s=r[o.data.root];if(!s)continue;const n=new Set;for(const i of Object.keys(o.data.targets??{})){const c=`targets.${i}`,h=new Set;for(const[d,g]of Object.entries(s)){if(d!==c&&!d.startsWith(`${c}.`))continue;const a=JSON.stringify(g);h.has(a)||(h.add(a),n.add(d))}}const p={};for(const[i,c]of Object.entries(s))n.has(i)&&(p[i]=c);t[o.data.root]=p}return t}u(compactSourceMaps,"compactSourceMaps"),f(compactSourceMaps,"compactSourceMaps");function projectsOnly(e){const r={};for(const[t,o]of Object.entries(e.dependencies))t in e.nodes&&(r[t]=o.filter(s=>s.target in e.nodes));return{nodes:e.nodes,dependencies:r}}u(projectsOnly,"projectsOnly"),f(projectsOnly,"projectsOnly");async function snapshotWorkspaceGraph(e,r=()=>(0,project_graph_store_1.computeProjectGraphInProcess)(e)){const t=Date.now(),o=(0,project_graph_store_1.filesystemNow)(),s=await r(),n=projectsOnly(s.projectGraph),p={};for(const i of(0,project_graph_store_1.declaringFiles)(e,s.projectGraph)){const c=fs.statSync(i,{throwIfNoEntry:!1});p[path.relative(e,i).split(path.sep).join("/")]=c&&c.mtimeMs>o?"?":(0,project_graph_store_1.statSignature)(i)}return{format:exports.FORWARDED_GRAPH_FORMAT,root:e,startedAt:t,projectGraph:n,...s.sourceMaps?{sourceMaps:compactSourceMaps(n,s.sourceMaps)}:{},files:p}}u(snapshotWorkspaceGraph,"snapshotWorkspaceGraph"),f(snapshotWorkspaceGraph,"snapshotWorkspaceGraph");function graphSnapshotScript(e=path.join(__dirname,"../../..")){const r=path.join(e,"graph-snapshot.js");if(fs.existsSync(r))return{path:r,execArgv:[]};const t=path.join(e,"graph-snapshot.ts");if(fs.existsSync(t))try{return{path:t,execArgv:["--require",require.resolve("@swc-node/register")]}}catch{return}}u(graphSnapshotScript,"graphSnapshotScript"),f(graphSnapshotScript,"graphSnapshotScript");function guestGraphEnv(e,r,t){const o={...(0,pod_env_1.podBaseEnv)(e,r,t)};for(const s of Object.keys(o))(s.startsWith("NX_TASK_")||["NX_WORKSPACE_ROOT","NX_WORKSPACE_ROOT_PATH","NX_WORKSPACE_DATA_DIRECTORY","NX_PROJECT_GRAPH_CACHE_DIRECTORY"].includes(s))&&delete o[s];return o.NX_DAEMON="false",o.NX_ISOLATE_PLUGINS="false",o}u(guestGraphEnv,"guestGraphEnv"),f(guestGraphEnv,"guestGraphEnv");function forwardedGraphInChild(e,r,t=graphSnapshotScript()){if(!t)return Promise.reject(new Error("graph-snapshot.js is missing from @lensmcp/cluster"));const o=fs.mkdtempSync(path.join(os.tmpdir(),"lensmcp-graph-")),s=path.join(o,"graph.json");return new Promise((n,p)=>{let i="";const c=(0,node_child_process_1.spawn)(process.execPath,[...t.execArgv,t.path,s],{cwd:e,env:r,stdio:["ignore","ignore","pipe"]});c.stderr?.on("data",d=>{i.length<4096&&(i+=d.toString())});const h=setTimeout(()=>c.kill("SIGKILL"),GUEST_GRAPH_TIMEOUT_MS);h.unref(),c.on("error",d=>{clearTimeout(h),p(d)}),c.on("exit",(d,g)=>{if(clearTimeout(h),d!==0){const a=i.trim().split(`
2
- `).pop();p(new Error(`the graph computation in ${e} exited ${g??d}${a?` \u2014 ${a}`:""}`));return}try{const a=fs.statSync(s).size;n({bytes:a,graph:a>exports.MAX_FORWARDED_GRAPH_BYTES?void 0:JSON.parse(fs.readFileSync(s,"utf8"))})}catch(a){p(a)}})}).finally(()=>fs.rmSync(o,{recursive:!0,force:!0}))}u(forwardedGraphInChild,"forwardedGraphInChild"),f(forwardedGraphInChild,"forwardedGraphInChild");function createGuestGraphStore(e,r=process.env){const{wsKey:t,admission:o,context:s}=e,n=(0,registration_guards_1.canonicalRoot)(e.root),p=e.compute??(()=>forwardedGraphInChild(n,guestGraphEnv(r,s.daemonRoot,n))),i=o===void 0?"its registration forwarded none":o.refused!==void 0?`the project graph its registration forwarded was refused: ${o.refused}`:void 0;return(0,project_graph_store_1.createProjectGraphStore)(n,async()=>{const{graph:c,bytes:h}=await p(),d=admitForwardedGraph(c,{...s,bytes:h});if(d.refused!==void 0)throw new Error(`the computed project graph was refused: ${d.refused}`);return{projectGraph:d.snapshot.projectGraph,...d.snapshot.sourceMaps?{sourceMaps:d.snapshot.sourceMaps}:{}}},{...o?.snapshot?{seed:o.snapshot}:{},...i?{error:i}:{},retryAfterFailureMs:exports.GUEST_GRAPH_RETRY_MS,onRefreshed:f(c=>console.log(`[gateway] project graph of '${t}' (${n}) refreshed \u2014 ${Object.keys(c.projectGraph.nodes).length} projects; its services start through the serve runner again`),"onRefreshed")})}u(createGuestGraphStore,"createGuestGraphStore"),f(createGuestGraphStore,"createGuestGraphStore");
1
+ "use strict";var m=Object.defineProperty;var h=(e,t)=>m(e,"name",{value:t,configurable:!0});var _=Object.defineProperty,u=h((e,t)=>_(e,"name",{value:t,configurable:!0}),"u"),l=Object.defineProperty,f=u((e,t)=>l(e,"name",{value:t,configurable:!0}),"f");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GUEST_GRAPH_RETRY_MS=exports.MAX_FORWARDED_PROJECTS=exports.MAX_FORWARDED_GRAPH_BYTES=exports.FORWARDED_GRAPH_FORMAT=void 0,exports.ownedByThisUser=ownedByThisUser,exports.admitForwardedGraph=admitForwardedGraph,exports.compactSourceMaps=compactSourceMaps,exports.projectsOnly=projectsOnly,exports.snapshotWorkspaceGraph=snapshotWorkspaceGraph,exports.graphSnapshotScript=graphSnapshotScript,exports.guestGraphEnv=guestGraphEnv,exports.forwardedGraphInChild=forwardedGraphInChild,exports.createGuestGraphStore=createGuestGraphStore;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),pod_env_1=require("./pod-env"),project_graph_store_1=require("./project-graph-store"),registration_guards_1=require("./registration-guards");exports.FORWARDED_GRAPH_FORMAT=1,exports.MAX_FORWARDED_GRAPH_BYTES=8*1024*1024,exports.MAX_FORWARDED_PROJECTS=2e4,exports.GUEST_GRAPH_RETRY_MS=6e4;const GUEST_GRAPH_TIMEOUT_MS=12e4,SIGNATURE=/^(?:-|\?|\d+(?:\.\d+)?:\d+:\d+)$/;function megabytes(e){return`${(e/(1024*1024)).toFixed(1)} MB`}h(megabytes,"megabytes"),u(megabytes,"megabytes"),f(megabytes,"megabytes");const isRecord=f(e=>!!e&&typeof e=="object"&&!Array.isArray(e),"isRecord");function insideWorkspace(e){return e===""||path.isAbsolute(e)||/^[a-zA-Z]:/.test(e)?!1:!path.posix.normalize(e.replace(/\\/g,"/")).split("/").includes("..")}h(insideWorkspace,"insideWorkspace"),u(insideWorkspace,"insideWorkspace"),f(insideWorkspace,"insideWorkspace");function ownedByThisUser(e){const t=fs.statSync(e,{throwIfNoEntry:!1});if(!t?.isDirectory())return!1;if(typeof process.getuid!="function")return!0;const r=process.getuid();return t.uid===r||r===0&&t.uid===Number(process.env.SUDO_UID)}h(ownedByThisUser,"ownedByThisUser"),u(ownedByThisUser,"ownedByThisUser"),f(ownedByThisUser,"ownedByThisUser");function relativeDeclaringFiles(e,t){return(0,project_graph_store_1.declaringFiles)(e,t).map(r=>path.relative(e,r).split(path.sep).join("/"))}h(relativeDeclaringFiles,"relativeDeclaringFiles"),u(relativeDeclaringFiles,"relativeDeclaringFiles"),f(relativeDeclaringFiles,"relativeDeclaringFiles");function shapeProblem(e){if(!isRecord(e)||!isRecord(e.nodes)||!isRecord(e.dependencies))return"it has no `nodes` and `dependencies`";const t=e.nodes,r=Object.keys(t);if(r.length>exports.MAX_FORWARDED_PROJECTS)return`it names ${r.length} projects (at most ${exports.MAX_FORWARDED_PROJECTS})`;for(const o of r){const s=t[o];if(!isRecord(s)||s.name!==o||typeof s.type!="string"||!isRecord(s.data))return`project '${o}' is not a project node`;const n=s.data.root;if(typeof n!="string"||!insideWorkspace(n))return`project '${o}' has a root outside the workspace (${String(n)})`;const p=s.data.targets;if(p!==void 0&&(!isRecord(p)||!Object.values(p).every(isRecord)))return`project '${o}' has malformed targets`}for(const[o,s]of Object.entries(e.dependencies)){if(!(o in t)||!Array.isArray(s))return`the dependencies of '${o}' are not a known project's`;for(const n of s)if(!isRecord(n)||n.source!==o||typeof n.target!="string"||!(n.target in t)||typeof n.type!="string")return`a dependency of '${o}' is malformed`}}h(shapeProblem,"shapeProblem"),u(shapeProblem,"shapeProblem"),f(shapeProblem,"shapeProblem");function sourceMapsProblem(e){if(e!==void 0){if(!isRecord(e))return"its source maps are not a map";for(const[t,r]of Object.entries(e)){if(!isRecord(r))return`the source map of ${t} is malformed`;for(const o of Object.values(r))if(!Array.isArray(o)||o.length!==2||o[0]!==null&&typeof o[0]!="string"||typeof o[1]!="string")return`the source map of ${t} is malformed`}}}h(sourceMapsProblem,"sourceMapsProblem"),u(sourceMapsProblem,"sourceMapsProblem"),f(sourceMapsProblem,"sourceMapsProblem");function admitForwardedGraph(e,t){const r=f(a=>({refused:a}),"refuse");if(t.bytes>exports.MAX_FORWARDED_GRAPH_BYTES)return r(`${megabytes(t.bytes)} is over the ${megabytes(exports.MAX_FORWARDED_GRAPH_BYTES)} limit`);if(!isRecord(e))return r("it is not a project graph");if(e.format!==exports.FORWARDED_GRAPH_FORMAT)return r(`its format is ${String(e.format)}, and this gateway reads ${exports.FORWARDED_GRAPH_FORMAT}`);const o=e.root;if(typeof o!="string"||!path.isAbsolute(o))return r("it does not say which workspace it describes");if(!(0,registration_guards_1.sameRoot)(o,t.root))return r(`it describes ${o}, not the registering workspace ${t.root}`);if((0,registration_guards_1.sameRoot)(t.root,t.daemonRoot))return r(`${t.root} is the gateway's own workspace \u2014 the gateway reads that graph itself`);if(t.otherRoots.some(a=>(0,registration_guards_1.sameRoot)(a,t.root)))return r(`${t.root} is registered under another key`);if(!ownedByThisUser(t.root))return r(`${t.root} is not a directory this user owns`);const s=e.startedAt;if(typeof s!="number"||!Number.isFinite(s))return r("it does not say when it was computed");const n=shapeProblem(e.projectGraph)??sourceMapsProblem(e.sourceMaps);if(n)return r(n);const p=e.projectGraph,i=e.files;if(!isRecord(i))return r("it carries no fingerprint of its declaring files");const c=(0,registration_guards_1.canonicalRoot)(t.root),g=relativeDeclaringFiles(c,p),d=Object.keys(i),R=g.filter(a=>!(a in i));return R.length>0||d.length!==g.length?r(`its fingerprint does not cover exactly the files that declare it${R.length>0?` (no ${R[0]})`:""}`):Object.values(i).every(a=>typeof a=="string"&&SIGNATURE.test(a))?{snapshot:{root:c,startedAt:s,files:new Map(g.map(a=>[path.join(c,a),i[a]])),projectGraph:{nodes:p.nodes,dependencies:p.dependencies,externalNodes:{}},...e.sourceMaps!==void 0?{sourceMaps:e.sourceMaps}:{}}}:r("its fingerprint is malformed")}h(admitForwardedGraph,"admitForwardedGraph"),u(admitForwardedGraph,"admitForwardedGraph"),f(admitForwardedGraph,"admitForwardedGraph");function compactSourceMaps(e,t){const r={};for(const o of Object.values(e.nodes)){const s=t[o.data.root];if(!s)continue;const n=new Set;for(const i of Object.keys(o.data.targets??{})){const c=`targets.${i}`,g=new Set;for(const[d,R]of Object.entries(s)){if(d!==c&&!d.startsWith(`${c}.`))continue;const a=JSON.stringify(R);g.has(a)||(g.add(a),n.add(d))}}const p={};for(const[i,c]of Object.entries(s))n.has(i)&&(p[i]=c);r[o.data.root]=p}return r}h(compactSourceMaps,"compactSourceMaps"),u(compactSourceMaps,"compactSourceMaps"),f(compactSourceMaps,"compactSourceMaps");function projectsOnly(e){const t={};for(const[r,o]of Object.entries(e.dependencies))r in e.nodes&&(t[r]=o.filter(s=>s.target in e.nodes));return{nodes:e.nodes,dependencies:t}}h(projectsOnly,"projectsOnly"),u(projectsOnly,"projectsOnly"),f(projectsOnly,"projectsOnly");async function snapshotWorkspaceGraph(e,t=()=>(0,project_graph_store_1.computeProjectGraphInProcess)(e)){const r=Date.now(),o=(0,project_graph_store_1.filesystemNow)(),s=await t(),n=projectsOnly(s.projectGraph),p={};for(const i of(0,project_graph_store_1.declaringFiles)(e,s.projectGraph)){const c=fs.statSync(i,{throwIfNoEntry:!1});p[path.relative(e,i).split(path.sep).join("/")]=c&&c.mtimeMs>o?"?":(0,project_graph_store_1.statSignature)(i)}return{format:exports.FORWARDED_GRAPH_FORMAT,root:e,startedAt:r,projectGraph:n,...s.sourceMaps?{sourceMaps:compactSourceMaps(n,s.sourceMaps)}:{},files:p}}h(snapshotWorkspaceGraph,"snapshotWorkspaceGraph"),u(snapshotWorkspaceGraph,"snapshotWorkspaceGraph"),f(snapshotWorkspaceGraph,"snapshotWorkspaceGraph");function graphSnapshotScript(e=path.join(__dirname,"../../..")){const t=path.join(e,"graph-snapshot.js");if(fs.existsSync(t))return{path:t,execArgv:[]};const r=path.join(e,"graph-snapshot.ts");if(fs.existsSync(r))try{return{path:r,execArgv:["--require",require.resolve("@swc-node/register")]}}catch{return}}h(graphSnapshotScript,"graphSnapshotScript"),u(graphSnapshotScript,"graphSnapshotScript"),f(graphSnapshotScript,"graphSnapshotScript");function guestGraphEnv(e,t,r){const o={...(0,pod_env_1.podBaseEnv)(e,t,r)};for(const s of Object.keys(o))(s.startsWith("NX_TASK_")||["NX_WORKSPACE_ROOT","NX_WORKSPACE_ROOT_PATH","NX_WORKSPACE_DATA_DIRECTORY","NX_PROJECT_GRAPH_CACHE_DIRECTORY"].includes(s))&&delete o[s];return o.NX_DAEMON="false",o.NX_ISOLATE_PLUGINS="false",o}h(guestGraphEnv,"guestGraphEnv"),u(guestGraphEnv,"guestGraphEnv"),f(guestGraphEnv,"guestGraphEnv");function forwardedGraphInChild(e,t,r=graphSnapshotScript()){if(!r)return Promise.reject(new Error("graph-snapshot.js is missing from @lensmcp/cluster"));const o=fs.mkdtempSync(path.join(os.tmpdir(),"lensmcp-graph-")),s=path.join(o,"graph.json");return new Promise((n,p)=>{let i="";const c=(0,node_child_process_1.spawn)(process.execPath,[...r.execArgv,r.path,s],{cwd:e,env:t,stdio:["ignore","ignore","pipe"]});c.stderr?.on("data",d=>{i.length<4096&&(i+=d.toString())});const g=setTimeout(()=>c.kill("SIGKILL"),GUEST_GRAPH_TIMEOUT_MS);g.unref(),c.on("error",d=>{clearTimeout(g),p(d)}),c.on("exit",(d,R)=>{if(clearTimeout(g),d!==0){const a=i.trim().split(`
2
+ `).pop();p(new Error(`the graph computation in ${e} exited ${R??d}${a?` \u2014 ${a}`:""}`));return}try{const a=fs.statSync(s).size;n({bytes:a,graph:a>exports.MAX_FORWARDED_GRAPH_BYTES?void 0:JSON.parse(fs.readFileSync(s,"utf8"))})}catch(a){p(a)}})}).finally(()=>fs.rmSync(o,{recursive:!0,force:!0}))}h(forwardedGraphInChild,"forwardedGraphInChild"),u(forwardedGraphInChild,"forwardedGraphInChild"),f(forwardedGraphInChild,"forwardedGraphInChild");function createGuestGraphStore(e,t=process.env){const{wsKey:r,admission:o,context:s}=e,n=(0,registration_guards_1.canonicalRoot)(e.root),p=e.compute??(()=>forwardedGraphInChild(n,guestGraphEnv(t,s.daemonRoot,n))),i=o===void 0?"its registration forwarded none":o.refused!==void 0?`the project graph its registration forwarded was refused: ${o.refused}`:void 0;return(0,project_graph_store_1.createProjectGraphStore)(n,async()=>{const{graph:c,bytes:g}=await p(),d=admitForwardedGraph(c,{...s,bytes:g});if(d.refused!==void 0)throw new Error(`the computed project graph was refused: ${d.refused}`);return{projectGraph:d.snapshot.projectGraph,...d.snapshot.sourceMaps?{sourceMaps:d.snapshot.sourceMaps}:{}}},{...o?.snapshot?{seed:o.snapshot}:{},...i?{error:i}:{},retryAfterFailureMs:exports.GUEST_GRAPH_RETRY_MS,onRefreshed:f(c=>console.log(`[gateway] project graph of '${r}' (${n}) refreshed \u2014 ${Object.keys(c.projectGraph.nodes).length} projects; its services start through the serve runner again`),"onRefreshed")})}h(createGuestGraphStore,"createGuestGraphStore"),u(createGuestGraphStore,"createGuestGraphStore"),f(createGuestGraphStore,"createGuestGraphStore");
@@ -1,2 +1,2 @@
1
- "use strict";var a=Object.defineProperty;var n=(r,t)=>a(r,"name",{value:t,configurable:!0});var c=Object.defineProperty,o=n((r,t)=>c(r,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.guestsFile=guestsFile,exports.readGuests=readGuests,exports.recordGuest=recordGuest,exports.forgetGuest=forgetGuest,exports.guestsToReplay=guestsToReplay;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path"));function guestsFile(){return path.join(process.env.LENSMCP_HOME||os.homedir(),".lensmcp","guests.json")}n(guestsFile,"guestsFile"),o(guestsFile,"guestsFile");function readGuests(r=guestsFile()){try{const t=JSON.parse(fs.readFileSync(r,"utf8"));return Array.isArray(t)?t.filter(e=>!!e&&typeof e=="object"&&typeof e.wsKey=="string"&&typeof e.root=="string"&&typeof e.daemonRoot=="string"&&!!e.projects&&typeof e.projects=="object"):[]}catch{return[]}}n(readGuests,"readGuests"),o(readGuests,"readGuests");function writeGuests(r,t){fs.mkdirSync(path.dirname(t),{recursive:!0,mode:448});const e=`${t}.${process.pid}.tmp`;fs.writeFileSync(e,JSON.stringify(r,null,2)+`
2
- `,{mode:384}),fs.renameSync(e,t)}n(writeGuests,"writeGuests"),o(writeGuests,"writeGuests");function recordGuest(r,t=guestsFile()){try{writeGuests([...readGuests(t).filter(e=>e.wsKey!==r.wsKey),r],t)}catch(e){console.warn(`[gateway] could not record '${r.wsKey}' for replay (${e.message}) \u2014 a daemon restart will not bring it back`)}}n(recordGuest,"recordGuest"),o(recordGuest,"recordGuest");function forgetGuest(r,t=guestsFile()){try{const e=readGuests(t),s=e.filter(i=>i.wsKey!==r);s.length!==e.length&&writeGuests(s,t)}catch{}}n(forgetGuest,"forgetGuest"),o(forgetGuest,"forgetGuest");const same=o((r,t)=>{const e=o(s=>{try{return fs.realpathSync(s)}catch{return path.resolve(s)}},"real");return e(r)===e(t)},"same");function guestsToReplay(r,t){const e=[],s=[];for(const i of t)!same(i.daemonRoot,r)||same(i.root,r)||(fs.existsSync(path.join(i.root,"package.json"))?e:s).push(i);return{replay:e,gone:s}}n(guestsToReplay,"guestsToReplay"),o(guestsToReplay,"guestsToReplay");
1
+ "use strict";var p=Object.defineProperty;var u=(r,t)=>p(r,"name",{value:t,configurable:!0});var a=Object.defineProperty,n=u((r,t)=>a(r,"name",{value:t,configurable:!0}),"n"),c=Object.defineProperty,o=n((r,t)=>c(r,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.guestsFile=guestsFile,exports.readGuests=readGuests,exports.recordGuest=recordGuest,exports.forgetGuest=forgetGuest,exports.guestsToReplay=guestsToReplay;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path"));function guestsFile(){return path.join(process.env.LENSMCP_HOME||os.homedir(),".lensmcp","guests.json")}u(guestsFile,"guestsFile"),n(guestsFile,"guestsFile"),o(guestsFile,"guestsFile");function readGuests(r=guestsFile()){try{const t=JSON.parse(fs.readFileSync(r,"utf8"));return Array.isArray(t)?t.filter(e=>!!e&&typeof e=="object"&&typeof e.wsKey=="string"&&typeof e.root=="string"&&typeof e.daemonRoot=="string"&&!!e.projects&&typeof e.projects=="object"):[]}catch{return[]}}u(readGuests,"readGuests"),n(readGuests,"readGuests"),o(readGuests,"readGuests");function writeGuests(r,t){fs.mkdirSync(path.dirname(t),{recursive:!0,mode:448});const e=`${t}.${process.pid}.tmp`;fs.writeFileSync(e,JSON.stringify(r,null,2)+`
2
+ `,{mode:384}),fs.renameSync(e,t)}u(writeGuests,"writeGuests"),n(writeGuests,"writeGuests"),o(writeGuests,"writeGuests");function recordGuest(r,t=guestsFile()){try{writeGuests([...readGuests(t).filter(e=>e.wsKey!==r.wsKey),r],t)}catch(e){console.warn(`[gateway] could not record '${r.wsKey}' for replay (${e.message}) \u2014 a daemon restart will not bring it back`)}}u(recordGuest,"recordGuest"),n(recordGuest,"recordGuest"),o(recordGuest,"recordGuest");function forgetGuest(r,t=guestsFile()){try{const e=readGuests(t),s=e.filter(i=>i.wsKey!==r);s.length!==e.length&&writeGuests(s,t)}catch{}}u(forgetGuest,"forgetGuest"),n(forgetGuest,"forgetGuest"),o(forgetGuest,"forgetGuest");const same=o((r,t)=>{const e=o(s=>{try{return fs.realpathSync(s)}catch{return path.resolve(s)}},"real");return e(r)===e(t)},"same");function guestsToReplay(r,t){const e=[],s=[];for(const i of t)!same(i.daemonRoot,r)||same(i.root,r)||(fs.existsSync(path.join(i.root,"package.json"))?e:s).push(i);return{replay:e,gone:s}}u(guestsToReplay,"guestsToReplay"),n(guestsToReplay,"guestsToReplay"),o(guestsToReplay,"guestsToReplay");
@@ -1 +1 @@
1
- "use strict";var q=Object.defineProperty;var y=(f,n)=>q(f,"name",{value:n,configurable:!0});var x=Object.defineProperty,p=y((f,n)=>x(f,"name",{value:n,configurable:!0}),"p");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(f){const{rt:n,obs:d,auth:v,proxy:_,hooks:i}=f,O=p(e=>(e.headers.host||"").split(":")[0],"hostOf"),S=p((e,t)=>{if((0,edge_1.cors)(e,t,n.routes),e.method==="OPTIONS"){t.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_NOROUTE,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),t.end();return}const o=(e.headers.host||"").split(":")[0],u=n.routes.filter(r=>r.host&&(0,manifest_1.hostMatches)(r.host,o)&&r.prefix),s=(e.url??"/").split("?")[0];if((s==="/"||s==="/index.html"||s==="")&&n.routes.some(r=>r.host&&(0,manifest_1.hostMatches)(r.host,o)&&r.project===observability_1.LENS_DASHBOARD_PROJECT)){(0,chooser_1.serveChooser)(t,n.wsKey,e);return}if(u.length>0&&(s==="/health"||s==="/healthz")){const r=u.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")})),h=r.every(l=>l.state!=="down"||!0);t.writeHead(h?200:503,{"content-type":"application/json"}),t.end(JSON.stringify({status:"ok",host:o,services:r},null,2));return}if(u.length>0&&s==="/.well-known/services"){t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({host:o,services:u.map(r=>({prefix:r.prefix,project:r.project,internal:!!r.internal}))},null,2));return}(0,edge_1.sendError)(t,e,404,"not_found",u.length>0?`No service mounted at ${s}. Mounted on ${o}: ${[...new Set(u.map(r=>r.prefix))].join(", ")} (+ /health, /.well-known/services)`:"No gateway route for this hostname.")},"handleNoRoute"),b=p(async(e,t)=>{if(!e.headers.host){const r=e.authority??e.headers[":authority"];r&&(e.headers.host=r)}(0,edge_1.stripOwnedHeaders)(e);let o=d.beginTrace(e);const u=Date.now();(0,gateway_errors_1.ensureRequestId)(e),o&&(d.traceStep(o,"received",{host:o.host,method:o.method,url:o.url}),e.__lensmcpTrace=o);const s=i.httpContext(e,t,o);try{const r=e.url??"/",h=(0,edge_1.canonicalize)(r);if(h===void 0){d.traceStep(o,"bad-path",{}),d.finishTrace(o,"gateway",400),(0,edge_1.sendError)(t,e,400,"bad_request","Bad Request");return}const l=h.policy,m=h.path+h.query;if(m!==r&&(0,edge_1.rememberRawTarget)(e,r),e.url=m,(0,edge_1.resolveClientIp)(n,e),i.has("onRequest")&&(await i.run("onRequest",s),s.responded()))return;const a=(0,manifest_1.matchRoute)(n.routes,O(e),l+h.query);if(!a){S(e,t);return}s.route=a;const w=d.startHeadlessFlow(e,a,o,u);if(w!==o&&(o=w,s.trace=w,e.__lensmcpTrace=w),d.traceStep(o,"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,t,n.routes),t.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_ROUTED,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),t.end();return}if((0,edge_1.cors)(e,t,n.routes),i.has("beforeAuth")&&(await i.run("beforeAuth",s),s.responded()))return;if(a.internal){const c=v.internal(e,a,o);if(!c.ok){d.finishTrace(o,a.project,c.status,void 0,a),(0,edge_1.sendError)(t,e,c.status,c.reason,c.detail);return}s.caller=c.caller}else{const c=v.public(e,a,o,l);if(!c.ok){d.finishTrace(o,a.project,c.status,void 0,a),(0,edge_1.sendError)(t,e,c.status,c.reason,c.detail);return}if(s.claims=c.claims,i.has("afterAuth")&&(await i.run("afterAuth",s),s.responded()))return}const g=a.pool?n.serviceKeys[(0,service_keys_1.serviceKeyId)(a.svc?.wsKey,a.project)]:void 0;if(g&&(e.headers["x-internal-token"]=g),(0,edge_1.stampForwardingHeaders)(n,e),i.has("beforeForward")&&(await i.run("beforeForward",s),s.responded()))return;i.has("onResponse")&&t.on("close",()=>{s.status=t.statusCode??0,i.run("onResponse",s)}),_.forward(a,e,t)}catch(r){s.error=r,console.error(`[gateway] ${new Date().toISOString()} pipeline error traceId=${(0,gateway_errors_1.ensureRequestId)(e)}: ${r?.stack??String(r)}`),i.has("onError")&&await i.run("onError",s),s.responded()||(0,edge_1.sendError)(t,e,500,"internal","Internal gateway error.")}},"runPipeline");return(e,t)=>{b(e,t)}}y(createHandler,"createHandler"),p(createHandler,"createHandler");
1
+ "use strict";var j=Object.defineProperty;var v=(h,n)=>j(h,"name",{value:n,configurable:!0});var q=Object.defineProperty,y=v((h,n)=>q(h,"name",{value:n,configurable:!0}),"y"),x=Object.defineProperty,p=y((h,n)=>x(h,"name",{value:n,configurable:!0}),"p");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(h){const{rt:n,obs:d,auth:m,proxy:b,hooks:i}=h,O=p(e=>(e.headers.host||"").split(":")[0],"hostOf"),S=p((e,t)=>{if((0,edge_1.cors)(e,t,n.routes),e.method==="OPTIONS"){t.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_NOROUTE,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),t.end();return}const s=(e.headers.host||"").split(":")[0],l=n.routes.filter(r=>r.host&&(0,manifest_1.hostMatches)(r.host,s)&&r.prefix),o=(e.url??"/").split("?")[0];if((o==="/"||o==="/index.html"||o==="")&&n.routes.some(r=>r.host&&(0,manifest_1.hostMatches)(r.host,s)&&r.project===observability_1.LENS_DASHBOARD_PROJECT)){(0,chooser_1.serveChooser)(t,n.wsKey,e);return}if(l.length>0&&(o==="/health"||o==="/healthz")){const r=l.map(u=>({project:u.project,prefix:u.prefix,pods:u.pool?((0,discovery_1.pickSock)(u.pool,0),u.pool.socks.length):void 0,state:u.svc?.state??(u.target?"up":"unknown")})),f=r.every(u=>u.state!=="down"||!0);t.writeHead(f?200:503,{"content-type":"application/json"}),t.end(JSON.stringify({status:"ok",host:s,services:r},null,2));return}if(l.length>0&&o==="/.well-known/services"){t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({host:s,services:l.map(r=>({prefix:r.prefix,project:r.project,internal:!!r.internal}))},null,2));return}(0,edge_1.sendError)(t,e,404,"not_found",l.length>0?`No service mounted at ${o}. Mounted on ${s}: ${[...new Set(l.map(r=>r.prefix))].join(", ")} (+ /health, /.well-known/services)`:"No gateway route for this hostname.")},"handleNoRoute"),H=p(async(e,t)=>{if(!e.headers.host){const r=e.authority??e.headers[":authority"];r&&(e.headers.host=r)}(0,edge_1.stripOwnedHeaders)(e);let s=d.beginTrace(e);const l=Date.now();(0,gateway_errors_1.ensureRequestId)(e),s&&(d.traceStep(s,"received",{host:s.host,method:s.method,url:s.url}),e.__lensmcpTrace=s);const o=i.httpContext(e,t,s);try{const r=e.url??"/",f=(0,edge_1.canonicalize)(r);if(f===void 0){d.traceStep(s,"bad-path",{}),d.finishTrace(s,"gateway",400),(0,edge_1.sendError)(t,e,400,"bad_request","Bad Request");return}const u=f.policy,g=f.path+f.query;if(g!==r&&(0,edge_1.rememberRawTarget)(e,r),e.url=g,(0,edge_1.resolveClientIp)(n,e),i.has("onRequest")&&(await i.run("onRequest",o),o.responded()))return;const a=(0,manifest_1.matchRoute)(n.routes,O(e),u+f.query);if(!a){S(e,t);return}o.route=a;const w=d.startHeadlessFlow(e,a,s,l);if(w!==s&&(s=w,o.trace=w,e.__lensmcpTrace=w),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,t,n.routes),t.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_ROUTED,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),t.end();return}if((0,edge_1.cors)(e,t,n.routes),i.has("beforeAuth")&&(await i.run("beforeAuth",o),o.responded()))return;if(a.internal){const c=m.internal(e,a,s);if(!c.ok){d.finishTrace(s,a.project,c.status,void 0,a),(0,edge_1.sendError)(t,e,c.status,c.reason,c.detail);return}o.caller=c.caller}else{const c=m.public(e,a,s,u);if(!c.ok){d.finishTrace(s,a.project,c.status,void 0,a),(0,edge_1.sendError)(t,e,c.status,c.reason,c.detail);return}if(o.claims=c.claims,i.has("afterAuth")&&(await i.run("afterAuth",o),o.responded()))return}const _=a.pool?n.serviceKeys[(0,service_keys_1.serviceKeyId)(a.svc?.wsKey,a.project)]:void 0;if(_&&(e.headers["x-internal-token"]=_),(0,edge_1.stampForwardingHeaders)(n,e),i.has("beforeForward")&&(await i.run("beforeForward",o),o.responded()))return;i.has("onResponse")&&t.on("close",()=>{o.status=t.statusCode??0,i.run("onResponse",o)}),b.forward(a,e,t)}catch(r){o.error=r,console.error(`[gateway] ${new Date().toISOString()} pipeline error traceId=${(0,gateway_errors_1.ensureRequestId)(e)}: ${r?.stack??String(r)}`),i.has("onError")&&await i.run("onError",o),o.responded()||(0,edge_1.sendError)(t,e,500,"internal","Internal gateway error.")}},"runPipeline");return(e,t)=>{H(e,t)}}v(createHandler,"createHandler"),y(createHandler,"createHandler"),p(createHandler,"createHandler");
@@ -1 +1 @@
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
+ "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 +1 @@
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
+ "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,2 +1,2 @@
1
- "use strict";var x=Object.defineProperty;var a=(t,e)=>x(t,"name",{value:e,configurable:!0});var h=Object.defineProperty,c=a((t,e)=>h(t,"name",{value:e,configurable:!0}),"c");Object.defineProperty(exports,"__esModule",{value:!0}),exports.INSTANCE_NAME_PATTERN=void 0,exports.parseInstanceDecl=parseInstanceDecl,exports.instanceKey=instanceKey,exports.instanceSockNs=instanceSockNs,exports.commonApex=commonApex,exports.rewriteHost=rewriteHost,exports.envSuffix=envSuffix,exports.instanceBuiltinEnv=instanceBuiltinEnv,exports.instanceEnvFile=instanceEnvFile,exports.instanceResourcesEnvFile=instanceResourcesEnvFile,exports.parseInstanceEnv=parseInstanceEnv,exports.instanceEnv=instanceEnv;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.INSTANCE_NAME_PATTERN=/^[a-z0-9](?:[a-z0-9-]{0,18}[a-z0-9])?$/;const HOST_PATTERN=/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/;function parseInstanceDecl(t){if(!t||typeof t!="object")return;const e=t;if(typeof e.name!="string"||!exports.INSTANCE_NAME_PATTERN.test(e.name)||typeof e.baseKey!="string"||e.baseKey.length===0)return;const n=typeof e.apex=="string"&&HOST_PATTERN.test(e.apex.toLowerCase())?e.apex.toLowerCase():void 0;return{name:e.name,baseKey:e.baseKey,...n?{apex:n}:{},...typeof e.mainRoot=="string"&&e.mainRoot.length>0?{mainRoot:e.mainRoot}:{},...e.frozen===!0?{frozen:!0}:{}}}a(parseInstanceDecl,"parseInstanceDecl"),c(parseInstanceDecl,"parseInstanceDecl");function instanceKey(t,e){return`${t}-${e}`}a(instanceKey,"instanceKey"),c(instanceKey,"instanceKey");function instanceSockNs(t){let e=2166136261;for(let n=0;n<t.length;n++)e^=t.charCodeAt(n),e=Math.imul(e,16777619);return`i-${(e>>>0&16777215).toString(16).padStart(6,"0")}`}a(instanceSockNs,"instanceSockNs"),c(instanceSockNs,"instanceSockNs");function commonApex(t){const e=t.map(s=>s.toLowerCase().replace(/^\*\./,"")).filter(s=>s.length>0).map(s=>s.split(".").reverse());if(e.length===0)return;const n=[];for(let s=0;;s++){const i=e[0]?.[s];if(i===void 0||!e.every(r=>r[s]===i))break;n.push(i)}return n.length>=2?n.reverse().join("."):void 0}a(commonApex,"commonApex"),c(commonApex,"commonApex");function rewriteHost(t,e,n){const s=t.toLowerCase();if(s.startsWith("*.")){const i=rewriteHost(s.slice(2),e,n);return i===void 0?void 0:`*.${i}`}if(s===e)return`${n}.${e}`;if(s.endsWith(`.${e}`))return`${s.slice(0,-e.length)}${n}.${e}`}a(rewriteHost,"rewriteHost"),c(rewriteHost,"rewriteHost");function envSuffix(t){return t.toUpperCase().replace(/[^A-Z0-9]+/g,"_").replace(/^_+|_+$/g,"")}a(envSuffix,"envSuffix"),c(envSuffix,"envSuffix");function instanceBuiltinEnv(t,e){const n={LENSMCP_INSTANCE:t.name,LENSMCP_APEX:t.apex,LENSMCP_BASE_APEX:t.baseApex},s={};for(const[i,r]of Object.entries(e).sort(([o],[l])=>o.localeCompare(l))){const o=envSuffix(i);o&&(r.host&&(n[`LENSMCP_HOST_${o}`]=r.host),r.internalHost&&(n[`LENSMCP_INTERNAL_HOST_${o}`]=r.internalHost),(r.host||r.internalHost)&&(s[i]={...r.host?{host:r.host}:{},...r.internalHost?{internalHost:r.internalHost}:{}}))}return n.LENSMCP_HOSTS_JSON=JSON.stringify(s),n}a(instanceBuiltinEnv,"instanceBuiltinEnv"),c(instanceBuiltinEnv,"instanceBuiltinEnv");function instanceEnvFile(t){return path.join(t,".lensmcp","instance.env")}a(instanceEnvFile,"instanceEnvFile"),c(instanceEnvFile,"instanceEnvFile");function instanceResourcesEnvFile(t){return path.join(t,".lensmcp","instance.resources.env")}a(instanceResourcesEnvFile,"instanceResourcesEnvFile"),c(instanceResourcesEnvFile,"instanceResourcesEnvFile");function parseInstanceEnv(t,e){const n={},s=[],i=c(o=>n[o]??e[o]??"","lookup"),r=c(o=>o.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g,(l,u)=>i(u)),"expand");return t.split(/\r?\n/).forEach((o,l)=>{const u=o.trim();if(u===""||u.startsWith("#"))return;const v=/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(u);if(!v){s.push(l+1);return}const[,_,p]=v;let E;if(p.startsWith("'")){const f=p.indexOf("'",1);if(f<0){s.push(l+1);return}E=p.slice(1,f)}else if(p.startsWith('"')){const f=p.indexOf('"',1);if(f<0){s.push(l+1);return}E=r(p.slice(1,f).replace(/\\n/g,`
2
- `))}else E=r(p.replace(/\s+#.*$/,"").trim());n[_]=E}),{env:n,skipped:s}}a(parseInstanceEnv,"parseInstanceEnv"),c(parseInstanceEnv,"parseInstanceEnv");function instanceEnv(t,e){let n={...e};for(const s of[instanceResourcesEnvFile(t),instanceEnvFile(t)]){let i;try{i=fs.readFileSync(s,"utf8")}catch{continue}const{env:r,skipped:o}=parseInstanceEnv(i,n);o.length>0&&console.warn(`[gateway] ${s}: skipped malformed line(s) ${o.join(", ")}`),n={...n,...r}}return{...n,...e}}a(instanceEnv,"instanceEnv"),c(instanceEnv,"instanceEnv");
1
+ "use strict";var S=Object.defineProperty;var p=(n,e)=>S(n,"name",{value:e,configurable:!0});var x=Object.defineProperty,a=p((n,e)=>x(n,"name",{value:e,configurable:!0}),"a"),h=Object.defineProperty,c=a((n,e)=>h(n,"name",{value:e,configurable:!0}),"c");Object.defineProperty(exports,"__esModule",{value:!0}),exports.INSTANCE_NAME_PATTERN=void 0,exports.parseInstanceDecl=parseInstanceDecl,exports.instanceKey=instanceKey,exports.instanceSockNs=instanceSockNs,exports.commonApex=commonApex,exports.rewriteHost=rewriteHost,exports.envSuffix=envSuffix,exports.instanceBuiltinEnv=instanceBuiltinEnv,exports.instanceEnvFile=instanceEnvFile,exports.instanceResourcesEnvFile=instanceResourcesEnvFile,exports.parseInstanceEnv=parseInstanceEnv,exports.instanceEnv=instanceEnv;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.INSTANCE_NAME_PATTERN=/^[a-z0-9](?:[a-z0-9-]{0,18}[a-z0-9])?$/;const HOST_PATTERN=/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/;function parseInstanceDecl(n){if(!n||typeof n!="object")return;const e=n;if(typeof e.name!="string"||!exports.INSTANCE_NAME_PATTERN.test(e.name)||typeof e.baseKey!="string"||e.baseKey.length===0)return;const t=typeof e.apex=="string"&&HOST_PATTERN.test(e.apex.toLowerCase())?e.apex.toLowerCase():void 0;return{name:e.name,baseKey:e.baseKey,...t?{apex:t}:{},...typeof e.mainRoot=="string"&&e.mainRoot.length>0?{mainRoot:e.mainRoot}:{},...e.frozen===!0?{frozen:!0}:{}}}p(parseInstanceDecl,"parseInstanceDecl"),a(parseInstanceDecl,"parseInstanceDecl"),c(parseInstanceDecl,"parseInstanceDecl");function instanceKey(n,e){return`${n}-${e}`}p(instanceKey,"instanceKey"),a(instanceKey,"instanceKey"),c(instanceKey,"instanceKey");function instanceSockNs(n){let e=2166136261;for(let t=0;t<n.length;t++)e^=n.charCodeAt(t),e=Math.imul(e,16777619);return`i-${(e>>>0&16777215).toString(16).padStart(6,"0")}`}p(instanceSockNs,"instanceSockNs"),a(instanceSockNs,"instanceSockNs"),c(instanceSockNs,"instanceSockNs");function commonApex(n){const e=n.map(s=>s.toLowerCase().replace(/^\*\./,"")).filter(s=>s.length>0).map(s=>s.split(".").reverse());if(e.length===0)return;const t=[];for(let s=0;;s++){const o=e[0]?.[s];if(o===void 0||!e.every(r=>r[s]===o))break;t.push(o)}return t.length>=2?t.reverse().join("."):void 0}p(commonApex,"commonApex"),a(commonApex,"commonApex"),c(commonApex,"commonApex");function rewriteHost(n,e,t){const s=n.toLowerCase();if(s.startsWith("*.")){const o=rewriteHost(s.slice(2),e,t);return o===void 0?void 0:`*.${o}`}if(s===e)return`${t}.${e}`;if(s.endsWith(`.${e}`))return`${s.slice(0,-e.length)}${t}.${e}`}p(rewriteHost,"rewriteHost"),a(rewriteHost,"rewriteHost"),c(rewriteHost,"rewriteHost");function envSuffix(n){return n.toUpperCase().replace(/[^A-Z0-9]+/g,"_").replace(/^_+|_+$/g,"")}p(envSuffix,"envSuffix"),a(envSuffix,"envSuffix"),c(envSuffix,"envSuffix");function instanceBuiltinEnv(n,e){const t={LENSMCP_INSTANCE:n.name,LENSMCP_APEX:n.apex,LENSMCP_BASE_APEX:n.baseApex},s={};for(const[o,r]of Object.entries(e).sort(([i],[u])=>i.localeCompare(u))){const i=envSuffix(o);i&&(r.host&&(t[`LENSMCP_HOST_${i}`]=r.host),r.internalHost&&(t[`LENSMCP_INTERNAL_HOST_${i}`]=r.internalHost),(r.host||r.internalHost)&&(s[o]={...r.host?{host:r.host}:{},...r.internalHost?{internalHost:r.internalHost}:{}}))}return t.LENSMCP_HOSTS_JSON=JSON.stringify(s),t}p(instanceBuiltinEnv,"instanceBuiltinEnv"),a(instanceBuiltinEnv,"instanceBuiltinEnv"),c(instanceBuiltinEnv,"instanceBuiltinEnv");function instanceEnvFile(n){return path.join(n,".lensmcp","instance.env")}p(instanceEnvFile,"instanceEnvFile"),a(instanceEnvFile,"instanceEnvFile"),c(instanceEnvFile,"instanceEnvFile");function instanceResourcesEnvFile(n){return path.join(n,".lensmcp","instance.resources.env")}p(instanceResourcesEnvFile,"instanceResourcesEnvFile"),a(instanceResourcesEnvFile,"instanceResourcesEnvFile"),c(instanceResourcesEnvFile,"instanceResourcesEnvFile");function parseInstanceEnv(n,e){const t={},s=[],o=c(i=>t[i]??e[i]??"","lookup"),r=c(i=>i.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g,(u,f)=>o(f)),"expand");return n.split(/\r?\n/).forEach((i,u)=>{const f=i.trim();if(f===""||f.startsWith("#"))return;const _=/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(f);if(!_){s.push(u+1);return}const[,m,l]=_;let E;if(l.startsWith("'")){const v=l.indexOf("'",1);if(v<0){s.push(u+1);return}E=l.slice(1,v)}else if(l.startsWith('"')){const v=l.indexOf('"',1);if(v<0){s.push(u+1);return}E=r(l.slice(1,v).replace(/\\n/g,`
2
+ `))}else E=r(l.replace(/\s+#.*$/,"").trim());t[m]=E}),{env:t,skipped:s}}p(parseInstanceEnv,"parseInstanceEnv"),a(parseInstanceEnv,"parseInstanceEnv"),c(parseInstanceEnv,"parseInstanceEnv");function instanceEnv(n,e){let t={...e};for(const s of[instanceResourcesEnvFile(n),instanceEnvFile(n)]){let o;try{o=fs.readFileSync(s,"utf8")}catch{continue}const{env:r,skipped:i}=parseInstanceEnv(o,t);i.length>0&&console.warn(`[gateway] ${s}: skipped malformed line(s) ${i.join(", ")}`),t={...t,...r}}return{...t,...e}}p(instanceEnv,"instanceEnv"),a(instanceEnv,"instanceEnv"),c(instanceEnv,"instanceEnv");
@@ -1 +1 @@
1
- "use strict";var Ce=Object.defineProperty;var v=(s,E)=>Ce(s,"name",{value:E,configurable:!0});var Pe=Object.defineProperty,d=v((s,E)=>Pe(s,"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.signalChild=signalChild,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(s,E){return new Promise(f=>{const _=net.createServer();_.unref(),_.once("error",p=>{const g=p.code??"";f(g==="EADDRINUSE"||g==="EACCES"?"in-use":"unavailable")}),_.listen(E===void 0?{port:s}:{port:s,host:E},()=>_.close(()=>f("free")))})}v(tryBind,"tryBind"),d(tryBind,"tryBind");async function probePortFree(s){for(const E of[void 0,"0.0.0.0","127.0.0.1","::1"])if(await tryBind(s,E)==="in-use")return!1;return!0}v(probePortFree,"probePortFree"),d(probePortFree,"probePortFree");function probeConnect(s,E,f){return new Promise(_=>{let p=!1;const g=net.createConnection({host:s,port:E});g.unref();const M=setTimeout(()=>L(!1),f);M.unref?.();function L(b){p||(p=!0,clearTimeout(M),g.destroy(),_(b))}v(L,"R"),d(L,"finish"),g.once("connect",()=>L(!0)),g.once("error",()=>L(!1))})}v(probeConnect,"probeConnect"),d(probeConnect,"probeConnect");async function probePortListening(s,E=1e3){return await probeConnect("127.0.0.1",s,E)?!0:probeConnect("::1",s,E)}v(probePortListening,"probePortListening"),d(probePortListening,"probePortListening");async function probeWatcherHealth(s,E=1500){try{const f=new AbortController,_=setTimeout(()=>f.abort(),E);_.unref?.();try{const p=await fetch(`http://127.0.0.1:${s}/__lensmcp/watcher-health`,{signal:f.signal});if(!p.ok)return null;const g=await p.json();if(typeof g?.lastFsSetEventAt!="number")return null;const M=Array.isArray(g.recentEvents)?g.recentEvents.filter(L=>L&&typeof L.path=="string"&&typeof L.at=="number"&&typeof L.sequence=="number"&&["add","addDir","unlink","unlinkDir"].includes(L.kind)):[];return{schemaVersion:g.schemaVersion===2?2:1,ready:g.ready!==!1,sequence:typeof g.sequence=="number"?g.sequence:0,lastFsSetEventAt:g.lastFsSetEventAt,fsSetEvents:typeof g.fsSetEvents=="number"?g.fsSetEvents:0,recentEvents:M}}finally{clearTimeout(_)}}catch{return null}}v(probeWatcherHealth,"probeWatcherHealth"),d(probeWatcherHealth,"probeWatcherHealth");const sleepUnref=d(s=>new Promise(E=>{setTimeout(E,s).unref?.()}),"sleepUnref");async function waitForPortFree(s,E,f={}){const _=f.isPortFree??probePortFree,p=Math.max(1,f.intervalMs??types_1.PORT_FREE_POLL_MS),g=Date.now()+Math.max(0,E);for(;;){if(await _(s))return!0;const M=g-Date.now();if(M<=0)return!1;await sleepUnref(Math.min(p,M))}}v(waitForPortFree,"waitForPortFree"),d(waitForPortFree,"waitForPortFree");function viteArgPort(s){const E=d(f=>Number.isInteger(f)&&f>0&&f<65536?f:void 0,"valid");for(let f=0;f<s.length;f+=1){const _=s[f];if(_==="--port")return E(Number(s[f+1]));if(_.startsWith("--port="))return E(Number(_.slice(7)))}}v(viteArgPort,"viteArgPort"),d(viteArgPort,"viteArgPort");function describeChildExit(s){return s.signalCode?`killed by ${s.signalCode}`:s.exitCode===null?"exit status unknown":`exit code ${s.exitCode}`}v(describeChildExit,"describeChildExit"),d(describeChildExit,"describeChildExit");function signalChild(s,E){if(s.pid===void 0)return!1;try{return s.kill(E)}catch{return!1}}v(signalChild,"signalChild"),d(signalChild,"signalChild");async function claimPort(s,E,f,_){let p=s;for(;E.has(p)||_?.has(p)||!await f(p);)p+=1;return E.add(p),p}v(claimPort,"claimPort"),d(claimPort,"claimPort");function createLensChildren(s,E,f,_){const{emit:p}=E,g=_?.isPortFree??probePortFree,M=(f.ports?.length?f.ports:[443]).join(","),L=_?.probeWatcherHealth??probeWatcherHealth,b=[],B=new Map,A=new Map,I=new Map,Y=new Map,W=new Set;let j;const m=new Map,$=new Set,q=new Set,V=new Set,T=new Set,C=new Map,F=new WeakMap,G=new Set,Q=d((e,r,o)=>{if(G.has(e))return;G.add(e);const t=setInterval(()=>{(async()=>{if(s.stopped()||$.has(e)){clearInterval(t),G.delete(e);return}await g(r)&&(clearInterval(t),G.delete(e),console.log(`[gateway] lens child ${e}: :${r} freed \u2014 respawning.`),o())})().catch(()=>{})},types_1.LENS_PARKED_PORT_REPROBE_MS);t.unref?.()},"parkUntilPortFree"),x=d(async(e,r,o)=>{const t=await claimPort(e,r,g,o?.reserved);return t!==e&&(o?.heldBy?console.log(`[gateway] handoff: :${e} is held by ${o.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,r,o)=>{const t=o?.LENSMCP_FRONTEND_KEY,n=Number(o?.LENSMCP_FRONTEND_GENERATION);if(!t||!Number.isFinite(n))return;const a=[...C.get(t)?.generations??[]].find(l=>l.generation===n);a&&(e.endsWith(":vite")?a.vite=r:e.endsWith(":browser-capture")&&(a.capture=r))},"attachRespawnedGenerationChild"),H=d(e=>{e.exitCode!==null||e.signalCode!==null||e.pid===void 0||(q.add(e),signalChild(e,"SIGTERM"),setTimeout(()=>{e.exitCode===null&&e.signalCode===null&&signalChild(e,"SIGKILL")},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.())},"retireChild"),de=d((e,r)=>{const o=m.get(e);!o||o===r||o.exitCode!==null||o.signalCode!==null||(console.warn(`[gateway] lens child ${e}: a replacement took the label \u2014 retiring the previous child (pid ${o.pid??"?"}).`),H(o))},"retireLabelHolder"),k=d((e,r,o,t,n=!1,a,l,c)=>{const u=Date.now(),i=(0,node_child_process_1.spawn)(r,o,{cwd:l??s.root,env:{...(0,pod_env_1.podBaseEnv)(process.env,s.root,l??s.root),...t??{},LENSMCP_PARENT_PID:String(process.pid)},stdio:"inherit"});b.push(i),de(e,i),m.set(e,i),ce(e,i,t);const S=e==="vite"||e.endsWith(":vite"),N=typeof t?.LENSMCP_EVENT_FILE=="string"?t.LENSMCP_EVENT_FILE:void 0,y=N&&N!==s.eventFile?N:void 0,w=S?viteArgPort(o):c;S&&A.set(i,{key:t?.LENSMCP_FRONTEND_KEY??`${l??s.root}:${t?.LENSMCP_PROJECT??"app"}`,project:t?.LENSMCP_PROJECT??"app",workspaceRoot:l??s.root,spawnedAt:u,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 h=e==="lens-mcp"?"lens-mcp":e==="lens-dashboard"||e.startsWith("lens-dashboard:")?"lens-dashboard":void 0;return h&&w!==void 0&&(p("info",`lens child starting: ${h} (:${w})`,`cluster-lens-child:${h}`,{kind:"lens-child-starting",project:h,label:e,pid:i.pid,port:w},void 0,y),(async()=>{const P=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<P;){if(i.exitCode!==null||i.signalCode!==null||$.has(e))return;if(await probePortListening(w,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){p("info",`lens child up: ${h} (:${w})`,`cluster-lens-child:${h}`,{kind:"lens-child-up",project:h,label:e,pid:i.pid,port:w},void 0,y);return}await sleepUnref(150)}})().catch(()=>{})),i.on("error",P=>{if(i.pid!==void 0){console.warn(`[gateway] lens child ${e}: ${P.message}`);return}const D=b.indexOf(i);D>=0&&b.splice(D,1),m.get(e)===i&&m.delete(e),A.delete(i),q.delete(i),console.error(`[gateway] lens child ${e} failed to spawn (${P.message}) \u2014 not started, not retried.`)}),i.on("exit",(P,D)=>{const se=b.indexOf(i);se>=0&&b.splice(se,1),m.get(e)===i&&m.delete(e);const O=A.get(i);if(A.delete(i),q.delete(i))return;const ve=$.delete(e);if(s.stopped()||ve||(h?p("warning",`lens child exited: ${h}`,`cluster-lens-child:${h}`,{kind:"lens-child-exit",project:h,label:e,pid:i.pid,code:P,signal:D},void 0,y):O&&p("warning",`lens frontend exited: ${O.project}`,`cluster-lens-child:${O.project}`,{kind:"lens-child-exit",project:O.project,label:e,pid:i.pid,code:P,signal:D,generation:O.generation,port:O.port,ranMs:Date.now()-u},void 0,y),O&&fe(i,O)))return;const ae=Date.now()-u,R=B.get(e)??{attempts:0,portConflicts:0};(async()=>{const Le=w!==void 0&&!await g(w),ie=(0,lifecycle_1.isPortConflictExit)({code:P,signal:D,ranMs:ae,portHeld:Le},{fastFailMs:types_1.CHILD_START_FAIL_MS});if(ie&&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=${P}); 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,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}),Q(e,w,()=>k(e,r,o,t,n,a,l,c));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,B.set(e,R),console.warn(`[gateway] lens child ${e} exited (code=${P} sig=${D}); auto-healing in ${Math.round(le/1e3)}s (attempt ${R.attempts}).`),await sleepUnref(le)}s.stopped()||$.has(e)||(w!==void 0&&!await waitForPortFree(w,types_1.PORT_FREE_WAIT_MS,{isPortFree:g,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.`),!(s.stopped()||$.has(e))&&k(e,r,o,t,n,a,l,c))})().catch(()=>{})}),i},"spawnManagedChild"),ee=d(e=>{const r=`${e.wsKey}:${e.project}`,o=C.get(r);if(o)return o;const t={key:r,...e,sourceDirs:e.frontend.sourceRoots?.length?e.frontend.sourceRoots:[e.projectRoot],generation:0,state:"starting",generations:new Set,disposed:!1};C.set(r,t);for(const n of e.routes)n.lens&&(n.lens.workspaceKey??=e.wsKey,F.set(n.lens,t));return e.frontend.workspaceKey??=e.wsKey,F.set(e.frontend,t),t},"registerFrontend"),pe=d(e=>{if(!types_1.LENS_WATCH_SCOPE_ENABLED)return{};const r=path.resolve(e.projectRoot),o=e.sourceDirs.map(t=>path.resolve(t)).filter(t=>t!==r);return o.length>0?{LENSMCP_WATCH_DIRS:o.join(path.delimiter)}:{}},"lensWatchScopeEnv"),te=d((e,r,o)=>{const t=++e.generation,n=`${e.key}:g${t}:`,a=`${n}vite`,l=`${n}browser-capture`;$.delete(a),$.delete(l);const c=d((S,N,y,w,h,P)=>k(S,N,y,w,h,P,e.workspaceRoot),"spawnInRoot"),u=(0,lens_frontend_1.spawnLensFrontend)({projectRoot:e.projectRoot,workspaceRoot:e.workspaceRoot,project:e.project,eventFile:e.eventFile,port:r,chrome:!0,headless:!0,viteEnv:{...e.frontend.env??{},...e.frontend.frozen?{LENSMCP_FREEZE:"1"}:{},LENSMCP_PROJECT:e.project,LENSMCP_FRONTEND_KEY:e.key,LENSMCP_FRONTEND_GENERATION:String(t),LENSMCP_FRONTEND_ROLE:o,...pe(e),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false"},labelPrefix:n,log:d(S=>console.log(S),"log")},c),i={ownerKey:e.key,generation:t,port:r,labelPrefix:n,vite:u?.vite??m.get(a),capture:m.get(l)};return e.generations.add(i),i},"spawnFrontendGeneration"),K=d((e,r)=>{if(!e)return;C.get(e.ownerKey)?.generations.delete(e);const o=[[`${e.labelPrefix}browser-capture`,e.capture],[`${e.labelPrefix}vite`,e.vite]];for(const[t,n]of o)$.add(t),n&&H(n);r&&T.delete(e.port)},"terminateGeneration"),ue=d(async e=>{const r=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<r;){const o=e.vite;if(!o||o.exitCode!==null||o.signalCode!==null)return!1;if(await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){const t=await L(e.port);if(!t||t.ready)return!0}await sleepUnref(150)}return!1},"waitForGenerationReady"),U=d(async e=>{const r=e?.vite;return!!(e&&r&&r.exitCode===null&&r.signalCode===null&&await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)))},"generationIsServing"),z=d(e=>!e.disposed&&!s.stopped()&&C.get(e.key)===e,"frontendIsCurrent"),X=d((e,r)=>{if(!z(e))return Promise.resolve(!1);if(e.replacement)return e.replacement;const o=e.active;e.state=o?"replacing":"starting",e.reason=r,e.startedAt=Date.now();const t=(async()=>{let n,a;const l=Date.now();try{const c=new Set;for(const h of C.values())h!==e&&c.add(h.desiredPort);const u=o&&o.port===e.desiredPort?`g${o.generation}`:void 0,i=await x(e.desiredPort,T,{reserved:c,heldBy:u});if(a=i,!z(e))return T.delete(i),!1;n=te(e,i,"replacement"),e.candidate=n;const S=await U(o);console.log(`[gateway] lens handoff start: ${e.key} g${o?.generation??0}\u2192g${n.generation} :${o?.port??"down"}\u2192:${i} reason=${r}`),p("info",`lens handoff starting: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-start",wsKey:e.wsKey,project:e.project,reason:r,generation:n.generation,oldPort:o?.port,newPort:i,oldServing:S},void 0,e.eventFile===s.eventFile?void 0:e.eventFile);const N=await ue(n);if(!z(e))return K(n,!0),e.candidate=void 0,!1;if(!N){K(n,!0),e.candidate=void 0;const h=await U(o);return e.state=h?"ready":"failed",h&&(e.reason=void 0,e.startedAt=void 0),console.error(`[gateway] lens handoff failed: ${e.key} g${n.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:r,generation:n.generation,port:i,durationMs:Date.now()-l,oldKept:h},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}for(const h of e.routes)h.target=`http://localhost:${n.port}`,h.lens&&(h.lens.port=n.port);e.frontend.port=n.port,e.active=n,e.candidate=void 0,e.state="ready",e.reason=void 0,e.startedAt=void 0;const y=n.vite?A.get(n.vite):void 0;y&&(y.role="active",y.listening=!0);const w=(0,hmr_reload_1.broadcastFullReload)(s,e.key);if(console.log(`[gateway] lens handoff ready: ${e.key} g${n.generation} :${n.port} in ${Date.now()-l}ms; draining g${o?.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:r,generation:n.generation,oldPort:o?.port,newPort:n.port,durationMs:Date.now()-l,reloadedTabs:w},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),o){const h=`${o.labelPrefix}browser-capture`;$.add(h),o.capture&&H(o.capture),setTimeout(()=>K(o,!0),types_1.LENS_REPLACEMENT_DRAIN_MS).unref?.()}return!0}catch(c){K(n,!0),!n&&a!==void 0&&T.delete(a),e.candidate=void 0;const u=await U(o);e.state=u?"ready":"failed",u&&(e.reason=void 0,e.startedAt=void 0);const i=c.message;return console.error(`[gateway] lens handoff failed: ${e.key}: ${i}`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:r,generation:n?.generation??e.generation,port:n?.port??a,durationMs:Date.now()-l,oldKept:u,error:i},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}finally{e.replacement=void 0}})();return e.replacement=t,t},"rollFrontend"),ne=d((e,r)=>{e.active=te(e,r,"active"),e.state="starting",e.startedAt=Date.now()},"spawnInitialFrontend"),fe=d((e,r)=>{const o=C.get(r.key);return!o||types_1.LENS_RESTART_MODE==="in-place"?!1:(o.candidate?.vite===e||o.active?.vite!==e||(o.state="starting",o.reason="child-exit",o.startedAt=Date.now(),console.warn(`[gateway] lens frontend exited: ${o.key} g${r.generation} :${r.port} (${describeChildExit(e)}); starting an alternate-port replacement.`),X(o,"child-exit")),!0)},"handleManagedViteExit");s.lensSupervisor=types_1.LENS_RESTART_MODE==="rolling"?{status(e){const r=F.get(e);return r?{state:r.state,generation:r.candidate?.generation??r.active?.generation??r.generation,reason:r.reason,startedAt:r.startedAt}:void 0},recover(e,r){const o=F.get(e);return o?X(o,r):Promise.resolve(!1)}}:void 0;let J=!1,oe=0;const Ee=d(()=>{J||Date.now()-oe<types_1.POD_STALE_SCAN_MS||(J=!0,oe=Date.now(),(async()=>{const e=new Map;for(const r of[...C.values()]){if(s.stopped())return;let o=e.get(r.workspaceRoot);if(!o){const i=(0,scope_1.readSourceSetOptions)(r.workspaceRoot);o={pass:(0,lifecycle_1.sourceScanPass)(r.workspaceRoot,i.exclude,{ignoreTests:i.ignoreTests}),startedAt:Date.now()},e.set(r.workspaceRoot,o)}const t=o.startedAt,n=await o.pass.snapshot(r.sourceDirs);if(C.get(r.key)!==r)continue;const a=r.sourceSnapshot,l=r.sourceScanStartedAt;if(r.sourceSnapshot=n,r.sourceScanStartedAt=t,!a)continue;const c=Date.now(),u=(0,lifecycle_1.diffSourceSets)(a,n,c,(0,lifecycle_1.sourceChangeWindowMs)(c,l,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS));u&&(r.sourceChange=u,p("info",`source file set changed for ${r.key}`,`cluster-lens-app:${r.project}`,{kind:"source-set-changed",scoped:!0,wsKey:r.wsKey,project:r.project,added:u.added,removed:u.removed,truncated:u.truncated},void 0,r.eventFile===s.eventFile?void 0:r.eventFile))}})().catch(()=>{}).finally(()=>{J=!1}))},"scanFrontendSourceSets");let Z=!1;const ge=d(async(e,r)=>{if(!Z){Z=!0;try{for(const[o,t]of[...A]){if(s.stopped())return;if(t.port===void 0||o.exitCode!==null||o.signalCode!==null)continue;if(await probePortListening(t.port,types_1.LENS_PROBE_TIMEOUT_MS)){if(t.probeFails=0,!t.listening){t.listening=!0;const c=C.get(t.key);c?.active?.vite===o&&(c.state="ready",c.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 n=t.listening?e.graceMs:Math.max(e.graceMs,e.neverListenedGraceMs);if(Date.now()-t.spawnedAt<n){t.probeFails=0;continue}if(!r)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 l=t.listening?"its listener VANISHED (was up, now refusing)":`it NEVER bound within the ${Math.round(n/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 ${l} \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),signalChild(o,"SIGKILL")}}finally{Z=!1}}},"probeLensChildren"),he=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(s.stopped()||A.size===0||(re(),!types_1.POD_RECYCLE_ENABLED))return;Ee();const r=Date.now();for(const[o,t]of A){const n=C.get(t.key);if(n?.frontend.frozen)continue;const a=n?.sourceChange?.changedAt??0,l=I.get(t.key)??0;(0,lifecycle_1.lensFrontendStale)(t.spawnedAt,l,a,r,e)&&((Y.get(t.key)??0)>=a||W.has(t.key)||(W.add(t.key),(async()=>{try{const c=n?.sourceChange,u=c&&!c.truncated?[...c.added,...c.removed].map(y=>path.resolve(t.workspaceRoot,y)):[],i=types_1.LENS_WATCHER_PROBE_ENABLED&&t.port!==void 0?(0,lifecycle_1.lensWatcherVerdict)(await L(t.port),a,c?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,u):"unknown";if(i==="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(i==="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(o.exitCode!==null||o.signalCode!==null)return;I.set(t.key,Date.now());const S=C.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 ${i==="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:i,added:c?.added,removed:c?.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 ${i==="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:i},void 0,t.bus);const N=(0,hmr_reload_1.broadcastFullReload)(s,t.key);N>0&&console.log(`[gateway] \u2192 told ${N} open tab(s) to reload (stale optimize-dep generation)`),signalChild(o,"SIGTERM"),setTimeout(()=>{o.exitCode===null&&o.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.`),signalChild(o,"SIGKILL"))},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"),we=d(async()=>{const e=[...new Map(s.routes.filter(t=>t.lens).map(t=>[t.project,t.lens])).values()],r=f.dashboard!==!1,o=f.mcp!==!1&&e.length>0;if(r){const t=(0,lens_frontend_1.findDashboardBundle)(s.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 n=(0,scope_1.readLensScope)(s.root),a=await x(f.dashboardPort??n.dashboardPort,V),l=f.lensHost??"lensmcp.local",c=n.basePath;s.registry.appendRoutes(s.wsKey,[{host:l,prefix:c,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),s.rebuildRoutes(),(0,workspace_registry_1.registerWorkspace)({key:n.key,root:s.root,base:c,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://${l}${c}/)`),p("info",`lens dashboard up: ${l}${c} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:l,port:a,base:c}),k("lens-dashboard",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",n.key,"dashboard")),[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:c,LENSMCP_GATEWAY_PORTS:M},!1,void 0,void 0,a)}}if(o){const t=(0,lens_frontend_1.findMcpBundle)(s.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 n=(0,scope_1.readLensScope)(s.root),a=Number(process.env.LENSMCP_PORT??n.mcpHttpPort),l=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",n.key,"mcp")),[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"mcp",LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:String(a),LENSMCP_WORKSPACE_KEY:n.key,LENSMCP_WORKSPACE_ROOT:s.root},!1,void 0,void 0,a)},"spawnMcp");await g(a)?l():(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}),Q("lens-mcp",a,l))}}for(const t of e){if(t.started)continue;t.started=!0;const n=t.port,a=(s.registry.get(s.wsKey)?.routes??s.routes).filter(u=>u.lens?.project===t.project),l=await x(t.port,T);for(const u of a)u.lens&&(u.lens.port=l),u.target=`http://localhost:${l}`;t.port=l;const c=ee({wsKey:s.wsKey,project:t.project,workspaceRoot:s.root,projectRoot:t.projectRoot,eventFile:s.eventFile,routes:a,frontend:t,desiredPort:n});try{ne(c,l),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(u){T.delete(l),c.state="failed",console.error(`[gateway] lens app ${t.project}: ${u.message}`)}}he()},"bootSingletonsAndApps"),_e=d(async e=>{if(f.dashboard===!1)return;const r=(0,lens_frontend_1.findDashboardBundle)(s.root);if(!r)return;const o=(0,scope_1.readLensScope)(e.root),t=f.lensHost??"lensmcp.local",n=o.basePath,a=await x(o.dashboardPort,V),l=`lens-dashboard:${e.wsKey}`,c=path.join(e.root,".lensmcp","events.jsonl");return $.delete(l),s.registry.appendRoutes(e.wsKey,[{host:t,prefix:n,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),(0,workspace_registry_1.registerWorkspace)({key:e.wsKey,root:e.root,base:n,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString(),...e.instance?{instance:{name:e.instance.name,baseKey:e.instance.baseKey,apex:e.instance.apex}}:{}}),console.log(`[gateway] hosting dashboard for workspace '${e.wsKey}' \u2192 http://localhost:${a} (routed at https://${t}${n}/)`),p("info",`lens dashboard up: ${t}${n} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:t,port:a,base:n}),k(l,(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",e.wsKey,"dashboard")),[r],{LENSMCP_EVENT_FILE:c,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:n,LENSMCP_WS_KEY:e.wsKey,...e.sockNs?{LENSMCP_SOCK_NS:e.sockNs}:{},LENSMCP_GATEWAY_PORTS:M},!1,void 0,e.root,a),()=>{$.add(l),V.delete(a),(0,workspace_registry_1.unregisterWorkspace)(e.wsKey);const u=m.get(l);u&&H(u),m.delete(l)}},"hostWorkspaceDashboard"),Se=d(async e=>{const r=new Map;for(const n of e.routes){if(!n.lens)continue;const a=r.get(n.lens.project)??[];a.push(n),r.set(n.lens.project,a)}if(r.size===0)return()=>{};const o=path.join(e.root,".lensmcp","events.jsonl"),t=[];for(const[n,a]of r){const l=a[0].lens;if(l.started)continue;const c=await x(l.port,T),u=l.port;for(const S of a)S.lens.started=!0,S.lens.port=c,S.target=`http://localhost:${c}`;const i=ee({wsKey:e.wsKey,project:n,workspaceRoot:e.root,projectRoot:l.projectRoot,eventFile:o,routes:a,frontend:l,desiredPort:u});t.push(i),console.log(`[gateway] hosting lens app '${n}' of '${e.wsKey}' \u2192 vite :${c}`);try{ne(i,c),p("info",`lens app started: ${e.wsKey}/${n} (vite :${c})`,`cluster-lens-app:${e.wsKey}:${n}`,{kind:"lens-app-up",project:n,port:c},void 0,o)}catch(S){T.delete(c),i.state="failed",console.error(`[gateway] lens app ${e.wsKey}/${n}: ${S.message}`)}}return()=>{for(const n of t){n.disposed=!0;for(const a of[...n.generations])K(a,!0);for(const a of n.routes)a.lens&&F.delete(a.lens);F.delete(n.frontend),I.delete(n.key),Y.delete(n.key),W.delete(n.key),C.delete(n.key)}}},"hostWorkspaceApps"),ye=d(async(e=2500)=>{j&&(clearInterval(j),j=void 0);const r=[...b];for(const n of r)signalChild(n,"SIGTERM");const o=d(n=>n.exitCode===null&&n.signalCode===null,"alive"),t=Date.now()+e;for(;Date.now()<t&&r.some(o);)await new Promise(n=>setTimeout(n,100));for(const n of r)o(n)&&signalChild(n,"SIGKILL")},"reapAll"),re=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:k,bootSingletonsAndApps:we,hostWorkspaceDashboard:_e,hostWorkspaceApps:Se,probeLensFrontends:re,reapAll:ye}}v(createLensChildren,"createLensChildren"),d(createLensChildren,"createLensChildren");
1
+ "use strict";var $e=Object.defineProperty;var P=(s,E)=>$e(s,"name",{value:E,configurable:!0});var Ce=Object.defineProperty,v=P((s,E)=>Ce(s,"name",{value:E,configurable:!0}),"v"),Pe=Object.defineProperty,d=v((s,E)=>Pe(s,"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.signalChild=signalChild,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(s,E){return new Promise(g=>{const _=net.createServer();_.unref(),_.once("error",p=>{const h=p.code??"";g(h==="EADDRINUSE"||h==="EACCES"?"in-use":"unavailable")}),_.listen(E===void 0?{port:s}:{port:s,host:E},()=>_.close(()=>g("free")))})}P(tryBind,"tryBind"),v(tryBind,"tryBind"),d(tryBind,"tryBind");async function probePortFree(s){for(const E of[void 0,"0.0.0.0","127.0.0.1","::1"])if(await tryBind(s,E)==="in-use")return!1;return!0}P(probePortFree,"probePortFree"),v(probePortFree,"probePortFree"),d(probePortFree,"probePortFree");function probeConnect(s,E,g){return new Promise(_=>{let p=!1;const h=net.createConnection({host:s,port:E});h.unref();const b=setTimeout(()=>y(!1),g);b.unref?.();function y(A){p||(p=!0,clearTimeout(b),h.destroy(),_(A))}P(y,"L"),v(y,"R"),d(y,"finish"),h.once("connect",()=>y(!0)),h.once("error",()=>y(!1))})}P(probeConnect,"probeConnect"),v(probeConnect,"probeConnect"),d(probeConnect,"probeConnect");async function probePortListening(s,E=1e3){return await probeConnect("127.0.0.1",s,E)?!0:probeConnect("::1",s,E)}P(probePortListening,"probePortListening"),v(probePortListening,"probePortListening"),d(probePortListening,"probePortListening");async function probeWatcherHealth(s,E=1500){try{const g=new AbortController,_=setTimeout(()=>g.abort(),E);_.unref?.();try{const p=await fetch(`http://127.0.0.1:${s}/__lensmcp/watcher-health`,{signal:g.signal});if(!p.ok)return null;const h=await p.json();if(typeof h?.lastFsSetEventAt!="number")return null;const b=Array.isArray(h.recentEvents)?h.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:h.schemaVersion===2?2:1,ready:h.ready!==!1,sequence:typeof h.sequence=="number"?h.sequence:0,lastFsSetEventAt:h.lastFsSetEventAt,fsSetEvents:typeof h.fsSetEvents=="number"?h.fsSetEvents:0,recentEvents:b}}finally{clearTimeout(_)}}catch{return null}}P(probeWatcherHealth,"probeWatcherHealth"),v(probeWatcherHealth,"probeWatcherHealth"),d(probeWatcherHealth,"probeWatcherHealth");const sleepUnref=d(s=>new Promise(E=>{setTimeout(E,s).unref?.()}),"sleepUnref");async function waitForPortFree(s,E,g={}){const _=g.isPortFree??probePortFree,p=Math.max(1,g.intervalMs??types_1.PORT_FREE_POLL_MS),h=Date.now()+Math.max(0,E);for(;;){if(await _(s))return!0;const b=h-Date.now();if(b<=0)return!1;await sleepUnref(Math.min(p,b))}}P(waitForPortFree,"waitForPortFree"),v(waitForPortFree,"waitForPortFree"),d(waitForPortFree,"waitForPortFree");function viteArgPort(s){const E=d(g=>Number.isInteger(g)&&g>0&&g<65536?g:void 0,"valid");for(let g=0;g<s.length;g+=1){const _=s[g];if(_==="--port")return E(Number(s[g+1]));if(_.startsWith("--port="))return E(Number(_.slice(7)))}}P(viteArgPort,"viteArgPort"),v(viteArgPort,"viteArgPort"),d(viteArgPort,"viteArgPort");function describeChildExit(s){return s.signalCode?`killed by ${s.signalCode}`:s.exitCode===null?"exit status unknown":`exit code ${s.exitCode}`}P(describeChildExit,"describeChildExit"),v(describeChildExit,"describeChildExit"),d(describeChildExit,"describeChildExit");function signalChild(s,E){if(s.pid===void 0)return!1;try{return s.kill(E)}catch{return!1}}P(signalChild,"signalChild"),v(signalChild,"signalChild"),d(signalChild,"signalChild");async function claimPort(s,E,g,_){let p=s;for(;E.has(p)||_?.has(p)||!await g(p);)p+=1;return E.add(p),p}P(claimPort,"claimPort"),v(claimPort,"claimPort"),d(claimPort,"claimPort");function createLensChildren(s,E,g,_){const{emit:p}=E,h=_?.isPortFree??probePortFree,b=(g.ports?.length?g.ports:[443]).join(","),y=_?.probeWatcherHealth??probeWatcherHealth,A=[],W=new Map,T=new Map,x=new Map,q=new Map,G=new Set;let F;const m=new Map,M=new Set,V=new Set,U=new Set,O=new Set,L=new Map,I=new WeakMap,H=new Set,ee=d((e,r,n)=>{if(H.has(e))return;H.add(e);const t=setInterval(()=>{(async()=>{if(s.stopped()||M.has(e)){clearInterval(t),H.delete(e);return}await h(r)&&(clearInterval(t),H.delete(e),console.log(`[gateway] lens child ${e}: :${r} freed \u2014 respawning.`),n())})().catch(()=>{})},types_1.LENS_PARKED_PORT_REPROBE_MS);t.unref?.()},"parkUntilPortFree"),K=d(async(e,r,n)=>{const t=await claimPort(e,r,h,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,r,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(l=>l.generation===o);a&&(e.endsWith(":vite")?a.vite=r:e.endsWith(":browser-capture")&&(a.capture=r))},"attachRespawnedGenerationChild"),Y=d(e=>{e.exitCode!==null||e.signalCode!==null||e.pid===void 0||(V.add(e),signalChild(e,"SIGTERM"),setTimeout(()=>{e.exitCode===null&&e.signalCode===null&&signalChild(e,"SIGKILL")},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.())},"retireChild"),pe=d((e,r)=>{const n=m.get(e);!n||n===r||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??"?"}).`),Y(n))},"retireLabelHolder"),D=d((e,r,n,t,o=!1,a,l,c)=>{const u=Date.now(),i=(0,node_child_process_1.spawn)(r,n,{cwd:l??s.root,env:{...(0,pod_env_1.podBaseEnv)(process.env,s.root,l??s.root),...t??{},LENSMCP_PARENT_PID:String(process.pid)},stdio:"inherit"});A.push(i),pe(e,i),m.set(e,i),de(e,i,t);const S=e==="vite"||e.endsWith(":vite"),N=typeof t?.LENSMCP_EVENT_FILE=="string"?t.LENSMCP_EVENT_FILE:void 0,C=N&&N!==s.eventFile?N:void 0,w=S?viteArgPort(n):c;S&&T.set(i,{key:t?.LENSMCP_FRONTEND_KEY??`${l??s.root}:${t?.LENSMCP_PROJECT??"app"}`,project:t?.LENSMCP_PROJECT??"app",workspaceRoot:l??s.root,spawnedAt:u,port:w,probeFails:0,listening:!1,generation:Number(t?.LENSMCP_FRONTEND_GENERATION??0),role:t?.LENSMCP_FRONTEND_ROLE==="replacement"?"replacement":"active",...C?{bus:C}:{}});const f=e==="lens-mcp"?"lens-mcp":e==="lens-dashboard"||e.startsWith("lens-dashboard:")?"lens-dashboard":void 0;return f&&w!==void 0&&(p("info",`lens child starting: ${f} (:${w})`,`cluster-lens-child:${f}`,{kind:"lens-child-starting",project:f,label:e,pid:i.pid,port:w},void 0,C),(async()=>{const R=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<R;){if(i.exitCode!==null||i.signalCode!==null||M.has(e))return;if(await probePortListening(w,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){p("info",`lens child up: ${f} (:${w})`,`cluster-lens-child:${f}`,{kind:"lens-child-up",project:f,label:e,pid:i.pid,port:w},void 0,C);return}await sleepUnref(150)}})().catch(()=>{})),i.on("error",R=>{if(i.pid!==void 0){console.warn(`[gateway] lens child ${e}: ${R.message}`);return}const j=A.indexOf(i);j>=0&&A.splice(j,1),m.get(e)===i&&m.delete(e),T.delete(i),V.delete(i),console.error(`[gateway] lens child ${e} failed to spawn (${R.message}) \u2014 not started, not retried.`)}),i.on("exit",(R,j)=>{const ae=A.indexOf(i);ae>=0&&A.splice(ae,1),m.get(e)===i&&m.delete(e);const k=T.get(i);if(T.delete(i),V.delete(i))return;const Le=M.delete(e);if(s.stopped()||Le||(f?p("warning",`lens child exited: ${f}`,`cluster-lens-child:${f}`,{kind:"lens-child-exit",project:f,label:e,pid:i.pid,code:R,signal:j},void 0,C):k&&p("warning",`lens frontend exited: ${k.project}`,`cluster-lens-child:${k.project}`,{kind:"lens-child-exit",project:k.project,label:e,pid:i.pid,code:R,signal:j,generation:k.generation,port:k.port,ranMs:Date.now()-u},void 0,C),k&&ge(i,k)))return;const ie=Date.now()-u,$=W.get(e)??{attempts:0,portConflicts:0};(async()=>{const Re=w!==void 0&&!await h(w),le=(0,lifecycle_1.isPortConflictExit)({code:R,signal:j,ranMs:ie,portHeld:Re},{fastFailMs:types_1.CHILD_START_FAIL_MS});if(le&&$.portConflicts<types_1.MAX_PORT_CONFLICT_RETRIES)$.portConflicts+=1,W.set(e,$),console.warn(`[gateway] lens child ${e} lost the :${w} bind race (EADDRINUSE, code=${R}); waiting for the port, then retrying (port-retry ${$.portConflicts}/${types_1.MAX_PORT_CONFLICT_RETRIES}; crash budget untouched).`);else if(le){$.portConflicts=0,W.set(e,$),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,()=>D(e,r,n,t,o,a,l,c));return}else{$.portConflicts=0,ie>=HEAL_HEALTHY_MS&&($.attempts=0);const ce=Math.min(HEAL_MAX_MS,HEAL_BASE_MS*2**$.attempts);$.attempts+=1,W.set(e,$),console.warn(`[gateway] lens child ${e} exited (code=${R} sig=${j}); auto-healing in ${Math.round(ce/1e3)}s (attempt ${$.attempts}).`),await sleepUnref(ce)}s.stopped()||M.has(e)||(w!==void 0&&!await waitForPortFree(w,types_1.PORT_FREE_WAIT_MS,{isPortFree:h,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.`),!(s.stopped()||M.has(e))&&D(e,r,n,t,o,a,l,c))})().catch(()=>{})}),i},"spawnManagedChild"),te=d(e=>{const r=`${e.wsKey}:${e.project}`,n=L.get(r);if(n)return n;const t={key:r,...e,sourceDirs:e.frontend.sourceRoots?.length?e.frontend.sourceRoots:[e.projectRoot],generation:0,state:"starting",generations:new Set,disposed:!1};L.set(r,t);for(const o of e.routes)o.lens&&(o.lens.workspaceKey??=e.wsKey,I.set(o.lens,t));return e.frontend.workspaceKey??=e.wsKey,I.set(e.frontend,t),t},"registerFrontend"),ue=d(e=>{if(!types_1.LENS_WATCH_SCOPE_ENABLED)return{};const r=path.resolve(e.projectRoot),n=e.sourceDirs.map(t=>path.resolve(t)).filter(t=>t!==r);return n.length>0?{LENSMCP_WATCH_DIRS:n.join(path.delimiter)}:{}},"lensWatchScopeEnv"),oe=d((e,r,n)=>{const t=++e.generation,o=`${e.key}:g${t}:`,a=`${o}vite`,l=`${o}browser-capture`;M.delete(a),M.delete(l);const c=d((S,N,C,w,f,R)=>D(S,N,C,w,f,R,e.workspaceRoot),"spawnInRoot"),u=(0,lens_frontend_1.spawnLensFrontend)({projectRoot:e.projectRoot,workspaceRoot:e.workspaceRoot,project:e.project,eventFile:e.eventFile,port:r,chrome:!0,headless:!0,viteEnv:{...e.frontend.env??{},...e.frontend.frozen?{LENSMCP_FREEZE:"1"}:{},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")},c),i={ownerKey:e.key,generation:t,port:r,labelPrefix:o,vite:u?.vite??m.get(a),capture:m.get(l)};return e.generations.add(i),i},"spawnFrontendGeneration"),B=d((e,r)=>{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)M.add(t),o&&Y(o);r&&O.delete(e.port)},"terminateGeneration"),Ee=d(async e=>{const r=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<r;){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"),z=d(async e=>{const r=e?.vite;return!!(e&&r&&r.exitCode===null&&r.signalCode===null&&await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)))},"generationIsServing"),X=d(e=>!e.disposed&&!s.stopped()&&L.get(e.key)===e,"frontendIsCurrent"),J=d((e,r)=>{if(!X(e))return Promise.resolve(!1);if(e.replacement)return e.replacement;const n=e.active;e.state=n?"replacing":"starting",e.reason=r,e.startedAt=Date.now();const t=(async()=>{let o,a;const l=Date.now();try{const c=new Set;for(const f of L.values())f!==e&&c.add(f.desiredPort);const u=n&&n.port===e.desiredPort?`g${n.generation}`:void 0,i=await K(e.desiredPort,O,{reserved:c,heldBy:u});if(a=i,!X(e))return O.delete(i),!1;o=oe(e,i,"replacement"),e.candidate=o;const S=await z(n);console.log(`[gateway] lens handoff start: ${e.key} g${n?.generation??0}\u2192g${o.generation} :${n?.port??"down"}\u2192:${i} reason=${r}`),p("info",`lens handoff starting: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-start",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,oldPort:n?.port,newPort:i,oldServing:S},void 0,e.eventFile===s.eventFile?void 0:e.eventFile);const N=await Ee(o);if(!X(e))return B(o,!0),e.candidate=void 0,!1;if(!N){B(o,!0),e.candidate=void 0;const f=await z(n);return e.state=f?"ready":"failed",f&&(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:r,generation:o.generation,port:i,durationMs:Date.now()-l,oldKept:f},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}for(const f of e.routes)f.target=`http://localhost:${o.port}`,f.lens&&(f.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 C=o.vite?T.get(o.vite):void 0;C&&(C.role="active",C.listening=!0);const w=(0,hmr_reload_1.broadcastFullReload)(s,e.key);if(console.log(`[gateway] lens handoff ready: ${e.key} g${o.generation} :${o.port} in ${Date.now()-l}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:r,generation:o.generation,oldPort:n?.port,newPort:o.port,durationMs:Date.now()-l,reloadedTabs:w},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),n){const f=`${n.labelPrefix}browser-capture`;M.add(f),n.capture&&Y(n.capture),setTimeout(()=>B(n,!0),types_1.LENS_REPLACEMENT_DRAIN_MS).unref?.()}return!0}catch(c){B(o,!0),!o&&a!==void 0&&O.delete(a),e.candidate=void 0;const u=await z(n);e.state=u?"ready":"failed",u&&(e.reason=void 0,e.startedAt=void 0);const i=c.message;return console.error(`[gateway] lens handoff failed: ${e.key}: ${i}`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:r,generation:o?.generation??e.generation,port:o?.port??a,durationMs:Date.now()-l,oldKept:u,error:i},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}finally{e.replacement=void 0}})();return e.replacement=t,t},"rollFrontend"),ne=d((e,r)=>{e.active=oe(e,r,"active"),e.state="starting",e.startedAt=Date.now()},"spawnInitialFrontend"),ge=d((e,r)=>{const n=L.get(r.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${r.generation} :${r.port} (${describeChildExit(e)}); starting an alternate-port replacement.`),J(n,"child-exit")),!0)},"handleManagedViteExit");s.lensSupervisor=types_1.LENS_RESTART_MODE==="rolling"?{status(e){const r=I.get(e);return r?{state:r.state,generation:r.candidate?.generation??r.active?.generation??r.generation,reason:r.reason,startedAt:r.startedAt}:void 0},recover(e,r){const n=I.get(e);return n?J(n,r):Promise.resolve(!1)}}:void 0;let Z=!1,re=0;const he=d(()=>{Z||Date.now()-re<types_1.POD_STALE_SCAN_MS||(Z=!0,re=Date.now(),(async()=>{const e=new Map;for(const r of[...L.values()]){if(s.stopped())return;let n=e.get(r.workspaceRoot);if(!n){const i=(0,scope_1.readSourceSetOptions)(r.workspaceRoot);n={pass:(0,lifecycle_1.sourceScanPass)(r.workspaceRoot,i.exclude,{ignoreTests:i.ignoreTests}),startedAt:Date.now()},e.set(r.workspaceRoot,n)}const t=n.startedAt,o=await n.pass.snapshot(r.sourceDirs);if(L.get(r.key)!==r)continue;const a=r.sourceSnapshot,l=r.sourceScanStartedAt;if(r.sourceSnapshot=o,r.sourceScanStartedAt=t,!a)continue;const c=Date.now(),u=(0,lifecycle_1.diffSourceSets)(a,o,c,(0,lifecycle_1.sourceChangeWindowMs)(c,l,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS));u&&(r.sourceChange=u,p("info",`source file set changed for ${r.key}`,`cluster-lens-app:${r.project}`,{kind:"source-set-changed",scoped:!0,wsKey:r.wsKey,project:r.project,added:u.added,removed:u.removed,truncated:u.truncated},void 0,r.eventFile===s.eventFile?void 0:r.eventFile))}})().catch(()=>{}).finally(()=>{Z=!1}))},"scanFrontendSourceSets");let Q=!1;const fe=d(async(e,r)=>{if(!Q){Q=!0;try{for(const[n,t]of[...T]){if(s.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 c=L.get(t.key);c?.active?.vite===n&&(c.state="ready",c.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(!r)continue;t.probeFails+=1;const a=(0,lifecycle_1.lensChildWedged)({spawnedAt:t.spawnedAt,probeFails:t.probeFails,hasListened:t.listening},x.get(t.key)??0,Date.now(),e);if(!a)continue;const l=t.listening?"its listener VANISHED (was up, now refusing)":`it NEVER bound within the ${Math.round(o/1e3)}s boot allowance`;x.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 ${l} \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),signalChild(n,"SIGKILL")}}finally{Q=!1}}},"probeLensChildren"),we=d(()=>{if(F||!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};F=setInterval(()=>{if(s.stopped()||T.size===0||(se(),!types_1.POD_RECYCLE_ENABLED))return;he();const r=Date.now();for(const[n,t]of T){const o=L.get(t.key);if(o?.frontend.frozen)continue;const a=o?.sourceChange?.changedAt??0,l=x.get(t.key)??0;(0,lifecycle_1.lensFrontendStale)(t.spawnedAt,l,a,r,e)&&((q.get(t.key)??0)>=a||G.has(t.key)||(G.add(t.key),(async()=>{try{const c=o?.sourceChange,u=c&&!c.truncated?[...c.added,...c.removed].map(C=>path.resolve(t.workspaceRoot,C)):[],i=types_1.LENS_WATCHER_PROBE_ENABLED&&t.port!==void 0?(0,lifecycle_1.lensWatcherVerdict)(await y(t.port),a,c?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,u):"unknown";if(i==="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(i==="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;x.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 ${i==="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:i,added:c?.added,removed:c?.removed},void 0,t.bus),await J(S,"stale-source-set");return}t.listening=!1,console.log(`[gateway] zombie recycle: lens app ${t.project} (stale-source-set) \u2014 watcher ${i==="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:i},void 0,t.bus);const N=(0,hmr_reload_1.broadcastFullReload)(s,t.key);N>0&&console.log(`[gateway] \u2192 told ${N} open tab(s) to reload (stale optimize-dep generation)`),signalChild(n,"SIGTERM"),setTimeout(()=>{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.`),signalChild(n,"SIGKILL"))},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}finally{G.delete(t.key)}})()))}},Math.min(types_1.POD_STALE_SCAN_MS,15e3)),F.unref?.()},"startLensSweeper"),_e=d(async()=>{const e=[...new Map(s.routes.filter(t=>t.lens).map(t=>[t.project,t.lens])).values()],r=g.dashboard!==!1,n=g.mcp!==!1&&e.length>0;if(r){const t=(0,lens_frontend_1.findDashboardBundle)(s.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)(s.root),a=await K(g.dashboardPort??o.dashboardPort,U),l=g.lensHost??"lensmcp.local",c=o.basePath;s.registry.appendRoutes(s.wsKey,[{host:l,prefix:c,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),s.rebuildRoutes(),(0,workspace_registry_1.registerWorkspace)({key:o.key,root:s.root,base:c,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://${l}${c}/)`),p("info",`lens dashboard up: ${l}${c} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:l,port:a,base:c}),D("lens-dashboard",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"dashboard")),[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:c,LENSMCP_GATEWAY_PORTS:b},!1,void 0,void 0,a)}}if(n){const t=(0,lens_frontend_1.findMcpBundle)(s.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)(s.root),a=Number(process.env.LENSMCP_PORT??o.mcpHttpPort),l=d(()=>{console.log(`[gateway] starting lens MCP server on 127.0.0.1:${a} (${t})`),D("lens-mcp",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"mcp")),[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"mcp",LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:String(a),LENSMCP_WORKSPACE_KEY:o.key,LENSMCP_WORKSPACE_ROOT:s.root},!1,void 0,void 0,a)},"spawnMcp");await h(a)?l():(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,l))}}for(const t of e){if(t.started)continue;t.started=!0;const o=t.port,a=(s.registry.get(s.wsKey)?.routes??s.routes).filter(u=>u.lens?.project===t.project),l=await K(t.port,O);for(const u of a)u.lens&&(u.lens.port=l),u.target=`http://localhost:${l}`;t.port=l;const c=te({wsKey:s.wsKey,project:t.project,workspaceRoot:s.root,projectRoot:t.projectRoot,eventFile:s.eventFile,routes:a,frontend:t,desiredPort:o});try{ne(c,l),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(u){O.delete(l),c.state="failed",console.error(`[gateway] lens app ${t.project}: ${u.message}`)}}we()},"bootSingletonsAndApps"),Se=d(async e=>{if(g.dashboard===!1)return;const r=(0,lens_frontend_1.findDashboardBundle)(s.root);if(!r)return;const n=(0,scope_1.readLensScope)(e.root),t=g.lensHost??"lensmcp.local",o=n.basePath,a=await K(n.dashboardPort,U),l=`lens-dashboard:${e.wsKey}`,c=path.join(e.root,".lensmcp","events.jsonl");return M.delete(l),s.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(),...e.instance?{instance:{name:e.instance.name,baseKey:e.instance.baseKey,apex:e.instance.apex}}:{}}),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}),D(l,(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",e.wsKey,"dashboard")),[r],{LENSMCP_EVENT_FILE:c,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:o,LENSMCP_WS_KEY:e.wsKey,...e.sockNs?{LENSMCP_SOCK_NS:e.sockNs}:{},LENSMCP_GATEWAY_PORTS:b},!1,void 0,e.root,a),()=>{M.add(l),U.delete(a),(0,workspace_registry_1.unregisterWorkspace)(e.wsKey);const u=m.get(l);u&&Y(u),m.delete(l)}},"hostWorkspaceDashboard"),ye=d(async e=>{const r=new Map;for(const o of e.routes){if(!o.lens)continue;const a=r.get(o.lens.project)??[];a.push(o),r.set(o.lens.project,a)}if(r.size===0)return()=>{};const n=path.join(e.root,".lensmcp","events.jsonl"),t=[];for(const[o,a]of r){const l=a[0].lens;if(l.started)continue;const c=await K(l.port,O),u=l.port;for(const S of a)S.lens.started=!0,S.lens.port=c,S.target=`http://localhost:${c}`;const i=te({wsKey:e.wsKey,project:o,workspaceRoot:e.root,projectRoot:l.projectRoot,eventFile:n,routes:a,frontend:l,desiredPort:u});t.push(i),console.log(`[gateway] hosting lens app '${o}' of '${e.wsKey}' \u2192 vite :${c}`);try{ne(i,c),p("info",`lens app started: ${e.wsKey}/${o} (vite :${c})`,`cluster-lens-app:${e.wsKey}:${o}`,{kind:"lens-app-up",project:o,port:c},void 0,n)}catch(S){O.delete(c),i.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])B(a,!0);for(const a of o.routes)a.lens&&I.delete(a.lens);I.delete(o.frontend),x.delete(o.key),q.delete(o.key),G.delete(o.key),L.delete(o.key)}}},"hostWorkspaceApps"),ve=d(async(e=2500)=>{F&&(clearInterval(F),F=void 0);const r=[...A];for(const o of r)signalChild(o,"SIGTERM");const n=d(o=>o.exitCode===null&&o.signalCode===null,"alive"),t=Date.now()+e;for(;Date.now()<t&&r.some(n);)await new Promise(o=>setTimeout(o,100));for(const o of r)n(o)&&signalChild(o,"SIGKILL")},"reapAll"),se=d(()=>fe({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:D,bootSingletonsAndApps:_e,hostWorkspaceDashboard:Se,hostWorkspaceApps:ye,probeLensFrontends:se,reapAll:ve}}P(createLensChildren,"createLensChildren"),v(createLensChildren,"createLensChildren"),d(createLensChildren,"createLensChildren");