@lensmcp/cluster 1.18.4 → 1.18.6
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.
- package/basic-ssl.js +1 -241
- package/build-scope-patterns.js +1 -40
- package/create-webpack-dev.js +1 -186
- package/create-webpack-prod.js +1 -169
- package/executors/build/build.impl.js +1 -98
- package/executors/gateway/gateway-errors.js +1 -43
- package/executors/gateway/gateway.impl.js +1 -53
- package/executors/gateway/gateway.lib.js +1 -29
- package/executors/gateway/health-check.js +1 -66
- package/executors/gateway/jwks-verify.js +1 -121
- package/executors/gateway/main.prod-gateway.js +2 -573
- package/executors/gateway/main.rollout.js +11 -117
- package/executors/gateway/manifest.js +1 -374
- package/executors/gateway/metrics.js +1 -56
- package/executors/gateway/otel-tracing.js +1 -74
- package/executors/gateway/prod-gateway.lib.js +1 -22
- package/executors/gateway/prod-runtime/access-log.js +1 -24
- package/executors/gateway/prod-runtime/app.js +1 -123
- package/executors/gateway/prod-runtime/auth.js +1 -51
- package/executors/gateway/prod-runtime/cors.js +1 -40
- package/executors/gateway/prod-runtime/edge.js +1 -65
- package/executors/gateway/prod-runtime/handler.js +1 -226
- package/executors/gateway/prod-runtime/hooks.js +1 -42
- package/executors/gateway/prod-runtime/observability.js +1 -125
- package/executors/gateway/prod-runtime/rollout.js +1 -103
- package/executors/gateway/prod-runtime/routing.js +1 -40
- package/executors/gateway/prod-runtime/server.js +1 -79
- package/executors/gateway/prod-runtime/trust.js +1 -32
- package/executors/gateway/prod-runtime/types.js +1 -2
- package/executors/gateway/prod-runtime/upgrade.js +4 -116
- package/executors/gateway/prod-runtime/upstream.js +1 -21
- package/executors/gateway/providers-prod.js +1 -232
- package/executors/gateway/rate-limit.js +2 -75
- package/executors/gateway/registry-source.js +1 -131
- package/executors/gateway/rollout-ops.js +2 -167
- package/executors/gateway/runtime/auth.js +1 -64
- package/executors/gateway/runtime/chooser.js +12 -45
- package/executors/gateway/runtime/control.js +1 -128
- package/executors/gateway/runtime/dev-auth.js +1 -108
- package/executors/gateway/runtime/discovery.js +1 -123
- package/executors/gateway/runtime/edge.js +1 -47
- package/executors/gateway/runtime/handler.js +1 -183
- package/executors/gateway/runtime/hooks.js +1 -55
- package/executors/gateway/runtime/lens-children.js +1 -651
- package/executors/gateway/runtime/lifecycle.js +3 -842
- package/executors/gateway/runtime/observability.js +2 -148
- package/executors/gateway/runtime/pod-env.js +2 -89
- package/executors/gateway/runtime/proxy.js +1 -457
- package/executors/gateway/runtime/route-registry.js +1 -72
- package/executors/gateway/runtime/scope.js +1 -117
- package/executors/gateway/runtime/server.js +3 -487
- package/executors/gateway/runtime/service-keys.js +1 -49
- package/executors/gateway/runtime/types.js +1 -151
- package/executors/gateway/runtime/upgrade.js +1 -71
- package/executors/gateway/runtime/workspace-registry.js +1 -99
- package/executors/gateway/ssrf-guard.js +1 -190
- package/executors/serve/serve.impl.js +1 -280
- package/executors/trust/trust.impl.js +4 -162
- package/gateway.js +1 -35
- package/index.js +1 -16
- package/main.devserver.js +10 -1117
- package/package.json +4 -3
- package/tsgo-check-plugin.js +4 -364
- package/typecheck-bus.js +4 -256
|
@@ -1,148 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.LENS_DASHBOARD_PROJECT = void 0;
|
|
4
|
-
exports.createObservability = createObservability;
|
|
5
|
-
const tslib_1 = require("tslib");
|
|
6
|
-
/**
|
|
7
|
-
* The observability layer: everything the gateway writes to the LensMCP bus.
|
|
8
|
-
* Bus (`emit`/`eid`), per-request mechanism trace (`beginTrace`/`traceStep`/
|
|
9
|
-
* `finishTrace`), and aggregated host→service traffic edges (`recordEdge` +
|
|
10
|
-
* `startEdgeFlusher`). Merged because they only ever vary together — trace and
|
|
11
|
-
* edges both emit; both need `eid`.
|
|
12
|
-
*
|
|
13
|
-
* Appends BaseEvent-shaped lines to the shared event file the MCP tails (same
|
|
14
|
-
* rendezvous the vite plugin and nest instrumentation use), so the lens sees
|
|
15
|
-
* the cluster itself: services up/down, cold starts, autoscale, idle kills, and
|
|
16
|
-
* aggregated traffic edges for the topology.
|
|
17
|
-
*/
|
|
18
|
-
const fs = tslib_1.__importStar(require("node:fs"));
|
|
19
|
-
const path = tslib_1.__importStar(require("node:path"));
|
|
20
|
-
const busHygiene = (() => {
|
|
21
|
-
try {
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
23
|
-
return require('@lensmcp/node-instrumentation');
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
})();
|
|
29
|
-
/**
|
|
30
|
-
* The lens's OWN dashboard route project (the value `lens-children.ts` gives the `lensmcp.local/<key>/`
|
|
31
|
-
* route). Traffic to it is the lens UI polling its own control-plane API (`/<key>/api/cluster|logs|snapshot`)
|
|
32
|
-
* ~1×/s — pure self-observation with NO app-diagnostic value. Its SUCCESSFUL request narration + traffic
|
|
33
|
-
* edges are suppressed from the bus (the same "don't bloat the bus" rationale as header-less traffic); a 5xx
|
|
34
|
-
* still surfaces so a genuine lens-dashboard failure isn't hidden. One home for the literal (imported by
|
|
35
|
-
* `lens-children.ts` for the route + this layer for the filter, so they can't drift).
|
|
36
|
-
*/
|
|
37
|
-
exports.LENS_DASHBOARD_PROJECT = '(lens-dashboard)';
|
|
38
|
-
const hdr = (v) => typeof v === 'string' && v !== '' ? v : Array.isArray(v) ? v[0] : undefined;
|
|
39
|
-
function createObservability(eventFile, opts) {
|
|
40
|
-
const eid = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 12);
|
|
41
|
-
// The gateway narrates OTHER apps' traffic — an app stuck in a retry loop must not turn that
|
|
42
|
-
// narration into a bus flood (2026-07-28: `gateway-request:<project>` alone wrote thousands of
|
|
43
|
-
// lines/min). Per-fingerprint token bucket: first burst passes, then a trickle carrying
|
|
44
|
-
// `floodSuppressed` counts. Errors stay loud — the burst re-arms once the storm subsides.
|
|
45
|
-
const floodGuard = busHygiene?.createEventFloodGuard({ burst: 30, perSec: 5 });
|
|
46
|
-
const emit = (severity, title, fingerprint, raw, flowCtx, busFile) => {
|
|
47
|
-
const target = busFile ?? eventFile; // a registered workspace's service events go to ITS bus, not the daemon's
|
|
48
|
-
try {
|
|
49
|
-
const admit = floodGuard ? floodGuard.admit(fingerprint) : { ok: true, suppressed: 0 };
|
|
50
|
-
if (!admit.ok)
|
|
51
|
-
return;
|
|
52
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
53
|
-
const line = JSON.stringify({
|
|
54
|
-
id: eid(), sessionId: 'pending', timestamp: Date.now(),
|
|
55
|
-
source: 'gateway', category: 'cluster', severity,
|
|
56
|
-
context: { sessionId: 'pending', ...flowCtx }, fingerprint, title,
|
|
57
|
-
raw: admit.suppressed > 0 ? { ...raw, floodSuppressed: admit.suppressed } : raw,
|
|
58
|
-
}) + '\n';
|
|
59
|
-
// The gateway was the one bus writer with NO size cap — enforce the same rotation contract
|
|
60
|
-
// as every other producer (emit.ts / capture-runner), per target file.
|
|
61
|
-
busHygiene?.maybeRotateEventFile(target, line.length);
|
|
62
|
-
fs.appendFileSync(target, line);
|
|
63
|
-
}
|
|
64
|
-
catch { /* lens offline — never block traffic */ }
|
|
65
|
-
};
|
|
66
|
-
// --- per-request mechanism trace (flows) ----------------------------------
|
|
67
|
-
// When a request carries lens flow headers (stamped by the browser client
|
|
68
|
-
// runtime or an instrumented upstream), the gateway narrates its own steps —
|
|
69
|
-
// received → route-match → auth → pod-select (+ cold-start) → response — as
|
|
70
|
-
// ONE `gateway-request` event correlated by the same flowId/requestId.
|
|
71
|
-
// Header-less traffic (curl, health checks) stays un-narrated so the bus
|
|
72
|
-
// doesn't bloat.
|
|
73
|
-
const beginTrace = (req) => {
|
|
74
|
-
const flowId = hdr(req.headers['x-lensmcp-flow-id']);
|
|
75
|
-
let requestId = hdr(req.headers['x-request-id']);
|
|
76
|
-
if (!flowId && !requestId && !hdr(req.headers['traceparent']))
|
|
77
|
-
return undefined;
|
|
78
|
-
if (!requestId) {
|
|
79
|
-
// Mint the request id AT THE EDGE and inject it downstream, so the
|
|
80
|
-
// gateway trace and the pod's server-request/spans share one id —
|
|
81
|
-
// that's the join key that attributes pod events to the routed service.
|
|
82
|
-
requestId = eid();
|
|
83
|
-
req.headers['x-request-id'] = requestId;
|
|
84
|
-
}
|
|
85
|
-
return {
|
|
86
|
-
startedAt: Date.now(),
|
|
87
|
-
method: (req.method ?? 'GET').toUpperCase(),
|
|
88
|
-
host: (req.headers.host || '').split(':')[0],
|
|
89
|
-
url: req.url ?? '/',
|
|
90
|
-
steps: [],
|
|
91
|
-
...(flowId ? { flowId } : {}),
|
|
92
|
-
...(requestId ? { requestId } : {}),
|
|
93
|
-
...(hdr(req.headers['x-lensmcp-origin-node-id']) ? { originNodeId: hdr(req.headers['x-lensmcp-origin-node-id']) } : {}),
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
|
-
const traceStep = (t, stepName, info) => {
|
|
97
|
-
if (!t)
|
|
98
|
-
return;
|
|
99
|
-
t.steps.push({ step: stepName, atMs: Date.now() - t.startedAt, ...info });
|
|
100
|
-
};
|
|
101
|
-
const finishTrace = (t, project, status, extra) => {
|
|
102
|
-
if (!t || t.done)
|
|
103
|
-
return;
|
|
104
|
-
t.done = true;
|
|
105
|
-
// The lens dashboard's own control-plane self-polling (1 req/s) would spam the bus with no
|
|
106
|
-
// app-diagnostic value — suppress its successful narration, but let a 5xx through (a real lens bug).
|
|
107
|
-
if (project === exports.LENS_DASHBOARD_PROJECT && status < 500)
|
|
108
|
-
return;
|
|
109
|
-
const durationMs = Date.now() - t.startedAt;
|
|
110
|
-
emit(status >= 500 ? 'error' : 'info', `gateway ${t.method} ${t.host}${t.url} → ${status} (${durationMs}ms)`, `gateway-request:${project}`, {
|
|
111
|
-
kind: 'gateway-request', project, host: t.host, method: t.method, url: t.url,
|
|
112
|
-
status, durationMs, startedAt: t.startedAt, steps: t.steps, ...extra,
|
|
113
|
-
}, {
|
|
114
|
-
...(t.flowId ? { flowId: t.flowId } : {}),
|
|
115
|
-
...(t.requestId ? { requestId: t.requestId } : {}),
|
|
116
|
-
...(t.originNodeId ? { originNodeId: t.originNodeId } : {}),
|
|
117
|
-
});
|
|
118
|
-
};
|
|
119
|
-
// --- aggregated host→service traffic edges --------------------------------
|
|
120
|
-
// The request-derived topology (nodes/edges appear from observed traffic).
|
|
121
|
-
const edges = new Map();
|
|
122
|
-
const recordEdge = (route, ms, status, caller) => {
|
|
123
|
-
// Don't accumulate a traffic edge for the lens dashboard's own self-polling (kills the
|
|
124
|
-
// `traffic lensmcp.local → (lens-dashboard)` spam); an error edge (5xx / connect-fail) still records.
|
|
125
|
-
if (route.project === exports.LENS_DASHBOARD_PROJECT && status < 500 && status !== 0)
|
|
126
|
-
return;
|
|
127
|
-
const host = route.host ?? '(default)';
|
|
128
|
-
const key = (caller ? caller + '⇒' : '') + host + '→' + route.project;
|
|
129
|
-
const e = edges.get(key) ?? { host, project: route.project, caller, count: 0, totalMs: 0, errors: 0 };
|
|
130
|
-
e.count += 1;
|
|
131
|
-
e.totalMs += ms;
|
|
132
|
-
if (status >= 500 || status === 0)
|
|
133
|
-
e.errors += 1;
|
|
134
|
-
edges.set(key, e);
|
|
135
|
-
};
|
|
136
|
-
const startEdgeFlusher = () => {
|
|
137
|
-
const t = setInterval(() => {
|
|
138
|
-
for (const e of edges.values()) {
|
|
139
|
-
const avgMs = Math.round(e.totalMs / e.count);
|
|
140
|
-
emit(e.errors ? 'warning' : 'info', `traffic ${e.host} → ${e.project}: ${e.count} req, ~${avgMs}ms${e.errors ? `, ${e.errors} errors` : ''}`, `gateway-traffic:${e.host}->${e.project}`, { kind: 'gateway-traffic', host: e.host, project: e.project, caller: e.caller, count: e.count, avgMs, errors: e.errors });
|
|
141
|
-
}
|
|
142
|
-
edges.clear();
|
|
143
|
-
}, opts.trafficFlushMs);
|
|
144
|
-
t.unref();
|
|
145
|
-
return t;
|
|
146
|
-
};
|
|
147
|
-
return { emit, eid, beginTrace, traceStep, finishTrace, recordEdge, startEdgeFlusher };
|
|
148
|
-
}
|
|
1
|
+
"use strict";var v=Object.defineProperty;var f=(o,d)=>v(o,"name",{value:d,configurable:!0});var _=Object.defineProperty,s=f((o,d)=>_(o,"name",{value:d,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.LENS_DASHBOARD_PROJECT=void 0,exports.createObservability=createObservability;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),redact_1=require("@lensmcp/core/redact"),busHygiene=(()=>{try{return require("@lensmcp/node-instrumentation")}catch{return}})();exports.LENS_DASHBOARD_PROJECT="(lens-dashboard)";const hdr=s(o=>typeof o=="string"&&o!==""?o:Array.isArray(o)?o[0]:void 0,"hdr");function createObservability(o,d){const p=s(()=>Date.now().toString(36)+Math.random().toString(36).slice(2,12),"eid"),g=busHygiene?.createEventFloodGuard({burst:30,perSec:5}),l=s((e,t,r,a,i,u)=>{const n=u??o;try{const h=g?g.admit(r):{ok:!0,suppressed:0};if(!h.ok)return;fs.mkdirSync(path.dirname(n),{recursive:!0});const m=a&&(0,redact_1.redactDeep)(a),y=JSON.stringify({id:p(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:e,context:(0,redact_1.redactDeep)({sessionId:"pending",...i}),fingerprint:r,title:(0,redact_1.safeTitle)(t),raw:h.suppressed>0?{...m,floodSuppressed:h.suppressed}:m})+`
|
|
2
|
+
`;busHygiene?.maybeRotateEventFile(n,y.length),fs.appendFileSync(n,y)}catch{}},"emit"),w=s(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=p(),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-origin-node-id"])?{originNodeId:hdr(e.headers["x-lensmcp-origin-node-id"])}:{}}},"beginTrace"),S=s((e,t,r)=>{e&&e.steps.push({step:t,atMs:Date.now()-e.startedAt,...r})},"traceStep"),b=s((e,t,r,a)=>{if(!e||e.done||(e.done=!0,t===exports.LENS_DASHBOARD_PROJECT&&r<500))return;const i=Date.now()-e.startedAt;l(r>=500?"error":"info",`gateway ${e.method} ${e.host}${e.url} \u2192 ${r} (${i}ms)`,`gateway-request:${t}`,{kind:"gateway-request",project:t,host:e.host,method:e.method,url:e.url,status:r,durationMs:i,startedAt:e.startedAt,steps:e.steps,...a},{...e.flowId?{flowId:e.flowId}:{},...e.requestId?{requestId:e.requestId}:{},...e.originNodeId?{originNodeId:e.originNodeId}:{}})},"finishTrace"),c=new Map;return{emit:l,eid:p,beginTrace:w,traceStep:S,finishTrace:b,recordEdge:s((e,t,r,a)=>{if(e.project===exports.LENS_DASHBOARD_PROJECT&&r<500&&r!==0)return;const i=e.host??"(default)",u=(a?a+"\u21D2":"")+i+"\u2192"+e.project,n=c.get(u)??{host:i,project:e.project,caller:a,count:0,totalMs:0,errors:0};n.count+=1,n.totalMs+=t,(r>=500||r===0)&&(n.errors+=1),c.set(u,n)},"recordEdge"),startEdgeFlusher:s(()=>{const e=setInterval(()=>{for(const t of c.values()){const r=Math.round(t.totalMs/t.count);l(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})}c.clear()},d.trafficFlushMs);return e.unref(),e},"startEdgeFlusher")}}f(createObservability,"createObservability"),s(createObservability,"createObservability");
|
|
@@ -1,89 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
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
|
-
}
|
|
1
|
+
"use strict";var p=Object.defineProperty;var a=(o,e)=>p(o,"name",{value:e,configurable:!0});var c=Object.defineProperty,s=a((o,e)=>c(o,"name",{value:e,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.FOREIGN_POD_ENV_DENYLIST=exports.WORKSPACE_DOTENV_FILES=void 0,exports.parseDotenvKeys=parseDotenvKeys,exports.workspaceDotenvKeys=workspaceDotenvKeys,exports.scrubEnv=scrubEnv,exports.podBaseEnv=podBaseEnv;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.WORKSPACE_DOTENV_FILES=[".env",".env.local",".local.env"],exports.FOREIGN_POD_ENV_DENYLIST=["PG_URL","REDIS_URL","DATABASE_URL","POSTGRES_URL"];function parseDotenvKeys(o){const e=new Set;for(const r of o.split(`
|
|
2
|
+
`)){const t=r.trim();if(!t||t.startsWith("#"))continue;const n=t.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/);n&&e.add(n[1])}return e}a(parseDotenvKeys,"parseDotenvKeys"),s(parseDotenvKeys,"parseDotenvKeys");function workspaceDotenvKeys(o){const e=new Set;for(const r of exports.WORKSPACE_DOTENV_FILES){let t;try{t=fs.readFileSync(path.join(o,r),"utf8")}catch{continue}for(const n of parseDotenvKeys(t))e.add(n)}return e}a(workspaceDotenvKeys,"workspaceDotenvKeys"),s(workspaceDotenvKeys,"workspaceDotenvKeys");function scrubEnv(o,e){const r={};for(const[t,n]of Object.entries(o))e.has(t)||exports.FOREIGN_POD_ENV_DENYLIST.includes(t)||(r[t]=n);return r}a(scrubEnv,"scrubEnv"),s(scrubEnv,"scrubEnv");function podBaseEnv(o,e,r){return path.resolve(r)===path.resolve(e)?o:scrubEnv(o,workspaceDotenvKeys(e))}a(podBaseEnv,"podBaseEnv"),s(podBaseEnv,"podBaseEnv");
|