@nylorun/runtime 0.17.0-beta → 0.19.1-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 (223) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/README.md +89 -58
  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/routes.js +1 -1
  9. package/dist/api/ag-ui/translate.d.ts +1 -3
  10. package/dist/api/ag-ui/translate.js +2 -17
  11. package/dist/api/components.d.ts +4871 -2614
  12. package/dist/api/components.js +12 -11
  13. package/dist/api/gate/routes.d.ts +7 -8
  14. package/dist/api/gate/routes.js +58 -52
  15. package/dist/api/http/app.d.ts +6 -0
  16. package/dist/api/http/app.js +18 -14
  17. package/dist/api/http/define.d.ts +14 -2
  18. package/dist/api/http/define.js +34 -15
  19. package/dist/api/http/routes/access.d.ts +3 -3
  20. package/dist/api/http/routes/access.js +18 -17
  21. package/dist/api/http/routes/artifacts.js +2 -4
  22. package/dist/api/http/routes/files.d.ts +8 -0
  23. package/dist/api/http/routes/files.js +77 -0
  24. package/dist/api/http/routes/keys.d.ts +10 -0
  25. package/dist/api/http/routes/keys.js +64 -0
  26. package/dist/api/http/routes/me.js +5 -2
  27. package/dist/api/http/routes/reads.d.ts +66 -0
  28. package/dist/api/http/routes/reads.js +127 -0
  29. package/dist/api/http/routes/sandboxes.js +7 -4
  30. package/dist/api/http/routes/sessions.js +25 -8
  31. package/dist/api/http/routes/tenant.js +15 -18
  32. package/dist/api/http/routes/vaults.d.ts +10 -9
  33. package/dist/api/http/routes/vaults.js +27 -23
  34. package/dist/api/openapi.d.ts +10 -11
  35. package/dist/api/openapi.js +288 -63
  36. package/dist/artifacts/links.js +1 -1
  37. package/dist/core/flow-host.d.ts +44 -23
  38. package/dist/core/flow-host.js +88 -106
  39. package/dist/core/provider.d.ts +4 -1
  40. package/dist/core/provider.js +6 -1
  41. package/dist/core/sandbox-routes.d.ts +0 -9
  42. package/dist/core/sandbox-routes.js +2 -21
  43. package/dist/execution/memory.d.ts +4 -5
  44. package/dist/execution/memory.js +11 -25
  45. package/dist/execution/types.d.ts +3 -33
  46. package/dist/execution/types.js +2 -12
  47. package/dist/gates/http-tool.d.ts +86 -0
  48. package/dist/gates/http-tool.js +197 -0
  49. package/dist/gates/mcp-handler.d.ts +3 -0
  50. package/dist/gates/mcp-handler.js +1 -3
  51. package/dist/gates/meter.d.ts +2 -2
  52. package/dist/gates/meter.js +6 -0
  53. package/dist/gates/tenant-vaults.d.ts +5 -9
  54. package/dist/gates/tool-calls.d.ts +7 -15
  55. package/dist/gates/tool-calls.js +4 -4
  56. package/dist/gates/tool-client.d.ts +1 -1
  57. package/dist/gates/tool-client.js +23 -47
  58. package/dist/gates/tool-contract.d.ts +27 -39
  59. package/dist/gates/tool-contract.js +30 -21
  60. package/dist/gates/tool-gate.d.ts +25 -24
  61. package/dist/gates/tool-gate.js +11 -7
  62. package/dist/harness/calls.d.ts +10 -4
  63. package/dist/harness/calls.js +15 -6
  64. package/dist/harness/executors.d.ts +1 -1
  65. package/dist/harness/executors.js +17 -12
  66. package/dist/harness/main.d.ts +2 -2
  67. package/dist/harness/main.js +5 -13
  68. package/dist/harness/service.d.ts +4 -5
  69. package/dist/harness/service.js +9 -2
  70. package/dist/harness-api/in-process.js +2 -2
  71. package/dist/harness-api/record.d.ts +6 -3
  72. package/dist/harness-api/record.js +65 -72
  73. package/dist/harness-api/server.d.ts +1 -9
  74. package/dist/harness-api/server.js +19 -17
  75. package/dist/harness-api/start.js +1 -5
  76. package/dist/harness-api/workspace.js +2 -3
  77. package/dist/harness-api/ws-server.js +1 -1
  78. package/dist/host/app.d.ts +2 -9
  79. package/dist/host/app.js +15 -25
  80. package/dist/host/config-for.d.ts +1 -5
  81. package/dist/host/config-for.js +0 -3
  82. package/dist/host/config.d.ts +0 -5
  83. package/dist/host/create-host.d.ts +3 -33
  84. package/dist/host/create-host.js +18 -94
  85. package/dist/host/environment.d.ts +0 -3
  86. package/dist/host/environment.js +0 -9
  87. package/dist/host/gates.d.ts +4 -1
  88. package/dist/host/gates.js +3 -2
  89. package/dist/host/http.d.ts +1 -2
  90. package/dist/host/http.js +1 -7
  91. package/dist/host/index.d.ts +2 -2
  92. package/dist/host/index.js +2 -2
  93. package/dist/host/main.js +27 -34
  94. package/dist/host/operate.d.ts +29 -0
  95. package/dist/host/operate.js +223 -0
  96. package/dist/host/stack-config.d.ts +12 -12
  97. package/dist/host/stack-config.js +5 -32
  98. package/dist/index.d.ts +1 -1
  99. package/dist/index.js +1 -1
  100. package/dist/infra/workers.d.ts +1 -1
  101. package/dist/keys/keys.js +2 -2
  102. package/dist/management-openapi.json +6491 -0
  103. package/dist/mcp/connect.d.ts +8 -4
  104. package/dist/mcp/connect.js +6 -26
  105. package/dist/mcp/pool.d.ts +5 -9
  106. package/dist/mcp/pool.js +8 -19
  107. package/dist/mcp/snapshot.d.ts +8 -2
  108. package/dist/mcp/snapshot.js +29 -2
  109. package/dist/media.d.ts +1 -1
  110. package/dist/media.js +1 -1
  111. package/dist/model/pi-model.js +3 -0
  112. package/dist/openapi.json +9372 -17030
  113. package/dist/reads/access.d.ts +4 -0
  114. package/dist/reads/access.js +12 -0
  115. package/dist/reads/cursor.d.ts +11 -0
  116. package/dist/reads/cursor.js +80 -0
  117. package/dist/reads/types.d.ts +25 -0
  118. package/dist/reads/types.js +1 -0
  119. package/dist/sandbox/manager.d.ts +16 -0
  120. package/dist/sandbox/manager.js +40 -0
  121. package/dist/sandbox/session-sandbox.js +13 -3
  122. package/dist/sandbox/skills.d.ts +13 -0
  123. package/dist/sandbox/skills.js +46 -0
  124. package/dist/sandbox/types.d.ts +2 -2
  125. package/dist/store/ownership.d.ts +9 -0
  126. package/dist/store/ownership.js +13 -0
  127. package/dist/store/postgres/connect.d.ts +2 -0
  128. package/dist/store/postgres/connect.js +29 -0
  129. package/dist/store/postgres/drizzle/0011_key_roles.sql +3 -0
  130. package/dist/store/postgres/drizzle/0012_session_reads.sql +8 -0
  131. package/dist/store/postgres/drizzle/0013_definition_files.sql +16 -0
  132. package/dist/store/postgres/drizzle/0014_action_endpoints_removed.sql +2 -0
  133. package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
  134. package/dist/store/postgres/reads.d.ts +3 -0
  135. package/dist/store/postgres/reads.js +272 -0
  136. package/dist/store/postgres/schema.d.ts +294 -489
  137. package/dist/store/postgres/schema.js +41 -76
  138. package/dist/store/postgres/store.js +51 -154
  139. package/dist/store/postgres/tenant.d.ts +34 -2
  140. package/dist/store/postgres/tenant.js +16 -32
  141. package/dist/store/types.d.ts +27 -96
  142. package/dist/store/types.js +0 -1
  143. package/dist/streams/control.d.ts +0 -2
  144. package/dist/streams/control.js +0 -5
  145. package/dist/streams/types.d.ts +1 -10
  146. package/dist/tenant/advance.d.ts +3 -3
  147. package/dist/tenant/advance.js +10 -7
  148. package/dist/tenant/auth.d.ts +14 -9
  149. package/dist/tenant/auth.js +24 -28
  150. package/dist/tenant/cause.d.ts +3 -3
  151. package/dist/tenant/cause.js +1 -1
  152. package/dist/tenant/commands.d.ts +2 -18
  153. package/dist/tenant/commands.js +35 -172
  154. package/dist/tenant/context.d.ts +14 -24
  155. package/dist/tenant/definition-files.d.ts +24 -0
  156. package/dist/tenant/definition-files.js +103 -0
  157. package/dist/tenant/effects.d.ts +18 -20
  158. package/dist/tenant/effects.js +56 -119
  159. package/dist/tenant/ephemeral.d.ts +7 -6
  160. package/dist/tenant/ephemeral.js +3 -11
  161. package/dist/tenant/host-token.js +1 -1
  162. package/dist/tenant/jwt.js +1 -1
  163. package/dist/tenant/module.d.ts +1 -4
  164. package/dist/tenant/module.js +3 -12
  165. package/dist/tenant/operator-keys.d.ts +34 -8
  166. package/dist/tenant/operator-keys.js +50 -18
  167. package/dist/tenant/outbound.d.ts +10 -1
  168. package/dist/tenant/outbound.js +44 -27
  169. package/dist/tenant/paths.d.ts +1 -1
  170. package/dist/tenant/paths.js +1 -3
  171. package/dist/tenant/principals.d.ts +11 -2
  172. package/dist/tenant/principals.js +27 -8
  173. package/dist/tenant/run-token.js +3 -3
  174. package/dist/tenant/runtime.d.ts +4 -6
  175. package/dist/tenant/runtime.js +19 -18
  176. package/dist/tenant/sandboxes.d.ts +4 -1
  177. package/dist/tenant/sandboxes.js +11 -0
  178. package/dist/tenant/scheduler.d.ts +1 -5
  179. package/dist/tenant/scheduler.js +2 -5
  180. package/dist/tenant/session-streams.d.ts +2 -1
  181. package/dist/tenant/session-streams.js +39 -5
  182. package/dist/tenant/session.d.ts +8 -41
  183. package/dist/tenant/session.js +0 -37
  184. package/dist/tenant/sessions.js +16 -8
  185. package/dist/tenant/signing-keys.d.ts +3 -3
  186. package/dist/tenant/signing-keys.js +5 -5
  187. package/dist/tenant/skill-tool.d.ts +20 -0
  188. package/dist/tenant/skill-tool.js +72 -0
  189. package/dist/tenant/slim.d.ts +1 -1
  190. package/dist/tenant/slim.js +1 -1
  191. package/dist/tenant/status.js +7 -12
  192. package/dist/tenant/store-pg.d.ts +15 -0
  193. package/dist/tenant/store-pg.js +7 -3
  194. package/dist/tenant/streams.d.ts +3 -10
  195. package/dist/tenant/streams.js +1 -24
  196. package/dist/tenant/sweep.js +0 -5
  197. package/dist/tenant/transcript.d.ts +2 -2
  198. package/dist/tenant/transcript.js +2 -2
  199. package/dist/tenant/types.d.ts +15 -22
  200. package/dist/tenant/worker.d.ts +1 -3
  201. package/dist/tenant/worker.js +3 -8
  202. package/dist/vault/sources.d.ts +7 -1
  203. package/dist/vault/sources.js +22 -11
  204. package/dist/version.d.ts +1 -1
  205. package/dist/version.js +1 -1
  206. package/package.json +4 -4
  207. package/dist/admin-openapi.json +0 -904
  208. package/dist/api/http/routes/actions.d.ts +0 -8
  209. package/dist/api/http/routes/actions.js +0 -75
  210. package/dist/api/http/routes/endpoints.d.ts +0 -7
  211. package/dist/api/http/routes/endpoints.js +0 -100
  212. package/dist/host/admin-api.d.ts +0 -30
  213. package/dist/host/admin-api.js +0 -140
  214. package/dist/mcp/stdio.d.ts +0 -17
  215. package/dist/mcp/stdio.js +0 -82
  216. package/dist/tenant/actions.d.ts +0 -14
  217. package/dist/tenant/actions.js +0 -29
  218. package/dist/tenant/delivery-token.d.ts +0 -41
  219. package/dist/tenant/delivery-token.js +0 -104
  220. package/dist/tenant/delivery.d.ts +0 -62
  221. package/dist/tenant/delivery.js +0 -481
  222. package/dist/tenant/endpoints.d.ts +0 -67
  223. package/dist/tenant/endpoints.js +0 -90
@@ -6,8 +6,8 @@ import { VaultError } from "../../../vault/error.js";
6
6
  import { readJson } from "../body.js";
7
7
  import { tenantRoute } from "../define.js";
8
8
  import { jsonResponse } from "../respond.js";
9
- /** Every vault route, and starting an MCP OAuth connect: an application key acting for no one. */
10
- const APPLICATION = { credentials: ["application"], scopes: "never" };
9
+ /** The Management API's vault routes (`/v1/tenant/vaults`): a management key. */
10
+ const MANAGEMENT = { credentials: ["management"], scopes: "never" };
11
11
  /**
12
12
  * The OAuth callback: a browser sent back by the authorization server, with no credential and no
13
13
  * protocol header. The `state` it carries is the grant.
@@ -30,10 +30,11 @@ const body = (schema) => ({
30
30
  });
31
31
  const vaultId = z.object({ vaultId: z.string() });
32
32
  const credentialId = vaultId.extend({ credentialId: z.string() });
33
- export function vaultRoutes(api) {
34
- tenantRoute(api, APPLICATION, {
33
+ /** The vault routes under `base` (`/v1/tenant/vaults`). */
34
+ function vaultRoutesAt(api, base, access) {
35
+ tenantRoute(api, access, {
35
36
  method: "post",
36
- path: "/v1/vaults",
37
+ path: `${base}`,
37
38
  tags: ["Vaults"],
38
39
  summary: "Create a vault",
39
40
  description: "With `scope: \"installation\"` the installation's own vault, owned by `installation`, which any session may attach; or a vault of one person (`ownerUserId`), which only that person's sessions attach.",
@@ -46,9 +47,9 @@ export function vaultRoutes(api) {
46
47
  const request = CreateVaultRequestSchema.parse(await readJson(c.req.raw));
47
48
  return jsonResponse(200, await c.env.tenant.vault.createVault(request));
48
49
  });
49
- tenantRoute(api, APPLICATION, {
50
+ tenantRoute(api, access, {
50
51
  method: "get",
51
- path: "/v1/vaults",
52
+ path: `${base}`,
52
53
  tags: ["Vaults"],
53
54
  summary: "List vaults",
54
55
  description: "The installation vaults, after the vaults of `ownerUserId` when it names a person.",
@@ -68,9 +69,9 @@ export function vaultRoutes(api) {
68
69
  }),
69
70
  });
70
71
  });
71
- tenantRoute(api, APPLICATION, {
72
+ tenantRoute(api, access, {
72
73
  method: "get",
73
- path: "/v1/vaults/{vaultId}",
74
+ path: `${base}/{vaultId}`,
74
75
  tags: ["Vaults"],
75
76
  summary: "Get a vault",
76
77
  request: { params: vaultId },
@@ -78,9 +79,9 @@ export function vaultRoutes(api) {
78
79
  }, async (c) => {
79
80
  return jsonResponse(200, await c.env.tenant.vault.getVault(c.req.param("vaultId")));
80
81
  });
81
- tenantRoute(api, APPLICATION, {
82
+ tenantRoute(api, access, {
82
83
  method: "delete",
83
- path: "/v1/vaults/{vaultId}",
84
+ path: `${base}/{vaultId}`,
84
85
  tags: ["Vaults"],
85
86
  summary: "Delete a vault and its credentials",
86
87
  request: { params: vaultId },
@@ -88,9 +89,9 @@ export function vaultRoutes(api) {
88
89
  }, async (c) => {
89
90
  return jsonResponse(200, await c.env.tenant.vault.deleteVault(c.req.param("vaultId")));
90
91
  });
91
- tenantRoute(api, APPLICATION, {
92
+ tenantRoute(api, access, {
92
93
  method: "post",
93
- path: "/v1/vaults/{vaultId}/credentials",
94
+ path: `${base}/{vaultId}/credentials`,
94
95
  tags: ["Vaults"],
95
96
  summary: "Add a credential",
96
97
  description: "A bearer token or OAuth tokens, bound to the URLs a tool may send them to.",
@@ -100,9 +101,9 @@ export function vaultRoutes(api) {
100
101
  const request = CreateCredentialRequestSchema.parse(await readJson(c.req.raw));
101
102
  return jsonResponse(200, await c.env.tenant.keys.createCredential(c.req.param("vaultId"), request));
102
103
  });
103
- tenantRoute(api, APPLICATION, {
104
+ tenantRoute(api, access, {
104
105
  method: "get",
105
- path: "/v1/vaults/{vaultId}/credentials",
106
+ path: `${base}/{vaultId}/credentials`,
106
107
  tags: ["Vaults"],
107
108
  summary: "List a vault's credentials",
108
109
  request: { params: vaultId },
@@ -112,9 +113,9 @@ export function vaultRoutes(api) {
112
113
  credentials: await c.env.tenant.vault.listCredentials(c.req.param("vaultId")),
113
114
  });
114
115
  });
115
- tenantRoute(api, APPLICATION, {
116
+ tenantRoute(api, access, {
116
117
  method: "get",
117
- path: "/v1/vaults/{vaultId}/credentials/{credentialId}",
118
+ path: `${base}/{vaultId}/credentials/{credentialId}`,
118
119
  tags: ["Vaults"],
119
120
  summary: "Get a credential",
120
121
  request: { params: credentialId },
@@ -122,9 +123,9 @@ export function vaultRoutes(api) {
122
123
  }, async (c) => {
123
124
  return jsonResponse(200, await c.env.tenant.vault.getCredential(c.req.param("vaultId"), c.req.param("credentialId")));
124
125
  });
125
- tenantRoute(api, APPLICATION, {
126
+ tenantRoute(api, access, {
126
127
  method: "post",
127
- path: "/v1/vaults/{vaultId}/credentials/{credentialId}",
128
+ path: `${base}/{vaultId}/credentials/{credentialId}`,
128
129
  tags: ["Vaults"],
129
130
  summary: "Rotate a credential's secret",
130
131
  request: { params: credentialId, body: body(RotateCredentialRequest) },
@@ -136,9 +137,9 @@ export function vaultRoutes(api) {
136
137
  const request = RotateCredentialRequestSchema.parse(await readJson(c.req.raw));
137
138
  return jsonResponse(200, await c.env.tenant.keys.rotateCredential(c.req.param("vaultId"), c.req.param("credentialId"), request));
138
139
  });
139
- tenantRoute(api, APPLICATION, {
140
+ tenantRoute(api, access, {
140
141
  method: "delete",
141
- path: "/v1/vaults/{vaultId}/credentials/{credentialId}",
142
+ path: `${base}/{vaultId}/credentials/{credentialId}`,
142
143
  tags: ["Vaults"],
143
144
  summary: "Delete a credential",
144
145
  request: { params: credentialId },
@@ -146,9 +147,9 @@ export function vaultRoutes(api) {
146
147
  }, async (c) => {
147
148
  return jsonResponse(200, await c.env.tenant.vault.deleteCredential(c.req.param("vaultId"), c.req.param("credentialId")));
148
149
  });
149
- tenantRoute(api, APPLICATION, {
150
+ tenantRoute(api, access, {
150
151
  method: "post",
151
- path: "/v1/vaults/{vaultId}/oauth/start",
152
+ path: `${base}/{vaultId}/oauth/start`,
152
153
  tags: ["Vaults"],
153
154
  summary: "Start an MCP OAuth connect",
154
155
  description: "Signs the installation in to the remote MCP server at `url` (declared as `server`) and stores its OAuth credential, bound to `url`, in this installation vault. The Runtime discovers the server's authorization server (RFC 9728, RFC 8414), registers itself (RFC 7591) unless `clientId` names a registered client, and answers the URL to open in a browser; the sign-in returns to `GET /v1/oauth/callback` within `expiresAt`. The callback URL is `NYLORUN_PUBLIC_URL` + `/v1/oauth/callback`, or this request's own origin when the Host has no public URL. Application keys acting for no one only. `oauth_client_required` when the server offers no registration and no `clientId` was given.",
@@ -171,6 +172,9 @@ export function vaultRoutes(api) {
171
172
  redirectUri: `${base}${OAUTH_CALLBACK_PATH}`,
172
173
  }));
173
174
  });
175
+ }
176
+ export function vaultRoutes(api) {
177
+ vaultRoutesAt(api, "/v1/tenant/vaults", MANAGEMENT);
174
178
  tenantRoute(api, CALLBACK, {
175
179
  method: "get",
176
180
  path: OAUTH_CALLBACK_PATH,
@@ -1,19 +1,18 @@
1
1
  /**
2
- * The Runtime's OpenAPI 3.2 documents, generated from the routes as declared for serving:
3
- *
4
- * - the Tenant API (`tenantDocument`): every Tenant route, with `/health`, `/ready` and
5
- * `/openapi.json`. Served at `GET /openapi.json`, packed as `@nylorun/runtime/openapi.json`
6
- * and attached to each release.
7
- * - the Admin API (`adminDocument`): served at `GET /v1/admin/openapi.json` behind the admin
8
- * key, packed as `@nylorun/runtime/admin-openapi.json`.
2
+ * The Runtime's two OpenAPI 3.2 documents, generated from the routes as declared for serving
3
+ * (protocol 8): the Runtime API (`runtimeDocument`: `/openapi/runtime.json`, alias
4
+ * `/openapi.json`, `@nylorun/runtime/openapi.json`) and the Management API (`managementDocument`:
5
+ * `/openapi/management.json`, `@nylorun/runtime/management-openapi.json`). Both are attached to
6
+ * each release. Each has described tags in the order a developer uses them; the Runtime API
7
+ * groups them (`x-tagGroups`).
9
8
  *
10
9
  * Event streams are `text/event-stream` with an `itemSchema` (OpenAPI 3.2). Nothing here reads
11
10
  * the environment: the same Runtime makes the same document.
12
11
  */
13
12
  import { OpenApiGeneratorV32 } from "@asteasolutions/zod-to-openapi";
14
13
  type OpenApiDocument = ReturnType<OpenApiGeneratorV32["generateDocument"]>;
15
- /** The Tenant API's document. */
16
- export declare function tenantDocument(): OpenApiDocument;
17
- /** The Admin API's document. */
18
- export declare function adminDocument(): OpenApiDocument;
14
+ /** The Runtime API's document: `/openapi/runtime.json` and `/openapi.json`. */
15
+ export declare function runtimeDocument(): OpenApiDocument;
16
+ /** The Management API's document: `/openapi/management.json`. */
17
+ export declare function managementDocument(): OpenApiDocument;
19
18
  export {};
@@ -1,11 +1,10 @@
1
1
  /**
2
- * The Runtime's OpenAPI 3.2 documents, generated from the routes as declared for serving:
3
- *
4
- * - the Tenant API (`tenantDocument`): every Tenant route, with `/health`, `/ready` and
5
- * `/openapi.json`. Served at `GET /openapi.json`, packed as `@nylorun/runtime/openapi.json`
6
- * and attached to each release.
7
- * - the Admin API (`adminDocument`): served at `GET /v1/admin/openapi.json` behind the admin
8
- * key, packed as `@nylorun/runtime/admin-openapi.json`.
2
+ * The Runtime's two OpenAPI 3.2 documents, generated from the routes as declared for serving
3
+ * (protocol 8): the Runtime API (`runtimeDocument`: `/openapi/runtime.json`, alias
4
+ * `/openapi.json`, `@nylorun/runtime/openapi.json`) and the Management API (`managementDocument`:
5
+ * `/openapi/management.json`, `@nylorun/runtime/management-openapi.json`). Both are attached to
6
+ * each release. Each has described tags in the order a developer uses them; the Runtime API
7
+ * groups them (`x-tagGroups`).
9
8
  *
10
9
  * Event streams are `text/event-stream` with an `itemSchema` (OpenAPI 3.2). Nothing here reads
11
10
  * the environment: the same Runtime makes the same document.
@@ -13,7 +12,6 @@
13
12
  import { OpenAPIRegistry, OpenApiGeneratorV32, } from "@asteasolutions/zod-to-openapi";
14
13
  import { HOST_PROTOCOL } from "@nylorun/core/compatibility";
15
14
  import { HealthResponseSchema, ReadyResponseSchema } from "@nylorun/core/contracts";
16
- import { createAdminApi } from "../host/admin-api.js";
17
15
  import { RUNTIME_VERSION } from "../version.js";
18
16
  import { tenantApi } from "./http/app.js";
19
17
  const PROTOCOL = {
@@ -27,7 +25,10 @@ const bearer = (description, bearerFormat) => ({
27
25
  ...(bearerFormat ? { bearerFormat } : {}),
28
26
  description,
29
27
  });
30
- /** `/health`, `/ready` and `/openapi.json`: what every listener answers without a key. */
28
+ /**
29
+ * `/health`, `/ready` and the documents: what every listener answers without a key. The
30
+ * `/openapi.json` alias is served but left out of the documents.
31
+ */
31
32
  function hostRoutes() {
32
33
  const registry = new OpenAPIRegistry();
33
34
  const route = (config) => registry.registerPath(config);
@@ -49,7 +50,7 @@ function hostRoutes() {
49
50
  path: "/ready",
50
51
  tags: ["Host"],
51
52
  summary: "Check the Runtime is ready",
52
- description: "The listeners, the Tenant (open), Postgres, Restate and S2.",
53
+ description: "The listener, the Tenant (open), Postgres, Restate and S2, and the open Tenant's harnesses.",
53
54
  responses: {
54
55
  200: {
55
56
  description: "Ready",
@@ -60,72 +61,296 @@ function hostRoutes() {
60
61
  });
61
62
  route({
62
63
  method: "get",
63
- path: "/openapi.json",
64
+ path: "/openapi/runtime.json",
65
+ tags: ["Host"],
66
+ summary: "Get the Runtime API's document",
67
+ description: "This document. `/openapi.json` is the same.",
68
+ responses: { 200: { description: "The Runtime API's OpenAPI document" } },
69
+ });
70
+ route({
71
+ method: "get",
72
+ path: "/openapi/management.json",
64
73
  tags: ["Host"],
65
- summary: "Get this document",
66
- responses: { 200: { description: "The Tenant API's OpenAPI document" } },
74
+ summary: "Get the Management API's document",
75
+ responses: { 200: { description: "The Management API's OpenAPI document" } },
67
76
  });
68
77
  return registry;
69
78
  }
70
79
  function tenantSchemes(registry) {
71
- registry.registerComponent("securitySchemes", "applicationKey", bearer("An application key of the Tenant: an operator key (`PUT /v1/admin/keys/{id}`), or Studio's key, derived from the admin key. With `Nylorun-Subject` and `Nylorun-Scopes`, it acts for that person, narrowed to those scopes. Never accepted from a browser (`Origin`)."));
80
+ registry.registerComponent("securitySchemes", "applicationKey", bearer("An application key of the Tenant (`PUT /v1/tenant/keys/{keyId}`), or Studio's key, derived from the admin key. With `Nylorun-Subject` and `Nylorun-Scopes`, it acts for that person, narrowed to those scopes. Never accepted from a browser (`Origin`)."));
81
+ registry.registerComponent("securitySchemes", "managementKey", bearer("A management key of the Tenant (role `management`): it reaches the Management API (`/v1/tenant/*`) and `/v1/me`, as itself, never for a subject. Issued only on the Tenant's machine (`nylorun-operate keys put <id> --role management`) or from `NYLORUN_MANAGEMENT_KEY_FILE`. Never accepted from a browser (`Origin`)."));
72
82
  registry.registerComponent("securitySchemes", "issuerToken", bearer("A JWT from a trusted issuer of the Host's identity file (Host feature `trusted-issuers`): one person, with the issuer's scopes, agents and sandbox grants, until it expires. Accepted from servers and browsers alike; CORS is the operator's proxy's.", "JWT"));
73
- registry.registerComponent("securitySchemes", "deliveryToken", bearer("The delivery token the Runtime signs each Action delivery with (`Nylorun-Signature`), sent back by the Action endpoint. It reaches only that Action's heartbeat, result and sandbox routes, while that delivery is current, for at most 15 minutes.", "JWT"));
74
83
  }
75
- let tenant;
76
- let admin;
77
- /** The Tenant API's document. */
78
- export function tenantDocument() {
79
- if (tenant)
80
- return tenant;
84
+ const RUNTIME_TAGS = [
85
+ {
86
+ name: "Agents",
87
+ group: "Agents",
88
+ description: "The agents a Tenant can run: put a definition, list what is there. In `@nylorun/agents`.",
89
+ operations: ["PUT /v1/agents/{agentId}", "GET /v1/agents"],
90
+ },
91
+ {
92
+ name: "Definition files",
93
+ group: "Agents",
94
+ description: "The files a definition names by the SHA-256 of their bytes (each skill's folder): upload each once before putting the definition, which is refused while it names one the Runtime does not hold (`definition_files_missing`). `saveAgent` in `@nylorun/agents` does both.",
95
+ operations: ["PUT /v1/files/{file}", "HEAD /v1/files/{file}"],
96
+ },
97
+ {
98
+ name: "Sessions API",
99
+ group: "Sessions",
100
+ description: "A conversation with an agent: open a session, send commands, follow its events, read its history. In `@nylorun/agents`.",
101
+ operations: [
102
+ "PUT /v1/sessions/{sessionId}",
103
+ "GET /v1/sessions",
104
+ "GET /v1/sessions/{sessionId}",
105
+ "POST /v1/sessions/{sessionId}/commands",
106
+ "GET /v1/sessions/{sessionId}/events",
107
+ "GET /v1/sessions/{sessionId}/items",
108
+ "GET /v1/sessions/{sessionId}/manifest",
109
+ "GET /v1/sessions/{sessionId}/usage",
110
+ "GET /v1/sessions/{sessionId}/calls/model",
111
+ "POST /v1/sessions/{sessionId}/sandbox/{tool}",
112
+ ],
113
+ },
114
+ {
115
+ name: "AG-UI",
116
+ group: "Sessions",
117
+ description: "The same sessions through AG-UI: a thread is one session per person, agent and thread, and each run is a turn.",
118
+ operations: [
119
+ "POST /v1/ag-ui/agents/{agentId}",
120
+ "GET /v1/ag-ui/agents/{agentId}/threads/{threadId}/events",
121
+ "GET /v1/ag-ui/agents/{agentId}/threads/{threadId}/messages",
122
+ "POST /v1/ag-ui/agents/{agentId}/threads/{threadId}/cancel",
123
+ ],
124
+ },
125
+ {
126
+ name: "A2A",
127
+ group: "Sessions",
128
+ description: "The same sessions through Agent2Agent: a context is one session per subject, agent and `contextId`, and a task is one turn. The card is how an A2A client finds the agent.",
129
+ operations: ["GET /v1/a2a/agents/{agentId}/card", "POST /v1/a2a/agents/{agentId}"],
130
+ },
131
+ {
132
+ name: "Sandboxes",
133
+ group: "Sandboxes",
134
+ description: "Isolated machines an agent works in: create or find one, watch its lifecycle, stop, reset or delete it. In `@nylorun/agents`.",
135
+ operations: [
136
+ "PUT /v1/sandboxes/{sandboxId}",
137
+ "GET /v1/sandboxes",
138
+ "GET /v1/sandboxes/{sandboxId}",
139
+ "GET /v1/sandboxes/{sandboxId}/events",
140
+ "POST /v1/sandboxes/{sandboxId}/stop",
141
+ "POST /v1/sandboxes/{sandboxId}/reset",
142
+ "DELETE /v1/sandboxes/{sandboxId}",
143
+ ],
144
+ },
145
+ {
146
+ name: "Artifacts",
147
+ group: "Artifacts",
148
+ description: "Files and folders agents and people produce, versioned, with short-lived capability links to share them. In `@nylorun/agents`.",
149
+ operations: [
150
+ "POST /v1/artifacts",
151
+ "GET /v1/artifacts",
152
+ "GET /v1/artifacts/{artifactId}",
153
+ "POST /v1/artifacts/{artifactId}/versions",
154
+ "GET /v1/artifacts/{artifactId}/versions/{version}/content",
155
+ "GET /v1/artifacts/{artifactId}/versions/{version}/tree",
156
+ "GET /v1/artifacts/{artifactId}/versions/{version}/files/{path}",
157
+ "GET /v1/artifacts/{artifactId}/versions/{version}/diff",
158
+ "GET /v1/artifacts/{artifactId}/versions/{version}/zip",
159
+ "POST /v1/artifacts/{artifactId}/links",
160
+ "GET /v1/artifact-links/{token}",
161
+ "DELETE /v1/artifacts/{artifactId}",
162
+ ],
163
+ },
164
+ {
165
+ name: "Service",
166
+ group: "Service",
167
+ description: "Check a Runtime is up and speaks your protocol, ask who your credential is, and read the public keys of the tokens it signs. `/health`, `/ready`, the JWKS and the documents need no key.",
168
+ operations: [
169
+ "GET /health",
170
+ "GET /ready",
171
+ "GET /v1/me",
172
+ "GET /v1/access/jwks",
173
+ "GET /openapi/runtime.json",
174
+ ],
175
+ },
176
+ ];
177
+ const MANAGEMENT_TAGS = [
178
+ {
179
+ name: "Tenant",
180
+ description: "The Tenant's status, and seeding or resetting it. `admin.tenant` in `@nylorun/admin`.",
181
+ operations: [
182
+ "GET /v1/tenant",
183
+ "PUT /v1/tenant/config/seed",
184
+ "POST /v1/tenant/reset",
185
+ "GET /v1/me",
186
+ "GET /openapi/management.json",
187
+ ],
188
+ },
189
+ {
190
+ name: "Application keys",
191
+ description: "The keys app servers call the Runtime API with: create, rotate, list and delete them. Management keys come only from the Tenant's machine. `admin.keys`.",
192
+ operations: ["GET /v1/tenant/keys", "PUT /v1/tenant/keys/{keyId}", "DELETE /v1/tenant/keys/{keyId}"],
193
+ },
194
+ {
195
+ name: "Models",
196
+ description: "Model providers, their credentials, the model the Tenant uses, what it spent, every model call for export, and the budgets that cap it. `admin.models`.",
197
+ operations: [
198
+ "GET /v1/tenant/models",
199
+ "GET /v1/tenant/providers",
200
+ "GET /v1/tenant/model",
201
+ "PUT /v1/tenant/model",
202
+ "PUT /v1/tenant/model/selection",
203
+ "GET /v1/tenant/usage",
204
+ "GET /v1/tenant/calls/model",
205
+ "GET /v1/tenant/budgets",
206
+ "PUT /v1/tenant/budgets",
207
+ ],
208
+ },
209
+ {
210
+ name: "Vaults",
211
+ description: "The installation's credentials for agents' tools: API keys and MCP OAuth connections. Sessions attach a vault by id. `admin.vaults`.",
212
+ operations: [
213
+ "POST /v1/tenant/vaults",
214
+ "GET /v1/tenant/vaults",
215
+ "GET /v1/tenant/vaults/{vaultId}",
216
+ "DELETE /v1/tenant/vaults/{vaultId}",
217
+ "POST /v1/tenant/vaults/{vaultId}/credentials",
218
+ "GET /v1/tenant/vaults/{vaultId}/credentials",
219
+ "GET /v1/tenant/vaults/{vaultId}/credentials/{credentialId}",
220
+ "POST /v1/tenant/vaults/{vaultId}/credentials/{credentialId}",
221
+ "DELETE /v1/tenant/vaults/{vaultId}/credentials/{credentialId}",
222
+ "POST /v1/tenant/vaults/{vaultId}/oauth/start",
223
+ "GET /v1/oauth/callback",
224
+ ],
225
+ },
226
+ {
227
+ name: "Signing keys",
228
+ description: "The keys the Runtime signs capability links and run tokens with; their public halves are the Runtime API's JWKS. `admin.signingKeys`.",
229
+ operations: [
230
+ "GET /v1/tenant/signing-keys",
231
+ "POST /v1/tenant/signing-keys/rotate",
232
+ "POST /v1/tenant/signing-keys/{kid}/revoke",
233
+ ],
234
+ },
235
+ {
236
+ name: "Settings",
237
+ description: "The Tenant's sandbox and artifact settings. `admin.settings`.",
238
+ operations: [
239
+ "GET /v1/tenant/sandbox",
240
+ "PUT /v1/tenant/sandbox",
241
+ "GET /v1/tenant/artifacts",
242
+ "PUT /v1/tenant/artifacts",
243
+ ],
244
+ },
245
+ ];
246
+ const METHODS = ["get", "head", "put", "post", "delete", "patch"];
247
+ const SERVERS = [
248
+ {
249
+ url: "{origin}",
250
+ description: "A Runtime: a local Tenant (`nylorun start`), or where yours runs",
251
+ variables: { origin: { default: "http://localhost:8787" } },
252
+ },
253
+ ];
254
+ /** The `#/components/schemas/…` names `value` refers to, followed through `schemas`. */
255
+ function referencedSchemas(value, schemas) {
256
+ const found = new Set();
257
+ const walk = (node) => {
258
+ if (Array.isArray(node))
259
+ return node.forEach(walk);
260
+ if (!node || typeof node !== "object")
261
+ return;
262
+ for (const [key, child] of Object.entries(node)) {
263
+ if (key === "$ref" && typeof child === "string" && child.startsWith("#/components/schemas/")) {
264
+ const name = child.slice("#/components/schemas/".length);
265
+ if (!found.has(name)) {
266
+ found.add(name);
267
+ walk(schemas[name]);
268
+ }
269
+ }
270
+ else
271
+ walk(child);
272
+ }
273
+ };
274
+ walk(value);
275
+ return found;
276
+ }
277
+ /** One reference document: `tags`' operations of `all`, in their order, with what they use. */
278
+ function document(all, tags, info) {
279
+ const paths = {};
280
+ for (const tag of tags)
281
+ for (const name of tag.operations) {
282
+ const [method, path] = name.split(" ");
283
+ const operation = all.paths?.[path]?.[method.toLowerCase()];
284
+ if (!operation)
285
+ throw new Error(`The Runtime has no operation ${name}`);
286
+ (paths[path] ??= {})[method.toLowerCase()] = { ...operation, tags: [tag.name] };
287
+ }
288
+ const schemas = (all.components?.schemas ?? {});
289
+ const used = referencedSchemas(paths, schemas);
290
+ const schemes = new Set();
291
+ for (const item of Object.values(paths))
292
+ for (const operation of Object.values(item))
293
+ for (const requirement of (operation.security ?? []))
294
+ for (const scheme of Object.keys(requirement))
295
+ schemes.add(scheme);
296
+ const groups = [...new Set(tags.flatMap((tag) => (tag.group ? [tag.group] : [])))];
297
+ return {
298
+ ...all,
299
+ info: { ...all.info, ...info },
300
+ tags: tags.map((tag) => ({ name: tag.name, description: tag.description })),
301
+ ...(groups.length
302
+ ? {
303
+ "x-tagGroups": groups.map((group) => ({
304
+ name: group,
305
+ tags: tags.filter((tag) => tag.group === group).map((tag) => tag.name),
306
+ })),
307
+ }
308
+ : {}),
309
+ paths,
310
+ components: {
311
+ ...all.components,
312
+ schemas: Object.fromEntries(Object.entries(schemas).filter(([name]) => used.has(name))),
313
+ securitySchemes: Object.fromEntries(Object.entries(all.components?.securitySchemes ?? {}).filter(([name]) => schemes.has(name))),
314
+ },
315
+ };
316
+ }
317
+ let built;
318
+ /** Both reference documents, built once from every route; throws when one is left out. */
319
+ function documents() {
320
+ if (built)
321
+ return built;
81
322
  const host = hostRoutes();
82
323
  tenantSchemes(host);
83
- tenant = new OpenApiGeneratorV32([
324
+ const all = new OpenApiGeneratorV32([
84
325
  ...host.definitions,
85
326
  ...tenantApi().openAPIRegistry.definitions,
86
327
  ]).generateDocument({
87
328
  openapi: "3.2.0",
88
- info: {
89
- title: "Nylorun Runtime: Tenant API",
90
- version: RUNTIME_VERSION,
91
- description: "Agents, sessions and their events, vaults, access and the Tenant's settings. A Runtime serves one Tenant: its URL is the Tenant's, and no request names it. Every request sends `Nylorun-Protocol`. Who may call each operation is its `security` and its `x-nylorun-credentials` and `x-nylorun-scopes` (the subject scopes that reach it) fields.",
92
- "x-nylorun-protocol": PROTOCOL,
93
- },
94
- servers: [
95
- {
96
- url: "{origin}",
97
- description: "A Runtime: a local Tenant (`nylorun start`), or where yours runs",
98
- variables: { origin: { default: "http://localhost:8787" } },
99
- },
100
- ],
329
+ info: { title: "Nylorun Runtime", version: RUNTIME_VERSION, "x-nylorun-protocol": PROTOCOL },
330
+ servers: SERVERS,
101
331
  });
102
- return tenant;
332
+ const listed = new Set([...RUNTIME_TAGS, ...MANAGEMENT_TAGS].flatMap((tag) => tag.operations));
333
+ for (const [path, item] of Object.entries(all.paths ?? {}))
334
+ for (const method of METHODS)
335
+ if (item[method] && !listed.has(`${method.toUpperCase()} ${path}`))
336
+ throw new Error(`${method.toUpperCase()} ${path} is in no reference tag (api/openapi.ts)`);
337
+ built = {
338
+ runtime: document(all, RUNTIME_TAGS, {
339
+ title: "Nylorun Runtime API",
340
+ description: "For developers: agents, sessions (with AG-UI and A2A), sandboxes and artifacts, through `@nylorun/agents`. Every Tenant serves it on its one URL, beside the Management API (`/openapi/management.json`). Every request sends `Nylorun-Protocol`. Who may call each operation is its `security` and its `x-nylorun-credentials` and `x-nylorun-scopes` (the subject scopes that reach it) fields: an application key (servers) or a trusted issuer's token (browsers and apps).",
341
+ }),
342
+ management: document(all, MANAGEMENT_TAGS, {
343
+ title: "Nylorun Management API",
344
+ description: "For operators: the Tenant's models, vaults, signing keys, settings and application keys, at `/v1/tenant/*` on the Tenant's URL, through `@nylorun/admin`. Every operation takes a management key, acting as itself: never for a subject and never from a browser. Management keys are issued only on the Tenant's machine (`nylorun key put <id> --management`) or from `NYLORUN_MANAGEMENT_KEY_FILE`.",
345
+ }),
346
+ };
347
+ return built;
103
348
  }
104
- /** The Admin API's document. */
105
- export function adminDocument() {
106
- if (admin)
107
- return admin;
108
- // Only the routes' declarations are read: nothing is served from this app.
109
- const api = createAdminApi({
110
- status: () => Promise.reject(new Error("Not served")),
111
- shutdown: () => { },
112
- });
113
- api.openAPIRegistry.registerComponent("securitySchemes", "adminKey", bearer("The Host's admin key (`host-credentials.json`). Never a Tenant bearer."));
114
- admin = new OpenApiGeneratorV32(api.openAPIRegistry.definitions).generateDocument({
115
- openapi: "3.2.0",
116
- info: {
117
- title: "Nylorun Runtime: Admin API",
118
- version: RUNTIME_VERSION,
119
- description: "The Host's status, its Tenant's state, shutdown and the Tenant's operator keys, with the admin key. Served on the operator listener when the Host has one; the public listener answers these routes with the opaque 404.",
120
- "x-nylorun-protocol": PROTOCOL,
121
- },
122
- servers: [
123
- {
124
- url: "{origin}",
125
- description: "The operator listener: a local Tenant's, or where yours runs",
126
- variables: { origin: { default: "http://localhost:8788" } },
127
- },
128
- ],
129
- });
130
- return admin;
349
+ /** The Runtime API's document: `/openapi/runtime.json` and `/openapi.json`. */
350
+ export function runtimeDocument() {
351
+ return documents().runtime;
352
+ }
353
+ /** The Management API's document: `/openapi/management.json`. */
354
+ export function managementDocument() {
355
+ return documents().management;
131
356
  }
@@ -2,7 +2,7 @@
2
2
  * Capability links (protocol 6): a short-lived URL that opens one artifact version with no
3
3
  * other credential, for UIs, `<img>` tags and sharing. The token in the path is an ES256 JWT
4
4
  * (`typ: nylorun-artifact+jwt`) signed with the Tenant's current signing key by the keys
5
- * service, like delivery tokens: `sub` is the artifact, `ver` the version, `aud`
5
+ * service, like run tokens: `sub` is the artifact, `ver` the version, `aud`
6
6
  * `nylorun-artifact`, and it lives at most `ARTIFACT_LINK_MAX_TTL_SECONDS` (`TOKEN_TTL_MAX_SECONDS`,
7
7
  * so a key rotation never revokes a live link). A link opens nothing once its artifact
8
8
  * is deleted. A folder's link (F8.2) opens its zip, or with a `path` claim one of its files.