@nylorun/runtime 0.25.0-beta → 0.27.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 (326) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/README.md +26 -16
  3. package/dist/adapters/execution/restate.d.ts +15 -18
  4. package/dist/adapters/execution/restate.js +31 -27
  5. package/dist/adapters/replication/pgoutput.d.ts +1 -1
  6. package/dist/adapters/replication/pgoutput.js +3 -2
  7. package/dist/adapters/sandbox/local.js +8 -5
  8. package/dist/adapters/sandbox/virtual.js +2 -2
  9. package/dist/adapters/streams/s2.d.ts +1 -1
  10. package/dist/adapters/streams/s2.js +18 -14
  11. package/dist/api/a2a/card.js +1 -1
  12. package/dist/api/a2a/endpoint.js +3 -4
  13. package/dist/api/a2a/protocol.js +4 -0
  14. package/dist/api/a2a/routes.d.ts +2 -6
  15. package/dist/api/a2a/routes.js +12 -18
  16. package/dist/api/ag-ui/endpoint.js +2 -3
  17. package/dist/api/ag-ui/routes.js +4 -4
  18. package/dist/api/components.d.ts +326 -45
  19. package/dist/api/components.js +5 -1
  20. package/dist/api/gate/keys.js +7 -4
  21. package/dist/api/gate/routes.d.ts +6 -2
  22. package/dist/api/gate/routes.js +15 -11
  23. package/dist/api/http/app.d.ts +2 -2
  24. package/dist/api/http/app.js +2 -2
  25. package/dist/api/http/body.d.ts +15 -3
  26. package/dist/api/http/body.js +15 -7
  27. package/dist/api/http/define.d.ts +1 -1
  28. package/dist/api/http/respond.js +7 -3
  29. package/dist/api/http/routes/access.js +5 -4
  30. package/dist/api/http/routes/artifacts.js +19 -7
  31. package/dist/api/http/routes/coverage.js +1 -1
  32. package/dist/api/http/routes/environment-manifests.js +1 -1
  33. package/dist/api/http/routes/environments.js +6 -6
  34. package/dist/api/http/routes/files.d.ts +2 -1
  35. package/dist/api/http/routes/files.js +31 -5
  36. package/dist/api/http/routes/mcp.js +1 -1
  37. package/dist/api/http/routes/reads.d.ts +35 -0
  38. package/dist/api/http/routes/reads.js +50 -22
  39. package/dist/api/http/routes/sessions.js +12 -11
  40. package/dist/api/http/routes/tenant.d.ts +2 -2
  41. package/dist/api/http/routes/tenant.js +69 -16
  42. package/dist/api/inbound-files.d.ts +3 -9
  43. package/dist/api/inbound-files.js +18 -24
  44. package/dist/api/openapi.js +6 -2
  45. package/dist/artifacts/disk.d.ts +0 -4
  46. package/dist/artifacts/disk.js +77 -73
  47. package/dist/artifacts/files.d.ts +13 -4
  48. package/dist/artifacts/files.js +27 -9
  49. package/dist/artifacts/folder-upload.d.ts +75 -0
  50. package/dist/artifacts/folder-upload.js +263 -0
  51. package/dist/artifacts/folders.d.ts +14 -8
  52. package/dist/artifacts/folders.js +19 -11
  53. package/dist/artifacts/links.js +7 -6
  54. package/dist/artifacts/parts.d.ts +9 -14
  55. package/dist/artifacts/parts.js +11 -9
  56. package/dist/artifacts/pipe.d.ts +15 -0
  57. package/dist/artifacts/pipe.js +71 -0
  58. package/dist/artifacts/quota.d.ts +36 -0
  59. package/dist/artifacts/quota.js +44 -0
  60. package/dist/artifacts/service.d.ts +25 -1
  61. package/dist/artifacts/service.js +70 -25
  62. package/dist/blob/fs.js +2 -1
  63. package/dist/blob/s3.d.ts +6 -2
  64. package/dist/blob/s3.js +9 -7
  65. package/dist/blob/types.d.ts +1 -1
  66. package/dist/blob/types.js +1 -1
  67. package/dist/core/limits.d.ts +11 -35
  68. package/dist/core/limits.js +5 -73
  69. package/dist/core/sandbox-routes.js +0 -1
  70. package/dist/core/turn-manifest.d.ts +1 -2
  71. package/dist/core/turn-manifest.js +4 -28
  72. package/dist/execution/memory.d.ts +8 -5
  73. package/dist/execution/memory.js +8 -6
  74. package/dist/execution/types.d.ts +1 -6
  75. package/dist/execution/types.js +0 -5
  76. package/dist/gates/contract.d.ts +3 -2
  77. package/dist/gates/contract.js +1 -1
  78. package/dist/gates/egress-credentials.js +4 -3
  79. package/dist/gates/egress.d.ts +9 -9
  80. package/dist/gates/egress.js +19 -19
  81. package/dist/gates/fixture-model.js +13 -2
  82. package/dist/gates/handler.d.ts +1 -3
  83. package/dist/gates/handler.js +4 -3
  84. package/dist/gates/http-client.d.ts +4 -3
  85. package/dist/gates/http-client.js +5 -7
  86. package/dist/gates/http-tool.d.ts +24 -4
  87. package/dist/gates/http-tool.js +53 -17
  88. package/dist/gates/in-process.d.ts +2 -1
  89. package/dist/gates/in-process.js +17 -9
  90. package/dist/gates/inflight.d.ts +2 -2
  91. package/dist/gates/inflight.js +3 -2
  92. package/dist/gates/journal.js +5 -7
  93. package/dist/gates/mcp-handler.d.ts +4 -3
  94. package/dist/gates/mcp-handler.js +15 -5
  95. package/dist/gates/model-gate.d.ts +11 -2
  96. package/dist/gates/policy.d.ts +28 -5
  97. package/dist/gates/policy.js +60 -17
  98. package/dist/gates/provider-gate.d.ts +22 -0
  99. package/dist/gates/provider-gate.js +30 -0
  100. package/dist/gates/tool-calls.d.ts +1 -3
  101. package/dist/gates/tool-calls.js +2 -3
  102. package/dist/gates/tool-client.d.ts +1 -1
  103. package/dist/gates/tool-client.js +5 -6
  104. package/dist/gates/tool-contract.d.ts +8 -5
  105. package/dist/gates/tool-contract.js +1 -1
  106. package/dist/gates/tool-gate.d.ts +18 -7
  107. package/dist/gates/tool-gate.js +49 -7
  108. package/dist/harness/calls.d.ts +27 -25
  109. package/dist/harness/calls.js +40 -46
  110. package/dist/harness/executors.d.ts +10 -3
  111. package/dist/harness/executors.js +53 -23
  112. package/dist/harness/main.js +2 -2
  113. package/dist/harness/pod.d.ts +0 -2
  114. package/dist/harness/pod.js +7 -6
  115. package/dist/harness/run-tokens.d.ts +4 -1
  116. package/dist/harness/run-tokens.js +6 -2
  117. package/dist/harness/service.d.ts +17 -14
  118. package/dist/harness/service.js +21 -35
  119. package/dist/harness/setup.d.ts +0 -2
  120. package/dist/harness/setup.js +4 -9
  121. package/dist/harness/ws-client.d.ts +2 -2
  122. package/dist/harness/ws-client.js +7 -5
  123. package/dist/harness/ws-port.d.ts +3 -4
  124. package/dist/harness/ws-port.js +3 -4
  125. package/dist/harness-api/artifacts.d.ts +20 -0
  126. package/dist/harness-api/artifacts.js +478 -0
  127. package/dist/harness-api/in-process.d.ts +2 -2
  128. package/dist/harness-api/in-process.js +18 -16
  129. package/dist/harness-api/record.d.ts +10 -9
  130. package/dist/harness-api/record.js +102 -157
  131. package/dist/harness-api/renew.d.ts +1 -1
  132. package/dist/harness-api/renew.js +2 -2
  133. package/dist/harness-api/server.d.ts +1 -16
  134. package/dist/harness-api/server.js +82 -73
  135. package/dist/harness-api/start.d.ts +20 -2
  136. package/dist/harness-api/start.js +57 -18
  137. package/dist/harness-api/tool-journal.d.ts +15 -10
  138. package/dist/harness-api/tool-journal.js +26 -24
  139. package/dist/harness-api/workspace.d.ts +0 -4
  140. package/dist/harness-api/workspace.js +2 -45
  141. package/dist/harness-api/ws-server.js +10 -10
  142. package/dist/host/create-host.js +2 -3
  143. package/dist/host/execution.js +2 -3
  144. package/dist/host/gates.d.ts +2 -9
  145. package/dist/host/gates.js +15 -12
  146. package/dist/host/http.d.ts +0 -2
  147. package/dist/host/http.js +0 -27
  148. package/dist/host/main.js +10 -3
  149. package/dist/host/operate.js +12 -3
  150. package/dist/host/stack-config.d.ts +11 -0
  151. package/dist/host/stack-config.js +21 -1
  152. package/dist/index.d.ts +0 -1
  153. package/dist/index.js +0 -1
  154. package/dist/infra/index.js +2 -1
  155. package/dist/infra/readiness.d.ts +0 -2
  156. package/dist/infra/readiness.js +4 -3
  157. package/dist/keys/client.d.ts +1 -0
  158. package/dist/keys/client.js +2 -3
  159. package/dist/keys/contract.d.ts +1 -3
  160. package/dist/keys/contract.js +1 -3
  161. package/dist/keys/egress-ca.d.ts +0 -2
  162. package/dist/keys/egress-ca.js +2 -3
  163. package/dist/keys/keys.js +6 -1
  164. package/dist/keys/x509.d.ts +8 -4
  165. package/dist/keys/x509.js +14 -5
  166. package/dist/management-openapi.json +1961 -994
  167. package/dist/mcp/connect.d.ts +35 -26
  168. package/dist/mcp/connect.js +112 -141
  169. package/dist/mcp/pool.d.ts +27 -22
  170. package/dist/mcp/pool.js +34 -48
  171. package/dist/mcp/preview.d.ts +13 -6
  172. package/dist/mcp/preview.js +37 -20
  173. package/dist/mcp/snapshot.d.ts +35 -86
  174. package/dist/mcp/snapshot.js +93 -135
  175. package/dist/model/auth-store.js +5 -3
  176. package/dist/model/capabilities.d.ts +1 -1
  177. package/dist/model/catalog.d.ts +9 -36
  178. package/dist/model/catalog.js +6 -33
  179. package/dist/model/descriptor.d.ts +51 -0
  180. package/dist/model/descriptor.js +83 -0
  181. package/dist/model/models.d.ts +0 -3
  182. package/dist/model/models.js +3 -5
  183. package/dist/model/native-blocks.js +1 -1
  184. package/dist/model/pi-model.d.ts +16 -5
  185. package/dist/model/pi-model.js +86 -105
  186. package/dist/openapi.json +866 -1218
  187. package/dist/reads/cursor.js +3 -1
  188. package/dist/record/append.d.ts +34 -2
  189. package/dist/record/append.js +50 -1
  190. package/dist/record/environment.d.ts +2 -0
  191. package/dist/record/environment.js +2 -0
  192. package/dist/record/index.d.ts +1 -1
  193. package/dist/record/index.js +1 -1
  194. package/dist/redact.d.ts +1 -1
  195. package/dist/redact.js +3 -2
  196. package/dist/sandbox/egress-token.d.ts +3 -3
  197. package/dist/sandbox/egress-token.js +3 -3
  198. package/dist/sandbox/join.js +3 -2
  199. package/dist/sandbox/manager.d.ts +41 -41
  200. package/dist/sandbox/manager.js +112 -44
  201. package/dist/sandbox/placement.d.ts +1 -1
  202. package/dist/sandbox/placement.js +5 -8
  203. package/dist/sandbox/pods/client.d.ts +1 -10
  204. package/dist/sandbox/pods/client.js +8 -4
  205. package/dist/sandbox/pods/lifecycle.d.ts +19 -11
  206. package/dist/sandbox/pods/lifecycle.js +45 -23
  207. package/dist/sandbox/pods/network-gate.d.ts +4 -5
  208. package/dist/sandbox/pods/network-gate.js +7 -7
  209. package/dist/sandbox/pods/reconcile.js +4 -1
  210. package/dist/sandbox/pods/spec.js +8 -5
  211. package/dist/sandbox/policy.d.ts +7 -1
  212. package/dist/sandbox/policy.js +10 -3
  213. package/dist/sandbox/resolve.d.ts +8 -3
  214. package/dist/sandbox/resolve.js +12 -2
  215. package/dist/sandbox/setup.d.ts +3 -1
  216. package/dist/sandbox/setup.js +34 -11
  217. package/dist/sandbox/share.d.ts +5 -14
  218. package/dist/sandbox/share.js +5 -34
  219. package/dist/sandbox/skills.d.ts +7 -13
  220. package/dist/sandbox/skills.js +16 -31
  221. package/dist/sandbox/tenant-config.d.ts +2 -2
  222. package/dist/sandbox/tenant-config.js +4 -3
  223. package/dist/sandbox/tools.d.ts +7 -1
  224. package/dist/sandbox/tools.js +26 -26
  225. package/dist/sandbox/types.d.ts +10 -3
  226. package/dist/sandbox/types.js +9 -0
  227. package/dist/store/postgres/connect.d.ts +6 -5
  228. package/dist/store/postgres/connect.js +14 -11
  229. package/dist/store/postgres/control.js +13 -13
  230. package/dist/store/postgres/drizzle/0028_artifact_write_keys.sql +2 -0
  231. package/dist/store/postgres/drizzle/0029_protocol_15.sql +11 -0
  232. package/dist/store/postgres/drizzle/0030_protocol_15_runtime_block.sql +11 -0
  233. package/dist/store/postgres/drizzle/0031_protocol_15_mcp_snapshot.sql +8 -0
  234. package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
  235. package/dist/store/postgres/migrate.js +1 -1
  236. package/dist/store/postgres/reads.js +10 -2
  237. package/dist/store/postgres/schema.d.ts +19 -0
  238. package/dist/store/postgres/schema.js +7 -0
  239. package/dist/store/postgres/store.js +55 -26
  240. package/dist/store/types.d.ts +17 -7
  241. package/dist/streams/relay/core.d.ts +3 -3
  242. package/dist/streams/relay/core.js +9 -10
  243. package/dist/tenant/advance.js +21 -31
  244. package/dist/tenant/commands.js +9 -16
  245. package/dist/tenant/context.d.ts +14 -17
  246. package/dist/tenant/definition-files.d.ts +25 -4
  247. package/dist/tenant/definition-files.js +85 -47
  248. package/dist/tenant/effects.js +9 -36
  249. package/dist/tenant/environment-manifests.js +9 -1
  250. package/dist/tenant/environments.d.ts +0 -2
  251. package/dist/tenant/environments.js +54 -30
  252. package/dist/tenant/ephemeral.d.ts +1 -1
  253. package/dist/tenant/ephemeral.js +2 -1
  254. package/dist/tenant/history.d.ts +1 -1
  255. package/dist/tenant/history.js +1 -1
  256. package/dist/tenant/host-token.d.ts +3 -3
  257. package/dist/tenant/host-token.js +12 -11
  258. package/dist/tenant/http.d.ts +5 -8
  259. package/dist/tenant/http.js +9 -0
  260. package/dist/tenant/identity-file.d.ts +24 -1
  261. package/dist/tenant/identity-file.js +35 -7
  262. package/dist/tenant/issuers.d.ts +5 -5
  263. package/dist/tenant/issuers.js +31 -23
  264. package/dist/tenant/jwt.d.ts +8 -2
  265. package/dist/tenant/jwt.js +10 -2
  266. package/dist/tenant/limits.d.ts +90 -0
  267. package/dist/tenant/limits.js +175 -0
  268. package/dist/tenant/module.d.ts +4 -1
  269. package/dist/tenant/module.js +9 -8
  270. package/dist/tenant/outbound.d.ts +17 -19
  271. package/dist/tenant/outbound.js +18 -21
  272. package/dist/tenant/run-grants.js +3 -2
  273. package/dist/tenant/run-token.d.ts +0 -4
  274. package/dist/tenant/run-token.js +6 -11
  275. package/dist/tenant/runtime-limits.d.ts +24 -0
  276. package/dist/tenant/runtime-limits.js +27 -0
  277. package/dist/tenant/runtime.js +30 -43
  278. package/dist/tenant/session-streams.js +7 -6
  279. package/dist/tenant/session.d.ts +1 -1
  280. package/dist/tenant/session.js +1 -1
  281. package/dist/tenant/sessions.js +32 -29
  282. package/dist/tenant/signing-keys.d.ts +1 -1
  283. package/dist/tenant/signing-keys.js +5 -6
  284. package/dist/tenant/status.js +4 -3
  285. package/dist/tenant/streams.js +18 -20
  286. package/dist/tenant/sweep.d.ts +1 -21
  287. package/dist/tenant/sweep.js +39 -48
  288. package/dist/tenant/transcript.d.ts +70 -23
  289. package/dist/tenant/transcript.js +28 -22
  290. package/dist/tenant/types.d.ts +11 -16
  291. package/dist/tenant/worker.d.ts +2 -10
  292. package/dist/tenant/worker.js +5 -14
  293. package/dist/traces/ids.js +5 -1
  294. package/dist/traces/map.d.ts +9 -6
  295. package/dist/traces/map.js +9 -11
  296. package/dist/traces/otlp.d.ts +3 -3
  297. package/dist/traces/otlp.js +5 -3
  298. package/dist/traces/projector.d.ts +9 -4
  299. package/dist/traces/projector.js +13 -7
  300. package/dist/traces/read.js +6 -1
  301. package/dist/tuning.d.ts +383 -0
  302. package/dist/tuning.js +658 -0
  303. package/dist/vault/headers.js +4 -2
  304. package/dist/version.d.ts +1 -1
  305. package/dist/version.js +1 -1
  306. package/package.json +3 -3
  307. package/dist/artifacts/export.d.ts +0 -8
  308. package/dist/artifacts/export.js +0 -204
  309. package/dist/artifacts/media-types.d.ts +0 -30
  310. package/dist/artifacts/media-types.js +0 -137
  311. package/dist/artifacts/workspace.d.ts +0 -60
  312. package/dist/artifacts/workspace.js +0 -45
  313. package/dist/media.d.ts +0 -10
  314. package/dist/media.js +0 -58
  315. package/dist/sandbox/runtime-tools.d.ts +0 -9
  316. package/dist/sandbox/runtime-tools.js +0 -16
  317. package/dist/sandbox/session-sandbox.d.ts +0 -16
  318. package/dist/sandbox/session-sandbox.js +0 -77
  319. package/dist/tenant/artifact-tool.d.ts +0 -13
  320. package/dist/tenant/artifact-tool.js +0 -243
  321. package/dist/tenant/skill-tool.d.ts +0 -20
  322. package/dist/tenant/skill-tool.js +0 -67
  323. package/dist/tenant/tool-results.d.ts +0 -57
  324. package/dist/tenant/tool-results.js +0 -298
  325. package/dist/tenant/tool-search.d.ts +0 -39
  326. package/dist/tenant/tool-search.js +0 -103
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { z } from "zod";
3
3
  import { decodeCursor } from "../record/index.js";
4
4
  import { fail } from "../tenant/http.js";
5
+ import { maxHeaderSize } from "node:http";
5
6
  const schema = z
6
7
  .object({
7
8
  version: z.literal(1),
@@ -23,7 +24,8 @@ export function readCursor(tenant, route, filters) {
23
24
  decode(value) {
24
25
  if (value === undefined)
25
26
  return undefined;
26
- if (value.length > 4096 || !/^[A-Za-z0-9_-]+$/.test(value))
27
+ // A cursor comes back in a URL, which Node refuses past `http.maxHeaderSize` anyway.
28
+ if (value.length > maxHeaderSize || !/^[A-Za-z0-9_-]+$/.test(value))
27
29
  return fail(400, "Invalid cursor", { code: "cursor_invalid" });
28
30
  let parsed;
29
31
  try {
@@ -9,8 +9,37 @@
9
9
  * The two statements run through `RecordWriter`, which the store implements on its
10
10
  * transaction (`store/postgres/record-writer.ts`): the database driver stays behind
11
11
  * `store/postgres/` (session-store.md §3), and this module decides what is written.
12
+ *
13
+ * Every entry is held to the Tenant's Runtime limit `recordEntryBytes`, which the caller reads
14
+ * and passes: an event whose payload is larger is refused (`RecordEntryTooLargeError`) before
15
+ * anything is written, whoever wrote it, so no record reaches S2 past its 1 MiB.
16
+ */
17
+ import { type EventPayload, type EventType, type EventWriter, type LiveEvent, type SessionEventOf } from "@nylorun/core/contracts";
18
+ /**
19
+ * An entry larger than the Tenant's `recordEntryBytes`: `limit_exceeded`, `413` to an API client
20
+ * and the Harness API error code to a harness.
12
21
  */
13
- import type { EventPayload, EventType, EventWriter, LiveEvent, SessionEventOf } from "@nylorun/core/contracts";
22
+ export declare class RecordEntryTooLargeError extends Error {
23
+ readonly bytes: number;
24
+ readonly maxBytes: number;
25
+ readonly code: "limit_exceeded";
26
+ readonly status = 413;
27
+ readonly rejection: {
28
+ readonly code: "limit_exceeded";
29
+ readonly details: {
30
+ readonly limit: "recordEntryBytes";
31
+ readonly bytes: number;
32
+ readonly maxBytes: number;
33
+ };
34
+ };
35
+ constructor(
36
+ /** What was refused, as the message names it: "The message.user event's payload". */
37
+ what: string, bytes: number, maxBytes: number);
38
+ }
39
+ /** The JSON size of an entry, in bytes: what the record holds of it. */
40
+ export declare function entryBytes(value: unknown): number;
41
+ /** Throws `RecordEntryTooLargeError` when `entry` is larger than `maxBytes`; `what` names it. */
42
+ export declare function checkEntry(what: string, entry: unknown, maxBytes: number): void;
14
43
  /** The record's two statements, in the caller's transaction. */
15
44
  export interface RecordWriter {
16
45
  /**
@@ -42,10 +71,13 @@ export interface AppendInput<T extends EventType> {
42
71
  payload: EventPayload<T>;
43
72
  /** Who wrote it (R4.9). */
44
73
  writer?: EventWriter;
74
+ /** The Tenant's Runtime limit `recordEntryBytes`: the most bytes the payload may hold, as JSON. */
75
+ maxEntryBytes: number;
45
76
  }
46
77
  /**
47
78
  * Appends one event through `writer`. An event the catalog does not describe throws
48
- * `InvalidEventError` before its row is written; the caller's transaction then rolls back.
79
+ * `InvalidEventError`, and one past `maxEntryBytes` `RecordEntryTooLargeError`, before its row is
80
+ * written; the caller's transaction then rolls back.
49
81
  */
50
82
  export declare function appendEvent<T extends EventType>(writer: RecordWriter, input: AppendInput<T>): Promise<{
51
83
  event: SessionEventOf<T>;
@@ -1,9 +1,58 @@
1
+ /**
2
+ * The only write path into the record (Durable Streams §6, blueprint D27): the session's log
3
+ * head allocates the next sequence, the event is built on the envelope and checked against the
4
+ * catalog, and its row is written, both in the caller's transaction. The database holds one
5
+ * Tenant, so rows are keyed by session alone; the Tenant id is the caller's and goes into the
6
+ * envelope only. The caller holds the session row lock, which orders the session's appends,
7
+ * and passes the epoch it read under that lock.
8
+ *
9
+ * The two statements run through `RecordWriter`, which the store implements on its
10
+ * transaction (`store/postgres/record-writer.ts`): the database driver stays behind
11
+ * `store/postgres/` (session-store.md §3), and this module decides what is written.
12
+ *
13
+ * Every entry is held to the Tenant's Runtime limit `recordEntryBytes`, which the caller reads
14
+ * and passes: an event whose payload is larger is refused (`RecordEntryTooLargeError`) before
15
+ * anything is written, whoever wrote it, so no record reaches S2 past its 1 MiB.
16
+ */
17
+ import { limitExceededMessage, } from "@nylorun/core/contracts";
1
18
  import { buildEvent } from "./envelope.js";
19
+ /**
20
+ * An entry larger than the Tenant's `recordEntryBytes`: `limit_exceeded`, `413` to an API client
21
+ * and the Harness API error code to a harness.
22
+ */
23
+ export class RecordEntryTooLargeError extends Error {
24
+ bytes;
25
+ maxBytes;
26
+ code = "limit_exceeded";
27
+ status = 413;
28
+ rejection;
29
+ constructor(
30
+ /** What was refused, as the message names it: "The message.user event's payload". */
31
+ what, bytes, maxBytes) {
32
+ super(limitExceededMessage(what, bytes, "recordEntryBytes", maxBytes));
33
+ this.bytes = bytes;
34
+ this.maxBytes = maxBytes;
35
+ this.name = "RecordEntryTooLargeError";
36
+ this.rejection = { code: "limit_exceeded", details: { limit: "recordEntryBytes", bytes, maxBytes } };
37
+ }
38
+ }
39
+ /** The JSON size of an entry, in bytes: what the record holds of it. */
40
+ export function entryBytes(value) {
41
+ return Buffer.byteLength(JSON.stringify(value) ?? "null");
42
+ }
43
+ /** Throws `RecordEntryTooLargeError` when `entry` is larger than `maxBytes`; `what` names it. */
44
+ export function checkEntry(what, entry, maxBytes) {
45
+ const bytes = entryBytes(entry);
46
+ if (bytes > maxBytes)
47
+ throw new RecordEntryTooLargeError(what, bytes, maxBytes);
48
+ }
2
49
  /**
3
50
  * Appends one event through `writer`. An event the catalog does not describe throws
4
- * `InvalidEventError` before its row is written; the caller's transaction then rolls back.
51
+ * `InvalidEventError`, and one past `maxEntryBytes` `RecordEntryTooLargeError`, before its row is
52
+ * written; the caller's transaction then rolls back.
5
53
  */
6
54
  export async function appendEvent(writer, input) {
55
+ checkEntry(`The ${input.type} event's payload`, input.payload, input.maxEntryBytes);
7
56
  const { seq, generation } = await writer.advance(input.sessionId);
8
57
  const event = buildEvent({
9
58
  tenantId: input.tenantId,
@@ -16,6 +16,8 @@ export interface EnvironmentAppendInput<T extends EnvironmentEventType> {
16
16
  time: Date;
17
17
  type: T;
18
18
  payload: EnvironmentEventPayload<T>;
19
+ /** The Tenant's Runtime limit `recordEntryBytes`, as for a session's events. */
20
+ maxEntryBytes: number;
19
21
  }
20
22
  /** Builds the event and checks it against the Environment event catalog. */
21
23
  export declare function buildEnvironmentEvent<T extends EnvironmentEventType>(input: EnvironmentAppendInput<T> & {
@@ -14,6 +14,7 @@ import { randomUUID } from "node:crypto";
14
14
  import { z } from "zod";
15
15
  import { ENVIRONMENT_EVENT_PAYLOADS, ENVIRONMENT_EVENT_SCHEMA, EnvironmentEventSchema, } from "@nylorun/core/contracts";
16
16
  import { InvalidEventError } from "./envelope.js";
17
+ import { checkEntry } from "./append.js";
17
18
  /** Builds the event and checks it against the Environment event catalog. */
18
19
  export function buildEnvironmentEvent(input) {
19
20
  const payload = ENVIRONMENT_EVENT_PAYLOADS[input.type];
@@ -37,6 +38,7 @@ export function buildEnvironmentEvent(input) {
37
38
  }
38
39
  /** Appends one event to the Environment's stream through `writer`. */
39
40
  export async function appendEnvironmentEvent(writer, input) {
41
+ checkEntry(`The ${input.type} event's payload`, input.payload, input.maxEntryBytes);
40
42
  const seq = await writer.nextSeq(input.environmentId);
41
43
  const event = buildEnvironmentEvent({ ...input, seq });
42
44
  await writer.insert({ environmentId: input.environmentId, seq, type: input.type, body: event });
@@ -8,5 +8,5 @@
8
8
  */
9
9
  export { buildEvent, InvalidEventError, type EventInput } from "./envelope.js";
10
10
  export { decodeCursor, encodeCursor } from "./cursor.js";
11
- export { appendEvent, type AppendInput, type RecordWriter } from "./append.js";
11
+ export { RecordEntryTooLargeError, appendEvent, checkEntry, entryBytes, type AppendInput, type RecordWriter, } from "./append.js";
12
12
  export { appendEnvironmentEvent, buildEnvironmentEvent, type EnvironmentAppendInput, type EnvironmentRecordWriter, } from "./environment.js";
@@ -8,5 +8,5 @@
8
8
  */
9
9
  export { buildEvent, InvalidEventError } from "./envelope.js";
10
10
  export { decodeCursor, encodeCursor } from "./cursor.js";
11
- export { appendEvent } from "./append.js";
11
+ export { RecordEntryTooLargeError, appendEvent, checkEntry, entryBytes, } from "./append.js";
12
12
  export { appendEnvironmentEvent, buildEnvironmentEvent, } from "./environment.js";
package/dist/redact.d.ts CHANGED
@@ -8,7 +8,7 @@ export interface ScrubOptions {
8
8
  readonly counted?: (replacements: number) => void;
9
9
  }
10
10
  /**
11
- * `value` with each of `secrets` (those of at least 8 characters) replaced by `[redacted]`. By
11
+ * `value` with each of `secrets` (those of at least `harness.scrubMinChars`, 8 by default) replaced by `[redacted]`. By
12
12
  * default also any value under a key such as `token` or `secret`, and inline image data.
13
13
  */
14
14
  export declare function scrub(value: unknown, secrets: readonly string[], options?: ScrubOptions): unknown;
package/dist/redact.js CHANGED
@@ -1,10 +1,11 @@
1
+ import { hostTuning } from "./tuning.js";
1
2
  /**
2
- * `value` with each of `secrets` (those of at least 8 characters) replaced by `[redacted]`. By
3
+ * `value` with each of `secrets` (those of at least `harness.scrubMinChars`, 8 by default) replaced by `[redacted]`. By
3
4
  * default also any value under a key such as `token` or `secret`, and inline image data.
4
5
  */
5
6
  export function scrub(value, secrets, options = {}) {
6
7
  // The longest first, so a header value goes whole before the token inside it.
7
- const sorted = secrets.filter((secret) => secret.length >= 8).sort((a, b) => b.length - a.length);
8
+ const sorted = secrets.filter((secret) => secret.length >= hostTuning().harness.scrubMinChars).sort((a, b) => b.length - a.length);
8
9
  let replaced = 0;
9
10
  const walk = (item) => {
10
11
  if (typeof item === "string") {
@@ -14,10 +14,10 @@
14
14
  * check (`EgressSandboxes.live`).
15
15
  */
16
16
  import type { SessionStore } from "../store/types.js";
17
- import { EGRESS_TOKEN_AUD, EGRESS_TOKEN_TYP, mintEgressToken, type EgressTokenRequest, type HostClaims, type HostTokenKeyCache, type HostTokenVerdict } from "../tenant/host-token.js";
17
+ import { EGRESS_TOKEN_AUD, EGRESS_TOKEN_TYP, hostTokenTtlSeconds, mintEgressToken, type EgressTokenRequest, type HostClaims, type HostTokenKeyCache, type HostTokenVerdict } from "../tenant/host-token.js";
18
18
  export { EGRESS_TOKEN_AUD, EGRESS_TOKEN_TYP, mintEgressToken, type EgressTokenRequest };
19
- /** The longest lifetime an egress token has: a host token's. */
20
- export declare const EGRESS_TOKEN_MAX_TTL_SECONDS: number;
19
+ /** The longest lifetime an egress token has: a host token's (`keys.hostTokenTtlSeconds`). */
20
+ export declare const egressTokenMaxTtlSeconds: typeof hostTokenTtlSeconds;
21
21
  export type EgressClaims = HostClaims;
22
22
  export type EgressTokenVerdict = HostTokenVerdict;
23
23
  /** Public keys imported by key id; the key row is still read on every verification. */
@@ -1,7 +1,7 @@
1
- import { EGRESS_TOKEN_AUD, EGRESS_TOKEN_TYP, HOST_TOKEN_TTL_SECONDS, mintEgressToken, verifyHostToken, } from "../tenant/host-token.js";
1
+ import { EGRESS_TOKEN_AUD, EGRESS_TOKEN_TYP, hostTokenTtlSeconds, mintEgressToken, verifyHostToken, } from "../tenant/host-token.js";
2
2
  export { EGRESS_TOKEN_AUD, EGRESS_TOKEN_TYP, mintEgressToken };
3
- /** The longest lifetime an egress token has: a host token's. */
4
- export const EGRESS_TOKEN_MAX_TTL_SECONDS = HOST_TOKEN_TTL_SECONDS;
3
+ /** The longest lifetime an egress token has: a host token's (`keys.hostTokenTtlSeconds`). */
4
+ export const egressTokenMaxTtlSeconds = hostTokenTtlSeconds;
5
5
  /** Verifies an egress token of Tenant `tenantId`; refusal reasons are `egress_token_*`. */
6
6
  export function verifyEgressToken(store, tenantId, raw, cache = new Map()) {
7
7
  return verifyHostToken(store, tenantId, raw, "egress", cache);
@@ -36,6 +36,7 @@ import { isEnvironmentId } from "@nylorun/core/contracts";
36
36
  import { recoverLostVolume, runPendingSeed } from "../artifacts/disk.js";
37
37
  import { recordSetup, setupFile, setupPlanOf, setupState, } from "./setup.js";
38
38
  import { mintHostTokens, staleHost, verifyHostToken, } from "../tenant/host-token.js";
39
+ import { JOIN_TOKEN_MAX, POD_UID_PATTERN } from "@nylorun/core/harness-api";
39
40
  /** A refused join, renewal or host connection. */
40
41
  export class HostAuthError extends Error {
41
42
  status;
@@ -49,7 +50,7 @@ export class HostAuthError extends Error {
49
50
  this.reason = reason;
50
51
  }
51
52
  }
52
- const POD_UID = /^[A-Za-z0-9-]{1,64}$/;
53
+ const POD_UID = POD_UID_PATTERN;
53
54
  const REFUSED = "The join was refused";
54
55
  export function sha256Hex(value) {
55
56
  return createHash("sha256").update(value).digest("hex");
@@ -91,7 +92,7 @@ export function hostAuthority(ctx) {
91
92
  !POD_UID.test(podUid) ||
92
93
  typeof joinToken !== "string" ||
93
94
  joinToken.length === 0 ||
94
- joinToken.length > 512 ||
95
+ joinToken.length > JOIN_TOKEN_MAX ||
95
96
  (volumeId !== undefined && (typeof volumeId !== "string" || !POD_UID.test(volumeId))))
96
97
  throw new HostAuthError(400, "A join is { sandboxId, podUid, joinToken }");
97
98
  const pods = ctx.pods;
@@ -1,38 +1,17 @@
1
- /**
2
- * Sandbox Manager: owns sandbox lifecycle for the Runtime. One workspace per sandbox resource
3
- * (`sandbox: { id }`, keyed by the sandbox id), or per owning session for a sandbox chosen
4
- * inline or by the Tenant default (keyed by the session id); created on the first sandbox tool
5
- * call, stopped after its idle timeout, reattached on the next call. Each session's calls on a
6
- * workspace run in the order it sends them, and different sessions' calls run at the same time
7
- * (D66): the sessions of one Environment run their turns at once. Opening, stopping and removing
8
- * a workspace run alone: a stop or removal waits for the calls running, and calls that come after
9
- * it wait for it.
10
- *
11
- * The manager keeps no timers and reaches no store: it keeps its compute records through a
12
- * `SandboxRecords` port (the Tenant's `sandboxes` table in core's process, a file in a harness's)
13
- * and writes its events through `emit`. Its owner drives it: `stopIdle` stops sandboxes idle
14
- * past their timeout and marks records of compute this process no longer holds as stopped
15
- * (after a restart); `reconcile` removes workspaces whose owner is gone. `sweep` does both, the
16
- * reconcile once per process, as the Tenant sweep does in core's process.
17
- *
18
- * A session's skills (track R2 M4) are mounted on its workspace, read-only, one folder per
19
- * version (`/skills/<name>@<hash>/`, D66), before the first call that needs them (`skills.ts`);
20
- * their bytes come through the `definitionFile` port.
21
- */
22
1
  import type { EventPayload } from "@nylorun/core/contracts";
23
- import { type AgentManifest, type SandboxManifest, type SandboxToolName } from "@nylorun/core/define";
2
+ import { type SandboxManifest, type SandboxToolName } from "@nylorun/core/define";
24
3
  import { type SandboxRecord, type SandboxRecords } from "./records.js";
25
4
  import { type SandboxSelection, type SandboxSelectionReport } from "./select.js";
5
+ import { type FolderFiles } from "./skills.js";
6
+ import { type SandboxToolLimits } from "@nylorun/harness";
26
7
  import { type DiskAnswer, type DiskOp } from "./disk-fs.js";
27
8
  import { type SandboxToolOutcome } from "./tools.js";
28
- import { type SandboxBackend, type SandboxListing } from "./types.js";
29
- export { sandboxToolSpec } from "./runtime-tools.js";
9
+ import { type SandboxBackend, type SandboxFileBytes, type SandboxListing } from "./types.js";
30
10
  export type { SandboxRecord, SandboxRecords, SandboxState } from "./records.js";
31
11
  export interface SandboxSessionRef {
32
12
  /** The session whose log records the workspace's events: the owning session. */
33
13
  readonly id: string;
34
14
  readonly activeTurnId: string | null;
35
- readonly manifest?: AgentManifest;
36
15
  /**
37
16
  * The sandbox resource the owning session is attached to. Its workspace is keyed by this id,
38
17
  * so every session attached to it shares the files; absent, the workspace is the session's.
@@ -76,12 +55,6 @@ export interface SandboxManagerOptions {
76
55
  readonly preference: string | undefined;
77
56
  /** Delete sandboxes on close (the Runtime's store does not outlive the process). */
78
57
  readonly ephemeral: boolean;
79
- /**
80
- * A definition file's bytes by `sha256:<hex>`, for the skills a session's workspace mounts:
81
- * the Tenant's Object store in core's process, core's answer in a harness (for the run that
82
- * made the call, `session.claim`). Without it no skills are mounted.
83
- */
84
- readonly definitionFile?: (sha256: string, session: SandboxSessionRef) => Promise<Uint8Array>;
85
58
  /** Writes a session event (in core, in its own transaction; in a harness, as a claim). */
86
59
  readonly emit: <T extends SandboxEventType>(sessionId: string, turnId: string | null, type: T, payload: EventPayload<T>, meta: SandboxEventMeta) => void | Promise<void>;
87
60
  }
@@ -119,7 +92,11 @@ export declare class SandboxManager {
119
92
  report(): Promise<SandboxSelectionReport & {
120
93
  readonly defaultImage: string;
121
94
  }>;
122
- run(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, toolName: SandboxToolName, input: unknown, signal: AbortSignal): Promise<SandboxToolOutcome>;
95
+ /**
96
+ * Runs sandbox operation `toolName` in the session's sandbox, held to `limits`: the harness's
97
+ * sandbox tool limits (`DEFAULT_SANDBOX_TOOL_LIMITS` when it names none).
98
+ */
99
+ run(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, toolName: SandboxToolName, input: unknown, signal: AbortSignal, limits?: SandboxToolLimits): Promise<SandboxToolOutcome>;
123
100
  /**
124
101
  * Runs `call` in session `sessionId`'s queue on `live`: after its earlier calls, and after any
125
102
  * stop or removal pending, beside other sessions' calls (D66).
@@ -130,8 +107,8 @@ export declare class SandboxManager {
130
107
  /** The workspace's handle, opened once for the calls that need it at the same time. */
131
108
  private handleOf;
132
109
  /**
133
- * The bytes of one file in the session's sandbox, for `save_artifact` (F8.1), in the same queue
134
- * as its tool calls: `missing` when there is no such file, a failed outcome when the sandbox
110
+ * The bytes of one file in the session's sandbox, for our engine's `save_artifact` and its
111
+ * outputs folder (`files.read`), in the same queue as its tool calls: `missing` when there is no such file, a failed outcome when the sandbox
135
112
  * cannot open or the file is larger than `maxBytes`. Relative paths resolve in the workspace.
136
113
  */
137
114
  readBytes(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, path: string, maxBytes: number, signal: AbortSignal): Promise<{
@@ -145,8 +122,20 @@ export declare class SandboxManager {
145
122
  kind: "failed";
146
123
  }>>;
147
124
  /**
148
- * The files under directory `dir` of the session's sandbox, for the turn-end export (F8.2), in
149
- * the same queue as its tool calls. `missing` when the sandbox was never created (nothing is
125
+ * Writes `body` to one file of the session's sandbox, as it comes, for our engine's
126
+ * `read_artifact` with `path` (protocol 15), in the same queue as its tool calls: its folders
127
+ * are made first, and a file there is replaced. Relative paths resolve in the workspace.
128
+ */
129
+ writeBytes(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, path: string, body: SandboxFileBytes, signal: AbortSignal): Promise<{
130
+ kind: "written";
131
+ path: string;
132
+ size: number;
133
+ } | Extract<SandboxToolOutcome, {
134
+ kind: "failed";
135
+ }>>;
136
+ /**
137
+ * The files under directory `dir` of the session's sandbox, for our engine's outputs folder
138
+ * (`files.list`, protocol 15), in the same queue as its tool calls. `missing` when the sandbox was never created (nothing is
150
139
  * started to look) or `dir` is not a directory. Relative paths resolve in the workspace.
151
140
  */
152
141
  listFiles(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, dir: string, maxEntries: number, signal: AbortSignal): Promise<{
@@ -171,14 +160,25 @@ export declare class SandboxManager {
171
160
  /** The session's live sandbox entry and spec, or why it cannot run here. */
172
161
  private prepare;
173
162
  private execute;
163
+ /**
164
+ * The workspace's handle, opened when there is none. A start that fails is recorded as stopped
165
+ * and answered as a failed outcome: nothing ran yet, so it is definite, not uncertain.
166
+ */
167
+ private started;
174
168
  private executeOpen;
175
169
  /**
176
- * Mounts the skill folders the session needs that the workspace does not hold (D66): on a
177
- * handle just opened all of them, later only versions another session has not mounted. Calls
178
- * that need one folder at once share its mount. A failed outcome when one cannot be mounted;
179
- * the folder is not marked mounted then, so the next call tries again.
170
+ * Writes `files` (path in `folder` to `sha256:<hex>`) to `folder` of the session's sandbox,
171
+ * read-only, each one's bytes from `read`, in the session's queue (protocol 15: the harness
172
+ * decides which folders, and when). A folder the open handle already holds is `present` without
173
+ * an exec; calls that need one folder at once share its mount. A failed outcome when the sandbox
174
+ * cannot start or the folder cannot be written; it is not marked mounted then, so the next call
175
+ * tries again. A reopened handle holds none.
180
176
  */
181
- private mountSkills;
177
+ mountFolder(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, folder: string, files: FolderFiles, read: (sha256: string) => SandboxFileBytes | Promise<SandboxFileBytes>, signal: AbortSignal): Promise<{
178
+ kind: "mounted" | "present";
179
+ } | Extract<SandboxToolOutcome, {
180
+ kind: "failed";
181
+ }>>;
182
182
  private open;
183
183
  private stop;
184
184
  private record;