@aventara/core 1.0.0-rc.0 → 1.0.0-rc.10

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 (338) hide show
  1. package/CHANGELOG.md +2068 -1
  2. package/ERRORS.md +142 -0
  3. package/README.md +485 -60
  4. package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
  5. package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
  6. package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
  7. package/dist/adapters/adapter-field.d.ts +33 -11
  8. package/dist/adapters/adapter-identifier.d.ts +15 -6
  9. package/dist/adapters/adapter-identifier.js +6 -1
  10. package/dist/adapters/adapter-model.d.ts +18 -9
  11. package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
  12. package/dist/adapters/adapter-operation.d.ts +21 -6
  13. package/dist/adapters/adapter-resource.d.ts +23 -9
  14. package/dist/adapters/adapter-sql-statement.d.ts +19 -0
  15. package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
  16. package/dist/adapters/adapter.interface.d.ts +59 -29
  17. package/dist/avz/avz-check.factory.d.ts +83 -0
  18. package/dist/avz/avz-check.factory.js +116 -0
  19. package/dist/avz/avz-check.registry.d.ts +35 -0
  20. package/dist/avz/avz-check.registry.js +9 -0
  21. package/dist/avz/avz.d.ts +203 -0
  22. package/dist/{json → avz}/avz.js +150 -8
  23. package/dist/{json → avz}/index.d.ts +2 -1
  24. package/dist/{json → avz}/json-shape.registry.d.ts +9 -8
  25. package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
  26. package/dist/{json → avz}/zod-issue.translator.js +7 -0
  27. package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
  28. package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
  29. package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
  30. package/dist/compiler/contract.compiler.d.ts +23 -17
  31. package/dist/compiler/contract.compiler.js +753 -443
  32. package/dist/compiler/create-requirements.projector.d.ts +49 -0
  33. package/dist/compiler/create-requirements.projector.js +423 -0
  34. package/dist/compiler/field-validator.compiler.d.ts +47 -0
  35. package/dist/compiler/field-validator.compiler.js +238 -0
  36. package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
  37. package/dist/compiler/managed-elsewhere.projector.js +179 -0
  38. package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
  39. package/dist/compiler/managed-elsewhere.validator.js +74 -0
  40. package/dist/config/any-framework-config.d.ts +19 -12
  41. package/dist/config/computed-fields.d.ts +62 -0
  42. package/dist/config/computed-fields.js +73 -0
  43. package/dist/config/config-diagnostic.d.ts +11 -4
  44. package/dist/config/config-diagnostic.guidance.d.ts +6 -0
  45. package/dist/config/config-diagnostic.guidance.js +32 -0
  46. package/dist/config/config-layer.d.ts +15 -6
  47. package/dist/config/config.resolver.d.ts +98 -31
  48. package/dist/config/config.resolver.js +173 -44
  49. package/dist/config/config.validator.d.ts +7 -7
  50. package/dist/config/config.validator.js +792 -69
  51. package/dist/config/define-resource.d.ts +53 -0
  52. package/dist/config/define-resource.js +14 -0
  53. package/dist/config/effective-fields.d.ts +19 -23
  54. package/dist/config/entrypoint.normalizer.d.ts +4 -3
  55. package/dist/config/exact-framework-config.d.ts +325 -0
  56. package/dist/config/field-compute.resolver.d.ts +21 -0
  57. package/dist/config/field-compute.resolver.js +123 -0
  58. package/dist/config/field-pipeline-config.d.ts +47 -0
  59. package/dist/config/forced-operation.validator.d.ts +10 -0
  60. package/dist/config/forced-operation.validator.js +66 -0
  61. package/dist/config/framework-config.d.ts +148 -39
  62. package/dist/config/framework-exemptions-config.d.ts +91 -0
  63. package/dist/config/framework-exemptions-config.js +1 -0
  64. package/dist/config/framework-field-definition.d.ts +78 -0
  65. package/dist/config/framework-field-definition.js +28 -0
  66. package/dist/config/framework-resources-config.d.ts +127 -0
  67. package/dist/config/framework-resources-config.js +1 -0
  68. package/dist/config/pipeline-config.d.ts +56 -20
  69. package/dist/config/pipeline-tree.resolver.d.ts +79 -0
  70. package/dist/config/pipeline-tree.resolver.js +220 -0
  71. package/dist/config/stage-type.eraser.d.ts +65 -0
  72. package/dist/config/stage-type.eraser.js +1 -0
  73. package/dist/contracts/access-route.rules.d.ts +10 -0
  74. package/dist/contracts/access-route.rules.js +45 -0
  75. package/dist/contracts/capability.d.ts +37 -12
  76. package/dist/contracts/capability.js +20 -0
  77. package/dist/contracts/client-contract-structure.validator.d.ts +621 -114
  78. package/dist/contracts/client-contract-structure.validator.js +189 -10
  79. package/dist/contracts/contract-access.d.ts +29 -0
  80. package/dist/contracts/contract-access.js +1 -0
  81. package/dist/contracts/contract-canonicalizer.d.ts +27 -3
  82. package/dist/contracts/contract-canonicalizer.js +168 -29
  83. package/dist/contracts/contract-hash.d.ts +11 -7
  84. package/dist/contracts/contract-hash.js +4 -3
  85. package/dist/contracts/contract-limits.d.ts +4 -1
  86. package/dist/contracts/contract-limits.js +1 -0
  87. package/dist/contracts/contract-lookup.d.ts +5 -5
  88. package/dist/contracts/contract-protocol.d.ts +4 -4
  89. package/dist/contracts/contract.d.ts +51 -17
  90. package/dist/contracts/create-requirements.d.ts +35 -0
  91. package/dist/contracts/create-requirements.js +1 -0
  92. package/dist/contracts/enum-definition.d.ts +1 -1
  93. package/dist/contracts/field-check.d.ts +101 -0
  94. package/dist/contracts/field-check.js +1 -0
  95. package/dist/contracts/field.d.ts +109 -42
  96. package/dist/contracts/identifier.d.ts +4 -4
  97. package/dist/contracts/json-schema.projector.d.ts +11 -0
  98. package/dist/contracts/json-schema.projector.js +78 -0
  99. package/dist/contracts/json-shape.d.ts +12 -1
  100. package/dist/contracts/lifecycle-trait.d.ts +2 -2
  101. package/dist/contracts/resource-operations.d.ts +28 -28
  102. package/dist/contracts/resource.d.ts +15 -9
  103. package/dist/contracts/scalar-value-type.d.ts +17 -15
  104. package/dist/contracts/scalar.d.ts +3 -3
  105. package/dist/contracts/transaction-capability.d.ts +1 -1
  106. package/dist/contracts/wire-scalar-format.d.ts +4 -4
  107. package/dist/framework/access-facade.d.ts +116 -0
  108. package/dist/framework/access-facade.js +120 -0
  109. package/dist/framework/contract-view.d.ts +315 -145
  110. package/dist/framework/framework-construction.error.d.ts +21 -11
  111. package/dist/framework/framework-construction.error.js +20 -4
  112. package/dist/framework/framework.d.ts +71 -26
  113. package/dist/framework/framework.factory.d.ts +8 -6
  114. package/dist/framework/framework.factory.js +150 -38
  115. package/dist/framework/operation-facade.d.ts +192 -54
  116. package/dist/framework/operation-facade.js +10 -1
  117. package/dist/index.d.ts +67 -50
  118. package/dist/index.js +7 -6
  119. package/dist/internal.d.ts +20 -10
  120. package/dist/internal.js +9 -1
  121. package/dist/operations/database-refusal.d.ts +51 -0
  122. package/dist/operations/database-refusal.js +45 -0
  123. package/dist/operations/operation-arguments.d.ts +381 -228
  124. package/dist/operations/operation-call.d.ts +31 -28
  125. package/dist/operations/operation-identity.d.ts +10 -10
  126. package/dist/operations/operation-result.d.ts +25 -23
  127. package/dist/operations/operation-validator-core.d.ts +6 -6
  128. package/dist/operations/operation-validator-core.js +172 -38
  129. package/dist/operations/operation-validator.d.ts +10 -10
  130. package/dist/operations/projection-scope.resolver.d.ts +6 -6
  131. package/dist/operations/structural-limits.walker.d.ts +7 -7
  132. package/dist/operations/structural-limits.walker.js +145 -0
  133. package/dist/operations/validation-code.d.ts +11 -6
  134. package/dist/operations/validation-code.guidance.d.ts +6 -0
  135. package/dist/operations/validation-code.guidance.js +90 -0
  136. package/dist/operations/validation-code.js +4 -0
  137. package/dist/operations/write-scope.resolver.d.ts +10 -6
  138. package/dist/operations/write-scope.resolver.js +2 -0
  139. package/dist/policy/access-provider.interface.d.ts +91 -0
  140. package/dist/policy/access-provider.interface.js +1 -0
  141. package/dist/policy/access-provider.registry.d.ts +17 -0
  142. package/dist/policy/access-provider.registry.js +15 -0
  143. package/dist/policy/access-question.d.ts +20 -0
  144. package/dist/policy/access-question.js +1 -0
  145. package/dist/policy/access-question.registry.d.ts +5 -0
  146. package/dist/policy/access-question.registry.js +19 -0
  147. package/dist/policy/access-question.runtime.d.ts +36 -0
  148. package/dist/policy/access-question.runtime.js +297 -0
  149. package/dist/policy/access-verb.table.d.ts +56 -0
  150. package/dist/policy/access-verb.table.js +21 -0
  151. package/dist/policy/access-verbs.d.ts +46 -0
  152. package/dist/policy/access-verbs.js +1 -0
  153. package/dist/policy/policy-admission.d.ts +20 -0
  154. package/dist/policy/policy-admission.js +409 -0
  155. package/dist/policy/policy-after-update.runtime.d.ts +79 -0
  156. package/dist/policy/policy-after-update.runtime.js +208 -0
  157. package/dist/policy/policy-condition.d.ts +15 -0
  158. package/dist/policy/policy-condition.js +36 -0
  159. package/dist/policy/policy-engine.d.ts +205 -0
  160. package/dist/policy/policy-engine.js +1 -0
  161. package/dist/policy/policy-named-rows.d.ts +18 -0
  162. package/dist/policy/policy-named-rows.js +51 -0
  163. package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
  164. package/dist/policy/policy-nested-write.runtime.js +545 -0
  165. package/dist/policy/policy-read.runtime.d.ts +81 -0
  166. package/dist/policy/policy-read.runtime.js +503 -0
  167. package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
  168. package/dist/policy/policy-reference-write.runtime.js +345 -0
  169. package/dist/policy/policy-request.d.ts +41 -0
  170. package/dist/policy/policy-request.js +63 -0
  171. package/dist/policy/policy-session.d.ts +106 -0
  172. package/dist/policy/policy-session.js +295 -0
  173. package/dist/policy/policy-startup.validator.d.ts +10 -0
  174. package/dist/policy/policy-startup.validator.js +112 -0
  175. package/dist/policy/policy-write.runtime.d.ts +39 -0
  176. package/dist/policy/policy-write.runtime.js +532 -0
  177. package/dist/prebuilt/core-version.generated.d.ts +2 -0
  178. package/dist/prebuilt/core-version.generated.js +1 -0
  179. package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
  180. package/dist/prebuilt/prebuilt-changes.js +65 -0
  181. package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
  182. package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
  183. package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
  184. package/dist/prebuilt/prebuilt-contracts.js +1 -0
  185. package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
  186. package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
  187. package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
  188. package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
  189. package/dist/protocol/absent-route.responder.d.ts +17 -34
  190. package/dist/protocol/absent-route.responder.js +53 -20
  191. package/dist/protocol/contract-document.responder.d.ts +5 -4
  192. package/dist/protocol/contract-document.responder.js +2 -2
  193. package/dist/protocol/http-request.decoder.d.ts +33 -13
  194. package/dist/protocol/http-request.decoder.js +34 -11
  195. package/dist/protocol/http-request.reader.d.ts +9 -6
  196. package/dist/protocol/http-request.reader.js +1 -0
  197. package/dist/protocol/http-response.encoder.d.ts +4 -4
  198. package/dist/protocol/http-response.encoder.js +94 -55
  199. package/dist/protocol/http-status.table.d.ts +2 -2
  200. package/dist/protocol/operation-response.guard.d.ts +2 -2
  201. package/dist/protocol/protocol-headers.d.ts +3 -3
  202. package/dist/protocol/protocol-surface.d.ts +10 -5
  203. package/dist/protocol/protocol-surface.js +7 -0
  204. package/dist/protocol/protocol.binder.d.ts +66 -28
  205. package/dist/protocol/protocol.binder.js +16 -10
  206. package/dist/protocol/protocol.handler.d.ts +34 -14
  207. package/dist/protocol/protocol.handler.js +122 -18
  208. package/dist/protocol/unmounted-route.error.d.ts +4 -4
  209. package/dist/protocol/unmounted-route.error.js +2 -2
  210. package/dist/runtime/caller-data.copier.d.ts +22 -7
  211. package/dist/runtime/caller-data.copier.js +30 -17
  212. package/dist/runtime/caller-data.door.d.ts +18 -11
  213. package/dist/runtime/caller-data.door.js +6 -4
  214. package/dist/runtime/computed-read-runtime.d.ts +12 -6
  215. package/dist/runtime/computed-read-runtime.js +271 -71
  216. package/dist/runtime/computed-value.error.d.ts +7 -6
  217. package/dist/runtime/computed-value.error.js +5 -4
  218. package/dist/runtime/context-executor.runtime.d.ts +60 -0
  219. package/dist/runtime/context-executor.runtime.js +277 -0
  220. package/dist/runtime/core-class.brand.d.ts +10 -0
  221. package/dist/runtime/core-class.brand.js +21 -0
  222. package/dist/runtime/create-requirement.d.ts +34 -79
  223. package/dist/runtime/create-requirement.js +205 -74
  224. package/dist/runtime/decimal.d.ts +16 -2
  225. package/dist/runtime/decimal.js +22 -1
  226. package/dist/runtime/diagnostics-reporter.d.ts +91 -30
  227. package/dist/runtime/diagnostics-reporter.js +37 -1
  228. package/dist/runtime/error-boundary.d.ts +73 -9
  229. package/dist/runtime/error-boundary.js +57 -19
  230. package/dist/runtime/error-guidance.d.ts +12 -0
  231. package/dist/runtime/error-guidance.js +1 -0
  232. package/dist/runtime/error.catalog.d.ts +49 -0
  233. package/dist/runtime/error.catalog.js +49 -0
  234. package/dist/runtime/execution-options.d.ts +18 -2
  235. package/dist/runtime/field-check.evaluator.d.ts +27 -0
  236. package/dist/runtime/field-check.evaluator.js +521 -0
  237. package/dist/runtime/field-compute.d.ts +65 -0
  238. package/dist/runtime/field-compute.js +1 -0
  239. package/dist/runtime/field-stage.plan.d.ts +15 -0
  240. package/dist/runtime/field-stage.plan.js +27 -0
  241. package/dist/runtime/field-stage.runtime.d.ts +37 -0
  242. package/dist/runtime/field-stage.runtime.js +147 -0
  243. package/dist/runtime/field-validator.runtime.d.ts +29 -0
  244. package/dist/runtime/field-validator.runtime.js +126 -0
  245. package/dist/runtime/framework-error-class.table.d.ts +33 -0
  246. package/dist/runtime/framework-error-class.table.js +25 -0
  247. package/dist/runtime/framework-error.d.ts +68 -8
  248. package/dist/runtime/framework-error.factory.d.ts +4 -0
  249. package/dist/runtime/framework-error.factory.js +15 -0
  250. package/dist/runtime/framework-error.js +32 -2
  251. package/dist/runtime/framework-warning.emitter.d.ts +6 -0
  252. package/dist/runtime/framework-warning.emitter.js +8 -0
  253. package/dist/runtime/interceptor-next.error.d.ts +5 -0
  254. package/dist/runtime/interceptor-next.error.js +6 -0
  255. package/dist/runtime/json-value.d.ts +11 -6
  256. package/dist/runtime/level-lifecycle.runtime.d.ts +26 -0
  257. package/dist/runtime/level-lifecycle.runtime.js +40 -0
  258. package/dist/runtime/misuse-reporter.d.ts +12 -12
  259. package/dist/runtime/mutation-planner.d.ts +20 -16
  260. package/dist/runtime/mutation-planner.js +48 -35
  261. package/dist/runtime/nested-write.walker.d.ts +32 -0
  262. package/dist/runtime/nested-write.walker.js +73 -0
  263. package/dist/runtime/operation-code.guidance.d.ts +6 -0
  264. package/dist/runtime/operation-code.guidance.js +167 -0
  265. package/dist/runtime/operation-request.d.ts +45 -11
  266. package/dist/runtime/operation-response.d.ts +17 -17
  267. package/dist/runtime/operation-runtime.d.ts +133 -27
  268. package/dist/runtime/operation-runtime.js +576 -84
  269. package/dist/runtime/outcome-mapper.d.ts +17 -5
  270. package/dist/runtime/outcome-mapper.js +23 -6
  271. package/dist/runtime/output-validator.d.ts +11 -11
  272. package/dist/runtime/output-validator.js +3 -3
  273. package/dist/runtime/owned-execution.registry.d.ts +16 -6
  274. package/dist/runtime/pipe-output.validator.d.ts +43 -18
  275. package/dist/runtime/pipe-output.validator.js +15 -13
  276. package/dist/runtime/pipeline.d.ts +221 -34
  277. package/dist/runtime/readonly-value.d.ts +47 -0
  278. package/dist/runtime/readonly-value.js +189 -0
  279. package/dist/runtime/referential-action.d.ts +1 -1
  280. package/dist/runtime/request-envelope.validator.d.ts +3 -3
  281. package/dist/runtime/request-envelope.validator.js +12 -7
  282. package/dist/runtime/request-id.d.ts +1 -1
  283. package/dist/runtime/request-state.d.ts +14 -0
  284. package/dist/runtime/request-state.js +1 -0
  285. package/dist/runtime/request-state.resolver.d.ts +12 -0
  286. package/dist/runtime/request-state.resolver.js +20 -0
  287. package/dist/runtime/scalar-runtime.d.ts +33 -25
  288. package/dist/runtime/scalar-runtime.js +105 -38
  289. package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
  290. package/dist/runtime/unsent-value.normalizer.js +128 -0
  291. package/dist/transactions/deferred-operation.d.ts +35 -20
  292. package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
  293. package/dist/transactions/operation-arguments-encoder.js +8 -3
  294. package/dist/transactions/operation-fingerprint.js +2 -2
  295. package/dist/transactions/sql-statement.d.ts +85 -0
  296. package/dist/transactions/sql-statement.js +47 -0
  297. package/dist/transactions/sql-statement.validator.d.ts +44 -0
  298. package/dist/transactions/sql-statement.validator.js +167 -0
  299. package/dist/transactions/transaction-envelope.d.ts +9 -8
  300. package/dist/transactions/transaction-integrity-error.d.ts +6 -6
  301. package/dist/transactions/transaction-integrity-error.js +7 -2
  302. package/dist/transactions/transaction-plan-assembler.d.ts +30 -13
  303. package/dist/transactions/transaction-plan-assembler.js +184 -32
  304. package/dist/transactions/transaction-plan-validator.d.ts +50 -25
  305. package/dist/transactions/transaction-plan-validator.js +96 -38
  306. package/dist/transactions/transaction-reference-collector.d.ts +5 -5
  307. package/dist/transactions/transaction-reference-resolver.d.ts +21 -3
  308. package/dist/transactions/transaction-reference-resolver.js +26 -14
  309. package/dist/transactions/transaction-reference-validator.d.ts +74 -4
  310. package/dist/transactions/transaction-reference-validator.js +129 -71
  311. package/dist/transactions/transaction-reference.d.ts +14 -14
  312. package/dist/transactions/transaction-reference.js +5 -0
  313. package/dist/transactions/transaction-request.d.ts +22 -9
  314. package/dist/transactions/transaction-response.d.ts +6 -6
  315. package/dist/transactions/transaction-runtime.d.ts +12 -8
  316. package/dist/transactions/transaction-runtime.js +218 -50
  317. package/dist/transactions/transaction-settlement.runtime.d.ts +52 -0
  318. package/dist/transactions/transaction-settlement.runtime.js +120 -0
  319. package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
  320. package/dist/transactions/transaction-slot-path-error.js +4 -2
  321. package/dist/transactions/transaction-slot-writer.js +2 -2
  322. package/dist/transactions/transaction-stage.runtime.d.ts +83 -0
  323. package/dist/transactions/transaction-stage.runtime.js +126 -0
  324. package/package.json +11 -9
  325. package/src/runtime/field-check.evaluator.ts +720 -0
  326. package/dist/config/define-fields.d.ts +0 -42
  327. package/dist/config/define-fields.js +0 -3
  328. package/dist/config/framework-behaviors-config.d.ts +0 -30
  329. package/dist/config/framework-fields-config.d.ts +0 -42
  330. package/dist/config/framework-restrictions-config.d.ts +0 -142
  331. package/dist/json/avz.d.ts +0 -96
  332. package/dist/runtime/field-behavior.d.ts +0 -48
  333. /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
  334. /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
  335. /package/dist/{json → avz}/index.js +0 -0
  336. /package/dist/{json → avz}/json-shape.registry.js +0 -0
  337. /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
  338. /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
@@ -1,34 +1,82 @@
1
+ import { isAccessPath, isAccessUrl } from "../contracts/access-route.rules.js";
1
2
  import { TRANSACTION_CAPABILITIES } from "../contracts/transaction-capability.js";
3
+ import { ACCESS_VERB_NAMES, isAccessVerbName, providerVerb, } from "../policy/access-verb.table.js";
2
4
  import { normalizeEntrypoint } from "./entrypoint.normalizer.js";
3
- const ROOT_PROPERTIES = new Set([
4
- "entrypoint",
5
+ import { AVZ_FORMATS } from "./framework-field-definition.js";
6
+ const ROOT_ONLY_PROPERTIES = new Set([
7
+ "api",
8
+ "mcp",
5
9
  "adapter",
6
- "fields",
7
- "behaviors",
8
- "restrictions",
9
- "limits",
10
- "pipelines",
11
- "transactions",
10
+ "prebuilt",
11
+ "policy",
12
+ "access",
12
13
  "diagnostics",
13
14
  "misuse",
14
15
  "application",
15
16
  "client",
17
+ "agent",
16
18
  ]);
17
- const SCOPE_PROPERTIES = new Set([
18
- "fields",
19
- "behaviors",
20
- "restrictions",
19
+ const MOVED_ROOT_PROPERTIES = new Map([
20
+ ["entrypoint", "api"],
21
+ ]);
22
+ const AGENT_PARENTS = new Set(["root", "application", "client"]);
23
+ const MCP_PROPERTIES = new Set(["path", "authorization"]);
24
+ const MCP_AUTHORIZATION_PROPERTIES = new Set(["servers", "verify"]);
25
+ const LAYER_PROPERTIES = new Set([
26
+ "exposed",
27
+ "transactionsStyle",
21
28
  "limits",
22
29
  "pipelines",
30
+ "resources",
31
+ "exemptions",
32
+ ]);
33
+ const MOVED_LAYER_PROPERTIES = new Map([
34
+ ["restrictions", ["exposed", "exemptions"]],
35
+ ["behaviors", ["resources.<Resource>.fields.<field>.pipelines.compute"]],
36
+ ["fields", ["resources.<Resource>.fields.<field>.definition"]],
37
+ ["transactions", ["transactionsStyle"]],
38
+ ]);
39
+ const RESOURCE_PROPERTIES = new Set([
40
+ "pipelines",
41
+ "operations",
23
42
  "transactions",
43
+ "fields",
44
+ "managedElsewhere",
24
45
  ]);
46
+ const FIELD_PROPERTIES = new Set(["definition", "pipelines"]);
47
+ const DEFINITION_PROPERTIES = new Set([
48
+ "type",
49
+ "nullable",
50
+ "list",
51
+ "lifecycle",
52
+ "format",
53
+ "capabilities",
54
+ "json",
55
+ ]);
56
+ const COMPUTE_PHASES = new Set(["create", "read", "update"]);
57
+ const FIELD_PIPELINE_PROPERTIES = new Set([
58
+ "validators",
59
+ "pipes",
60
+ "compute",
61
+ "guards",
62
+ ]);
63
+ const OPERATION_FAMILIES = new Set([
64
+ "find",
65
+ "create",
66
+ "update",
67
+ "delete",
68
+ "upsert",
69
+ ]);
70
+ const OPERATION_VARIANTS = new Set(["first", "unique", "many", "count", "one"]);
25
71
  const TRANSACTION_CAPABILITY_SET = new Set(TRANSACTION_CAPABILITIES);
72
+ const AVZ_FORMAT_SET = new Set(AVZ_FORMATS);
26
73
  const LIMIT_PROPERTIES = new Set([
27
74
  "maxRequestBytes",
28
75
  "maxNestingDepth",
29
76
  "maxListLimit",
30
77
  "maxTransactionOperations",
31
78
  "maxBooleanNodes",
79
+ "maxJsonDepth",
32
80
  ]);
33
81
  const PIPELINE_PROPERTIES = new Set([
34
82
  "guards",
@@ -48,20 +96,21 @@ function isPlainRecord(value) {
48
96
  function diagnostic(code, path, message) {
49
97
  return { code, path, message };
50
98
  }
51
- export function entrypointRefusalDiagnostic(message) {
52
- return diagnostic("CONFIG_INVALID_VALUE", "entrypoint", `entrypoint ${message}`);
99
+ function childPath(path, key) {
100
+ return path === "" ? key : `${path}.${key}`;
53
101
  }
54
- function validateNamedObject(owner, key, path, diagnostics) {
55
- if (!Object.hasOwn(owner, key)) {
56
- return;
57
- }
58
- if (!isPlainRecord(owner[key])) {
59
- diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object`));
102
+ export function mountPathRefusalDiagnostic(path, message) {
103
+ return diagnostic("CONFIG_INVALID_VALUE", path, `${path} ${message}`);
104
+ }
105
+ function requireRecord(value, path, diagnostics) {
106
+ if (isPlainRecord(value)) {
107
+ return true;
60
108
  }
109
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object`));
110
+ return false;
61
111
  }
62
112
  function validateLimits(value, path, diagnostics) {
63
- if (!isPlainRecord(value)) {
64
- diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object`));
113
+ if (!requireRecord(value, path, diagnostics)) {
65
114
  return;
66
115
  }
67
116
  for (const [key, limit] of Object.entries(value)) {
@@ -78,7 +127,7 @@ function validateLimits(value, path, diagnostics) {
78
127
  }
79
128
  }
80
129
  }
81
- function validatePipelineArray(value, key, path, diagnostics) {
130
+ function validateArray(value, key, path, diagnostics) {
82
131
  if (!Object.hasOwn(value, key)) {
83
132
  return;
84
133
  }
@@ -88,8 +137,7 @@ function validatePipelineArray(value, key, path, diagnostics) {
88
137
  }
89
138
  }
90
139
  function validatePipelineHooks(value, path, diagnostics) {
91
- if (!isPlainRecord(value)) {
92
- diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object`));
140
+ if (!requireRecord(value, path, diagnostics)) {
93
141
  return;
94
142
  }
95
143
  for (const key of Object.keys(value)) {
@@ -97,48 +145,441 @@ function validatePipelineHooks(value, path, diagnostics) {
97
145
  diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `${path}.${key}`, `unknown pipeline hook property: ${key}`));
98
146
  }
99
147
  }
100
- validatePipelineArray(value, "before", path, diagnostics);
101
- validatePipelineArray(value, "after", path, diagnostics);
148
+ validateArray(value, "before", path, diagnostics);
149
+ validateArray(value, "after", path, diagnostics);
102
150
  }
103
151
  function validatePipelines(value, path, diagnostics) {
104
- if (!isPlainRecord(value)) {
105
- diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object`));
152
+ if (!requireRecord(value, path, diagnostics)) {
106
153
  return;
107
154
  }
108
155
  for (const key of Object.keys(value)) {
156
+ if (PIPELINE_HOOK_PROPERTIES.has(key)) {
157
+ diagnostics.push(diagnostic("CONFIG_MOVED_PROPERTY", `${path}.${key}`, `${path}.${key} moved in rc.1: hooks are ${path}.hooks.${key}`));
158
+ continue;
159
+ }
109
160
  if (!PIPELINE_PROPERTIES.has(key)) {
110
161
  diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `${path}.${key}`, `unknown pipeline property: ${key}`));
111
162
  }
112
163
  }
113
164
  for (const key of ["guards", "pipes", "interceptors", "filters"]) {
114
- validatePipelineArray(value, key, path, diagnostics);
165
+ validateArray(value, key, path, diagnostics);
115
166
  }
116
167
  if (Object.hasOwn(value, "hooks")) {
117
168
  validatePipelineHooks(value.hooks, `${path}.hooks`, diagnostics);
118
169
  }
119
170
  }
120
- function validateScope(value, path, diagnostics) {
171
+ function validateForceTransaction(value, path, diagnostics) {
172
+ if (!Object.hasOwn(value, "forceTransaction")) {
173
+ return;
174
+ }
175
+ const propertyPath = `${path}.forceTransaction`;
176
+ if (typeof value.forceTransaction !== "boolean") {
177
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", propertyPath, `${propertyPath} must be a boolean`));
178
+ }
179
+ }
180
+ function validateOperationLevel(value, path, isFamily, diagnostics) {
181
+ if (!requireRecord(value, path, diagnostics)) {
182
+ return;
183
+ }
184
+ for (const [key, child] of Object.entries(value)) {
185
+ const keyPath = `${path}.${key}`;
186
+ if (key === "pipelines") {
187
+ validatePipelines(child, keyPath, diagnostics);
188
+ continue;
189
+ }
190
+ if (key === "forceTransaction") {
191
+ continue;
192
+ }
193
+ if (isFamily && OPERATION_VARIANTS.has(key)) {
194
+ validateOperationLevel(child, keyPath, false, diagnostics);
195
+ continue;
196
+ }
197
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, isFamily
198
+ ? `unknown operation family property: ${key}; a family takes pipelines, forceTransaction and its variants by name`
199
+ : `unknown operation variant property: ${key}; a variant takes pipelines and forceTransaction`));
200
+ }
201
+ validateForceTransaction(value, path, diagnostics);
202
+ }
203
+ function validateOperations(value, path, diagnostics) {
204
+ if (!requireRecord(value, path, diagnostics)) {
205
+ return;
206
+ }
207
+ for (const [family, level] of Object.entries(value)) {
208
+ const familyPath = `${path}.${family}`;
209
+ if (!OPERATION_FAMILIES.has(family)) {
210
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", familyPath, `unknown operation family: ${family}`));
211
+ continue;
212
+ }
213
+ validateOperationLevel(level, familyPath, true, diagnostics);
214
+ }
215
+ }
216
+ function validateResourceTransactions(value, path, diagnostics) {
217
+ if (!requireRecord(value, path, diagnostics)) {
218
+ return;
219
+ }
220
+ for (const [key, child] of Object.entries(value)) {
221
+ const keyPath = `${path}.${key}`;
222
+ if (key !== "pipelines") {
223
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown Resource transactions property: ${key}`));
224
+ continue;
225
+ }
226
+ validatePipelines(child, keyPath, diagnostics);
227
+ }
228
+ }
229
+ function validateDefinition(value, path, diagnostics) {
230
+ if (!requireRecord(value, path, diagnostics)) {
231
+ return;
232
+ }
233
+ for (const key of Object.keys(value)) {
234
+ if (!DEFINITION_PROPERTIES.has(key)) {
235
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `${path}.${key}`, `unknown field definition property: ${key}`));
236
+ }
237
+ }
238
+ if (Object.hasOwn(value, "format") && !AVZ_FORMAT_SET.has(value.format)) {
239
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.format`, `${path}.format must be one of zod's named string formats (${AVZ_FORMATS.join(", ")})`));
240
+ }
241
+ }
242
+ function validateComputeStage(value, path, phase, diagnostics) {
243
+ if (typeof value === "function") {
244
+ return;
245
+ }
246
+ if (phase === "read" && isPlainRecord(value)) {
247
+ for (const key of Object.keys(value)) {
248
+ if (key !== "compute" && key !== "dependsOn") {
249
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `${path}.${key}`, `unknown computed read property: ${key}`));
250
+ }
251
+ }
252
+ if (typeof value.compute !== "function") {
253
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${path}.compute`, `${path}.compute must be a function`));
254
+ }
255
+ validateArray(value, "dependsOn", path, diagnostics);
256
+ return;
257
+ }
258
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, value === false
259
+ ? `${path} must be a function: compute stages chain across layers, and none is disabled from below`
260
+ : phase === "read"
261
+ ? `${path} must be a function or { compute, dependsOn }`
262
+ : `${path} must be a function`));
263
+ }
264
+ function validateCompute(value, path, diagnostics) {
265
+ if (!requireRecord(value, path, diagnostics)) {
266
+ return;
267
+ }
268
+ for (const [phase, stage] of Object.entries(value)) {
269
+ const phasePath = `${path}.${phase}`;
270
+ if (!COMPUTE_PHASES.has(phase)) {
271
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", phasePath, `unknown compute phase: ${phase}; the phases are create, read and update`));
272
+ continue;
273
+ }
274
+ if (stage !== undefined) {
275
+ validateComputeStage(stage, phasePath, phase, diagnostics);
276
+ }
277
+ }
278
+ }
279
+ function validateFieldPipelines(value, path, diagnostics) {
280
+ if (!requireRecord(value, path, diagnostics)) {
281
+ return;
282
+ }
283
+ for (const [key, child] of Object.entries(value)) {
284
+ const keyPath = `${path}.${key}`;
285
+ if (!FIELD_PIPELINE_PROPERTIES.has(key)) {
286
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown field pipeline property: ${key}`));
287
+ continue;
288
+ }
289
+ if (key === "compute") {
290
+ validateCompute(child, keyPath, diagnostics);
291
+ continue;
292
+ }
293
+ validateArray(value, key, path, diagnostics);
294
+ }
295
+ }
296
+ function movedFieldKey(key) {
297
+ if (DEFINITION_PROPERTIES.has(key)) {
298
+ return `definition.${key}`;
299
+ }
300
+ if (COMPUTE_PHASES.has(key)) {
301
+ return `pipelines.compute.${key}`;
302
+ }
303
+ return undefined;
304
+ }
305
+ function validateField(value, path, isRoot, resourcePath, diagnostics) {
306
+ if (!requireRecord(value, path, diagnostics)) {
307
+ return;
308
+ }
309
+ for (const [key, child] of Object.entries(value)) {
310
+ const keyPath = `${path}.${key}`;
311
+ if (key === "definition") {
312
+ if (!isRoot) {
313
+ diagnostics.push(diagnostic("CONFIG_FORBIDDEN_IN_OVERLAY", keyPath, `${keyPath}: definition is only allowed at root; a field is defined once and overlays only choose its visibility (define it at ${resourcePath})`));
314
+ continue;
315
+ }
316
+ validateDefinition(child, keyPath, diagnostics);
317
+ continue;
318
+ }
319
+ if (key === "pipelines") {
320
+ validateFieldPipelines(child, keyPath, diagnostics);
321
+ continue;
322
+ }
323
+ if (key === "hidden") {
324
+ diagnostics.push(movedHidden(keyPath));
325
+ continue;
326
+ }
327
+ const moved = movedFieldKey(key);
328
+ if (moved !== undefined) {
329
+ diagnostics.push(diagnostic("CONFIG_MOVED_PROPERTY", keyPath, `${keyPath} moved in rc.1: it is ${path}.${moved}`));
330
+ continue;
331
+ }
332
+ if (!FIELD_PROPERTIES.has(key)) {
333
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown field property: ${key}; a field takes definition and pipelines`));
334
+ }
335
+ }
336
+ }
337
+ function validateResource(value, path, resource, isRoot, diagnostics) {
338
+ if (!requireRecord(value, path, diagnostics)) {
339
+ return;
340
+ }
341
+ for (const [key, child] of Object.entries(value)) {
342
+ const keyPath = `${path}.${key}`;
343
+ if (key === "hidden") {
344
+ diagnostics.push(movedHidden(keyPath));
345
+ continue;
346
+ }
347
+ if (!RESOURCE_PROPERTIES.has(key)) {
348
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown Resource property: ${key}; a Resource takes pipelines, operations, transactions and fields (and managedElsewhere at the root)`));
349
+ continue;
350
+ }
351
+ if (key === "managedElsewhere") {
352
+ if (!isRoot) {
353
+ diagnostics.push(diagnostic("CONFIG_FORBIDDEN_IN_OVERLAY", keyPath, `${keyPath}: managedElsewhere is only allowed at root; it states who owns the table, which no layer changes (state it at resources.${resource}.managedElsewhere)`));
354
+ }
355
+ else if (typeof child !== "boolean") {
356
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", keyPath, `${keyPath} must be a boolean`));
357
+ }
358
+ continue;
359
+ }
360
+ if (key === "pipelines") {
361
+ validatePipelines(child, keyPath, diagnostics);
362
+ continue;
363
+ }
364
+ if (key === "operations") {
365
+ validateOperations(child, keyPath, diagnostics);
366
+ continue;
367
+ }
368
+ if (key === "transactions") {
369
+ validateResourceTransactions(child, keyPath, diagnostics);
370
+ continue;
371
+ }
372
+ if (!requireRecord(child, keyPath, diagnostics)) {
373
+ continue;
374
+ }
375
+ for (const [field, entry] of Object.entries(child)) {
376
+ validateField(entry, `${keyPath}.${field}`, isRoot, `resources.${resource}.fields.${field}.definition`, diagnostics);
377
+ }
378
+ }
379
+ }
380
+ function validateResources(value, path, isRoot, diagnostics) {
381
+ if (!requireRecord(value, path, diagnostics)) {
382
+ return;
383
+ }
384
+ for (const [resource, entry] of Object.entries(value)) {
385
+ validateResource(entry, `${path}.${resource}`, resource, isRoot, diagnostics);
386
+ }
387
+ }
388
+ const EXEMPTIONS_PROPERTIES = new Set(["resources"]);
389
+ const RESOURCE_EXEMPTION_PROPERTIES = new Set(["operations", "fields"]);
390
+ const FLAG_CAPABILITIES = new Set(["select", "include", "order", "orderNulls"]);
391
+ function movedHidden(path) {
392
+ return diagnostic("CONFIG_MOVED_PROPERTY", path, `${path} moved in rc.1: an entry is hidden with \`true\` under exposed: true`);
393
+ }
394
+ function validateNameList(value, path, what, diagnostics) {
395
+ value.forEach((entry, index) => {
396
+ if (typeof entry !== "string") {
397
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${path}[${index}]`, `${path}[${index}] must be ${what}`));
398
+ }
399
+ });
400
+ }
401
+ function validateExemptionValue(value, path, what, diagnostics) {
402
+ if (typeof value === "boolean") {
403
+ return "boolean";
404
+ }
405
+ if (Array.isArray(value)) {
406
+ validateNameList(value, path, what, diagnostics);
407
+ return "list";
408
+ }
409
+ if (isPlainRecord(value)) {
410
+ if (Object.hasOwn(value, "hidden")) {
411
+ diagnostics.push(movedHidden(`${path}.hidden`));
412
+ }
413
+ return "object";
414
+ }
415
+ return undefined;
416
+ }
417
+ function validateOperationsExemption(value, path, diagnostics) {
418
+ const kind = validateExemptionValue(value, path, "an operation family name", diagnostics);
419
+ if (kind === undefined) {
420
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be true, false, a list of operation families, or an object of them`));
421
+ return;
422
+ }
423
+ if (kind !== "object") {
424
+ return;
425
+ }
426
+ for (const [family, variants] of Object.entries(value)) {
427
+ if (family === "hidden") {
428
+ continue;
429
+ }
430
+ const familyPath = `${path}.${family}`;
431
+ const familyKind = validateExemptionValue(variants, familyPath, "an operation variant name", diagnostics);
432
+ if (familyKind === undefined) {
433
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", familyPath, `${familyPath} must be true, false, a list of variants, or an object of them`));
434
+ continue;
435
+ }
436
+ if (familyKind !== "object") {
437
+ continue;
438
+ }
439
+ for (const [variant, flag] of Object.entries(variants)) {
440
+ if (variant !== "hidden" && typeof flag !== "boolean") {
441
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${familyPath}.${variant}`, `${familyPath}.${variant} must be a boolean`));
442
+ }
443
+ }
444
+ }
445
+ }
446
+ function validateFieldExemption(value, path, diagnostics) {
447
+ const kind = validateExemptionValue(value, path, "a capability name", diagnostics);
448
+ if (kind === undefined) {
449
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be true, false, a list of capability names, or an object of them`));
450
+ return;
451
+ }
452
+ if (kind !== "object") {
453
+ return;
454
+ }
455
+ for (const [capability, entry] of Object.entries(value)) {
456
+ if (capability === "hidden") {
457
+ continue;
458
+ }
459
+ const capabilityPath = `${path}.${capability}`;
460
+ if (capability === "capabilities") {
461
+ diagnostics.push(diagnostic("CONFIG_MOVED_PROPERTY", capabilityPath, `${capabilityPath} moved in rc.1: capabilities are named directly on the field's exemption`));
462
+ continue;
463
+ }
464
+ if (typeof entry === "boolean") {
465
+ continue;
466
+ }
467
+ if (Array.isArray(entry) && !FLAG_CAPABILITIES.has(capability)) {
468
+ validateNameList(entry, capabilityPath, "a token", diagnostics);
469
+ continue;
470
+ }
471
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", capabilityPath, FLAG_CAPABILITIES.has(capability)
472
+ ? `${capabilityPath} must be a boolean`
473
+ : `${capabilityPath} must be a boolean or a list of tokens`));
474
+ }
475
+ }
476
+ function validateResourceExemption(value, path, diagnostics) {
477
+ if (typeof value === "boolean") {
478
+ return;
479
+ }
121
480
  if (!isPlainRecord(value)) {
122
- diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object`));
481
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be true, false or { operations, fields }; a Resource takes no list`));
123
482
  return;
124
483
  }
484
+ for (const [key, entry] of Object.entries(value)) {
485
+ const keyPath = `${path}.${key}`;
486
+ if (key === "hidden") {
487
+ diagnostics.push(movedHidden(keyPath));
488
+ continue;
489
+ }
490
+ if (!RESOURCE_EXEMPTION_PROPERTIES.has(key)) {
491
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown Resource exemption property: ${key}; a Resource's exemption takes operations and fields`));
492
+ continue;
493
+ }
494
+ if (key === "operations") {
495
+ validateOperationsExemption(entry, keyPath, diagnostics);
496
+ continue;
497
+ }
498
+ if (!requireRecord(entry, keyPath, diagnostics)) {
499
+ continue;
500
+ }
501
+ for (const [field, fieldEntry] of Object.entries(entry)) {
502
+ validateFieldExemption(fieldEntry, `${keyPath}.${field}`, diagnostics);
503
+ }
504
+ }
505
+ }
506
+ function validateExemptions(value, path, diagnostics) {
507
+ if (!requireRecord(value, path, diagnostics)) {
508
+ return;
509
+ }
510
+ for (const [key, entry] of Object.entries(value)) {
511
+ const keyPath = `${path}.${key}`;
512
+ if (!EXEMPTIONS_PROPERTIES.has(key)) {
513
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown exemptions property: ${key}; exemptions take resources`));
514
+ continue;
515
+ }
516
+ if (!requireRecord(entry, keyPath, diagnostics)) {
517
+ continue;
518
+ }
519
+ for (const [resource, resourceEntry] of Object.entries(entry)) {
520
+ validateResourceExemption(resourceEntry, `${keyPath}.${resource}`, diagnostics);
521
+ }
522
+ }
523
+ }
524
+ function validateLayer(value, path, kind, diagnostics) {
525
+ const isRoot = kind === "root";
125
526
  for (const key of Object.keys(value)) {
126
- if (!SCOPE_PROPERTIES.has(key)) {
127
- diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `${path}.${key}`, `unknown scoped configuration property: ${key}`));
527
+ const keyPath = childPath(path, key);
528
+ const moved = MOVED_LAYER_PROPERTIES.get(key);
529
+ if (moved !== undefined) {
530
+ diagnostics.push(diagnostic("CONFIG_MOVED_PROPERTY", keyPath, `${keyPath} moved in rc.1: use ${moved.map((next) => childPath(path, next)).join(" + ")}`));
531
+ continue;
532
+ }
533
+ const movedRootKey = isRoot ? MOVED_ROOT_PROPERTIES.get(key) : undefined;
534
+ if (movedRootKey !== undefined) {
535
+ diagnostics.push(diagnostic("CONFIG_MOVED_PROPERTY", keyPath, `${keyPath} moved in rc.1: use ${movedRootKey}`));
536
+ continue;
537
+ }
538
+ if (LAYER_PROPERTIES.has(key) ||
539
+ (isRoot && ROOT_ONLY_PROPERTIES.has(key)) ||
540
+ (kind === "agent" && key === "extends")) {
541
+ continue;
542
+ }
543
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, key === "extends"
544
+ ? `${keyPath}: extends is only allowed in the agent layer (agent.extends)`
545
+ : !isRoot && ROOT_ONLY_PROPERTIES.has(key)
546
+ ? `${keyPath}: ${key} is a root-only configuration property`
547
+ : isRoot
548
+ ? `unknown configuration property: ${key}`
549
+ : `unknown scoped configuration property: ${key}`));
550
+ }
551
+ if (kind === "agent" && Object.hasOwn(value, "extends")) {
552
+ if (!AGENT_PARENTS.has(value.extends)) {
553
+ const extendsPath = childPath(path, "extends");
554
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", extendsPath, `${extendsPath} must be "client", "application" or "root"`));
555
+ }
556
+ }
557
+ const exposedPath = childPath(path, "exposed");
558
+ if (Object.hasOwn(value, "exposed")) {
559
+ if (typeof value.exposed !== "boolean") {
560
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", exposedPath, `${exposedPath} must be a boolean`));
561
+ }
562
+ }
563
+ if (Object.hasOwn(value, "exemptions")) {
564
+ const exemptionsPath = childPath(path, "exemptions");
565
+ if (!isRoot && !Object.hasOwn(value, "exposed")) {
566
+ diagnostics.push(diagnostic("CONFIG_REQUIRED", exposedPath, `${exposedPath} is required when ${exemptionsPath} is set: true makes the exemptions hide, false makes them the only entries exposed`));
128
567
  }
568
+ validateExemptions(value.exemptions, exemptionsPath, diagnostics);
569
+ }
570
+ if (Object.hasOwn(value, "transactionsStyle") &&
571
+ !TRANSACTION_CAPABILITY_SET.has(value.transactionsStyle)) {
572
+ const stylePath = childPath(path, "transactionsStyle");
573
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", stylePath, `${stylePath} must be "none" or "interactive"`));
129
574
  }
130
- validateNamedObject(value, "fields", `${path}.fields`, diagnostics);
131
- validateNamedObject(value, "behaviors", `${path}.behaviors`, diagnostics);
132
- validateNamedObject(value, "restrictions", `${path}.restrictions`, diagnostics);
133
575
  if (Object.hasOwn(value, "limits")) {
134
- validateLimits(value.limits, `${path}.limits`, diagnostics);
576
+ validateLimits(value.limits, childPath(path, "limits"), diagnostics);
135
577
  }
136
578
  if (Object.hasOwn(value, "pipelines")) {
137
- validatePipelines(value.pipelines, `${path}.pipelines`, diagnostics);
579
+ validatePipelines(value.pipelines, childPath(path, "pipelines"), diagnostics);
138
580
  }
139
- if (Object.hasOwn(value, "transactions") &&
140
- !TRANSACTION_CAPABILITY_SET.has(value.transactions)) {
141
- diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.transactions`, `${path}.transactions must be "none" or "interactive"`));
581
+ if (Object.hasOwn(value, "resources")) {
582
+ validateResources(value.resources, childPath(path, "resources"), isRoot, diagnostics);
142
583
  }
143
584
  }
144
585
  function validateAdapter(value, diagnostics) {
@@ -166,41 +607,45 @@ export function validateFrameworkConfig(value) {
166
607
  diagnostic("CONFIG_INVALID_TYPE", "$", "framework configuration must be an object"),
167
608
  ];
168
609
  }
169
- for (const key of Object.keys(value)) {
170
- if (!ROOT_PROPERTIES.has(key)) {
171
- diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", key, `unknown configuration property: ${key}`));
172
- }
610
+ validateLayer(value, "", "root", diagnostics);
611
+ let api;
612
+ if (!Object.hasOwn(value, "api")) {
613
+ diagnostics.push(diagnostic("CONFIG_REQUIRED", "api", "api is required"));
173
614
  }
174
- if (!Object.hasOwn(value, "entrypoint")) {
175
- diagnostics.push(diagnostic("CONFIG_REQUIRED", "entrypoint", "entrypoint is required"));
176
- }
177
- else if (typeof value.entrypoint !== "string") {
178
- diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "entrypoint", "entrypoint must be a string"));
615
+ else if (typeof value.api !== "string") {
616
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "api", "api must be a string"));
179
617
  }
180
618
  else {
181
- const normalized = normalizeEntrypoint(value.entrypoint);
182
- if (!normalized.ok) {
183
- diagnostics.push(entrypointRefusalDiagnostic(normalized.message));
619
+ const normalized = normalizeEntrypoint(value.api);
620
+ if (normalized.ok) {
621
+ api = normalized.path;
622
+ }
623
+ else {
624
+ diagnostics.push(mountPathRefusalDiagnostic("api", normalized.message));
184
625
  }
185
626
  }
627
+ if (Object.hasOwn(value, "mcp")) {
628
+ validateMcp(value.mcp, api, diagnostics);
629
+ }
186
630
  if (!Object.hasOwn(value, "adapter")) {
187
631
  diagnostics.push(diagnostic("CONFIG_REQUIRED", "adapter", "adapter is required"));
188
632
  }
189
633
  else {
190
634
  validateAdapter(value.adapter, diagnostics);
191
635
  }
192
- validateNamedObject(value, "fields", "fields", diagnostics);
193
- validateNamedObject(value, "behaviors", "behaviors", diagnostics);
194
- validateNamedObject(value, "restrictions", "restrictions", diagnostics);
195
- if (Object.hasOwn(value, "limits")) {
196
- validateLimits(value.limits, "limits", diagnostics);
636
+ if (Object.hasOwn(value, "prebuilt") &&
637
+ value.prebuilt !== undefined &&
638
+ (value.prebuilt === null || typeof value.prebuilt !== "object")) {
639
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "prebuilt", "prebuilt must be the generated prebuilt Contracts object when provided"));
197
640
  }
198
- if (Object.hasOwn(value, "pipelines")) {
199
- validatePipelines(value.pipelines, "pipelines", diagnostics);
641
+ if (Object.hasOwn(value, "policy") && value.policy !== undefined) {
642
+ validatePolicy(value.policy, diagnostics);
200
643
  }
201
- if (Object.hasOwn(value, "transactions") &&
202
- !TRANSACTION_CAPABILITY_SET.has(value.transactions)) {
203
- diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", "transactions", 'transactions must be "none" or "interactive"'));
644
+ if (Object.hasOwn(value, "access") && value.access !== undefined) {
645
+ validateAccess(value.access, diagnostics);
646
+ if (Object.hasOwn(value, "policy") && value.policy !== undefined) {
647
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", "policy", "policy cannot be configured with access: access.policy is the policy engine, and ctx.$state.me the principal; remove policy"));
648
+ }
204
649
  }
205
650
  if (Object.hasOwn(value, "diagnostics") &&
206
651
  value.diagnostics !== undefined &&
@@ -212,11 +657,289 @@ export function validateFrameworkConfig(value) {
212
657
  typeof value.misuse !== "function") {
213
658
  diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "misuse", "misuse must be a function when provided"));
214
659
  }
215
- if (Object.hasOwn(value, "application")) {
216
- validateScope(value.application, "application", diagnostics);
217
- }
218
- if (Object.hasOwn(value, "client")) {
219
- validateScope(value.client, "client", diagnostics);
660
+ for (const overlay of ["application", "client", "agent"]) {
661
+ if (!Object.hasOwn(value, overlay)) {
662
+ continue;
663
+ }
664
+ const layer = value[overlay];
665
+ if (requireRecord(layer, overlay, diagnostics)) {
666
+ validateLayer(layer, overlay, overlay === "agent" ? "agent" : "overlay", diagnostics);
667
+ }
220
668
  }
221
669
  return diagnostics;
222
670
  }
671
+ const POLICY_PROPERTIES = new Set(["engine", "principal"]);
672
+ function validatePolicy(value, diagnostics) {
673
+ if (!isPlainRecord(value)) {
674
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "policy", "policy must be { engine, principal }"));
675
+ return;
676
+ }
677
+ for (const key of Object.keys(value)) {
678
+ if (!POLICY_PROPERTIES.has(key)) {
679
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `policy.${key}`, `unknown policy property: ${key}`));
680
+ }
681
+ }
682
+ if (!Object.hasOwn(value, "principal")) {
683
+ diagnostics.push(diagnostic("CONFIG_REQUIRED", "policy.principal", "policy.principal is required"));
684
+ }
685
+ else if (typeof value.principal !== "function") {
686
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "policy.principal", "policy.principal must be a function"));
687
+ }
688
+ if (!Object.hasOwn(value, "engine")) {
689
+ diagnostics.push(diagnostic("CONFIG_REQUIRED", "policy.engine", "policy.engine is required"));
690
+ return;
691
+ }
692
+ validatePolicyEngine(value.engine, "policy.engine", diagnostics);
693
+ }
694
+ function validateAccess(value, diagnostics) {
695
+ if (value === null || typeof value !== "object") {
696
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access", "access must be an access provider, { policy, state }"));
697
+ return;
698
+ }
699
+ const provider = value;
700
+ if (typeof provider.state !== "function") {
701
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.state", "access.state must be a function"));
702
+ }
703
+ if (provider.client !== undefined) {
704
+ validateAccessClient(provider.client, diagnostics);
705
+ }
706
+ if (provider.policy === undefined) {
707
+ diagnostics.push(diagnostic("CONFIG_REQUIRED", "access.policy", "access.policy is required"));
708
+ return;
709
+ }
710
+ validatePolicyEngine(provider.policy, "access.policy", diagnostics);
711
+ }
712
+ function validateAccessClient(value, diagnostics) {
713
+ if (value === null || typeof value !== "object") {
714
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.client", "access.client must be an object, { url, verbs }"));
715
+ return;
716
+ }
717
+ const client = value;
718
+ if (!isAccessUrl(client.url)) {
719
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", "access.client.url", 'access.client.url must be an absolute http(s) URL or a root-relative path ("/api/auth")'));
720
+ }
721
+ const verbs = client.verbs;
722
+ if (verbs === null || typeof verbs !== "object") {
723
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.client.verbs", `access.client.verbs must be an object of $access verbs (${ACCESS_VERB_NAMES.join(", ")})`));
724
+ return;
725
+ }
726
+ for (const name of ACCESS_VERB_NAMES) {
727
+ const verb = providerVerb(verbs, name);
728
+ if (verb !== undefined) {
729
+ validateAccessVerb(verb, `access.client.verbs.${name}`, diagnostics);
730
+ }
731
+ }
732
+ for (const name of Object.keys(verbs)) {
733
+ if (!isAccessVerbName(name)) {
734
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `access.client.verbs.${name}`, `access.client.verbs.${name} is not a $access verb`));
735
+ }
736
+ }
737
+ }
738
+ function validateAccessVerb(value, path, diagnostics) {
739
+ if (value === null || typeof value !== "object") {
740
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object, { method, path, args?, result, call }`));
741
+ return;
742
+ }
743
+ const verb = value;
744
+ if (verb.method !== "GET" && verb.method !== "POST") {
745
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.method`, `${path}.method must be "GET" or "POST"`));
746
+ }
747
+ if (!isAccessPath(verb.path)) {
748
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.path`, `${path}.path must be a path under access.client.url, starting with one "/"`));
749
+ }
750
+ for (const schema of ["args", "result"]) {
751
+ const given = verb[schema];
752
+ if ((schema === "result" || given !== undefined) && !isPlainRecord(given)) {
753
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${path}.${schema}`, `${path}.${schema} must be a JSON Schema object`));
754
+ }
755
+ }
756
+ if (typeof verb.call !== "function") {
757
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${path}.call`, `${path}.call must be a function`));
758
+ }
759
+ }
760
+ function validatePolicyEngine(engine, at, diagnostics) {
761
+ if (engine === null || typeof engine !== "object") {
762
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", at, `${at} must be an object`));
763
+ return;
764
+ }
765
+ const members = engine;
766
+ for (const question of ["can", "scopeOf", "fieldsOf"]) {
767
+ if (typeof members[question] !== "function") {
768
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${question}`, `${at}.${question} must be a function`));
769
+ }
770
+ }
771
+ for (const optional of ["grantsOf", "hosted"]) {
772
+ if (members[optional] !== undefined &&
773
+ typeof members[optional] !== "function") {
774
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${optional}`, `${at}.${optional} must be a function when present`));
775
+ }
776
+ }
777
+ validatePolicyLists(members.governed, at, "governed", { all: "string lists", one: "a list of strings" }, isStringList, diagnostics);
778
+ validatePolicyLists(members.paths, at, "paths", {
779
+ all: "path lists",
780
+ one: "a list of paths, each a list of strings",
781
+ }, (paths) => Array.isArray(paths) && paths.every(isStringList), diagnostics);
782
+ validatePolicyLists(members.afterChecks, at, "afterChecks", { all: "action lists", one: "a list of actions" }, isStringList, diagnostics);
783
+ validateAfterCheckActions(members.afterChecks, at, diagnostics);
784
+ if (members.unheld !== undefined && !isStringList(members.unheld)) {
785
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.unheld`, `${at}.unheld must be a list of Resource names when provided`));
786
+ }
787
+ }
788
+ function validateAfterCheckActions(lists, at, diagnostics) {
789
+ if (!isPlainRecord(lists)) {
790
+ return;
791
+ }
792
+ for (const [resource, actions] of Object.entries(lists)) {
793
+ if (!isStringList(actions)) {
794
+ continue;
795
+ }
796
+ for (const action of actions) {
797
+ if (action !== "update") {
798
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${at}.afterChecks.${resource}`, `${at}.afterChecks.${resource}: "${action}" is no action an after check runs on; only "update" is`));
799
+ }
800
+ }
801
+ }
802
+ }
803
+ function isStringList(value) {
804
+ return (Array.isArray(value) && value.every((name) => typeof name === "string"));
805
+ }
806
+ function validatePolicyLists(lists, at, list, entry, isEntry, diagnostics) {
807
+ if (lists === undefined) {
808
+ return;
809
+ }
810
+ if (!isPlainRecord(lists)) {
811
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${list}`, `${at}.${list} must be an object of ${entry.all} when provided`));
812
+ return;
813
+ }
814
+ for (const [key, value] of Object.entries(lists)) {
815
+ if (!isEntry(value)) {
816
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${list}.${key}`, `${at}.${list}.${key} must be ${entry.one}`));
817
+ }
818
+ }
819
+ }
820
+ function validateMcp(value, api, diagnostics) {
821
+ if (typeof value === "string") {
822
+ validateMcpPath(value, "mcp", api, diagnostics);
823
+ return;
824
+ }
825
+ if (!isPlainRecord(value)) {
826
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "mcp", "mcp must be a mount path or { path, authorization? }"));
827
+ return;
828
+ }
829
+ for (const key of Object.keys(value)) {
830
+ if (!MCP_PROPERTIES.has(key)) {
831
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `mcp.${key}`, `unknown mcp property: ${key}`));
832
+ }
833
+ }
834
+ if (!Object.hasOwn(value, "path")) {
835
+ diagnostics.push(diagnostic("CONFIG_REQUIRED", "mcp.path", "mcp.path is required"));
836
+ }
837
+ else if (typeof value.path !== "string") {
838
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "mcp.path", "mcp.path must be a string"));
839
+ }
840
+ else {
841
+ validateMcpPath(value.path, "mcp.path", api, diagnostics);
842
+ }
843
+ if (Object.hasOwn(value, "authorization")) {
844
+ validateMcpAuthorization(value.authorization, diagnostics);
845
+ }
846
+ }
847
+ function validateMcpPath(value, path, api, diagnostics) {
848
+ const normalized = normalizeEntrypoint(value);
849
+ if (!normalized.ok) {
850
+ diagnostics.push(mountPathRefusalDiagnostic(path, normalized.message));
851
+ return;
852
+ }
853
+ if (api === undefined) {
854
+ return;
855
+ }
856
+ if (normalized.path === api) {
857
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", path, `${path} is the mount path api already has; mount the MCP endpoint at a path of its own`));
858
+ }
859
+ else if (normalized.path.startsWith(`${api}/_`)) {
860
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", path, `${path} is inside the protocol's namespace (the "_" segments under api); mount the MCP endpoint outside it`));
861
+ }
862
+ }
863
+ function validateMcpAuthorization(value, diagnostics) {
864
+ const path = "mcp.authorization";
865
+ if (!requireRecord(value, path, diagnostics)) {
866
+ return;
867
+ }
868
+ for (const key of Object.keys(value)) {
869
+ if (!MCP_AUTHORIZATION_PROPERTIES.has(key)) {
870
+ diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `${path}.${key}`, `unknown mcp.authorization property: ${key}`));
871
+ }
872
+ }
873
+ const serversPath = `${path}.servers`;
874
+ if (!Object.hasOwn(value, "servers")) {
875
+ diagnostics.push(diagnostic("CONFIG_REQUIRED", serversPath, `${serversPath} is required`));
876
+ }
877
+ else if (!Array.isArray(value.servers)) {
878
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", serversPath, `${serversPath} must be a list of https URLs`));
879
+ }
880
+ else if (value.servers.length === 0) {
881
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", serversPath, `${serversPath} must name at least one authorization server`));
882
+ }
883
+ else {
884
+ value.servers.forEach((server, index) => {
885
+ const serverPath = `${serversPath}[${index}]`;
886
+ const refusal = authorizationServerRefusal(server, serverPath);
887
+ if (refusal !== undefined) {
888
+ diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", serverPath, refusal));
889
+ }
890
+ });
891
+ }
892
+ const verifyPath = `${path}.verify`;
893
+ if (!Object.hasOwn(value, "verify")) {
894
+ diagnostics.push(diagnostic("CONFIG_REQUIRED", verifyPath, `${verifyPath} is required`));
895
+ }
896
+ else if (typeof value.verify !== "function") {
897
+ diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", verifyPath, `${verifyPath} must be a function: token in, the caller or null out`));
898
+ }
899
+ }
900
+ const LOOPBACK_HOSTNAMES = new Set(["127.0.0.1", "[::1]"]);
901
+ const LOOPBACK_NAME = "localhost";
902
+ function authorizationServerRefusal(value, path) {
903
+ const notHttps = `${path} must be an absolute https URL`;
904
+ if (typeof value !== "string") {
905
+ return notHttps;
906
+ }
907
+ let url;
908
+ try {
909
+ url = new URL(value);
910
+ }
911
+ catch {
912
+ return notHttps;
913
+ }
914
+ const http = url.protocol === "http:";
915
+ if (!http && url.protocol !== "https:") {
916
+ return notHttps;
917
+ }
918
+ if (http &&
919
+ ((!LOOPBACK_HOSTNAMES.has(url.hostname) &&
920
+ url.hostname !== LOOPBACK_NAME) ||
921
+ url.username !== "" ||
922
+ url.password !== "")) {
923
+ return notHttps;
924
+ }
925
+ if (url.pathname.includes("//")) {
926
+ return `${path} has an empty path segment ("//"); a client can read what follows it as another host`;
927
+ }
928
+ if (url.port === "0") {
929
+ return `${path} names port 0, which no server listens on`;
930
+ }
931
+ if (url.href.includes("?") || url.href.includes("#")) {
932
+ return `${path} has a query or fragment; an authorization server's URL (its issuer) takes neither`;
933
+ }
934
+ if (!http) {
935
+ return undefined;
936
+ }
937
+ if (url.hostname === LOOPBACK_NAME) {
938
+ url.hostname = "127.0.0.1";
939
+ }
940
+ const canonical = url.href;
941
+ const short = canonical === `${url.origin}/` ? url.origin : canonical;
942
+ return value === canonical || value === short
943
+ ? undefined
944
+ : `${path} is an http loopback URL; write it as ${short}, the spelling every client reads as this machine`;
945
+ }