@aexhq/sdk 0.46.4-canary → 0.50.0

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 (337) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +38 -0
  3. package/README.md +23 -31
  4. package/dist/client/aex.d.ts +33 -0
  5. package/dist/client/aex.js +98 -0
  6. package/dist/client/aex.js.map +1 -0
  7. package/dist/client/credentials.d.ts +25 -0
  8. package/dist/client/credentials.js +97 -0
  9. package/dist/client/credentials.js.map +1 -0
  10. package/dist/client/routing.d.ts +7 -0
  11. package/dist/client/routing.js +29 -0
  12. package/dist/client/routing.js.map +1 -0
  13. package/dist/downloads/download.d.ts +25 -0
  14. package/dist/downloads/download.js +53 -0
  15. package/dist/downloads/download.js.map +1 -0
  16. package/dist/generated/errors.d.ts +12 -0
  17. package/dist/generated/errors.js +81 -0
  18. package/dist/generated/errors.js.map +1 -0
  19. package/dist/generated/resources.d.ts +730 -0
  20. package/dist/generated/resources.js +606 -0
  21. package/dist/generated/resources.js.map +1 -0
  22. package/dist/generated/routes.d.ts +42 -0
  23. package/dist/generated/routes.js +2101 -0
  24. package/dist/generated/routes.js.map +1 -0
  25. package/dist/index.d.ts +20 -50
  26. package/dist/index.js +11 -62
  27. package/dist/index.js.map +1 -1
  28. package/dist/observations/stream.d.ts +1 -0
  29. package/dist/observations/stream.js +18 -0
  30. package/dist/observations/stream.js.map +1 -0
  31. package/dist/transport/errors.d.ts +60 -0
  32. package/dist/transport/errors.js +107 -0
  33. package/dist/transport/errors.js.map +1 -0
  34. package/dist/transport/pagination.d.ts +8 -0
  35. package/dist/transport/pagination.js +34 -0
  36. package/dist/transport/pagination.js.map +1 -0
  37. package/dist/transport/retry.d.ts +21 -0
  38. package/dist/transport/retry.js +37 -0
  39. package/dist/transport/retry.js.map +1 -0
  40. package/dist/transport/transport.d.ts +25 -0
  41. package/dist/transport/transport.js +28 -0
  42. package/dist/transport/transport.js.map +1 -0
  43. package/package.json +63 -30
  44. package/dist/_contracts/account-operations.d.ts +0 -101
  45. package/dist/_contracts/account-operations.js +0 -242
  46. package/dist/_contracts/account-types.d.ts +0 -461
  47. package/dist/_contracts/account-types.js +0 -1
  48. package/dist/_contracts/api-key.d.ts +0 -61
  49. package/dist/_contracts/api-key.js +0 -101
  50. package/dist/_contracts/api-routes.d.ts +0 -20
  51. package/dist/_contracts/api-routes.js +0 -109
  52. package/dist/_contracts/archive-limits.d.ts +0 -3
  53. package/dist/_contracts/archive-limits.js +0 -23
  54. package/dist/_contracts/asset-authoring.d.ts +0 -22
  55. package/dist/_contracts/asset-authoring.js +0 -106
  56. package/dist/_contracts/asset-bundle.d.ts +0 -64
  57. package/dist/_contracts/asset-bundle.js +0 -263
  58. package/dist/_contracts/asset-upload-helper.d.ts +0 -31
  59. package/dist/_contracts/asset-upload-helper.js +0 -84
  60. package/dist/_contracts/billing-admission.d.ts +0 -29
  61. package/dist/_contracts/billing-admission.js +0 -28
  62. package/dist/_contracts/bundle-manifest.d.ts +0 -89
  63. package/dist/_contracts/bundle-manifest.js +0 -158
  64. package/dist/_contracts/canonical-sha256.d.ts +0 -8
  65. package/dist/_contracts/canonical-sha256.js +0 -8
  66. package/dist/_contracts/connection-ticket.d.ts +0 -22
  67. package/dist/_contracts/connection-ticket.js +0 -54
  68. package/dist/_contracts/continuation-event.d.ts +0 -31
  69. package/dist/_contracts/continuation-event.js +0 -6
  70. package/dist/_contracts/contract-parse-error.d.ts +0 -12
  71. package/dist/_contracts/contract-parse-error.js +0 -51
  72. package/dist/_contracts/error-codes.d.ts +0 -26
  73. package/dist/_contracts/error-codes.js +0 -116
  74. package/dist/_contracts/error-factory.d.ts +0 -32
  75. package/dist/_contracts/error-factory.js +0 -174
  76. package/dist/_contracts/event-envelope.d.ts +0 -471
  77. package/dist/_contracts/event-envelope.js +0 -501
  78. package/dist/_contracts/event-stream-client.d.ts +0 -122
  79. package/dist/_contracts/event-stream-client.js +0 -445
  80. package/dist/_contracts/event-view.d.ts +0 -44
  81. package/dist/_contracts/event-view.js +0 -69
  82. package/dist/_contracts/failure-class.d.ts +0 -29
  83. package/dist/_contracts/failure-class.js +0 -73
  84. package/dist/_contracts/http.d.ts +0 -135
  85. package/dist/_contracts/http.js +0 -434
  86. package/dist/_contracts/ids.d.ts +0 -66
  87. package/dist/_contracts/ids.js +0 -119
  88. package/dist/_contracts/index.d.ts +0 -42
  89. package/dist/_contracts/index.js +0 -52
  90. package/dist/_contracts/internal.d.ts +0 -55
  91. package/dist/_contracts/internal.js +0 -113
  92. package/dist/_contracts/models.d.ts +0 -30
  93. package/dist/_contracts/models.js +0 -28
  94. package/dist/_contracts/operation-core.d.ts +0 -36
  95. package/dist/_contracts/operation-core.js +0 -70
  96. package/dist/_contracts/operations.d.ts +0 -218
  97. package/dist/_contracts/operations.js +0 -1496
  98. package/dist/_contracts/otlp-projection.d.ts +0 -78
  99. package/dist/_contracts/otlp-projection.js +0 -171
  100. package/dist/_contracts/post-hook.d.ts +0 -31
  101. package/dist/_contracts/post-hook.js +0 -61
  102. package/dist/_contracts/provider-fault.d.ts +0 -34
  103. package/dist/_contracts/provider-fault.js +0 -68
  104. package/dist/_contracts/retry-core.d.ts +0 -29
  105. package/dist/_contracts/retry-core.js +0 -79
  106. package/dist/_contracts/runner-event.d.ts +0 -117
  107. package/dist/_contracts/runner-event.js +0 -172
  108. package/dist/_contracts/runtime-kind.d.ts +0 -60
  109. package/dist/_contracts/runtime-kind.js +0 -70
  110. package/dist/_contracts/runtime-manifest.d.ts +0 -121
  111. package/dist/_contracts/runtime-manifest.js +0 -83
  112. package/dist/_contracts/runtime-security-profile.d.ts +0 -26
  113. package/dist/_contracts/runtime-security-profile.js +0 -73
  114. package/dist/_contracts/runtime-sizes.d.ts +0 -104
  115. package/dist/_contracts/runtime-sizes.js +0 -111
  116. package/dist/_contracts/runtime-types.d.ts +0 -618
  117. package/dist/_contracts/runtime-types.js +0 -58
  118. package/dist/_contracts/schemas/asset-bundle.d.ts +0 -70
  119. package/dist/_contracts/schemas/asset-bundle.js +0 -107
  120. package/dist/_contracts/schemas/asset-ref.d.ts +0 -61
  121. package/dist/_contracts/schemas/asset-ref.js +0 -118
  122. package/dist/_contracts/schemas/bundle-manifest.d.ts +0 -66
  123. package/dist/_contracts/schemas/bundle-manifest.js +0 -77
  124. package/dist/_contracts/schemas/index.d.ts +0 -32
  125. package/dist/_contracts/schemas/index.js +0 -30
  126. package/dist/_contracts/schemas/mcp-server.d.ts +0 -99
  127. package/dist/_contracts/schemas/mcp-server.js +0 -209
  128. package/dist/_contracts/schemas/models.d.ts +0 -29
  129. package/dist/_contracts/schemas/models.js +0 -51
  130. package/dist/_contracts/schemas/numeric.d.ts +0 -18
  131. package/dist/_contracts/schemas/numeric.js +0 -28
  132. package/dist/_contracts/schemas/post-hook.d.ts +0 -45
  133. package/dist/_contracts/schemas/post-hook.js +0 -68
  134. package/dist/_contracts/schemas/response-assets.d.ts +0 -75
  135. package/dist/_contracts/schemas/response-assets.js +0 -81
  136. package/dist/_contracts/schemas/response-billing.d.ts +0 -208
  137. package/dist/_contracts/schemas/response-billing.js +0 -139
  138. package/dist/_contracts/schemas/response-common.d.ts +0 -132
  139. package/dist/_contracts/schemas/response-common.js +0 -162
  140. package/dist/_contracts/schemas/response-identity.d.ts +0 -648
  141. package/dist/_contracts/schemas/response-identity.js +0 -131
  142. package/dist/_contracts/schemas/response-mcp-servers.d.ts +0 -51
  143. package/dist/_contracts/schemas/response-mcp-servers.js +0 -32
  144. package/dist/_contracts/schemas/response-secrets.d.ts +0 -50
  145. package/dist/_contracts/schemas/response-secrets.js +0 -32
  146. package/dist/_contracts/schemas/response-sessions-internal.d.ts +0 -200
  147. package/dist/_contracts/schemas/response-sessions-internal.js +0 -142
  148. package/dist/_contracts/schemas/response-sessions.d.ts +0 -1598
  149. package/dist/_contracts/schemas/response-sessions.js +0 -377
  150. package/dist/_contracts/schemas/response-webhooks.d.ts +0 -76
  151. package/dist/_contracts/schemas/response-webhooks.js +0 -42
  152. package/dist/_contracts/schemas/response-workspace.d.ts +0 -225
  153. package/dist/_contracts/schemas/response-workspace.js +0 -99
  154. package/dist/_contracts/schemas/runtime-kind.d.ts +0 -31
  155. package/dist/_contracts/schemas/runtime-kind.js +0 -29
  156. package/dist/_contracts/schemas/runtime-security-profile.d.ts +0 -28
  157. package/dist/_contracts/schemas/runtime-security-profile.js +0 -26
  158. package/dist/_contracts/schemas/runtime-sizes.d.ts +0 -70
  159. package/dist/_contracts/schemas/runtime-sizes.js +0 -127
  160. package/dist/_contracts/schemas/session-limits.d.ts +0 -34
  161. package/dist/_contracts/schemas/session-limits.js +0 -39
  162. package/dist/_contracts/schemas/session-machine.d.ts +0 -23
  163. package/dist/_contracts/schemas/session-machine.js +0 -24
  164. package/dist/_contracts/schemas/session-request-config.d.ts +0 -58
  165. package/dist/_contracts/schemas/session-request-config.js +0 -134
  166. package/dist/_contracts/schemas/session-webhook.d.ts +0 -11
  167. package/dist/_contracts/schemas/session-webhook.js +0 -38
  168. package/dist/_contracts/schemas/side-effect-audit.d.ts +0 -98
  169. package/dist/_contracts/schemas/side-effect-audit.js +0 -102
  170. package/dist/_contracts/schemas/submission-assets.d.ts +0 -117
  171. package/dist/_contracts/schemas/submission-assets.js +0 -147
  172. package/dist/_contracts/schemas/submission-body.d.ts +0 -251
  173. package/dist/_contracts/schemas/submission-body.js +0 -378
  174. package/dist/_contracts/schemas/submission-environment.d.ts +0 -79
  175. package/dist/_contracts/schemas/submission-environment.js +0 -179
  176. package/dist/_contracts/schemas/submission-request.d.ts +0 -158
  177. package/dist/_contracts/schemas/submission-request.js +0 -49
  178. package/dist/_contracts/schemas/submission-secrets.d.ts +0 -47
  179. package/dist/_contracts/schemas/submission-secrets.js +0 -108
  180. package/dist/_contracts/schemas/wire.d.ts +0 -118
  181. package/dist/_contracts/schemas/wire.js +0 -171
  182. package/dist/_contracts/schemas/workspace-resources.d.ts +0 -50
  183. package/dist/_contracts/schemas/workspace-resources.js +0 -87
  184. package/dist/_contracts/sdk-errors.d.ts +0 -212
  185. package/dist/_contracts/sdk-errors.js +0 -313
  186. package/dist/_contracts/sdk-secrets.d.ts +0 -67
  187. package/dist/_contracts/sdk-secrets.js +0 -427
  188. package/dist/_contracts/session-archive.d.ts +0 -16
  189. package/dist/_contracts/session-archive.js +0 -92
  190. package/dist/_contracts/session-artifacts.d.ts +0 -189
  191. package/dist/_contracts/session-artifacts.js +0 -264
  192. package/dist/_contracts/session-config.d.ts +0 -373
  193. package/dist/_contracts/session-config.js +0 -562
  194. package/dist/_contracts/session-cost-types.d.ts +0 -211
  195. package/dist/_contracts/session-cost-types.js +0 -69
  196. package/dist/_contracts/session-cost.d.ts +0 -8
  197. package/dist/_contracts/session-cost.js +0 -582
  198. package/dist/_contracts/session-custody.d.ts +0 -165
  199. package/dist/_contracts/session-custody.js +0 -345
  200. package/dist/_contracts/session-file-query.d.ts +0 -14
  201. package/dist/_contracts/session-file-query.js +0 -178
  202. package/dist/_contracts/session-record.d.ts +0 -112
  203. package/dist/_contracts/session-record.js +0 -165
  204. package/dist/_contracts/session-retention.d.ts +0 -201
  205. package/dist/_contracts/session-retention.js +0 -450
  206. package/dist/_contracts/side-effect-audit.d.ts +0 -126
  207. package/dist/_contracts/side-effect-audit.js +0 -520
  208. package/dist/_contracts/sse.d.ts +0 -74
  209. package/dist/_contracts/sse.js +0 -227
  210. package/dist/_contracts/stable.d.ts +0 -45
  211. package/dist/_contracts/stable.js +0 -62
  212. package/dist/_contracts/status.d.ts +0 -25
  213. package/dist/_contracts/status.js +0 -57
  214. package/dist/_contracts/submission-limits.d.ts +0 -61
  215. package/dist/_contracts/submission-limits.js +0 -60
  216. package/dist/_contracts/submission.d.ts +0 -547
  217. package/dist/_contracts/submission.js +0 -812
  218. package/dist/_contracts/suggest.d.ts +0 -15
  219. package/dist/_contracts/suggest.js +0 -53
  220. package/dist/_contracts/testing/response-bindings.d.ts +0 -45
  221. package/dist/_contracts/testing/response-bindings.js +0 -256
  222. package/dist/_contracts/testing/wire-conformance-entry.d.ts +0 -10
  223. package/dist/_contracts/testing/wire-conformance-entry.js +0 -8
  224. package/dist/_contracts/testing/wire-conformance.d.ts +0 -169
  225. package/dist/_contracts/testing/wire-conformance.js +0 -276
  226. package/dist/_contracts/turn-trace.d.ts +0 -28
  227. package/dist/_contracts/turn-trace.js +0 -1
  228. package/dist/_contracts/unknown-field-error.d.ts +0 -13
  229. package/dist/_contracts/unknown-field-error.js +0 -21
  230. package/dist/_contracts/value-guards.d.ts +0 -20
  231. package/dist/_contracts/value-guards.js +0 -34
  232. package/dist/_contracts/webhook-verify.d.ts +0 -34
  233. package/dist/_contracts/webhook-verify.js +0 -93
  234. package/dist/_contracts/wire-observer.d.ts +0 -49
  235. package/dist/_contracts/wire-observer.js +0 -34
  236. package/dist/_contracts/workflow-status.d.ts +0 -7
  237. package/dist/_contracts/workflow-status.js +0 -43
  238. package/dist/_contracts/workspace-resources.d.ts +0 -98
  239. package/dist/_contracts/workspace-resources.js +0 -39
  240. package/dist/archive-limits.d.ts +0 -1
  241. package/dist/archive-limits.js +0 -2
  242. package/dist/archive-limits.js.map +0 -1
  243. package/dist/asset-upload.d.ts +0 -47
  244. package/dist/asset-upload.js +0 -269
  245. package/dist/asset-upload.js.map +0 -1
  246. package/dist/bundle.d.ts +0 -9
  247. package/dist/bundle.js +0 -20
  248. package/dist/bundle.js.map +0 -1
  249. package/dist/canonical-zip.d.ts +0 -68
  250. package/dist/canonical-zip.js +0 -355
  251. package/dist/canonical-zip.js.map +0 -1
  252. package/dist/cli.mjs +0 -12048
  253. package/dist/cli.mjs.sha256 +0 -1
  254. package/dist/client-types.d.ts +0 -192
  255. package/dist/client-types.js +0 -2
  256. package/dist/client-types.js.map +0 -1
  257. package/dist/client.d.ts +0 -464
  258. package/dist/client.js +0 -1207
  259. package/dist/client.js.map +0 -1
  260. package/dist/event-projection.d.ts +0 -22
  261. package/dist/event-projection.js +0 -380
  262. package/dist/event-projection.js.map +0 -1
  263. package/dist/fetch-archive.d.ts +0 -16
  264. package/dist/fetch-archive.js +0 -252
  265. package/dist/fetch-archive.js.map +0 -1
  266. package/dist/file.d.ts +0 -96
  267. package/dist/file.js +0 -272
  268. package/dist/file.js.map +0 -1
  269. package/dist/instructions.d.ts +0 -20
  270. package/dist/instructions.js +0 -40
  271. package/dist/instructions.js.map +0 -1
  272. package/dist/legacy-session-provider-fault.d.ts +0 -7
  273. package/dist/legacy-session-provider-fault.js +0 -38
  274. package/dist/legacy-session-provider-fault.js.map +0 -1
  275. package/dist/mcp-server.d.ts +0 -84
  276. package/dist/mcp-server.js +0 -117
  277. package/dist/mcp-server.js.map +0 -1
  278. package/dist/node-fs.d.ts +0 -29
  279. package/dist/node-fs.js +0 -19
  280. package/dist/node-fs.js.map +0 -1
  281. package/dist/node-walk.d.ts +0 -69
  282. package/dist/node-walk.js +0 -151
  283. package/dist/node-walk.js.map +0 -1
  284. package/dist/path-basename.d.ts +0 -5
  285. package/dist/path-basename.js +0 -9
  286. package/dist/path-basename.js.map +0 -1
  287. package/dist/retry.d.ts +0 -70
  288. package/dist/retry.js +0 -155
  289. package/dist/retry.js.map +0 -1
  290. package/dist/secret.d.ts +0 -65
  291. package/dist/secret.js +0 -110
  292. package/dist/secret.js.map +0 -1
  293. package/dist/session-validate.d.ts +0 -100
  294. package/dist/session-validate.js +0 -303
  295. package/dist/session-validate.js.map +0 -1
  296. package/dist/skill.d.ts +0 -99
  297. package/dist/skill.js +0 -169
  298. package/dist/skill.js.map +0 -1
  299. package/dist/submission-wire.d.ts +0 -13
  300. package/dist/submission-wire.js +0 -69
  301. package/dist/submission-wire.js.map +0 -1
  302. package/dist/tool.d.ts +0 -41
  303. package/dist/tool.js +0 -76
  304. package/dist/tool.js.map +0 -1
  305. package/dist/version.d.ts +0 -9
  306. package/dist/version.js +0 -10
  307. package/dist/version.js.map +0 -1
  308. package/docs/authentication.md +0 -125
  309. package/docs/billing.md +0 -164
  310. package/docs/cleanup.md +0 -27
  311. package/docs/concepts/agent-tools.md +0 -47
  312. package/docs/concepts/composition.md +0 -60
  313. package/docs/concepts/providers-and-runtimes.md +0 -121
  314. package/docs/concepts/sessions.md +0 -51
  315. package/docs/concepts/subagents.md +0 -35
  316. package/docs/credentials.md +0 -116
  317. package/docs/defaults.md +0 -51
  318. package/docs/errors.md +0 -258
  319. package/docs/events.md +0 -143
  320. package/docs/files.md +0 -130
  321. package/docs/limits-and-quotas.md +0 -114
  322. package/docs/limits.md +0 -51
  323. package/docs/mcp.md +0 -47
  324. package/docs/networking.md +0 -114
  325. package/docs/provider-runtime-capabilities.md +0 -32
  326. package/docs/public-surface.json +0 -73
  327. package/docs/quickstart.md +0 -135
  328. package/docs/release.md +0 -44
  329. package/docs/retries.md +0 -108
  330. package/docs/secrets.md +0 -141
  331. package/docs/session-config.md +0 -51
  332. package/docs/session-record.md +0 -58
  333. package/docs/skills.md +0 -65
  334. package/docs/telemetry.md +0 -66
  335. package/docs/testing.md +0 -35
  336. package/docs/vision-skills.md +0 -94
  337. package/docs/webhooks.md +0 -143
@@ -1,378 +0,0 @@
1
- /**
2
- * Schemas for the submission BRIEF — `request.submission` — and for the inline
3
- * policy objects that hang directly off it: platform injection, file capture,
4
- * response format and the HITL approval gate.
5
- *
6
- * Declaration order is the permitted-key order reported on an unknown field, and
7
- * `test/allowed-keys-parser-golden.test.ts` pins every sentence below
8
- * byte-for-byte — including the three different wordings, which are historical
9
- * and deliberately not normalised toward each other.
10
- *
11
- * **What stays in `submission.ts`** (D4/L1): every transform and every
12
- * cross-field rule. Splitting `"pip:pandas"`, decoding a duration, collapsing an
13
- * empty object to `undefined`, canonicalising a capture path, deduplicating a
14
- * tool list, reconciling `secretEnv` against `secrets.envSecrets` — none of
15
- * those are shapes, and a `.transform()` here would make the response half of
16
- * the generated spec ungenerable. Rule sets whose ORDER decides which message
17
- * fires (`prompt`, `secretEnv`, the capture-path ladders) are single
18
- * `z.check()`s for the reason `submission-environment.ts` documents: composed
19
- * schemas report in Zod's order, not the ladder's.
20
- */
21
- import * as z from "zod/mini";
22
- import { isJsonValue, isRecord } from "../value-guards.js";
23
- import { SECRET_ENV_NAME_PATTERN, SECRET_HANDLE_PATTERN } from "../submission-limits.js";
24
- import { modelSlugSchema } from "./models.js";
25
- import { RuntimeSecurityProfileSchema } from "./runtime-security-profile.js";
26
- import { SubmissionAssetsSchema } from "./submission-assets.js";
27
- import { EnvironmentSchema } from "./submission-environment.js";
28
- import { lastSegment, nonEmptyString, wireObject } from "./wire.js";
29
- const SUBMISSION = "submission";
30
- const PROMPT = `${SUBMISSION}.prompt`;
31
- const MCP_SERVERS = `${SUBMISSION}.mcpServers`;
32
- const SECRET_ENV = `${SUBMISSION}.secretEnv`;
33
- const METADATA = `${SUBMISSION}.metadata`;
34
- const BUILTIN_TOOLS = `${SUBMISSION}.builtinTools`;
35
- const PLATFORM = `${SUBMISSION}.platform`;
36
- const FILE_CAPTURE = `${SUBMISSION}.fileCapture`;
37
- const RESPONSE_FORMAT = `${SUBMISSION}.responseFormat`;
38
- const APPROVAL_GATE = `${SUBMISSION}.approvalGate`;
39
- /** Assistant-output granularity values. Buffered is the platform default. */
40
- export const OUTPUT_MODES = ["buffered", "stream"];
41
- /** Response-format kinds: free-form `text` (default) or provider-native `json_schema`. */
42
- export const RESPONSE_FORMAT_KINDS = ["text", "json_schema"];
43
- /**
44
- * Maximum number of file capture entries accepted per list.
45
- *
46
- * 32 is enough room for the typical "one or two capture roots" pattern plus a
47
- * generous margin for legitimate multi-root use cases (per-tool file directory +
48
- * scratch state + logs, repeated across a few subdirectories), without inviting
49
- * abuse of the synthetic-turn path the platform capture path drives at session
50
- * terminal.
51
- */
52
- export const MAX_FILE_CAPTURE_DIRS = 32;
53
- /**
54
- * Maximum byte length of a single file capture entry (after UTF-8 encoding).
55
- * 512 bytes comfortably covers `/very/long/nested/path` style entries without
56
- * letting a misuse smuggle large blobs through the field.
57
- */
58
- export const MAX_FILE_CAPTURE_DIR_BYTES = 512;
59
- function rejector(payload) {
60
- return (message) => {
61
- payload.issues.push({ code: "custom", message, input: payload.value });
62
- };
63
- }
64
- // ---------------------------------------------------------------------------
65
- // prompt
66
- // ---------------------------------------------------------------------------
67
- /**
68
- * The prompt as a single string or an ordered list of parts.
69
- *
70
- * The union admits ANY array rather than an array of strings, and the per-entry
71
- * rules ride the ladder below, because a union reports its own failure — the
72
- * caller would learn "must be a string or an array of strings" for
73
- * `["ok", 7]` instead of which entry is wrong. The ladder is the parser's own
74
- * order: length, then each entry, then the all-whitespace check that only makes
75
- * sense once every entry is a string.
76
- */
77
- export const PromptSchema = z
78
- .union([z.string(), z.array(z.unknown())], {
79
- error: `${PROMPT} must be a string or an array of strings`
80
- })
81
- .check(z.check((payload) => {
82
- const reject = rejector(payload);
83
- const value = payload.value;
84
- if (typeof value === "string") {
85
- if (value.length === 0) {
86
- reject(`${PROMPT} must be non-empty`);
87
- }
88
- else if (value.trim().length === 0) {
89
- reject(`${PROMPT} must contain non-whitespace text`);
90
- }
91
- return;
92
- }
93
- const parts = value;
94
- if (parts.length === 0) {
95
- reject(`${PROMPT} array must be non-empty`);
96
- return;
97
- }
98
- for (const [index, part] of parts.entries()) {
99
- if (typeof part !== "string" || part.length === 0) {
100
- reject(`${PROMPT}[${index}] must be a non-empty string`);
101
- return;
102
- }
103
- }
104
- if (parts.every((part) => part.trim().length === 0)) {
105
- reject(`${PROMPT} must contain non-whitespace text`);
106
- }
107
- }))
108
- .register(z.globalRegistry, {
109
- id: "SubmissionPrompt",
110
- description: "The run brief: one string, or an ordered list of non-empty parts. At least one part must " +
111
- "carry non-whitespace text. A single string is normalised to a one-element list."
112
- });
113
- // ---------------------------------------------------------------------------
114
- // mcpServers
115
- // ---------------------------------------------------------------------------
116
- /**
117
- * The non-secret half of the MCP server declarations.
118
- *
119
- * Deliberately an array of unvalidated entries: the per-entry rules
120
- * (`mcpServerRefSchema`) need the SSRF host deny-list and the transport parser,
121
- * which `schemas/mcp-server.ts` takes as an injected `McpWirePolicy` because
122
- * they must stay inside `session-config.ts` for the cross-repo parity check —
123
- * and `session-config.ts` imports `submission.ts`, so this module cannot reach
124
- * them without a cycle. `parseMcpServers` applies them one entry at a time.
125
- */
126
- export const McpServerRefsSchema = z
127
- .array(z.unknown(), { error: `${MCP_SERVERS} must be an array of {name, url} objects` })
128
- .register(z.globalRegistry, {
129
- id: "SubmissionMcpServers",
130
- description: "Remote MCP servers, each `{ name, url, transport? }`. Names must be unique and every URL " +
131
- "must clear the SSRF host deny-list — enforced in packages/contracts/src/session-config.ts."
132
- });
133
- // ---------------------------------------------------------------------------
134
- // secretEnv
135
- // ---------------------------------------------------------------------------
136
- /**
137
- * Value-free env-var secret bindings, keyed by env name.
138
- *
139
- * One ordered `z.check()` rather than a record of a union, for the reason
140
- * `EnvSecretsSchema` documents: each rung has its own message and the key rule
141
- * must beat the value rule, which a composed schema cannot promise.
142
- */
143
- export const SecretEnvSchema = z
144
- .record(z.string(), z.unknown(), { error: `${SECRET_ENV} must be an object` })
145
- .check(z.check((payload) => {
146
- const reject = rejector(payload);
147
- for (const [envName, entry] of Object.entries(payload.value)) {
148
- if (!SECRET_ENV_NAME_PATTERN.test(envName)) {
149
- reject(`${SECRET_ENV} key "${envName}" must be a valid env var name matching ${SECRET_ENV_NAME_PATTERN.source}`);
150
- return;
151
- }
152
- const path = `${SECRET_ENV}.${envName}`;
153
- if (!isRecord(entry)) {
154
- reject(`${path} must be an object`);
155
- return;
156
- }
157
- const keys = Object.keys(entry);
158
- if (keys.length !== 1 || (!("ref" in entry) && !("ephemeral" in entry))) {
159
- reject(`${path} must be exactly one of { ref } or { ephemeral: true }`);
160
- return;
161
- }
162
- if ("ref" in entry) {
163
- const handle = entry.ref;
164
- if (typeof handle !== "string" || handle.length === 0) {
165
- reject(`${path}.ref must be a non-empty string`);
166
- return;
167
- }
168
- if (!SECRET_HANDLE_PATTERN.test(handle)) {
169
- reject(`${path}.ref handle must match ${SECRET_HANDLE_PATTERN.source}`);
170
- return;
171
- }
172
- }
173
- else if (entry.ephemeral !== true) {
174
- reject(`${path}.ephemeral must be the literal true`);
175
- return;
176
- }
177
- }
178
- }))
179
- .register(z.globalRegistry, {
180
- id: "SubmissionSecretEnv",
181
- description: "Env-var secret bindings keyed by env name. Each value is exactly one of `{ ref }` (a " +
182
- `workspace secret handle matching ${SECRET_HANDLE_PATTERN.source}) or ` +
183
- "`{ ephemeral: true }` (the value rides in `secrets.envSecrets`). Enforced in " +
184
- "packages/contracts/src/schemas/submission-body.ts."
185
- });
186
- // ---------------------------------------------------------------------------
187
- // metadata
188
- // ---------------------------------------------------------------------------
189
- /** Caller-owned metadata: any JSON-serializable value per key. */
190
- export const MetadataSchema = z.record(z.string(), z.unknown().check(z.refine(isJsonValue, {
191
- error: (issue) => `${METADATA}.${lastSegment(issue.path)} must be JSON-serializable`,
192
- abort: true
193
- })), { error: `${METADATA} must be an object` });
194
- // ---------------------------------------------------------------------------
195
- // builtinTools
196
- // ---------------------------------------------------------------------------
197
- /**
198
- * The builtin-capability selection.
199
- *
200
- * The array branch admits any entry: the closed name set lives on
201
- * `submission.ts` (`BUILTIN_TOOL_NAMES`, pinned equal to the platform's
202
- * `HANDS_TOOLS`), which imports this module, and `resolveBuiltinToolNames` both
203
- * validates membership and re-orders the result — a transform either way.
204
- */
205
- export const BuiltinToolsSchema = z.union([z.literal("default"), z.literal("none"), z.array(z.unknown())], { error: `${BUILTIN_TOOLS} must be 'default', 'none', or an array of builtin tool names` });
206
- // ---------------------------------------------------------------------------
207
- // outputMode
208
- // ---------------------------------------------------------------------------
209
- /** Assistant-output granularity. */
210
- export const OutputModeSchema = z.enum(OUTPUT_MODES, {
211
- error: `${SUBMISSION}.outputMode must be one of ${OUTPUT_MODES.join(", ")}`
212
- });
213
- // ---------------------------------------------------------------------------
214
- // fileCapture
215
- // ---------------------------------------------------------------------------
216
- function utf8Bytes(value) {
217
- return new TextEncoder().encode(value).length;
218
- }
219
- /**
220
- * The shared entry rules for a capture list, in the order the parser applied
221
- * them: the list bound first, then each entry top to bottom. One ladder rather
222
- * than a composed array schema because the bound must outrank an entry
223
- * complaint, and every rung words itself differently.
224
- */
225
- function captureDirs(field, emptyEntry, notArray) {
226
- const path = `${FILE_CAPTURE}.${field}`;
227
- return z.array(z.unknown(), { error: notArray }).check(z.check((payload) => {
228
- const reject = rejector(payload);
229
- const entries = payload.value;
230
- if (entries.length > MAX_FILE_CAPTURE_DIRS) {
231
- reject(`${path} has ${entries.length} entries; max is ${MAX_FILE_CAPTURE_DIRS}`);
232
- return;
233
- }
234
- for (const [index, entry] of entries.entries()) {
235
- const at = `${path}[${index}]`;
236
- if (typeof entry !== "string") {
237
- reject(`${at} must be a string`);
238
- return;
239
- }
240
- if (entry.length === 0) {
241
- reject(`${at} ${emptyEntry}`);
242
- return;
243
- }
244
- const bytes = utf8Bytes(entry);
245
- if (bytes > MAX_FILE_CAPTURE_DIR_BYTES) {
246
- reject(`${at} exceeds ${MAX_FILE_CAPTURE_DIR_BYTES} bytes (got ${bytes})`);
247
- return;
248
- }
249
- if (field === "allowedDirs" && !entry.startsWith("/")) {
250
- reject(`${at} must be an absolute UNIX path (start with '/')`);
251
- return;
252
- }
253
- if (entry.includes("\0")) {
254
- reject(`${at} must not contain NUL bytes`);
255
- return;
256
- }
257
- if (entry.includes("\n") || entry.includes("\r")) {
258
- reject(`${at} must not contain newline characters`);
259
- return;
260
- }
261
- if (entry.split("/").includes("..")) {
262
- reject(`${at} must not contain '..' segments`);
263
- return;
264
- }
265
- }
266
- }));
267
- }
268
- /** A positive integer capture bound. Clamping to the platform maximum is the parser's. */
269
- function captureInteger(field) {
270
- const message = `${FILE_CAPTURE}.${field} must be a positive integer`;
271
- return z
272
- .number({ error: message })
273
- .check(z.refine((value) => Number.isInteger(value) && value > 0, {
274
- error: message,
275
- abort: true
276
- }));
277
- }
278
- /** `submission.fileCapture` — the post-run capture policy. */
279
- export const FileCaptureSchema = wireObject(FILE_CAPTURE, {
280
- allowedDirs: z.optional(captureDirs("allowedDirs", "must be a non-empty absolute UNIX path", `${FILE_CAPTURE}.allowedDirs must be an array of absolute UNIX paths`)),
281
- deniedDirs: z.optional(captureDirs("deniedDirs", "must be a non-empty pattern", `${FILE_CAPTURE}.deniedDirs must be an array of strings`)),
282
- captureTimeoutMs: z.optional(captureInteger("captureTimeoutMs")),
283
- maxFileBytes: z.optional(captureInteger("maxFileBytes")),
284
- maxTotalBytes: z.optional(captureInteger("maxTotalBytes")),
285
- maxFiles: z.optional(captureInteger("maxFiles"))
286
- }).register(z.globalRegistry, {
287
- id: "SubmissionFileCapture",
288
- description: "Post-run file capture policy. Entries are bounded to " +
289
- `${MAX_FILE_CAPTURE_DIRS} per list and ${MAX_FILE_CAPTURE_DIR_BYTES} bytes each; allowed ` +
290
- "roots are absolute UNIX paths and neither list may contain '..' segments. Paths are " +
291
- "canonicalised and deduplicated after parsing, and `captureTimeoutMs` is clamped to the " +
292
- "platform maximum. Enforced in packages/contracts/src/schemas/submission-body.ts."
293
- });
294
- // ---------------------------------------------------------------------------
295
- // responseFormat
296
- // ---------------------------------------------------------------------------
297
- /**
298
- * `submission.responseFormat` when `kind` is `"text"` — a free-form response
299
- * admits no other field, and says so in its own words rather than listing a
300
- * permitted set of one.
301
- */
302
- export const ResponseFormatTextSchema = wireObject(RESPONSE_FORMAT, { kind: z.literal("text") }, { unknownKey: (path, key) => `${path}.${key} is not allowed when kind is 'text'` });
303
- const RESPONSE_FORMAT_SCHEMA_FIELD = `${RESPONSE_FORMAT}.schema must be a JSON-serializable object`;
304
- /** `submission.responseFormat` when `kind` is `"json_schema"`. */
305
- export const ResponseFormatJsonSchemaSchema = wireObject(RESPONSE_FORMAT, {
306
- kind: z.literal("json_schema"),
307
- schema: z
308
- .record(z.string(), z.unknown(), { error: RESPONSE_FORMAT_SCHEMA_FIELD })
309
- .check(z.refine(isJsonValue, { error: RESPONSE_FORMAT_SCHEMA_FIELD, abort: true })),
310
- strict: z.optional(z.boolean({ error: `${RESPONSE_FORMAT}.strict must be a boolean` })),
311
- name: z.optional(nonEmptyString(`${RESPONSE_FORMAT}.name`))
312
- });
313
- /**
314
- * The structured-output policy, selected by `kind`.
315
- *
316
- * A DISCRIMINATED union rather than a plain one: `kind` picks the variant before
317
- * either member runs, so a bad `kind` outranks an unknown key and each variant
318
- * words its own rejection — which is exactly the two-stage sequencing the
319
- * hand-written parser had. A plain `z.union` would report its own failure for
320
- * both cases and lose the distinction.
321
- *
322
- * The union's own message therefore covers only what routing itself can fail on:
323
- * a non-object, or an object whose `kind` names no variant.
324
- */
325
- export const ResponseFormatSchema = z.discriminatedUnion("kind", [ResponseFormatTextSchema, ResponseFormatJsonSchemaSchema], {
326
- error: (issue) => isRecord(issue.input)
327
- ? `${RESPONSE_FORMAT}.kind must be one of ${RESPONSE_FORMAT_KINDS.join(", ")}`
328
- : `${RESPONSE_FORMAT} must be an object`
329
- });
330
- // ---------------------------------------------------------------------------
331
- // approvalGate + platform
332
- // ---------------------------------------------------------------------------
333
- const approvalTool = (() => {
334
- const message = (issue) => `${APPROVAL_GATE}.tools[${lastSegment(issue.path)}] must be a non-empty string`;
335
- return z.string({ error: message }).check(z.minLength(1, { error: message, abort: true }));
336
- })();
337
- /** `submission.approvalGate` — the declarative HITL write-gate. */
338
- export const ApprovalGateSchema = wireObject(APPROVAL_GATE, {
339
- tools: z.array(approvalTool, { error: `${APPROVAL_GATE}.tools must be an array of tool names` })
340
- });
341
- /** `submission.platform` — platform-injection controls. */
342
- export const PlatformInjectionSchema = wireObject(PLATFORM, {
343
- systemPrompt: z.optional(z.enum(["default", "off"], {
344
- error: `${PLATFORM}.systemPrompt must be "default" or "off"`
345
- }))
346
- });
347
- // ---------------------------------------------------------------------------
348
- // the brief
349
- // ---------------------------------------------------------------------------
350
- /**
351
- * Wire shape of the submission brief.
352
- *
353
- * The two diagnostics report under DIFFERENT paths and always have: an unknown
354
- * key is `submission.<key> …` (the brief's fields are the caller's
355
- * `submission.*` fields), while a non-object brief is `submission.submission …`
356
- * (the brief's own position inside the request envelope). Both are pinned.
357
- *
358
- * `null` is admitted wherever the parser treated it as "unset" — that
359
- * back-compat is the parser's, and the schema states it rather than letting a
360
- * null reach a normaliser that would have to re-check it.
361
- */
362
- export const SubmissionSchema = wireObject(SUBMISSION, {
363
- model: modelSlugSchema(`${SUBMISSION}.model`),
364
- system: z.optional(nonEmptyString(`${SUBMISSION}.system`)),
365
- prompt: PromptSchema,
366
- assets: SubmissionAssetsSchema,
367
- mcpServers: z.optional(McpServerRefsSchema),
368
- secretEnv: z.optional(z.nullable(SecretEnvSchema)),
369
- environment: z.optional(EnvironmentSchema),
370
- securityProfile: z.optional(z.nullable(RuntimeSecurityProfileSchema)),
371
- metadata: z.optional(MetadataSchema),
372
- fileCapture: z.optional(z.nullable(FileCaptureSchema)),
373
- builtinTools: z.optional(z.nullable(BuiltinToolsSchema)),
374
- outputMode: z.optional(z.nullable(OutputModeSchema)),
375
- responseFormat: z.optional(z.nullable(ResponseFormatSchema)),
376
- approvalGate: z.optional(z.nullable(ApprovalGateSchema)),
377
- platform: z.optional(z.nullable(PlatformInjectionSchema))
378
- }, { notObject: () => `${SUBMISSION}.submission must be an object` });
@@ -1,79 +0,0 @@
1
- /**
2
- * Schemas for `submission.environment` — the customer-controlled runtime
3
- * environment: egress policy, OS/language packages, and plain env vars.
4
- *
5
- * Two behaviours here are deliberately NOT in the schemas, per D4/L1:
6
- *
7
- * - **Ecosystem-prefix splitting** (`"pip:pandas"` -> `{name:"pandas",
8
- * ecosystem:"pip"}`) is a transform, so it lives in
9
- * {@link normalizePlatformPackage}. A `.transform()` would make the response
10
- * half of the generated spec ungenerable.
11
- * - **Host lower-casing** lives in {@link normalizeAllowedHosts} for the same
12
- * reason.
13
- */
14
- import * as z from "zod/mini";
15
- /**
16
- * `envVars` as a bounded map of shell-portable names to UTF-8 values.
17
- *
18
- * The whole rule set is one ordered `z.check()` rather than a composition of
19
- * record key/value schemas, because the ladder is order-sensitive and every rung
20
- * has its own message: a key that is both malformed AND non-string must report
21
- * the malformed key, and the byte budget must fail on the entry that crosses
22
- * `ENV_VARS_MAX_TOTAL_BYTES` — not on the map as a whole. Composed schemas
23
- * report in Zod's order, not this one.
24
- *
25
- * The cost is that these rules are invisible in the generated OpenAPI document
26
- * (L2), so the description below is what a spec consumer sees. A weaker-but-true
27
- * schema beats a precise-but-wrong one.
28
- */
29
- export declare const EnvVarsSchema: z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnknown>;
30
- export declare const AllowedHostsSchema: z.ZodMiniArray<z.ZodMiniString<string>>;
31
- /** Lower-case every host so the deny/allow comparison downstream is case-insensitive. */
32
- export declare function normalizeAllowedHosts(hosts: readonly string[]): readonly string[];
33
- export declare const NetworkingSchema: z.ZodMiniObject<{
34
- mode: z.ZodMiniOptional<z.ZodMiniEnum<{
35
- limited: "limited";
36
- open: "open";
37
- }>>;
38
- allowedHosts: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
39
- }, z.core.$strict>;
40
- export declare const PlatformPackageSchema: z.ZodMiniObject<{
41
- name: z.ZodMiniString<string>;
42
- version: z.ZodMiniOptional<z.ZodMiniString<string>>;
43
- }, z.core.$strict>;
44
- export declare const PackagesSchema: z.ZodMiniArray<z.ZodMiniObject<{
45
- name: z.ZodMiniString<string>;
46
- version: z.ZodMiniOptional<z.ZodMiniString<string>>;
47
- }, z.core.$strict>>;
48
- /**
49
- * Split the `"<ecosystem>:<name>"` prefix a caller encodes into `name`.
50
- *
51
- * An unprefixed name defaults to `apt`. A colon-delimited prefix that is not a
52
- * known ecosystem is rejected rather than folded into the package name, so a
53
- * typo'd manager fails closed instead of installing something unexpected.
54
- *
55
- * Throws rather than returning a result because it runs inside the parser's
56
- * existing `withContractParseError` boundary, which brands whatever it throws.
57
- */
58
- export declare function normalizePlatformPackage(pkg: {
59
- readonly name: string;
60
- readonly version?: string | undefined;
61
- }, path: string): {
62
- readonly name: string;
63
- readonly version?: string;
64
- readonly ecosystem: string;
65
- };
66
- export declare const EnvironmentSchema: z.ZodMiniObject<{
67
- networking: z.ZodMiniOptional<z.ZodMiniObject<{
68
- mode: z.ZodMiniOptional<z.ZodMiniEnum<{
69
- limited: "limited";
70
- open: "open";
71
- }>>;
72
- allowedHosts: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
73
- }, z.core.$strict>>;
74
- packages: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniObject<{
75
- name: z.ZodMiniString<string>;
76
- version: z.ZodMiniOptional<z.ZodMiniString<string>>;
77
- }, z.core.$strict>>>;
78
- envVars: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnknown>>;
79
- }, z.core.$strict>;
@@ -1,179 +0,0 @@
1
- /**
2
- * Schemas for `submission.environment` — the customer-controlled runtime
3
- * environment: egress policy, OS/language packages, and plain env vars.
4
- *
5
- * Two behaviours here are deliberately NOT in the schemas, per D4/L1:
6
- *
7
- * - **Ecosystem-prefix splitting** (`"pip:pandas"` -> `{name:"pandas",
8
- * ecosystem:"pip"}`) is a transform, so it lives in
9
- * {@link normalizePlatformPackage}. A `.transform()` would make the response
10
- * half of the generated spec ungenerable.
11
- * - **Host lower-casing** lives in {@link normalizeAllowedHosts} for the same
12
- * reason.
13
- */
14
- import * as z from "zod/mini";
15
- import { ENV_VARS_MAX_ENTRIES, ENV_VARS_MAX_TOTAL_BYTES, ENV_VARS_MAX_VALUE_BYTES, ENV_VAR_KEY_PATTERN, AEX_RESERVED_ENV_PREFIX, PLATFORM_PACKAGE_ECOSYSTEMS } from "../submission-limits.js";
16
- import { indexedPath, lastSegment, wireObject } from "./wire.js";
17
- /**
18
- * Every schema below is mounted under {@link EnvironmentSchema}, which is itself
19
- * mounted under the submission brief. That matters for paths: Zod reports an
20
- * issue position relative to the schema the parse STARTED at, so a message
21
- * rendered by folding the whole reported position is only correct at one mount
22
- * depth. Every path below is either a fixed string or derived from the last
23
- * segment(s) Zod reports (`indexedPath`, `lastSegment`), which is what keeps it
24
- * right however deeply the environment is mounted.
25
- */
26
- const ENVIRONMENT = "submission.environment";
27
- const NETWORKING = `${ENVIRONMENT}.networking`;
28
- const PACKAGES = `${ENVIRONMENT}.packages`;
29
- const ENV_VARS = `${ENVIRONMENT}.envVars`;
30
- /**
31
- * `envVars` as a bounded map of shell-portable names to UTF-8 values.
32
- *
33
- * The whole rule set is one ordered `z.check()` rather than a composition of
34
- * record key/value schemas, because the ladder is order-sensitive and every rung
35
- * has its own message: a key that is both malformed AND non-string must report
36
- * the malformed key, and the byte budget must fail on the entry that crosses
37
- * `ENV_VARS_MAX_TOTAL_BYTES` — not on the map as a whole. Composed schemas
38
- * report in Zod's order, not this one.
39
- *
40
- * The cost is that these rules are invisible in the generated OpenAPI document
41
- * (L2), so the description below is what a spec consumer sees. A weaker-but-true
42
- * schema beats a precise-but-wrong one.
43
- */
44
- export const EnvVarsSchema = z
45
- .record(z.string(), z.unknown(), { error: `${ENV_VARS} must be an object` })
46
- .check(z.check((payload) => {
47
- const value = payload.value;
48
- const keys = Object.keys(value);
49
- const reject = (message) => {
50
- payload.issues.push({ code: "custom", message, input: payload.value });
51
- };
52
- if (keys.length > ENV_VARS_MAX_ENTRIES) {
53
- reject(`${ENV_VARS} has ${keys.length} entries; maximum is ${ENV_VARS_MAX_ENTRIES}`);
54
- return;
55
- }
56
- let totalBytes = 0;
57
- for (const key of keys) {
58
- if (!ENV_VAR_KEY_PATTERN.test(key)) {
59
- reject(`${ENV_VARS}.${key} key must match /^[A-Z_][A-Z0-9_]*$/`);
60
- return;
61
- }
62
- if (key.startsWith(AEX_RESERVED_ENV_PREFIX)) {
63
- reject(`${ENV_VARS}.${key} uses reserved prefix "${AEX_RESERVED_ENV_PREFIX}" (set by the aex runtime)`);
64
- return;
65
- }
66
- const raw = value[key];
67
- if (typeof raw !== "string") {
68
- reject(`${ENV_VARS}.${key} must be a string`);
69
- return;
70
- }
71
- if (raw.includes("\0")) {
72
- reject(`${ENV_VARS}.${key} must not contain NUL bytes`);
73
- return;
74
- }
75
- const valueBytes = Buffer.byteLength(raw, "utf8");
76
- if (valueBytes > ENV_VARS_MAX_VALUE_BYTES) {
77
- reject(`${ENV_VARS}.${key} value is ${valueBytes} bytes; maximum is ${ENV_VARS_MAX_VALUE_BYTES}`);
78
- return;
79
- }
80
- totalBytes += Buffer.byteLength(key, "utf8") + valueBytes;
81
- if (totalBytes > ENV_VARS_MAX_TOTAL_BYTES) {
82
- reject(`${ENV_VARS} total byte size exceeds maximum ${ENV_VARS_MAX_TOTAL_BYTES}`);
83
- return;
84
- }
85
- }
86
- }))
87
- .register(z.globalRegistry, {
88
- id: "SubmissionEnvVars",
89
- description: "Environment variables injected into the session runtime. Keys match /^[A-Z_][A-Z0-9_]*$/ " +
90
- `and must not use the reserved "${AEX_RESERVED_ENV_PREFIX}" prefix. Bounded to ` +
91
- `${ENV_VARS_MAX_ENTRIES} entries, ${ENV_VARS_MAX_VALUE_BYTES} bytes per value and ` +
92
- `${ENV_VARS_MAX_TOTAL_BYTES} bytes in total. Enforced in packages/contracts/src/schemas/submission-environment.ts.`
93
- });
94
- /** A single allowed egress host. Case folding is {@link normalizeAllowedHosts}' job. */
95
- const allowedHost = z.string().check(z.refine((value) => typeof value === "string" && value.length > 0, {
96
- error: (issue) => `${NETWORKING}.allowedHosts[${lastSegment(issue.path)}] must be a non-empty string`,
97
- abort: true
98
- }));
99
- export const AllowedHostsSchema = z
100
- .array(allowedHost, {
101
- error: `${NETWORKING}.allowedHosts must be an array of strings`
102
- })
103
- .check(z.check((payload) => {
104
- const seen = new Set();
105
- for (const entry of payload.value) {
106
- const lower = entry.toLowerCase();
107
- if (seen.has(lower)) {
108
- payload.issues.push({
109
- code: "custom",
110
- message: `${NETWORKING}.allowedHosts duplicate entry: ${entry}`,
111
- input: payload.value
112
- });
113
- return;
114
- }
115
- seen.add(lower);
116
- }
117
- }));
118
- /** Lower-case every host so the deny/allow comparison downstream is case-insensitive. */
119
- export function normalizeAllowedHosts(hosts) {
120
- return hosts.map((host) => host.toLowerCase());
121
- }
122
- export const NetworkingSchema = wireObject(NETWORKING, {
123
- mode: z.optional(z.enum(["limited", "open"], {
124
- error: `${NETWORKING}.mode must be one of: limited, open`
125
- })),
126
- allowedHosts: z.optional(AllowedHostsSchema)
127
- }, {
128
- unknownKey: (path, key) => `${path}.${key} is not an allowed field; permitted: mode, allowedHosts`
129
- }).check(
130
- // `mode` is optional on the wire only so that an unknown-key error outranks a
131
- // missing-mode error, matching the parser's order. Supplying `networking` at
132
- // all is a commitment to state the egress mode.
133
- z.refine((value) => value.mode !== undefined, {
134
- error: `${NETWORKING}.mode is required when networking is provided`,
135
- abort: true
136
- }));
137
- export const PlatformPackageSchema = wireObject(indexedPath(PACKAGES), {
138
- name: z.string(),
139
- version: z.optional(z.string())
140
- }, {
141
- unknownKey: (path, key) => `${path}.${key} is not an allowed field; permitted: name, version`
142
- });
143
- export const PackagesSchema = z.array(PlatformPackageSchema, {
144
- error: `${PACKAGES} must be an array`
145
- });
146
- /**
147
- * Split the `"<ecosystem>:<name>"` prefix a caller encodes into `name`.
148
- *
149
- * An unprefixed name defaults to `apt`. A colon-delimited prefix that is not a
150
- * known ecosystem is rejected rather than folded into the package name, so a
151
- * typo'd manager fails closed instead of installing something unexpected.
152
- *
153
- * Throws rather than returning a result because it runs inside the parser's
154
- * existing `withContractParseError` boundary, which brands whatever it throws.
155
- */
156
- export function normalizePlatformPackage(pkg, path) {
157
- let ecosystem = "apt";
158
- let name = pkg.name;
159
- const colon = pkg.name.indexOf(":");
160
- if (colon > 0) {
161
- const prefix = pkg.name.slice(0, colon);
162
- if (!PLATFORM_PACKAGE_ECOSYSTEMS.includes(prefix)) {
163
- throw new Error(`${path}.name has unknown ecosystem prefix "${prefix}:"; permitted: ${PLATFORM_PACKAGE_ECOSYSTEMS.join(", ")}`);
164
- }
165
- ecosystem = prefix;
166
- name = pkg.name.slice(colon + 1);
167
- }
168
- if (name.length === 0) {
169
- throw new Error(`${path}.name resolves to an empty package after stripping the "${ecosystem}:" ecosystem prefix`);
170
- }
171
- return pkg.version !== undefined ? { name, version: pkg.version, ecosystem } : { name, ecosystem };
172
- }
173
- export const EnvironmentSchema = wireObject(ENVIRONMENT, {
174
- networking: z.optional(NetworkingSchema),
175
- packages: z.optional(PackagesSchema),
176
- envVars: z.optional(EnvVarsSchema)
177
- }, {
178
- unknownKey: (path, key) => `${path}.${key} is not an allowed field; permitted: networking, packages, envVars`
179
- });