@lensmcp/cluster 1.20.1 → 1.21.1

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.
@@ -15,6 +15,19 @@ export interface ControlServer {
15
15
  socketPath: string;
16
16
  close: () => void;
17
17
  }
18
+ /**
19
+ * The @lensmcp/cluster version THIS daemon is executing — stamped into `/status` so a consumer
20
+ * (the CLI's `gateway status`, `lensmcp upgrade`) can PROVE the running daemon is behind the
21
+ * workspace's node_modules. Without it an upgraded workspace has no way to tell that :443 is
22
+ * still serving last month's code: the process was started before the install and keeps its
23
+ * loaded bundle forever (same failure mode as the embedded MCP server, measured at 2+ days).
24
+ *
25
+ * Walks up from this file to the nearest package.json NAMED `@lensmcp/cluster` — the
26
+ * published layout (`<pkg>/executors/gateway/runtime/control.js`) and the source tree
27
+ * (`libs/cluster/src/...`) both resolve their own manifest; an un-prepared dist layout
28
+ * resolves nothing and reports nothing — absent means "cannot vouch", never a guess.
29
+ */
30
+ export declare function clusterVersion(): string | undefined;
18
31
  /** Start the control listener. The socket is loopback-only (a filesystem socket), so no IP allow-listing
19
32
  * is needed — anything that can open it is already on this machine as this user. */
20
33
  export declare function startControlServer(deps: ControlServerDeps): ControlServer;
@@ -1 +1 @@
1
- "use strict";var v=Object.defineProperty;var d=(o,r)=>v(o,"name",{value:r,configurable:!0});var w=Object.defineProperty,y=d((o,r)=>w(o,"name",{value:r,configurable:!0}),"y");Object.defineProperty(exports,"__esModule",{value:!0}),exports.controlSocketPath=controlSocketPath,exports.startControlServer=startControlServer;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery");function controlSocketPath(){const o=process.env.LENSMCP_HOME||os.homedir();return path.join(o,".lensmcp","control.sock")}d(controlSocketPath,"controlSocketPath"),y(controlSocketPath,"controlSocketPath");function readJsonBody(o){return new Promise((r,c)=>{let s="";o.on("data",u=>{s+=u,s.length>1e6&&c(new Error("body too large"))}),o.on("end",()=>{try{r(s?JSON.parse(s):{})}catch(u){c(u)}}),o.on("error",c)})}d(readJsonBody,"readJsonBody"),y(readJsonBody,"readJsonBody");function startControlServer(o){const{rt:r}=o,c=controlSocketPath();fs.mkdirSync(path.dirname(c),{recursive:!0});try{fs.unlinkSync(c)}catch{}const s=y((n,i,a)=>{n.writeHead(i,{"content-type":"application/json"}),n.end(JSON.stringify(a))},"send"),u=http.createServer((n,i)=>{(async()=>{try{const a=(n.url??"").split("?")[0];if(n.method==="GET"&&a==="/list")return s(i,200,{workspaces:r.registry.keys().map(e=>{const t=r.registry.get(e);return{key:e,root:t?.root,routes:t?.routes.length??0,services:t?.services.length??0}})});if(n.method==="GET"&&a==="/status")return s(i,200,{daemon:{pid:process.pid,wsKey:r.wsKey},workspaces:r.registry.keys().map(e=>{const t=r.registry.get(e);return{key:e,root:t?.root,routes:t?.routes.length??0,services:t?.services.length??0,isDaemon:e===r.wsKey}}),services:r.registry.allServices().map(e=>({project:e.project,wsKey:e.wsKey,host:e.decl.host,state:e.state}))});if(n.method==="POST"&&a==="/register"){const e=await readJsonBody(n);if(!e.wsKey||!e.root)return s(i,400,{error:"wsKey and root are required"});const t=e.projects??{},l=(0,discovery_1.projectSourceRoots)(e.root,t,e.projectDependencies),{routes:p,services:g}=(0,discovery_1.discoverRoutes)(e.root,t,void 0,e.wsKey,l),h={wsKey:e.wsKey,root:e.root,routes:p,services:g};return r.registry.register(h),await o.onRegister?.(h),r.rebuildRoutes(),s(i,200,{ok:!0,wsKey:e.wsKey,routes:p.length,services:g.length,workspaces:r.registry.keys()})}if(n.method==="POST"&&a==="/unregister"){const e=await readJsonBody(n);if(!e.wsKey)return s(i,400,{error:"wsKey is required"});const t=r.registry.unregister(e.wsKey);if(t){for(const l of t.services)o.killService(l,"workspace unregistered");o.onUnregister?.(t)}return r.rebuildRoutes(),s(i,200,{ok:!0,removed:!!t,workspaces:r.registry.keys()})}s(i,404,{error:"not found"})}catch(a){s(i,500,{error:a.message})}})()});return u.listen(c),{socketPath:c,close:y(()=>{u.close();try{fs.unlinkSync(c)}catch{}},"close")}}d(startControlServer,"startControlServer"),y(startControlServer,"startControlServer");
1
+ "use strict";var h=Object.defineProperty;var d=(t,e)=>h(t,"name",{value:e,configurable:!0});var f=Object.defineProperty,y=d((t,e)=>f(t,"name",{value:e,configurable:!0}),"y");Object.defineProperty(exports,"__esModule",{value:!0}),exports.controlSocketPath=controlSocketPath,exports.clusterVersion=clusterVersion,exports.startControlServer=startControlServer;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery");function controlSocketPath(){const t=process.env.LENSMCP_HOME||os.homedir();return path.join(t,".lensmcp","control.sock")}d(controlSocketPath,"controlSocketPath"),y(controlSocketPath,"controlSocketPath");function clusterVersion(){let t=__dirname;for(let e=0;e<6;e++){const n=path.join(t,"package.json");if(fs.existsSync(n))try{const i=JSON.parse(fs.readFileSync(n,"utf8"));if(i.name==="@lensmcp/cluster"&&typeof i.version=="string")return i.version}catch{}const o=path.dirname(t);if(o===t)break;t=o}}d(clusterVersion,"clusterVersion"),y(clusterVersion,"clusterVersion");function readJsonBody(t){return new Promise((e,n)=>{let o="";t.on("data",i=>{o+=i,o.length>1e6&&n(new Error("body too large"))}),t.on("end",()=>{try{e(o?JSON.parse(o):{})}catch(i){n(i)}}),t.on("error",n)})}d(readJsonBody,"readJsonBody"),y(readJsonBody,"readJsonBody");function startControlServer(t){const{rt:e}=t,n=controlSocketPath();fs.mkdirSync(path.dirname(n),{recursive:!0});try{fs.unlinkSync(n)}catch{}const o=y((c,a,u)=>{c.writeHead(a,{"content-type":"application/json"}),c.end(JSON.stringify(u))},"send"),i=http.createServer((c,a)=>{(async()=>{try{const u=(c.url??"").split("?")[0];if(c.method==="GET"&&u==="/list")return o(a,200,{workspaces:e.registry.keys().map(s=>{const r=e.registry.get(s);return{key:s,root:r?.root,routes:r?.routes.length??0,services:r?.services.length??0}})});if(c.method==="GET"&&u==="/status"){const s=clusterVersion();return o(a,200,{daemon:{pid:process.pid,wsKey:e.wsKey,...s?{version:s}:{}},workspaces:e.registry.keys().map(r=>{const l=e.registry.get(r);return{key:r,root:l?.root,routes:l?.routes.length??0,services:l?.services.length??0,isDaemon:r===e.wsKey}}),services:e.registry.allServices().map(r=>({project:r.project,wsKey:r.wsKey,host:r.decl.host,state:r.state}))})}if(c.method==="POST"&&u==="/register"){const s=await readJsonBody(c);if(!s.wsKey||!s.root)return o(a,400,{error:"wsKey and root are required"});const r=s.projects??{},l=(0,discovery_1.projectSourceRoots)(s.root,r,s.projectDependencies),{routes:p,services:g}=(0,discovery_1.discoverRoutes)(s.root,r,void 0,s.wsKey,l),v={wsKey:s.wsKey,root:s.root,routes:p,services:g};return e.registry.register(v),await t.onRegister?.(v),e.rebuildRoutes(),o(a,200,{ok:!0,wsKey:s.wsKey,routes:p.length,services:g.length,workspaces:e.registry.keys()})}if(c.method==="POST"&&u==="/unregister"){const s=await readJsonBody(c);if(!s.wsKey)return o(a,400,{error:"wsKey is required"});const r=e.registry.unregister(s.wsKey);if(r){for(const l of r.services)t.killService(l,"workspace unregistered");t.onUnregister?.(r)}return e.rebuildRoutes(),o(a,200,{ok:!0,removed:!!r,workspaces:e.registry.keys()})}o(a,404,{error:"not found"})}catch(u){o(a,500,{error:u.message})}})()});return i.listen(n),{socketPath:n,close:y(()=>{i.close();try{fs.unlinkSync(n)}catch{}},"close")}}d(startControlServer,"startControlServer"),y(startControlServer,"startControlServer");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/cluster",
3
- "version": "1.20.1",
3
+ "version": "1.21.1",
4
4
  "description": "Run your Nx workspace as a local production cluster: pods on unix sockets with true HMR, one https gateway with per-project domains, scale-from-zero, autoscale, idle-kill, local-CA TLS — observed by the LensMCP lens.",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -29,8 +29,6 @@
29
29
  "@nx/devkit": ">=20.0.0",
30
30
  "@nx/webpack": ">=20.0.0",
31
31
  "webpack": "^5.0.0",
32
- "fastify": "^5.0.0",
33
- "@fastify/reply-from": "^12.0.0",
34
32
  "ioredis": "^5.0.0",
35
33
  "@opentelemetry/api": "^1.9.0",
36
34
  "@opentelemetry/core": "^2.9.0",
@@ -39,12 +37,6 @@
39
37
  "@opentelemetry/exporter-trace-otlp-http": "^0.220.0"
40
38
  },
41
39
  "peerDependenciesMeta": {
42
- "fastify": {
43
- "optional": true
44
- },
45
- "@fastify/reply-from": {
46
- "optional": true
47
- },
48
40
  "ioredis": {
49
41
  "optional": true
50
42
  },
@@ -65,9 +57,11 @@
65
57
  }
66
58
  },
67
59
  "dependencies": {
68
- "@lensmcp/core": "1.20.1",
69
- "@lensmcp/node-instrumentation": "1.20.1",
70
- "@lensmcp/nx-plugin": "1.20.1",
60
+ "@lensmcp/core": "1.21.1",
61
+ "@lensmcp/node-instrumentation": "1.21.1",
62
+ "@lensmcp/nx-plugin": "1.21.1",
63
+ "fastify": "^5.0.0",
64
+ "@fastify/reply-from": "^12.0.0",
71
65
  "@typescript/native-preview": "^7.0.0-dev.20260707.2",
72
66
  "fork-ts-checker-webpack-plugin": "^9.0.0",
73
67
  "glob": "^11.0.0",