@lensmcp/cluster 1.18.3 → 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.
Files changed (190) hide show
  1. package/basic-ssl.d.ts +0 -1
  2. package/basic-ssl.js +1 -241
  3. package/build-scope-patterns.d.ts +0 -1
  4. package/build-scope-patterns.js +1 -40
  5. package/create-webpack-dev.d.ts +0 -1
  6. package/create-webpack-dev.js +1 -186
  7. package/create-webpack-prod.d.ts +0 -1
  8. package/create-webpack-prod.js +1 -169
  9. package/executors/build/build.impl.d.ts +0 -1
  10. package/executors/build/build.impl.js +1 -98
  11. package/executors/gateway/gateway-errors.d.ts +0 -1
  12. package/executors/gateway/gateway-errors.js +1 -43
  13. package/executors/gateway/gateway.impl.d.ts +0 -1
  14. package/executors/gateway/gateway.impl.js +1 -53
  15. package/executors/gateway/gateway.lib.d.ts +0 -1
  16. package/executors/gateway/gateway.lib.js +1 -29
  17. package/executors/gateway/health-check.d.ts +0 -1
  18. package/executors/gateway/health-check.js +1 -66
  19. package/executors/gateway/jwks-verify.d.ts +0 -1
  20. package/executors/gateway/jwks-verify.js +1 -121
  21. package/executors/gateway/main.prod-gateway.d.ts +0 -1
  22. package/executors/gateway/main.prod-gateway.js +2 -573
  23. package/executors/gateway/main.rollout.d.ts +0 -1
  24. package/executors/gateway/main.rollout.js +11 -117
  25. package/executors/gateway/manifest.d.ts +0 -1
  26. package/executors/gateway/manifest.js +1 -374
  27. package/executors/gateway/metrics.d.ts +0 -1
  28. package/executors/gateway/metrics.js +1 -56
  29. package/executors/gateway/otel-tracing.d.ts +0 -1
  30. package/executors/gateway/otel-tracing.js +1 -74
  31. package/executors/gateway/prod-gateway.lib.d.ts +0 -1
  32. package/executors/gateway/prod-gateway.lib.js +1 -22
  33. package/executors/gateway/prod-runtime/access-log.d.ts +0 -1
  34. package/executors/gateway/prod-runtime/access-log.js +1 -24
  35. package/executors/gateway/prod-runtime/app.d.ts +0 -1
  36. package/executors/gateway/prod-runtime/app.js +1 -123
  37. package/executors/gateway/prod-runtime/auth.d.ts +0 -1
  38. package/executors/gateway/prod-runtime/auth.js +1 -51
  39. package/executors/gateway/prod-runtime/cors.d.ts +0 -1
  40. package/executors/gateway/prod-runtime/cors.js +1 -40
  41. package/executors/gateway/prod-runtime/edge.d.ts +0 -1
  42. package/executors/gateway/prod-runtime/edge.js +1 -65
  43. package/executors/gateway/prod-runtime/handler.d.ts +0 -1
  44. package/executors/gateway/prod-runtime/handler.js +1 -226
  45. package/executors/gateway/prod-runtime/hooks.d.ts +0 -1
  46. package/executors/gateway/prod-runtime/hooks.js +1 -42
  47. package/executors/gateway/prod-runtime/observability.d.ts +0 -1
  48. package/executors/gateway/prod-runtime/observability.js +1 -125
  49. package/executors/gateway/prod-runtime/rollout.d.ts +0 -1
  50. package/executors/gateway/prod-runtime/rollout.js +1 -103
  51. package/executors/gateway/prod-runtime/routing.d.ts +0 -1
  52. package/executors/gateway/prod-runtime/routing.js +1 -40
  53. package/executors/gateway/prod-runtime/server.d.ts +0 -1
  54. package/executors/gateway/prod-runtime/server.js +1 -79
  55. package/executors/gateway/prod-runtime/trust.d.ts +0 -1
  56. package/executors/gateway/prod-runtime/trust.js +1 -32
  57. package/executors/gateway/prod-runtime/types.d.ts +0 -1
  58. package/executors/gateway/prod-runtime/types.js +1 -2
  59. package/executors/gateway/prod-runtime/upgrade.d.ts +0 -1
  60. package/executors/gateway/prod-runtime/upgrade.js +4 -116
  61. package/executors/gateway/prod-runtime/upstream.d.ts +0 -1
  62. package/executors/gateway/prod-runtime/upstream.js +1 -21
  63. package/executors/gateway/providers-prod.d.ts +0 -1
  64. package/executors/gateway/providers-prod.js +1 -232
  65. package/executors/gateway/rate-limit.d.ts +0 -1
  66. package/executors/gateway/rate-limit.js +2 -75
  67. package/executors/gateway/registry-source.d.ts +0 -1
  68. package/executors/gateway/registry-source.js +1 -131
  69. package/executors/gateway/rollout-ops.d.ts +0 -1
  70. package/executors/gateway/rollout-ops.js +2 -167
  71. package/executors/gateway/runtime/auth.d.ts +0 -1
  72. package/executors/gateway/runtime/auth.js +1 -64
  73. package/executors/gateway/runtime/chooser.d.ts +0 -1
  74. package/executors/gateway/runtime/chooser.js +12 -45
  75. package/executors/gateway/runtime/control.d.ts +0 -1
  76. package/executors/gateway/runtime/control.js +1 -128
  77. package/executors/gateway/runtime/dev-auth.d.ts +0 -1
  78. package/executors/gateway/runtime/dev-auth.js +1 -108
  79. package/executors/gateway/runtime/discovery.d.ts +0 -1
  80. package/executors/gateway/runtime/discovery.js +1 -123
  81. package/executors/gateway/runtime/edge.d.ts +0 -1
  82. package/executors/gateway/runtime/edge.js +1 -47
  83. package/executors/gateway/runtime/handler.d.ts +0 -1
  84. package/executors/gateway/runtime/handler.js +1 -183
  85. package/executors/gateway/runtime/hooks.d.ts +0 -1
  86. package/executors/gateway/runtime/hooks.js +1 -55
  87. package/executors/gateway/runtime/lens-children.d.ts +0 -1
  88. package/executors/gateway/runtime/lens-children.js +1 -651
  89. package/executors/gateway/runtime/lifecycle.d.ts +0 -1
  90. package/executors/gateway/runtime/lifecycle.js +3 -842
  91. package/executors/gateway/runtime/observability.d.ts +0 -1
  92. package/executors/gateway/runtime/observability.js +2 -148
  93. package/executors/gateway/runtime/pod-env.d.ts +0 -1
  94. package/executors/gateway/runtime/pod-env.js +2 -89
  95. package/executors/gateway/runtime/proxy.d.ts +0 -1
  96. package/executors/gateway/runtime/proxy.js +1 -457
  97. package/executors/gateway/runtime/route-registry.d.ts +0 -1
  98. package/executors/gateway/runtime/route-registry.js +1 -72
  99. package/executors/gateway/runtime/scope.d.ts +0 -1
  100. package/executors/gateway/runtime/scope.js +1 -117
  101. package/executors/gateway/runtime/server.d.ts +0 -1
  102. package/executors/gateway/runtime/server.js +3 -487
  103. package/executors/gateway/runtime/service-keys.d.ts +0 -1
  104. package/executors/gateway/runtime/service-keys.js +1 -49
  105. package/executors/gateway/runtime/types.d.ts +0 -1
  106. package/executors/gateway/runtime/types.js +1 -151
  107. package/executors/gateway/runtime/upgrade.d.ts +0 -1
  108. package/executors/gateway/runtime/upgrade.js +1 -71
  109. package/executors/gateway/runtime/workspace-registry.d.ts +0 -1
  110. package/executors/gateway/runtime/workspace-registry.js +1 -99
  111. package/executors/gateway/ssrf-guard.d.ts +0 -1
  112. package/executors/gateway/ssrf-guard.js +1 -190
  113. package/executors/serve/serve.impl.d.ts +0 -1
  114. package/executors/serve/serve.impl.js +1 -280
  115. package/executors/trust/trust.impl.d.ts +0 -1
  116. package/executors/trust/trust.impl.js +4 -162
  117. package/gateway.d.ts +0 -1
  118. package/gateway.js +1 -35
  119. package/index.d.ts +0 -1
  120. package/index.js +1 -16
  121. package/main.devserver.d.ts +0 -1
  122. package/main.devserver.js +10 -1117
  123. package/package.json +4 -3
  124. package/tsgo-check-plugin.d.ts +0 -1
  125. package/tsgo-check-plugin.js +4 -364
  126. package/typecheck-bus.d.ts +0 -1
  127. package/typecheck-bus.js +4 -256
  128. package/basic-ssl.d.ts.map +0 -1
  129. package/build-scope-patterns.d.ts.map +0 -1
  130. package/create-webpack-dev.d.ts.map +0 -1
  131. package/create-webpack-prod.d.ts.map +0 -1
  132. package/executors/build/build.impl.d.ts.map +0 -1
  133. package/executors/gateway/gateway-errors.d.ts.map +0 -1
  134. package/executors/gateway/gateway.impl.d.ts.map +0 -1
  135. package/executors/gateway/gateway.lib.d.ts.map +0 -1
  136. package/executors/gateway/health-check.d.ts.map +0 -1
  137. package/executors/gateway/jwks-verify.d.ts.map +0 -1
  138. package/executors/gateway/main.prod-gateway.d.ts.map +0 -1
  139. package/executors/gateway/main.rollout.d.ts.map +0 -1
  140. package/executors/gateway/manifest.d.ts.map +0 -1
  141. package/executors/gateway/metrics.d.ts.map +0 -1
  142. package/executors/gateway/otel-tracing.d.ts.map +0 -1
  143. package/executors/gateway/prod-gateway.lib.d.ts.map +0 -1
  144. package/executors/gateway/prod-runtime/access-log.d.ts.map +0 -1
  145. package/executors/gateway/prod-runtime/app.d.ts.map +0 -1
  146. package/executors/gateway/prod-runtime/auth.d.ts.map +0 -1
  147. package/executors/gateway/prod-runtime/cors.d.ts.map +0 -1
  148. package/executors/gateway/prod-runtime/edge.d.ts.map +0 -1
  149. package/executors/gateway/prod-runtime/handler.d.ts.map +0 -1
  150. package/executors/gateway/prod-runtime/hooks.d.ts.map +0 -1
  151. package/executors/gateway/prod-runtime/observability.d.ts.map +0 -1
  152. package/executors/gateway/prod-runtime/rollout.d.ts.map +0 -1
  153. package/executors/gateway/prod-runtime/routing.d.ts.map +0 -1
  154. package/executors/gateway/prod-runtime/server.d.ts.map +0 -1
  155. package/executors/gateway/prod-runtime/trust.d.ts.map +0 -1
  156. package/executors/gateway/prod-runtime/types.d.ts.map +0 -1
  157. package/executors/gateway/prod-runtime/upgrade.d.ts.map +0 -1
  158. package/executors/gateway/prod-runtime/upstream.d.ts.map +0 -1
  159. package/executors/gateway/providers-prod.d.ts.map +0 -1
  160. package/executors/gateway/rate-limit.d.ts.map +0 -1
  161. package/executors/gateway/registry-source.d.ts.map +0 -1
  162. package/executors/gateway/rollout-ops.d.ts.map +0 -1
  163. package/executors/gateway/runtime/auth.d.ts.map +0 -1
  164. package/executors/gateway/runtime/chooser.d.ts.map +0 -1
  165. package/executors/gateway/runtime/control.d.ts.map +0 -1
  166. package/executors/gateway/runtime/dev-auth.d.ts.map +0 -1
  167. package/executors/gateway/runtime/discovery.d.ts.map +0 -1
  168. package/executors/gateway/runtime/edge.d.ts.map +0 -1
  169. package/executors/gateway/runtime/handler.d.ts.map +0 -1
  170. package/executors/gateway/runtime/hooks.d.ts.map +0 -1
  171. package/executors/gateway/runtime/lens-children.d.ts.map +0 -1
  172. package/executors/gateway/runtime/lifecycle.d.ts.map +0 -1
  173. package/executors/gateway/runtime/observability.d.ts.map +0 -1
  174. package/executors/gateway/runtime/pod-env.d.ts.map +0 -1
  175. package/executors/gateway/runtime/proxy.d.ts.map +0 -1
  176. package/executors/gateway/runtime/route-registry.d.ts.map +0 -1
  177. package/executors/gateway/runtime/scope.d.ts.map +0 -1
  178. package/executors/gateway/runtime/server.d.ts.map +0 -1
  179. package/executors/gateway/runtime/service-keys.d.ts.map +0 -1
  180. package/executors/gateway/runtime/types.d.ts.map +0 -1
  181. package/executors/gateway/runtime/upgrade.d.ts.map +0 -1
  182. package/executors/gateway/runtime/workspace-registry.d.ts.map +0 -1
  183. package/executors/gateway/ssrf-guard.d.ts.map +0 -1
  184. package/executors/serve/serve.impl.d.ts.map +0 -1
  185. package/executors/trust/trust.impl.d.ts.map +0 -1
  186. package/gateway.d.ts.map +0 -1
  187. package/index.d.ts.map +0 -1
  188. package/main.devserver.d.ts.map +0 -1
  189. package/tsgo-check-plugin.d.ts.map +0 -1
  190. package/typecheck-bus.d.ts.map +0 -1
@@ -1,108 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.devAttrs = void 0;
4
- exports.verifyDevJwt = verifyDevJwt;
5
- exports.stampIdentity = stampIdentity;
6
- /**
7
- * Dev edge auth: verify the end-user token, then stamp the trusted identity headers the services read
8
- * (via GatewayTrustGuard). It MIRRORS the prod gateway's posture — a real JWKS/RS256 verifier when one is
9
- * wired (see `../jwks-verify` + the composition in `server.ts`), an HS256 shared-secret path as the legacy
10
- * fallback. Pure functions (the verifier is injected, so unit tests supply their own JWKS).
11
- *
12
- * SECURITY (the invariant this file must hold): a `jwt` route MUST NOT accept a token whose signature the
13
- * edge cannot verify. When a JWKS verifier is wired it is the SOLE acceptor — every alg goes through it, so
14
- * an unknown `kid`, a bad signature, `alg:none`, an HS256-confusion token, and an expired token ALL fail
15
- * closed (rejected). Without a verifier, an asymmetric (RS256/ES*) token cannot be checked (we don't hold
16
- * the issuer's public keys), so it also fails closed — unless an operator EXPLICITLY opts into the old
17
- * insecure decode-only path (`LENSMCP_GW_DEV_JWT_INSECURE_DECODE=1`) for local bring-up. The HS256
18
- * shared-secret path stays for services using that convention (and is itself bypassed once JWKS is wired).
19
- */
20
- const node_crypto_1 = require("node:crypto");
21
- /** The compact JWS from the `Authorization: Bearer …` header, or undefined. */
22
- function bearerToken(req) {
23
- const raw = Array.isArray(req.headers['authorization']) ? req.headers['authorization'][0] : req.headers['authorization'];
24
- const auth = String(raw ?? '');
25
- return auth.startsWith('Bearer ') ? auth.slice(7) : undefined;
26
- }
27
- /**
28
- * Verify the end-user JWT and return its claims, or undefined.
29
- *
30
- * @param verifier when provided (the RS256/JWKS verifier wired by the composition root), it is the ONLY
31
- * acceptor — the token is verified against the issuer's published keys by `kid`, so a rogue key / unknown
32
- * kid / bad signature / `alg:none` / HS256-confusion / expired token all return undefined (fail closed).
33
- */
34
- function verifyDevJwt(req, verifier) {
35
- const token = bearerToken(req);
36
- if (!token)
37
- return undefined;
38
- const [h, p, s] = token.split('.');
39
- if (!h || !p || !s)
40
- return undefined;
41
- // Preferred: a real JWKS/RS256 verifier (mirrors the prod gateway's `jwks ? jwks.verify(tok) : hs256`).
42
- // When wired it is the SOLE acceptor, so every forgery vector below is closed at once.
43
- if (verifier)
44
- return verifier.verify(token);
45
- // ── No verifier wired (legacy dev) ──────────────────────────────────────────────────────────────────
46
- let alg;
47
- try {
48
- alg = JSON.parse(Buffer.from(h, 'base64url').toString())['alg'];
49
- }
50
- catch {
51
- return undefined;
52
- }
53
- if (typeof alg === 'string' && alg !== 'HS256') {
54
- // An asymmetric IdP (RS256 + JWKS) does NOT use the HS256 dev shared secret. Without the issuer's public
55
- // keys we CANNOT verify the signature, so — unlike the old code, which decode-accepted any RS256 token
56
- // (a full edge auth bypass: a rogue key or a forged `alg:none` sailed through) — we FAIL CLOSED. Wire a
57
- // JWKS verifier (LENSMCP_GW_JWKS_URL, or the auto-derived auth-host JWKS) to accept RS256 tokens.
58
- if (process.env['LENSMCP_GW_DEV_JWT_INSECURE_DECODE'] !== '1')
59
- return undefined; // fail closed
60
- // Explicit, dev-only opt-in to the legacy decode + exp-check (NO signature check) — bring-up escape hatch.
61
- try {
62
- const rsClaims = JSON.parse(Buffer.from(p, 'base64url').toString());
63
- if (typeof rsClaims['exp'] === 'number' && Date.now() / 1000 > rsClaims['exp'])
64
- return undefined;
65
- return rsClaims;
66
- }
67
- catch {
68
- return undefined;
69
- }
70
- }
71
- // HS256 shared-secret convention (only reachable when NO JWKS verifier is wired).
72
- const secret = process.env['AUTH_JWT_SECRET'] ?? 'tetros-dev-secret';
73
- const expected = (0, node_crypto_1.createHmac)('sha256', secret).update(`${h}.${p}`).digest('base64url');
74
- const a = Buffer.from(s);
75
- const b = Buffer.from(expected);
76
- if (a.length !== b.length || !(0, node_crypto_1.timingSafeEqual)(a, b))
77
- return undefined;
78
- try {
79
- const claims = JSON.parse(Buffer.from(p, 'base64url').toString());
80
- if (typeof claims['exp'] === 'number' && Date.now() / 1000 > claims['exp'])
81
- return undefined;
82
- return claims;
83
- }
84
- catch {
85
- return undefined;
86
- }
87
- }
88
- /** Stamp verified identity onto the forwarded request — tenant from the `tid` CLAIM, never a client header. */
89
- function stampIdentity(req, claims) {
90
- const set = (k, v) => { if (v !== undefined && v !== null && v !== '')
91
- req.headers[k] = String(v); };
92
- set('x-user-id', claims['sub']);
93
- set('x-tenant-id', claims['tid']);
94
- const roles = claims['roles'];
95
- if (Array.isArray(roles) && roles.length)
96
- req.headers['x-user-roles'] = roles.map(String).join(',');
97
- const perms = claims['perms'];
98
- if (Array.isArray(perms) && perms.length)
99
- req.headers['x-user-permissions'] = perms.map(String).join(',');
100
- }
101
- /** Build the ABAC attribute bag from the verified claims + request envelope. */
102
- const devAttrs = (req, claims) => ({
103
- ...claims,
104
- ip: req.socket.remoteAddress ?? '',
105
- method: (req.method ?? 'GET').toUpperCase(),
106
- path: (req.url ?? '/').split('?')[0],
107
- });
108
- exports.devAttrs = devAttrs;
1
+ "use strict";var y=Object.defineProperty;var a=(e,r)=>y(e,"name",{value:r,configurable:!0});var h=Object.defineProperty,u=a((e,r)=>h(e,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.devAttrs=void 0,exports.verifyDevJwt=verifyDevJwt,exports.stampIdentity=stampIdentity;const node_crypto_1=require("node:crypto");function bearerToken(e){const r=Array.isArray(e.headers.authorization)?e.headers.authorization[0]:e.headers.authorization,t=String(r??"");return t.startsWith("Bearer ")?t.slice(7):void 0}a(bearerToken,"bearerToken"),u(bearerToken,"bearerToken");function verifyDevJwt(e,r){const t=bearerToken(e);if(!t)return;const[n,s,f]=t.split(".");if(!n||!s||!f)return;if(r)return r.verify(t);let o;try{o=JSON.parse(Buffer.from(n,"base64url").toString()).alg}catch{return}if(typeof o=="string"&&o!=="HS256"){if(process.env.LENSMCP_GW_DEV_JWT_INSECURE_DECODE!=="1")return;try{const i=JSON.parse(Buffer.from(s,"base64url").toString());return typeof i.exp=="number"&&Date.now()/1e3>i.exp?void 0:i}catch{return}}const d=process.env.AUTH_JWT_SECRET??"tetros-dev-secret",l=(0,node_crypto_1.createHmac)("sha256",d).update(`${n}.${s}`).digest("base64url"),p=Buffer.from(f),c=Buffer.from(l);if(!(p.length!==c.length||!(0,node_crypto_1.timingSafeEqual)(p,c)))try{const i=JSON.parse(Buffer.from(s,"base64url").toString());return typeof i.exp=="number"&&Date.now()/1e3>i.exp?void 0:i}catch{return}}a(verifyDevJwt,"verifyDevJwt"),u(verifyDevJwt,"verifyDevJwt");function stampIdentity(e,r){const t=u((f,o)=>{o!=null&&o!==""&&(e.headers[f]=String(o))},"set");t("x-user-id",r.sub),t("x-tenant-id",r.tid);const n=r.roles;Array.isArray(n)&&n.length&&(e.headers["x-user-roles"]=n.map(String).join(","));const s=r.perms;Array.isArray(s)&&s.length&&(e.headers["x-user-permissions"]=s.map(String).join(","))}a(stampIdentity,"stampIdentity"),u(stampIdentity,"stampIdentity");const devAttrs=u((e,r)=>({...r,ip:e.socket.remoteAddress??"",method:(e.method??"GET").toUpperCase(),path:(e.url??"/").split("?")[0]}),"devAttrs");exports.devAttrs=devAttrs;
@@ -14,4 +14,3 @@ export declare function discoverRoutes(rootDir: string, projects: Record<string,
14
14
  routes: Route[];
15
15
  services: ServiceCtl[];
16
16
  };
17
- //# sourceMappingURL=discovery.d.ts.map
@@ -1,123 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pickSock = pickSock;
4
- exports.lensPortFromUpstream = lensPortFromUpstream;
5
- exports.discoverRoutes = discoverRoutes;
6
- const tslib_1 = require("tslib");
7
- /**
8
- * Route discovery + socket-pool round-robin. Pure (fs reads only): reads every
9
- * project's `cluster` (or legacy `davnx`) declaration and builds the route table.
10
- */
11
- const fs = tslib_1.__importStar(require("node:fs"));
12
- const os = tslib_1.__importStar(require("node:os"));
13
- const path = tslib_1.__importStar(require("node:path"));
14
- const manifest_1 = require("../manifest");
15
- const scope_1 = require("./scope");
16
- /** Round-robin over the pool's sockets, rescanning the dir when the cache ages out. */
17
- function pickSock(pool, scanTtlMs = 1500) {
18
- const now = Date.now();
19
- if (now - pool.scannedAt > scanTtlMs) {
20
- try {
21
- pool.socks = fs.readdirSync(pool.dir)
22
- .filter((f) => /^child-\d+\.sock$/.test(f))
23
- .map((f) => path.join(pool.dir, f));
24
- }
25
- catch {
26
- pool.socks = [];
27
- }
28
- pool.scannedAt = now;
29
- }
30
- if (pool.socks.length === 0)
31
- return undefined;
32
- pool.idx = (pool.idx + 1) % pool.socks.length;
33
- return pool.socks[pool.idx];
34
- }
35
- /** Extract the port from an `upstream` URL like `http://localhost:5173`. */
36
- function lensPortFromUpstream(upstream) {
37
- if (!upstream)
38
- return undefined;
39
- const m = /:(\d+)/.exec(upstream);
40
- return m ? Number(m[1]) : undefined;
41
- }
42
- /**
43
- * Read every project's `cluster` (or legacy `davnx`) declaration and build
44
- * the route table: host routes first (plus auto `internal.<host>` for pod
45
- * services), the `default` catch-all last.
46
- */
47
- function discoverRoutes(rootDir, projects, sockBaseDir = os.tmpdir(),
48
- // The workspace key namespaces the pod sock dir (planning/multi-workspace-gateway.md) — MUST match
49
- // `main.devserver.ts`'s `SOCK_DIR` derivation so the gateway scans the same dir the devserver writes.
50
- // Empty → the legacy un-namespaced path (single-workspace / pre-multi-workspace).
51
- wsKey = '') {
52
- const sockDirFor = (service) => wsKey ? path.join(sockBaseDir, wsKey, `${service}-devserver`) : path.join(sockBaseDir, `${service}-devserver`);
53
- const routes = [];
54
- const services = [];
55
- const hosts = []; // every declared host — the default's apex is derived from these
56
- let defaultRoute;
57
- for (const [name, p] of Object.entries(projects)) {
58
- let decl;
59
- try {
60
- const raw = JSON.parse(fs.readFileSync(path.join(rootDir, p.root, 'project.json'), 'utf8'));
61
- decl = raw.cluster ?? raw.davnx;
62
- }
63
- catch {
64
- continue;
65
- }
66
- if (!decl)
67
- continue;
68
- let pool;
69
- let svc;
70
- let target;
71
- let lens;
72
- if (decl.service) {
73
- // `lens` applies to FRONTEND apps only; a pod service is already
74
- // instrumented by the serve executor's node-instrumentation graft.
75
- if (decl.lens)
76
- console.warn(`[gateway] ${name}: cluster.lens is ignored for pod (service) decls — backends are instrumented by serve-hmr.`);
77
- pool = { dir: sockDirFor(decl.service), socks: [], idx: -1, scannedAt: 0 };
78
- svc = { project: name, decl, root: rootDir, wsKey, pool, state: 'down', lastUsed: Date.now(), inflight: 0, lastScaleAt: 0 };
79
- services.push(svc);
80
- }
81
- else if (decl.lens) {
82
- // Lens-mode frontend: the gateway SPAWNS this app's Vite + instrumentation
83
- // (deterministically on `port`) and upstreams to it. One LensFrontend per
84
- // project is SHARED across its host/default routes (so the spawn fires once).
85
- const port = decl.port ?? lensPortFromUpstream(decl.upstream) ?? 5173;
86
- target = `http://localhost:${port}`;
87
- lens = { project: name, projectRoot: path.join(rootDir, p.root), port };
88
- }
89
- else {
90
- target = decl.upstream ?? (decl.port ? `http://localhost:${decl.port}` : undefined);
91
- if (!target) {
92
- console.warn(`[gateway] ${name}: no service/upstream/port — skipped.`);
93
- continue;
94
- }
95
- }
96
- const base = { project: name, prependPrefix: decl.prependPrefix, target, pool, svc, prefix: decl.path, auth: decl.auth, lens };
97
- if (decl.host) {
98
- routes.push({ ...base, host: decl.host });
99
- hosts.push(decl.host);
100
- // internal.<host>: east-west traffic, same pods, NO middleware.
101
- if (pool && decl.internalHost !== false) {
102
- routes.push({
103
- ...base,
104
- host: typeof decl.internalHost === 'string' ? decl.internalHost : `internal.${decl.host}`,
105
- internal: true,
106
- });
107
- }
108
- }
109
- if (decl.default)
110
- defaultRoute = { ...base, prefix: undefined };
111
- }
112
- if (defaultRoute) {
113
- // Stamp the apex so a shared multi-workspace gateway routes an unclaimed host to THIS workspace's
114
- // default (see matchRoute). Harmless for a single workspace — one default ignores its apex.
115
- defaultRoute.apex = (0, scope_1.baseDomainOf)(hosts);
116
- routes.push(defaultRoute);
117
- }
118
- // specificity sort (shared with prod): host+path beats host-only beats
119
- // catch-all — so a path-mounted service (api.x/channels) wins over the
120
- // host's owner (api.x → api).
121
- (0, manifest_1.sortBySpecificity)(routes);
122
- return { routes, services };
123
- }
1
+ "use strict";var S=Object.defineProperty;var p=(e,r)=>S(e,"name",{value:r,configurable:!0});var k=Object.defineProperty,a=p((e,r)=>k(e,"name",{value:r,configurable:!0}),"a");Object.defineProperty(exports,"__esModule",{value:!0}),exports.pickSock=pickSock,exports.lensPortFromUpstream=lensPortFromUpstream,exports.discoverRoutes=discoverRoutes;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),manifest_1=require("../manifest"),scope_1=require("./scope");function pickSock(e,r=1500){const i=Date.now();if(i-e.scannedAt>r){try{e.socks=fs.readdirSync(e.dir).filter(s=>/^child-\d+\.sock$/.test(s)).map(s=>path.join(e.dir,s))}catch{e.socks=[]}e.scannedAt=i}if(e.socks.length!==0)return e.idx=(e.idx+1)%e.socks.length,e.socks[e.idx]}p(pickSock,"pickSock"),a(pickSock,"pickSock");function lensPortFromUpstream(e){if(!e)return;const r=/:(\d+)/.exec(e);return r?Number(r[1]):void 0}p(lensPortFromUpstream,"lensPortFromUpstream"),a(lensPortFromUpstream,"lensPortFromUpstream");function discoverRoutes(e,r,i=os.tmpdir(),s=""){const y=a(t=>s?path.join(i,s,`${t}-devserver`):path.join(i,`${t}-devserver`),"sockDirFor"),n=[],v=[],m=[];let l;for(const[t,x]of Object.entries(r)){let o;try{const c=JSON.parse(fs.readFileSync(path.join(e,x.root,"project.json"),"utf8"));o=c.cluster??c.davnx}catch{continue}if(!o)continue;let d,f,u,j;if(o.service)o.lens&&console.warn(`[gateway] ${t}: cluster.lens is ignored for pod (service) decls \u2014 backends are instrumented by serve-hmr.`),d={dir:y(o.service),socks:[],idx:-1,scannedAt:0},f={project:t,decl:o,root:e,wsKey:s,pool:d,state:"down",lastUsed:Date.now(),inflight:0,lastScaleAt:0},v.push(f);else if(o.lens){const c=o.port??lensPortFromUpstream(o.upstream)??5173;u=`http://localhost:${c}`,j={project:t,projectRoot:path.join(e,x.root),port:c}}else if(u=o.upstream??(o.port?`http://localhost:${o.port}`:void 0),!u){console.warn(`[gateway] ${t}: no service/upstream/port \u2014 skipped.`);continue}const h={project:t,prependPrefix:o.prependPrefix,target:u,pool:d,svc:f,prefix:o.path,auth:o.auth,lens:j};o.host&&(n.push({...h,host:o.host}),m.push(o.host),d&&o.internalHost!==!1&&n.push({...h,host:typeof o.internalHost=="string"?o.internalHost:`internal.${o.host}`,internal:!0})),o.default&&(l={...h,prefix:void 0})}return l&&(l.apex=(0,scope_1.baseDomainOf)(m),n.push(l)),(0,manifest_1.sortBySpecificity)(n),{routes:n,services:v}}p(discoverRoutes,"discoverRoutes"),a(discoverRoutes,"discoverRoutes");
@@ -28,4 +28,3 @@ export declare const corsPreflight: (req: http.IncomingMessage, res: http.Server
28
28
  /** Allowed-methods lists for the two preflight sites. */
29
29
  export declare const PREFLIGHT_METHODS_NOROUTE = "GET,HEAD,OPTIONS";
30
30
  export declare const PREFLIGHT_METHODS_ROUTED = "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS";
31
- //# sourceMappingURL=edge.d.ts.map
@@ -1,47 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PREFLIGHT_METHODS_ROUTED = exports.PREFLIGHT_METHODS_NOROUTE = exports.corsPreflight = exports.cors = exports.GATEWAY_OWNED_HEADERS = exports.sendError = void 0;
4
- const gateway_errors_1 = require("../gateway-errors");
5
- /**
6
- * Send a gateway-generated edge error as the JSON envelope `{ key, status, traceId, message? }` (NOT
7
- * `text/plain`) + an `x-request-id` header — the SAME localized contract a service returns, so a browser
8
- * app renders `t(key)` and surfaces the trace id. Mirrors the prod gateway's `sendError`.
9
- */
10
- const sendError = (res, req, status, reason, detail) => {
11
- const traceId = (0, gateway_errors_1.ensureRequestId)(req);
12
- if (!res.headersSent)
13
- res.writeHead(status, { 'content-type': gateway_errors_1.GATEWAY_ERROR_CONTENT_TYPE, 'x-request-id': traceId });
14
- res.end((0, gateway_errors_1.gatewayErrorBody)(status, reason, traceId, detail));
15
- };
16
- exports.sendError = sendError;
17
- /**
18
- * The gateway OWNS these headers — strip any client-supplied copy at ingress so identity + trust can
19
- * only originate from the gateway (mirrors the prod gateway's stripTrust). Applied at the very top of
20
- * BOTH the HTTP handler and the WS upgrade.
21
- */
22
- exports.GATEWAY_OWNED_HEADERS = ['x-internal-token', 'x-api-key-id', 'x-user-id', 'x-tenant-id', 'x-user-roles', 'x-user-permissions'];
23
- /** Reflect the request Origin back with credentials — the gateway is the edge CORS authority. */
24
- const cors = (req, res) => {
25
- const origin = String(req.headers.origin ?? '*');
26
- res.setHeader('access-control-allow-origin', origin);
27
- res.setHeader('access-control-allow-credentials', 'true');
28
- res.setHeader('vary', 'Origin');
29
- };
30
- exports.cors = cors;
31
- /**
32
- * Answer a CORS preflight (OPTIONS) at the edge: reflect CORS + 204 with the allowed `methods` and the
33
- * requested headers echoed back. `methods` differs by caller — the no-route host-root uses the narrow
34
- * `GET,HEAD,OPTIONS`; a routed path uses the wide verb list.
35
- */
36
- const corsPreflight = (req, res, methods) => {
37
- (0, exports.cors)(req, res);
38
- res.writeHead(204, {
39
- 'access-control-allow-methods': methods,
40
- 'access-control-allow-headers': String(req.headers['access-control-request-headers'] ?? '*'),
41
- });
42
- res.end();
43
- };
44
- exports.corsPreflight = corsPreflight;
45
- /** Allowed-methods lists for the two preflight sites. */
46
- exports.PREFLIGHT_METHODS_NOROUTE = 'GET,HEAD,OPTIONS';
47
- exports.PREFLIGHT_METHODS_ROUTED = 'GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS';
1
+ "use strict";var i=Object.defineProperty;var a=(r,e)=>i(r,"name",{value:e,configurable:!0});var c=Object.defineProperty,s=a((r,e)=>c(r,"name",{value:e,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.PREFLIGHT_METHODS_ROUTED=exports.PREFLIGHT_METHODS_NOROUTE=exports.corsPreflight=exports.cors=exports.GATEWAY_OWNED_HEADERS=exports.sendError=void 0;const gateway_errors_1=require("../gateway-errors"),sendError=s((r,e,o,n,E)=>{const t=(0,gateway_errors_1.ensureRequestId)(e);r.headersSent||r.writeHead(o,{"content-type":gateway_errors_1.GATEWAY_ERROR_CONTENT_TYPE,"x-request-id":t}),r.end((0,gateway_errors_1.gatewayErrorBody)(o,n,t,E))},"sendError");exports.sendError=sendError,exports.GATEWAY_OWNED_HEADERS=["x-internal-token","x-api-key-id","x-user-id","x-tenant-id","x-user-roles","x-user-permissions"];const cors=s((r,e)=>{const o=String(r.headers.origin??"*");e.setHeader("access-control-allow-origin",o),e.setHeader("access-control-allow-credentials","true"),e.setHeader("vary","Origin")},"cors");exports.cors=cors;const corsPreflight=s((r,e,o)=>{(0,exports.cors)(r,e),e.writeHead(204,{"access-control-allow-methods":o,"access-control-allow-headers":String(r.headers["access-control-request-headers"]??"*")}),e.end()},"corsPreflight");exports.corsPreflight=corsPreflight,exports.PREFLIGHT_METHODS_NOROUTE="GET,HEAD,OPTIONS",exports.PREFLIGHT_METHODS_ROUTED="GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS";
@@ -21,4 +21,3 @@ export interface HandlerDeps {
21
21
  hooks: HooksLayer;
22
22
  }
23
23
  export declare function createHandler(deps: HandlerDeps): http.RequestListener;
24
- //# sourceMappingURL=handler.d.ts.map
@@ -1,183 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createHandler = createHandler;
4
- const manifest_1 = require("../manifest");
5
- const gateway_errors_1 = require("../gateway-errors");
6
- const discovery_1 = require("./discovery");
7
- const edge_1 = require("./edge");
8
- const observability_1 = require("./observability");
9
- const chooser_1 = require("./chooser");
10
- function createHandler(deps) {
11
- const { rt, obs, auth, proxy, hooks } = deps;
12
- const match = (req) => (0, manifest_1.matchRoute)(rt.routes, (req.headers.host || '').split(':')[0], req.url ?? '/');
13
- // Host-root infra: when a host only has PATH-mounted services (pure
14
- // microservices under api.<domain>/{prefix}), the gateway itself owns the
15
- // root — CORS, health aggregation + service discovery, like a real edge.
16
- const handleNoRoute = (req, res) => {
17
- // gateway-owned endpoints are cross-origin by design (the app calls
18
- // api.<domain>/health from app.<domain>) — answer CORS here; routed
19
- // paths inherit CORS from the services themselves.
20
- (0, edge_1.cors)(req, res);
21
- if (req.method === 'OPTIONS') {
22
- res.writeHead(204, {
23
- 'access-control-allow-methods': edge_1.PREFLIGHT_METHODS_NOROUTE,
24
- 'access-control-allow-headers': String(req.headers['access-control-request-headers'] ?? '*'),
25
- });
26
- res.end();
27
- return;
28
- }
29
- const host = (req.headers.host || '').split(':')[0];
30
- const mounted = rt.routes.filter((r) => r.host && (0, manifest_1.hostMatches)(r.host, host) && r.prefix);
31
- const url = (req.url ?? '/').split('?')[0];
32
- // The lens dashboard HOST ROOT → the multi-workspace chooser. The dashboard itself mounts at `/<key>`,
33
- // so the bare `/` is unrouted and lands here; serve the landing page listing every known workspace.
34
- if ((url === '/' || url === '/index.html' || url === '') &&
35
- rt.routes.some((r) => r.host && (0, manifest_1.hostMatches)(r.host, host) && r.project === observability_1.LENS_DASHBOARD_PROJECT)) {
36
- (0, chooser_1.serveChooser)(res, rt.wsKey);
37
- return;
38
- }
39
- if (mounted.length > 0 && (url === '/health' || url === '/healthz')) {
40
- const services = mounted.map((r) => ({
41
- project: r.project,
42
- prefix: r.prefix,
43
- pods: r.pool ? ((0, discovery_1.pickSock)(r.pool, 0), r.pool.socks.length) : undefined,
44
- state: r.svc?.state ?? (r.target ? 'up' : 'unknown'),
45
- }));
46
- const ok = services.every((s) => s.state !== 'down' || true);
47
- res.writeHead(ok ? 200 : 503, { 'content-type': 'application/json' });
48
- res.end(JSON.stringify({ status: 'ok', host, services }, null, 2));
49
- return;
50
- }
51
- if (mounted.length > 0 && url === '/.well-known/services') {
52
- res.writeHead(200, { 'content-type': 'application/json' });
53
- res.end(JSON.stringify({ host, services: mounted.map((r) => ({ prefix: r.prefix, project: r.project, internal: !!r.internal })) }, null, 2));
54
- return;
55
- }
56
- (0, edge_1.sendError)(res, req, 404, 'not_found', mounted.length > 0
57
- ? `No service mounted at ${url}. Mounted on ${host}: ${[...new Set(mounted.map((r) => r.prefix))].join(', ')} (+ /health, /.well-known/services)`
58
- : 'No gateway route for this hostname.');
59
- };
60
- const runPipeline = async (req, res) => {
61
- // 0. HTTP/2 carries the host in the `:authority` pseudo-header, NOT `host` — the
62
- // http2 compat layer exposes it as `req.authority` and omits `host` from `req.headers`.
63
- // Every downstream step (route match, trace, CORS) reads `req.headers.host`, so
64
- // normalize it here before anything else. No-op for HTTP/1.1 (host is already set).
65
- if (!req.headers.host) {
66
- const authority = req.authority ?? req.headers[':authority'];
67
- if (authority)
68
- req.headers.host = authority;
69
- }
70
- // 1. STRIP client-supplied trust headers before anything else: the gateway is
71
- // the ONLY party allowed to assert `x-internal-token` (came through me) and
72
- // `x-api-key-id` (validated caller identity). Without this, a keyless/TCP route
73
- // would leak a spoofed token and any public route would forward a spoofed caller
74
- // id to downstream audit. The gateway re-stamps them below where earned.
75
- for (const h of edge_1.GATEWAY_OWNED_HEADERS)
76
- delete req.headers[h];
77
- // 2. Mint a trace id for EVERY request (not just lens-traced ones): forwarded to the
78
- // pod (adopted as its traceId) and returned on the response — any request is traceable.
79
- (0, gateway_errors_1.ensureRequestId)(req);
80
- const trace = obs.beginTrace(req);
81
- if (trace) {
82
- obs.traceStep(trace, 'received', { host: trace.host, method: trace.method, url: trace.url });
83
- req.__lensmcpTrace = trace;
84
- }
85
- const ctx = hooks.httpContext(req, res, trace);
86
- try {
87
- // 3. onRequest (sees already-stripped headers; may short-circuit)
88
- if (hooks.has('onRequest')) {
89
- await hooks.run('onRequest', ctx);
90
- if (ctx.responded())
91
- return;
92
- }
93
- // 4. route match
94
- const route = match(req);
95
- if (!route) {
96
- handleNoRoute(req, res);
97
- return;
98
- }
99
- ctx.route = route;
100
- obs.traceStep(trace, 'route-match', {
101
- project: route.project,
102
- ...(route.prefix ? { prefix: route.prefix } : {}),
103
- ...(route.host ? { routeHost: route.host } : {}),
104
- ...(route.internal ? { internal: true } : {}),
105
- });
106
- // 7. CORS preflight on a ROUTED path: answer it HERE, BEFORE edge auth — an OPTIONS preflight
107
- // carries no token by spec, so the JWT (or x-api-key) enforcement below would 401 it and the
108
- // browser's CORS check fails. The matching real request still goes through auth normally.
109
- if (req.method === 'OPTIONS') {
110
- (0, edge_1.cors)(req, res);
111
- res.writeHead(204, {
112
- 'access-control-allow-methods': edge_1.PREFLIGHT_METHODS_ROUTED,
113
- 'access-control-allow-headers': String(req.headers['access-control-request-headers'] ?? '*'),
114
- });
115
- res.end();
116
- return;
117
- }
118
- // 8. CORS on EVERY routed response — including the 401/403/5xx the gateway generates ITSELF
119
- // below. Without this a gateway-generated error short-circuits before the upstream (which
120
- // carries CORS on success), so the browser sees the error WITHOUT an Access-Control-Allow-Origin
121
- // and reports a CORS failure that MASKS the real status. On success the upstream's CORS header
122
- // overwrites this one (http-proxy setHeader), so there's no duplicate.
123
- (0, edge_1.cors)(req, res);
124
- // 9. beforeAuth
125
- if (hooks.has('beforeAuth')) {
126
- await hooks.run('beforeAuth', ctx);
127
- if (ctx.responded())
128
- return;
129
- }
130
- // 10/11. auth + authz. internal.* validates the caller's api-key; public verifies the end-user
131
- // JWT + enforces per-route rules. Custom middleware (afterAuth) runs AFTER core auth, public ONLY.
132
- if (route.internal) {
133
- const v = auth.internal(req, route, trace);
134
- if (!v.ok) {
135
- obs.finishTrace(trace, route.project, v.status);
136
- (0, edge_1.sendError)(res, req, v.status, v.reason, v.detail);
137
- return;
138
- }
139
- ctx.caller = v.caller;
140
- }
141
- else {
142
- const v = auth.public(req, route, trace);
143
- if (!v.ok) {
144
- obs.finishTrace(trace, route.project, v.status);
145
- (0, edge_1.sendError)(res, req, v.status, v.reason, v.detail);
146
- return;
147
- }
148
- ctx.claims = v.claims;
149
- if (hooks.has('afterAuth')) {
150
- await hooks.run('afterAuth', ctx);
151
- if (ctx.responded())
152
- return;
153
- }
154
- }
155
- // 12. inject the target service's key so pods trust the gateway (pool routes, both branches)
156
- if (route.pool && rt.serviceKeys[route.project]) {
157
- req.headers['x-internal-token'] = rt.serviceKeys[route.project];
158
- }
159
- // 13. beforeForward (last chance to mutate headers/url)
160
- if (hooks.has('beforeForward')) {
161
- await hooks.run('beforeForward', ctx);
162
- if (ctx.responded())
163
- return;
164
- }
165
- // 15. onResponse — fire user handlers once the response closes (the built-in
166
- // recordEdge/finishTrace live in proxy.forward's own close handler).
167
- if (hooks.has('onResponse')) {
168
- res.on('close', () => { ctx.status = res.statusCode ?? 0; void hooks.run('onResponse', ctx); });
169
- }
170
- // 14. forward
171
- void proxy.forward(route, req, res);
172
- }
173
- catch (e) {
174
- // A hook (or the pipeline) threw — narrate via onError, then 500 if nobody responded.
175
- ctx.error = e;
176
- if (hooks.has('onError'))
177
- await hooks.run('onError', ctx);
178
- if (!ctx.responded())
179
- (0, edge_1.sendError)(res, req, 500, 'internal', e.message);
180
- }
181
- };
182
- return (req, res) => { void runPipeline(req, res); };
183
- }
1
+ "use strict";var E=Object.defineProperty;var d=(l,i)=>E(l,"name",{value:i,configurable:!0});var v=Object.defineProperty,h=d((l,i)=>v(l,"name",{value:i,configurable:!0}),"h");Object.defineProperty(exports,"__esModule",{value:!0}),exports.createHandler=createHandler;const manifest_1=require("../manifest"),gateway_errors_1=require("../gateway-errors"),discovery_1=require("./discovery"),edge_1=require("./edge"),observability_1=require("./observability"),chooser_1=require("./chooser");function createHandler(l){const{rt:i,obs:u,auth:p,proxy:f,hooks:a}=l,w=h(e=>(0,manifest_1.matchRoute)(i.routes,(e.headers.host||"").split(":")[0],e.url??"/"),"match"),m=h((e,o)=>{if((0,edge_1.cors)(e,o),e.method==="OPTIONS"){o.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_NOROUTE,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),o.end();return}const n=(e.headers.host||"").split(":")[0],s=i.routes.filter(r=>r.host&&(0,manifest_1.hostMatches)(r.host,n)&&r.prefix),t=(e.url??"/").split("?")[0];if((t==="/"||t==="/index.html"||t==="")&&i.routes.some(r=>r.host&&(0,manifest_1.hostMatches)(r.host,n)&&r.project===observability_1.LENS_DASHBOARD_PROJECT)){(0,chooser_1.serveChooser)(o,i.wsKey);return}if(s.length>0&&(t==="/health"||t==="/healthz")){const r=s.map(c=>({project:c.project,prefix:c.prefix,pods:c.pool?((0,discovery_1.pickSock)(c.pool,0),c.pool.socks.length):void 0,state:c.svc?.state??(c.target?"up":"unknown")})),_=r.every(c=>c.state!=="down"||!0);o.writeHead(_?200:503,{"content-type":"application/json"}),o.end(JSON.stringify({status:"ok",host:n,services:r},null,2));return}if(s.length>0&&t==="/.well-known/services"){o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({host:n,services:s.map(r=>({prefix:r.prefix,project:r.project,internal:!!r.internal}))},null,2));return}(0,edge_1.sendError)(o,e,404,"not_found",s.length>0?`No service mounted at ${t}. Mounted on ${n}: ${[...new Set(s.map(r=>r.prefix))].join(", ")} (+ /health, /.well-known/services)`:"No gateway route for this hostname.")},"handleNoRoute"),y=h(async(e,o)=>{if(!e.headers.host){const t=e.authority??e.headers[":authority"];t&&(e.headers.host=t)}for(const t of edge_1.GATEWAY_OWNED_HEADERS)delete e.headers[t];(0,gateway_errors_1.ensureRequestId)(e);const n=u.beginTrace(e);n&&(u.traceStep(n,"received",{host:n.host,method:n.method,url:n.url}),e.__lensmcpTrace=n);const s=a.httpContext(e,o,n);try{if(a.has("onRequest")&&(await a.run("onRequest",s),s.responded()))return;const t=w(e);if(!t){m(e,o);return}if(s.route=t,u.traceStep(n,"route-match",{project:t.project,...t.prefix?{prefix:t.prefix}:{},...t.host?{routeHost:t.host}:{},...t.internal?{internal:!0}:{}}),e.method==="OPTIONS"){(0,edge_1.cors)(e,o),o.writeHead(204,{"access-control-allow-methods":edge_1.PREFLIGHT_METHODS_ROUTED,"access-control-allow-headers":String(e.headers["access-control-request-headers"]??"*")}),o.end();return}if((0,edge_1.cors)(e,o),a.has("beforeAuth")&&(await a.run("beforeAuth",s),s.responded()))return;if(t.internal){const r=p.internal(e,t,n);if(!r.ok){u.finishTrace(n,t.project,r.status),(0,edge_1.sendError)(o,e,r.status,r.reason,r.detail);return}s.caller=r.caller}else{const r=p.public(e,t,n);if(!r.ok){u.finishTrace(n,t.project,r.status),(0,edge_1.sendError)(o,e,r.status,r.reason,r.detail);return}if(s.claims=r.claims,a.has("afterAuth")&&(await a.run("afterAuth",s),s.responded()))return}if(t.pool&&i.serviceKeys[t.project]&&(e.headers["x-internal-token"]=i.serviceKeys[t.project]),a.has("beforeForward")&&(await a.run("beforeForward",s),s.responded()))return;a.has("onResponse")&&o.on("close",()=>{s.status=o.statusCode??0,a.run("onResponse",s)}),f.forward(t,e,o)}catch(t){s.error=t,a.has("onError")&&await a.run("onError",s),s.responded()||(0,edge_1.sendError)(o,e,500,"internal",t.message)}},"runPipeline");return(e,o)=>{y(e,o)}}d(createHandler,"createHandler"),h(createHandler,"createHandler");
@@ -20,4 +20,3 @@ export interface HooksLayer {
20
20
  upgradeContext(req: http.IncomingMessage, socket: stream.Duplex, trace: GwTrace | undefined): HookContext;
21
21
  }
22
22
  export declare function createHooks(hooks: GatewayHooks): HooksLayer;
23
- //# sourceMappingURL=hooks.d.ts.map
@@ -1,55 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createHooks = createHooks;
4
- const edge_1 = require("./edge");
5
- // Terminal phases observe a request whose response is ALREADY complete, so
6
- // `responded()` is true by definition — they must run every handler regardless.
7
- // The request-flow phases short-circuit the moment a handler responds.
8
- const TERMINAL_PHASES = new Set(['onResponse', 'onError']);
9
- function createHooks(hooks) {
10
- const run = async (phase, ctx) => {
11
- const list = hooks[phase];
12
- if (!list || list.length === 0)
13
- return;
14
- const terminal = TERMINAL_PHASES.has(phase);
15
- for (const h of list) {
16
- if (!terminal && ctx.responded())
17
- return; // a request-flow hook already responded → stop
18
- await h(ctx);
19
- }
20
- };
21
- const has = (phase) => (hooks[phase]?.length ?? 0) > 0;
22
- const httpContext = (req, res, trace) => ({
23
- req,
24
- res,
25
- socket: undefined,
26
- trace,
27
- route: undefined,
28
- claims: undefined,
29
- caller: undefined,
30
- pod: undefined,
31
- error: undefined,
32
- status: undefined,
33
- sendError: (status, reason, detail) => (0, edge_1.sendError)(res, req, status, reason, detail),
34
- responded: () => res.writableEnded || res.headersSent,
35
- });
36
- const upgradeContext = (req, socket, trace) => ({
37
- req,
38
- res: undefined,
39
- socket,
40
- trace,
41
- route: undefined,
42
- claims: undefined,
43
- caller: undefined,
44
- pod: undefined,
45
- error: undefined,
46
- status: undefined,
47
- // No HTTP response on an upgrade — short-circuiting means destroying the socket.
48
- sendError: () => { try {
49
- socket.destroy();
50
- }
51
- catch { /* already gone */ } },
52
- responded: () => socket.destroyed,
53
- });
54
- return { run, has, httpContext, upgradeContext };
55
- }
1
+ "use strict";var u=Object.defineProperty;var i=(t,e)=>u(t,"name",{value:e,configurable:!0});var a=Object.defineProperty,n=i((t,e)=>a(t,"name",{value:e,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.createHooks=createHooks;const edge_1=require("./edge"),TERMINAL_PHASES=new Set(["onResponse","onError"]);function createHooks(t){return{run:n(async(e,r)=>{const o=t[e];if(!o||o.length===0)return;const d=TERMINAL_PHASES.has(e);for(const s of o){if(!d&&r.responded())return;await s(r)}},"run"),has:n(e=>(t[e]?.length??0)>0,"has"),httpContext:n((e,r,o)=>({req:e,res:r,socket:void 0,trace:o,route:void 0,claims:void 0,caller:void 0,pod:void 0,error:void 0,status:void 0,sendError:n((d,s,c)=>(0,edge_1.sendError)(r,e,d,s,c),"sendError"),responded:n(()=>r.writableEnded||r.headersSent,"responded")}),"httpContext"),upgradeContext:n((e,r,o)=>({req:e,res:void 0,socket:r,trace:o,route:void 0,claims:void 0,caller:void 0,pod:void 0,error:void 0,status:void 0,sendError:n(()=>{try{r.destroy()}catch{}},"sendError"),responded:n(()=>r.destroyed,"responded")}),"upgradeContext")}}i(createHooks,"createHooks"),n(createHooks,"createHooks");
@@ -57,4 +57,3 @@ export interface LensChildren {
57
57
  export declare function createLensChildren(rt: GatewayRuntime, obs: Observability, options: GatewayRuntimeOptions, deps?: {
58
58
  isPortFree?: (port: number) => Promise<boolean>;
59
59
  }): LensChildren;
60
- //# sourceMappingURL=lens-children.d.ts.map