@nylorun/runtime 0.13.0-beta → 0.15.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 (309) hide show
  1. package/CHANGELOG.md +434 -0
  2. package/README.md +137 -41
  3. package/dist/adapters/execution/restate.d.ts +7 -2
  4. package/dist/adapters/execution/restate.js +40 -10
  5. package/dist/adapters/replication/pgoutput.d.ts +21 -0
  6. package/dist/adapters/replication/pgoutput.js +170 -0
  7. package/dist/adapters/streams/s2.js +37 -20
  8. package/dist/admin-openapi.json +570 -0
  9. package/dist/api/a2a/card.d.ts +15 -0
  10. package/dist/api/a2a/card.js +24 -0
  11. package/dist/api/a2a/endpoint.d.ts +8 -0
  12. package/dist/api/a2a/endpoint.js +81 -0
  13. package/dist/api/a2a/protocol.d.ts +144 -0
  14. package/dist/api/a2a/protocol.js +188 -0
  15. package/dist/api/a2a/routes.d.ts +19 -0
  16. package/dist/api/a2a/routes.js +289 -0
  17. package/dist/api/a2a/tasks.d.ts +50 -0
  18. package/dist/api/a2a/tasks.js +186 -0
  19. package/dist/api/ag-ui/endpoint.d.ts +8 -0
  20. package/dist/api/ag-ui/endpoint.js +126 -0
  21. package/dist/api/ag-ui/history.d.ts +7 -0
  22. package/dist/api/ag-ui/history.js +60 -0
  23. package/dist/api/ag-ui/routes.d.ts +32 -0
  24. package/dist/api/ag-ui/routes.js +305 -0
  25. package/dist/api/ag-ui/session-id.d.ts +1 -0
  26. package/dist/api/ag-ui/session-id.js +12 -0
  27. package/dist/api/ag-ui/sse.d.ts +9 -0
  28. package/dist/api/ag-ui/sse.js +7 -0
  29. package/dist/api/ag-ui/translate.d.ts +38 -0
  30. package/dist/api/ag-ui/translate.js +222 -0
  31. package/dist/api/components.d.ts +8065 -0
  32. package/dist/api/components.js +82 -0
  33. package/dist/api/gate/keys.d.ts +14 -0
  34. package/dist/api/gate/keys.js +59 -0
  35. package/dist/api/gate/routes.d.ts +34 -0
  36. package/dist/api/gate/routes.js +235 -0
  37. package/dist/api/http/app.d.ts +18 -0
  38. package/dist/api/http/app.js +58 -0
  39. package/dist/api/http/body.d.ts +4 -0
  40. package/dist/api/http/body.js +37 -0
  41. package/dist/api/http/define.d.ts +39 -0
  42. package/dist/api/http/define.js +122 -0
  43. package/dist/api/http/respond.d.ts +9 -0
  44. package/dist/api/http/respond.js +44 -0
  45. package/dist/api/http/routes/access.d.ts +24 -0
  46. package/dist/api/http/routes/access.js +266 -0
  47. package/dist/api/http/routes/actions.d.ts +8 -0
  48. package/dist/api/http/routes/actions.js +76 -0
  49. package/dist/api/http/routes/endpoints.d.ts +7 -0
  50. package/dist/api/http/routes/endpoints.js +100 -0
  51. package/dist/api/http/routes/sessions.d.ts +3 -0
  52. package/dist/api/http/routes/sessions.js +205 -0
  53. package/dist/api/http/routes/tenant.d.ts +11 -0
  54. package/dist/api/http/routes/tenant.js +244 -0
  55. package/dist/api/http/routes/vaults.d.ts +8 -0
  56. package/dist/api/http/routes/vaults.js +167 -0
  57. package/dist/api/openapi.d.ts +19 -0
  58. package/dist/api/openapi.js +137 -0
  59. package/dist/api/route.d.ts +12 -0
  60. package/dist/api/route.js +4 -0
  61. package/dist/core/bearer.d.ts +8 -0
  62. package/dist/core/bearer.js +11 -0
  63. package/dist/core/flow-host.d.ts +7 -15
  64. package/dist/core/flow-host.js +16 -41
  65. package/dist/core/sandbox-routes.d.ts +12 -7
  66. package/dist/core/sandbox-routes.js +24 -25
  67. package/dist/execution/memory.d.ts +8 -5
  68. package/dist/execution/memory.js +33 -13
  69. package/dist/execution/types.d.ts +38 -6
  70. package/dist/execution/types.js +12 -3
  71. package/dist/gates/contract.d.ts +51 -0
  72. package/dist/gates/contract.js +37 -0
  73. package/dist/gates/handler.d.ts +21 -0
  74. package/dist/gates/handler.js +55 -0
  75. package/dist/gates/http-client.d.ts +12 -0
  76. package/dist/gates/http-client.js +160 -0
  77. package/dist/gates/in-process.d.ts +32 -0
  78. package/dist/gates/in-process.js +42 -0
  79. package/dist/gates/inflight.d.ts +39 -0
  80. package/dist/gates/inflight.js +70 -0
  81. package/dist/gates/mcp-handler.d.ts +35 -0
  82. package/dist/gates/mcp-handler.js +142 -0
  83. package/dist/gates/meter.d.ts +24 -0
  84. package/dist/gates/meter.js +165 -0
  85. package/dist/gates/model-gate.d.ts +45 -0
  86. package/dist/gates/model-gate.js +1 -0
  87. package/dist/gates/tenant-vaults.d.ts +64 -0
  88. package/dist/gates/tenant-vaults.js +94 -0
  89. package/dist/gates/tool-calls.d.ts +51 -0
  90. package/dist/gates/tool-calls.js +64 -0
  91. package/dist/gates/tool-client.d.ts +12 -0
  92. package/dist/gates/tool-client.js +201 -0
  93. package/dist/gates/tool-contract.d.ts +116 -0
  94. package/dist/gates/tool-contract.js +64 -0
  95. package/dist/gates/tool-gate.d.ts +45 -0
  96. package/dist/gates/tool-gate.js +10 -0
  97. package/dist/host/admin-api.d.ts +23 -0
  98. package/dist/host/admin-api.js +74 -0
  99. package/dist/host/app.d.ts +34 -0
  100. package/dist/host/app.js +181 -0
  101. package/dist/host/config-for.d.ts +3 -1
  102. package/dist/host/config-for.js +3 -2
  103. package/dist/host/config.d.ts +11 -0
  104. package/dist/host/cors.d.ts +27 -0
  105. package/dist/host/cors.js +64 -0
  106. package/dist/host/create-host.d.ts +36 -8
  107. package/dist/host/create-host.js +161 -330
  108. package/dist/host/execution.d.ts +20 -18
  109. package/dist/host/execution.js +2 -2
  110. package/dist/host/gates.d.ts +58 -0
  111. package/dist/host/gates.js +127 -0
  112. package/dist/host/http.d.ts +20 -4
  113. package/dist/host/http.js +81 -23
  114. package/dist/host/index.d.ts +1 -1
  115. package/dist/host/main.js +189 -58
  116. package/dist/host/stack-config.d.ts +91 -19
  117. package/dist/host/stack-config.js +246 -17
  118. package/dist/infra/database.d.ts +2 -2
  119. package/dist/infra/execution.d.ts +5 -5
  120. package/dist/infra/execution.js +8 -6
  121. package/dist/infra/index.d.ts +1 -1
  122. package/dist/infra/workers.d.ts +17 -17
  123. package/dist/infra/workers.js +9 -9
  124. package/dist/keys/client.d.ts +9 -0
  125. package/dist/keys/client.js +70 -0
  126. package/dist/keys/contract.d.ts +24 -0
  127. package/dist/keys/contract.js +12 -0
  128. package/dist/keys/keys.d.ts +41 -0
  129. package/dist/keys/keys.js +50 -0
  130. package/dist/mcp/connect.d.ts +43 -3
  131. package/dist/mcp/connect.js +12 -5
  132. package/dist/mcp/pool.d.ts +39 -3
  133. package/dist/mcp/pool.js +74 -11
  134. package/dist/model/catalog.d.ts +2 -10
  135. package/dist/model/classify.d.ts +13 -0
  136. package/dist/model/classify.js +61 -0
  137. package/dist/model/models.d.ts +10 -1
  138. package/dist/model/models.js +14 -6
  139. package/dist/model/pi-model.d.ts +17 -2
  140. package/dist/model/pi-model.js +366 -222
  141. package/dist/openapi.json +25889 -0
  142. package/dist/record/append.d.ts +51 -0
  143. package/dist/record/append.js +20 -0
  144. package/dist/record/envelope.d.ts +19 -0
  145. package/dist/record/envelope.js +49 -0
  146. package/dist/record/index.d.ts +11 -0
  147. package/dist/record/index.js +11 -0
  148. package/dist/sandbox/manager.d.ts +13 -1
  149. package/dist/sandbox/manager.js +8 -11
  150. package/dist/sandbox/resolve.d.ts +33 -0
  151. package/dist/sandbox/resolve.js +81 -0
  152. package/dist/sandbox/session-sandbox.d.ts +11 -0
  153. package/dist/sandbox/session-sandbox.js +51 -0
  154. package/dist/sandbox/share.d.ts +14 -2
  155. package/dist/sandbox/share.js +33 -3
  156. package/dist/sandbox/tenant-config.d.ts +37 -0
  157. package/dist/sandbox/tenant-config.js +51 -0
  158. package/dist/sandbox/tools.d.ts +7 -9
  159. package/dist/sandbox/tools.js +11 -3
  160. package/dist/sandbox/types.d.ts +8 -2
  161. package/dist/store/postgres/connect.d.ts +25 -9
  162. package/dist/store/postgres/connect.js +27 -10
  163. package/dist/store/postgres/db.d.ts +16 -0
  164. package/dist/store/postgres/db.js +28 -0
  165. package/dist/store/postgres/drizzle/0000_foundation.sql +22 -0
  166. package/dist/store/postgres/drizzle/0001_baseline.sql +255 -0
  167. package/dist/store/postgres/drizzle/0002_stream_relay.sql +4 -0
  168. package/dist/store/postgres/drizzle/0003_tool_crossings.sql +9 -0
  169. package/dist/store/postgres/drizzle/meta/_journal.json +34 -0
  170. package/dist/store/postgres/migrate.d.ts +68 -0
  171. package/dist/store/postgres/migrate.js +183 -0
  172. package/dist/store/postgres/record-writer.d.ts +4 -0
  173. package/dist/store/postgres/record-writer.js +34 -0
  174. package/dist/store/postgres/record.d.ts +5 -0
  175. package/dist/store/postgres/record.js +60 -0
  176. package/dist/store/postgres/schema.d.ts +3096 -0
  177. package/dist/store/postgres/schema.js +363 -0
  178. package/dist/store/postgres/store.d.ts +2 -4
  179. package/dist/store/postgres/store.js +590 -434
  180. package/dist/store/postgres/tenant.d.ts +56 -0
  181. package/dist/store/postgres/tenant.js +154 -0
  182. package/dist/store/types.d.ts +183 -132
  183. package/dist/store/types.js +0 -1
  184. package/dist/streams/basin.d.ts +18 -1
  185. package/dist/streams/basin.js +34 -2
  186. package/dist/streams/control.d.ts +18 -0
  187. package/dist/streams/control.js +33 -0
  188. package/dist/streams/memory.d.ts +3 -1
  189. package/dist/streams/memory.js +14 -8
  190. package/dist/streams/relay/core.d.ts +35 -0
  191. package/dist/streams/relay/core.js +366 -0
  192. package/dist/streams/relay/types.d.ts +78 -0
  193. package/dist/streams/relay/types.js +8 -0
  194. package/dist/streams/types.d.ts +71 -36
  195. package/dist/streams/types.js +18 -53
  196. package/dist/tenant/access-policy.d.ts +30 -0
  197. package/dist/tenant/access-policy.js +52 -0
  198. package/dist/tenant/actions.d.ts +10 -149
  199. package/dist/tenant/actions.js +5 -167
  200. package/dist/tenant/advance.d.ts +7 -2
  201. package/dist/tenant/advance.js +125 -14
  202. package/dist/tenant/auth.d.ts +19 -17
  203. package/dist/tenant/auth.js +90 -93
  204. package/dist/tenant/browser.d.ts +15 -0
  205. package/dist/tenant/browser.js +39 -0
  206. package/dist/tenant/cause.d.ts +25 -0
  207. package/dist/tenant/cause.js +45 -0
  208. package/dist/tenant/commands.d.ts +18 -2
  209. package/dist/tenant/commands.js +111 -115
  210. package/dist/tenant/context.d.ts +101 -21
  211. package/dist/tenant/context.js +14 -10
  212. package/dist/tenant/delivery-token.d.ts +41 -0
  213. package/dist/tenant/delivery-token.js +104 -0
  214. package/dist/tenant/delivery.d.ts +62 -0
  215. package/dist/tenant/delivery.js +481 -0
  216. package/dist/tenant/effects.d.ts +20 -1
  217. package/dist/tenant/effects.js +159 -42
  218. package/dist/tenant/endpoints.d.ts +67 -0
  219. package/dist/tenant/endpoints.js +90 -0
  220. package/dist/tenant/ephemeral.d.ts +22 -7
  221. package/dist/tenant/ephemeral.js +83 -125
  222. package/dist/tenant/history.d.ts +64 -0
  223. package/dist/tenant/history.js +120 -0
  224. package/dist/tenant/http.d.ts +8 -9
  225. package/dist/tenant/http.js +13 -27
  226. package/dist/tenant/jwt.d.ts +16 -0
  227. package/dist/tenant/jwt.js +50 -0
  228. package/dist/tenant/model-setting.d.ts +2 -2
  229. package/dist/tenant/module.d.ts +17 -28
  230. package/dist/tenant/module.js +133 -279
  231. package/dist/tenant/outbound.d.ts +44 -0
  232. package/dist/tenant/outbound.js +127 -0
  233. package/dist/tenant/paths.d.ts +11 -16
  234. package/dist/tenant/paths.js +24 -68
  235. package/dist/tenant/pool.d.ts +1 -3
  236. package/dist/tenant/pool.js +1 -19
  237. package/dist/tenant/principals.d.ts +23 -11
  238. package/dist/tenant/principals.js +61 -49
  239. package/dist/tenant/reset.d.ts +0 -4
  240. package/dist/tenant/reset.js +0 -5
  241. package/dist/tenant/runtime.d.ts +28 -20
  242. package/dist/tenant/runtime.js +95 -64
  243. package/dist/tenant/scheduler.d.ts +10 -3
  244. package/dist/tenant/scheduler.js +9 -5
  245. package/dist/tenant/session-streams.d.ts +127 -0
  246. package/dist/tenant/session-streams.js +404 -0
  247. package/dist/tenant/sessions.d.ts +28 -4
  248. package/dist/tenant/sessions.js +118 -24
  249. package/dist/tenant/signing-keys.d.ts +55 -0
  250. package/dist/tenant/signing-keys.js +172 -0
  251. package/dist/tenant/slim.d.ts +8 -0
  252. package/dist/tenant/slim.js +21 -0
  253. package/dist/tenant/status.d.ts +3 -3
  254. package/dist/tenant/status.js +20 -13
  255. package/dist/tenant/store-pg.d.ts +9 -6
  256. package/dist/tenant/store-pg.js +60 -125
  257. package/dist/tenant/streams.d.ts +62 -85
  258. package/dist/tenant/streams.js +143 -226
  259. package/dist/tenant/subject-limits.d.ts +16 -0
  260. package/dist/tenant/subject-limits.js +45 -0
  261. package/dist/tenant/sweep.d.ts +1 -10
  262. package/dist/tenant/sweep.js +29 -69
  263. package/dist/tenant/tokens.d.ts +14 -0
  264. package/dist/tenant/tokens.js +180 -0
  265. package/dist/tenant/transcript.d.ts +48 -5
  266. package/dist/tenant/transcript.js +58 -1
  267. package/dist/tenant/types.d.ts +69 -98
  268. package/dist/tenant/types.js +4 -15
  269. package/dist/tenant/worker.d.ts +3 -1
  270. package/dist/tenant/worker.js +13 -7
  271. package/dist/vault/host-model.d.ts +31 -0
  272. package/dist/vault/host-model.js +57 -0
  273. package/dist/vault/service.d.ts +44 -17
  274. package/dist/vault/service.js +126 -121
  275. package/dist/version.d.ts +1 -1
  276. package/dist/version.js +1 -1
  277. package/package.json +25 -9
  278. package/dist/core/executors.d.ts +0 -44
  279. package/dist/core/executors.js +0 -95
  280. package/dist/store/memory.d.ts +0 -57
  281. package/dist/store/memory.js +0 -645
  282. package/dist/store/postgres/migrations/001_initial.d.ts +0 -27
  283. package/dist/store/postgres/migrations/001_initial.js +0 -196
  284. package/dist/store/postgres/migrations/002_session_owner.d.ts +0 -6
  285. package/dist/store/postgres/migrations/002_session_owner.js +0 -13
  286. package/dist/store/postgres/migrations/index.d.ts +0 -49
  287. package/dist/store/postgres/migrations/index.js +0 -76
  288. package/dist/store/postgres/names.d.ts +0 -11
  289. package/dist/store/postgres/names.js +0 -42
  290. package/dist/store/postgres/tenants.d.ts +0 -90
  291. package/dist/store/postgres/tenants.js +0 -214
  292. package/dist/streams/relay.d.ts +0 -37
  293. package/dist/streams/relay.js +0 -254
  294. package/dist/tenant/envelope.d.ts +0 -7
  295. package/dist/tenant/envelope.js +0 -22
  296. package/dist/tenant/live.d.ts +0 -92
  297. package/dist/tenant/live.js +0 -290
  298. package/dist/tenant/quarantine-error.d.ts +0 -6
  299. package/dist/tenant/quarantine-error.js +0 -9
  300. package/dist/tenant/quarantine.d.ts +0 -27
  301. package/dist/tenant/quarantine.js +0 -72
  302. package/dist/tenant/routes-tenant.d.ts +0 -12
  303. package/dist/tenant/routes-tenant.js +0 -137
  304. package/dist/tenant/routes.d.ts +0 -9
  305. package/dist/tenant/routes.js +0 -151
  306. package/dist/tenant/store-memory.d.ts +0 -16
  307. package/dist/tenant/store-memory.js +0 -111
  308. /package/dist/{store → record}/cursor.d.ts +0 -0
  309. /package/dist/{store → record}/cursor.js +0 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Named schemas of the OpenAPI document: each becomes `#/components/schemas/<id>`, referenced
3
+ * wherever a route uses it. Named with Zod's own `.meta({ id })`, which works on the contracts'
4
+ * schemas whenever they were created; made once per process, since ids are unique in Zod's
5
+ * global registry.
6
+ */
7
+ import { z } from "zod";
8
+ import { JwksSchema, CreateTokenRequestSchema, CreateTokenResponseSchema, AccessPolicyResponseSchema, PutAccessPolicyRequestSchema, SigningKeyListSchema, SigningKeyViewSchema, RotateSigningKeysRequestSchema, RevokeSigningKeyRequestSchema, ListPublishableKeysResponseSchema, PublishableKeySchema, CreatePublishableKeyRequestSchema, UpdatePublishableKeyRequestSchema, RevokeSubjectRequestSchema, RevokeSubjectResponseSchema, TenantStatusSchema, ResetTenantRequestSchema, ResetTenantResponseSchema, SeedTenantConfigRequestSchema, SeedTenantConfigResponseSchema, HostModelCatalogSchema, TenantSandboxViewSchema, ModelUsageTotalsSchema, ModelBudgetsSchema, PutModelBudgetsRequestSchema, PutTenantSandboxRequestSchema, ListProvidersResponseSchema, HostModelViewSchema, PutHostModelRequestSchema, SelectHostModelRequestSchema, CreateVaultRequestSchema, VaultInfoSchema, ListVaultsResponseSchema, CreateCredentialRequestSchema, CredentialInfoSchema, ListCredentialsResponseSchema, RotateCredentialRequestSchema, DeletedResponseSchema, ListAgentsResponseSchema, ListPublicAgentsResponseSchema, ListSessionsResponseSchema, LiveEventSchema, PutAgentRequestSchema, PutAgentResponseSchema, PutSessionRequestSchema, SessionItemsResponseSchema, SessionViewSchema, StreamClosedFrameSchema, AcceptedResponseSchema, ActionResultReceiptSchema, DeleteEndpointResponseSchema, DeliveryHeartbeatResponseSchema, ActionOutcomeSchema, EndpointPingResponseSchema, ListEndpointsResponseSchema, PutEndpointsRequestSchema, SandboxToolOutcomeSchema, SessionCommandSchema, AdminStatusSchema, HostShutdownResponseSchema, ProtocolRejectedResponseSchema, RejectedResponseSchema, EVENT_SCHEMAS, EVENT_TYPES, } from "@nylorun/core/contracts";
9
+ function named(id, schema) {
10
+ return schema.meta({ id });
11
+ }
12
+ export const Rejected = named("Rejected", RejectedResponseSchema);
13
+ export const ProtocolRejected = named("ProtocolRejected", ProtocolRejectedResponseSchema);
14
+ export const AdminStatus = named("AdminStatus", AdminStatusSchema);
15
+ export const HostShutdownResponse = named("HostShutdownResponse", HostShutdownResponseSchema);
16
+ export const SandboxToolOutcome = named("SandboxToolOutcome", SandboxToolOutcomeSchema);
17
+ export const PutEndpointsRequest = named("PutEndpointsRequest", PutEndpointsRequestSchema);
18
+ export const ListEndpointsResponse = named("ListEndpointsResponse", ListEndpointsResponseSchema);
19
+ export const DeleteEndpointResponse = named("DeleteEndpointResponse", DeleteEndpointResponseSchema);
20
+ export const EndpointPingResponse = named("EndpointPingResponse", EndpointPingResponseSchema);
21
+ export const DeliveryHeartbeatResponse = named("DeliveryHeartbeatResponse", DeliveryHeartbeatResponseSchema);
22
+ export const ActionOutcome = named("ActionOutcome", ActionOutcomeSchema);
23
+ export const SessionCommand = named("SessionCommand", SessionCommandSchema);
24
+ export const AcceptedResponse = named("AcceptedResponse", AcceptedResponseSchema);
25
+ export const ActionResultReceipt = named("ActionResultReceipt", ActionResultReceiptSchema);
26
+ export const ListAgentsResponse = named("ListAgentsResponse", ListAgentsResponseSchema);
27
+ export const ListPublicAgentsResponse = named("ListPublicAgentsResponse", ListPublicAgentsResponseSchema);
28
+ export const PutAgentRequest = named("PutAgentRequest", PutAgentRequestSchema);
29
+ export const PutAgentResponse = named("PutAgentResponse", PutAgentResponseSchema);
30
+ export const ListSessionsResponse = named("ListSessionsResponse", ListSessionsResponseSchema);
31
+ export const PutSessionRequest = named("PutSessionRequest", PutSessionRequestSchema);
32
+ export const SessionView = named("SessionView", SessionViewSchema);
33
+ export const LiveEvent = named("LiveEvent", LiveEventSchema);
34
+ /** `action.delivery_failed` → `ActionDeliveryFailedEvent`. */
35
+ export function eventComponentName(type) {
36
+ return `${type
37
+ .split(/[._]/)
38
+ .map((part) => part[0].toUpperCase() + part.slice(1))
39
+ .join("")}Event`;
40
+ }
41
+ /** The event catalog as components: one per event type, and `SessionEvent`, their union. */
42
+ export const SessionEvent = named("SessionEvent", z.discriminatedUnion("type", EVENT_TYPES.map((type) => named(eventComponentName(type), EVENT_SCHEMAS[type]))));
43
+ export const SessionItemsResponse = named("SessionItemsResponse", SessionItemsResponseSchema.extend({ items: z.array(SessionEvent) }));
44
+ export const StreamClosedFrame = named("StreamClosedFrame", StreamClosedFrameSchema);
45
+ export const TenantStatus = named("TenantStatus", TenantStatusSchema);
46
+ export const ResetTenantRequest = named("ResetTenantRequest", ResetTenantRequestSchema);
47
+ export const ResetTenantResponse = named("ResetTenantResponse", ResetTenantResponseSchema);
48
+ export const SeedTenantConfigRequest = named("SeedTenantConfigRequest", SeedTenantConfigRequestSchema);
49
+ export const SeedTenantConfigResponse = named("SeedTenantConfigResponse", SeedTenantConfigResponseSchema);
50
+ export const HostModelCatalog = named("HostModelCatalog", HostModelCatalogSchema);
51
+ export const TenantSandboxView = named("TenantSandboxView", TenantSandboxViewSchema);
52
+ export const ModelUsageTotals = named("ModelUsageTotals", ModelUsageTotalsSchema);
53
+ export const ModelBudgets = named("ModelBudgets", ModelBudgetsSchema);
54
+ export const PutModelBudgetsRequest = named("PutModelBudgetsRequest", PutModelBudgetsRequestSchema);
55
+ export const PutTenantSandboxRequest = named("PutTenantSandboxRequest", PutTenantSandboxRequestSchema);
56
+ export const ListProvidersResponse = named("ListProvidersResponse", ListProvidersResponseSchema);
57
+ export const HostModelView = named("HostModelView", HostModelViewSchema);
58
+ export const PutHostModelRequest = named("PutHostModelRequest", PutHostModelRequestSchema);
59
+ export const SelectHostModelRequest = named("SelectHostModelRequest", SelectHostModelRequestSchema);
60
+ export const CreateVaultRequest = named("CreateVaultRequest", CreateVaultRequestSchema);
61
+ export const VaultInfo = named("VaultInfo", VaultInfoSchema);
62
+ export const ListVaultsResponse = named("ListVaultsResponse", ListVaultsResponseSchema);
63
+ export const CreateCredentialRequest = named("CreateCredentialRequest", CreateCredentialRequestSchema);
64
+ export const CredentialInfo = named("CredentialInfo", CredentialInfoSchema);
65
+ export const ListCredentialsResponse = named("ListCredentialsResponse", ListCredentialsResponseSchema);
66
+ export const RotateCredentialRequest = named("RotateCredentialRequest", RotateCredentialRequestSchema);
67
+ export const DeletedResponse = named("DeletedResponse", DeletedResponseSchema);
68
+ export const Jwks = named("Jwks", JwksSchema);
69
+ export const CreateTokenRequest = named("CreateTokenRequest", CreateTokenRequestSchema);
70
+ export const CreateTokenResponse = named("CreateTokenResponse", CreateTokenResponseSchema);
71
+ export const AccessPolicyResponse = named("AccessPolicyResponse", AccessPolicyResponseSchema);
72
+ export const PutAccessPolicyRequest = named("PutAccessPolicyRequest", PutAccessPolicyRequestSchema);
73
+ export const SigningKeyList = named("SigningKeyList", SigningKeyListSchema);
74
+ export const SigningKeyView = named("SigningKeyView", SigningKeyViewSchema);
75
+ export const RotateSigningKeysRequest = named("RotateSigningKeysRequest", RotateSigningKeysRequestSchema);
76
+ export const RevokeSigningKeyRequest = named("RevokeSigningKeyRequest", RevokeSigningKeyRequestSchema);
77
+ export const ListPublishableKeysResponse = named("ListPublishableKeysResponse", ListPublishableKeysResponseSchema);
78
+ export const PublishableKey = named("PublishableKey", PublishableKeySchema);
79
+ export const CreatePublishableKeyRequest = named("CreatePublishableKeyRequest", CreatePublishableKeyRequestSchema);
80
+ export const UpdatePublishableKeyRequest = named("UpdatePublishableKeyRequest", UpdatePublishableKeyRequestSchema);
81
+ export const RevokeSubjectRequest = named("RevokeSubjectRequest", RevokeSubjectRequestSchema);
82
+ export const RevokeSubjectResponse = named("RevokeSubjectResponse", RevokeSubjectResponseSchema);
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The `keys` service's route on the gateway's listener (F4.2, `contract.ts`): one operation of
3
+ * `Keys` per request, run with the vault key of the gateway's Tenant. Errors keep their status,
4
+ * code and details. Logs the operation and its outcome, never an argument or a result.
5
+ */
6
+ import type { Hono, MiddlewareHandler } from "hono";
7
+ import type { Logger } from "../../tenant/types.js";
8
+ import { type Keys } from "../../keys/keys.js";
9
+ export declare function mountKeysRoutes(app: Hono, options: {
10
+ readonly authorized: MiddlewareHandler;
11
+ /** The gateway's Tenant's keys; rejects when the Tenant is not ready. */
12
+ readonly keys: () => Promise<Keys>;
13
+ readonly logger: Logger;
14
+ }): void;
@@ -0,0 +1,59 @@
1
+ import { bodyLimit } from "hono/body-limit";
2
+ import { HttpError } from "../../tenant/http.js";
3
+ import { VaultError } from "../../vault/error.js";
4
+ import { KEYS_PATH, MAX_KEYS_BODY_BYTES } from "../../keys/contract.js";
5
+ import { KEYS_OPERATIONS } from "../../keys/keys.js";
6
+ export function mountKeysRoutes(app, options) {
7
+ app.post(`${KEYS_PATH}/:operation`, options.authorized, bodyLimit({
8
+ maxSize: MAX_KEYS_BODY_BYTES,
9
+ onError: (c) => c.json({ error: { code: "invalid_request", message: "The body is too large" } }, 400),
10
+ }), async (c) => {
11
+ const operation = c.req.param("operation");
12
+ if (!KEYS_OPERATIONS.includes(operation))
13
+ return c.json({ error: { code: "invalid_request", message: `Unknown keys operation ${operation}` } }, 404);
14
+ let args;
15
+ try {
16
+ args = (await c.req.json()).args;
17
+ }
18
+ catch {
19
+ args = undefined;
20
+ }
21
+ if (!Array.isArray(args))
22
+ return c.json({ error: { code: "invalid_request", message: "The body must be {args: [...]}" } }, 400);
23
+ const started = Date.now();
24
+ let answer;
25
+ try {
26
+ const keys = await options.keys();
27
+ const run = keys[operation];
28
+ answer = { result: (await run.apply(keys, args)) ?? null };
29
+ }
30
+ catch (error) {
31
+ answer = { error: errorOf(error) };
32
+ }
33
+ options.logger.info("keys_request", {
34
+ operation,
35
+ ms: Date.now() - started,
36
+ outcome: "result" in answer ? "ok" : String(answer.error.status),
37
+ });
38
+ return c.json(answer);
39
+ });
40
+ }
41
+ function errorOf(error) {
42
+ if (error instanceof VaultError)
43
+ return { kind: "vault", status: error.status, message: error.message };
44
+ if (error instanceof HttpError)
45
+ return {
46
+ kind: "http",
47
+ status: error.status,
48
+ message: error.message,
49
+ ...(error.rejection.code === undefined ? {} : { code: error.rejection.code }),
50
+ ...(error.rejection.details === undefined ? {} : { details: error.rejection.details }),
51
+ };
52
+ // A request error the route would answer 400 for, or an internal failure.
53
+ const zod = error?.name === "ZodError";
54
+ return {
55
+ kind: "http",
56
+ status: zod ? 400 : 500,
57
+ message: zod ? error.message : "The keys service failed",
58
+ };
59
+ }
@@ -0,0 +1,34 @@
1
+ import { Hono } from "hono";
2
+ import type { ModelCallHandler } from "../../gates/handler.js";
3
+ import { type InflightCalls } from "../../gates/inflight.js";
4
+ import type { McpHandler } from "../../gates/mcp-handler.js";
5
+ import type { ToolCalls } from "../../gates/tool-calls.js";
6
+ import type { Keys } from "../../keys/keys.js";
7
+ import type { Logger } from "../../tenant/types.js";
8
+ import { type OutboundPolicy } from "../../tenant/outbound.js";
9
+ export interface GatesAppOptions {
10
+ /** The bearer every model call must present (`NYLORUN_GATES_TOKEN`). */
11
+ readonly token: string;
12
+ /** Serves an authenticated, well-formed call. */
13
+ readonly modelGate: ModelCallHandler;
14
+ /** Keyed calls, which outlive their client (P1.2). */
15
+ readonly inflight: InflightCalls;
16
+ /** Whether the gate's dependencies answer (Postgres). */
17
+ readonly ready: () => Promise<boolean>;
18
+ /** Largest body read. Default `MAX_MODEL_CALL_BYTES`. */
19
+ readonly maxBodyBytes?: number;
20
+ /** Remote MCP servers (F4.1). Without it the MCP routes answer 404. */
21
+ readonly mcp?: McpHandler;
22
+ /** Keyed MCP calls, which outlive their client and run once (F4.1 G3). Needs `mcp`. */
23
+ readonly toolCalls?: ToolCalls;
24
+ /** The keys service's operations (F4.2). Without it the keys route answers 404. */
25
+ readonly keys?: () => Promise<Keys>;
26
+ /** Logs the keys service's requests. */
27
+ readonly logger?: Logger;
28
+ /**
29
+ * How the gate may call Action endpoints (the gateway's own `NYLORUN_ENDPOINT_*`), for
30
+ * deliveries (F4.1). Without it the delivery route answers 404.
31
+ */
32
+ readonly delivery?: OutboundPolicy;
33
+ }
34
+ export declare function createGatesApp(options: GatesAppOptions): Hono;
@@ -0,0 +1,235 @@
1
+ /**
2
+ * The gates service's HTTP routes (blueprint §15, P1.1): the Model Gate's IR endpoint, the Tool
3
+ * Gate's remote MCP and delivery routes (F4.1), and the health and readiness probes. Internal:
4
+ * only the loop calls them, with the stack's gates token, so they are not in the published
5
+ * OpenAPI documents. The wire formats are `gates/contract.ts` and `gates/tool-contract.ts`.
6
+ */
7
+ import { createHash } from "node:crypto";
8
+ import { Hono } from "hono";
9
+ import { bodyLimit } from "hono/body-limit";
10
+ import { isTenantId } from "@nylorun/core/compatibility";
11
+ import { MAX_MODEL_CALL_BYTES, MODEL_CALLS_PATH, ModelCallBodySchema, TENANT_HEADER, } from "../../gates/contract.js";
12
+ import { InflightConflict } from "../../gates/inflight.js";
13
+ import { mountKeysRoutes } from "./keys.js";
14
+ import { DELIVERIES_PATH, DELIVERY_HEADERS, DeliveryBodySchema, MAX_TOOL_BODY_BYTES, MCP_CLOSE_PATH, MCP_CONNECT_PATH, MCP_LIST_PATH, McpListBodySchema, McpServerBodySchema, TOOL_CALLS_PATH, ToolCallBodySchema, } from "../../gates/tool-contract.js";
15
+ import { post } from "../../tenant/outbound.js";
16
+ import { adminKeyMatches } from "../../host/http.js";
17
+ import { canonical } from "../../store/canonical.js";
18
+ const invalid = (message) => ({
19
+ error: { code: "invalid_request", message },
20
+ });
21
+ export function createGatesApp(options) {
22
+ const app = new Hono();
23
+ const maxSize = options.maxBodyBytes ?? MAX_MODEL_CALL_BYTES;
24
+ app.get("/health", (c) => c.json({ status: "ok" }));
25
+ app.get("/ready", async (c) => (await options.ready()) ? c.json({ ready: true }) : c.json({ ready: false }, 503));
26
+ const authorized = async (c, next) => {
27
+ const presented = /^Bearer (.+)$/.exec(c.req.header("authorization") ?? "")?.[1];
28
+ if (!adminKeyMatches(presented, options.token)) {
29
+ const body = {
30
+ error: {
31
+ code: "gate_unauthorized",
32
+ message: "Missing or wrong gates token; the caller and the gateway must share NYLORUN_GATES_TOKEN",
33
+ },
34
+ };
35
+ return c.json(body, 401);
36
+ }
37
+ await next();
38
+ };
39
+ const tenantOf = (c) => {
40
+ const tenantId = c.req.header(TENANT_HEADER);
41
+ return tenantId !== undefined && !isTenantId(tenantId) ? false : tenantId;
42
+ };
43
+ const toolBodies = bodyLimit({
44
+ maxSize: MAX_TOOL_BODY_BYTES,
45
+ onError: (c) => c.json(invalid(`A request body may be at most ${MAX_TOOL_BODY_BYTES} bytes`), 400),
46
+ });
47
+ /** The parsed body, or the 400 to answer. */
48
+ async function read(c, schema) {
49
+ const tenantId = tenantOf(c);
50
+ if (tenantId === false)
51
+ return { ok: false, response: c.json(invalid(`The ${TENANT_HEADER} header must name a Tenant`), 400) };
52
+ let raw;
53
+ try {
54
+ raw = await c.req.json();
55
+ }
56
+ catch {
57
+ return { ok: false, response: c.json(invalid("The body must be JSON"), 400) };
58
+ }
59
+ const parsed = schema.safeParse(raw);
60
+ if (!parsed.success)
61
+ return {
62
+ ok: false,
63
+ response: c.json(invalid(`Invalid request: ${parsed.error.issues[0]?.message ?? "malformed"}`), 400),
64
+ };
65
+ return { ok: true, tenantId, body: parsed.data };
66
+ }
67
+ if (options.keys)
68
+ mountKeysRoutes(app, {
69
+ authorized,
70
+ keys: options.keys,
71
+ logger: options.logger ?? { info() { }, warn() { }, error() { } },
72
+ });
73
+ const mcp = options.mcp;
74
+ if (mcp) {
75
+ app.post(MCP_CONNECT_PATH, authorized, toolBodies, async (c) => {
76
+ const request = await read(c, McpServerBodySchema);
77
+ if (!request.ok)
78
+ return request.response;
79
+ return c.json(await mcp.connect(request.tenantId, request.body.server));
80
+ });
81
+ app.post(MCP_LIST_PATH, authorized, toolBodies, async (c) => {
82
+ const request = await read(c, McpListBodySchema);
83
+ if (!request.ok)
84
+ return request.response;
85
+ const { server, cursor } = request.body;
86
+ return c.json(await mcp.list(request.tenantId, server, cursor, c.req.raw.signal));
87
+ });
88
+ app.post(MCP_CLOSE_PATH, authorized, toolBodies, async (c) => {
89
+ const request = await read(c, McpServerBodySchema);
90
+ if (!request.ok)
91
+ return request.response;
92
+ await mcp.close(request.body.server);
93
+ return c.body(null, 204);
94
+ });
95
+ const toolCalls = options.toolCalls;
96
+ app.post(`${TOOL_CALLS_PATH}/:key/cancel`, authorized, (c) => {
97
+ if (tenantOf(c) === false)
98
+ return c.json(invalid(`The ${TENANT_HEADER} header must name a Tenant`), 400);
99
+ toolCalls?.cancel(c.req.param("key"));
100
+ return c.body(null, 204);
101
+ });
102
+ app.post(TOOL_CALLS_PATH, authorized, toolBodies, async (c) => {
103
+ const request = await read(c, ToolCallBodySchema);
104
+ if (!request.ok)
105
+ return request.response;
106
+ const signal = c.req.raw.signal;
107
+ const key = c.req.header("idempotency-key");
108
+ try {
109
+ // Keyed: the call runs under its own signal, once, and outlives this request (G3).
110
+ const answer = key && toolCalls
111
+ ? await untilAborted(toolCalls.run(request.tenantId, key, createHash("sha256").update(canonical(request.body)).digest("hex"), request.body), signal)
112
+ : await mcp.call(request.tenantId, request.body, signal);
113
+ if (signal.aborted)
114
+ return new Response(null, { status: 499 });
115
+ return c.json(answer);
116
+ }
117
+ catch (error) {
118
+ if (error instanceof InflightConflict) {
119
+ const body = { error: { code: "gate_conflict", message: error.message } };
120
+ return c.json(body, 409);
121
+ }
122
+ if (signal.aborted)
123
+ return new Response(null, { status: 499 });
124
+ throw error;
125
+ }
126
+ });
127
+ }
128
+ const policy = options.delivery;
129
+ if (policy) {
130
+ app.post(DELIVERIES_PATH, authorized, toolBodies, async (c) => {
131
+ const request = await read(c, DeliveryBodySchema);
132
+ if (!request.ok)
133
+ return request.response;
134
+ const { url, body, headers, timeoutMs } = request.body;
135
+ const forwarded = {};
136
+ for (const [name, value] of Object.entries(headers)) {
137
+ if (!DELIVERY_HEADERS.has(name.toLowerCase()))
138
+ return c.json(invalid(`A delivery may not carry the header ${name}`), 400);
139
+ forwarded[name] = value;
140
+ }
141
+ const signal = c.req.raw.signal;
142
+ const result = await post(url, body, forwarded, {
143
+ policy,
144
+ signal: AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]),
145
+ });
146
+ if (signal.aborted)
147
+ return new Response(null, { status: 499 });
148
+ const answer = {
149
+ result: result.kind === "response"
150
+ ? {
151
+ kind: "response",
152
+ status: result.status,
153
+ headers: result.headers,
154
+ body: result.body.toString("base64"),
155
+ }
156
+ : result,
157
+ };
158
+ return c.json(answer);
159
+ });
160
+ }
161
+ app.post(`${MODEL_CALLS_PATH}/:key/cancel`, authorized, (c) => {
162
+ // Optional, as on a call: the gate serves one Tenant, so the key alone names the call.
163
+ const tenantId = c.req.header(TENANT_HEADER);
164
+ if (tenantId !== undefined && !isTenantId(tenantId))
165
+ return c.json(invalid(`The ${TENANT_HEADER} header must name a Tenant`), 400);
166
+ options.inflight.cancel(c.req.param("key"));
167
+ return c.body(null, 204);
168
+ });
169
+ app.post(MODEL_CALLS_PATH, authorized, bodyLimit({
170
+ maxSize,
171
+ onError: (c) => c.json(invalid(`A model call body may be at most ${maxSize} bytes`), 400),
172
+ }), async (c) => {
173
+ // Optional: the gate serves its database's one Tenant, and refuses a call naming another.
174
+ const tenantId = c.req.header(TENANT_HEADER);
175
+ if (tenantId !== undefined && !isTenantId(tenantId))
176
+ return c.json(invalid(`The ${TENANT_HEADER} header must name a Tenant`), 400);
177
+ let raw;
178
+ try {
179
+ raw = await c.req.json();
180
+ }
181
+ catch {
182
+ return c.json(invalid("The body must be JSON"), 400);
183
+ }
184
+ const parsed = ModelCallBodySchema.safeParse(raw);
185
+ if (!parsed.success)
186
+ return c.json(invalid(`Invalid model call: ${parsed.error.issues[0]?.message ?? "malformed"}`), 400);
187
+ const { call, ...ids } = parsed.data;
188
+ const request = {
189
+ ...(tenantId === undefined ? {} : { tenantId }),
190
+ ...ids,
191
+ call: call,
192
+ };
193
+ const signal = c.req.raw.signal;
194
+ const key = c.req.header("idempotency-key");
195
+ try {
196
+ let outcome;
197
+ if (key) {
198
+ // Keyed: the call runs under its own signal and outlives this request (P1.2). The
199
+ // gate serves one Tenant, so the effect id alone is the key.
200
+ const hash = createHash("sha256").update(canonical(parsed.data)).digest("hex");
201
+ outcome = await untilAborted(options.inflight.run(key, hash, (own) => options.modelGate.call(request, own)), signal);
202
+ }
203
+ else
204
+ outcome = await options.modelGate.call(request, signal);
205
+ return c.json({ outcome });
206
+ }
207
+ catch (error) {
208
+ if (error instanceof InflightConflict) {
209
+ const body = { error: { code: "gate_conflict", message: error.message } };
210
+ return c.json(body, 409);
211
+ }
212
+ // The caller went away (or cancelled): nobody reads the answer.
213
+ if (signal.aborted)
214
+ return new Response(null, { status: 499 });
215
+ throw error;
216
+ }
217
+ });
218
+ return app;
219
+ }
220
+ /** `promise`, or a rejection as soon as `signal` aborts (the call itself keeps running). */
221
+ function untilAborted(promise, signal) {
222
+ if (signal.aborted)
223
+ return Promise.reject(signal.reason);
224
+ return new Promise((resolve, reject) => {
225
+ const onAbort = () => reject(signal.reason);
226
+ signal.addEventListener("abort", onAbort, { once: true });
227
+ promise.then((value) => {
228
+ signal.removeEventListener("abort", onAbort);
229
+ resolve(value);
230
+ }, (error) => {
231
+ signal.removeEventListener("abort", onAbort);
232
+ reject(error);
233
+ });
234
+ });
235
+ }
@@ -0,0 +1,18 @@
1
+ import { OpenAPIHono } from "@hono/zod-openapi";
2
+ import type { AuthScope, TenantContext } from "../../tenant/context.js";
3
+ import type { NodeBindings } from "../../tenant/types.js";
4
+ import { type RouteAccess } from "./define.js";
5
+ export type TenantBindings = NodeBindings & {
6
+ readonly tenant: TenantContext;
7
+ };
8
+ export type TenantEnv = {
9
+ Bindings: TenantBindings;
10
+ Variables: {
11
+ /** Who is calling, once authenticated. */
12
+ scope: AuthScope;
13
+ };
14
+ };
15
+ /** The Tenant API, built on first use. */
16
+ export declare function tenantApi(): OpenAPIHono<TenantEnv>;
17
+ /** Who may call `method` on a Tenant path (its decoded segments), if it is a route. */
18
+ export declare function findTenantRoute(method: string, segments: readonly string[]): RouteAccess | undefined;
@@ -0,0 +1,58 @@
1
+ import { OpenAPIHono } from "@hono/zod-openapi";
2
+ import { RESPONSE_ALREADY_SENT } from "@hono/node-server/utils/response";
3
+ import { fail } from "../../tenant/http.js";
4
+ import { a2aRoutes } from "../a2a/endpoint.js";
5
+ import { agUiRoutes } from "../ag-ui/endpoint.js";
6
+ import { authenticateCaller, declaredRoute, pathSegments } from "./define.js";
7
+ import { jsonResponse, rejectionOf } from "./respond.js";
8
+ import { accessRoutes } from "./routes/access.js";
9
+ import { endpointRoutes } from "./routes/endpoints.js";
10
+ import { actionRoutes } from "./routes/actions.js";
11
+ import { sessionRoutes } from "./routes/sessions.js";
12
+ import { tenantRoutes } from "./routes/tenant.js";
13
+ import { vaultRoutes } from "./routes/vaults.js";
14
+ let app;
15
+ /** The Tenant API, built on first use. */
16
+ export function tenantApi() {
17
+ return (app ??= build());
18
+ }
19
+ /** Who may call `method` on a Tenant path (its decoded segments), if it is a route. */
20
+ export function findTenantRoute(method, segments) {
21
+ tenantApi();
22
+ return declaredRoute(method, segments);
23
+ }
24
+ /** No route: authenticated first, so an unknown credential stays the opaque 404. */
25
+ async function notFound(c) {
26
+ await authenticateCaller(c);
27
+ return fail(404, "Route not found");
28
+ }
29
+ function build() {
30
+ const api = new OpenAPIHono();
31
+ // Hono serves HEAD with the GET route; the Tenant API has no HEAD routes.
32
+ api.use(async (c, next) => (c.req.method === "HEAD" ? await notFound(c) : await next()));
33
+ // A malformed path is rejected before anything else reads it.
34
+ api.use(async (c, next) => {
35
+ pathSegments(c.env.incoming);
36
+ await next();
37
+ });
38
+ actionRoutes(api);
39
+ endpointRoutes(api);
40
+ sessionRoutes(api);
41
+ tenantRoutes(api);
42
+ vaultRoutes(api);
43
+ accessRoutes(api);
44
+ agUiRoutes(api);
45
+ a2aRoutes(api);
46
+ api.notFound(notFound);
47
+ api.onError((error, c) => {
48
+ const { outgoing } = c.env;
49
+ // Once a response has started, the rejection can only end it.
50
+ if (outgoing.headersSent) {
51
+ outgoing.end();
52
+ return RESPONSE_ALREADY_SENT;
53
+ }
54
+ const rejection = rejectionOf(error);
55
+ return jsonResponse(rejection.status, rejection.body, rejection.headers);
56
+ });
57
+ return api;
58
+ }
@@ -0,0 +1,4 @@
1
+ /** The body as text. */
2
+ export declare function readText(request: Request): Promise<string>;
3
+ /** The body as JSON, before any schema. */
4
+ export declare function readJson(request: Request): Promise<unknown>;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Request bodies of Tenant routes, read as the router they replace read them
3
+ * (`tenant/http.ts`): at most 1 MiB, UTF-8, and a missing or malformed JSON body is
4
+ * `400 Invalid JSON`.
5
+ */
6
+ import { fail } from "../../tenant/http.js";
7
+ const MAX_BODY_BYTES = 1024 * 1024;
8
+ /** The body as text. */
9
+ export async function readText(request) {
10
+ if (request.body === null)
11
+ return "";
12
+ const chunks = [];
13
+ let bytes = 0;
14
+ const reader = request.body.getReader();
15
+ for (;;) {
16
+ const { done, value } = await reader.read();
17
+ if (done)
18
+ break;
19
+ bytes += value.byteLength;
20
+ if (bytes > MAX_BODY_BYTES) {
21
+ await reader.cancel();
22
+ fail(413, "Request too large");
23
+ }
24
+ chunks.push(value);
25
+ }
26
+ return Buffer.concat(chunks).toString("utf8");
27
+ }
28
+ /** The body as JSON, before any schema. */
29
+ export async function readJson(request) {
30
+ const text = await readText(request);
31
+ try {
32
+ return JSON.parse(text);
33
+ }
34
+ catch {
35
+ return fail(400, "Invalid JSON");
36
+ }
37
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * How a Tenant API route is declared: once, with who may call it, for serving and for the
3
+ * OpenAPI document.
4
+ *
5
+ * `RouteAccess` says which credentials a route takes, which subject scopes reach it and
6
+ * whether browsers may call it: the one statement of who may call a route. The document shows
7
+ * it as the operation's `security`, its `Nylorun-*` headers and `x-nylorun-*` fields; the Host
8
+ * answers browser preflights from it (`findTenantRoute`). Serving runs the Tenant's checks in
9
+ * order: the browser client, the bearer, the subject's scopes, then the handler, which parses
10
+ * its body.
11
+ */
12
+ import type { IncomingMessage } from "node:http";
13
+ import type { OpenAPIHono, RouteConfig } from "@hono/zod-openapi";
14
+ import type { Context, Handler } from "hono";
15
+ import type { SubjectScope } from "@nylorun/core/contracts";
16
+ import type { AuthScope } from "../../tenant/context.js";
17
+ import type { TenantEnv } from "./app.js";
18
+ export type Credential = "application" | "subject" | "token" | "publishable" | "delivery";
19
+ export interface RouteAccess {
20
+ readonly credentials: readonly Credential[];
21
+ /** The subject scopes that reach the route: any one of them, none (`never`), or all (`any`). */
22
+ readonly scopes: readonly SubjectScope[] | "never" | "any";
23
+ /** A browser page may call it: its preflight is allowed. */
24
+ readonly browser?: boolean;
25
+ /**
26
+ * Public data: a request with no credential at all (no `Authorization`, no `Nylorun-Key`) is
27
+ * served too. A credential that is sent is still checked, so a wrong one stays the opaque 404.
28
+ */
29
+ readonly anonymous?: boolean;
30
+ }
31
+ /** The route's path segments, decoded, as the Tenant's checks read them. */
32
+ export declare function pathSegments(incoming: IncomingMessage): string[];
33
+ /** Who is calling: the browser client and the bearer, as every Tenant request checks them. */
34
+ export declare function authenticateCaller(c: Context<TenantEnv>,
35
+ /** The route serves public data (`RouteAccess.anonymous`): no credential is needed. */
36
+ anonymous?: boolean): Promise<AuthScope>;
37
+ /** The declared route `method path` is, if any. `{param}` segments match any one segment. */
38
+ export declare function declaredRoute(method: string, segments: readonly string[]): RouteAccess | undefined;
39
+ export declare function tenantRoute(api: OpenAPIHono<TenantEnv>, access: RouteAccess, route: RouteConfig, handler: Handler<TenantEnv>): void;