@lensmcp/cluster 1.25.25 → 1.25.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,3 @@
1
- "use strict";var A=Object.defineProperty;var w=(s,c)=>A(s,"name",{value:c,configurable:!0});var _=Object.defineProperty,d=w((s,c)=>_(s,"name",{value:c,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.EDGE_DURATION_SAMPLES=exports.LENS_DASHBOARD_PROJECT=void 0,exports.createObservability=createObservability;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),headless_flow_1=require("@lensmcp/core/headless-flow"),redact_1=require("@lensmcp/core/redact"),busHygiene=(()=>{try{return require("@lensmcp/node-instrumentation")}catch{return}})();exports.LENS_DASHBOARD_PROJECT="(lens-dashboard)",exports.EDGE_DURATION_SAMPLES=64;function ownerOf(s){return s?.svc?{root:s.svc.root,wsKey:s.svc.wsKey}:s?.lens?{...s.lens.workspaceRoot?{root:s.lens.workspaceRoot}:{},...s.lens.workspaceKey?{wsKey:s.lens.workspaceKey}:{}}:{}}w(ownerOf,"ownerOf"),d(ownerOf,"ownerOf");function busFileFor(s,c){const{root:l}=ownerOf(s);if(!l)return;const f=path.join(l,".lensmcp","events.jsonl");return f===c?void 0:f}w(busFileFor,"busFileFor"),d(busFileFor,"busFileFor");const hdr=d(s=>typeof s=="string"&&s!==""?s:Array.isArray(s)?s[0]:void 0,"hdr");function createObservability(s,c){const l=d(()=>Date.now().toString(36)+Math.random().toString(36).slice(2,12),"eid"),f=busHygiene?.createEventFloodGuard({burst:30,perSec:5}),y=d((e,t,r,u,n,a)=>{const o=a??s;try{const i=f?f.admit(r):{ok:!0,suppressed:0};if(!i.ok)return;fs.mkdirSync(path.dirname(o),{recursive:!0});const p=u&&(0,redact_1.redactDeep)(u),h=JSON.stringify({id:l(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:e,context:(0,redact_1.redactDeep)({sessionId:"pending",...n}),fingerprint:r,title:(0,redact_1.safeTitle)(t),raw:i.suppressed>0?{...p,floodSuppressed:i.suppressed}:p})+`
2
- `;busHygiene?.maybeRotateEventFile(o,h.length),fs.appendFileSync(o,h)}catch{}},"emit"),I=d(e=>{const t=hdr(e.headers["x-lensmcp-flow-id"]);let r=hdr(e.headers["x-request-id"]);if(!(!t&&!r&&!hdr(e.headers.traceparent)))return r||(r=l(),e.headers["x-request-id"]=r),{startedAt:Date.now(),method:(e.method??"GET").toUpperCase(),host:(e.headers.host||"").split(":")[0],url:e.url??"/",steps:[],...t?{flowId:t}:{},...r?{requestId:r}:{},...hdr(e.headers["x-lensmcp-parent-request-id"])?{parentRequestId:hdr(e.headers["x-lensmcp-parent-request-id"])}:{},...hdr(e.headers["x-lensmcp-origin-node-id"])?{originNodeId:hdr(e.headers["x-lensmcp-origin-node-id"])}:{}}},"beginTrace"),E=d((e,t,r,u)=>{if(r?.flowId||!t.pool||t.internal||t.project===exports.LENS_DASHBOARD_PROJECT||!(0,headless_flow_1.headlessFlowsEnabled)())return r;const n=e.url??"/";if((0,headless_flow_1.isProbePath)(n))return r;const a=hdr(e.headers["x-request-id"]);if(!a)return r;const o=(0,headless_flow_1.headlessFlowId)(a);e.headers["x-lensmcp-flow-id"]=o;const i=(e.method??"GET").toUpperCase(),p=(e.headers.host||"").split(":")[0],h=`request:${i} ${n.split("?")[0]}`,m=r??{startedAt:u,method:i,host:p,url:n,steps:[{step:"received",atMs:0,host:p,method:i,url:n}],requestId:a};return m.flowId=o,m.originNodeId=h,y("info",`${i} ${n.split("?")[0]}`,`gateway-origin:${t.project}`,{kind:"flow-origin",originNodeId:h,project:t.project,host:p,method:i,url:n,...ownerOf(t).wsKey?{wsKey:ownerOf(t).wsKey}:{}},{flowId:o,requestId:a,originType:"request",originNodeId:h},busFileFor(t,s)),m},"startHeadlessFlow"),S=d((e,t,r)=>{e&&e.steps.push({step:t,atMs:Date.now()-e.startedAt,...r})},"traceStep"),q=d((e,t,r,u,n)=>{if(!e||e.done||(e.done=!0,t===exports.LENS_DASHBOARD_PROJECT&&r<500))return;const a=Date.now()-e.startedAt;y(r>=500?"error":"info",`gateway ${e.method} ${e.host}${e.url} \u2192 ${r} (${a}ms)`,`gateway-request:${t}`,{kind:"gateway-request",project:t,host:e.host,method:e.method,url:e.url,status:r,durationMs:a,startedAt:e.startedAt,steps:e.steps,...ownerOf(n).wsKey?{wsKey:ownerOf(n).wsKey}:{},...u},{...e.flowId?{flowId:e.flowId}:{},...e.requestId?{requestId:e.requestId}:{},...e.parentRequestId?{parentRequestId:e.parentRequestId}:{},...e.originNodeId?{originNodeId:e.originNodeId}:{}},busFileFor(n,s))},"finishTrace"),g=new Map;return{emit:y,eid:l,beginTrace:I,startHeadlessFlow:E,traceStep:S,finishTrace:q,recordEdge:d((e,t,r,u)=>{if(e.project===exports.LENS_DASHBOARD_PROJECT&&r<500&&r!==0)return;const n=e.host??"(default)",a=(u?u+"\u21D2":"")+n+"\u2192"+e.project,o=g.get(a)??{host:n,project:e.project,caller:u,count:0,totalMs:0,errors:0,durations:[],...busFileFor(e,s)?{busFile:busFileFor(e,s)}:{},...ownerOf(e).wsKey?{wsKey:ownerOf(e).wsKey}:{}};if(o.count+=1,o.totalMs+=t,o.durations.length<exports.EDGE_DURATION_SAMPLES)o.durations.push(Math.round(t));else{const i=Math.floor(Math.random()*o.count);i<exports.EDGE_DURATION_SAMPLES&&(o.durations[i]=Math.round(t))}(r>=500||r===0)&&(o.errors+=1),g.set(a,o)},"recordEdge"),startEdgeFlusher:d(()=>{const e=setInterval(()=>{for(const t of g.values()){const r=Math.round(t.totalMs/t.count);y(t.errors?"warning":"info",`traffic ${t.host} \u2192 ${t.project}: ${t.count} req, ~${r}ms${t.errors?`, ${t.errors} errors`:""}`,`gateway-traffic:${t.host}->${t.project}`,{kind:"gateway-traffic",host:t.host,project:t.project,caller:t.caller,count:t.count,avgMs:r,errors:t.errors,durationsMs:t.durations,...t.wsKey?{wsKey:t.wsKey}:{}},void 0,t.busFile)}g.clear()},c.trafficFlushMs);return e.unref(),e},"startEdgeFlusher")}}w(createObservability,"createObservability"),d(createObservability,"createObservability");
1
+ "use strict";var v=Object.defineProperty;var f=(s,u)=>v(s,"name",{value:u,configurable:!0});var $=Object.defineProperty,i=f((s,u)=>$(s,"name",{value:u,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.EDGE_DURATION_SAMPLES=exports.LENS_DASHBOARD_PROJECT=void 0,exports.createObservability=createObservability;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),headless_flow_1=require("@lensmcp/core/headless-flow"),redact_1=require("@lensmcp/core/redact"),busHygiene=(()=>{try{return require("@lensmcp/node-instrumentation")}catch{return}})();exports.LENS_DASHBOARD_PROJECT="(lens-dashboard)",exports.EDGE_DURATION_SAMPLES=64;function ownerOf(s){return s?.svc?{root:s.svc.root,wsKey:s.svc.wsKey}:s?.lens?{...s.lens.workspaceRoot?{root:s.lens.workspaceRoot}:{},...s.lens.workspaceKey?{wsKey:s.lens.workspaceKey}:{}}:{}}f(ownerOf,"ownerOf"),i(ownerOf,"ownerOf");function busFileFor(s,u){const{root:l}=ownerOf(s);if(!l)return;const w=path.join(l,".lensmcp","events.jsonl");return w===u?void 0:w}f(busFileFor,"busFileFor"),i(busFileFor,"busFileFor");const hdr=i(s=>typeof s=="string"&&s!==""?s:Array.isArray(s)?s[0]:void 0,"hdr");function createObservability(s,u){const l=i(()=>Date.now().toString(36)+Math.random().toString(36).slice(2,12),"eid"),w=busHygiene?.createEventFloodGuard({burst:30,perSec:5}),g=new Map,S=i((e,t)=>{try{const r=g.get(e);r&&(fs.appendFileSync(e,JSON.stringify({id:l(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:"warning",context:{sessionId:"pending"},fingerprint:"cluster-gateway:bus-dropped",title:`lens bus: ${r.count} event${r.count===1?"":"s"} could not be written since ${new Date(r.since).toISOString()} (${r.code}) \u2014 they are lost`,raw:{kind:"bus-events-dropped",project:"gateway",dropped:r.count,since:r.since,until:Date.now(),code:r.code}})+`
2
+ `),g.delete(e),console.warn(`[gateway] the lens bus ${e} takes events again \u2014 ${r.count} were lost (${r.code})`)),fs.appendFileSync(e,t)}catch(r){const a=g.get(e);if(a){a.count+=1;return}const o=r?.code??"EIO";g.set(e,{count:1,since:Date.now(),code:o}),console.warn(`[gateway] the lens bus ${e} cannot be written (${o}) \u2014 counting the events lost until it can`)}},"appendCounted"),y=i((e,t,r,a,o,d)=>{const n=d??s;try{const c=w?w.admit(r):{ok:!0,suppressed:0};if(!c.ok)return;fs.mkdirSync(path.dirname(n),{recursive:!0});const p=a&&(0,redact_1.redactDeep)(a),h=JSON.stringify({id:l(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:e,context:(0,redact_1.redactDeep)({sessionId:"pending",...o}),fingerprint:r,title:(0,redact_1.safeTitle)(t),raw:c.suppressed>0?{...p,floodSuppressed:c.suppressed}:p})+`
3
+ `;busHygiene?.maybeRotateEventFile(n,h.length),S(n,h)}catch{}},"emit"),E=i(e=>{const t=hdr(e.headers["x-lensmcp-flow-id"]);let r=hdr(e.headers["x-request-id"]);if(!(!t&&!r&&!hdr(e.headers.traceparent)))return r||(r=l(),e.headers["x-request-id"]=r),{startedAt:Date.now(),method:(e.method??"GET").toUpperCase(),host:(e.headers.host||"").split(":")[0],url:e.url??"/",steps:[],...t?{flowId:t}:{},...r?{requestId:r}:{},...hdr(e.headers["x-lensmcp-parent-request-id"])?{parentRequestId:hdr(e.headers["x-lensmcp-parent-request-id"])}:{},...hdr(e.headers["x-lensmcp-origin-node-id"])?{originNodeId:hdr(e.headers["x-lensmcp-origin-node-id"])}:{}}},"beginTrace"),D=i((e,t,r,a)=>{if(r?.flowId||!t.pool||t.internal||t.project===exports.LENS_DASHBOARD_PROJECT||!(0,headless_flow_1.headlessFlowsEnabled)())return r;const o=e.url??"/";if((0,headless_flow_1.isProbePath)(o))return r;const d=hdr(e.headers["x-request-id"]);if(!d)return r;const n=(0,headless_flow_1.headlessFlowId)(d);e.headers["x-lensmcp-flow-id"]=n;const c=(e.method??"GET").toUpperCase(),p=(e.headers.host||"").split(":")[0],h=`request:${c} ${o.split("?")[0]}`,I=r??{startedAt:a,method:c,host:p,url:o,steps:[{step:"received",atMs:0,host:p,method:c,url:o}],requestId:d};return I.flowId=n,I.originNodeId=h,y("info",`${c} ${o.split("?")[0]}`,`gateway-origin:${t.project}`,{kind:"flow-origin",originNodeId:h,project:t.project,host:p,method:c,url:o,...ownerOf(t).wsKey?{wsKey:ownerOf(t).wsKey}:{}},{flowId:n,requestId:d,originType:"request",originNodeId:h},busFileFor(t,s)),I},"startHeadlessFlow"),b=i((e,t,r)=>{e&&e.steps.push({step:t,atMs:Date.now()-e.startedAt,...r})},"traceStep"),_=i((e,t,r,a,o)=>{if(!e||e.done||(e.done=!0,t===exports.LENS_DASHBOARD_PROJECT&&r<500))return;const d=Date.now()-e.startedAt;y(r>=500?"error":"info",`gateway ${e.method} ${e.host}${e.url} \u2192 ${r} (${d}ms)`,`gateway-request:${t}`,{kind:"gateway-request",project:t,host:e.host,method:e.method,url:e.url,status:r,durationMs:d,startedAt:e.startedAt,steps:e.steps,...ownerOf(o).wsKey?{wsKey:ownerOf(o).wsKey}:{},...a},{...e.flowId?{flowId:e.flowId}:{},...e.requestId?{requestId:e.requestId}:{},...e.parentRequestId?{parentRequestId:e.parentRequestId}:{},...e.originNodeId?{originNodeId:e.originNodeId}:{}},busFileFor(o,s))},"finishTrace"),m=new Map;return{emit:y,eid:l,beginTrace:E,startHeadlessFlow:D,traceStep:b,finishTrace:_,recordEdge:i((e,t,r,a)=>{if(e.project===exports.LENS_DASHBOARD_PROJECT&&r<500&&r!==0)return;const o=e.host??"(default)",d=(a?a+"\u21D2":"")+o+"\u2192"+e.project,n=m.get(d)??{host:o,project:e.project,caller:a,count:0,totalMs:0,errors:0,durations:[],...busFileFor(e,s)?{busFile:busFileFor(e,s)}:{},...ownerOf(e).wsKey?{wsKey:ownerOf(e).wsKey}:{}};if(n.count+=1,n.totalMs+=t,n.durations.length<exports.EDGE_DURATION_SAMPLES)n.durations.push(Math.round(t));else{const c=Math.floor(Math.random()*n.count);c<exports.EDGE_DURATION_SAMPLES&&(n.durations[c]=Math.round(t))}(r>=500||r===0)&&(n.errors+=1),m.set(d,n)},"recordEdge"),startEdgeFlusher:i(()=>{const e=setInterval(()=>{for(const t of m.values()){const r=Math.round(t.totalMs/t.count);y(t.errors?"warning":"info",`traffic ${t.host} \u2192 ${t.project}: ${t.count} req, ~${r}ms${t.errors?`, ${t.errors} errors`:""}`,`gateway-traffic:${t.host}->${t.project}`,{kind:"gateway-traffic",host:t.host,project:t.project,caller:t.caller,count:t.count,avgMs:r,errors:t.errors,durationsMs:t.durations,...t.wsKey?{wsKey:t.wsKey}:{}},void 0,t.busFile)}m.clear()},u.trafficFlushMs);return e.unref(),e},"startEdgeFlusher")}}f(createObservability,"createObservability"),i(createObservability,"createObservability");
@@ -0,0 +1,44 @@
1
+ /** One process, as `ps` lists it. */
2
+ export interface PsRow {
3
+ pid: number;
4
+ ppid: number;
5
+ pgid: number;
6
+ uid: number;
7
+ command: string;
8
+ }
9
+ /** The `ps` arguments {@link parsePsRows} reads. */
10
+ export declare const PS_ROW_ARGS: string[];
11
+ export declare function parsePsRows(out: string): PsRow[];
12
+ /** A service whose orphaned executors may be reaped: the label its processes are named with, and its workspace root. */
13
+ export interface OrphanOwner {
14
+ label: string;
15
+ project: string;
16
+ root: string;
17
+ }
18
+ /** The roles of the process that holds a service's executor: nx's (client and run-executor), and the serve runner. */
19
+ export declare const ORPHAN_ROLES: readonly ["nx", "serve"];
20
+ type OrphanRole = (typeof ORPHAN_ROLES)[number];
21
+ export interface OrphanMatchOptions {
22
+ /** Where process-name links live (process-name.ts `defaultLinkDirs`). */
23
+ linkDirs: readonly string[];
24
+ /** This user. */
25
+ uid: number;
26
+ /** This gateway. */
27
+ selfPid: number;
28
+ /** The process groups of every tree this gateway holds — live, standby, retiring, stopping. */
29
+ ownGroups: ReadonlySet<number>;
30
+ }
31
+ export interface Orphan {
32
+ row: PsRow;
33
+ owner: OrphanOwner;
34
+ role: OrphanRole;
35
+ /** Kill its process group: it leads it, or the group's leader is gone. Otherwise only the process. */
36
+ group: boolean;
37
+ }
38
+ /**
39
+ * The orphaned executors among `rows` — of the services in `owners` only. A process this gateway holds, a process with
40
+ * a parent, another user's, and one whose name or arguments are not exactly a gateway's for one of `owners` are never
41
+ * returned.
42
+ */
43
+ export declare function findOrphanExecutors(rows: readonly PsRow[], owners: readonly OrphanOwner[], opts: OrphanMatchOptions): Orphan[];
44
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";var x=Object.defineProperty;var u=(r,o)=>x(r,"name",{value:o,configurable:!0});var m=Object.defineProperty,d=u((r,o)=>m(r,"name",{value:o,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.ORPHAN_ROLES=exports.PS_ROW_ARGS=void 0,exports.parsePsRows=parsePsRows,exports.findOrphanExecutors=findOrphanExecutors;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),process_name_1=require("../../../process-name"),serve_launch_1=require("./serve-launch");exports.PS_ROW_ARGS=["ax","-ww","-o","pid=,ppid=,pgid=,uid=,command="];function parsePsRows(r){const o=[];for(const t of r.split(`
2
+ `)){const s=/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/.exec(t);s&&o.push({pid:Number(s[1]),ppid:Number(s[2]),pgid:Number(s[3]),uid:Number(s[4]),command:s[5]})}return o}u(parsePsRows,"parsePsRows"),d(parsePsRows,"parsePsRows"),exports.ORPHAN_ROLES=["nx",serve_launch_1.SERVE_RUNNER_ROLE];function namedExecutable(r,o){for(const t of o){const s=`${t.replace(/\/+$/,"")}/`;if(!r.startsWith(s))continue;const i=/^\d+-\d+\/([A-Za-z0-9._-]+)(?=\s|$)/.exec(r.slice(s.length));if(i)return{name:i[1],args:r.slice(s.length+i[0].length).trim().split(/\s+/).filter(Boolean)}}}u(namedExecutable,"namedExecutable"),d(namedExecutable,"namedExecutable");function rootForms(r){const o=new Set([path.resolve(r)]);try{o.add(fs.realpathSync(r))}catch{}return[...o]}u(rootForms,"rootForms"),d(rootForms,"rootForms");function isNxOf(r,o,t){const s=`${o}/node_modules/`,i=d(n=>n.startsWith(s)&&!n.slice(s.length).split("/").includes(".."),"under");if(r.some(n=>i(n)&&n.endsWith("/nx/dist/bin/run-executor.js")))return!0;const a=r.findIndex(n=>i(n)&&n.endsWith("/nx/dist/bin/nx.js"));return a>=0&&r[a+1]==="run"&&(r[a+2]??"").startsWith(`${t}:`)}u(isNxOf,"isNxOf"),d(isNxOf,"isNxOf");function findOrphanExecutors(r,o,t){const s=new Map;for(const e of o)for(const c of exports.ORPHAN_ROLES)for(const p of new Set([(0,process_name_1.processName)(e.label,e.project,c),(0,process_name_1.legacyProcessName)(e.label,e.project,c)])){if(!p)continue;const f=s.get(p)??[];f.push({owner:e,role:c}),s.set(p,f)}const i=new Set(r.map(e=>e.pid)),a=r.find(e=>e.pid===t.selfPid)?.pgid,n=[];for(const e of r){if(e.ppid!==1||e.uid!==t.uid||e.pid<=1||e.pgid<=1||e.pid===t.selfPid||t.ownGroups.has(e.pgid)||t.ownGroups.has(e.pid)||e.pgid===a)continue;const c=namedExecutable(e.command,t.linkDirs);if(!c)continue;const p=(s.get(c.name)??[]).find(({owner:f,role:h})=>rootForms(f.root).some(l=>h===serve_launch_1.SERVE_RUNNER_ROLE?(0,serve_launch_1.isServeRunnerCommandOf)(e.command,l):isNxOf(c.args,l,f.project)));p&&n.push({row:e,owner:p.owner,role:p.role,group:e.pid===e.pgid||!i.has(e.pgid)})}return n}u(findOrphanExecutors,"findOrphanExecutors"),d(findOrphanExecutors,"findOrphanExecutors");
@@ -19,6 +19,9 @@
19
19
  * still grew ~70 MB an hour on 1.25.9 (issues/closed/foodguard-77, reopened 2026-10-20). Truncating by path is safe for
20
20
  * the same reason as through the descriptor: every writer holds the launcher's append descriptor. A gateway run in a
21
21
  * terminal, or under a test, with neither, has nothing to rotate.
22
+ *
23
+ * Since issues/closed/foodguard-92 the gateway also opens that file itself and writes its stdout and stderr there
24
+ * ({@link takeOverGatewayLog}) — an append descriptor like the others, so the copy-and-truncate holds for it too.
22
25
  */
23
26
  export declare const OWN_LOG_MAX_BYTES: number;
24
27
  export declare const OWN_LOG_GENERATIONS = 3;
@@ -48,9 +51,77 @@ export declare function rotateOwnLog(file: string, opts?: OwnLogOptions): boolea
48
51
  export declare function startOwnLogRotation(root: string, opts?: OwnLogOptions & {
49
52
  everyMs?: number;
50
53
  }): () => void;
54
+ /** What a log writer could not write since its last write that worked. */
55
+ export interface DroppedOutput {
56
+ lines: number;
57
+ bytes: number;
58
+ firstAt: number;
59
+ lastAt: number;
60
+ /** The error of the last write that failed — `ENOSPC` on a full disk. */
61
+ code: string;
62
+ }
63
+ export interface LogWriter {
64
+ /** Write `data`. Never throws: a write that fails is counted. Returns whether it was written. */
65
+ write(data: string | Uint8Array): boolean;
66
+ /** What was lost since the last write that worked; nothing once a note has said so. */
67
+ dropped(): DroppedOutput | undefined;
68
+ }
69
+ /** The one line a log gets once it can be written again: how much of it is missing, when, and why. */
70
+ export declare function droppedNote(d: DroppedOutput, file?: string): string;
71
+ /**
72
+ * A log writer that outlives a failed write (issues/closed/foodguard-92): `append` may throw — `ENOSPC` on a full disk —
73
+ * and the writer counts what it could not write instead. The first write that works again is preceded by ONE line
74
+ * ({@link droppedNote}) saying how many lines were lost, between when and when, and why; then the writer goes on as before.
75
+ */
76
+ export declare function createLogWriter(append: (data: Buffer) => void, opts?: {
77
+ now?: () => number;
78
+ file?: string;
79
+ }): LogWriter;
80
+ /** The gateway writing its own log ({@link takeOverGatewayLog}). */
81
+ export interface GatewayLogTakeover {
82
+ readonly file: string;
83
+ /** The file at the path is not the one held open (removed, or renamed away): open the path again. Returns whether it did. */
84
+ reopenIfMoved(): boolean;
85
+ dropped(): DroppedOutput | undefined;
86
+ /** Give the streams their own `write` back and close the file. */
87
+ restore(): void;
88
+ }
89
+ /** A stream whose `write` the takeover replaces — `process.stdout` / `process.stderr`. */
90
+ interface Writable {
91
+ write: (...args: never[]) => boolean;
92
+ }
93
+ export interface TakeOverOptions {
94
+ /** The log to write. Default: {@link GATEWAY_LOG_ENV}, the file the launcher opened. */
95
+ file?: string;
96
+ /** Default: this process's stdout and stderr. */
97
+ streams?: Writable[];
98
+ now?: () => number;
99
+ /** Write `data` to `fd`, returning how much was written — the spec makes it fail. */
100
+ writeFd?: (fd: number, data: Buffer) => number;
101
+ }
102
+ /** The takeover in force in this process, if any — a child whose output should reach the log is relayed through it. */
103
+ export declare function gatewayLogTakeover(): GatewayLogTakeover | undefined;
104
+ /**
105
+ * The gateway writes `gateway.log` itself (issues/closed/foodguard-92).
106
+ *
107
+ * Under `lensmcp gateway start` the gateway's stdout and stderr are a socket to the `nx run gateway:serve` client, and
108
+ * that client writes the file. One write of it that failed on a full disk (ENOSPC) was an unhandled error in nx, and nx
109
+ * died; from then on every line the gateway wrote went to a socket nobody read — its EPIPE swallowed as benign, nothing
110
+ * reopening anything — and the log stopped for good. FoodGuard, 2026-10-24: no line after 21:02:26Z (Node's fatal-exit
111
+ * footer, nx's), space free again from 21:07, nothing more until a restart; `events.jsonl`, which the gateway appends
112
+ * itself, went on.
113
+ *
114
+ * So when the launcher names the log it opened for append ({@link GATEWAY_LOG_ENV}), the gateway opens the same file
115
+ * for append and every write to its stdout and stderr goes there: nx is no longer between it and the file. A write
116
+ * that fails is counted ({@link createLogWriter}); the next one that works says how much was lost. Nothing is written to
117
+ * the old streams any more, so nothing is written twice. Returns `undefined` — the streams left as they are — when no
118
+ * log is named or it cannot be opened.
119
+ */
120
+ export declare function takeOverGatewayLog(opts?: TakeOverOptions): GatewayLogTakeover | undefined;
51
121
  /**
52
122
  * A service's output, every line tagged with it. The relay used to tag a chunk — so a multi-line record (TypeORM's
53
123
  * «query is slow» with its SQL and parameters, a stack) had one `[engine]` on its first line and nothing on the rest,
54
124
  * and a chunk that began mid-line put the tag in the middle of one. Per stream: whether the next byte starts a line.
55
125
  */
56
126
  export declare function linePrefixer(project: string): (text: string) => string;
127
+ export {};
@@ -1,4 +1,6 @@
1
- "use strict";var O=Object.defineProperty;var a=(e,t)=>O(e,"name",{value:t,configurable:!0});var y=Object.defineProperty,o=a((e,t)=>y(e,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_LOG_ENV=exports.OWN_LOG_GENERATIONS=exports.OWN_LOG_MAX_BYTES=void 0,exports.shiftGenerations=shiftGenerations,exports.rotateOwnLog=rotateOwnLog,exports.startOwnLogRotation=startOwnLogRotation,exports.linePrefixer=linePrefixer;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.OWN_LOG_MAX_BYTES=50*1024*1024,exports.OWN_LOG_GENERATIONS=3;const CHECK_EVERY_MS=3e4;exports.GATEWAY_LOG_ENV="LENSMCP_GATEWAY_LOG";const readEnv=o(e=>process.env[e],"readEnv");function shiftGenerations(e,t){try{fs.unlinkSync(`${e}.${t}`)}catch{}for(let r=t-1;r>=1;r--)try{fs.renameSync(`${e}.${r}`,`${e}.${r+1}`)}catch{}}a(shiftGenerations,"shiftGenerations"),o(shiftGenerations,"shiftGenerations");const sameFile=o((e,t)=>!!e&&e.isFile()&&e.dev===t.dev&&e.ino===t.ino,"sameFile"),statOr=o(e=>{try{return e()}catch{return}},"statOr");function rotateOwnLog(e,t={}){const r=t.fd??1,s=t.maxBytes??exports.OWN_LOG_MAX_BYTES,c=t.keep??exports.OWN_LOG_GENERATIONS,n=statOr(()=>fs.statSync(e));if(!n||n.size<=s)return!1;const i=sameFile(statOr(()=>fs.fstatSync(r)),n),u=t.launchedLog??readEnv(exports.GATEWAY_LOG_ENV);if(!i&&!(u&&sameFile(statOr(()=>fs.statSync(u)),n)))return!1;try{shiftGenerations(e,c),fs.copyFileSync(e,`${e}.1`);try{fs.chmodSync(`${e}.1`,384)}catch{}i?fs.ftruncateSync(r,0):fs.truncateSync(e,0)}catch{return!1}const p=i?_=>{try{fs.writeSync(r,`${_}
2
- `)}catch{}}:_=>{try{fs.appendFileSync(e,`${_}
3
- `)}catch{}};return(t.note??p)(`[gateway] ${path.basename(e)} passed ${Math.round(s/1048576)} MB \u2014 rotated; the lines before are in ${path.basename(e)}.1 (\u2026${c} kept)`),!0}a(rotateOwnLog,"rotateOwnLog"),o(rotateOwnLog,"rotateOwnLog");function startOwnLogRotation(e,t={}){const r=path.join(e,".lensmcp","gateway.log"),s=setInterval(()=>rotateOwnLog(r,t),t.everyMs??CHECK_EVERY_MS);return s.unref?.(),()=>clearInterval(s)}a(startOwnLogRotation,"startOwnLogRotation"),o(startOwnLogRotation,"startOwnLogRotation");function linePrefixer(e){let t=!0;const r=`[${e}] `;return s=>{let c="";for(const n of s.split(/(?<=\n)/))n&&(c+=(t?r:"")+n,t=n.endsWith(`
4
- `));return c}}a(linePrefixer,"linePrefixer"),o(linePrefixer,"linePrefixer");
1
+ "use strict";var g=Object.defineProperty;var l=(t,e)=>g(t,"name",{value:e,configurable:!0});var S=Object.defineProperty,i=l((t,e)=>S(t,"name",{value:e,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_LOG_ENV=exports.OWN_LOG_GENERATIONS=exports.OWN_LOG_MAX_BYTES=void 0,exports.shiftGenerations=shiftGenerations,exports.rotateOwnLog=rotateOwnLog,exports.startOwnLogRotation=startOwnLogRotation,exports.droppedNote=droppedNote,exports.createLogWriter=createLogWriter,exports.gatewayLogTakeover=gatewayLogTakeover,exports.takeOverGatewayLog=takeOverGatewayLog,exports.linePrefixer=linePrefixer;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.OWN_LOG_MAX_BYTES=50*1024*1024,exports.OWN_LOG_GENERATIONS=3;const CHECK_EVERY_MS=3e4;exports.GATEWAY_LOG_ENV="LENSMCP_GATEWAY_LOG";const readEnv=i(t=>process.env[t],"readEnv");function shiftGenerations(t,e){try{fs.unlinkSync(`${t}.${e}`)}catch{}for(let s=e-1;s>=1;s--)try{fs.renameSync(`${t}.${s}`,`${t}.${s+1}`)}catch{}}l(shiftGenerations,"shiftGenerations"),i(shiftGenerations,"shiftGenerations");const sameFile=i((t,e)=>!!t&&t.isFile()&&t.dev===e.dev&&t.ino===e.ino,"sameFile"),statOr=i(t=>{try{return t()}catch{return}},"statOr");function rotateOwnLog(t,e={}){const s=e.fd??1,r=e.maxBytes??exports.OWN_LOG_MAX_BYTES,p=e.keep??exports.OWN_LOG_GENERATIONS,d=statOr(()=>fs.statSync(t));if(!d||d.size<=r)return!1;const u=sameFile(statOr(()=>fs.fstatSync(s)),d),a=e.launchedLog??readEnv(exports.GATEWAY_LOG_ENV);if(!u&&!(a&&sameFile(statOr(()=>fs.statSync(a)),d)))return!1;try{shiftGenerations(t,p),fs.copyFileSync(t,`${t}.1`);try{fs.chmodSync(`${t}.1`,384)}catch{}u?fs.ftruncateSync(s,0):fs.truncateSync(t,0)}catch{return!1}const f=u?n=>{try{fs.writeSync(s,`${n}
2
+ `)}catch{}}:n=>{try{fs.appendFileSync(t,`${n}
3
+ `)}catch{}};return(e.note??f)(`[gateway] ${path.basename(t)} passed ${Math.round(r/1048576)} MB \u2014 rotated; the lines before are in ${path.basename(t)}.1 (\u2026${p} kept)`),!0}l(rotateOwnLog,"rotateOwnLog"),i(rotateOwnLog,"rotateOwnLog");function startOwnLogRotation(t,e={}){const s=path.join(t,".lensmcp","gateway.log"),r=setInterval(()=>{activeTakeover?.reopenIfMoved(),rotateOwnLog(s,e)},e.everyMs??CHECK_EVERY_MS);return r.unref?.(),()=>clearInterval(r)}l(startOwnLogRotation,"startOwnLogRotation"),i(startOwnLogRotation,"startOwnLogRotation");const sizeText=i(t=>t>=1048576?`${(t/1048576).toFixed(1)} MB`:t>=1024?`${Math.round(t/1024)} KB`:`${t} B`,"sizeText");function droppedNote(t,e="gateway.log"){const s=t.code==="ENOSPC"?"ENOSPC \u2014 the disk was full":t.code;return`[gateway] ${new Date(t.lastAt).toISOString()} ${e}: ${t.lines} line${t.lines===1?"":"s"} (${sizeText(t.bytes)}) could not be written between ${new Date(t.firstAt).toISOString()} and ${new Date(t.lastAt).toISOString()} (${s}) \u2014 they are lost
4
+ `}l(droppedNote,"droppedNote"),i(droppedNote,"droppedNote");function createLogWriter(t,e={}){const s=e.now??Date.now;let r,p=!0;const d=i(a=>{try{t(a);return}catch(f){return f??new Error("the write failed")}},"attempt"),u=i((a,f)=>{const n=s();let o=0;for(const y of a)y===10&&(o+=1);o=Math.max(1,o);const c=f?.code??"EIO";r=r?{lines:r.lines+o,bytes:r.bytes+a.length,firstAt:r.firstAt,lastAt:n,code:c}:{lines:o,bytes:a.length,firstAt:n,lastAt:n,code:c},p=!1},"count");return{write(a){const f=typeof a=="string"?Buffer.from(a):Buffer.from(a.buffer,a.byteOffset,a.byteLength);if(f.length===0)return!0;if(r){const o=Buffer.from(`${p?"":`
5
+ `}${droppedNote(r,e.file)}`),c=d(o);if(c)return u(f,c),!1;r=void 0,p=!0}const n=d(f);return n?(u(f,n),!1):(p=f[f.length-1]===10,!0)},dropped:i(()=>r?{...r}:void 0,"dropped")}}l(createLogWriter,"createLogWriter"),i(createLogWriter,"createLogWriter");let activeTakeover;function gatewayLogTakeover(){return activeTakeover}l(gatewayLogTakeover,"gatewayLogTakeover"),i(gatewayLogTakeover,"gatewayLogTakeover");function takeOverGatewayLog(t={}){const e=t.file??readEnv(exports.GATEWAY_LOG_ENV);if(!e||!path.isAbsolute(e))return;const s=i(()=>{try{const n=fs.openSync(e,"a",384);try{fs.fchmodSync(n,384)}catch{}return n}catch{return}},"open");let r=s();if(r===void 0)return;const p=t.writeFd??((n,o)=>fs.writeSync(n,o)),d=createLogWriter(i(n=>{if(r===void 0&&(r=s()),r===void 0)throw Object.assign(new Error(`${e} cannot be opened`),{code:"ENOENT"});let o=n;for(;o.length>0;){const c=p(r,o);if(!(c>0))throw Object.assign(new Error("nothing was written"),{code:"EIO"});o=o.subarray(c)}},"append"),{...t.now?{now:t.now}:{},file:path.basename(e)}),u=t.streams??[process.stdout,process.stderr],a=u.map(n=>n.write);for(const n of u)n.write=((o,c,y)=>{const O=typeof c=="function"?c:typeof y=="function"?y:void 0,w=typeof o=="string"?Buffer.from(o,typeof c=="string"&&Buffer.isEncoding(c)?c:"utf8"):o instanceof Uint8Array?o:Buffer.from(String(o));return d.write(w),O&&process.nextTick(O),!0});const f={file:e,reopenIfMoved(){const n=statOr(()=>fs.statSync(e)),o=r===void 0?void 0:statOr(()=>fs.fstatSync(r));if(n&&sameFile(o,n))return!1;const c=s();if(c===void 0)return!1;const y=r;if(r=c,y!==void 0)try{fs.closeSync(y)}catch{}return!0},dropped:i(()=>d.dropped(),"dropped"),restore(){if(u.forEach((n,o)=>{n.write=a[o]}),r!==void 0)try{fs.closeSync(r)}catch{}r=void 0,activeTakeover===f&&(activeTakeover=void 0)}};return t.streams||(activeTakeover=f),f}l(takeOverGatewayLog,"takeOverGatewayLog"),i(takeOverGatewayLog,"takeOverGatewayLog");function linePrefixer(t){let e=!0;const s=`[${t}] `;return r=>{let p="";for(const d of r.split(/(?<=\n)/))d&&(p+=(e?s:"")+d,e=d.endsWith(`
6
+ `));return p}}l(linePrefixer,"linePrefixer"),i(linePrefixer,"linePrefixer");
@@ -1,3 +1,3 @@
1
- "use strict";var fe=Object.defineProperty;var T=(r,t)=>fe(r,"name",{value:t,configurable:!0});var ye=Object.defineProperty,o=T((r,t)=>ye(r,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT=exports.GATEWAY_MAX_H2_STREAMS_DEFAULT=exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT=exports.GATEWAY_MAX_CONNECTIONS_DEFAULT=exports.BENIGN_SOCKET_ERRNOS=void 0,exports.buildEdgeVerifierPool=buildEdgeVerifierPool,exports.edgeKeyWait=edgeKeyWait,exports.withBuiltinHooks=withBuiltinHooks,exports.classifyClientError=classifyClientError,exports.createClientErrorLogGate=createClientErrorLogGate,exports.retirePreviousWorkspace=retirePreviousWorkspace,exports.resolveMaxConnections=resolveMaxConnections,exports.h2BudgetFromEnv=h2BudgetFromEnv,exports.createH2Governor=createH2Governor,exports.startGateway=startGateway;const tslib_1=require("tslib"),http=tslib_1.__importStar(require("node:http")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),scope_1=require("./scope"),route_registry_1=require("./route-registry"),act_1=require("./act"),control_1=require("./control"),workspace_middleware_1=require("./workspace-middleware"),workspace_registry_1=require("./workspace-registry"),service_keys_1=require("./service-keys"),source_poller_1=require("./source-poller"),client_ip_1=require("../client-ip"),workspace_log_1=require("./workspace-log"),own_log_1=require("./own-log"),observability_1=require("./observability"),lifecycle_1=require("./lifecycle"),process_names_1=require("./process-names"),project_graph_store_1=require("./project-graph-store"),serve_launch_1=require("./serve-launch"),process_name_1=require("../../../process-name"),protocol_1=require("../../../shared-build/protocol"),lens_children_1=require("./lens-children"),proxy_1=require("./proxy"),auth_1=require("./auth"),hooks_1=require("./hooks"),handler_1=require("./handler"),upgrade_1=require("./upgrade"),jwks_verify_1=require("../jwks-verify"),manifest_1=require("../manifest"),edge_1=require("./edge"),warm_start_1=require("./warm-start"),types_1=require("./types");function insecureLocalFetch(r,t){return new Promise((i,c)=>{const a=(r.startsWith("https:")?require("node:https"):require("node:http")).request(r,{method:"GET",headers:t?.headers,rejectUnauthorized:!1},_=>{const y=[];_.on("data",h=>y.push(h)),_.on("error",c),_.on("end",()=>{const h=_.statusCode??0,A=Buffer.concat(y).toString("utf8");i({ok:h>=200&&h<300,status:h,json:o(async()=>JSON.parse(A),"json")})})});a.on("error",c),t?.signal?.addEventListener("abort",()=>a.destroy(new Error(`JWKS ${r} \u2192 aborted`)),{once:!0}),a.end()})}T(insecureLocalFetch,"insecureLocalFetch"),o(insecureLocalFetch,"insecureLocalFetch");function buildEdgeVerifierPool(r,t={}){const i=process.env.LENSMCP_GW_JWKS_URL,c=process.env.LENSMCP_GW_JWT_ISS,a=new Map;let _,y=!1;const h=o((s,l)=>{console.log(`[gateway] edge JWT: verifying via JWKS ${s}${l}`);const d=(0,jwks_verify_1.createJwksVerifier)({jwksUrl:s,...c?{issuer:c}:{},fetchImpl:t.fetchImpl??insecureLocalFetch});let E=!1;return d.warm({...t.warm,onError:o((M,x,b)=>{E=!0,x===1&&b!==void 0&&console.warn(`[gateway] edge JWKS ${s} not loaded yet (${M.message}) \u2014 retrying in the background`),b===void 0&&console.warn(`[gateway] edge JWKS ${s} still not loaded after ${x} attempts (${M.message}) \u2014 the first token that needs it fetches it`)},"onError")}).then(M=>{M&&E&&console.log(`[gateway] edge JWKS ${s} loaded`)}),d},"make"),A=o(s=>{let l=a.get(s);return l||(l=h(`https://auth.${s}/jwks.json`,` (auto-derived for apex ${s})`),a.set(s,l)),l},"forApex");return{for(s){if(i)return _??=h(i,"");const l=s.split(":")[0].toLowerCase();let d;for(const E of idpApexes(r()))(l===E||l.endsWith(`.${E}`))&&(!d||E.length>d.length)&&(d=E);return d?A(d):void 0},warm(){if(!y){if(i){_??=h(i,"");return}for(const s of idpApexes(r()))A(s)}},stop(){y=!0,_?.stop();for(const s of a.values())s.stop()}}}T(buildEdgeVerifierPool,"buildEdgeVerifierPool"),o(buildEdgeVerifierPool,"buildEdgeVerifierPool");function idpApexes(r){const t=new Set;for(const i of r){const c=i.host;typeof c!="string"||!/^auth\./.test(c)||c.startsWith("internal.")||t.add(c.slice(5))}return t}T(idpApexes,"idpApexes"),o(idpApexes,"idpApexes");function edgeKeyWait(r){return async t=>{const i=t.route;if(!i?.auth||i.internal)return;const{req:c}=t,a=Array.isArray(c.headers.authorization)?c.headers.authorization[0]:c.headers.authorization,_=String(a??"");if(!_.startsWith("Bearer "))return;const y=c.url??"/";if((0,manifest_1.authRuleFor)(i.auth,(0,edge_1.canonicalPath)(y)??y.split("?")[0],(c.method??"GET").toUpperCase()).mode!=="jwt")return;const h=String(c.headers.host??"").split(":")[0].toLowerCase();await r.for(h)?.awaitKey(_.slice(7))}}T(edgeKeyWait,"edgeKeyWait"),o(edgeKeyWait,"edgeKeyWait");function withBuiltinHooks(r,t){return{...r,beforeAuth:[...r.beforeAuth??[],t.keyWait],afterAuth:[t.middleware,...r.afterAuth??[]]}}T(withBuiltinHooks,"withBuiltinHooks"),o(withBuiltinHooks,"withBuiltinHooks"),exports.BENIGN_SOCKET_ERRNOS=new Set(["ECONNRESET","EPIPE","ETIMEDOUT","ECONNABORTED","ECANCELED"]);function classifyClientError(r,t){return r&&exports.BENIGN_SOCKET_ERRNOS.has(r)?{status:null,report:!1,cause:"client-abort"}:r==="HPE_INVALID_EOF_STATE"?{status:null,report:!1,cause:"truncated-at-eof"}:r==="ERR_HTTP_REQUEST_TIMEOUT"?{status:408,report:!0,cause:"request-timeout"}:r==="HPE_HEADER_OVERFLOW"?{status:431,report:!0,cause:"header-overflow"}:r?.startsWith("HPE_")?{status:400,report:!0,cause:"parse-error"}:{status:400,report:!0,cause:r??t??"unknown"}}T(classifyClientError,"classifyClientError"),o(classifyClientError,"classifyClientError");const CLIENT_ERROR_REASON={400:"Bad Request",408:"Request Timeout",431:"Request Header Fields Too Large"};function createClientErrorLogGate(r=1e4){const t=new Map;return i=>{const c=Date.now(),a=t.get(i)??0;return c-a<r?!1:(t.set(i,c),!0)}}T(createClientErrorLogGate,"createClientErrorLogGate"),o(createClientErrorLogGate,"createClientErrorLogGate");function guardInboundSocket(r){r.on("error",t=>{exports.BENIGN_SOCKET_ERRNOS.has(t.code??"")||console.warn(`[gateway] inbound socket error (${t.code??t.message}) \u2014 dropping this connection only`),r.destroy()})}T(guardInboundSocket,"guardInboundSocket"),o(guardInboundSocket,"guardInboundSocket");function retirePreviousWorkspace(r,t,i){const c=r.get(t);if(!c)return!1;r.delete(t),i==="re-registered"&&console.log(`[gateway] workspace '${t}' re-registered \u2014 retiring the children of its previous registration first.`);try{c()}catch(a){console.warn(`[gateway] could not fully retire the previous registration of '${t}' (${i}): ${a.message}`)}return!0}T(retirePreviousWorkspace,"retirePreviousWorkspace"),o(retirePreviousWorkspace,"retirePreviousWorkspace"),exports.GATEWAY_MAX_CONNECTIONS_DEFAULT=512,exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT=64,exports.GATEWAY_MAX_H2_STREAMS_DEFAULT=4096,exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT=3e5;function parseBudget(r,t){if(r===void 0||r.trim()==="")return t;const i=Number(r);return!Number.isFinite(i)||i<0?t:Math.floor(i)}T(parseBudget,"parseBudget"),o(parseBudget,"parseBudget");function resolveMaxConnections(r){return parseBudget(r,exports.GATEWAY_MAX_CONNECTIONS_DEFAULT)}T(resolveMaxConnections,"resolveMaxConnections"),o(resolveMaxConnections,"resolveMaxConnections");function h2BudgetFromEnv(r=process.env){return{maxSessions:parseBudget(r.LENSMCP_MAX_H2_SESSIONS,exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT),maxStreams:parseBudget(r.LENSMCP_MAX_H2_STREAMS,exports.GATEWAY_MAX_H2_STREAMS_DEFAULT),idleSessionMs:parseBudget(r.LENSMCP_H2_IDLE_MS,exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT)}}T(h2BudgetFromEnv,"h2BudgetFromEnv"),o(h2BudgetFromEnv,"h2BudgetFromEnv");function createH2Governor(r,t){const{NGHTTP2_ENHANCE_YOUR_CALM:i,NGHTTP2_REFUSED_STREAM:c}=require("node:http2").constants,a=new Map;let _=0;const y=o(s=>{s.idle&&(clearTimeout(s.idle),s.idle=void 0)},"disarm"),h=o((s,l)=>{y(l),!(r.idleSessionMs<=0||l.open>0)&&(l.idle=setTimeout(()=>{s.destroyed||s.closed||(t("session-reclaimed",{idleMs:r.idleSessionMs,sessions:a.size}),a.delete(s),s.close())},r.idleSessionMs),l.idle.unref?.())},"arm"),A=o(()=>{for(const[s,l]of a)if(!(l.open>0||s.destroyed))return y(l),a.delete(s),t("session-reclaimed",{reason:"cap",sessions:a.size+1,maxSessions:r.maxSessions}),s.close(),!0;return!1},"reclaimOldestIdle");return{admitSession(s){if(r.maxSessions>0&&a.size>=r.maxSessions&&!A()){t("session-refused",{sessions:a.size,maxSessions:r.maxSessions,streams:_});try{s.goaway(i)}catch{}try{s.close()}catch{}return!1}const l={open:0};return a.set(s,l),h(s,l),s.once("close",()=>{y(l),a.delete(s)}),!0},admitStream(s,l){const d=a.get(s);if(!d)return!0;if(r.maxStreams>0&&_>=r.maxStreams){t("stream-refused",{streams:_,maxStreams:r.maxStreams,sessions:a.size});try{l.close(c)}catch{}return!1}return _+=1,d.open+=1,y(d),l.once("close",()=>{_=Math.max(0,_-1),d.open=Math.max(0,d.open-1),d.open===0&&a.has(s)&&h(s,d)}),!0},dispose(){for(const s of a.values())y(s);a.clear()}}}T(createH2Governor,"createH2Governor"),o(createH2Governor,"createH2Governor");async function startGateway(r,t){const i=r.https!==!1,c=r.ports?.length?r.ports:[443],a=r.scanTtlMs??1500,_=r.startupTimeoutMs??12e4,y=r.sweepMs??1e4,h=r.trafficFlushMs??5e3;let A=!1;const s=process.env.LENSMCP_EVENT_FILE??path.join(t.root,".lensmcp","events.jsonl"),l=(0,own_log_1.startOwnLogRotation)(t.root),d=(0,scope_1.readLensScope)(t.root),E=d.key,M=d.sockNs!==E?d.sockNs:void 0,x=t.projectsConfigurations?.projects??{},b=(0,discovery_1.projectSourceRoots)(t.root,x,t.projectDependencies),{routes:j,services:P,instance:Q}=(0,discovery_1.discoverRoutes)(t.root,x,void 0,E,b,M,d.instance);if(j.length===0)throw new Error("[gateway] no project declares a `cluster` field \u2014 nothing to route.");const K=new route_registry_1.RouteRegistry;K.register({wsKey:E,...M?{sockNs:M}:{},root:t.root,routes:j,services:P,...Q?{instance:Q}:{}});const R=[];let Z=o(()=>{},"refreshCert"),U=o(()=>{},"warmEdgeVerifiers");const ee=o(()=>{(0,route_registry_1.rebuildRoutesInPlace)(R,K),Z(),U()},"rebuildRoutes");ee();const{serviceKeys:le,keyToProject:ue,keyToWorkspace:de}=(0,service_keys_1.loadServiceKeys)(t.root,P,E),pe=(0,client_ip_1.createClientIpResolver)({...(0,client_ip_1.clientIpOptionsFromEnv)(),...r.trustProxyHops!==void 0?{trustProxyHops:r.trustProxyHops}:{},...r.clientIpHeader?{clientIpHeader:r.clientIpHeader}:{},...r.clientIpTrustedProxies?{clientIpTrustedProxies:r.clientIpTrustedProxies}:{}}),S={root:t.root,wsKey:E,...M?{sockNs:M}:{},eventFile:s,routes:R,registry:K,rebuildRoutes:ee,services:P,serviceKeys:le,keyToProject:ue,keyToWorkspace:de,clientIp:pe,bodyStallMs:r.bodyStallMs??types_1.BODY_STALL_MS,scanTtlMs:a,startupTimeoutMs:_,sweepMs:y,trafficFlushMs:h,https:i,projectRoots:Object.fromEntries(Object.entries(t.projectsConfigurations?.projects??{}).map(([e,n])=>[e,path.resolve(t.root,n.root)])),projectSourceRoots:b,...t.projectGraphStore?{graphStores:(0,project_graph_store_1.createProjectGraphStores)(t.projectGraphStore)}:{},...r.sharedCompiler!==void 0?{sharedCompiler:r.sharedCompiler}:{},stopped:o(()=>A,"stopped")};(0,process_name_1.prelinkProcessNames)((0,process_names_1.gatewayProcessNames)(P,{runner:(0,serve_launch_1.serveRunnerEnabled)()&&!!t.projectGraphStore,sharedBuild:(0,protocol_1.sharedCompilerEnabled)(process.env,r.sharedCompiler),label:E||path.basename(t.root),lens:{key:E,dashboard:r.dashboard!==!1,mcp:r.mcp!==!1&&j.some(e=>!!e.lens)}}));const m=(0,observability_1.createObservability)(s,{trafficFlushMs:h}),_e=createClientErrorLogGate(),L=h2BudgetFromEnv(),Se=createClientErrorLogGate(3e4),D=createH2Governor(L,(e,n)=>{Se(e)&&console.warn(`[gateway] h2 aggregate budget: ${e} (${JSON.stringify(n)}). These are the FRONT DOOR's ceilings, not an upstream's \u2014 raise/disable with LENSMCP_MAX_H2_SESSIONS / LENSMCP_MAX_H2_STREAMS / LENSMCP_H2_IDLE_MS / LENSMCP_MAX_CONNECTIONS (0 = unbounded).`),m.emit(e==="session-reclaimed"?"info":"warning",`h2 aggregate budget: ${e}`,`gateway-h2-budget:${e}`,{kind:"h2-aggregate-budget",event:e,project:"gateway",...n})}),v=(0,lifecycle_1.createServiceLayer)(S,m),O=(0,lens_children_1.createLensChildren)(S,m,r),F=new Map;let re=o(()=>{},"ownBooted");const ge=new Promise(e=>re=e),te=(0,warm_start_1.createWorktreeWarmer)({rt:S,obs:m,ready:ge,ensureUp:o(e=>v.ensureUp(e),"ensureUp")});let B;if(r.middleware){const e=require(path.resolve(t.root,r.middleware));B=e.default??e}const Y=(0,workspace_middleware_1.createWorkspaceMiddleware)({ownerKey:E,...B?{owner:B}:{},policy:(0,workspace_middleware_1.guestMiddlewarePolicy)()}),I=process.env.LENSMCP_GW_ACT==="0"?void 0:(0,act_1.createActStore)({dir:path.join(path.dirname((0,control_1.controlSocketPath)()),"identities")});let $;try{$=(0,control_1.startControlServer)({rt:S,killService:o((e,n)=>v.killSpawned(e,n),"killService"),restartService:o((e,n)=>v.restartService(e,n),"restartService"),ensureService:o(e=>v.ensureUp(e),"ensureService"),...I?{act:I}:{},onRegister:o(async e=>{retirePreviousWorkspace(F,e.wsKey,"re-registered"),Y.set(e.wsKey,e.root,e.middleware);const n=await O.hostWorkspaceDashboard(e),w=await O.hostWorkspaceApps(e);F.set(e.wsKey,()=>{try{n?.()}finally{w()}}),te.onRegister(e)},"onRegister"),onUnregister:o(e=>{te.onUnregister(e.wsKey),retirePreviousWorkspace(F,e.wsKey,"unregistered"),Y.drop(e.wsKey),v.stopBuildHost(e.root)},"onUnregister")})}catch(e){console.warn("[gateway] control plane failed to start (multi-workspace register disabled):",e.message)}const H=(0,proxy_1.createProxy)(S,m,v),W=buildEdgeVerifierPool(()=>S.routes),se=(0,auth_1.createEdgeAuth)(S,m,W,I),he=o(e=>{const n=e.route?.wsKey,w=Y.for(n);if(w)try{const u=n?S.registry.get(n):void 0;w(e.req,{...n?{wsKey:n}:{},...u?{root:u.root}:{},env:u?.instance?.env??{}})}catch(u){m.traceStep(e.trace,"auth",{mode:"middleware",ok:!1,reason:u.message}),e.route&&m.finishTrace(e.trace,e.route.project,401),e.sendError(401,"unauthorized",`Gateway middleware rejected the request: ${u.message}`)}},"builtinMiddleware"),oe=(0,hooks_1.createHooks)(withBuiltinHooks(r.hooks??{},{keyWait:edgeKeyWait(W),middleware:he})),ne=(0,handler_1.createHandler)({rt:S,obs:m,auth:se,proxy:H,hooks:oe}),ae=(0,upgrade_1.createUpgrade)({rt:S,auth:se,proxy:H,hooks:oe,obs:m}),Ee=m.startEdgeFlusher(),me=v.startSweeper(),ie=(0,source_poller_1.createSourcePoller)({services:o(()=>S.registry.allServices(),"services"),serviceKey:o(e=>S.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],"serviceKey"),emit:o((e,n,w,u,g)=>m.emit(n,w,u,{wsKey:e.wsKey,...g},void 0,e.wsKey===S.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl")),"emit"),scanTtlMs:a,stopped:o(()=>A,"stopped")});(0,source_poller_1.sourcesEnabled)()&&ie.start(),await O.bootSingletonsAndApps();const ce=P.filter(e=>e.decl.eager).map(e=>v.ensureUp(e));Promise.allSettled(ce).then(()=>setTimeout(re,ce.length?2e4:0).unref());let k,X,q;if(i){const e=require("../../../basic-ssl"),n=(0,service_keys_1.gatewayCacheDir)(t.root);q=o(()=>e.getCertificateSync(n,"gateway",S.routes.map(w=>w.host).filter(w=>!!w)),"mintCert"),k=q(),X=e.caCertPath()}const J=[],G=[],z=r.maxConnections??resolveMaxConnections(process.env.LENSMCP_MAX_CONNECTIONS);for(const e of c){const n=k?require("node:http2").createSecureServer({key:k,cert:k,allowHTTP1:!0,maxSessionMemory:512,settings:{maxConcurrentStreams:512},peerMaxConcurrentStreams:512,streamResetBurst:r.h2ResetBurst??types_1.GATEWAY_H2_RESET_BURST,streamResetRate:r.h2ResetRate??types_1.GATEWAY_H2_RESET_RATE},(u,g)=>ne(u,g)):http.createServer(ne);n.on("upgrade",ae),n.on("error",u=>console.error(`[gateway] port ${e}: ${u.code}`)),n.on("connection",guardInboundSocket),n.on("secureConnection",guardInboundSocket),n.on("tlsClientError",(u,g)=>g.destroy()),n.on("clientError",(u,g)=>{const p=u,f=classifyClientError(p.code,p.message);if(f.report&&_e(f.cause)){const N=g.remoteAddress??"unknown",C=f.status===null?"dropped":String(f.status);console.warn(`[gateway] inbound H1 clientError from ${N}: ${f.cause} (${p.code??p.message}${p.bytesParsed!==void 0?`, bytesParsed=${p.bytesParsed}`:""}) \u2192 ${C}. This status is the GATEWAY's, not the upstream service's.`),m.emit("warning",`inbound clientError: ${f.cause} \u2192 ${C}`,`gateway-client-error:${f.cause}`,{kind:"gateway-client-error",cause:f.cause,code:p.code??null,status:f.status,peer:N,bytesParsed:p.bytesParsed??null})}f.status!==null&&g.writable&&g.end(`HTTP/1.1 ${f.status} ${CLIENT_ERROR_REASON[f.status]}\r
1
+ "use strict";var fe=Object.defineProperty;var T=(r,t)=>fe(r,"name",{value:t,configurable:!0});var ye=Object.defineProperty,o=T((r,t)=>ye(r,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT=exports.GATEWAY_MAX_H2_STREAMS_DEFAULT=exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT=exports.GATEWAY_MAX_CONNECTIONS_DEFAULT=exports.BENIGN_SOCKET_ERRNOS=void 0,exports.buildEdgeVerifierPool=buildEdgeVerifierPool,exports.edgeKeyWait=edgeKeyWait,exports.withBuiltinHooks=withBuiltinHooks,exports.classifyClientError=classifyClientError,exports.createClientErrorLogGate=createClientErrorLogGate,exports.retirePreviousWorkspace=retirePreviousWorkspace,exports.resolveMaxConnections=resolveMaxConnections,exports.h2BudgetFromEnv=h2BudgetFromEnv,exports.createH2Governor=createH2Governor,exports.startGateway=startGateway;const tslib_1=require("tslib"),http=tslib_1.__importStar(require("node:http")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),scope_1=require("./scope"),route_registry_1=require("./route-registry"),act_1=require("./act"),control_1=require("./control"),workspace_middleware_1=require("./workspace-middleware"),workspace_registry_1=require("./workspace-registry"),service_keys_1=require("./service-keys"),source_poller_1=require("./source-poller"),client_ip_1=require("../client-ip"),workspace_log_1=require("./workspace-log"),own_log_1=require("./own-log"),observability_1=require("./observability"),lifecycle_1=require("./lifecycle"),process_names_1=require("./process-names"),project_graph_store_1=require("./project-graph-store"),serve_launch_1=require("./serve-launch"),process_name_1=require("../../../process-name"),protocol_1=require("../../../shared-build/protocol"),lens_children_1=require("./lens-children"),proxy_1=require("./proxy"),auth_1=require("./auth"),hooks_1=require("./hooks"),handler_1=require("./handler"),upgrade_1=require("./upgrade"),jwks_verify_1=require("../jwks-verify"),manifest_1=require("../manifest"),edge_1=require("./edge"),warm_start_1=require("./warm-start"),types_1=require("./types");function insecureLocalFetch(r,t){return new Promise((i,c)=>{const a=(r.startsWith("https:")?require("node:https"):require("node:http")).request(r,{method:"GET",headers:t?.headers,rejectUnauthorized:!1},_=>{const y=[];_.on("data",h=>y.push(h)),_.on("error",c),_.on("end",()=>{const h=_.statusCode??0,v=Buffer.concat(y).toString("utf8");i({ok:h>=200&&h<300,status:h,json:o(async()=>JSON.parse(v),"json")})})});a.on("error",c),t?.signal?.addEventListener("abort",()=>a.destroy(new Error(`JWKS ${r} \u2192 aborted`)),{once:!0}),a.end()})}T(insecureLocalFetch,"insecureLocalFetch"),o(insecureLocalFetch,"insecureLocalFetch");function buildEdgeVerifierPool(r,t={}){const i=process.env.LENSMCP_GW_JWKS_URL,c=process.env.LENSMCP_GW_JWT_ISS,a=new Map;let _,y=!1;const h=o((s,l)=>{console.log(`[gateway] edge JWT: verifying via JWKS ${s}${l}`);const d=(0,jwks_verify_1.createJwksVerifier)({jwksUrl:s,...c?{issuer:c}:{},fetchImpl:t.fetchImpl??insecureLocalFetch});let E=!1;return d.warm({...t.warm,onError:o((M,x,b)=>{E=!0,x===1&&b!==void 0&&console.warn(`[gateway] edge JWKS ${s} not loaded yet (${M.message}) \u2014 retrying in the background`),b===void 0&&console.warn(`[gateway] edge JWKS ${s} still not loaded after ${x} attempts (${M.message}) \u2014 the first token that needs it fetches it`)},"onError")}).then(M=>{M&&E&&console.log(`[gateway] edge JWKS ${s} loaded`)}),d},"make"),v=o(s=>{let l=a.get(s);return l||(l=h(`https://auth.${s}/jwks.json`,` (auto-derived for apex ${s})`),a.set(s,l)),l},"forApex");return{for(s){if(i)return _??=h(i,"");const l=s.split(":")[0].toLowerCase();let d;for(const E of idpApexes(r()))(l===E||l.endsWith(`.${E}`))&&(!d||E.length>d.length)&&(d=E);return d?v(d):void 0},warm(){if(!y){if(i){_??=h(i,"");return}for(const s of idpApexes(r()))v(s)}},stop(){y=!0,_?.stop();for(const s of a.values())s.stop()}}}T(buildEdgeVerifierPool,"buildEdgeVerifierPool"),o(buildEdgeVerifierPool,"buildEdgeVerifierPool");function idpApexes(r){const t=new Set;for(const i of r){const c=i.host;typeof c!="string"||!/^auth\./.test(c)||c.startsWith("internal.")||t.add(c.slice(5))}return t}T(idpApexes,"idpApexes"),o(idpApexes,"idpApexes");function edgeKeyWait(r){return async t=>{const i=t.route;if(!i?.auth||i.internal)return;const{req:c}=t,a=Array.isArray(c.headers.authorization)?c.headers.authorization[0]:c.headers.authorization,_=String(a??"");if(!_.startsWith("Bearer "))return;const y=c.url??"/";if((0,manifest_1.authRuleFor)(i.auth,(0,edge_1.canonicalPath)(y)??y.split("?")[0],(c.method??"GET").toUpperCase()).mode!=="jwt")return;const h=String(c.headers.host??"").split(":")[0].toLowerCase();await r.for(h)?.awaitKey(_.slice(7))}}T(edgeKeyWait,"edgeKeyWait"),o(edgeKeyWait,"edgeKeyWait");function withBuiltinHooks(r,t){return{...r,beforeAuth:[...r.beforeAuth??[],t.keyWait],afterAuth:[t.middleware,...r.afterAuth??[]]}}T(withBuiltinHooks,"withBuiltinHooks"),o(withBuiltinHooks,"withBuiltinHooks"),exports.BENIGN_SOCKET_ERRNOS=new Set(["ECONNRESET","EPIPE","ETIMEDOUT","ECONNABORTED","ECANCELED"]);function classifyClientError(r,t){return r&&exports.BENIGN_SOCKET_ERRNOS.has(r)?{status:null,report:!1,cause:"client-abort"}:r==="HPE_INVALID_EOF_STATE"?{status:null,report:!1,cause:"truncated-at-eof"}:r==="ERR_HTTP_REQUEST_TIMEOUT"?{status:408,report:!0,cause:"request-timeout"}:r==="HPE_HEADER_OVERFLOW"?{status:431,report:!0,cause:"header-overflow"}:r?.startsWith("HPE_")?{status:400,report:!0,cause:"parse-error"}:{status:400,report:!0,cause:r??t??"unknown"}}T(classifyClientError,"classifyClientError"),o(classifyClientError,"classifyClientError");const CLIENT_ERROR_REASON={400:"Bad Request",408:"Request Timeout",431:"Request Header Fields Too Large"};function createClientErrorLogGate(r=1e4){const t=new Map;return i=>{const c=Date.now(),a=t.get(i)??0;return c-a<r?!1:(t.set(i,c),!0)}}T(createClientErrorLogGate,"createClientErrorLogGate"),o(createClientErrorLogGate,"createClientErrorLogGate");function guardInboundSocket(r){r.on("error",t=>{exports.BENIGN_SOCKET_ERRNOS.has(t.code??"")||console.warn(`[gateway] inbound socket error (${t.code??t.message}) \u2014 dropping this connection only`),r.destroy()})}T(guardInboundSocket,"guardInboundSocket"),o(guardInboundSocket,"guardInboundSocket");function retirePreviousWorkspace(r,t,i){const c=r.get(t);if(!c)return!1;r.delete(t),i==="re-registered"&&console.log(`[gateway] workspace '${t}' re-registered \u2014 retiring the children of its previous registration first.`);try{c()}catch(a){console.warn(`[gateway] could not fully retire the previous registration of '${t}' (${i}): ${a.message}`)}return!0}T(retirePreviousWorkspace,"retirePreviousWorkspace"),o(retirePreviousWorkspace,"retirePreviousWorkspace"),exports.GATEWAY_MAX_CONNECTIONS_DEFAULT=512,exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT=64,exports.GATEWAY_MAX_H2_STREAMS_DEFAULT=4096,exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT=3e5;function parseBudget(r,t){if(r===void 0||r.trim()==="")return t;const i=Number(r);return!Number.isFinite(i)||i<0?t:Math.floor(i)}T(parseBudget,"parseBudget"),o(parseBudget,"parseBudget");function resolveMaxConnections(r){return parseBudget(r,exports.GATEWAY_MAX_CONNECTIONS_DEFAULT)}T(resolveMaxConnections,"resolveMaxConnections"),o(resolveMaxConnections,"resolveMaxConnections");function h2BudgetFromEnv(r=process.env){return{maxSessions:parseBudget(r.LENSMCP_MAX_H2_SESSIONS,exports.GATEWAY_MAX_H2_SESSIONS_DEFAULT),maxStreams:parseBudget(r.LENSMCP_MAX_H2_STREAMS,exports.GATEWAY_MAX_H2_STREAMS_DEFAULT),idleSessionMs:parseBudget(r.LENSMCP_H2_IDLE_MS,exports.GATEWAY_H2_IDLE_SESSION_MS_DEFAULT)}}T(h2BudgetFromEnv,"h2BudgetFromEnv"),o(h2BudgetFromEnv,"h2BudgetFromEnv");function createH2Governor(r,t){const{NGHTTP2_ENHANCE_YOUR_CALM:i,NGHTTP2_REFUSED_STREAM:c}=require("node:http2").constants,a=new Map;let _=0;const y=o(s=>{s.idle&&(clearTimeout(s.idle),s.idle=void 0)},"disarm"),h=o((s,l)=>{y(l),!(r.idleSessionMs<=0||l.open>0)&&(l.idle=setTimeout(()=>{s.destroyed||s.closed||(t("session-reclaimed",{idleMs:r.idleSessionMs,sessions:a.size}),a.delete(s),s.close())},r.idleSessionMs),l.idle.unref?.())},"arm"),v=o(()=>{for(const[s,l]of a)if(!(l.open>0||s.destroyed))return y(l),a.delete(s),t("session-reclaimed",{reason:"cap",sessions:a.size+1,maxSessions:r.maxSessions}),s.close(),!0;return!1},"reclaimOldestIdle");return{admitSession(s){if(r.maxSessions>0&&a.size>=r.maxSessions&&!v()){t("session-refused",{sessions:a.size,maxSessions:r.maxSessions,streams:_});try{s.goaway(i)}catch{}try{s.close()}catch{}return!1}const l={open:0};return a.set(s,l),h(s,l),s.once("close",()=>{y(l),a.delete(s)}),!0},admitStream(s,l){const d=a.get(s);if(!d)return!0;if(r.maxStreams>0&&_>=r.maxStreams){t("stream-refused",{streams:_,maxStreams:r.maxStreams,sessions:a.size});try{l.close(c)}catch{}return!1}return _+=1,d.open+=1,y(d),l.once("close",()=>{_=Math.max(0,_-1),d.open=Math.max(0,d.open-1),d.open===0&&a.has(s)&&h(s,d)}),!0},dispose(){for(const s of a.values())y(s);a.clear()}}}T(createH2Governor,"createH2Governor"),o(createH2Governor,"createH2Governor");async function startGateway(r,t){const i=r.https!==!1,c=r.ports?.length?r.ports:[443],a=r.scanTtlMs??1500,_=r.startupTimeoutMs??12e4,y=r.sweepMs??1e4,h=r.trafficFlushMs??5e3;let v=!1;const s=process.env.LENSMCP_EVENT_FILE??path.join(t.root,".lensmcp","events.jsonl"),l=(0,own_log_1.startOwnLogRotation)(t.root),d=(0,scope_1.readLensScope)(t.root),E=d.key,M=d.sockNs!==E?d.sockNs:void 0,x=t.projectsConfigurations?.projects??{},b=(0,discovery_1.projectSourceRoots)(t.root,x,t.projectDependencies),{routes:j,services:P,instance:Q}=(0,discovery_1.discoverRoutes)(t.root,x,void 0,E,b,M,d.instance);if(j.length===0)throw new Error("[gateway] no project declares a `cluster` field \u2014 nothing to route.");const K=new route_registry_1.RouteRegistry;K.register({wsKey:E,...M?{sockNs:M}:{},root:t.root,routes:j,services:P,...Q?{instance:Q}:{}});const R=[];let Z=o(()=>{},"refreshCert"),U=o(()=>{},"warmEdgeVerifiers");const ee=o(()=>{(0,route_registry_1.rebuildRoutesInPlace)(R,K),Z(),U()},"rebuildRoutes");ee();const{serviceKeys:le,keyToProject:ue,keyToWorkspace:de}=(0,service_keys_1.loadServiceKeys)(t.root,P,E),pe=(0,client_ip_1.createClientIpResolver)({...(0,client_ip_1.clientIpOptionsFromEnv)(),...r.trustProxyHops!==void 0?{trustProxyHops:r.trustProxyHops}:{},...r.clientIpHeader?{clientIpHeader:r.clientIpHeader}:{},...r.clientIpTrustedProxies?{clientIpTrustedProxies:r.clientIpTrustedProxies}:{}}),g={root:t.root,wsKey:E,...M?{sockNs:M}:{},eventFile:s,routes:R,registry:K,rebuildRoutes:ee,services:P,serviceKeys:le,keyToProject:ue,keyToWorkspace:de,clientIp:pe,bodyStallMs:r.bodyStallMs??types_1.BODY_STALL_MS,scanTtlMs:a,startupTimeoutMs:_,sweepMs:y,trafficFlushMs:h,https:i,projectRoots:Object.fromEntries(Object.entries(t.projectsConfigurations?.projects??{}).map(([e,n])=>[e,path.resolve(t.root,n.root)])),projectSourceRoots:b,...t.projectGraphStore?{graphStores:(0,project_graph_store_1.createProjectGraphStores)(t.projectGraphStore)}:{},...r.sharedCompiler!==void 0?{sharedCompiler:r.sharedCompiler}:{},stopped:o(()=>v,"stopped")};(0,process_name_1.prelinkProcessNames)((0,process_names_1.gatewayProcessNames)(P,{runner:(0,serve_launch_1.serveRunnerEnabled)()&&!!t.projectGraphStore,sharedBuild:(0,protocol_1.sharedCompilerEnabled)(process.env,r.sharedCompiler),label:E||path.basename(t.root),lens:{key:E,dashboard:r.dashboard!==!1,mcp:r.mcp!==!1&&j.some(e=>!!e.lens)}}));const m=(0,observability_1.createObservability)(s,{trafficFlushMs:h}),_e=createClientErrorLogGate(),L=h2BudgetFromEnv(),ge=createClientErrorLogGate(3e4),D=createH2Governor(L,(e,n)=>{ge(e)&&console.warn(`[gateway] h2 aggregate budget: ${e} (${JSON.stringify(n)}). These are the FRONT DOOR's ceilings, not an upstream's \u2014 raise/disable with LENSMCP_MAX_H2_SESSIONS / LENSMCP_MAX_H2_STREAMS / LENSMCP_H2_IDLE_MS / LENSMCP_MAX_CONNECTIONS (0 = unbounded).`),m.emit(e==="session-reclaimed"?"info":"warning",`h2 aggregate budget: ${e}`,`gateway-h2-budget:${e}`,{kind:"h2-aggregate-budget",event:e,project:"gateway",...n})}),A=(0,lifecycle_1.createServiceLayer)(g,m),O=(0,lens_children_1.createLensChildren)(g,m,r),F=new Map;let re=o(()=>{},"ownBooted");const Se=new Promise(e=>re=e),te=(0,warm_start_1.createWorktreeWarmer)({rt:g,obs:m,ready:Se,ensureUp:o(e=>A.ensureUp(e),"ensureUp")});let B;if(r.middleware){const e=require(path.resolve(t.root,r.middleware));B=e.default??e}const Y=(0,workspace_middleware_1.createWorkspaceMiddleware)({ownerKey:E,...B?{owner:B}:{},policy:(0,workspace_middleware_1.guestMiddlewarePolicy)()}),I=process.env.LENSMCP_GW_ACT==="0"?void 0:(0,act_1.createActStore)({dir:path.join(path.dirname((0,control_1.controlSocketPath)()),"identities")});let $;try{$=(0,control_1.startControlServer)({rt:g,killService:o((e,n)=>A.killSpawned(e,n),"killService"),restartService:o((e,n)=>A.restartService(e,n),"restartService"),ensureService:o(e=>A.ensureUp(e),"ensureService"),...I?{act:I}:{},onRegister:o(async e=>{retirePreviousWorkspace(F,e.wsKey,"re-registered"),Y.set(e.wsKey,e.root,e.middleware);const n=await O.hostWorkspaceDashboard(e),w=await O.hostWorkspaceApps(e);F.set(e.wsKey,()=>{try{n?.()}finally{w()}}),te.onRegister(e)},"onRegister"),onUnregister:o(e=>{te.onUnregister(e.wsKey),retirePreviousWorkspace(F,e.wsKey,"unregistered"),Y.drop(e.wsKey),A.stopBuildHost(e.root)},"onUnregister")})}catch(e){console.warn("[gateway] control plane failed to start (multi-workspace register disabled):",e.message)}const H=(0,proxy_1.createProxy)(g,m,A),W=buildEdgeVerifierPool(()=>g.routes),se=(0,auth_1.createEdgeAuth)(g,m,W,I),he=o(e=>{const n=e.route?.wsKey,w=Y.for(n);if(w)try{const u=n?g.registry.get(n):void 0;w(e.req,{...n?{wsKey:n}:{},...u?{root:u.root}:{},env:u?.instance?.env??{}})}catch(u){m.traceStep(e.trace,"auth",{mode:"middleware",ok:!1,reason:u.message}),e.route&&m.finishTrace(e.trace,e.route.project,401),e.sendError(401,"unauthorized",`Gateway middleware rejected the request: ${u.message}`)}},"builtinMiddleware"),oe=(0,hooks_1.createHooks)(withBuiltinHooks(r.hooks??{},{keyWait:edgeKeyWait(W),middleware:he})),ne=(0,handler_1.createHandler)({rt:g,obs:m,auth:se,proxy:H,hooks:oe}),ae=(0,upgrade_1.createUpgrade)({rt:g,auth:se,proxy:H,hooks:oe,obs:m}),Ee=m.startEdgeFlusher(),me=A.startSweeper(),ie=(0,source_poller_1.createSourcePoller)({services:o(()=>g.registry.allServices(),"services"),serviceKey:o(e=>g.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],"serviceKey"),emit:o((e,n,w,u,S)=>m.emit(n,w,u,{wsKey:e.wsKey,...S},void 0,e.wsKey===g.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl")),"emit"),scanTtlMs:a,stopped:o(()=>v,"stopped")});(0,source_poller_1.sourcesEnabled)()&&ie.start(),await O.bootSingletonsAndApps();const ce=P.filter(e=>e.decl.eager).map(e=>A.ensureUp(e));Promise.allSettled(ce).then(()=>setTimeout(re,ce.length?2e4:0).unref());let k,X,q;if(i){const e=require("../../../basic-ssl"),n=(0,service_keys_1.gatewayCacheDir)(t.root);q=o(()=>e.getCertificateSync(n,"gateway",g.routes.map(w=>w.host).filter(w=>!!w)),"mintCert"),k=q(),X=e.caCertPath()}const J=[],G=[],z=r.maxConnections??resolveMaxConnections(process.env.LENSMCP_MAX_CONNECTIONS);for(const e of c){const n=k?require("node:http2").createSecureServer({key:k,cert:k,allowHTTP1:!0,maxSessionMemory:512,settings:{maxConcurrentStreams:512},peerMaxConcurrentStreams:512,streamResetBurst:r.h2ResetBurst??types_1.GATEWAY_H2_RESET_BURST,streamResetRate:r.h2ResetRate??types_1.GATEWAY_H2_RESET_RATE},(u,S)=>ne(u,S)):http.createServer(ne);n.on("upgrade",ae),n.on("error",u=>console.error(`[gateway] port ${e}: ${u.code}`)),n.on("connection",guardInboundSocket),n.on("secureConnection",guardInboundSocket),n.on("tlsClientError",(u,S)=>S.destroy()),n.on("clientError",(u,S)=>{const p=u,f=classifyClientError(p.code,p.message);if(f.report&&_e(f.cause)){const N=S.remoteAddress??"unknown",C=f.status===null?"dropped":String(f.status);console.warn(`[gateway] inbound H1 clientError from ${N}: ${f.cause} (${p.code??p.message}${p.bytesParsed!==void 0?`, bytesParsed=${p.bytesParsed}`:""}) \u2192 ${C}. This status is the GATEWAY's, not the upstream service's.`),m.emit("warning",`inbound clientError: ${f.cause} \u2192 ${C}`,`gateway-client-error:${f.cause}`,{kind:"gateway-client-error",cause:f.cause,code:p.code??null,status:f.status,peer:N,bytesParsed:p.bytesParsed??null})}f.status!==null&&S.writable&&S.end(`HTTP/1.1 ${f.status} ${CLIENT_ERROR_REASON[f.status]}\r
2
2
  \r
3
- `),g.destroy()}),n.keepAliveTimeout=types_1.GATEWAY_KEEPALIVE_TIMEOUT_MS,n.headersTimeout=r.headersTimeoutMs??types_1.GATEWAY_HEADERS_TIMEOUT_MS,z>0&&(n.maxConnections=z);const w=r.connectionsCheckingIntervalMs??types_1.GATEWAY_CONN_CHECK_MS;if(w>0&&(n.connectionsCheckingInterval=w),k!=null){const u=n,{NGHTTP2_CANCEL:g}=require("node:http2").constants;u.on("session",p=>{if(!D.admitSession(p)){p.on("error",()=>{});return}let f=0,N=0;p.on("stream",C=>{D.admitStream(p,C)&&C.once("close",()=>{p.destroyed?N+=1:C.rstCode===g&&(f+=1)})}),p.once("close",()=>{N!==0&&(console.warn(`[gateway] h2 session closed with ${N} stream(s) in flight after ${f} client reset(s) \u2014 every in-flight fetch on that connection failed at once (ERR_HTTP2_PROTOCOL_ERROR in the browser). Reset budget: LENSMCP_H2_RESET_BURST/LENSMCP_H2_RESET_RATE (issues/closed/foodguard-14).`),m.emit("warning",`h2 session lost with ${N} stream(s) in flight`,"gateway-h2-session-lost",{kind:"h2-session-lost",project:"gateway",inflight:N,clientResets:f}))}),p.on("error",C=>{const we=C.code??C.message;console.warn(`[gateway] h2 session error (${we}) \u2014 dropping this session only`),p.destroyed||p.destroy()})}),u.on("sessionError",p=>{console.warn(`[gateway] h2 sessionError: ${p.code??p.message}`)})}await new Promise(u=>{n.listen(e,()=>{const g=n.address()?.port??e;G.push(g),console.log(`[gateway] Listening on ${k?"https":"http"}://localhost:${g}`),u()})}),J.push(n)}q&&(Z=o(()=>{const e=q();for(const n of J)n.setSecureContext?.({key:e,cert:e})},"refreshCert")),console.log("[gateway] Routes:");for(const e of R){const n=e.pool?`pods@${e.pool.dir}`:e.target;console.log(`[gateway] ${e.host??"(default)"} \u2192 ${n}${e.prependPrefix?` (+${e.prependPrefix})`:""}${e.internal?" [internal: no middleware]":""} [${e.project}]`)}X&&console.log(`[gateway] CA: ${X} \u2014 one-time setup via the trust executor.`),U=o(()=>W.warm(),"warmEdgeVerifiers"),U();const V=o(e=>e>0?String(e):"unbounded","unbounded");return console.log(`[gateway] front-door budget: \u2264${V(z)} connections, \u2264${V(L.maxSessions)} h2 sessions (each \u2264512 MB session memory, \u2264512 streams), \u2264${V(L.maxStreams)} open streams in total, idle h2 session reclaimed after ${L.idleSessionMs>0?`${Math.round(L.idleSessionMs/1e3)}s`:"never"}. Override: LENSMCP_MAX_CONNECTIONS / LENSMCP_MAX_H2_SESSIONS / LENSMCP_MAX_H2_STREAMS / LENSMCP_H2_IDLE_MS (0 = unbounded).`),m.emit("info",`gateway up: ${R.length} routes on ${G.join("/")}`,"cluster-gateway",{kind:"gateway-up",project:"gateway",ports:G,routes:R.map(e=>({host:e.host??"(default)",project:e.project,mode:e.pool?"pods":"tcp",internal:!!e.internal,prependPrefix:e.prependPrefix}))}),$&&process.env.LENSMCP_GUEST_REPLAY!=="0"&&$.replay().catch(e=>console.warn("[gateway] guest replay failed:",e.message)),{ports:G,routes:R,services:P,stop:o(async()=>{if(!A){A=!0,clearInterval(Ee),clearInterval(me),ie.stop(),m.emit("info","gateway down","cluster-gateway",{kind:"gateway-down",project:"gateway"}),W.stop(),$?.close(),I?.flush(),(0,workspace_registry_1.unregisterWorkspace)(E);for(const e of P)v.killSpawned(e,"gateway shutdown");v.stopRetiringTrees(),await v.stopBuildHost(),await O.reapAll(),ae.closeTunnels(),await Promise.all(J.map(e=>new Promise(n=>{let w=!1;const u=o(()=>{w||(w=!0,n())},"done"),g=e;e.close(()=>u());try{g.closeIdleConnections?.()}catch{}setTimeout(()=>{try{g.closeAllConnections?.()}catch{}u()},types_1.GATEWAY_STOP_GRACE_MS).unref?.()}))),H.closeProxy(),H.destroyAgents(),D.dispose(),(0,workspace_log_1.closeWorkspaceLogs)(),l()}},"stop"),...S.lensSupervisor?{lensSupervisor:S.lensSupervisor}:{},...S.graphStores?{graphStores:S.graphStores}:{}}}T(startGateway,"startGateway"),o(startGateway,"startGateway");
3
+ `),S.destroy()}),n.keepAliveTimeout=types_1.GATEWAY_KEEPALIVE_TIMEOUT_MS,n.headersTimeout=r.headersTimeoutMs??types_1.GATEWAY_HEADERS_TIMEOUT_MS,z>0&&(n.maxConnections=z);const w=r.connectionsCheckingIntervalMs??types_1.GATEWAY_CONN_CHECK_MS;if(w>0&&(n.connectionsCheckingInterval=w),k!=null){const u=n,{NGHTTP2_CANCEL:S}=require("node:http2").constants;u.on("session",p=>{if(!D.admitSession(p)){p.on("error",()=>{});return}let f=0,N=0;p.on("stream",C=>{D.admitStream(p,C)&&C.once("close",()=>{p.destroyed?N+=1:C.rstCode===S&&(f+=1)})}),p.once("close",()=>{N!==0&&(console.warn(`[gateway] h2 session closed with ${N} stream(s) in flight after ${f} client reset(s) \u2014 every in-flight fetch on that connection failed at once (ERR_HTTP2_PROTOCOL_ERROR in the browser). Reset budget: LENSMCP_H2_RESET_BURST/LENSMCP_H2_RESET_RATE (issues/closed/foodguard-14).`),m.emit("warning",`h2 session lost with ${N} stream(s) in flight`,"gateway-h2-session-lost",{kind:"h2-session-lost",project:"gateway",inflight:N,clientResets:f}))}),p.on("error",C=>{const we=C.code??C.message;console.warn(`[gateway] h2 session error (${we}) \u2014 dropping this session only`),p.destroyed||p.destroy()})}),u.on("sessionError",p=>{console.warn(`[gateway] h2 sessionError: ${p.code??p.message}`)})}await new Promise(u=>{n.listen(e,()=>{const S=n.address()?.port??e;G.push(S),console.log(`[gateway] Listening on ${k?"https":"http"}://localhost:${S}`),u()})}),J.push(n)}q&&(Z=o(()=>{const e=q();for(const n of J)n.setSecureContext?.({key:e,cert:e})},"refreshCert")),console.log("[gateway] Routes:");for(const e of R){const n=e.pool?`pods@${e.pool.dir}`:e.target;console.log(`[gateway] ${e.host??"(default)"} \u2192 ${n}${e.prependPrefix?` (+${e.prependPrefix})`:""}${e.internal?" [internal: no middleware]":""} [${e.project}]`)}X&&console.log(`[gateway] CA: ${X} \u2014 one-time setup via the trust executor.`),U=o(()=>W.warm(),"warmEdgeVerifiers"),U();const V=o(e=>e>0?String(e):"unbounded","unbounded");return console.log(`[gateway] front-door budget: \u2264${V(z)} connections, \u2264${V(L.maxSessions)} h2 sessions (each \u2264512 MB session memory, \u2264512 streams), \u2264${V(L.maxStreams)} open streams in total, idle h2 session reclaimed after ${L.idleSessionMs>0?`${Math.round(L.idleSessionMs/1e3)}s`:"never"}. Override: LENSMCP_MAX_CONNECTIONS / LENSMCP_MAX_H2_SESSIONS / LENSMCP_MAX_H2_STREAMS / LENSMCP_H2_IDLE_MS (0 = unbounded).`),m.emit("info",`gateway up: ${R.length} routes on ${G.join("/")}`,"cluster-gateway",{kind:"gateway-up",project:"gateway",ports:G,routes:R.map(e=>({host:e.host??"(default)",project:e.project,mode:e.pool?"pods":"tcp",internal:!!e.internal,prependPrefix:e.prependPrefix}))}),$&&process.env.LENSMCP_GUEST_REPLAY!=="0"&&$.replay().catch(e=>console.warn("[gateway] guest replay failed:",e.message)),{ports:G,routes:R,services:P,stop:o(async()=>{if(!v){v=!0,clearInterval(Ee),clearInterval(me),ie.stop(),m.emit("info","gateway down","cluster-gateway",{kind:"gateway-down",project:"gateway"}),W.stop(),$?.close(),I?.flush(),(0,workspace_registry_1.unregisterWorkspace)(E);for(const e of P)A.killSpawned(e,"gateway shutdown");A.stopRetiringTrees(),await A.stopBuildHost(),await A.finishDyingTrees(),await O.reapAll(),ae.closeTunnels(),await Promise.all(J.map(e=>new Promise(n=>{let w=!1;const u=o(()=>{w||(w=!0,n())},"done"),S=e;e.close(()=>u());try{S.closeIdleConnections?.()}catch{}setTimeout(()=>{try{S.closeAllConnections?.()}catch{}u()},types_1.GATEWAY_STOP_GRACE_MS).unref?.()}))),H.closeProxy(),H.destroyAgents(),D.dispose(),(0,workspace_log_1.closeWorkspaceLogs)(),l()}},"stop"),...g.lensSupervisor?{lensSupervisor:g.lensSupervisor}:{},...g.graphStores?{graphStores:g.graphStores}:{}}}T(startGateway,"startGateway"),o(startGateway,"startGateway");
@@ -563,6 +563,16 @@ export declare const POD_ROLL_READY_MS: number;
563
563
  * `0` removes the cap. Default 2.
564
564
  */
565
565
  export declare const POD_MAX_CONCURRENT_ROLLS: number;
566
+ /**
567
+ * How long a service tree told to stop (SIGTERM to its process group) has before what is left of the group is
568
+ * SIGKILLed (issues/closed/foodguard-93). A tree's own shutdown takes under a second; an executor that ignores the
569
+ * signal — nx's run-executor under a serve executor that only stopped its devserver — never ends, and lived for two days
570
+ * at 0.6 GB. Override `LENSMCP_TREE_KILL_GRACE_MS`; `0` sends SIGTERM only. Default 10 s.
571
+ */
572
+ export declare const TREE_KILL_GRACE_MS: number;
573
+ /** How often the sweep looks for orphaned service executors (orphan-reaper.ts); the first look is the first sweep.
574
+ * Override `LENSMCP_ORPHAN_REAP_MS`; `0` turns the reaper off. Default 5 min. */
575
+ export declare const ORPHAN_REAP_EVERY_MS: number;
566
576
  /**
567
577
  * How many services may COLD START at once, daemon-wide — every workspace's and every worktree instance's
568
578
  * together. A cold start is a whole `serve-hmr` tree and a cold webpack compile; a page that touches a dozen lazy
@@ -1 +1 @@
1
- "use strict";var O=Object.defineProperty;var e=(_,E)=>O(_,"name",{value:E,configurable:!0});var M=Object.defineProperty,R=e((_,E)=>M(_,"name",{value:E,configurable:!0}),"R");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_H2_RESET_RATE=exports.GATEWAY_H2_RESET_BURST=exports.BODY_STALL_MS=exports.GATEWAY_CONN_CHECK_MS=exports.GATEWAY_MAX_CONNECTIONS=exports.GATEWAY_STOP_GRACE_MS=exports.GATEWAY_HEADERS_TIMEOUT_MS=exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=exports.LENS_REQUEST_RECOVERY_WAIT_MS=exports.LENS_REPLACEMENT_DRAIN_MS=exports.LENS_REPLACEMENT_READY_MS=exports.LENS_RESTART_MODE=exports.LENS_RECYCLE_KILL_GRACE_MS=exports.LENS_PARKED_PORT_REPROBE_MS=exports.MAX_PORT_CONFLICT_RETRIES=exports.CHILD_START_FAIL_MS=exports.PORT_FREE_POLL_MS=exports.PORT_FREE_WAIT_MS=exports.LENS_PROBE_BOOT_GRACE_MS=exports.LENS_PROBE_COOLDOWN_MS=exports.LENS_PROBE_TIMEOUT_MS=exports.LENS_PROBE_FAILS=exports.LENS_PROBE_GRACE_MS=exports.MAX_COLD_STARTS=exports.POD_MAX_CONCURRENT_ROLLS=exports.POD_ROLL_READY_MS=exports.POD_RECYCLE_MODE=exports.POD_WATCHER_SILENT=exports.POD_WATCHER_UNVERIFIED=exports.LENS_WATCH_SCOPE_ENABLED=exports.LENS_WATCHER_UNVERIFIED=exports.LENS_WATCHER_PROBE_ENABLED=exports.LENS_PROBE_ENABLED=exports.POD_STALE_RECYCLE_COOLDOWN_MS=exports.POD_STALE_SCAN_MS=exports.POD_RECYCLE_SETTLE_MS=exports.POD_STALE_GRACE_MS=exports.POD_MAX_AGE_MS=exports.POD_RECYCLE_ENABLED=exports.WEDGE_RECYCLE_GRACE_MS=exports.POD_ALIVE_PATH=exports.POD_WEDGE_CONFIRM_MS=exports.POD_ALIVE_PROBE_TIMEOUT_MS=exports.POD_SLOW_FIRST_BYTE_MS=exports.POD_RESPONSE_TIMEOUT_MS=exports.UPSTREAM_HEAL_STEP_MS=exports.UPSTREAM_HEAL_WINDOW_MS=exports.SERVICE_RESTART_WINDOW_MS=exports.SERVICE_MAX_RESTARTS=exports.SERVICE_ERROR_THROTTLE_MS=void 0;const tslib_1=require("tslib"),os=tslib_1.__importStar(require("node:os"));function envInt(_,E,L=!1){const S=Number(process.env[_]);return!Number.isFinite(S)||S<0?E:S===0?L?0:E:S}e(envInt,"envInt"),R(envInt,"envInt"),exports.SERVICE_ERROR_THROTTLE_MS=5e3,exports.SERVICE_MAX_RESTARTS=5,exports.SERVICE_RESTART_WINDOW_MS=6e4,exports.UPSTREAM_HEAL_WINDOW_MS=8e3,exports.UPSTREAM_HEAL_STEP_MS=300,exports.POD_RESPONSE_TIMEOUT_MS=(()=>{const _=Number(process.env.LENSMCP_POD_RESPONSE_TIMEOUT_MS);return Number.isFinite(_)&&_>0?_:3e4})(),exports.POD_SLOW_FIRST_BYTE_MS=envInt("LENSMCP_POD_SLOW_FIRST_BYTE_MS",10*6e4,!0),exports.POD_ALIVE_PROBE_TIMEOUT_MS=envInt("LENSMCP_POD_ALIVE_PROBE_TIMEOUT_MS",1e3),exports.POD_WEDGE_CONFIRM_MS=envInt("LENSMCP_POD_WEDGE_CONFIRM_MS",1e4,!0),exports.POD_ALIVE_PATH="/__lensmcp/alive",exports.WEDGE_RECYCLE_GRACE_MS=(()=>{const _=Number(process.env.LENSMCP_WEDGE_RECYCLE_GRACE_MS);return Number.isFinite(_)&&_>0?_:15e3})(),exports.POD_RECYCLE_ENABLED=process.env.LENSMCP_POD_RECYCLE!=="0",exports.POD_MAX_AGE_MS=envInt("LENSMCP_POD_MAX_AGE_MS",240*6e4,!0),exports.POD_STALE_GRACE_MS=envInt("LENSMCP_POD_STALE_GRACE_MS",1e4),exports.POD_RECYCLE_SETTLE_MS=envInt("LENSMCP_POD_RECYCLE_SETTLE_MS",8e3),exports.POD_STALE_SCAN_MS=envInt("LENSMCP_POD_STALE_SCAN_MS",3e4),exports.POD_STALE_RECYCLE_COOLDOWN_MS=envInt("LENSMCP_POD_STALE_RECYCLE_COOLDOWN_MS",6e4),exports.LENS_PROBE_ENABLED=process.env.LENSMCP_LENS_PROBE!=="0",exports.LENS_WATCHER_PROBE_ENABLED=process.env.LENSMCP_LENS_WATCHER_PROBE!=="0",exports.LENS_WATCHER_UNVERIFIED=process.env.LENSMCP_LENS_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.LENS_WATCH_SCOPE_ENABLED=process.env.LENSMCP_LENS_WATCH_SCOPE!=="0",exports.POD_WATCHER_UNVERIFIED=process.env.LENSMCP_POD_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.POD_WATCHER_SILENT=process.env.LENSMCP_POD_WATCHER_SILENT==="recycle"?"recycle":"keep",exports.POD_RECYCLE_MODE=process.env.LENSMCP_POD_RECYCLE_MODE==="in-place"?"in-place":"rolling",exports.POD_ROLL_READY_MS=envInt("LENSMCP_POD_ROLL_READY_MS",18e4),exports.POD_MAX_CONCURRENT_ROLLS=envInt("LENSMCP_POD_MAX_CONCURRENT_ROLLS",2,!0),exports.MAX_COLD_STARTS=envInt("LENSMCP_MAX_COLD_STARTS",Math.max(2,Math.floor(os.availableParallelism()/2)),!0),exports.LENS_PROBE_GRACE_MS=envInt("LENSMCP_LENS_PROBE_GRACE_MS",45e3),exports.LENS_PROBE_FAILS=envInt("LENSMCP_LENS_PROBE_FAILS",2),exports.LENS_PROBE_TIMEOUT_MS=envInt("LENSMCP_LENS_PROBE_TIMEOUT_MS",1e3),exports.LENS_PROBE_COOLDOWN_MS=envInt("LENSMCP_LENS_PROBE_COOLDOWN_MS",3e4),exports.LENS_PROBE_BOOT_GRACE_MS=envInt("LENSMCP_LENS_PROBE_BOOT_GRACE_MS",24e4),exports.PORT_FREE_WAIT_MS=envInt("LENSMCP_PORT_FREE_WAIT_MS",1e4),exports.PORT_FREE_POLL_MS=envInt("LENSMCP_PORT_FREE_POLL_MS",250),exports.CHILD_START_FAIL_MS=envInt("LENSMCP_CHILD_START_FAIL_MS",1e4),exports.MAX_PORT_CONFLICT_RETRIES=envInt("LENSMCP_MAX_PORT_CONFLICT_RETRIES",5),exports.LENS_PARKED_PORT_REPROBE_MS=envInt("LENSMCP_PARKED_PORT_REPROBE_MS",3e5),exports.LENS_RECYCLE_KILL_GRACE_MS=envInt("LENSMCP_RECYCLE_KILL_GRACE_MS",5e3),exports.LENS_RESTART_MODE=process.env.LENSMCP_LENS_RESTART_MODE==="in-place"?"in-place":"rolling",exports.LENS_REPLACEMENT_READY_MS=envInt("LENSMCP_LENS_REPLACEMENT_READY_MS",3e4),exports.LENS_REPLACEMENT_DRAIN_MS=envInt("LENSMCP_LENS_REPLACEMENT_DRAIN_MS",2e3,!0),exports.LENS_REQUEST_RECOVERY_WAIT_MS=envInt("LENSMCP_LENS_REQUEST_RECOVERY_WAIT_MS",15e3),exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=envInt("LENSMCP_KEEPALIVE_TIMEOUT_MS",76e3),exports.GATEWAY_HEADERS_TIMEOUT_MS=envInt("LENSMCP_HEADERS_TIMEOUT_MS",6e4),exports.GATEWAY_STOP_GRACE_MS=envInt("LENSMCP_STOP_GRACE_MS",3e3),exports.GATEWAY_MAX_CONNECTIONS=envInt("LENSMCP_MAX_CONNECTIONS",0,!0),exports.GATEWAY_CONN_CHECK_MS=envInt("LENSMCP_CONN_CHECK_MS",0,!0),exports.BODY_STALL_MS=envInt("LENSMCP_BODY_STALL_MS",6e4,!0),exports.GATEWAY_H2_RESET_BURST=envInt("LENSMCP_H2_RESET_BURST",1e5),exports.GATEWAY_H2_RESET_RATE=envInt("LENSMCP_H2_RESET_RATE",1e4);
1
+ "use strict";var O=Object.defineProperty;var e=(_,E)=>O(_,"name",{value:E,configurable:!0});var M=Object.defineProperty,R=e((_,E)=>M(_,"name",{value:E,configurable:!0}),"R");Object.defineProperty(exports,"__esModule",{value:!0}),exports.BODY_STALL_MS=exports.GATEWAY_CONN_CHECK_MS=exports.GATEWAY_MAX_CONNECTIONS=exports.GATEWAY_STOP_GRACE_MS=exports.GATEWAY_HEADERS_TIMEOUT_MS=exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=exports.LENS_REQUEST_RECOVERY_WAIT_MS=exports.LENS_REPLACEMENT_DRAIN_MS=exports.LENS_REPLACEMENT_READY_MS=exports.LENS_RESTART_MODE=exports.LENS_RECYCLE_KILL_GRACE_MS=exports.LENS_PARKED_PORT_REPROBE_MS=exports.MAX_PORT_CONFLICT_RETRIES=exports.CHILD_START_FAIL_MS=exports.PORT_FREE_POLL_MS=exports.PORT_FREE_WAIT_MS=exports.LENS_PROBE_BOOT_GRACE_MS=exports.LENS_PROBE_COOLDOWN_MS=exports.LENS_PROBE_TIMEOUT_MS=exports.LENS_PROBE_FAILS=exports.LENS_PROBE_GRACE_MS=exports.MAX_COLD_STARTS=exports.ORPHAN_REAP_EVERY_MS=exports.TREE_KILL_GRACE_MS=exports.POD_MAX_CONCURRENT_ROLLS=exports.POD_ROLL_READY_MS=exports.POD_RECYCLE_MODE=exports.POD_WATCHER_SILENT=exports.POD_WATCHER_UNVERIFIED=exports.LENS_WATCH_SCOPE_ENABLED=exports.LENS_WATCHER_UNVERIFIED=exports.LENS_WATCHER_PROBE_ENABLED=exports.LENS_PROBE_ENABLED=exports.POD_STALE_RECYCLE_COOLDOWN_MS=exports.POD_STALE_SCAN_MS=exports.POD_RECYCLE_SETTLE_MS=exports.POD_STALE_GRACE_MS=exports.POD_MAX_AGE_MS=exports.POD_RECYCLE_ENABLED=exports.WEDGE_RECYCLE_GRACE_MS=exports.POD_ALIVE_PATH=exports.POD_WEDGE_CONFIRM_MS=exports.POD_ALIVE_PROBE_TIMEOUT_MS=exports.POD_SLOW_FIRST_BYTE_MS=exports.POD_RESPONSE_TIMEOUT_MS=exports.UPSTREAM_HEAL_STEP_MS=exports.UPSTREAM_HEAL_WINDOW_MS=exports.SERVICE_RESTART_WINDOW_MS=exports.SERVICE_MAX_RESTARTS=exports.SERVICE_ERROR_THROTTLE_MS=void 0,exports.GATEWAY_H2_RESET_RATE=exports.GATEWAY_H2_RESET_BURST=void 0;const tslib_1=require("tslib"),os=tslib_1.__importStar(require("node:os"));function envInt(_,E,L=!1){const S=Number(process.env[_]);return!Number.isFinite(S)||S<0?E:S===0?L?0:E:S}e(envInt,"envInt"),R(envInt,"envInt"),exports.SERVICE_ERROR_THROTTLE_MS=5e3,exports.SERVICE_MAX_RESTARTS=5,exports.SERVICE_RESTART_WINDOW_MS=6e4,exports.UPSTREAM_HEAL_WINDOW_MS=8e3,exports.UPSTREAM_HEAL_STEP_MS=300,exports.POD_RESPONSE_TIMEOUT_MS=(()=>{const _=Number(process.env.LENSMCP_POD_RESPONSE_TIMEOUT_MS);return Number.isFinite(_)&&_>0?_:3e4})(),exports.POD_SLOW_FIRST_BYTE_MS=envInt("LENSMCP_POD_SLOW_FIRST_BYTE_MS",10*6e4,!0),exports.POD_ALIVE_PROBE_TIMEOUT_MS=envInt("LENSMCP_POD_ALIVE_PROBE_TIMEOUT_MS",1e3),exports.POD_WEDGE_CONFIRM_MS=envInt("LENSMCP_POD_WEDGE_CONFIRM_MS",1e4,!0),exports.POD_ALIVE_PATH="/__lensmcp/alive",exports.WEDGE_RECYCLE_GRACE_MS=(()=>{const _=Number(process.env.LENSMCP_WEDGE_RECYCLE_GRACE_MS);return Number.isFinite(_)&&_>0?_:15e3})(),exports.POD_RECYCLE_ENABLED=process.env.LENSMCP_POD_RECYCLE!=="0",exports.POD_MAX_AGE_MS=envInt("LENSMCP_POD_MAX_AGE_MS",240*6e4,!0),exports.POD_STALE_GRACE_MS=envInt("LENSMCP_POD_STALE_GRACE_MS",1e4),exports.POD_RECYCLE_SETTLE_MS=envInt("LENSMCP_POD_RECYCLE_SETTLE_MS",8e3),exports.POD_STALE_SCAN_MS=envInt("LENSMCP_POD_STALE_SCAN_MS",3e4),exports.POD_STALE_RECYCLE_COOLDOWN_MS=envInt("LENSMCP_POD_STALE_RECYCLE_COOLDOWN_MS",6e4),exports.LENS_PROBE_ENABLED=process.env.LENSMCP_LENS_PROBE!=="0",exports.LENS_WATCHER_PROBE_ENABLED=process.env.LENSMCP_LENS_WATCHER_PROBE!=="0",exports.LENS_WATCHER_UNVERIFIED=process.env.LENSMCP_LENS_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.LENS_WATCH_SCOPE_ENABLED=process.env.LENSMCP_LENS_WATCH_SCOPE!=="0",exports.POD_WATCHER_UNVERIFIED=process.env.LENSMCP_POD_WATCHER_UNVERIFIED==="keep"?"keep":"recycle",exports.POD_WATCHER_SILENT=process.env.LENSMCP_POD_WATCHER_SILENT==="recycle"?"recycle":"keep",exports.POD_RECYCLE_MODE=process.env.LENSMCP_POD_RECYCLE_MODE==="in-place"?"in-place":"rolling",exports.POD_ROLL_READY_MS=envInt("LENSMCP_POD_ROLL_READY_MS",18e4),exports.POD_MAX_CONCURRENT_ROLLS=envInt("LENSMCP_POD_MAX_CONCURRENT_ROLLS",2,!0),exports.TREE_KILL_GRACE_MS=envInt("LENSMCP_TREE_KILL_GRACE_MS",1e4,!0),exports.ORPHAN_REAP_EVERY_MS=envInt("LENSMCP_ORPHAN_REAP_MS",3e5,!0),exports.MAX_COLD_STARTS=envInt("LENSMCP_MAX_COLD_STARTS",Math.max(2,Math.floor(os.availableParallelism()/2)),!0),exports.LENS_PROBE_GRACE_MS=envInt("LENSMCP_LENS_PROBE_GRACE_MS",45e3),exports.LENS_PROBE_FAILS=envInt("LENSMCP_LENS_PROBE_FAILS",2),exports.LENS_PROBE_TIMEOUT_MS=envInt("LENSMCP_LENS_PROBE_TIMEOUT_MS",1e3),exports.LENS_PROBE_COOLDOWN_MS=envInt("LENSMCP_LENS_PROBE_COOLDOWN_MS",3e4),exports.LENS_PROBE_BOOT_GRACE_MS=envInt("LENSMCP_LENS_PROBE_BOOT_GRACE_MS",24e4),exports.PORT_FREE_WAIT_MS=envInt("LENSMCP_PORT_FREE_WAIT_MS",1e4),exports.PORT_FREE_POLL_MS=envInt("LENSMCP_PORT_FREE_POLL_MS",250),exports.CHILD_START_FAIL_MS=envInt("LENSMCP_CHILD_START_FAIL_MS",1e4),exports.MAX_PORT_CONFLICT_RETRIES=envInt("LENSMCP_MAX_PORT_CONFLICT_RETRIES",5),exports.LENS_PARKED_PORT_REPROBE_MS=envInt("LENSMCP_PARKED_PORT_REPROBE_MS",3e5),exports.LENS_RECYCLE_KILL_GRACE_MS=envInt("LENSMCP_RECYCLE_KILL_GRACE_MS",5e3),exports.LENS_RESTART_MODE=process.env.LENSMCP_LENS_RESTART_MODE==="in-place"?"in-place":"rolling",exports.LENS_REPLACEMENT_READY_MS=envInt("LENSMCP_LENS_REPLACEMENT_READY_MS",3e4),exports.LENS_REPLACEMENT_DRAIN_MS=envInt("LENSMCP_LENS_REPLACEMENT_DRAIN_MS",2e3,!0),exports.LENS_REQUEST_RECOVERY_WAIT_MS=envInt("LENSMCP_LENS_REQUEST_RECOVERY_WAIT_MS",15e3),exports.GATEWAY_KEEPALIVE_TIMEOUT_MS=envInt("LENSMCP_KEEPALIVE_TIMEOUT_MS",76e3),exports.GATEWAY_HEADERS_TIMEOUT_MS=envInt("LENSMCP_HEADERS_TIMEOUT_MS",6e4),exports.GATEWAY_STOP_GRACE_MS=envInt("LENSMCP_STOP_GRACE_MS",3e3),exports.GATEWAY_MAX_CONNECTIONS=envInt("LENSMCP_MAX_CONNECTIONS",0,!0),exports.GATEWAY_CONN_CHECK_MS=envInt("LENSMCP_CONN_CHECK_MS",0,!0),exports.BODY_STALL_MS=envInt("LENSMCP_BODY_STALL_MS",6e4,!0),exports.GATEWAY_H2_RESET_BURST=envInt("LENSMCP_H2_RESET_BURST",1e5),exports.GATEWAY_H2_RESET_RATE=envInt("LENSMCP_H2_RESET_RATE",1e4);
@@ -1 +1 @@
1
- "use strict";var ie=Object.defineProperty;var c=(e,t)=>ie(e,"name",{value:t,configurable:!0});var se=Object.defineProperty,o=c((e,t)=>se(e,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0});const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),node_child_process_1=require("node:child_process"),yaml=tslib_1.__importStar(require("js-yaml")),child_process_env_1=require("../../child-process-env"),dev_devtool_1=require("../../dev-devtool"),devserver_notifier_1=require("../../devserver-notifier"),process_name_1=require("../../process-name"),worker_supervisor_1=require("../../worker-supervisor"),attach_1=require("../../shared-build/attach");function definedEnv(e){const t={};for(const[_,i]of Object.entries(e))typeof i=="string"&&(t[_]=i);return t}c(definedEnv,"definedEnv"),o(definedEnv,"definedEnv");const frozen=o(()=>process.env.LENSMCP_FREEZE==="1","frozen");async function*serveExecutor(e,t){process.env.NODE_ENV="development";const _=t.projectsConfigurations.projects[t.projectName],i=t.root,g=path.join(i,_.root),U=e.outputPath?path.join(i,e.outputPath):path.join(i,"dist",_.root),B=e.configEnv||"development",R=path.join(i,"config",`config.${B}.yaml`),$=3050;let d=$,a=t.projectName,S={};fs.existsSync(R)?(S=yaml.load(fs.readFileSync(R,"utf8")),d=Number(S.port)||d,a=S.serviceName||a):console.warn(`[serve] ${t.projectName}: no config file at ${R} \u2014 public devserver port defaults to ${$}. If another service also lacks its config, both bind ${$} \u2192 EADDRINUSE. Add config/config.${B}.yaml with a distinct \`port:\` (matching this project's cluster.port).`),e.serviceName&&(a=e.serviceName);const T=e.servePrefix??"",h=e.debugPort??(Number(process.env.LENSMCP_DEBUG_PORT)||void 0),z=/^(1|true|yes|on)$/i.test((process.env.LENSMCP_DEBUG_FIXED_PORTS??"").trim()),p=e.logFile?path.resolve(i,e.logFile):process.env.LENSMCP_LOG_FILE||void 0;if(p){fs.mkdirSync(path.dirname(p),{recursive:!0}),fs.writeFileSync(p,"",{mode:384});try{fs.chmodSync(p,384)}catch{}}let k,D;e.gateway?.middleware&&(k=path.resolve(g,e.gateway.middleware),D=JSON.stringify(S));const K=e.entryFile||"./src/deployments/service/main.ts",Q=e.tsConfigFile||"./tsconfig.app.json",Z=path.resolve(g,K),q=path.resolve(g,Q),ee=(e.workers||[]).map(r=>({entryName:r.name,entryPath:path.resolve(g,r.entryPath)})),W={appName:t.projectName,appRoot:g,outputDir:U,main:Z,tsConfig:q,assets:e.assets||[],additionalEntryPoints:ee,port:d,serviceName:a,memoryLimit:e.memoryLimit||8192,buildLibsFromSource:e.buildLibsFromSource!==!1,workspaceRoot:i,orgScopes:e.orgScopes||[],bundlePackages:e.bundlePackages||[],nodeExternalsConfig:e.nodeExternalsConfig,webpackConfigPath:e.webpackConfigPath,httpsReload:e.gateway?.https===!0,...e.devtool!==void 0&&{devtool:e.devtool}};let l=null,O=!1,I=!1,m=!1;const V=path.join(__dirname,"../../main.devserver.js"),H=path.join(__dirname,"../../main.devserver.ts"),Y=!fs.existsSync(V)&&fs.existsSync(H),x=Y?H:V,oe=path.join(U,"main.js");function A(){l&&!l.killed&&(l.kill("SIGTERM"),l=null)}c(A,"H"),o(A,"cleanup");function N(){m=!0,A()}c(N,"O"),o(N,"stop");const re=["SIGINT","SIGTERM","SIGHUP","SIGQUIT"].map(r=>{const n=o(()=>N(),"handler");return process.on(r,n),{sig:r,handler:n}});process.on("exit",N);function E(){if(m)return;if(!fs.existsSync(x)){console.error(`[serve] devserver script not found at ${x}`);return}const r=["--enable-source-maps"];Y&&r.unshift("--require","@swc-node/register");const n=(0,node_child_process_1.fork)(x,{cwd:i,env:(0,child_process_env_1.childProcessEnv)({...process.env,PORT:String(d),SERVICE_NAME:a,SERVE_PREFIX:T,LENSMCP_PROJECT:process.env.LENSMCP_PROJECT||t.projectName||a,LENSMCP_EVENT_FILE:process.env.LENSMCP_EVENT_FILE||path.join(i,".lensmcp","events.jsonl"),CHILD_COUNT:String(e.childCount||process.env.CHILD_COUNT||1),BUNDLE_PATH:oe,...k&&{GATEWAY_MIDDLEWARE:k},...D&&{GATEWAY_CONFIG:D},...e.gateway?.routes?.length&&{GATEWAY_ROUTES:JSON.stringify(e.gateway.routes)},...e.gateway?.https&&{GATEWAY_HTTPS:"1"},...e.gateway?.extraPorts?.length&&{GATEWAY_EXTRA_PORTS:JSON.stringify(e.gateway.extraPorts)},...e.internalPort&&{INTERNAL_PORT:String(e.internalPort)},...h&&{LENSMCP_DEBUG_PORT:String(h)},...p&&{LENSMCP_LOG_FILE:p},...e.workers?.length&&{WORKERS:(0,worker_supervisor_1.serializeWorkerSpecs)(e.workers)},[dev_devtool_1.DEV_SOURCE_MAPS_ENV]:I?"1":"0"}),stdio:["inherit","inherit","inherit","ipc"],execArgv:r,execPath:(0,process_name_1.namedExecPath)((0,process_name_1.processName)(process.env.LENSMCP_WS_KEY||path.basename(i),a,"dev"))});l=n,n.on("exit",(u,f)=>{l===n&&(l=null),!(f||u===0||m)&&(console.error(`[serve] devserver exited unexpectedly (code=${u}, signal=${f}) \u2014 respawning in 1.5s`),setTimeout(()=>{!m&&!l&&O&&E()},1500).unref?.())}),console.log(`[serve] Devserver started on port ${d} (service: ${a}${T?`, prefix: /${T}`:""})`),h?(console.warn(`[serve] DEBUGGER ENABLED for ${a}. Node's inspector has NO authentication \u2014 the ws:// UUID is the whole credential, and any account on this host that obtains it runs code as you. Do not enable this on a shared machine.`),z?console.warn(`[serve] LENSMCP_DEBUG_FIXED_PORTS=1 \u2014 pod inspectors bind PREDICTABLE ports 127.0.0.1:${h}+slot (workers ${h}+20+i), reachable by any account on this host. Attach WebStorm (Attach to Node.js/Chrome) to ${h}. Unset it to bind ephemeral ports instead.`):console.log(`[serve] Debug: pod inspectors bind an EPHEMERAL 127.0.0.1 port. Get the ws:// URLs with \`lensmcp debug ${a}\` (the owner-only control socket); a devserver run in your own terminal also prints them there. Set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs a fixed attach port.`)):console.log(`[serve] Debug on demand: \`lensmcp debug ${a}\` opens pod inspectors without a restart`),p&&console.log(`[serve] Logs teed to ${p} \u2014 tail it in WebStorm via Run/Debug configuration \u2192 Logs tab`)}c(E,"_"),o(E,"startDevServer");function te(){if(!l||l.killed){console.log("[serve] Devserver not running, restarting..."),E();return}fetch(`http://localhost:${d}/webpack/reload`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}).then(()=>console.log("[serve] Notified devserver to reload")).catch(r=>{console.warn("[serve] Failed to notify devserver, restarting...",r.message),A(),E()})}c(te,"ne"),o(te,"_notifyDevServerReload");let w=null;const M=[];function v(r){if(w){const n=w;w=null,n(r)}else M.push(r)}c(v,"h"),o(v,"pushResult");function J(){return M.length>0?Promise.resolve(M.shift()):new Promise(r=>{w=r})}c(J,"ee"),o(J,"waitForNext");let y=o(()=>{},"closeBuild");function F(){return!O||!l?(O=!0,E(),!0):!1}c(F,"J"),o(F,"builtOk");function b(){if(m)return;const{createDevWebpackConfig:r}=require("../../create-webpack-dev"),n=require("webpack"),u=r(W),{watch:f,...P}=u,s=n(P);I=(0,dev_devtool_1.bundleCarriesSourceMaps)(s.options.devtool);const j=o((L,C)=>{if(L){console.error("[serve] Webpack error:",L),v({success:!1});return}const ne=C.hasErrors();if(console.info(C.toString({colors:!0,chunks:!1,assets:!0})),ne){v({success:!1});return}F(),v({success:!0,baseUrl:`http://localhost:${d}`})},"onBuild");if(frozen()){console.log(`[serve] ${t.projectName}: frozen \u2014 compiling once, no file watcher`),s.run((L,C)=>{j(L,C),s.close(()=>{})});return}const G=s.watch(u.watchOptions||{},j);y=o(()=>G.close(()=>{}),"closeBuild")}c(b,"A"),o(b,"compileOnItsOwn");function X(r){const n=r.accepted.projects.filter(s=>s!==t.projectName);console.log(`[serve] ${t.projectName}: compiled by the workspace's shared compilation ${r.accepted.group.slice(0,8)}${n.length?` with ${n.join(", ")}`:""} \u2014 no webpack in this process`);const u=new devserver_notifier_1.DevserverNotifier(d,e.gateway?.https===!0,(0,devserver_notifier_1.devserverControlSock)(a)),f=(0,attach_1.createAttachedTypecheck)({appName:t.projectName,tsConfig:q,workspaceRoot:i,memoryLimit:e.memoryLimit||8192});let P;y=o(()=>{r.close(),f.dispose()},"closeBuild"),r.listen(s=>{if(!m)switch(s.type){case"watch-run":u.watchRun(s.paths);return;case"watch-closed":u.degrade("watch closed");return;case"failed":console.error(`[serve] the shared compiler failed: ${s.message}`),u.degrade(`compiler failed: ${s.message}`),v({success:!1});return;case"refused":console.log(`[serve] ${t.projectName}: compiling on its own from now on \u2014 ${s.reason}`),y(),b();return;case"built":{if(console.info(s.text),I=s.sourceMaps,f.built(s),!s.ok){u.failed(),v({success:!1});return}const j=s.hash!==P;P=s.hash;const G=F();u.built(j&&!G),v({success:!0,baseUrl:`http://localhost:${d}`});return}default:return}})}if(c(X,"re"),o(X,"attachToSharedBuild"),(0,attach_1.sharedBuildOffered)()&&!frozen()){const r=await(0,attach_1.joinSharedBuild)({project:t.projectName,target:t.targetName??"serve-hmr",...t.configurationName?{configuration:t.configurationName}:{},options:W,targetOptions:{...e},env:definedEnv(process.env)});r.kind==="attached"?X(r.session):(console.log(`[serve] ${t.projectName}: compiling on its own \u2014 ${r.reason}`),b())}else b();try{for(;;)yield await J()}finally{N(),y(),re.forEach(({sig:r,handler:n})=>process.removeListener(r,n))}}c(serveExecutor,"serveExecutor"),o(serveExecutor,"serveExecutor"),exports.default=serveExecutor,module.exports=serveExecutor,module.exports.default=serveExecutor;
1
+ "use strict";var le=Object.defineProperty;var i=(e,o)=>le(e,"name",{value:o,configurable:!0});var ie=Object.defineProperty,s=i((e,o)=>ie(e,"name",{value:o,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0});const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),node_child_process_1=require("node:child_process"),yaml=tslib_1.__importStar(require("js-yaml")),child_process_env_1=require("../../child-process-env"),dev_devtool_1=require("../../dev-devtool"),devserver_notifier_1=require("../../devserver-notifier"),process_name_1=require("../../process-name"),worker_supervisor_1=require("../../worker-supervisor"),attach_1=require("../../shared-build/attach"),stop_on_signal_1=require("./stop-on-signal"),compile_retry_1=require("../../compile-retry");function definedEnv(e){const o={};for(const[w,n]of Object.entries(e))typeof n=="string"&&(o[w]=n);return o}i(definedEnv,"definedEnv"),s(definedEnv,"definedEnv");const frozen=s(()=>process.env.LENSMCP_FREEZE==="1","frozen");async function*serveExecutor(e,o){process.env.NODE_ENV="development";const w=o.projectsConfigurations.projects[o.projectName],n=o.root,E=path.join(n,w.root),G=e.outputPath?path.join(n,e.outputPath):path.join(n,"dist",w.root),q=e.configEnv||"development",k=path.join(n,"config",`config.${q}.yaml`),C=3050;let d=C,a=o.projectName,S={};fs.existsSync(k)?(S=yaml.load(fs.readFileSync(k,"utf8")),d=Number(S.port)||d,a=S.serviceName||a):console.warn(`[serve] ${o.projectName}: no config file at ${k} \u2014 public devserver port defaults to ${C}. If another service also lacks its config, both bind ${C} \u2192 EADDRINUSE. Add config/config.${q}.yaml with a distinct \`port:\` (matching this project's cluster.port).`),e.serviceName&&(a=e.serviceName);const O=e.servePrefix??"",f=e.debugPort??(Number(process.env.LENSMCP_DEBUG_PORT)||void 0),K=/^(1|true|yes|on)$/i.test((process.env.LENSMCP_DEBUG_FIXED_PORTS??"").trim()),p=e.logFile?path.resolve(n,e.logFile):process.env.LENSMCP_LOG_FILE||void 0;if(p){fs.mkdirSync(path.dirname(p),{recursive:!0}),fs.writeFileSync(p,"",{mode:384});try{fs.chmodSync(p,384)}catch{}}let D,T;e.gateway?.middleware&&(D=path.resolve(E,e.gateway.middleware),T=JSON.stringify(S));const Z=e.entryFile||"./src/deployments/service/main.ts",Q=e.tsConfigFile||"./tsconfig.app.json",ee=path.resolve(E,Z),B=path.resolve(E,Q),oe=(e.workers||[]).map(t=>({entryName:t.name,entryPath:path.resolve(E,t.entryPath)})),W={appName:o.projectName,appRoot:E,outputDir:G,main:ee,tsConfig:B,assets:e.assets||[],additionalEntryPoints:oe,port:d,serviceName:a,memoryLimit:e.memoryLimit||8192,buildLibsFromSource:e.buildLibsFromSource!==!1,workspaceRoot:n,orgScopes:e.orgScopes||[],bundlePackages:e.bundlePackages||[],nodeExternalsConfig:e.nodeExternalsConfig,webpackConfigPath:e.webpackConfigPath,httpsReload:e.gateway?.https===!0,...e.devtool!==void 0&&{devtool:e.devtool}};let c=null,x=!1,A=!1,v=!1;const V=path.join(__dirname,"../../main.devserver.js"),Y=path.join(__dirname,"../../main.devserver.ts"),H=!fs.existsSync(V)&&fs.existsSync(Y),M=H?Y:V,te=path.join(G,"main.js");function F(){c&&!c.killed&&(c.kill("SIGTERM"),c=null)}i(F,"H"),s(F,"cleanup");function P(){v=!0,F()}i(P,"F"),s(P,"stop");const re=(0,stop_on_signal_1.stopOnSignal)({stop:P,close:s(()=>y(),"close")});process.on("exit",P);function _(){if(v)return;if(!fs.existsSync(M)){console.error(`[serve] devserver script not found at ${M}`);return}const t=["--enable-source-maps"];H&&t.unshift("--require","@swc-node/register");const u=(0,node_child_process_1.fork)(M,{cwd:n,env:(0,child_process_env_1.childProcessEnv)({...process.env,PORT:String(d),SERVICE_NAME:a,SERVE_PREFIX:O,LENSMCP_PROJECT:process.env.LENSMCP_PROJECT||o.projectName||a,LENSMCP_EVENT_FILE:process.env.LENSMCP_EVENT_FILE||path.join(n,".lensmcp","events.jsonl"),CHILD_COUNT:String(e.childCount||process.env.CHILD_COUNT||1),BUNDLE_PATH:te,...D&&{GATEWAY_MIDDLEWARE:D},...T&&{GATEWAY_CONFIG:T},...e.gateway?.routes?.length&&{GATEWAY_ROUTES:JSON.stringify(e.gateway.routes)},...e.gateway?.https&&{GATEWAY_HTTPS:"1"},...e.gateway?.extraPorts?.length&&{GATEWAY_EXTRA_PORTS:JSON.stringify(e.gateway.extraPorts)},...e.internalPort&&{INTERNAL_PORT:String(e.internalPort)},...f&&{LENSMCP_DEBUG_PORT:String(f)},...p&&{LENSMCP_LOG_FILE:p},...e.workers?.length&&{WORKERS:(0,worker_supervisor_1.serializeWorkerSpecs)(e.workers)},[dev_devtool_1.DEV_SOURCE_MAPS_ENV]:A?"1":"0"}),stdio:["inherit","inherit","inherit","ipc"],execArgv:t,execPath:(0,process_name_1.namedExecPath)((0,process_name_1.processName)(process.env.LENSMCP_WS_KEY||path.basename(n),a,"dev"))});c=u,u.on("exit",(l,g)=>{c===u&&(c=null),!(g||l===0||v)&&(console.error(`[serve] devserver exited unexpectedly (code=${l}, signal=${g}) \u2014 respawning in 1.5s`),setTimeout(()=>{!v&&!c&&x&&_()},1500).unref?.())}),console.log(`[serve] Devserver started on port ${d} (service: ${a}${O?`, prefix: /${O}`:""})`),f?(console.warn(`[serve] DEBUGGER ENABLED for ${a}. Node's inspector has NO authentication \u2014 the ws:// UUID is the whole credential, and any account on this host that obtains it runs code as you. Do not enable this on a shared machine.`),K?console.warn(`[serve] LENSMCP_DEBUG_FIXED_PORTS=1 \u2014 pod inspectors bind PREDICTABLE ports 127.0.0.1:${f}+slot (workers ${f}+20+i), reachable by any account on this host. Attach WebStorm (Attach to Node.js/Chrome) to ${f}. Unset it to bind ephemeral ports instead.`):console.log(`[serve] Debug: pod inspectors bind an EPHEMERAL 127.0.0.1 port. Get the ws:// URLs with \`lensmcp debug ${a}\` (the owner-only control socket); a devserver run in your own terminal also prints them there. Set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs a fixed attach port.`)):console.log(`[serve] Debug on demand: \`lensmcp debug ${a}\` opens pod inspectors without a restart`),p&&console.log(`[serve] Logs teed to ${p} \u2014 tail it in WebStorm via Run/Debug configuration \u2192 Logs tab`)}i(_,"w"),s(_,"startDevServer");function se(){if(!c||c.killed){console.log("[serve] Devserver not running, restarting..."),_();return}fetch(`http://localhost:${d}/webpack/reload`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}).then(()=>console.log("[serve] Notified devserver to reload")).catch(t=>{console.warn("[serve] Failed to notify devserver, restarting...",t.message),F(),_()})}i(se,"ce"),s(se,"_notifyDevServerReload");let b=null;const I=[];function h(t){if(b){const u=b;b=null,u(t)}else I.push(t)}i(h,"v"),s(h,"pushResult");function J(){return I.length>0?Promise.resolve(I.shift()):new Promise(t=>{b=t})}i(J,"re"),s(J,"waitForNext");let y=s(()=>{},"closeBuild");function U(){return!x||!c?(x=!0,_(),!0):!1}i(U,"J"),s(U,"builtOk");function j(){if(v)return;const{createDevWebpackConfig:t}=require("../../create-webpack-dev"),u=require("webpack"),l=t(W),{watch:g,...$}=l,r=u($);A=(0,dev_devtool_1.bundleCarriesSourceMaps)(r.options.devtool);let m;const N=(0,compile_retry_1.createFailureRetry)(()=>{v||!m||(console.log(`[serve] ${o.projectName}: compiling again after the failure`),m.invalidate())}),z=s((L,R)=>{if(L){if(console.error("[serve] Webpack error:",L),m&&!v){const{delayMs:ae,retry:ce}=N.failed();console.log(`[serve] ${o.projectName}: compiling again in ${Math.round(ae/1e3)} s (retry ${ce}) \u2014 webpack does not after a failure like this`)}h({success:!1});return}N.succeeded();const ne=R.hasErrors();if(console.info(R.toString({colors:!0,chunks:!1,assets:!0})),ne){h({success:!1});return}U(),h({success:!0,baseUrl:`http://localhost:${d}`})},"onBuild");if(frozen()){console.log(`[serve] ${o.projectName}: frozen \u2014 compiling once, no file watcher`),r.run((L,R)=>{z(L,R),r.close(()=>{})});return}m=r.watch(l.watchOptions||{},z),y=s(()=>{N.dispose(),m.close(()=>{})},"closeBuild")}i(j,"M"),s(j,"compileOnItsOwn");function X(t){const u=t.accepted.projects.filter(r=>r!==o.projectName);console.log(`[serve] ${o.projectName}: compiled by the workspace's shared compilation ${t.accepted.group.slice(0,8)}${u.length?` with ${u.join(", ")}`:""} \u2014 no webpack in this process`);const l=new devserver_notifier_1.DevserverNotifier(d,e.gateway?.https===!0,(0,devserver_notifier_1.devserverControlSock)(a)),g=(0,attach_1.createAttachedTypecheck)({appName:o.projectName,tsConfig:B,workspaceRoot:n,memoryLimit:e.memoryLimit||8192});let $;y=s(()=>{t.close(),g.dispose()},"closeBuild"),t.listen(r=>{if(!v)switch(r.type){case"watch-run":l.watchRun(r.paths);return;case"watch-closed":l.degrade("watch closed");return;case"failed":console.error(`[serve] the shared compiler failed: ${r.message}`),l.failed(`the shared compiler failed: ${r.message}`),h({success:!1});return;case"refused":console.log(`[serve] ${o.projectName}: compiling on its own from now on \u2014 ${r.reason}`),y(),j();return;case"built":{if(console.info(r.text),A=r.sourceMaps,g.built(r),!r.ok){l.failed(),h({success:!1});return}const m=r.hash!==$;$=r.hash;const N=U();l.built(m&&!N),h({success:!0,baseUrl:`http://localhost:${d}`});return}default:return}})}if(i(X,"te"),s(X,"attachToSharedBuild"),(0,attach_1.sharedBuildOffered)()&&!frozen()){const t=await(0,attach_1.joinSharedBuild)({project:o.projectName,target:o.targetName??"serve-hmr",...o.configurationName?{configuration:o.configurationName}:{},options:W,targetOptions:{...e},env:definedEnv(process.env)});t.kind==="attached"?X(t.session):(console.log(`[serve] ${o.projectName}: compiling on its own \u2014 ${t.reason}`),j())}else j();try{for(;;)yield await J()}finally{P(),y(),re()}}i(serveExecutor,"serveExecutor"),s(serveExecutor,"serveExecutor"),exports.default=serveExecutor,module.exports=serveExecutor,module.exports.default=serveExecutor;
@@ -0,0 +1,19 @@
1
+ export declare const STOP_SIGNALS: readonly ["SIGINT", "SIGTERM", "SIGHUP", "SIGQUIT"];
2
+ /** The process the handlers are installed on — `process` unless a spec hands a stand-in. */
3
+ export interface StoppableProcess {
4
+ on(event: string, listener: (...args: unknown[]) => void): unknown;
5
+ removeListener(event: string, listener: (...args: unknown[]) => void): unknown;
6
+ exit(code: number): void;
7
+ /** Present when the process has an IPC channel to its parent: then losing it is a stop. */
8
+ send?: unknown;
9
+ }
10
+ export interface StopOnSignalOptions {
11
+ /** Stop for good: no devserver is started again (serve.impl `stop`). */
12
+ stop(): void;
13
+ /** Close whatever builds the service — its watcher, or its membership of the shared compilation. */
14
+ close(): void;
15
+ proc?: StoppableProcess;
16
+ log?: (line: string) => void;
17
+ }
18
+ /** Install the handlers; the returned function removes them (the executor's generator returned on its own). */
19
+ export declare function stopOnSignal(opts: StopOnSignalOptions): () => void;
@@ -0,0 +1 @@
1
+ "use strict";var S=Object.defineProperty;var c=(r,n)=>S(r,"name",{value:n,configurable:!0});var l=Object.defineProperty,o=c((r,n)=>l(r,"name",{value:n,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.STOP_SIGNALS=void 0,exports.stopOnSignal=stopOnSignal;const serve_runner_1=require("../../serve-runner");exports.STOP_SIGNALS=["SIGINT","SIGTERM","SIGHUP","SIGQUIT"];function stopOnSignal(r){const n=r.proc??process,a=r.log??(e=>console.log(e));let s=!1;const i=o(e=>{if(r.stop(),!s){s=!0;try{r.close()}catch{}setImmediate(()=>n.exit((0,serve_runner_1.exitCodeForSignal)(e)))}},"end"),p=exports.STOP_SIGNALS.map(e=>{const t=o(()=>i(e),"handler");return n.on(e,t),{event:e,handler:t}});if(typeof n.send=="function"){const e=o(()=>{s||(a("[serve] the parent process is gone (its IPC channel closed) \u2014 stopping the service"),i("SIGTERM"))},"onDisconnect");n.on("disconnect",e),p.push({event:"disconnect",handler:e})}return()=>{for(const{event:e,handler:t}of p)n.removeListener(e,t)}}c(stopOnSignal,"stopOnSignal"),o(stopOnSignal,"stopOnSignal");