@nylorun/runtime 0.15.2-beta → 0.17.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 (291) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +68 -29
  3. package/dist/adapters/execution/restate.d.ts +9 -1
  4. package/dist/adapters/execution/restate.js +64 -5
  5. package/dist/adapters/sandbox/local.d.ts +10 -0
  6. package/dist/adapters/sandbox/local.js +195 -0
  7. package/dist/adapters/sandbox/virtual.js +36 -1
  8. package/dist/admin-openapi.json +341 -7
  9. package/dist/api/a2a/tasks.js +6 -1
  10. package/dist/api/ag-ui/endpoint.js +1 -2
  11. package/dist/api/ag-ui/history.js +6 -1
  12. package/dist/api/ag-ui/routes.d.ts +1 -1
  13. package/dist/api/ag-ui/routes.js +15 -13
  14. package/dist/api/components.d.ts +2667 -711
  15. package/dist/api/components.js +24 -11
  16. package/dist/api/gate/keys.d.ts +4 -3
  17. package/dist/api/gate/routes.d.ts +19 -3
  18. package/dist/api/gate/routes.js +162 -53
  19. package/dist/api/http/app.js +6 -0
  20. package/dist/api/http/define.d.ts +19 -12
  21. package/dist/api/http/define.js +13 -27
  22. package/dist/api/http/routes/access.d.ts +3 -19
  23. package/dist/api/http/routes/access.js +12 -172
  24. package/dist/api/http/routes/actions.js +0 -1
  25. package/dist/api/http/routes/artifacts.d.ts +11 -0
  26. package/dist/api/http/routes/artifacts.js +516 -0
  27. package/dist/api/http/routes/me.d.ts +13 -0
  28. package/dist/api/http/routes/me.js +45 -0
  29. package/dist/api/http/routes/sandboxes.d.ts +9 -0
  30. package/dist/api/http/routes/sandboxes.js +150 -0
  31. package/dist/api/http/routes/sessions.js +9 -13
  32. package/dist/api/http/routes/tenant.js +36 -2
  33. package/dist/api/http/routes/vaults.d.ts +12 -3
  34. package/dist/api/http/routes/vaults.js +122 -54
  35. package/dist/api/openapi.js +4 -10
  36. package/dist/artifacts/config.d.ts +23 -0
  37. package/dist/artifacts/config.js +27 -0
  38. package/dist/artifacts/export.d.ts +8 -0
  39. package/dist/artifacts/export.js +205 -0
  40. package/dist/artifacts/files.d.ts +36 -0
  41. package/dist/artifacts/files.js +45 -0
  42. package/dist/artifacts/folders.d.ts +60 -0
  43. package/dist/artifacts/folders.js +209 -0
  44. package/dist/artifacts/links.d.ts +28 -0
  45. package/dist/artifacts/links.js +92 -0
  46. package/dist/artifacts/media-types.d.ts +13 -0
  47. package/dist/artifacts/media-types.js +80 -0
  48. package/dist/artifacts/parts.d.ts +34 -0
  49. package/dist/artifacts/parts.js +38 -0
  50. package/dist/artifacts/service.d.ts +74 -0
  51. package/dist/artifacts/service.js +301 -0
  52. package/dist/artifacts/workspace.d.ts +60 -0
  53. package/dist/artifacts/workspace.js +57 -0
  54. package/dist/artifacts/zip.d.ts +10 -0
  55. package/dist/artifacts/zip.js +126 -0
  56. package/dist/blob/fs.d.ts +13 -0
  57. package/dist/blob/fs.js +194 -0
  58. package/dist/blob/index.d.ts +9 -0
  59. package/dist/blob/index.js +9 -0
  60. package/dist/blob/s3.d.ts +42 -0
  61. package/dist/blob/s3.js +366 -0
  62. package/dist/blob/types.d.ts +108 -0
  63. package/dist/blob/types.js +85 -0
  64. package/dist/core/sandbox-routes.d.ts +2 -2
  65. package/dist/core/sandbox-routes.js +4 -3
  66. package/dist/execution/memory.d.ts +11 -1
  67. package/dist/execution/memory.js +77 -3
  68. package/dist/execution/types.d.ts +54 -1
  69. package/dist/execution/types.js +31 -0
  70. package/dist/gates/contract.d.ts +14 -13
  71. package/dist/gates/contract.js +13 -12
  72. package/dist/gates/egress.d.ts +72 -0
  73. package/dist/gates/egress.js +319 -0
  74. package/dist/gates/handler.d.ts +3 -0
  75. package/dist/gates/handler.js +3 -2
  76. package/dist/gates/http-client.d.ts +3 -2
  77. package/dist/gates/http-client.js +17 -6
  78. package/dist/gates/in-process.d.ts +13 -1
  79. package/dist/gates/in-process.js +11 -0
  80. package/dist/gates/inflight.d.ts +23 -4
  81. package/dist/gates/inflight.js +18 -4
  82. package/dist/gates/mcp-handler.js +5 -1
  83. package/dist/gates/model-gate.d.ts +6 -2
  84. package/dist/gates/tenant-vaults.d.ts +18 -9
  85. package/dist/gates/tenant-vaults.js +17 -12
  86. package/dist/gates/tool-calls.d.ts +9 -5
  87. package/dist/gates/tool-calls.js +6 -6
  88. package/dist/gates/tool-client.d.ts +9 -2
  89. package/dist/gates/tool-client.js +56 -22
  90. package/dist/gates/tool-contract.d.ts +12 -7
  91. package/dist/gates/tool-contract.js +10 -4
  92. package/dist/gates/tool-gate.d.ts +1 -0
  93. package/dist/harness/calls.d.ts +52 -0
  94. package/dist/harness/calls.js +113 -0
  95. package/dist/harness/executors.d.ts +22 -0
  96. package/dist/harness/executors.js +96 -0
  97. package/dist/harness/main.d.ts +6 -0
  98. package/dist/harness/main.js +103 -0
  99. package/dist/harness/pod.d.ts +21 -0
  100. package/dist/harness/pod.js +119 -0
  101. package/dist/harness/run-tokens.d.ts +18 -0
  102. package/dist/harness/run-tokens.js +15 -0
  103. package/dist/harness/service.d.ts +46 -0
  104. package/dist/harness/service.js +179 -0
  105. package/dist/harness/ws-client.d.ts +43 -0
  106. package/dist/harness/ws-client.js +122 -0
  107. package/dist/harness/ws-port.d.ts +22 -0
  108. package/dist/harness/ws-port.js +78 -0
  109. package/dist/harness-api/in-process.d.ts +24 -0
  110. package/dist/harness-api/in-process.js +119 -0
  111. package/dist/harness-api/record.d.ts +44 -0
  112. package/dist/harness-api/record.js +250 -0
  113. package/dist/harness-api/renew.d.ts +37 -0
  114. package/dist/harness-api/renew.js +77 -0
  115. package/dist/harness-api/server.d.ts +104 -0
  116. package/dist/harness-api/server.js +408 -0
  117. package/dist/harness-api/start.d.ts +36 -0
  118. package/dist/harness-api/start.js +118 -0
  119. package/dist/harness-api/workspace.d.ts +53 -0
  120. package/dist/harness-api/workspace.js +201 -0
  121. package/dist/harness-api/ws-server.d.ts +34 -0
  122. package/dist/harness-api/ws-server.js +227 -0
  123. package/dist/host/admin-api.d.ts +12 -5
  124. package/dist/host/admin-api.js +72 -6
  125. package/dist/host/app.d.ts +0 -1
  126. package/dist/host/app.js +35 -24
  127. package/dist/host/config-for.d.ts +4 -0
  128. package/dist/host/config-for.js +2 -0
  129. package/dist/host/config.d.ts +0 -6
  130. package/dist/host/create-host.d.ts +3 -10
  131. package/dist/host/create-host.js +4 -1
  132. package/dist/host/gates.d.ts +27 -2
  133. package/dist/host/gates.js +52 -2
  134. package/dist/host/http.d.ts +4 -1
  135. package/dist/host/http.js +6 -1
  136. package/dist/host/main.js +167 -37
  137. package/dist/host/stack-config.d.ts +112 -9
  138. package/dist/host/stack-config.js +222 -20
  139. package/dist/index.d.ts +3 -0
  140. package/dist/index.js +2 -0
  141. package/dist/keys/client.js +9 -1
  142. package/dist/keys/keys.d.ts +12 -2
  143. package/dist/keys/keys.js +8 -0
  144. package/dist/mcp/connect.js +2 -1
  145. package/dist/mcp/pool.d.ts +1 -0
  146. package/dist/mcp/pool.js +1 -0
  147. package/dist/mcp/snapshot.d.ts +8 -1
  148. package/dist/mcp/snapshot.js +28 -0
  149. package/dist/media.d.ts +5 -24
  150. package/dist/media.js +5 -0
  151. package/dist/model/pi-model.d.ts +6 -2
  152. package/dist/model/pi-model.js +39 -22
  153. package/dist/node/index.d.ts +1 -1
  154. package/dist/node/index.js +1 -1
  155. package/dist/openapi.json +14084 -9426
  156. package/dist/record/index.d.ts +1 -0
  157. package/dist/record/index.js +1 -0
  158. package/dist/record/sandbox.d.ts +25 -0
  159. package/dist/record/sandbox.js +43 -0
  160. package/dist/sandbox/capability.d.ts +3 -0
  161. package/dist/sandbox/capability.js +10 -0
  162. package/dist/sandbox/egress-token.d.ts +26 -0
  163. package/dist/sandbox/egress-token.js +8 -0
  164. package/dist/sandbox/join.d.ts +37 -0
  165. package/dist/sandbox/join.js +165 -0
  166. package/dist/sandbox/manager.d.ts +99 -34
  167. package/dist/sandbox/manager.js +216 -84
  168. package/dist/sandbox/placement.d.ts +27 -0
  169. package/dist/sandbox/placement.js +44 -0
  170. package/dist/sandbox/pods/client.d.ts +90 -0
  171. package/dist/sandbox/pods/client.js +79 -0
  172. package/dist/sandbox/pods/lifecycle.d.ts +91 -0
  173. package/dist/sandbox/pods/lifecycle.js +178 -0
  174. package/dist/sandbox/pods/name.d.ts +1 -0
  175. package/dist/sandbox/pods/name.js +28 -0
  176. package/dist/sandbox/pods/network-gate.d.ts +25 -0
  177. package/dist/sandbox/pods/network-gate.js +71 -0
  178. package/dist/sandbox/pods/reconcile.d.ts +11 -0
  179. package/dist/sandbox/pods/reconcile.js +152 -0
  180. package/dist/sandbox/pods/spec.d.ts +45 -0
  181. package/dist/sandbox/pods/spec.js +62 -0
  182. package/dist/sandbox/records.d.ts +29 -0
  183. package/dist/sandbox/records.js +79 -0
  184. package/dist/sandbox/resolve.d.ts +5 -0
  185. package/dist/sandbox/resolve.js +3 -2
  186. package/dist/sandbox/session-sandbox.js +7 -5
  187. package/dist/sandbox/share.d.ts +11 -0
  188. package/dist/sandbox/share.js +10 -0
  189. package/dist/sandbox/tenant-config.d.ts +16 -1
  190. package/dist/sandbox/tenant-config.js +9 -0
  191. package/dist/sandbox/types.d.ts +29 -1
  192. package/dist/sandbox/types.js +13 -1
  193. package/dist/store/postgres/drizzle/0004_sandbox_resources.sql +20 -0
  194. package/dist/store/postgres/drizzle/0005_artifacts.sql +27 -0
  195. package/dist/store/postgres/drizzle/0006_folder_artifacts.sql +12 -0
  196. package/dist/store/postgres/drizzle/0007_sandbox_pods.sql +14 -0
  197. package/dist/store/postgres/drizzle/0008_installation_vaults.sql +2 -0
  198. package/dist/store/postgres/drizzle/0009_oauth_pending.sql +19 -0
  199. package/dist/store/postgres/drizzle/0010_oss_auth_removals.sql +3 -0
  200. package/dist/store/postgres/drizzle/meta/_journal.json +49 -0
  201. package/dist/store/postgres/record-writer.d.ts +6 -1
  202. package/dist/store/postgres/record-writer.js +20 -2
  203. package/dist/store/postgres/schema.d.ts +1168 -250
  204. package/dist/store/postgres/schema.js +174 -28
  205. package/dist/store/postgres/store.js +339 -103
  206. package/dist/store/postgres/tenant.d.ts +1 -1
  207. package/dist/store/postgres/tenant.js +2 -2
  208. package/dist/store/types.d.ts +163 -32
  209. package/dist/streams/control.d.ts +2 -5
  210. package/dist/streams/control.js +5 -8
  211. package/dist/streams/types.d.ts +8 -8
  212. package/dist/streams/types.js +1 -1
  213. package/dist/tenant/advance.js +218 -160
  214. package/dist/tenant/artifact-tool.d.ts +5 -0
  215. package/dist/tenant/artifact-tool.js +119 -0
  216. package/dist/tenant/auth.d.ts +13 -9
  217. package/dist/tenant/auth.js +25 -32
  218. package/dist/tenant/commands.js +31 -10
  219. package/dist/tenant/context.d.ts +83 -26
  220. package/dist/tenant/delivery-token.js +4 -4
  221. package/dist/tenant/effects.d.ts +24 -14
  222. package/dist/tenant/effects.js +10 -398
  223. package/dist/tenant/ephemeral.d.ts +14 -2
  224. package/dist/tenant/ephemeral.js +8 -1
  225. package/dist/tenant/history.d.ts +13 -23
  226. package/dist/tenant/history.js +14 -62
  227. package/dist/tenant/host-token.d.ts +92 -0
  228. package/dist/tenant/host-token.js +179 -0
  229. package/dist/tenant/identity-file.d.ts +75 -0
  230. package/dist/tenant/identity-file.js +202 -0
  231. package/dist/tenant/issuers.d.ts +48 -0
  232. package/dist/tenant/issuers.js +311 -0
  233. package/dist/tenant/jwt.js +3 -3
  234. package/dist/tenant/module.js +1 -0
  235. package/dist/tenant/operator-keys.d.ts +18 -0
  236. package/dist/tenant/operator-keys.js +55 -0
  237. package/dist/tenant/outbound.d.ts +30 -0
  238. package/dist/tenant/outbound.js +142 -10
  239. package/dist/tenant/paths.d.ts +2 -1
  240. package/dist/tenant/paths.js +3 -1
  241. package/dist/tenant/principals.d.ts +2 -11
  242. package/dist/tenant/principals.js +10 -30
  243. package/dist/tenant/reset.d.ts +5 -2
  244. package/dist/tenant/reset.js +22 -2
  245. package/dist/tenant/run-grants.d.ts +49 -0
  246. package/dist/tenant/run-grants.js +62 -0
  247. package/dist/tenant/run-token.d.ts +70 -0
  248. package/dist/tenant/run-token.js +138 -0
  249. package/dist/tenant/runtime.d.ts +42 -0
  250. package/dist/tenant/runtime.js +134 -33
  251. package/dist/tenant/sandboxes.d.ts +119 -0
  252. package/dist/tenant/sandboxes.js +551 -0
  253. package/dist/tenant/session-streams.d.ts +6 -10
  254. package/dist/tenant/session-streams.js +9 -27
  255. package/dist/tenant/session.d.ts +2 -13
  256. package/dist/tenant/session.js +4 -28
  257. package/dist/tenant/sessions.d.ts +6 -1
  258. package/dist/tenant/sessions.js +29 -2
  259. package/dist/tenant/signing-keys.d.ts +2 -1
  260. package/dist/tenant/signing-keys.js +2 -2
  261. package/dist/tenant/status.d.ts +8 -3
  262. package/dist/tenant/status.js +5 -0
  263. package/dist/tenant/streams.d.ts +8 -2
  264. package/dist/tenant/streams.js +25 -6
  265. package/dist/tenant/sweep.js +37 -4
  266. package/dist/tenant/types.d.ts +39 -1
  267. package/dist/tenant/worker.d.ts +11 -5
  268. package/dist/tenant/worker.js +12 -6
  269. package/dist/vault/crypto.d.ts +7 -0
  270. package/dist/vault/crypto.js +16 -0
  271. package/dist/vault/oauth.d.ts +55 -0
  272. package/dist/vault/oauth.js +186 -0
  273. package/dist/vault/service.d.ts +54 -7
  274. package/dist/vault/service.js +261 -17
  275. package/dist/vault/sources.d.ts +54 -0
  276. package/dist/vault/sources.js +185 -0
  277. package/dist/version.d.ts +1 -1
  278. package/dist/version.js +1 -1
  279. package/package.json +14 -10
  280. package/dist/adapters/media.d.ts +0 -24
  281. package/dist/adapters/media.js +0 -111
  282. package/dist/host/cors.d.ts +0 -27
  283. package/dist/host/cors.js +0 -64
  284. package/dist/tenant/access-policy.d.ts +0 -30
  285. package/dist/tenant/access-policy.js +0 -52
  286. package/dist/tenant/browser.d.ts +0 -15
  287. package/dist/tenant/browser.js +0 -39
  288. package/dist/tenant/subject-limits.d.ts +0 -16
  289. package/dist/tenant/subject-limits.js +0 -45
  290. package/dist/tenant/tokens.d.ts +0 -14
  291. package/dist/tenant/tokens.js +0 -180
@@ -5,9 +5,8 @@
5
5
  * "snake_case"`, here, in `db.ts` and in `drizzle.config.ts`).
6
6
  *
7
7
  * - `nylorun` holds the Tenant's state: the one `tenant` row, the document tables, Action
8
- * endpoints, principals, vaults and credentials, signing keys, publishable keys, subject
9
- * epochs and usage, settings, the model usage ledger, the model budgets and the Tool Gate's
10
- * crossings.
8
+ * endpoints, principals, vaults and credentials, signing keys, settings, the model usage
9
+ * ledger, the model budgets, the Tool Gate's crossings and file artifacts with their versions.
11
10
  * - `nylorun_streams` holds the record (Durable Streams §6): `session_events`,
12
11
  * `session_log_heads` and the relay's `relay_slots`. The relay's publication is custom SQL
13
12
  * (`drizzle/0002_stream_relay.sql`).
@@ -103,10 +102,13 @@ export const sessions = nylorun.table("sessions", {
103
102
  ownerExpiresAt: timestamp({ withTimezone: true, mode: "date" }),
104
103
  /** The session owner (`ownerUserId`), not the lease column `owner`. */
105
104
  ownerUserId: field("->>'ownerUserId'"),
105
+ /** The sandbox resource the session is attached to (`sandbox: { id }`). */
106
+ sandboxId: field("->>'sandboxId'"),
106
107
  }, (t) => [
107
108
  index("sessions_status").on(t.status, t.ownerExpiresAt),
108
109
  index("sessions_agent").on(t.agentId),
109
110
  index("sessions_owner_user").on(t.ownerUserId),
111
+ index("sessions_sandbox").on(t.sandboxId),
110
112
  ]);
111
113
  export const commands = documents("commands");
112
114
  export const effects = nylorun.table("effects", {
@@ -157,11 +159,15 @@ export const vaults = nylorun.table("vaults", {
157
159
  /** JSON text, or null. */
158
160
  metadataJson: text(),
159
161
  createdAt: textC().notNull(),
160
- scope: text({ enum: ["user", "host"] }).notNull().default("user"),
162
+ /**
163
+ * `user`: one person's (owner `ownerUserId`); `installation`: the installation's own,
164
+ * attachable to any session (owner `installation`); `host`: the model vault, never attached.
165
+ */
166
+ scope: text({ enum: ["user", "installation", "host"] }).notNull().default("user"),
161
167
  }, (t) => [
162
168
  index("vaults_owner").on(t.ownerUserId, t.createdAt, t.id),
163
169
  uniqueIndex("vaults_one_host").on(t.scope).where(sql `scope = 'host'`),
164
- check("vaults_scope_check", sql `scope IN ('user', 'host')`),
170
+ check("vaults_scope_check", sql `scope IN ('user', 'installation', 'host')`),
165
171
  ]);
166
172
  /** A credential of a vault: its binding in the clear, its secret sealed. */
167
173
  export const vaultCredentials = nylorun.table("vault_credentials", {
@@ -204,11 +210,48 @@ export const vaultIdempotency = nylorun.table("vault_idempotency", {
204
210
  /** JSON text of the original response. */
205
211
  response: text().notNull(),
206
212
  });
213
+ /**
214
+ * An MCP OAuth connect between its start and its callback (F9 C2): found by the SHA-256 of its
215
+ * `state`, used once, for ten minutes. The PKCE verifier and any client secret are sealed under
216
+ * the vault key (`sealBytes`), which only the keys module holds.
217
+ */
218
+ export const oauthPending = nylorun.table("oauth_pending", {
219
+ stateHash: text().primaryKey(),
220
+ vaultId: text().notNull(),
221
+ /** The MCP server's name in the agent, the credential's name. */
222
+ server: text().notNull(),
223
+ /** The MCP server's URL (normalized): the credential's binding. */
224
+ url: text().notNull(),
225
+ tokenEndpoint: text().notNull(),
226
+ clientId: text().notNull(),
227
+ /** How the client authenticates at the token endpoint: `none`, `client_secret_basic` or `client_secret_post`. */
228
+ tokenEndpointAuth: text({ enum: ["none", "client_secret_basic", "client_secret_post"] }).notNull(),
229
+ /** The RFC 8707 resource indicator sent with the authorization request, if any. */
230
+ resource: text(),
231
+ kekId: text().notNull(),
232
+ /** Sealed; null for a public client. */
233
+ clientSecret: bytes(),
234
+ /** Sealed. */
235
+ codeVerifier: bytes().notNull(),
236
+ redirectUri: text().notNull(),
237
+ expiresAt: textC().notNull(),
238
+ createdAt: textC().notNull(),
239
+ }, (t) => [
240
+ foreignKey({
241
+ name: "oauth_pending_vault_id_fkey",
242
+ columns: [t.vaultId],
243
+ foreignColumns: [vaults.id],
244
+ }).onDelete("cascade"),
245
+ index("oauth_pending_expires").on(t.expiresAt),
246
+ ]);
207
247
  export const tenantSettings = nylorun.table("tenant_settings", {
208
248
  key: text().primaryKey(),
209
249
  value: text().notNull(),
210
250
  });
211
- /** The Tenant's signing keys (subject tokens): the private half sealed, the public JWK not. */
251
+ /**
252
+ * The Tenant's signing keys (delivery tokens, capability links, run and host tokens): the
253
+ * private half sealed, the public JWK not.
254
+ */
212
255
  export const signingKeys = nylorun.table("signing_keys", {
213
256
  id: textC().primaryKey(),
214
257
  state: text({ enum: ["standby", "current", "previous", "revoked"] }).notNull(),
@@ -230,28 +273,6 @@ export const signingKeys = nylorun.table("signing_keys", {
230
273
  uniqueIndex("signing_keys_one_current").on(t.state).where(sql `state = 'current'`),
231
274
  uniqueIndex("signing_keys_one_previous").on(t.state).where(sql `state = 'previous'`),
232
275
  ]);
233
- /** Each subject's revocation epoch. */
234
- export const subjectEpochs = nylorun.table("subject_epochs", {
235
- subject: textC().primaryKey(),
236
- epoch: bigint({ mode: "number" }).notNull(),
237
- revokedAt: text().notNull(),
238
- });
239
- /** Each subject's turn bucket: tokens left and when they were last refilled. */
240
- export const subjectUsage = nylorun.table("subject_usage", {
241
- subject: textC().primaryKey(),
242
- turnTokens: doublePrecision().notNull(),
243
- refilledAt: text().notNull(),
244
- });
245
- /** Publishable keys (Host feature `browser-access`): public by design. */
246
- export const publishableKeys = nylorun.table("publishable_keys", {
247
- id: textC().primaryKey(),
248
- key: textC().notNull().unique("publishable_keys_key_key"),
249
- name: text().notNull().unique("publishable_keys_name_key"),
250
- /** JSON array of allowed origins. */
251
- originsJson: text().notNull(),
252
- createdAt: text().notNull(),
253
- revokedAt: text(),
254
- });
255
276
  /**
256
277
  * Action endpoints: where the Runtime delivers each agent's Actions over HTTP, and the health
257
278
  * recent deliveries and the last ping report.
@@ -335,8 +356,133 @@ export const toolCrossings = nylorun.table("tool_crossings", {
335
356
  /** The gate's answer (`McpAnswer`), once the call ended; null while it runs or once lost. */
336
357
  answer: jsonText(),
337
358
  }, (t) => [index("tool_crossings_settled").on(t.settledAt)]);
359
+ /**
360
+ * A sandbox resource (blueprint D39, F7.1): its id, kind, the spec resolved against the
361
+ * Tenant's limits when it was created, and the developer's labels. Sessions attach to it by id
362
+ * (the session body's `sandboxId`). Not the `sandboxes` document table, which holds the virtual
363
+ * backend's compute records, keyed by workspace key.
364
+ */
365
+ export const sandboxResources = nylorun.table("sandbox_resources", {
366
+ id: textC().primaryKey(),
367
+ kind: text({ enum: ["virtual", "pod"] }).notNull(),
368
+ /** The resolved `SandboxManifest`. */
369
+ spec: jsonText().notNull(),
370
+ /** `{ key: value }`, filtered through `nylorun.doc(labels)`. */
371
+ labels: jsonText().notNull(),
372
+ createdAt: textC().notNull(),
373
+ updatedAt: textC().notNull(),
374
+ // Kind `pod` (F7.2, D34): null for a virtual sandbox. `tenant/sandboxes.ts` and the
375
+ // `Sandbox` object's reconcile (`sandbox/pods/reconcile.ts`) are the only writers.
376
+ /** The agent-sandbox Sandbox's name, `sbx-<16 base32>-g<volume_gen>` (`podName`). */
377
+ k8sName: textC(),
378
+ /** Bumped by every reset: a new Sandbox on a new volume. */
379
+ volumeGen: integer().notNull().default(0),
380
+ /** `running`, `suspended` or `deleted`. */
381
+ desired: text({ enum: ["running", "suspended", "deleted"] }),
382
+ /** `creating`, `running`, `suspended`, `expired`, `lost`, `failed` or `deleting`. */
383
+ observed: text({
384
+ enum: ["creating", "running", "suspended", "expired", "lost", "failed", "deleting"],
385
+ }),
386
+ /** The UID of the pod that last joined. */
387
+ podUid: text(),
388
+ /**
389
+ * Bumped by every join (`host.join`), relaunch, loss and reset: host and egress tokens carry
390
+ * it (`epc`), and one of an older epoch is refused (egress-gate reads it too).
391
+ */
392
+ hostEpoch: integer().notNull().default(0),
393
+ /** sha256 (hex) of the incarnation's join token; the token itself is never stored. */
394
+ joinTokenHash: text(),
395
+ /** Bumped by every change the Runtime asks of the pod: the sandboxes service's `opId`. */
396
+ rev: integer().notNull().default(0),
397
+ /** When a turn last ended on it, for the idle timer. */
398
+ lastActiveAt: timestamp({ withTimezone: true }),
399
+ /** When its TTL passes (`createdAt + lifecycle.ttl`). */
400
+ expiresAt: timestamp({ withTimezone: true }),
401
+ /** When the current incarnation was asked to run, for the ready deadline. */
402
+ startedAt: timestamp({ withTimezone: true }),
403
+ /** Why it failed or was lost. */
404
+ reason: text(),
405
+ /** An earlier incarnation's Sandbox still to delete (after a reset or a loss). */
406
+ retiring: textC(),
407
+ /**
408
+ * The id the engine keeps on the volume (`/harness/volume-id`), recorded at the first join:
409
+ * a join with another one means the volume was replaced (its files are gone), so `lost`.
410
+ */
411
+ volumeId: text(),
412
+ });
413
+ /**
414
+ * Artifacts (blueprint D35, F8.1 and F8.2): an id, a name and numbered versions. The bytes are in
415
+ * the Object store under each version's `blobKey` (a folder's: its manifest); a blob counts only
416
+ * once its version row commits. `sessionId` is the session the artifact belongs to, or null for
417
+ * a Tenant-wide one an application made. `latestVersion` is the newest version's number.
418
+ */
419
+ export const artifacts = nylorun.table("artifacts", {
420
+ id: textC().primaryKey(),
421
+ kind: text({ enum: ["file", "folder"] }).notNull(),
422
+ name: text().notNull(),
423
+ contentType: text().notNull(),
424
+ sessionId: textC(),
425
+ latestVersion: integer().notNull(),
426
+ /** Labels as JSON text, or null. */
427
+ labelsJson: text(),
428
+ createdAt: textC().notNull(),
429
+ updatedAt: text().notNull(),
430
+ }, (t) => [
431
+ index("artifacts_session").on(t.sessionId, t.createdAt, t.id),
432
+ check("artifacts_kind_check", sql `kind IN ('file', 'folder')`),
433
+ ]);
434
+ /** The versions of an artifact, immutable once written. */
435
+ export const artifactVersions = nylorun.table("artifact_versions", {
436
+ artifactId: textC().notNull(),
437
+ version: integer().notNull(),
438
+ /** Where the bytes are in the Object store (`BlobStore`). */
439
+ blobKey: text().notNull(),
440
+ size: bigint({ mode: "number" }).notNull(),
441
+ sha256: text().notNull(),
442
+ contentType: text().notNull(),
443
+ source: text({ enum: ["upload", "engine", "export"] }).notNull(),
444
+ createdAt: textC().notNull(),
445
+ }, (t) => [
446
+ primaryKey({ name: "artifact_versions_pkey", columns: [t.artifactId, t.version] }),
447
+ foreignKey({
448
+ name: "artifact_versions_artifact_id_fkey",
449
+ columns: [t.artifactId],
450
+ foreignColumns: [artifacts.id],
451
+ }).onDelete("cascade"),
452
+ ]);
453
+ /**
454
+ * The content-addressed files each folder version references (F8.2), one row per distinct
455
+ * SHA-256: the index that says which `blobs/sha256/<hex>` objects are still in use, so deleting
456
+ * a folder removes only the files no other version names, and the Tenant total counts each file
457
+ * once. The manifest itself stays the source of truth for paths.
458
+ */
459
+ export const artifactContent = nylorun.table("artifact_content", {
460
+ artifactId: textC().notNull(),
461
+ version: integer().notNull(),
462
+ sha256: textC().notNull(),
463
+ size: bigint({ mode: "number" }).notNull(),
464
+ }, (t) => [
465
+ primaryKey({ name: "artifact_content_pkey", columns: [t.artifactId, t.version, t.sha256] }),
466
+ foreignKey({
467
+ name: "artifact_content_version_fkey",
468
+ columns: [t.artifactId, t.version],
469
+ foreignColumns: [artifactVersions.artifactId, artifactVersions.version],
470
+ }).onDelete("cascade"),
471
+ index("artifact_content_sha256").on(t.sha256),
472
+ ]);
338
473
  // ---------------------------------------------------------------------------
339
474
  // nylorun_streams: the record
475
+ /**
476
+ * Each sandbox's lifecycle stream (`nylorun.sandbox-event/1`), numbered from 0 per sandbox id.
477
+ * Written only by the record module; not published to the stream relay.
478
+ */
479
+ export const sandboxEvents = nylorunStreams.table("sandbox_events", {
480
+ sandboxId: textC().notNull(),
481
+ seq: bigint({ mode: "number" }).notNull(),
482
+ type: text().notNull(),
483
+ body: jsonText().notNull(),
484
+ committedAt: timestamp({ withTimezone: true, mode: "string" }).notNull().defaultNow(),
485
+ }, (t) => [primaryKey({ name: "sandbox_events_pkey", columns: [t.sandboxId, t.seq] })]);
340
486
  /** Each session's log head: the next seq and the basin generation its events go to. */
341
487
  export const sessionLogHeads = nylorunStreams.table("session_log_heads", {
342
488
  sessionId: textC().primaryKey(),