@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
@@ -1,16 +1,25 @@
1
1
  import { z } from "zod";
2
- import { CreateCredentialRequestSchema, CreateVaultRequestSchema, RotateCredentialRequestSchema, } from "@nylorun/core/contracts";
3
- import { CreateCredentialRequest, CreateVaultRequest, CredentialInfo, DeletedResponse, ListCredentialsResponse, ListVaultsResponse, RotateCredentialRequest, VaultInfo, } from "../../components.js";
4
- import { ownerOf } from "../../../tenant/auth.js";
5
- import { fail } from "../../../tenant/http.js";
2
+ import { CreateCredentialRequestSchema, CreateVaultRequestSchema, RotateCredentialRequestSchema, StartOAuthRequestSchema, } from "@nylorun/core/contracts";
3
+ import { CreateCredentialRequest, CreateVaultRequest, CredentialInfo, DeletedResponse, ListCredentialsResponse, ListVaultsResponse, RotateCredentialRequest, StartOAuthRequest, StartOAuthResponse, VaultInfo, } from "../../components.js";
4
+ import { HttpError } from "../../../tenant/http.js";
5
+ import { VaultError } from "../../../vault/error.js";
6
6
  import { readJson } from "../body.js";
7
- import { pathSegments, tenantRoute } from "../define.js";
7
+ import { tenantRoute } from "../define.js";
8
8
  import { jsonResponse } from "../respond.js";
9
- const OWN_VAULTS = {
9
+ /** The Management API's vault routes (`/v1/tenant/vaults`): a management key. */
10
+ const MANAGEMENT = { credentials: ["management"], scopes: "never" };
11
+ /**
12
+ * The OAuth callback: a browser sent back by the authorization server, with no credential and no
13
+ * protocol header. The `state` it carries is the grant.
14
+ */
15
+ const CALLBACK = {
10
16
  credentials: ["application", "subject", "token"],
11
- scopes: ["vaults:own"],
12
- browser: true,
17
+ scopes: "any",
18
+ anonymous: true,
19
+ unversioned: true,
13
20
  };
21
+ /** Where the authorization server sends the browser back. */
22
+ export const OAUTH_CALLBACK_PATH = "/v1/oauth/callback";
14
23
  const json = (schema, description) => ({
15
24
  description,
16
25
  content: { "application/json": { schema } },
@@ -21,126 +30,102 @@ const body = (schema) => ({
21
30
  });
22
31
  const vaultId = z.object({ vaultId: z.string() });
23
32
  const credentialId = vaultId.extend({ credentialId: z.string() });
24
- /**
25
- * Who a vault route acts for: the subject, or no one in particular (an application key). Below
26
- * a vault, the vault must be the subject's before anything else.
27
- */
28
- async function ownerFor(c) {
29
- const { vault } = c.env.tenant;
30
- const owner = ownerOf(c.get("scope"));
31
- const id = c.req.param("vaultId");
32
- if (id !== undefined && owner !== undefined)
33
- await vault.assertOwner(id, owner);
34
- return owner;
35
- }
36
- export function vaultRoutes(api) {
37
- tenantRoute(api, OWN_VAULTS, {
33
+ /** The vault routes under `base` (`/v1/tenant/vaults`). */
34
+ function vaultRoutesAt(api, base, access) {
35
+ tenantRoute(api, access, {
38
36
  method: "post",
39
- path: "/v1/vaults",
37
+ path: `${base}`,
40
38
  tags: ["Vaults"],
41
39
  summary: "Create a vault",
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.",
42
41
  request: { body: body(CreateVaultRequest) },
43
42
  responses: {
44
43
  200: json(VaultInfo, "The vault"),
45
44
  409: { description: "The idempotency key was used for another vault" },
46
45
  },
47
46
  }, async (c) => {
48
- const owner = await ownerFor(c);
49
47
  const request = CreateVaultRequestSchema.parse(await readJson(c.req.raw));
50
- if (owner !== undefined && request.ownerUserId !== owner)
51
- fail(403, "ownerUserId must be the subject");
52
48
  return jsonResponse(200, await c.env.tenant.vault.createVault(request));
53
49
  });
54
- tenantRoute(api, OWN_VAULTS, {
50
+ tenantRoute(api, access, {
55
51
  method: "get",
56
- path: "/v1/vaults",
52
+ path: `${base}`,
57
53
  tags: ["Vaults"],
58
- summary: "List a person's vaults",
54
+ summary: "List vaults",
55
+ description: "The installation vaults, after the vaults of `ownerUserId` when it names a person.",
59
56
  request: {
60
57
  query: z.object({
61
58
  ownerUserId: z
62
59
  .string()
63
60
  .optional()
64
- .meta({ description: "Whose vaults; required with an application key acting for no one" }),
61
+ .meta({ description: "Also list this person's vaults" }),
65
62
  }),
66
63
  },
67
64
  responses: { 200: json(ListVaultsResponse, "The vaults") },
68
65
  }, async (c) => {
69
- const owner = await ownerFor(c);
70
- const ownerUserId = c.req.query("ownerUserId") ?? owner ?? fail(400, "ownerUserId is required");
71
- if (owner !== undefined && ownerUserId !== owner)
72
- fail(403, "ownerUserId must be the subject");
73
- return jsonResponse(200, { vaults: await c.env.tenant.vault.listVaults(ownerUserId) });
66
+ return jsonResponse(200, {
67
+ vaults: await c.env.tenant.vault.listVaults(c.req.query("ownerUserId"), {
68
+ installation: true,
69
+ }),
70
+ });
74
71
  });
75
- tenantRoute(api, OWN_VAULTS, {
72
+ tenantRoute(api, access, {
76
73
  method: "get",
77
- path: "/v1/vaults/{vaultId}",
74
+ path: `${base}/{vaultId}`,
78
75
  tags: ["Vaults"],
79
76
  summary: "Get a vault",
80
77
  request: { params: vaultId },
81
78
  responses: { 200: json(VaultInfo, "The vault") },
82
79
  }, async (c) => {
83
- await ownerFor(c);
84
80
  return jsonResponse(200, await c.env.tenant.vault.getVault(c.req.param("vaultId")));
85
81
  });
86
- tenantRoute(api, OWN_VAULTS, {
82
+ tenantRoute(api, access, {
87
83
  method: "delete",
88
- path: "/v1/vaults/{vaultId}",
84
+ path: `${base}/{vaultId}`,
89
85
  tags: ["Vaults"],
90
86
  summary: "Delete a vault and its credentials",
91
87
  request: { params: vaultId },
92
88
  responses: { 200: json(DeletedResponse, "Deleted") },
93
89
  }, async (c) => {
94
- await ownerFor(c);
95
90
  return jsonResponse(200, await c.env.tenant.vault.deleteVault(c.req.param("vaultId")));
96
91
  });
97
- tenantRoute(api, OWN_VAULTS, {
92
+ tenantRoute(api, access, {
98
93
  method: "post",
99
- path: "/v1/vaults/{vaultId}/credentials",
94
+ path: `${base}/{vaultId}/credentials`,
100
95
  tags: ["Vaults"],
101
96
  summary: "Add a credential",
102
- description: "A bearer token or OAuth tokens, bound to the URLs a tool may send them to. A subject token cannot store OAuth refresh credentials.",
97
+ description: "A bearer token or OAuth tokens, bound to the URLs a tool may send them to.",
103
98
  request: { params: vaultId, body: body(CreateCredentialRequest) },
104
99
  responses: { 200: json(CredentialInfo, "The credential, without its secret") },
105
100
  }, async (c) => {
106
- await ownerFor(c);
107
101
  const request = CreateCredentialRequestSchema.parse(await readJson(c.req.raw));
108
- // The Runtime calls a refresh credential's token endpoint itself: never for a browser.
109
- if (c.get("scope").kind === "token" &&
110
- request.auth.type === "oauth" &&
111
- request.auth.refresh)
112
- fail(403, "A subject token cannot store OAuth refresh credentials", {
113
- code: "scope_required",
114
- });
115
102
  return jsonResponse(200, await c.env.tenant.keys.createCredential(c.req.param("vaultId"), request));
116
103
  });
117
- tenantRoute(api, OWN_VAULTS, {
104
+ tenantRoute(api, access, {
118
105
  method: "get",
119
- path: "/v1/vaults/{vaultId}/credentials",
106
+ path: `${base}/{vaultId}/credentials`,
120
107
  tags: ["Vaults"],
121
108
  summary: "List a vault's credentials",
122
109
  request: { params: vaultId },
123
110
  responses: { 200: json(ListCredentialsResponse, "The credentials, without their secrets") },
124
111
  }, async (c) => {
125
- await ownerFor(c);
126
112
  return jsonResponse(200, {
127
113
  credentials: await c.env.tenant.vault.listCredentials(c.req.param("vaultId")),
128
114
  });
129
115
  });
130
- tenantRoute(api, OWN_VAULTS, {
116
+ tenantRoute(api, access, {
131
117
  method: "get",
132
- path: "/v1/vaults/{vaultId}/credentials/{credentialId}",
118
+ path: `${base}/{vaultId}/credentials/{credentialId}`,
133
119
  tags: ["Vaults"],
134
120
  summary: "Get a credential",
135
121
  request: { params: credentialId },
136
122
  responses: { 200: json(CredentialInfo, "The credential, without its secret") },
137
123
  }, async (c) => {
138
- await ownerFor(c);
139
124
  return jsonResponse(200, await c.env.tenant.vault.getCredential(c.req.param("vaultId"), c.req.param("credentialId")));
140
125
  });
141
- tenantRoute(api, OWN_VAULTS, {
126
+ tenantRoute(api, access, {
142
127
  method: "post",
143
- path: "/v1/vaults/{vaultId}/credentials/{credentialId}",
128
+ path: `${base}/{vaultId}/credentials/{credentialId}`,
144
129
  tags: ["Vaults"],
145
130
  summary: "Rotate a credential's secret",
146
131
  request: { params: credentialId, body: body(RotateCredentialRequest) },
@@ -149,19 +134,106 @@ export function vaultRoutes(api) {
149
134
  409: { description: "A credential's type cannot change" },
150
135
  },
151
136
  }, async (c) => {
152
- await ownerFor(c);
153
137
  const request = RotateCredentialRequestSchema.parse(await readJson(c.req.raw));
154
138
  return jsonResponse(200, await c.env.tenant.keys.rotateCredential(c.req.param("vaultId"), c.req.param("credentialId"), request));
155
139
  });
156
- tenantRoute(api, OWN_VAULTS, {
140
+ tenantRoute(api, access, {
157
141
  method: "delete",
158
- path: "/v1/vaults/{vaultId}/credentials/{credentialId}",
142
+ path: `${base}/{vaultId}/credentials/{credentialId}`,
159
143
  tags: ["Vaults"],
160
144
  summary: "Delete a credential",
161
145
  request: { params: credentialId },
162
146
  responses: { 200: json(DeletedResponse, "Deleted") },
163
147
  }, async (c) => {
164
- await ownerFor(c);
165
148
  return jsonResponse(200, await c.env.tenant.vault.deleteCredential(c.req.param("vaultId"), c.req.param("credentialId")));
166
149
  });
150
+ tenantRoute(api, access, {
151
+ method: "post",
152
+ path: `${base}/{vaultId}/oauth/start`,
153
+ tags: ["Vaults"],
154
+ summary: "Start an MCP OAuth connect",
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.",
156
+ request: { params: vaultId, body: body(StartOAuthRequest) },
157
+ responses: {
158
+ 200: json(StartOAuthResponse, "Where to send the browser"),
159
+ 502: {
160
+ description: "The authorization server, or its discovery, failed or refused (`oauth_failed`)",
161
+ },
162
+ },
163
+ }, async (c) => {
164
+ const request = StartOAuthRequestSchema.parse(await readJson(c.req.raw));
165
+ const tenant = c.env.tenant;
166
+ const base = tenant.config.publicUrl ?? new URL(c.req.url).origin;
167
+ return jsonResponse(200, await tenant.keys.startOAuth({
168
+ vaultId: c.req.param("vaultId"),
169
+ server: request.server,
170
+ url: request.url,
171
+ ...(request.clientId === undefined ? {} : { clientId: request.clientId }),
172
+ redirectUri: `${base}${OAUTH_CALLBACK_PATH}`,
173
+ }));
174
+ });
175
+ }
176
+ export function vaultRoutes(api) {
177
+ vaultRoutesAt(api, "/v1/tenant/vaults", MANAGEMENT);
178
+ tenantRoute(api, CALLBACK, {
179
+ method: "get",
180
+ path: OAUTH_CALLBACK_PATH,
181
+ tags: ["Vaults"],
182
+ summary: "Finish an MCP OAuth connect",
183
+ description: "Where the authorization server sends the browser back with `code` and `state` (or `error`). Exchanges the code once and stores the credential; answers a small HTML page. Needs no credential and no `Nylorun-Protocol`. A `state` is used once, for ten minutes (`oauth_state_invalid`).",
184
+ request: {
185
+ query: z.object({
186
+ code: z.string().optional(),
187
+ state: z.string().optional(),
188
+ error: z.string().optional(),
189
+ }),
190
+ },
191
+ responses: {
192
+ 200: { description: "Connected", content: { "text/html": { schema: z.string() } } },
193
+ 502: { description: "The authorization server refused the code (`oauth_failed`)" },
194
+ },
195
+ }, async (c) => {
196
+ const state = c.req.query("state");
197
+ const code = c.req.query("code");
198
+ const error = c.req.query("error");
199
+ if (!state)
200
+ return page(400, "Sign-in failed", "The authorization server sent no state. Start the connect again.");
201
+ try {
202
+ await c.env.tenant.keys.finishOAuth({
203
+ state,
204
+ ...(code === undefined ? {} : { code }),
205
+ ...(error === undefined ? {} : { error }),
206
+ });
207
+ }
208
+ catch (failure) {
209
+ if (failure instanceof HttpError || failure instanceof VaultError)
210
+ return page(failure.status, "Sign-in failed", failure.message);
211
+ c.env.tenant.config.logger.error("oauth_callback_failed", {
212
+ error: failure instanceof Error ? failure.name : "unknown",
213
+ });
214
+ return page(500, "Sign-in failed", "The connect failed. Start it again.");
215
+ }
216
+ return page(200, "Connected", "Connected. You can close this tab.");
217
+ });
218
+ }
219
+ const ESCAPES = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
220
+ const escape = (text) => text.replace(/[&<>"']/g, (char) => ESCAPES[char]);
221
+ /** The callback's answer: a small page that loads nothing, is never cached and leaks no referrer. */
222
+ function page(status, title, message) {
223
+ const html = `<!doctype html>
224
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
225
+ <title>${escape(title)} · Nylorun</title>
226
+ <style>body{font:16px/1.5 system-ui,sans-serif;max-width:32rem;margin:15vh auto;padding:0 1rem;color:#1a1a1a;background:#fff}@media (prefers-color-scheme:dark){body{color:#eee;background:#111}}h1{font-size:1.25rem}</style>
227
+ </head><body><h1>${escape(title)}</h1><p>${escape(message)}</p></body></html>
228
+ `;
229
+ return new Response(html, {
230
+ status,
231
+ headers: {
232
+ "content-type": "text/html; charset=utf-8",
233
+ "cache-control": "no-store",
234
+ "referrer-policy": "no-referrer",
235
+ "content-security-policy": "default-src 'none'; style-src 'unsafe-inline'",
236
+ "x-content-type-options": "nosniff",
237
+ },
238
+ });
167
239
  }
@@ -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 {};