@nylorun/runtime 0.16.0-beta → 0.19.0-beta

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 (256) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/README.md +105 -63
  3. package/dist/adapters/execution/restate.d.ts +1 -3
  4. package/dist/adapters/execution/restate.js +4 -31
  5. package/dist/adapters/replication/pgoutput.js +1 -1
  6. package/dist/adapters/sandbox/local.js +1 -1
  7. package/dist/adapters/sandbox/virtual.js +1 -1
  8. package/dist/api/ag-ui/endpoint.js +1 -2
  9. package/dist/api/ag-ui/routes.d.ts +1 -1
  10. package/dist/api/ag-ui/routes.js +11 -13
  11. package/dist/api/ag-ui/translate.d.ts +1 -3
  12. package/dist/api/ag-ui/translate.js +2 -17
  13. package/dist/api/components.d.ts +4783 -2588
  14. package/dist/api/components.js +19 -21
  15. package/dist/api/gate/routes.d.ts +7 -8
  16. package/dist/api/gate/routes.js +58 -52
  17. package/dist/api/http/app.d.ts +6 -0
  18. package/dist/api/http/app.js +20 -14
  19. package/dist/api/http/define.d.ts +22 -13
  20. package/dist/api/http/define.js +43 -39
  21. package/dist/api/http/routes/access.d.ts +3 -19
  22. package/dist/api/http/routes/access.js +25 -184
  23. package/dist/api/http/routes/artifacts.js +3 -7
  24. package/dist/api/http/routes/files.d.ts +8 -0
  25. package/dist/api/http/routes/files.js +77 -0
  26. package/dist/api/http/routes/keys.d.ts +10 -0
  27. package/dist/api/http/routes/keys.js +64 -0
  28. package/dist/api/http/routes/me.d.ts +13 -0
  29. package/dist/api/http/routes/me.js +48 -0
  30. package/dist/api/http/routes/reads.d.ts +66 -0
  31. package/dist/api/http/routes/reads.js +127 -0
  32. package/dist/api/http/routes/sandboxes.d.ts +2 -2
  33. package/dist/api/http/routes/sandboxes.js +8 -7
  34. package/dist/api/http/routes/sessions.js +31 -20
  35. package/dist/api/http/routes/tenant.js +15 -18
  36. package/dist/api/http/routes/vaults.d.ts +13 -3
  37. package/dist/api/http/routes/vaults.js +136 -64
  38. package/dist/api/openapi.d.ts +10 -11
  39. package/dist/api/openapi.js +292 -68
  40. package/dist/artifacts/links.js +6 -6
  41. package/dist/artifacts/service.js +1 -1
  42. package/dist/core/flow-host.d.ts +44 -23
  43. package/dist/core/flow-host.js +88 -106
  44. package/dist/core/provider.d.ts +4 -1
  45. package/dist/core/provider.js +6 -1
  46. package/dist/core/sandbox-routes.d.ts +0 -9
  47. package/dist/core/sandbox-routes.js +2 -21
  48. package/dist/execution/memory.d.ts +4 -5
  49. package/dist/execution/memory.js +11 -25
  50. package/dist/execution/types.d.ts +3 -33
  51. package/dist/execution/types.js +2 -12
  52. package/dist/gates/http-tool.d.ts +86 -0
  53. package/dist/gates/http-tool.js +197 -0
  54. package/dist/gates/mcp-handler.d.ts +3 -0
  55. package/dist/gates/mcp-handler.js +6 -4
  56. package/dist/gates/meter.d.ts +2 -2
  57. package/dist/gates/meter.js +6 -0
  58. package/dist/gates/tenant-vaults.d.ts +19 -14
  59. package/dist/gates/tenant-vaults.js +17 -12
  60. package/dist/gates/tool-calls.d.ts +7 -15
  61. package/dist/gates/tool-calls.js +4 -4
  62. package/dist/gates/tool-client.d.ts +1 -1
  63. package/dist/gates/tool-client.js +23 -47
  64. package/dist/gates/tool-contract.d.ts +27 -39
  65. package/dist/gates/tool-contract.js +30 -21
  66. package/dist/gates/tool-gate.d.ts +25 -24
  67. package/dist/gates/tool-gate.js +11 -7
  68. package/dist/harness/calls.d.ts +10 -4
  69. package/dist/harness/calls.js +15 -6
  70. package/dist/harness/executors.d.ts +1 -1
  71. package/dist/harness/executors.js +17 -12
  72. package/dist/harness/main.d.ts +2 -2
  73. package/dist/harness/main.js +5 -13
  74. package/dist/harness/service.d.ts +4 -5
  75. package/dist/harness/service.js +9 -2
  76. package/dist/harness-api/in-process.js +2 -2
  77. package/dist/harness-api/record.d.ts +6 -3
  78. package/dist/harness-api/record.js +65 -72
  79. package/dist/harness-api/server.d.ts +1 -9
  80. package/dist/harness-api/server.js +19 -17
  81. package/dist/harness-api/start.js +1 -5
  82. package/dist/harness-api/workspace.js +2 -3
  83. package/dist/harness-api/ws-server.js +1 -1
  84. package/dist/host/app.d.ts +2 -10
  85. package/dist/host/app.js +24 -44
  86. package/dist/host/config-for.d.ts +5 -5
  87. package/dist/host/config-for.js +2 -3
  88. package/dist/host/config.d.ts +0 -11
  89. package/dist/host/create-host.d.ts +3 -40
  90. package/dist/host/create-host.js +18 -91
  91. package/dist/host/environment.d.ts +0 -3
  92. package/dist/host/environment.js +0 -9
  93. package/dist/host/gates.d.ts +4 -1
  94. package/dist/host/gates.js +9 -3
  95. package/dist/host/http.d.ts +1 -2
  96. package/dist/host/http.js +1 -7
  97. package/dist/host/index.d.ts +2 -2
  98. package/dist/host/index.js +2 -2
  99. package/dist/host/main.js +55 -40
  100. package/dist/host/operate.d.ts +29 -0
  101. package/dist/host/operate.js +223 -0
  102. package/dist/host/stack-config.d.ts +23 -20
  103. package/dist/host/stack-config.js +28 -44
  104. package/dist/index.d.ts +4 -1
  105. package/dist/index.js +3 -1
  106. package/dist/infra/workers.d.ts +1 -1
  107. package/dist/keys/client.js +9 -1
  108. package/dist/keys/keys.d.ts +12 -2
  109. package/dist/keys/keys.js +10 -2
  110. package/dist/management-openapi.json +6491 -0
  111. package/dist/mcp/connect.d.ts +8 -4
  112. package/dist/mcp/connect.js +8 -27
  113. package/dist/mcp/pool.d.ts +6 -9
  114. package/dist/mcp/pool.js +8 -18
  115. package/dist/mcp/snapshot.d.ts +8 -2
  116. package/dist/mcp/snapshot.js +29 -2
  117. package/dist/media.d.ts +1 -1
  118. package/dist/media.js +1 -1
  119. package/dist/model/pi-model.js +3 -0
  120. package/dist/openapi.json +6228 -15615
  121. package/dist/reads/access.d.ts +4 -0
  122. package/dist/reads/access.js +12 -0
  123. package/dist/reads/cursor.d.ts +11 -0
  124. package/dist/reads/cursor.js +80 -0
  125. package/dist/reads/types.d.ts +25 -0
  126. package/dist/reads/types.js +1 -0
  127. package/dist/sandbox/manager.d.ts +16 -0
  128. package/dist/sandbox/manager.js +40 -0
  129. package/dist/sandbox/session-sandbox.js +13 -3
  130. package/dist/sandbox/skills.d.ts +13 -0
  131. package/dist/sandbox/skills.js +46 -0
  132. package/dist/sandbox/types.d.ts +2 -2
  133. package/dist/store/ownership.d.ts +9 -0
  134. package/dist/store/ownership.js +13 -0
  135. package/dist/store/postgres/connect.d.ts +2 -0
  136. package/dist/store/postgres/connect.js +29 -0
  137. package/dist/store/postgres/drizzle/0008_installation_vaults.sql +2 -0
  138. package/dist/store/postgres/drizzle/0009_oauth_pending.sql +19 -0
  139. package/dist/store/postgres/drizzle/0010_oss_auth_removals.sql +3 -0
  140. package/dist/store/postgres/drizzle/0011_key_roles.sql +3 -0
  141. package/dist/store/postgres/drizzle/0012_session_reads.sql +8 -0
  142. package/dist/store/postgres/drizzle/0013_definition_files.sql +16 -0
  143. package/dist/store/postgres/drizzle/0014_action_endpoints_removed.sql +2 -0
  144. package/dist/store/postgres/drizzle/meta/_journal.json +49 -0
  145. package/dist/store/postgres/reads.d.ts +3 -0
  146. package/dist/store/postgres/reads.js +272 -0
  147. package/dist/store/postgres/schema.d.ts +423 -594
  148. package/dist/store/postgres/schema.js +84 -101
  149. package/dist/store/postgres/store.js +96 -248
  150. package/dist/store/postgres/tenant.d.ts +34 -2
  151. package/dist/store/postgres/tenant.js +16 -32
  152. package/dist/store/types.d.ts +44 -119
  153. package/dist/store/types.js +0 -1
  154. package/dist/streams/control.d.ts +0 -7
  155. package/dist/streams/control.js +0 -13
  156. package/dist/streams/types.d.ts +2 -20
  157. package/dist/streams/types.js +1 -1
  158. package/dist/tenant/advance.d.ts +3 -3
  159. package/dist/tenant/advance.js +10 -7
  160. package/dist/tenant/auth.d.ts +24 -15
  161. package/dist/tenant/auth.js +44 -55
  162. package/dist/tenant/cause.d.ts +3 -3
  163. package/dist/tenant/cause.js +1 -1
  164. package/dist/tenant/commands.d.ts +2 -18
  165. package/dist/tenant/commands.js +38 -179
  166. package/dist/tenant/context.d.ts +33 -45
  167. package/dist/tenant/definition-files.d.ts +24 -0
  168. package/dist/tenant/definition-files.js +103 -0
  169. package/dist/tenant/effects.d.ts +20 -18
  170. package/dist/tenant/effects.js +59 -133
  171. package/dist/tenant/ephemeral.d.ts +21 -8
  172. package/dist/tenant/ephemeral.js +11 -12
  173. package/dist/tenant/host-token.js +5 -5
  174. package/dist/tenant/identity-file.d.ts +75 -0
  175. package/dist/tenant/identity-file.js +202 -0
  176. package/dist/tenant/issuers.d.ts +48 -0
  177. package/dist/tenant/issuers.js +311 -0
  178. package/dist/tenant/jwt.js +3 -3
  179. package/dist/tenant/module.d.ts +1 -4
  180. package/dist/tenant/module.js +3 -12
  181. package/dist/tenant/operator-keys.d.ts +44 -0
  182. package/dist/tenant/operator-keys.js +87 -0
  183. package/dist/tenant/outbound.d.ts +40 -1
  184. package/dist/tenant/outbound.js +167 -18
  185. package/dist/tenant/paths.d.ts +1 -1
  186. package/dist/tenant/paths.js +1 -3
  187. package/dist/tenant/principals.d.ts +13 -13
  188. package/dist/tenant/principals.js +35 -36
  189. package/dist/tenant/run-token.js +6 -6
  190. package/dist/tenant/runtime.d.ts +5 -3
  191. package/dist/tenant/runtime.js +29 -15
  192. package/dist/tenant/sandboxes.d.ts +9 -6
  193. package/dist/tenant/sandboxes.js +16 -5
  194. package/dist/tenant/scheduler.d.ts +1 -5
  195. package/dist/tenant/scheduler.js +2 -5
  196. package/dist/tenant/session-streams.d.ts +8 -11
  197. package/dist/tenant/session-streams.js +48 -32
  198. package/dist/tenant/session.d.ts +8 -41
  199. package/dist/tenant/session.js +0 -37
  200. package/dist/tenant/sessions.d.ts +2 -2
  201. package/dist/tenant/sessions.js +17 -9
  202. package/dist/tenant/signing-keys.d.ts +3 -2
  203. package/dist/tenant/signing-keys.js +5 -5
  204. package/dist/tenant/skill-tool.d.ts +20 -0
  205. package/dist/tenant/skill-tool.js +72 -0
  206. package/dist/tenant/slim.d.ts +1 -1
  207. package/dist/tenant/slim.js +1 -1
  208. package/dist/tenant/status.js +7 -12
  209. package/dist/tenant/store-pg.d.ts +15 -0
  210. package/dist/tenant/store-pg.js +7 -3
  211. package/dist/tenant/streams.d.ts +3 -11
  212. package/dist/tenant/streams.js +2 -29
  213. package/dist/tenant/sweep.js +0 -5
  214. package/dist/tenant/transcript.d.ts +2 -2
  215. package/dist/tenant/transcript.js +2 -2
  216. package/dist/tenant/types.d.ts +33 -19
  217. package/dist/tenant/worker.d.ts +1 -3
  218. package/dist/tenant/worker.js +3 -8
  219. package/dist/vault/crypto.d.ts +7 -0
  220. package/dist/vault/crypto.js +16 -0
  221. package/dist/vault/oauth.d.ts +55 -0
  222. package/dist/vault/oauth.js +186 -0
  223. package/dist/vault/service.d.ts +54 -7
  224. package/dist/vault/service.js +261 -17
  225. package/dist/vault/sources.d.ts +60 -0
  226. package/dist/vault/sources.js +196 -0
  227. package/dist/version.d.ts +1 -1
  228. package/dist/version.js +1 -1
  229. package/package.json +5 -4
  230. package/dist/admin-openapi.json +0 -604
  231. package/dist/api/http/routes/actions.d.ts +0 -8
  232. package/dist/api/http/routes/actions.js +0 -76
  233. package/dist/api/http/routes/endpoints.d.ts +0 -7
  234. package/dist/api/http/routes/endpoints.js +0 -100
  235. package/dist/host/admin-api.d.ts +0 -23
  236. package/dist/host/admin-api.js +0 -74
  237. package/dist/host/cors.d.ts +0 -27
  238. package/dist/host/cors.js +0 -64
  239. package/dist/mcp/stdio.d.ts +0 -17
  240. package/dist/mcp/stdio.js +0 -82
  241. package/dist/tenant/access-policy.d.ts +0 -30
  242. package/dist/tenant/access-policy.js +0 -52
  243. package/dist/tenant/actions.d.ts +0 -14
  244. package/dist/tenant/actions.js +0 -29
  245. package/dist/tenant/browser.d.ts +0 -15
  246. package/dist/tenant/browser.js +0 -39
  247. package/dist/tenant/delivery-token.d.ts +0 -41
  248. package/dist/tenant/delivery-token.js +0 -104
  249. package/dist/tenant/delivery.d.ts +0 -62
  250. package/dist/tenant/delivery.js +0 -481
  251. package/dist/tenant/endpoints.d.ts +0 -67
  252. package/dist/tenant/endpoints.js +0 -90
  253. package/dist/tenant/subject-limits.d.ts +0 -16
  254. package/dist/tenant/subject-limits.js +0 -45
  255. package/dist/tenant/tokens.d.ts +0 -14
  256. package/dist/tenant/tokens.js +0 -187
@@ -15,6 +15,8 @@
15
15
  * `NYLORUN_GATES_TOKEN`. In a container, loop requires the gate: the loop
16
16
  * process must never hold a model credential. `egress` (egress-gate, F7.2) joins gates and keys
17
17
  * in the gateway and parses its listener (`NYLORUN_EGRESS_LISTEN_*`, default `0.0.0.0:4200`).
18
+ * Only gates reads the operator's credential resolver (`NYLORUN_RESOLVER_URL`,
19
+ * `NYLORUN_RESOLVER_TOKEN`, F9 C1): remote MCP calls are authorized in the gateway.
18
20
  *
19
21
  * `harness` (F6.2) runs alone: it holds the harness credential and nothing else. It connects to
20
22
  * core's Harness API listener (`NYLORUN_HARNESS_URL`, `NYLORUN_HARNESS_TOKEN`), calls models and
@@ -34,9 +36,9 @@
34
36
  * The Postgres, Restate and S2 endpoints are parsed and validated here;
35
37
  * `infra/*` builds the clients from them. So is the Object store (`NYLORUN_OBJECT_STORE_*`),
36
38
  * which every service may read; `host/main.ts` builds the `BlobStore` from it. So is who the Host's Tenant is when its database
37
- * holds none yet (`NYLORUN_TENANT_ID`, `NYLORUN_TENANT_NAME`, `NYLORUN_DERIVED_PRINCIPALS`).
39
+ * holds none yet (`NYLORUN_TENANT_ID`, `NYLORUN_TENANT_NAME`).
38
40
  */
39
- import { DERIVED_PRINCIPAL_ID_PATTERN, isTenantId } from "@nylorun/core/compatibility";
41
+ import { isTenantId } from "@nylorun/core/compatibility";
40
42
  import { blockedAddresses } from "../sandbox/pods/network-gate.js";
41
43
  export const RUNTIME_SERVICES = ["core", "loop", "gates", "keys", "egress", "harness"];
42
44
  /**
@@ -223,30 +225,6 @@ function parseListen(env) {
223
225
  const allowedHosts = [...new Set([...explicit, ...loopbackForms(port)])];
224
226
  return { host, port, allowedHosts };
225
227
  }
226
- function parseAdminListen(env) {
227
- const rawPort = read(env, "NYLORUN_ADMIN_LISTEN_PORT");
228
- const rawHost = read(env, "NYLORUN_ADMIN_LISTEN_HOST");
229
- const rawAllowed = read(env, "NYLORUN_ADMIN_ALLOWED_HOSTS");
230
- if (rawPort === undefined) {
231
- if (rawHost !== undefined || rawAllowed !== undefined)
232
- throw new StackConfigError("NYLORUN_ADMIN_LISTEN_PORT is required with NYLORUN_ADMIN_LISTEN_HOST or NYLORUN_ADMIN_ALLOWED_HOSTS");
233
- return undefined;
234
- }
235
- const host = rawHost ?? DEFAULT_CONTAINER_LISTEN_HOST;
236
- if (/\s|\//.test(host))
237
- throw new StackConfigError(`NYLORUN_ADMIN_LISTEN_HOST is not an address: ${host}`);
238
- const port = parsePort("NYLORUN_ADMIN_LISTEN_PORT", rawPort);
239
- const explicit = rawAllowed === undefined
240
- ? []
241
- : rawAllowed
242
- .split(",")
243
- .map((entry) => entry.trim())
244
- .filter((entry) => entry !== "")
245
- .map((entry) => normalizeAllowedHost("NYLORUN_ADMIN_ALLOWED_HOSTS", entry));
246
- if (explicit.length === 0 && !isLoopbackAddress(host))
247
- throw new StackConfigError(`NYLORUN_ADMIN_ALLOWED_HOSTS is required when NYLORUN_ADMIN_LISTEN_HOST is ${host}: list the Host headers operators send, e.g. runtime:${port},localhost:<published port>`);
248
- return { host, port, allowedHosts: [...new Set([...explicit, ...loopbackForms(port)])] };
249
- }
250
228
  const IDENTITY_KEY = /^publickeyv1_[1-9A-HJ-NP-Za-km-z]{32,64}$/;
251
229
  function parseIdentityKeys(env) {
252
230
  const raw = read(env, "NYLORUN_RESTATE_IDENTITY_KEY");
@@ -269,15 +247,12 @@ export function parseStackConfig(env, argv) {
269
247
  // The image sets NYLORUN_LISTEN_*: only the API's processes read them.
270
248
  const servesApi = services.has("core") || services.has("loop");
271
249
  const listen = servesApi ? parseListen(env) : undefined;
272
- const operator = servesApi ? parseAdminListen(env) : undefined;
273
250
  const gates = services.has("gates") || services.has("keys") ? parseGates(env) : undefined;
274
251
  const egress = services.has("egress") ? parseEgress(env) : undefined;
275
- // The gates service's clients: the loop's model and tool calls, and core's endpoint pings.
252
+ // The gates service's clients: the loop's model and tool calls.
276
253
  const modelGate = servesApi ? parseModelGate(env) : undefined;
277
254
  // The keys service is the gateway's unless NYLORUN_KEYS_URL names another listener.
278
255
  const keys = servesApi ? (parseKeysEndpoint(env) ?? modelGate) : undefined;
279
- if (operator && listen && operator.port === listen.port)
280
- throw new StackConfigError("NYLORUN_ADMIN_LISTEN_PORT must differ from NYLORUN_LISTEN_PORT");
281
256
  if (services.has("loop") && listen && !modelGate)
282
257
  throw new StackConfigError("NYLORUN_GATES_URL is required for the loop service in a container: model calls go through the gates service (the gateway container), so the loop never holds a model credential. Set NYLORUN_GATES_URL and NYLORUN_GATES_TOKEN (`nylorun start` sets both)");
283
258
  const rawPacking = read(env, "NYLORUN_PACKING");
@@ -318,18 +293,14 @@ export function parseStackConfig(env, argv) {
318
293
  if (restateIdentityKeys)
319
294
  endpoints.restateIdentityKeys = restateIdentityKeys;
320
295
  const publicUrl = parseUrl(env, "NYLORUN_PUBLIC_URL", http)?.replace(/\/+$/, "");
321
- const rawBrowser = read(env, "NYLORUN_BROWSER_ACCESS");
322
- if (rawBrowser !== undefined && rawBrowser !== "on" && rawBrowser !== "off")
323
- throw new StackConfigError(`NYLORUN_BROWSER_ACCESS must be on or off, not ${rawBrowser}`);
324
296
  const harnessMode = servesApi ? parseHarnessMode(env) : undefined;
325
297
  const sandboxes = servesApi ? parseSandboxes(env) : undefined;
326
298
  // Pods connect to the Harness API listener even when the Tenant runs its own harness.
327
299
  const harnessListener = harnessMode === "remote" || sandboxes
328
300
  ? parseHarnessListener(env, harnessMode === "remote")
329
301
  : undefined;
330
- if (harnessListener &&
331
- [listen?.port, operator?.port].includes(harnessListener.listen.port))
332
- throw new StackConfigError("NYLORUN_HARNESS_LISTEN_PORT must differ from NYLORUN_LISTEN_PORT and NYLORUN_ADMIN_LISTEN_PORT");
302
+ if (harnessListener && listen?.port === harnessListener.listen.port)
303
+ throw new StackConfigError("NYLORUN_HARNESS_LISTEN_PORT must differ from NYLORUN_LISTEN_PORT");
333
304
  const delivery = parseDelivery(env);
334
305
  const tenant = servesApi ? parseTenant(env) : undefined;
335
306
  const objectStore = parseObjectStore(env);
@@ -344,11 +315,9 @@ export function parseStackConfig(env, argv) {
344
315
  ...(listen ? { listen } : {}),
345
316
  endpoints,
346
317
  ...(publicUrl ? { publicUrl } : {}),
347
- ...(rawBrowser === undefined ? {} : { browserAccess: rawBrowser === "on" }),
348
318
  ...(harnessMode ? { harnessMode } : {}),
349
319
  ...(harnessListener ? { harnessListener } : {}),
350
320
  ...(sandboxes ? { sandboxes } : {}),
351
- ...(operator ? { operator } : {}),
352
321
  ...(delivery ? { delivery } : {}),
353
322
  ...(tenant ? { tenant } : {}),
354
323
  ...(objectStore ? { objectStore } : {}),
@@ -380,15 +349,13 @@ function parseTenant(env) {
380
349
  const id = read(env, "NYLORUN_TENANT_ID");
381
350
  if (id !== undefined && !isTenantId(id))
382
351
  throw new StackConfigError(`NYLORUN_TENANT_ID must be a Tenant id (tn_ and 26 Crockford characters), not ${id}`);
383
- const raw = read(env, "NYLORUN_DERIVED_PRINCIPALS");
384
- const derivedPrincipals = raw === undefined ? ["project"] : raw.split(",").map((entry) => entry.trim());
385
- for (const principal of derivedPrincipals)
386
- if (!DERIVED_PRINCIPAL_ID_PATTERN.test(principal) || principal === "studio")
387
- throw new StackConfigError(`NYLORUN_DERIVED_PRINCIPALS has '${principal}': each entry must match ${DERIVED_PRINCIPAL_ID_PATTERN} and not be studio`);
352
+ const identityFile = read(env, "NYLORUN_IDENTITY_FILE");
353
+ const managementKeyFile = read(env, "NYLORUN_MANAGEMENT_KEY_FILE");
388
354
  return {
389
355
  ...(id ? { id } : {}),
390
356
  name: read(env, "NYLORUN_TENANT_NAME") ?? "default",
391
- derivedPrincipals: [...new Set(derivedPrincipals)],
357
+ ...(identityFile ? { identityFile } : {}),
358
+ ...(managementKeyFile ? { managementKeyFile } : {}),
392
359
  };
393
360
  }
394
361
  const GATES_TOKEN = /^[0-9a-f]{64,}$/i;
@@ -542,11 +509,28 @@ function parseGates(env) {
542
509
  throw new StackConfigError("NYLORUN_GATES_TOKEN is required for --service gates: the token the loop presents (`nylorun start` sets it)");
543
510
  if (!GATES_TOKEN.test(token))
544
511
  throw new StackConfigError("NYLORUN_GATES_TOKEN must be at least 32 bytes as hex");
512
+ const resolver = parseResolver(env);
545
513
  return {
546
514
  listen: { host, port, allowedHosts: [...new Set([...explicit, ...loopbackForms(port)])] },
547
515
  token,
516
+ ...(resolver ? { resolver } : {}),
548
517
  };
549
518
  }
519
+ /** `GatesConfig.resolver` from `NYLORUN_RESOLVER_URL` and `NYLORUN_RESOLVER_TOKEN`: both or neither. */
520
+ function parseResolver(env) {
521
+ const url = parseUrl(env, "NYLORUN_RESOLVER_URL", ["http:", "https:"]);
522
+ const token = read(env, "NYLORUN_RESOLVER_TOKEN");
523
+ if (url === undefined) {
524
+ if (token !== undefined)
525
+ throw new StackConfigError("NYLORUN_RESOLVER_TOKEN is set without NYLORUN_RESOLVER_URL: set the URL of your credential resolver");
526
+ return undefined;
527
+ }
528
+ if (token === undefined)
529
+ throw new StackConfigError("NYLORUN_RESOLVER_TOKEN is required with NYLORUN_RESOLVER_URL: the bearer the gateway presents to your credential resolver");
530
+ if (/\s/.test(token))
531
+ throw new StackConfigError("NYLORUN_RESOLVER_TOKEN cannot contain whitespace");
532
+ return { url, token };
533
+ }
550
534
  /** `StackConfig.egress` from `NYLORUN_EGRESS_LISTEN_*`. CONNECT has no Host header to check. */
551
535
  function parseEgress(env) {
552
536
  const host = read(env, "NYLORUN_EGRESS_LISTEN_HOST") ?? DEFAULT_CONTAINER_LISTEN_HOST;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,13 @@
1
1
  export { openTenantRuntime, type TenantOpenHooks, } from "./tenant/runtime.js";
2
2
  export { startEphemeralRuntime, type StartEphemeralRuntimeOptions, type EphemeralRuntime, } from "./tenant/ephemeral.js";
3
+ export { parseIdentityFile, IdentityFileError, type TrustedIssuerConfig, } from "./tenant/identity-file.js";
4
+ export { createTrustedIssuers, type TrustedIssuers, type TrustedIssuersOptions, } from "./tenant/issuers.js";
3
5
  export type { TenantConfig, TenantHandle, TenantPaths, Logger, OpenTenantRuntime, } from "./tenant/types.js";
4
6
  export { scriptedModel, gatewayModel, type ModelProvider } from "./core/provider.js";
7
+ export type { ResolverConfig } from "./vault/sources.js";
5
8
  export type { RuntimeAgent } from "./contracts.js";
6
9
  export { IMAGE_MEDIA_TYPES, MAX_IMAGE_BYTES, decodeImageBase64, validateImageBytes, } from "./media.js";
7
10
  export type { RuntimeModelAdapter } from "./contracts.js";
8
- export { baselineEnvironment, hostProcessEnvironment, tenantChildEnvironment, } from "./host/environment.js";
11
+ export { baselineEnvironment, hostProcessEnvironment, } from "./host/environment.js";
9
12
  export type { HostProcessPathInputs } from "./host/environment.js";
10
13
  export type { HostConfigFile, HostCredentialsFile, } from "./host/config.js";
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  export { openTenantRuntime, } from "./tenant/runtime.js";
2
2
  export { startEphemeralRuntime, } from "./tenant/ephemeral.js";
3
+ export { parseIdentityFile, IdentityFileError, } from "./tenant/identity-file.js";
4
+ export { createTrustedIssuers, } from "./tenant/issuers.js";
3
5
  export { scriptedModel, gatewayModel } from "./core/provider.js";
4
6
  export { IMAGE_MEDIA_TYPES, MAX_IMAGE_BYTES, decodeImageBase64, validateImageBytes, } from "./media.js";
5
- export { baselineEnvironment, hostProcessEnvironment, tenantChildEnvironment, } from "./host/environment.js";
7
+ export { baselineEnvironment, hostProcessEnvironment, } from "./host/environment.js";
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * | Services | Serves | `execution.start` |
5
5
  * | --- | --- | --- |
6
- * | `core` | Tenant API, Admin API, SSE | **never**: wakes, timers and sweep arming go through Restate's ingress, which needs no Worker endpoint |
6
+ * | `core` | Runtime and Management APIs, SSE | **never**: wakes, timers and sweep arming go through Restate's ingress, which needs no Worker endpoint |
7
7
  * | `loop` | the Restate endpoint (`NylorunSession.advance`, `NylorunTenant.sweep`, timers) | yes |
8
8
  * | `core,loop` | both (the local stack's `runtime` container) | yes |
9
9
  *
@@ -12,10 +12,18 @@ import { KEYS_PATH } from "./contract.js";
12
12
  import { KEYS_OPERATIONS } from "./keys.js";
13
13
  /** Signing and vault writes are short; anything slower is a gateway in trouble. */
14
14
  const KEYS_TIMEOUT_MS = 30_000;
15
+ /**
16
+ * MCP OAuth connect calls the authorization server several times (discovery, registration, the
17
+ * code exchange), each bounded by `guardedFetch`'s 30 s: these wait longer.
18
+ */
19
+ const SLOW_OPERATIONS = {
20
+ startOAuth: 120_000,
21
+ finishOAuth: 60_000,
22
+ };
15
23
  export function httpKeys(options) {
16
24
  const where = new URL(options.url).origin;
17
- const timeoutMs = options.timeoutMs ?? KEYS_TIMEOUT_MS;
18
25
  function call(operation, args) {
26
+ const timeoutMs = Math.max(options.timeoutMs ?? KEYS_TIMEOUT_MS, SLOW_OPERATIONS[operation] ?? 0);
19
27
  const url = new URL(`${KEYS_PATH}/${operation}`, options.url);
20
28
  const send = url.protocol === "https:" ? httpsRequest : httpRequest;
21
29
  const payload = Buffer.from(JSON.stringify({ args }), "utf8");
@@ -1,7 +1,7 @@
1
1
  import type { CreateCredentialRequest, CredentialInfo, HostModelView, PutHostModelRequest, RotateCredentialRequest, SelectHostModelRequest, SigningKeyView } from "@nylorun/core/contracts";
2
2
  import type { SessionStore } from "../store/types.js";
3
3
  import { type SigningKeys } from "../tenant/signing-keys.js";
4
- import type { VaultService } from "../vault/service.js";
4
+ import type { FinishOAuthInput, StartOAuthInput, VaultService } from "../vault/service.js";
5
5
  /** One JWT to sign: its `typ` and every claim, `iss`, `aud`, `sub`, `iat`, `exp` and `jti` included. */
6
6
  export interface SignRequest {
7
7
  readonly typ: string;
@@ -26,9 +26,19 @@ export interface Keys {
26
26
  }): Promise<SigningKeyView[]>;
27
27
  /** Creates the current and standby keys when the Tenant has none. */
28
28
  ensureSigningKeys(): Promise<void>;
29
+ /** Starts an MCP OAuth connect into an installation vault (`VaultService.startOAuth`). */
30
+ startOAuth(input: StartOAuthInput): Promise<{
31
+ authorizeUrl: string;
32
+ expiresAt: string;
33
+ }>;
34
+ /** Finishes one from its callback (`VaultService.finishOAuth`). */
35
+ finishOAuth(input: FinishOAuthInput): Promise<{
36
+ vaultId: string;
37
+ credentialId: string;
38
+ }>;
29
39
  }
30
40
  /** The operations, by the name the HTTP route carries. */
31
- export declare const KEYS_OPERATIONS: readonly ["createCredential", "rotateCredential", "putHostModel", "selectHostModel", "sign", "rotateSigningKeys", "ensureSigningKeys"];
41
+ export declare const KEYS_OPERATIONS: readonly ["createCredential", "rotateCredential", "putHostModel", "selectHostModel", "sign", "rotateSigningKeys", "ensureSigningKeys", "startOAuth", "finishOAuth"];
32
42
  export type KeysOperation = (typeof KEYS_OPERATIONS)[number];
33
43
  export interface InProcessKeysOptions {
34
44
  readonly store: SessionStore;
package/dist/keys/keys.js CHANGED
@@ -1,10 +1,14 @@
1
1
  /**
2
2
  * The keys seam (blueprint §14, F4.2): everything that needs the vault key. Vault writes that
3
3
  * touch a secret (creating and rotating a credential, setting and selecting the host model;
4
- * rotation and selection decrypt the old secret first) and all token signing (subject and
5
- * delivery tokens, signing-key rotation) run here, whole, so the process that calls them never
4
+ * rotation and selection decrypt the old secret first) and all token signing (capability
5
+ * links, run and host tokens, signing-key rotation) run here, whole, so the process that calls them never
6
6
  * holds the key or a private signing key.
7
7
  *
8
+ * MCP OAuth connect (F9-D14) runs here too: discovery, registration, the code exchange and the
9
+ * credential it seals, so the plaintext tokens, the PKCE verifier and any client secret never
10
+ * reach the runtime container; core only routes the start and the callback.
11
+ *
8
12
  * Two implementations: `inProcessKeys` (embedding, the ephemeral Runtime, tests, and the gates
9
13
  * service itself, which serves the HTTP routes with it), and `httpKeys` (`client.ts`), the
10
14
  * runtime container's client of the `keys` service in the gateway.
@@ -20,6 +24,8 @@ export const KEYS_OPERATIONS = [
20
24
  "sign",
21
25
  "rotateSigningKeys",
22
26
  "ensureSigningKeys",
27
+ "startOAuth",
28
+ "finishOAuth",
23
29
  ];
24
30
  export function inProcessKeys(options) {
25
31
  const { store, vault, signingKeys, kek } = options;
@@ -28,6 +34,8 @@ export function inProcessKeys(options) {
28
34
  rotateCredential: (vaultId, id, body) => vault.rotateCredential(vaultId, id, body),
29
35
  putHostModel: (body) => vault.putHostModel(body),
30
36
  selectHostModel: (body) => vault.selectHostModel(body),
37
+ startOAuth: (input) => vault.startOAuth(input),
38
+ finishOAuth: (input) => vault.finishOAuth(input),
31
39
  async sign(request) {
32
40
  const key = kek();
33
41
  const row = await store.tx((t) => signingKeys.ensure(t, key));