@nylorun/runtime 0.13.0-beta → 0.14.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 (223) hide show
  1. package/CHANGELOG.md +330 -0
  2. package/README.md +69 -15
  3. package/dist/adapters/execution/restate.d.ts +7 -2
  4. package/dist/adapters/execution/restate.js +38 -8
  5. package/dist/adapters/replication/pgoutput.d.ts +16 -0
  6. package/dist/adapters/replication/pgoutput.js +169 -0
  7. package/dist/adapters/streams/s2.js +37 -20
  8. package/dist/admin-openapi.json +1071 -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 +7825 -0
  32. package/dist/api/components.js +83 -0
  33. package/dist/api/http/app.d.ts +18 -0
  34. package/dist/api/http/app.js +58 -0
  35. package/dist/api/http/body.d.ts +4 -0
  36. package/dist/api/http/body.js +37 -0
  37. package/dist/api/http/define.d.ts +39 -0
  38. package/dist/api/http/define.js +130 -0
  39. package/dist/api/http/respond.d.ts +9 -0
  40. package/dist/api/http/respond.js +44 -0
  41. package/dist/api/http/routes/access.d.ts +24 -0
  42. package/dist/api/http/routes/access.js +259 -0
  43. package/dist/api/http/routes/actions.d.ts +8 -0
  44. package/dist/api/http/routes/actions.js +76 -0
  45. package/dist/api/http/routes/endpoints.d.ts +7 -0
  46. package/dist/api/http/routes/endpoints.js +100 -0
  47. package/dist/api/http/routes/sessions.d.ts +3 -0
  48. package/dist/api/http/routes/sessions.js +205 -0
  49. package/dist/api/http/routes/tenant.d.ts +10 -0
  50. package/dist/api/http/routes/tenant.js +172 -0
  51. package/dist/api/http/routes/vaults.d.ts +8 -0
  52. package/dist/api/http/routes/vaults.js +167 -0
  53. package/dist/api/openapi.d.ts +19 -0
  54. package/dist/api/openapi.js +138 -0
  55. package/dist/api/route.d.ts +12 -0
  56. package/dist/api/route.js +4 -0
  57. package/dist/core/bearer.d.ts +8 -0
  58. package/dist/core/bearer.js +11 -0
  59. package/dist/core/flow-host.d.ts +7 -15
  60. package/dist/core/flow-host.js +16 -41
  61. package/dist/core/sandbox-routes.d.ts +12 -7
  62. package/dist/core/sandbox-routes.js +24 -25
  63. package/dist/execution/memory.d.ts +8 -5
  64. package/dist/execution/memory.js +33 -13
  65. package/dist/execution/types.d.ts +38 -6
  66. package/dist/execution/types.js +12 -3
  67. package/dist/host/admin-api.d.ts +22 -0
  68. package/dist/host/admin-api.js +178 -0
  69. package/dist/host/app.d.ts +34 -0
  70. package/dist/host/app.js +185 -0
  71. package/dist/host/config-for.d.ts +2 -0
  72. package/dist/host/config-for.js +1 -0
  73. package/dist/host/config.d.ts +11 -0
  74. package/dist/host/cors.d.ts +27 -0
  75. package/dist/host/cors.js +64 -0
  76. package/dist/host/create-host.d.ts +31 -3
  77. package/dist/host/create-host.js +168 -327
  78. package/dist/host/http.d.ts +14 -3
  79. package/dist/host/http.js +64 -23
  80. package/dist/host/main.js +55 -4
  81. package/dist/host/stack-config.d.ts +20 -0
  82. package/dist/host/stack-config.js +55 -0
  83. package/dist/mcp/pool.d.ts +19 -1
  84. package/dist/mcp/pool.js +60 -10
  85. package/dist/model/catalog.d.ts +2 -10
  86. package/dist/model/classify.d.ts +13 -0
  87. package/dist/model/classify.js +61 -0
  88. package/dist/model/models.d.ts +10 -1
  89. package/dist/model/models.js +14 -6
  90. package/dist/model/pi-model.d.ts +17 -2
  91. package/dist/model/pi-model.js +366 -222
  92. package/dist/openapi.json +25696 -0
  93. package/dist/sandbox/manager.d.ts +13 -1
  94. package/dist/sandbox/manager.js +8 -11
  95. package/dist/sandbox/resolve.d.ts +33 -0
  96. package/dist/sandbox/resolve.js +81 -0
  97. package/dist/sandbox/session-sandbox.d.ts +11 -0
  98. package/dist/sandbox/session-sandbox.js +51 -0
  99. package/dist/sandbox/share.d.ts +14 -2
  100. package/dist/sandbox/share.js +33 -3
  101. package/dist/sandbox/tenant-config.d.ts +37 -0
  102. package/dist/sandbox/tenant-config.js +51 -0
  103. package/dist/sandbox/tools.d.ts +7 -9
  104. package/dist/sandbox/tools.js +11 -3
  105. package/dist/sandbox/types.d.ts +8 -2
  106. package/dist/store/event.d.ts +19 -0
  107. package/dist/store/event.js +49 -0
  108. package/dist/store/memory.d.ts +20 -8
  109. package/dist/store/memory.js +265 -100
  110. package/dist/store/postgres/connect.d.ts +13 -0
  111. package/dist/store/postgres/connect.js +5 -0
  112. package/dist/store/postgres/migrations/003_subject_tokens.d.ts +8 -0
  113. package/dist/store/postgres/migrations/003_subject_tokens.js +42 -0
  114. package/dist/store/postgres/migrations/004_publishable_keys.d.ts +6 -0
  115. package/dist/store/postgres/migrations/004_publishable_keys.js +18 -0
  116. package/dist/store/postgres/migrations/005_action_endpoints.d.ts +6 -0
  117. package/dist/store/postgres/migrations/005_action_endpoints.js +32 -0
  118. package/dist/store/postgres/migrations/006_drop_executors.d.ts +11 -0
  119. package/dist/store/postgres/migrations/006_drop_executors.js +32 -0
  120. package/dist/store/postgres/migrations/007_event_time.d.ts +7 -0
  121. package/dist/store/postgres/migrations/007_event_time.js +14 -0
  122. package/dist/store/postgres/migrations/008_durable_streams.d.ts +13 -0
  123. package/dist/store/postgres/migrations/008_durable_streams.js +35 -0
  124. package/dist/store/postgres/migrations/index.d.ts +5 -1
  125. package/dist/store/postgres/migrations/index.js +22 -2
  126. package/dist/store/postgres/migrations/shared/index.d.ts +31 -0
  127. package/dist/store/postgres/migrations/shared/index.js +92 -0
  128. package/dist/store/postgres/record.d.ts +11 -0
  129. package/dist/store/postgres/record.js +64 -0
  130. package/dist/store/postgres/store.js +337 -95
  131. package/dist/store/postgres/tenants.js +14 -0
  132. package/dist/store/types.d.ts +176 -81
  133. package/dist/streams/basin.d.ts +18 -1
  134. package/dist/streams/basin.js +34 -2
  135. package/dist/streams/control.d.ts +18 -0
  136. package/dist/streams/control.js +29 -0
  137. package/dist/streams/memory.d.ts +3 -1
  138. package/dist/streams/memory.js +14 -8
  139. package/dist/streams/relay/core.d.ts +35 -0
  140. package/dist/streams/relay/core.js +366 -0
  141. package/dist/streams/relay/memory.d.ts +69 -0
  142. package/dist/streams/relay/memory.js +176 -0
  143. package/dist/streams/relay/types.d.ts +77 -0
  144. package/dist/streams/relay/types.js +7 -0
  145. package/dist/streams/types.d.ts +66 -36
  146. package/dist/streams/types.js +18 -53
  147. package/dist/tenant/access-policy.d.ts +30 -0
  148. package/dist/tenant/access-policy.js +52 -0
  149. package/dist/tenant/actions.d.ts +10 -149
  150. package/dist/tenant/actions.js +5 -167
  151. package/dist/tenant/advance.js +32 -0
  152. package/dist/tenant/auth.d.ts +19 -17
  153. package/dist/tenant/auth.js +90 -93
  154. package/dist/tenant/browser.d.ts +15 -0
  155. package/dist/tenant/browser.js +39 -0
  156. package/dist/tenant/commands.d.ts +18 -2
  157. package/dist/tenant/commands.js +107 -113
  158. package/dist/tenant/context.d.ts +75 -18
  159. package/dist/tenant/context.js +14 -10
  160. package/dist/tenant/delivery-token.d.ts +41 -0
  161. package/dist/tenant/delivery-token.js +105 -0
  162. package/dist/tenant/delivery.d.ts +62 -0
  163. package/dist/tenant/delivery.js +476 -0
  164. package/dist/tenant/effects.d.ts +5 -0
  165. package/dist/tenant/effects.js +78 -37
  166. package/dist/tenant/endpoints.d.ts +67 -0
  167. package/dist/tenant/endpoints.js +90 -0
  168. package/dist/tenant/ephemeral.d.ts +6 -0
  169. package/dist/tenant/ephemeral.js +60 -36
  170. package/dist/tenant/http.d.ts +8 -9
  171. package/dist/tenant/http.js +13 -27
  172. package/dist/tenant/jwt.d.ts +16 -0
  173. package/dist/tenant/jwt.js +50 -0
  174. package/dist/tenant/module.d.ts +3 -0
  175. package/dist/tenant/module.js +6 -12
  176. package/dist/tenant/outbound.d.ts +44 -0
  177. package/dist/tenant/outbound.js +127 -0
  178. package/dist/tenant/pool.d.ts +0 -2
  179. package/dist/tenant/pool.js +0 -18
  180. package/dist/tenant/reset.d.ts +0 -4
  181. package/dist/tenant/reset.js +0 -5
  182. package/dist/tenant/runtime.d.ts +10 -20
  183. package/dist/tenant/runtime.js +59 -42
  184. package/dist/tenant/scheduler.d.ts +7 -2
  185. package/dist/tenant/scheduler.js +7 -3
  186. package/dist/tenant/session-streams.d.ts +125 -0
  187. package/dist/tenant/session-streams.js +399 -0
  188. package/dist/tenant/sessions.d.ts +28 -4
  189. package/dist/tenant/sessions.js +118 -24
  190. package/dist/tenant/signing-keys.d.ts +55 -0
  191. package/dist/tenant/signing-keys.js +172 -0
  192. package/dist/tenant/slim.d.ts +8 -0
  193. package/dist/tenant/slim.js +21 -0
  194. package/dist/tenant/status.d.ts +0 -3
  195. package/dist/tenant/status.js +19 -12
  196. package/dist/tenant/streams.d.ts +60 -67
  197. package/dist/tenant/streams.js +140 -208
  198. package/dist/tenant/subject-limits.d.ts +16 -0
  199. package/dist/tenant/subject-limits.js +45 -0
  200. package/dist/tenant/sweep.d.ts +1 -10
  201. package/dist/tenant/sweep.js +29 -69
  202. package/dist/tenant/tokens.d.ts +14 -0
  203. package/dist/tenant/tokens.js +178 -0
  204. package/dist/tenant/transcript.d.ts +48 -5
  205. package/dist/tenant/transcript.js +58 -1
  206. package/dist/tenant/types.d.ts +29 -7
  207. package/dist/tenant/worker.d.ts +3 -1
  208. package/dist/tenant/worker.js +9 -3
  209. package/dist/vault/service.d.ts +18 -2
  210. package/dist/vault/service.js +57 -13
  211. package/dist/version.d.ts +1 -1
  212. package/dist/version.js +1 -1
  213. package/package.json +20 -8
  214. package/dist/core/executors.d.ts +0 -44
  215. package/dist/core/executors.js +0 -95
  216. package/dist/streams/relay.d.ts +0 -37
  217. package/dist/streams/relay.js +0 -254
  218. package/dist/tenant/live.d.ts +0 -92
  219. package/dist/tenant/live.js +0 -290
  220. package/dist/tenant/routes-tenant.d.ts +0 -12
  221. package/dist/tenant/routes-tenant.js +0 -137
  222. package/dist/tenant/routes.d.ts +0 -9
  223. package/dist/tenant/routes.js +0 -151
@@ -0,0 +1,83 @@
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, 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, AdminTenantListSchema, AdminTenantStatusSchema, CreateTenantRequestSchema, HostShutdownResponseSchema, ProtocolRejectedResponseSchema, RejectedResponseSchema, TenantEnvelopeSchema, 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 TenantEnvelope = named("TenantEnvelope", TenantEnvelopeSchema);
15
+ export const CreateTenantRequest = named("CreateTenantRequest", CreateTenantRequestSchema);
16
+ export const AdminTenantList = named("AdminTenantList", AdminTenantListSchema);
17
+ export const AdminTenantStatus = named("AdminTenantStatus", AdminTenantStatusSchema);
18
+ export const AdminStatus = named("AdminStatus", AdminStatusSchema);
19
+ export const HostShutdownResponse = named("HostShutdownResponse", HostShutdownResponseSchema);
20
+ export const SandboxToolOutcome = named("SandboxToolOutcome", SandboxToolOutcomeSchema);
21
+ export const PutEndpointsRequest = named("PutEndpointsRequest", PutEndpointsRequestSchema);
22
+ export const ListEndpointsResponse = named("ListEndpointsResponse", ListEndpointsResponseSchema);
23
+ export const DeleteEndpointResponse = named("DeleteEndpointResponse", DeleteEndpointResponseSchema);
24
+ export const EndpointPingResponse = named("EndpointPingResponse", EndpointPingResponseSchema);
25
+ export const DeliveryHeartbeatResponse = named("DeliveryHeartbeatResponse", DeliveryHeartbeatResponseSchema);
26
+ export const ActionOutcome = named("ActionOutcome", ActionOutcomeSchema);
27
+ export const SessionCommand = named("SessionCommand", SessionCommandSchema);
28
+ export const AcceptedResponse = named("AcceptedResponse", AcceptedResponseSchema);
29
+ export const ActionResultReceipt = named("ActionResultReceipt", ActionResultReceiptSchema);
30
+ export const ListAgentsResponse = named("ListAgentsResponse", ListAgentsResponseSchema);
31
+ export const ListPublicAgentsResponse = named("ListPublicAgentsResponse", ListPublicAgentsResponseSchema);
32
+ export const PutAgentRequest = named("PutAgentRequest", PutAgentRequestSchema);
33
+ export const PutAgentResponse = named("PutAgentResponse", PutAgentResponseSchema);
34
+ export const ListSessionsResponse = named("ListSessionsResponse", ListSessionsResponseSchema);
35
+ export const PutSessionRequest = named("PutSessionRequest", PutSessionRequestSchema);
36
+ export const SessionView = named("SessionView", SessionViewSchema);
37
+ export const LiveEvent = named("LiveEvent", LiveEventSchema);
38
+ /** `action.delivery_failed` → `ActionDeliveryFailedEvent`. */
39
+ export function eventComponentName(type) {
40
+ return `${type
41
+ .split(/[._]/)
42
+ .map((part) => part[0].toUpperCase() + part.slice(1))
43
+ .join("")}Event`;
44
+ }
45
+ /** The event catalog as components: one per event type, and `SessionEvent`, their union. */
46
+ export const SessionEvent = named("SessionEvent", z.discriminatedUnion("type", EVENT_TYPES.map((type) => named(eventComponentName(type), EVENT_SCHEMAS[type]))));
47
+ export const SessionItemsResponse = named("SessionItemsResponse", SessionItemsResponseSchema.extend({ items: z.array(SessionEvent) }));
48
+ export const StreamClosedFrame = named("StreamClosedFrame", StreamClosedFrameSchema);
49
+ export const TenantStatus = named("TenantStatus", TenantStatusSchema);
50
+ export const ResetTenantRequest = named("ResetTenantRequest", ResetTenantRequestSchema);
51
+ export const ResetTenantResponse = named("ResetTenantResponse", ResetTenantResponseSchema);
52
+ export const SeedTenantConfigRequest = named("SeedTenantConfigRequest", SeedTenantConfigRequestSchema);
53
+ export const SeedTenantConfigResponse = named("SeedTenantConfigResponse", SeedTenantConfigResponseSchema);
54
+ export const HostModelCatalog = named("HostModelCatalog", HostModelCatalogSchema);
55
+ export const TenantSandboxView = named("TenantSandboxView", TenantSandboxViewSchema);
56
+ export const PutTenantSandboxRequest = named("PutTenantSandboxRequest", PutTenantSandboxRequestSchema);
57
+ export const ListProvidersResponse = named("ListProvidersResponse", ListProvidersResponseSchema);
58
+ export const HostModelView = named("HostModelView", HostModelViewSchema);
59
+ export const PutHostModelRequest = named("PutHostModelRequest", PutHostModelRequestSchema);
60
+ export const SelectHostModelRequest = named("SelectHostModelRequest", SelectHostModelRequestSchema);
61
+ export const CreateVaultRequest = named("CreateVaultRequest", CreateVaultRequestSchema);
62
+ export const VaultInfo = named("VaultInfo", VaultInfoSchema);
63
+ export const ListVaultsResponse = named("ListVaultsResponse", ListVaultsResponseSchema);
64
+ export const CreateCredentialRequest = named("CreateCredentialRequest", CreateCredentialRequestSchema);
65
+ export const CredentialInfo = named("CredentialInfo", CredentialInfoSchema);
66
+ export const ListCredentialsResponse = named("ListCredentialsResponse", ListCredentialsResponseSchema);
67
+ export const RotateCredentialRequest = named("RotateCredentialRequest", RotateCredentialRequestSchema);
68
+ export const DeletedResponse = named("DeletedResponse", DeletedResponseSchema);
69
+ export const Jwks = named("Jwks", JwksSchema);
70
+ export const CreateTokenRequest = named("CreateTokenRequest", CreateTokenRequestSchema);
71
+ export const CreateTokenResponse = named("CreateTokenResponse", CreateTokenResponseSchema);
72
+ export const AccessPolicyResponse = named("AccessPolicyResponse", AccessPolicyResponseSchema);
73
+ export const PutAccessPolicyRequest = named("PutAccessPolicyRequest", PutAccessPolicyRequestSchema);
74
+ export const SigningKeyList = named("SigningKeyList", SigningKeyListSchema);
75
+ export const SigningKeyView = named("SigningKeyView", SigningKeyViewSchema);
76
+ export const RotateSigningKeysRequest = named("RotateSigningKeysRequest", RotateSigningKeysRequestSchema);
77
+ export const RevokeSigningKeyRequest = named("RevokeSigningKeyRequest", RevokeSigningKeyRequestSchema);
78
+ export const ListPublishableKeysResponse = named("ListPublishableKeysResponse", ListPublishableKeysResponseSchema);
79
+ export const PublishableKey = named("PublishableKey", PublishableKeySchema);
80
+ export const CreatePublishableKeyRequest = named("CreatePublishableKeyRequest", CreatePublishableKeyRequestSchema);
81
+ export const UpdatePublishableKeyRequest = named("UpdatePublishableKeyRequest", UpdatePublishableKeyRequestSchema);
82
+ export const RevokeSubjectRequest = named("RevokeSubjectRequest", RevokeSubjectRequestSchema);
83
+ export const RevokeSubjectResponse = named("RevokeSubjectResponse", RevokeSubjectResponseSchema);
@@ -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;
@@ -0,0 +1,130 @@
1
+ import { z } from "zod";
2
+ import { PROTOCOL_VERSION } from "@nylorun/core/compatibility";
3
+ import { authenticate, requireScopes } from "../../tenant/auth.js";
4
+ import { identifyClient } from "../../tenant/browser.js";
5
+ import { fail } from "../../tenant/http.js";
6
+ import { ProtocolRejected, Rejected } from "../components.js";
7
+ const SCHEMES = {
8
+ application: "applicationKey",
9
+ subject: "applicationKey",
10
+ token: "subjectToken",
11
+ publishable: "publishableKey",
12
+ delivery: "deliveryToken",
13
+ };
14
+ const rejected = (description) => ({
15
+ description,
16
+ content: { "application/json": { schema: Rejected } },
17
+ });
18
+ /** The route's path segments, decoded, as the Tenant's checks read them. */
19
+ export function pathSegments(incoming) {
20
+ return new URL(incoming.url ?? "/", "http://runtime").pathname
21
+ .split("/")
22
+ .filter(Boolean)
23
+ .map((segment) => {
24
+ try {
25
+ return decodeURIComponent(segment);
26
+ }
27
+ catch {
28
+ return fail(400, "Malformed path");
29
+ }
30
+ });
31
+ }
32
+ /** Who is calling: the browser client and the bearer, as every Tenant request checks them. */
33
+ export async function authenticateCaller(c,
34
+ /** The route serves public data (`RouteAccess.anonymous`): no credential is needed. */
35
+ anonymous = false) {
36
+ const { tenant, incoming, outgoing } = c.env;
37
+ // The client app first: a browser's origin is checked, and CORS headers set, before the
38
+ // bearer is looked at, so every answer from here on is readable by an allowed page.
39
+ const client = await identifyClient(tenant, incoming, outgoing);
40
+ if (anonymous && !client && incoming.headers.authorization === undefined)
41
+ return { kind: "anonymous" };
42
+ return await authenticate(tenant, incoming, client);
43
+ }
44
+ const declared = [];
45
+ /** The declared route `method path` is, if any. `{param}` segments match any one segment. */
46
+ export function declaredRoute(method, segments) {
47
+ return declared.find((route) => route.method === method.toUpperCase() &&
48
+ route.segments.length === segments.length &&
49
+ route.segments.every((segment, index) => segment === segments[index] ||
50
+ (segment.startsWith("{") && segments[index] !== "")))?.access;
51
+ }
52
+ function authenticated(access) {
53
+ return async (c, next) => {
54
+ const scope = await authenticateCaller(c, access.anonymous === true);
55
+ requireScopes(scope, access.scopes);
56
+ if (scope.kind === "publishable" && !access.credentials.includes("publishable"))
57
+ fail(403, "A publishable key alone reaches only the agent list", {
58
+ code: "scope_required",
59
+ });
60
+ // Handlers tell callers apart by kind, and a delivery token is none of theirs: only the
61
+ // routes that list it may see one.
62
+ if (scope.kind === "delivery" && !access.credentials.includes("delivery"))
63
+ fail(403, "A delivery token reaches only its Action's callbacks");
64
+ c.set("scope", scope);
65
+ await next();
66
+ };
67
+ }
68
+ export function tenantRoute(api, access, route, handler) {
69
+ const takes = (credential) => access.credentials.includes(credential);
70
+ const schemes = [...new Set(access.credentials.map((credential) => SCHEMES[credential]))];
71
+ const headers = z.object({
72
+ "Nylorun-Protocol": z.string().meta({ description: `The protocol version, \`${PROTOCOL_VERSION}\`` }),
73
+ ...(access.browser || takes("publishable")
74
+ ? {
75
+ "Nylorun-Tenant": z
76
+ .string()
77
+ .optional()
78
+ .meta({ description: "The Tenant; optional with a publishable key, which names it" }),
79
+ }
80
+ : { "Nylorun-Tenant": z.string().meta({ description: "The Tenant" }) }),
81
+ ...(takes("subject")
82
+ ? {
83
+ "Nylorun-Subject": z
84
+ .string()
85
+ .optional()
86
+ .meta({ description: "The person an application key acts for" }),
87
+ "Nylorun-Scopes": z
88
+ .string()
89
+ .optional()
90
+ .meta({ description: "The subject's space-separated scopes; required with a subject" }),
91
+ }
92
+ : {}),
93
+ ...(takes("publishable")
94
+ ? {
95
+ "Nylorun-Key": z
96
+ .string()
97
+ .optional()
98
+ .meta({ description: "A publishable key, from a browser page on an allowed origin" }),
99
+ }
100
+ : {}),
101
+ });
102
+ api.openAPIRegistry.registerPath({
103
+ ...route,
104
+ // `{}`: no credential needed (OpenAPI's optional security).
105
+ security: [
106
+ ...schemes.map((scheme) => ({ [scheme]: [] })),
107
+ ...(access.anonymous ? [{}] : []),
108
+ ],
109
+ request: { ...route.request, headers },
110
+ responses: {
111
+ 400: rejected("Invalid headers, path, body or cursor"),
112
+ ...(takes("token") ? { 401: rejected("The subject token expired or was revoked (`token_expired`)") } : {}),
113
+ 403: rejected("Not allowed for this credential, subject scope or origin"),
114
+ 404: rejected("Not found, or a credential the Tenant does not know (`not_found`)"),
115
+ 426: { description: "`Nylorun-Protocol` missing or unsupported", content: { "application/json": { schema: ProtocolRejected } } },
116
+ ...(takes("token") ? { 429: rejected("The subject's turn limits are reached (`limit_exceeded`)") } : {}),
117
+ 503: rejected("The Tenant's storage or streams are unavailable"),
118
+ ...route.responses,
119
+ },
120
+ "x-nylorun-credentials": access.credentials,
121
+ "x-nylorun-scopes": access.scopes,
122
+ "x-nylorun-browser": access.browser === true,
123
+ });
124
+ declared.push({
125
+ method: route.method.toUpperCase(),
126
+ segments: route.path.split("/").filter(Boolean),
127
+ access,
128
+ });
129
+ api.on(route.method.toUpperCase(), route.path.replaceAll(/\/{(.+?)}/g, "/:$1"), authenticated(access), handler);
130
+ }
@@ -0,0 +1,9 @@
1
+ /** A JSON answer. CORS headers a browser needs are already on the Node response. */
2
+ export declare function jsonResponse(status: number, body: unknown, headers?: Readonly<Record<string, string>>): Response;
3
+ export interface Rejection {
4
+ readonly status: number;
5
+ readonly body: unknown;
6
+ readonly headers: Readonly<Record<string, string>>;
7
+ }
8
+ /** What a Tenant route that threw `error` answers. */
9
+ export declare function rejectionOf(error: unknown): Rejection;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * How the Tenant API answers: JSON with an explicit length, and the one mapping from what a
3
+ * route throws to the rejection a client sees. The Hono routes and the router they replace
4
+ * (`routes.ts`) both answer through here, so a route answers the same wherever it runs.
5
+ */
6
+ import { SandboxRouteError } from "../../core/sandbox-routes.js";
7
+ import { HttpError, OpaqueAuthError } from "../../tenant/http.js";
8
+ import { VaultError } from "../../vault/error.js";
9
+ /** A JSON answer. CORS headers a browser needs are already on the Node response. */
10
+ export function jsonResponse(status, body, headers = {}) {
11
+ const payload = JSON.stringify(body);
12
+ return new Response(payload, {
13
+ status,
14
+ headers: {
15
+ ...headers,
16
+ "content-type": "application/json",
17
+ "content-length": String(Buffer.byteLength(payload)),
18
+ },
19
+ });
20
+ }
21
+ /** What a Tenant route that threw `error` answers. */
22
+ export function rejectionOf(error) {
23
+ if (error instanceof OpaqueAuthError)
24
+ return { status: error.status, body: error.body, headers: {} };
25
+ const status = error instanceof HttpError ||
26
+ error instanceof VaultError ||
27
+ error instanceof SandboxRouteError
28
+ ? error.status
29
+ : error?.name === "ZodError" ||
30
+ error?.message === "Invalid cursor"
31
+ ? 400
32
+ : 500;
33
+ const rejection = error instanceof HttpError ? error.rejection : {};
34
+ return {
35
+ status,
36
+ body: {
37
+ status: "rejected",
38
+ code: status === 500 ? "internal_error" : (rejection.code ?? "request_rejected"),
39
+ message: status === 500 ? "Runtime request failed" : error.message,
40
+ ...(rejection.details === undefined ? {} : { details: rejection.details }),
41
+ },
42
+ headers: error instanceof HttpError ? error.headers : {},
43
+ };
44
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Access management (Host feature `subject-tokens`), for the application key only: subject
3
+ * tokens, the access policy, signing keys, publishable keys and subject revocation; and the
4
+ * public keys, for any caller that reached the Tenant.
5
+ *
6
+ * Subjects travel in bodies, not paths, because they may be email addresses and request paths
7
+ * are logged.
8
+ */
9
+ import type { OpenAPIHono } from "@hono/zod-openapi";
10
+ import type { PublishableKey as PublishableKeyBody } from "@nylorun/core/contracts";
11
+ import type { PublishableKeyRow } from "../../../store/types.js";
12
+ import type { TenantContext } from "../../../tenant/context.js";
13
+ import type { TenantEnv } from "../app.js";
14
+ export declare function accessRoutes(api: OpenAPIHono<TenantEnv>): void;
15
+ /** A publishable key as the API shows it. */
16
+ export declare function publishableKeyView(row: PublishableKeyRow): PublishableKeyBody;
17
+ /**
18
+ * Ends every token of `subject` minted so far: bumps its epoch, then ends its open streams
19
+ * here and, through `tenant/control`, on every other process. Running turns continue.
20
+ */
21
+ export declare function revokeSubject(ctx: TenantContext, subject: string): Promise<{
22
+ subject: string;
23
+ epoch: number;
24
+ }>;