@lensmcp/cluster 1.16.28 → 1.16.29

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 +1 @@
1
- {"version":3,"file":"lens-children.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/lens-children.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAuB,MAAM,SAAS,CAAC;AAQ1F,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAM7E;;;;8CAI8C;AAC9C,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5D;AAED,MAAM,WAAW,YAAY;IAC3B,iBAAiB,EAAE,UAAU,CAAC;IAC9B;;gFAE4E;IAC5E,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC;;6GAEyG;IACzG,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;IACvF;;yGAEqG;IACrG,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;IACpE;gHAC4G;IAC5G,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,EAClB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,qBAAqB,EAE9B,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,GACzD,YAAY,CAgWd"}
1
+ {"version":3,"file":"lens-children.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/lens-children.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,kCAAkC,CAAC;AAI1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAuB,MAAM,SAAS,CAAC;AAQ1F,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAM7E;;;;8CAI8C;AAC9C,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5D;AAED,MAAM,WAAW,YAAY;IAC3B,iBAAiB,EAAE,UAAU,CAAC;IAC9B;;gFAE4E;IAC5E,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC;;6GAEyG;IACzG,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;IACvF;;yGAEqG;IACrG,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;IACpE;gHAC4G;IAC5G,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,EAClB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,qBAAqB,EAE9B,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,GACzD,YAAY,CAmWd"}
@@ -13,6 +13,7 @@ const net = tslib_1.__importStar(require("node:net"));
13
13
  const path = tslib_1.__importStar(require("node:path"));
14
14
  const node_child_process_1 = require("node:child_process");
15
15
  const lens_frontend_1 = require("@lensmcp/nx-plugin/lens-frontend");
16
+ const pod_env_1 = require("./pod-env");
16
17
  const scope_1 = require("./scope");
17
18
  const workspace_registry_1 = require("./workspace-registry");
18
19
  const lifecycle_1 = require("./lifecycle");
@@ -91,7 +92,10 @@ deps) {
91
92
  // their ports for the next gateway to route into.
92
93
  const child = (0, node_child_process_1.spawn)(bin, args, {
93
94
  cwd: cwd ?? rt.root,
94
- env: { ...process.env, ...(env ?? {}), LENSMCP_PARENT_PID: String(process.pid) },
95
+ // FOREIGN-POD ENV SCRUB (pod-env.ts): a registered workspace's vite/child runs in ITS root and must
96
+ // not inherit the daemon host's dotenv-loaded env (vite, like nx, keeps an already-set var over the
97
+ // workspace's own .env) — the caller's explicit `env` overlay still applies on top.
98
+ env: { ...(0, pod_env_1.podBaseEnv)(process.env, rt.root, cwd ?? rt.root), ...(env ?? {}), LENSMCP_PARENT_PID: String(process.pid) },
95
99
  stdio: 'inherit',
96
100
  });
97
101
  lensChildren.push(child);
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/lifecycle.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAapE,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,iBAAiB,CAAC;AA8C/D;;sGAEsG;AACtG,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBtE;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,oBAAoB,CAAC,EACpG,GAAG,EAAE,MAAM,EACX,kBAAkB,EAAE,MAAM,EAC1B,GAAG,EAAE,gBAAgB,GACpB,kBAAkB,GAAG,SAAS,GAAG,IAAI,CAQvC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,kBAAkB,EAAE,MAAM,EAC1B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC7D,OAAO,CAMT;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAChC,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,2EAA2E;IAC3E,YAAY,IAAI,MAAM,CAAC,OAAO,CAAC;CAChC;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAwXvF"}
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/lifecycle.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAapE,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,iBAAiB,CAAC;AA8C/D;;sGAEsG;AACtG,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBtE;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,oBAAoB,CAAC,EACpG,GAAG,EAAE,MAAM,EACX,kBAAkB,EAAE,MAAM,EAC1B,GAAG,EAAE,gBAAgB,GACpB,kBAAkB,GAAG,SAAS,GAAG,IAAI,CAQvC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,kBAAkB,EAAE,MAAM,EAC1B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC7D,OAAO,CAMT;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAChC,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,2EAA2E;IAC3E,YAAY,IAAI,MAAM,CAAC,OAAO,CAAC;CAChC;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CA4XvF"}
@@ -15,6 +15,7 @@ const fs = tslib_1.__importStar(require("node:fs"));
15
15
  const http = tslib_1.__importStar(require("node:http"));
16
16
  const path = tslib_1.__importStar(require("node:path"));
17
17
  const discovery_1 = require("./discovery");
18
+ const pod_env_1 = require("./pod-env");
18
19
  const types_1 = require("./types");
19
20
  /**
20
21
  * The east-west env a pod needs to call ANOTHER service's `internal.<host>` route (memberships, settings,
@@ -248,7 +249,11 @@ function createServiceLayer(rt, obs) {
248
249
  // so its dashboard shows its live traces, not the daemon's. The daemon's own services keep rt.eventFile
249
250
  // exactly (svc.root === rt.root), so single-workspace behavior is unchanged.
250
251
  env: {
251
- ...process.env,
252
+ // FOREIGN-POD ENV SCRUB (pod-env.ts): a registered workspace's pod must NOT inherit the daemon
253
+ // host's dotenv-loaded env (nx never overrides an already-set var, so foodguard's PG_URL/REDIS_URL
254
+ // riding the daemon once pointed tetros's auth+iam at foodguard's stores). The daemon's own
255
+ // workspace keeps the full inherit — its pods reload the same files anyway.
256
+ ...(0, pod_env_1.podBaseEnv)(process.env, rt.root, svc.root),
252
257
  NX_DAEMON: 'false',
253
258
  // NX_ISOLATE_PLUGINS=false: with the daemon off (above), EVERY serve client builds the
254
259
  // project graph itself — and with plugin isolation on (nx's default) each client spawns
@@ -0,0 +1,24 @@
1
+ /** The root-level dotenv files nx (and vite) auto-load for any invocation at a workspace root. */
2
+ export declare const WORKSPACE_DOTENV_FILES: readonly [".env", ".env.local", ".local.env"];
3
+ /**
4
+ * Data-store pointers that must never cross a workspace boundary, even when they arrived in the daemon's
5
+ * env some way other than the host's dotenv (an exported shell var at gateway start). Belt-and-suspenders
6
+ * under the dotenv-derived scrub — kept to the class that caused the incident.
7
+ */
8
+ export declare const FOREIGN_POD_ENV_DENYLIST: readonly ["PG_URL", "REDIS_URL", "DATABASE_URL", "POSTGRES_URL"];
9
+ /**
10
+ * The keys a dotenv file DECLARES — assignment lines only (`KEY=…`, optional `export ` prefix), comments
11
+ * and malformed lines ignored. We only need the key names (what to scrub), never the values.
12
+ */
13
+ export declare function parseDotenvKeys(content: string): Set<string>;
14
+ /** Every key declared across a workspace root's dotenv files (missing/unreadable files contribute nothing). */
15
+ export declare function workspaceDotenvKeys(root: string): Set<string>;
16
+ /** PURE scrub: a copy of `base` without the given keys nor the store-pointer denylist. Never mutates `base`. */
17
+ export declare function scrubEnv(base: NodeJS.ProcessEnv, hostKeys: ReadonlySet<string>): NodeJS.ProcessEnv;
18
+ /**
19
+ * The spawn-base env for a child of `childRoot` under a daemon hosted at `hostRoot`: the daemon's own
20
+ * workspace inherits untouched; a foreign workspace gets the scrubbed copy (the child's own nx/vite dotenv
21
+ * load then supplies THAT workspace's values, which is the whole point).
22
+ */
23
+ export declare function podBaseEnv(base: NodeJS.ProcessEnv, hostRoot: string, childRoot: string): NodeJS.ProcessEnv;
24
+ //# sourceMappingURL=pod-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pod-env.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/pod-env.ts"],"names":[],"mappings":"AAoBA,kGAAkG;AAClG,eAAO,MAAM,sBAAsB,+CAAgD,CAAC;AAEpF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,kEAAmE,CAAC;AAEzG;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAS5D;AAED,+GAA+G;AAC/G,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAY7D;AAED,gHAAgH;AAChH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,CAQlG;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,CAG1G"}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FOREIGN_POD_ENV_DENYLIST = exports.WORKSPACE_DOTENV_FILES = void 0;
4
+ exports.parseDotenvKeys = parseDotenvKeys;
5
+ exports.workspaceDotenvKeys = workspaceDotenvKeys;
6
+ exports.scrubEnv = scrubEnv;
7
+ exports.podBaseEnv = podBaseEnv;
8
+ const tslib_1 = require("tslib");
9
+ /**
10
+ * FOREIGN-POD ENV SCRUB (the cross-workspace store bleed, foodguard↔tetros 2026-07-26).
11
+ *
12
+ * `nx run gateway:serve` auto-loads the DAEMON workspace's root dotenv (`.env`, `.env.local`) into the
13
+ * daemon's own process env, and the spawn sites' `...process.env` handed that to EVERY child — including a
14
+ * REGISTERED (foreign) workspace's pods. nx's dotenv load in the child never overrides an already-set var,
15
+ * so the daemon host's values beat the foreign workspace's own `.env.local`: with the daemon hosted from
16
+ * foodguard (whose root `.env.local` declares `PG_URL`/`REDIS_URL`), tetros's auth+iam pods booted onto
17
+ * foodguard's Postgres/Valkey — foodguard tenants rendered inside the tetros app, and tetros's boot seed
18
+ * wrote rows into foodguard's database.
19
+ *
20
+ * The rule: a FOREIGN workspace's pod gets the inherited env MINUS (every key the daemon workspace's root
21
+ * dotenv files declare ∪ a hard denylist of data-store pointers). The daemon's OWN workspace pods keep the
22
+ * full inherit — their nx/vite reload the exact same files at spawn (so the scrub would change nothing),
23
+ * and a deliberate shell override (`PG_URL=… lensmcp gateway start`) staying live for one's own pods is
24
+ * ordinary env semantics. Hosting order must never matter for anyone else's pods.
25
+ */
26
+ const fs = tslib_1.__importStar(require("node:fs"));
27
+ const path = tslib_1.__importStar(require("node:path"));
28
+ /** The root-level dotenv files nx (and vite) auto-load for any invocation at a workspace root. */
29
+ exports.WORKSPACE_DOTENV_FILES = ['.env', '.env.local', '.local.env'];
30
+ /**
31
+ * Data-store pointers that must never cross a workspace boundary, even when they arrived in the daemon's
32
+ * env some way other than the host's dotenv (an exported shell var at gateway start). Belt-and-suspenders
33
+ * under the dotenv-derived scrub — kept to the class that caused the incident.
34
+ */
35
+ exports.FOREIGN_POD_ENV_DENYLIST = ['PG_URL', 'REDIS_URL', 'DATABASE_URL', 'POSTGRES_URL'];
36
+ /**
37
+ * The keys a dotenv file DECLARES — assignment lines only (`KEY=…`, optional `export ` prefix), comments
38
+ * and malformed lines ignored. We only need the key names (what to scrub), never the values.
39
+ */
40
+ function parseDotenvKeys(content) {
41
+ const keys = new Set();
42
+ for (const raw of content.split('\n')) {
43
+ const line = raw.trim();
44
+ if (!line || line.startsWith('#'))
45
+ continue;
46
+ const m = line.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/);
47
+ if (m)
48
+ keys.add(m[1]);
49
+ }
50
+ return keys;
51
+ }
52
+ /** Every key declared across a workspace root's dotenv files (missing/unreadable files contribute nothing). */
53
+ function workspaceDotenvKeys(root) {
54
+ const keys = new Set();
55
+ for (const file of exports.WORKSPACE_DOTENV_FILES) {
56
+ let content;
57
+ try {
58
+ content = fs.readFileSync(path.join(root, file), 'utf8');
59
+ }
60
+ catch {
61
+ continue;
62
+ }
63
+ for (const k of parseDotenvKeys(content))
64
+ keys.add(k);
65
+ }
66
+ return keys;
67
+ }
68
+ /** PURE scrub: a copy of `base` without the given keys nor the store-pointer denylist. Never mutates `base`. */
69
+ function scrubEnv(base, hostKeys) {
70
+ const out = {};
71
+ for (const [k, v] of Object.entries(base)) {
72
+ if (hostKeys.has(k))
73
+ continue;
74
+ if (exports.FOREIGN_POD_ENV_DENYLIST.includes(k))
75
+ continue;
76
+ out[k] = v;
77
+ }
78
+ return out;
79
+ }
80
+ /**
81
+ * The spawn-base env for a child of `childRoot` under a daemon hosted at `hostRoot`: the daemon's own
82
+ * workspace inherits untouched; a foreign workspace gets the scrubbed copy (the child's own nx/vite dotenv
83
+ * load then supplies THAT workspace's values, which is the whole point).
84
+ */
85
+ function podBaseEnv(base, hostRoot, childRoot) {
86
+ if (path.resolve(childRoot) === path.resolve(hostRoot))
87
+ return base;
88
+ return scrubEnv(base, workspaceDotenvKeys(hostRoot));
89
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/cluster",
3
- "version": "1.16.28",
3
+ "version": "1.16.29",
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",
@@ -65,8 +65,8 @@
65
65
  }
66
66
  },
67
67
  "dependencies": {
68
- "@lensmcp/node-instrumentation": "1.16.28",
69
- "@lensmcp/nx-plugin": "1.16.28",
68
+ "@lensmcp/node-instrumentation": "1.16.29",
69
+ "@lensmcp/nx-plugin": "1.16.29",
70
70
  "fork-ts-checker-webpack-plugin": "^9.0.0",
71
71
  "glob": "^11.0.0",
72
72
  "http-proxy": "^1.18.0",