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

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 (242) hide show
  1. package/CHANGELOG.md +1140 -0
  2. package/README.md +224 -57
  3. package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
  4. package/dist/adapters/adapter-field.d.ts +11 -11
  5. package/dist/adapters/adapter-identifier.d.ts +6 -6
  6. package/dist/adapters/adapter-model.d.ts +9 -9
  7. package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
  8. package/dist/adapters/adapter-operation.d.ts +3 -3
  9. package/dist/adapters/adapter-resource.d.ts +18 -9
  10. package/dist/adapters/adapter-sql-statement.d.ts +19 -0
  11. package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
  12. package/dist/adapters/adapter.interface.d.ts +49 -29
  13. package/dist/avz/avz-check.factory.d.ts +83 -0
  14. package/dist/avz/avz-check.factory.js +116 -0
  15. package/dist/avz/avz-check.registry.d.ts +35 -0
  16. package/dist/avz/avz-check.registry.js +9 -0
  17. package/dist/avz/avz.d.ts +203 -0
  18. package/dist/{json → avz}/avz.js +150 -8
  19. package/dist/{json → avz}/index.d.ts +2 -1
  20. package/dist/{json → avz}/json-shape.registry.d.ts +7 -7
  21. package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
  22. package/dist/{json → avz}/zod-issue.translator.js +7 -0
  23. package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
  24. package/dist/compiler/contract.compiler.d.ts +18 -18
  25. package/dist/compiler/contract.compiler.js +548 -441
  26. package/dist/compiler/create-requirements.projector.d.ts +49 -0
  27. package/dist/compiler/create-requirements.projector.js +423 -0
  28. package/dist/compiler/field-validator.compiler.d.ts +47 -0
  29. package/dist/compiler/field-validator.compiler.js +238 -0
  30. package/dist/config/any-framework-config.d.ts +19 -12
  31. package/dist/config/config-diagnostic.d.ts +11 -4
  32. package/dist/config/config-layer.d.ts +15 -6
  33. package/dist/config/config.resolver.d.ts +74 -31
  34. package/dist/config/config.resolver.js +108 -44
  35. package/dist/config/config.validator.d.ts +7 -7
  36. package/dist/config/config.validator.js +581 -72
  37. package/dist/config/define-resource.d.ts +57 -0
  38. package/dist/config/define-resource.js +14 -0
  39. package/dist/config/effective-fields.d.ts +19 -23
  40. package/dist/config/entrypoint.normalizer.d.ts +1 -1
  41. package/dist/config/exact-framework-config.d.ts +280 -0
  42. package/dist/config/field-compute.resolver.d.ts +19 -0
  43. package/dist/config/field-compute.resolver.js +115 -0
  44. package/dist/config/field-pipeline-config.d.ts +47 -0
  45. package/dist/config/forced-operation.validator.d.ts +10 -0
  46. package/dist/config/forced-operation.validator.js +66 -0
  47. package/dist/config/framework-config.d.ts +110 -39
  48. package/dist/config/framework-exemptions-config.d.ts +91 -0
  49. package/dist/config/framework-exemptions-config.js +1 -0
  50. package/dist/config/framework-field-definition.d.ts +78 -0
  51. package/dist/config/framework-field-definition.js +28 -0
  52. package/dist/config/framework-resources-config.d.ts +116 -0
  53. package/dist/config/framework-resources-config.js +1 -0
  54. package/dist/config/pipeline-config.d.ts +56 -20
  55. package/dist/config/pipeline-tree.resolver.d.ts +79 -0
  56. package/dist/config/pipeline-tree.resolver.js +220 -0
  57. package/dist/config/stage-type.eraser.d.ts +65 -0
  58. package/dist/config/stage-type.eraser.js +1 -0
  59. package/dist/contracts/capability.d.ts +11 -11
  60. package/dist/contracts/client-contract-structure.validator.d.ts +323 -28
  61. package/dist/contracts/client-contract-structure.validator.js +152 -8
  62. package/dist/contracts/contract-canonicalizer.d.ts +19 -3
  63. package/dist/contracts/contract-canonicalizer.js +141 -28
  64. package/dist/contracts/contract-hash.d.ts +12 -7
  65. package/dist/contracts/contract-hash.js +3 -2
  66. package/dist/contracts/contract-limits.d.ts +4 -1
  67. package/dist/contracts/contract-limits.js +1 -0
  68. package/dist/contracts/contract-lookup.d.ts +5 -5
  69. package/dist/contracts/contract-protocol.d.ts +4 -4
  70. package/dist/contracts/contract.d.ts +24 -16
  71. package/dist/contracts/create-requirements.d.ts +35 -0
  72. package/dist/contracts/create-requirements.js +1 -0
  73. package/dist/contracts/enum-definition.d.ts +1 -1
  74. package/dist/contracts/field-check.d.ts +101 -0
  75. package/dist/contracts/field-check.js +1 -0
  76. package/dist/contracts/field.d.ts +52 -42
  77. package/dist/contracts/identifier.d.ts +4 -4
  78. package/dist/contracts/json-shape.d.ts +12 -1
  79. package/dist/contracts/lifecycle-trait.d.ts +2 -2
  80. package/dist/contracts/resource-operations.d.ts +28 -28
  81. package/dist/contracts/resource.d.ts +15 -9
  82. package/dist/contracts/scalar-value-type.d.ts +15 -15
  83. package/dist/contracts/scalar.d.ts +3 -3
  84. package/dist/contracts/transaction-capability.d.ts +1 -1
  85. package/dist/contracts/wire-scalar-format.d.ts +4 -4
  86. package/dist/framework/contract-view.d.ts +213 -147
  87. package/dist/framework/framework-construction.error.d.ts +10 -10
  88. package/dist/framework/framework-construction.error.js +2 -2
  89. package/dist/framework/framework.d.ts +47 -23
  90. package/dist/framework/framework.factory.d.ts +8 -6
  91. package/dist/framework/framework.factory.js +40 -20
  92. package/dist/framework/operation-facade.d.ts +123 -52
  93. package/dist/framework/operation-facade.js +9 -1
  94. package/dist/index.d.ts +55 -50
  95. package/dist/index.js +6 -6
  96. package/dist/internal.d.ts +15 -10
  97. package/dist/internal.js +3 -1
  98. package/dist/operations/operation-arguments.d.ts +267 -202
  99. package/dist/operations/operation-call.d.ts +27 -28
  100. package/dist/operations/operation-identity.d.ts +10 -10
  101. package/dist/operations/operation-result.d.ts +21 -21
  102. package/dist/operations/operation-validator-core.d.ts +6 -6
  103. package/dist/operations/operation-validator-core.js +13 -2
  104. package/dist/operations/operation-validator.d.ts +9 -9
  105. package/dist/operations/projection-scope.resolver.d.ts +6 -6
  106. package/dist/operations/structural-limits.walker.d.ts +6 -6
  107. package/dist/operations/structural-limits.walker.js +145 -0
  108. package/dist/operations/validation-code.d.ts +11 -6
  109. package/dist/operations/validation-code.js +4 -0
  110. package/dist/operations/write-scope.resolver.d.ts +6 -6
  111. package/dist/protocol/absent-route.responder.d.ts +13 -12
  112. package/dist/protocol/absent-route.responder.js +19 -19
  113. package/dist/protocol/contract-document.responder.d.ts +3 -3
  114. package/dist/protocol/contract-document.responder.js +2 -2
  115. package/dist/protocol/http-request.decoder.d.ts +17 -13
  116. package/dist/protocol/http-request.decoder.js +10 -10
  117. package/dist/protocol/http-request.reader.d.ts +3 -3
  118. package/dist/protocol/http-response.encoder.d.ts +4 -4
  119. package/dist/protocol/http-response.encoder.js +94 -55
  120. package/dist/protocol/http-status.table.d.ts +2 -2
  121. package/dist/protocol/operation-response.guard.d.ts +2 -2
  122. package/dist/protocol/protocol-surface.d.ts +4 -4
  123. package/dist/protocol/protocol.binder.d.ts +50 -27
  124. package/dist/protocol/protocol.binder.js +12 -9
  125. package/dist/protocol/protocol.handler.d.ts +22 -13
  126. package/dist/protocol/protocol.handler.js +44 -9
  127. package/dist/protocol/unmounted-route.error.d.ts +4 -4
  128. package/dist/protocol/unmounted-route.error.js +2 -2
  129. package/dist/runtime/caller-data.copier.d.ts +5 -5
  130. package/dist/runtime/caller-data.copier.js +13 -13
  131. package/dist/runtime/caller-data.door.d.ts +6 -6
  132. package/dist/runtime/caller-data.door.js +6 -4
  133. package/dist/runtime/computed-read-runtime.d.ts +7 -6
  134. package/dist/runtime/computed-read-runtime.js +61 -48
  135. package/dist/runtime/computed-value.error.d.ts +6 -6
  136. package/dist/runtime/computed-value.error.js +3 -3
  137. package/dist/runtime/context-executor.runtime.d.ts +59 -0
  138. package/dist/runtime/context-executor.runtime.js +275 -0
  139. package/dist/runtime/create-requirement.d.ts +10 -81
  140. package/dist/runtime/create-requirement.js +80 -57
  141. package/dist/runtime/decimal.d.ts +2 -2
  142. package/dist/runtime/decimal.js +1 -1
  143. package/dist/runtime/diagnostics-reporter.d.ts +53 -27
  144. package/dist/runtime/diagnostics-reporter.js +24 -0
  145. package/dist/runtime/error-boundary.d.ts +65 -8
  146. package/dist/runtime/error-boundary.js +45 -19
  147. package/dist/runtime/execution-options.d.ts +10 -2
  148. package/dist/runtime/field-check.evaluator.d.ts +29 -0
  149. package/dist/runtime/field-check.evaluator.js +521 -0
  150. package/dist/runtime/field-compute.d.ts +64 -0
  151. package/dist/runtime/field-compute.js +1 -0
  152. package/dist/runtime/field-stage.plan.d.ts +15 -0
  153. package/dist/runtime/field-stage.plan.js +27 -0
  154. package/dist/runtime/field-stage.runtime.d.ts +35 -0
  155. package/dist/runtime/field-stage.runtime.js +143 -0
  156. package/dist/runtime/field-validator.runtime.d.ts +11 -0
  157. package/dist/runtime/field-validator.runtime.js +87 -0
  158. package/dist/runtime/framework-error-class.table.d.ts +33 -0
  159. package/dist/runtime/framework-error-class.table.js +25 -0
  160. package/dist/runtime/framework-error.d.ts +68 -8
  161. package/dist/runtime/framework-error.factory.d.ts +4 -0
  162. package/dist/runtime/framework-error.factory.js +15 -0
  163. package/dist/runtime/framework-error.js +23 -2
  164. package/dist/runtime/interceptor-next.error.d.ts +5 -0
  165. package/dist/runtime/interceptor-next.error.js +6 -0
  166. package/dist/runtime/json-value.d.ts +3 -3
  167. package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
  168. package/dist/runtime/level-lifecycle.runtime.js +42 -0
  169. package/dist/runtime/misuse-reporter.d.ts +12 -12
  170. package/dist/runtime/mutation-planner.d.ts +19 -10
  171. package/dist/runtime/mutation-planner.js +54 -30
  172. package/dist/runtime/nested-write.walker.d.ts +32 -0
  173. package/dist/runtime/nested-write.walker.js +73 -0
  174. package/dist/runtime/operation-request.d.ts +33 -6
  175. package/dist/runtime/operation-response.d.ts +17 -17
  176. package/dist/runtime/operation-runtime.d.ts +113 -25
  177. package/dist/runtime/operation-runtime.js +395 -74
  178. package/dist/runtime/outcome-mapper.d.ts +16 -5
  179. package/dist/runtime/outcome-mapper.js +23 -6
  180. package/dist/runtime/output-validator.d.ts +10 -10
  181. package/dist/runtime/output-validator.js +3 -3
  182. package/dist/runtime/owned-execution.registry.d.ts +6 -6
  183. package/dist/runtime/pipe-output.validator.d.ts +33 -18
  184. package/dist/runtime/pipe-output.validator.js +12 -12
  185. package/dist/runtime/pipeline.d.ts +196 -34
  186. package/dist/runtime/readonly-value.d.ts +32 -0
  187. package/dist/runtime/readonly-value.js +141 -0
  188. package/dist/runtime/request-envelope.validator.d.ts +3 -3
  189. package/dist/runtime/request-envelope.validator.js +12 -7
  190. package/dist/runtime/request-id.d.ts +1 -1
  191. package/dist/runtime/request-state.d.ts +14 -0
  192. package/dist/runtime/request-state.js +1 -0
  193. package/dist/runtime/request-state.resolver.d.ts +12 -0
  194. package/dist/runtime/request-state.resolver.js +20 -0
  195. package/dist/runtime/scalar-runtime.d.ts +31 -16
  196. package/dist/runtime/scalar-runtime.js +16 -18
  197. package/dist/transactions/deferred-operation.d.ts +35 -20
  198. package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
  199. package/dist/transactions/operation-arguments-encoder.js +2 -2
  200. package/dist/transactions/sql-statement.d.ts +77 -0
  201. package/dist/transactions/sql-statement.js +47 -0
  202. package/dist/transactions/sql-statement.validator.d.ts +44 -0
  203. package/dist/transactions/sql-statement.validator.js +134 -0
  204. package/dist/transactions/transaction-envelope.d.ts +4 -4
  205. package/dist/transactions/transaction-integrity-error.d.ts +6 -6
  206. package/dist/transactions/transaction-integrity-error.js +5 -2
  207. package/dist/transactions/transaction-plan-assembler.d.ts +21 -11
  208. package/dist/transactions/transaction-plan-assembler.js +148 -34
  209. package/dist/transactions/transaction-plan-validator.d.ts +29 -20
  210. package/dist/transactions/transaction-plan-validator.js +70 -38
  211. package/dist/transactions/transaction-reference-collector.d.ts +5 -5
  212. package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
  213. package/dist/transactions/transaction-reference-resolver.js +26 -14
  214. package/dist/transactions/transaction-reference-validator.d.ts +34 -4
  215. package/dist/transactions/transaction-reference-validator.js +58 -26
  216. package/dist/transactions/transaction-reference.d.ts +13 -13
  217. package/dist/transactions/transaction-request.d.ts +18 -5
  218. package/dist/transactions/transaction-response.d.ts +6 -6
  219. package/dist/transactions/transaction-runtime.d.ts +8 -7
  220. package/dist/transactions/transaction-runtime.js +166 -50
  221. package/dist/transactions/transaction-settlement.runtime.d.ts +51 -0
  222. package/dist/transactions/transaction-settlement.runtime.js +120 -0
  223. package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
  224. package/dist/transactions/transaction-slot-path-error.js +2 -2
  225. package/dist/transactions/transaction-slot-writer.js +2 -2
  226. package/dist/transactions/transaction-stage.runtime.d.ts +81 -0
  227. package/dist/transactions/transaction-stage.runtime.js +123 -0
  228. package/package.json +6 -5
  229. package/src/runtime/field-check.evaluator.ts +720 -0
  230. package/dist/config/define-fields.d.ts +0 -42
  231. package/dist/config/define-fields.js +0 -3
  232. package/dist/config/framework-behaviors-config.d.ts +0 -30
  233. package/dist/config/framework-fields-config.d.ts +0 -42
  234. package/dist/config/framework-restrictions-config.d.ts +0 -142
  235. package/dist/json/avz.d.ts +0 -96
  236. package/dist/runtime/field-behavior.d.ts +0 -48
  237. /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
  238. /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
  239. /package/dist/{json → avz}/index.js +0 -0
  240. /package/dist/{json → avz}/json-shape.registry.js +0 -0
  241. /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
  242. /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
@@ -0,0 +1,238 @@
1
+ import { avzCheckOf, } from "../avz/avz-check.registry.js";
2
+ import { FIELD_CHECK_SUBJECTS, } from "../runtime/field-check.evaluator.js";
3
+ function isRecord(value) {
4
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5
+ }
6
+ function own(record, key) {
7
+ return Object.hasOwn(record, key) ? record[key] : undefined;
8
+ }
9
+ function scalarOf(field) {
10
+ const type = field.type;
11
+ return typeof type?.scalar === "string" ? type.scalar : undefined;
12
+ }
13
+ function subjectOf(field) {
14
+ const scalar = scalarOf(field);
15
+ return scalar === undefined ? undefined : own(FIELD_CHECK_SUBJECTS, scalar);
16
+ }
17
+ function describeField(field) {
18
+ const scalar = scalarOf(field) ?? "enum";
19
+ const noun = `${scalar}${field.list === true ? " list" : ""} field`;
20
+ return `${/^[aeiou]/.test(scalar) ? "an" : "a"} ${noun}`;
21
+ }
22
+ function describeCheck(check) {
23
+ switch (check.check) {
24
+ case "less_than":
25
+ return check.inclusive ? "AvZ.lte" : "AvZ.lt";
26
+ case "greater_than":
27
+ return check.inclusive ? "AvZ.gte" : "AvZ.gt";
28
+ case "multiple_of":
29
+ return "AvZ.multipleOf";
30
+ case "max_length":
31
+ return check.list === true ? "AvZ.maxItems" : "AvZ.maxLength";
32
+ case "min_length":
33
+ return check.list === true ? "AvZ.minItems" : "AvZ.minLength";
34
+ case "length_equals":
35
+ return "AvZ.length";
36
+ case "string_format":
37
+ return `a string format check (${check.format})`;
38
+ case "max_size":
39
+ return "AvZ.maxSize";
40
+ case "min_size":
41
+ return "AvZ.minSize";
42
+ case "size_equals":
43
+ return "AvZ.size";
44
+ }
45
+ }
46
+ function boundFor(value, subject, multiple) {
47
+ switch (subject) {
48
+ case "number":
49
+ return typeof value === "number"
50
+ ? { value }
51
+ : { fault: "an int or float field's bound is a number" };
52
+ case "decimal":
53
+ return value instanceof Date
54
+ ? { fault: "a decimal field's bound is a number or a bigint" }
55
+ : { value: String(value) };
56
+ case "bigint":
57
+ return typeof value === "bigint" ||
58
+ (typeof value === "number" && Number.isSafeInteger(value))
59
+ ? { value: String(value) }
60
+ : { fault: "a bigint field's bound is a bigint" };
61
+ case "datetime":
62
+ return multiple
63
+ ? { fault: "a datetime takes bounds, not multiples" }
64
+ : value instanceof Date
65
+ ? { value: value.toISOString() }
66
+ : { fault: "a datetime field's bound is a Date" };
67
+ default:
68
+ return {
69
+ fault: "bounds apply to number, bigint, decimal and datetime fields",
70
+ };
71
+ }
72
+ }
73
+ function compileCheck(check, field) {
74
+ const subject = subjectOf(field);
75
+ switch (check.check) {
76
+ case "less_than":
77
+ case "greater_than":
78
+ case "multiple_of": {
79
+ const written = boundFor(check.value, subject, check.check === "multiple_of");
80
+ if ("fault" in written) {
81
+ return written;
82
+ }
83
+ return {
84
+ check: check.check === "multiple_of"
85
+ ? { check: "multiple_of", value: written.value }
86
+ : {
87
+ check: check.check,
88
+ value: written.value,
89
+ inclusive: check.inclusive,
90
+ },
91
+ };
92
+ }
93
+ case "max_length":
94
+ case "min_length":
95
+ if (check.list === true) {
96
+ return field.list === true
97
+ ? { check }
98
+ : {
99
+ fault: "AvZ.minItems and AvZ.maxItems check a list's length; the field is not a list",
100
+ };
101
+ }
102
+ return subject === "string"
103
+ ? { check }
104
+ : { fault: "length checks apply to string fields" };
105
+ case "length_equals":
106
+ case "string_format":
107
+ return subject === "string"
108
+ ? { check }
109
+ : { fault: "string checks apply to string fields" };
110
+ case "max_size":
111
+ case "min_size":
112
+ case "size_equals":
113
+ return subject === "bytes"
114
+ ? { check }
115
+ : { fault: "size checks apply to bytes fields" };
116
+ }
117
+ }
118
+ function label(resource, field) {
119
+ return `${resource}.${field}`;
120
+ }
121
+ export function checkLayerValidators(resources, layer, tree, diagnostics) {
122
+ if (!isRecord(tree)) {
123
+ return;
124
+ }
125
+ for (const [resourceName, entry] of Object.entries(tree)) {
126
+ const resource = own(resources, resourceName);
127
+ if (resource === undefined || !isRecord(entry) || !isRecord(entry.fields)) {
128
+ continue;
129
+ }
130
+ for (const [fieldName, fieldEntry] of Object.entries(entry.fields)) {
131
+ const field = own(resource.fields, fieldName);
132
+ if (field === undefined ||
133
+ !isRecord(fieldEntry) ||
134
+ !isRecord(fieldEntry.pipelines) ||
135
+ !Object.hasOwn(fieldEntry.pipelines, "validators")) {
136
+ continue;
137
+ }
138
+ const path = `${layer}.resources.${resourceName}.fields.${fieldName}.pipelines.validators`;
139
+ const refuse = (at, message) => diagnostics.push({
140
+ code: "COMPILER_INVALID_VALIDATOR",
141
+ path: at,
142
+ message,
143
+ });
144
+ if (field.kind === "relation") {
145
+ refuse(path, `relation field "${label(resourceName, fieldName)}" takes write guards only; validators check a scalar field's value`);
146
+ continue;
147
+ }
148
+ if (scalarOf(field) === "json") {
149
+ refuse(path, `field "${label(resourceName, fieldName)}" is a Json field: Json fields carry their checks in definition.json (AvZ.string().check(AvZ.maxLength(80)), …)`);
150
+ continue;
151
+ }
152
+ const validators = fieldEntry.pipelines.validators;
153
+ if (!Array.isArray(validators)) {
154
+ continue;
155
+ }
156
+ for (const [index, value] of validators.entries()) {
157
+ const at = `${path}[${index}]`;
158
+ const check = avzCheckOf(value);
159
+ if (check === undefined) {
160
+ refuse(at, `field "${label(resourceName, fieldName)}": a validator must be a check built with AvZ from "@aventara/core/avz" (AvZ.maxLength(80), AvZ.email(), …); a Zod check or any other value is not accepted`);
161
+ continue;
162
+ }
163
+ const compiled = compileCheck(check, field);
164
+ if ("fault" in compiled) {
165
+ refuse(at, `${describeCheck(check)} does not fit field "${label(resourceName, fieldName)}", ${describeField(field)}: ${compiled.fault}`);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+ export function compileValidatorTable(resources, tree) {
172
+ const table = {};
173
+ for (const [resourceName, pipelines] of Object.entries(tree.resources)) {
174
+ const resource = own(resources, resourceName);
175
+ if (resource === undefined) {
176
+ continue;
177
+ }
178
+ for (const [fieldName, field] of Object.entries(resource.fields)) {
179
+ const stages = own(pipelines.fields, fieldName);
180
+ if (stages === undefined ||
181
+ field.kind !== "scalar" ||
182
+ scalarOf(field) === "json" ||
183
+ stages.validators.length === 0) {
184
+ continue;
185
+ }
186
+ const checks = stages.validators.flatMap((value) => {
187
+ const check = avzCheckOf(value);
188
+ const compiled = check === undefined ? undefined : compileCheck(check, field);
189
+ return compiled !== undefined && "check" in compiled
190
+ ? [compiled.check]
191
+ : [];
192
+ });
193
+ if (checks.length > 0) {
194
+ table[resourceName] ??= {};
195
+ table[resourceName][fieldName] = {
196
+ checks,
197
+ subject: subjectOf(field),
198
+ list: field.list === true,
199
+ };
200
+ }
201
+ }
202
+ }
203
+ return table;
204
+ }
205
+ export function applyValidators(resources, table) {
206
+ for (const [resourceName, fields] of Object.entries(table)) {
207
+ const resource = own(resources, resourceName);
208
+ for (const [fieldName, compiled] of Object.entries(fields)) {
209
+ const field = resource === undefined ? undefined : own(resource.fields, fieldName);
210
+ if (field !== undefined && field.kind === "scalar") {
211
+ field.validators = compiled.checks.map((check) => ({ ...check }));
212
+ }
213
+ }
214
+ }
215
+ }
216
+ const tables = new WeakMap();
217
+ export function bindFieldValidators(contract, table) {
218
+ tables.set(contract, table);
219
+ }
220
+ const shaped = new WeakMap();
221
+ function hasShapedField(contract) {
222
+ let found = shaped.get(contract);
223
+ if (found === undefined) {
224
+ found = Object.values(contract.resources).some((resource) => Object.values(resource.fields).some((field) => field.kind === "scalar" && field.json !== undefined));
225
+ shaped.set(contract, found);
226
+ }
227
+ return found;
228
+ }
229
+ export function hasFieldValidators(contract) {
230
+ const table = tables.get(contract);
231
+ return ((table !== undefined && Object.keys(table).length > 0) ||
232
+ hasShapedField(contract));
233
+ }
234
+ const NO_FIELDS = Object.freeze({});
235
+ export function validatedFieldsOf(contract, resource) {
236
+ const table = tables.get(contract);
237
+ return (table === undefined ? undefined : own(table, resource)) ?? NO_FIELDS;
238
+ }
@@ -1,19 +1,26 @@
1
- /** A `fields` block whose resource and field names are both unconstrained. */
2
- export type AnyFieldsBlock = Readonly<Record<string, Readonly<Record<string, unknown>> | undefined>>;
3
- /** The widest scope overlay: a `fields` block, and anything else. */
4
- export type AnyScopeConfig = {
1
+ /**
2
+ * A `resources` block whose Resource and field names are both unconstrained:
3
+ * each Resource entry may carry a `fields` record of any names.
4
+ */
5
+ export type AvConfigResourcesAny = Readonly<Record<string, {
5
6
  readonly [key: string]: unknown;
6
- readonly fields?: AnyFieldsBlock;
7
+ readonly fields?: Readonly<Record<string, unknown>> | undefined;
8
+ } | undefined>>;
9
+ /** The widest layer overlay: a `resources` block, and anything else. */
10
+ export type AvConfigLayerAny = {
11
+ readonly [key: string | symbol]: unknown;
12
+ readonly resources?: AvConfigResourcesAny;
7
13
  };
8
14
  /**
9
- * The widest configuration type: every resource admits every field name. It
10
- * is the default `Cfg` of `FrameworkConfig`, `Framework` and
15
+ * The widest configuration type: every Resource admits every field name. It
16
+ * is the default `Cfg` of `AvConfig`, `AvFramework` and
11
17
  * `createFramework`; pass your own configuration's type instead to get field
12
18
  * names checked.
13
19
  */
14
- export type AnyFrameworkConfig = {
15
- readonly [key: string]: unknown;
16
- readonly fields?: AnyFieldsBlock;
17
- readonly application?: AnyScopeConfig;
18
- readonly client?: AnyScopeConfig;
20
+ export type AvConfigAny = {
21
+ readonly [key: string | symbol]: unknown;
22
+ readonly resources?: AvConfigResourcesAny;
23
+ readonly application?: AvConfigLayerAny;
24
+ readonly client?: AvConfigLayerAny;
25
+ readonly agent?: AvConfigLayerAny;
19
26
  };
@@ -1,8 +1,15 @@
1
- /** Codes of {@link ConfigDiagnostic}. */
2
- export type ConfigDiagnosticCode = "CONFIG_REQUIRED" | "CONFIG_UNKNOWN_PROPERTY" | "CONFIG_INVALID_TYPE" | "CONFIG_INVALID_VALUE";
1
+ /** Codes of {@link AvConfigDiagnostic}. */
2
+ export type AvConfigDiagnosticCode = "CONFIG_REQUIRED" | "CONFIG_UNKNOWN_PROPERTY" | "CONFIG_INVALID_TYPE" | "CONFIG_INVALID_VALUE"
3
+ /** An rc.0 key that moved in rc.1; the message names where it lives now. */
4
+ | "CONFIG_MOVED_PROPERTY"
5
+ /**
6
+ * A key only the root may hold, written in `application`, `client` or `agent`: a field's
7
+ * `definition` is the root's, and an overlay only chooses its visibility.
8
+ */
9
+ | "CONFIG_FORBIDDEN_IN_OVERLAY";
3
10
  /** One problem found in a configuration, at its path. */
4
- export type ConfigDiagnostic = {
5
- readonly code: ConfigDiagnosticCode;
11
+ export type AvConfigDiagnostic = {
12
+ readonly code: AvConfigDiagnosticCode;
6
13
  readonly path: string;
7
14
  readonly message: string;
8
15
  };
@@ -1,12 +1,21 @@
1
1
  /**
2
2
  * One layer of the configuration: `root` is the configuration's own top level
3
3
  * and compiles to the Core Contract; `application` and `client` are overlays
4
- * on top of it and compile to the Application and Client Contracts.
4
+ * on top of it and compile to the Application and Client Contracts; `agent`
5
+ * narrows the layer it extends and compiles to the Agent Contract.
5
6
  */
6
- export type ConfigLayer = "root" | "application" | "client";
7
+ export type AvConfigLayerName = "root" | "application" | "client" | "agent";
7
8
  /**
8
- * The layers a request can come from: `application` (in-process calls) or
9
- * `client` (remote calls). Each sees the root configuration plus its own
10
- * overlay.
9
+ * The layers a request can come from: `application` (in-process calls),
10
+ * `client` (remote calls) or `agent` (calls an AI agent makes over MCP). Each
11
+ * sees the root configuration plus its own layer, and `agent` the layer it
12
+ * extends between the two.
11
13
  */
12
- export type RequestOrigin = Exclude<ConfigLayer, "root">;
14
+ export type AvRequestOrigin = Exclude<AvConfigLayerName, "root">;
15
+ /**
16
+ * The layer the `agent` layer starts from (its `extends`): its final view is
17
+ * the agent's parent, and its pipelines run before the agent's.
18
+ */
19
+ export type AvConfigAgentParent = Exclude<AvConfigLayerName, "agent">;
20
+ /** The origins whose requests carry a protocol identity: remote callers. */
21
+ export type RemoteRequestOrigin = Exclude<AvRequestOrigin, "application">;
@@ -1,38 +1,81 @@
1
- import type { Adapter } from "../adapters/adapter.interface.js";
2
- import type { AdapterModel } from "../adapters/adapter-model.js";
3
- import type { TransactionCapability } from "../contracts/transaction-capability.js";
4
- import type { FrameworkDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
5
- import type { FrameworkMisuseSink } from "../runtime/misuse-reporter.js";
6
- import type { FrameworkBehaviorsConfig } from "./framework-behaviors-config.js";
7
- import type { FrameworkConfig, FrameworkLimitsConfig } from "./framework-config.js";
8
- import type { FrameworkFieldsConfig } from "./framework-fields-config.js";
9
- import type { FrameworkRestrictionsConfig } from "./framework-restrictions-config.js";
10
- import type { ResolvedPipelineConfig } from "./pipeline-config.js";
11
- /** One resolved layer of the configuration: root, application or client. */
12
- export type ResolvedFrameworkScopeConfig<M extends AdapterModel = AdapterModel> = {
13
- readonly fields: FrameworkFieldsConfig<M> | undefined;
14
- /** The behaviors configuration, with Resource and field keys as plain strings. */
15
- readonly behaviors: FrameworkBehaviorsConfig | undefined;
16
- readonly restrictions: FrameworkRestrictionsConfig<M> | undefined;
17
- readonly limits: FrameworkLimitsConfig | undefined;
18
- readonly pipelines: ResolvedPipelineConfig;
19
- readonly transactions: TransactionCapability | undefined;
1
+ import type { AvAdapter } from "../adapters/adapter.interface.js";
2
+ import type { AvAdapterModel } from "../adapters/adapter-model.js";
3
+ import type { AvTransactionCapability } from "../contracts/transaction-capability.js";
4
+ import type { AvDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
5
+ import type { AvMisuseSink } from "../runtime/misuse-reporter.js";
6
+ import type { AvConfigAgentParent } from "./config-layer.js";
7
+ import { type ResolvedComputeConfig } from "./field-compute.resolver.js";
8
+ import type { AvConfig, AvConfigLimits } from "./framework-config.js";
9
+ import type { AvConfigFieldDefinition } from "./framework-field-definition.js";
10
+ import { type ResolvedPipelineTree } from "./pipeline-tree.resolver.js";
11
+ /** The root's field definitions, by Resource and field name. */
12
+ export type ResolvedFieldDefinitions = Readonly<Record<string, Readonly<Record<string, AvConfigFieldDefinition>>>>;
13
+ /** One resolved layer of the configuration: root, application, client or agent. */
14
+ export type ResolvedFrameworkLayerConfig = {
15
+ /** The compute stages that run for this layer's operations, chained root first. */
16
+ readonly compute: ResolvedComputeConfig;
17
+ /**
18
+ * Whether this layer's exemptions hide (`true`, the root's default) or grant
19
+ * (`false`); `undefined` for an overlay that states none, which keeps the
20
+ * root's view.
21
+ */
22
+ readonly exposed: boolean | undefined;
23
+ /** This layer's own `exemptions`, as authored; the compiler checks every name. */
24
+ readonly exemptions: unknown;
25
+ readonly limits: AvConfigLimits | undefined;
26
+ /**
27
+ * Every stage that runs for this layer's operations, level by level: the root's
28
+ * registrations, then the overlay's, at each level.
29
+ */
30
+ readonly pipelines: ResolvedPipelineTree;
31
+ readonly transactionsStyle: AvTransactionCapability | undefined;
32
+ };
33
+ /**
34
+ * The MCP endpoint a Framework serves (`mcp` resolved): its mount path in
35
+ * canonical form, and the authorization its callers present, when it has one.
36
+ */
37
+ export type AvMcpEndpoint = {
38
+ /** The mount path in its canonical form, as `framework.api` is. */
39
+ readonly path: string;
40
+ readonly authorization?: {
41
+ readonly servers: readonly string[];
42
+ readonly verify: (token: string) => unknown | null | Promise<unknown | null>;
43
+ };
44
+ };
45
+ /** The agent layer resolved: a layer, and the layer it extends. */
46
+ export type ResolvedAgentLayerConfig = ResolvedFrameworkLayerConfig & {
47
+ /** The layer whose final view the agent narrows (`extends`; `"client"` when left out). */
48
+ readonly parent: AvConfigAgentParent;
49
+ /** Whether the configuration states `agent` or `mcp`. */
50
+ readonly stated: boolean;
20
51
  };
21
52
  /** A configuration after defaults and overlays are resolved, before compilation. */
22
- export type ResolvedFrameworkConfig<M extends AdapterModel = AdapterModel> = {
53
+ export type ResolvedFrameworkConfig<M extends AvAdapterModel = AvAdapterModel> = {
23
54
  /**
24
- * The mount path in its canonical form: `""` at the root, otherwise
25
- * `/seg(/seg)*`.
55
+ * The protocol's mount path (`api`) in its canonical form: `""` at the
56
+ * root, otherwise `/seg(/seg)*`.
26
57
  */
27
- readonly entrypoint: string;
28
- readonly adapter: Adapter<M>;
58
+ readonly api: string;
59
+ /** The MCP endpoint, when `mcp` turns it on. */
60
+ readonly mcp: AvMcpEndpoint | undefined;
61
+ readonly adapter: AvAdapter<M>;
29
62
  /** The diagnostics sink, from the root configuration only. */
30
- readonly diagnostics: FrameworkDiagnosticsSink | undefined;
63
+ readonly diagnostics: AvDiagnosticsSink | undefined;
31
64
  /** The misuse sink, from the root configuration only. */
32
- readonly misuse: FrameworkMisuseSink | undefined;
33
- readonly root: ResolvedFrameworkScopeConfig<M>;
34
- readonly application: ResolvedFrameworkScopeConfig<M>;
35
- readonly client: ResolvedFrameworkScopeConfig<M>;
65
+ readonly misuse: AvMisuseSink | undefined;
66
+ /** Every field definition, from the root only; the same for all three layers. */
67
+ readonly definitions: ResolvedFieldDefinitions;
68
+ /** Each layer's `resources` tree as authored: the compiler checks its names. */
69
+ readonly trees: {
70
+ readonly root: unknown;
71
+ readonly application: unknown;
72
+ readonly client: unknown;
73
+ readonly agent: unknown;
74
+ };
75
+ readonly root: ResolvedFrameworkLayerConfig;
76
+ readonly application: ResolvedFrameworkLayerConfig;
77
+ readonly client: ResolvedFrameworkLayerConfig;
78
+ readonly agent: ResolvedAgentLayerConfig;
36
79
  };
37
- /** Resolve root, application, and client configuration without compiling Contracts. */
38
- export declare function resolveFrameworkConfig<M extends AdapterModel>(config: FrameworkConfig<M>): ResolvedFrameworkConfig<M>;
80
+ /** Resolve every layer of the configuration without compiling Contracts. */
81
+ export declare function resolveFrameworkConfig<M extends AvAdapterModel>(config: AvConfig<M>): ResolvedFrameworkConfig<M>;
@@ -1,6 +1,8 @@
1
- import { FrameworkConstructionError } from "../framework/framework-construction.error.js";
2
- import { entrypointRefusalDiagnostic } from "./config.validator.js";
1
+ import { AvConstructionError } from "../framework/framework-construction.error.js";
2
+ import { mountPathRefusalDiagnostic } from "./config.validator.js";
3
3
  import { normalizeEntrypoint } from "./entrypoint.normalizer.js";
4
+ import { chainCompute, computeOfLayer, } from "./field-compute.resolver.js";
5
+ import { resolvePipelineTree, } from "./pipeline-tree.resolver.js";
4
6
  const hasOwn = (value, key) => Object.hasOwn(value, key);
5
7
  function isPlainRecord(value) {
6
8
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
@@ -39,7 +41,7 @@ function resolveRecord(root, scoped) {
39
41
  }
40
42
  return result;
41
43
  }
42
- function resolveProperty(root, scoped, key) {
44
+ function resolveOverride(root, scoped, key) {
43
45
  if (scoped === undefined || !hasOwn(scoped, key)) {
44
46
  return cloneConfigValue(root[key]);
45
47
  }
@@ -49,63 +51,125 @@ function resolveProperty(root, scoped, key) {
49
51
  ? resolveRecord(rootValue, scopedValue)
50
52
  : cloneConfigValue(scopedValue);
51
53
  }
52
- function resolvePipelines(root, scoped) {
54
+ function resolveLayer(root, rootCompute, overlay, scoped) {
53
55
  return {
54
- guards: [...(root?.guards ?? []), ...(scoped?.guards ?? [])],
55
- pipes: [...(root?.pipes ?? []), ...(scoped?.pipes ?? [])],
56
- hooks: {
57
- before: [
58
- ...(root?.hooks?.before ?? []),
59
- ...(scoped?.hooks?.before ?? []),
60
- ],
61
- after: [...(root?.hooks?.after ?? []), ...(scoped?.hooks?.after ?? [])],
62
- },
63
- interceptors: [
64
- ...(root?.interceptors ?? []),
65
- ...(scoped?.interceptors ?? []),
66
- ],
67
- filters: [...(root?.filters ?? []), ...(scoped?.filters ?? [])],
56
+ compute: scoped === undefined
57
+ ? rootCompute
58
+ : chainCompute(rootCompute, computeOfLayer(scoped.resources)),
59
+ exposed: overlay
60
+ ? scoped?.exposed
61
+ : (root.exposed ?? true),
62
+ exemptions: overlay ? scoped?.exemptions : root.exemptions,
63
+ limits: resolveOverride(root, scoped, "limits"),
64
+ transactionsStyle: resolveOverride(root, scoped, "transactionsStyle"),
65
+ pipelines: scoped === undefined
66
+ ? resolvePipelineTree([root])
67
+ : resolvePipelineTree([root, scoped]),
68
68
  };
69
69
  }
70
- function resolveScope(root, scoped) {
70
+ function resolveAgentLayer(root, parentName, parentOverlay, parent, agent, stated) {
71
+ const effective = {
72
+ limits: parent.limits,
73
+ transactionsStyle: parent.transactionsStyle,
74
+ };
75
+ const chain = [root];
76
+ if (parentName !== "root" && parentOverlay !== undefined) {
77
+ chain.push(parentOverlay);
78
+ }
79
+ if (agent !== undefined) {
80
+ chain.push(agent);
81
+ }
71
82
  return {
72
- fields: resolveProperty(root, scoped, "fields"),
73
- behaviors: resolveProperty(root, scoped, "behaviors"),
74
- restrictions: resolveProperty(root, scoped, "restrictions"),
75
- limits: resolveProperty(root, scoped, "limits"),
76
- transactions: resolveProperty(root, scoped, "transactions"),
77
- pipelines: resolvePipelines(root.pipelines, scoped?.pipelines),
83
+ parent: parentName,
84
+ stated,
85
+ compute: agent === undefined
86
+ ? parent.compute
87
+ : chainCompute(parent.compute, computeOfLayer(agent.resources)),
88
+ exposed: agent?.exposed,
89
+ exemptions: agent?.exemptions,
90
+ limits: resolveOverride(effective, agent, "limits"),
91
+ transactionsStyle: resolveOverride(effective, agent, "transactionsStyle"),
92
+ pipelines: resolvePipelineTree(chain),
78
93
  };
79
94
  }
80
- function resolveEntrypoint(entrypoint) {
81
- const normalized = normalizeEntrypoint(entrypoint);
95
+ function definitionsOf(resources) {
96
+ const result = {};
97
+ if (!isPlainRecord(resources)) {
98
+ return result;
99
+ }
100
+ for (const [resourceName, resource] of Object.entries(resources)) {
101
+ if (!isPlainRecord(resource) || !isPlainRecord(resource.fields)) {
102
+ continue;
103
+ }
104
+ for (const [fieldName, field] of Object.entries(resource.fields)) {
105
+ if (!isPlainRecord(field) || field.definition === undefined) {
106
+ continue;
107
+ }
108
+ result[resourceName] ??= {};
109
+ result[resourceName][fieldName] =
110
+ field.definition;
111
+ }
112
+ }
113
+ return result;
114
+ }
115
+ function resolveMountPath(value, path) {
116
+ const normalized = normalizeEntrypoint(value);
82
117
  if (!normalized.ok) {
83
- throw new FrameworkConstructionError("configuration", [
84
- entrypointRefusalDiagnostic(normalized.message),
118
+ throw new AvConstructionError("configuration", [
119
+ mountPathRefusalDiagnostic(path, normalized.message),
85
120
  ]);
86
121
  }
87
122
  return normalized.path;
88
123
  }
124
+ function resolveMcp(mcp) {
125
+ if (mcp === undefined) {
126
+ return undefined;
127
+ }
128
+ if (typeof mcp === "string") {
129
+ return Object.freeze({ path: resolveMountPath(mcp, "mcp") });
130
+ }
131
+ const path = resolveMountPath(mcp.path, "mcp.path");
132
+ const authorization = mcp.authorization;
133
+ return Object.freeze(authorization === undefined
134
+ ? { path }
135
+ : {
136
+ path,
137
+ authorization: Object.freeze({
138
+ servers: Object.freeze([...authorization.servers]),
139
+ verify: authorization.verify,
140
+ }),
141
+ });
142
+ }
89
143
  export function resolveFrameworkConfig(config) {
90
- const root = {
91
- ...(hasOwn(config, "fields") ? { fields: config.fields } : {}),
92
- ...(hasOwn(config, "behaviors") ? { behaviors: config.behaviors } : {}),
93
- ...(hasOwn(config, "restrictions")
94
- ? { restrictions: config.restrictions }
95
- : {}),
96
- ...(hasOwn(config, "limits") ? { limits: config.limits } : {}),
97
- ...(hasOwn(config, "pipelines") ? { pipelines: config.pipelines } : {}),
98
- ...(hasOwn(config, "transactions")
99
- ? { transactions: config.transactions }
100
- : {}),
144
+ const root = config;
145
+ const application = config.application;
146
+ const client = config.client;
147
+ const agent = config.agent;
148
+ const rootCompute = computeOfLayer(root.resources);
149
+ const layers = {
150
+ root: resolveLayer(root, rootCompute, false),
151
+ application: resolveLayer(root, rootCompute, true, application),
152
+ client: resolveLayer(root, rootCompute, true, client),
101
153
  };
154
+ const parent = agent?.extends ?? "client";
102
155
  return {
103
- entrypoint: resolveEntrypoint(config.entrypoint),
156
+ api: resolveMountPath(config.api, "api"),
157
+ mcp: resolveMcp(config.mcp),
104
158
  adapter: config.adapter,
105
159
  diagnostics: config.diagnostics,
106
160
  misuse: config.misuse,
107
- root: resolveScope(root),
108
- application: resolveScope(root, config.application),
109
- client: resolveScope(root, config.client),
161
+ definitions: definitionsOf(root.resources),
162
+ trees: {
163
+ root: root.resources,
164
+ application: application?.resources,
165
+ client: client?.resources,
166
+ agent: agent?.resources,
167
+ },
168
+ ...layers,
169
+ agent: resolveAgentLayer(root, parent, parent === "application"
170
+ ? application
171
+ : parent === "client"
172
+ ? client
173
+ : undefined, layers[parent], agent, agent !== undefined || config.mcp !== undefined),
110
174
  };
111
175
  }
@@ -1,12 +1,12 @@
1
- import type { ConfigDiagnostic } from "./config-diagnostic.js";
1
+ import type { AvConfigDiagnostic } from "./config-diagnostic.js";
2
2
  /**
3
- * The refusal of an entrypoint whose mount path is not canonical, from the
4
- * normalizer's message: it names the defect and the rule — never the value, which may
5
- * carry credentials.
3
+ * The refusal of a mount path (`api`, `mcp`, `mcp.path`) that is not canonical,
4
+ * from the normalizer's message: it names the defect and the rule — never the
5
+ * value, which may carry credentials.
6
6
  */
7
- export declare function entrypointRefusalDiagnostic(message: string): ConfigDiagnostic;
7
+ export declare function mountPathRefusalDiagnostic(path: string, message: string): AvConfigDiagnostic;
8
8
  /**
9
9
  * Checks the structure of a configuration object and reports each problem as
10
- * a {@link ConfigDiagnostic}.
10
+ * a {@link AvConfigDiagnostic}.
11
11
  */
12
- export declare function validateFrameworkConfig(value: unknown): readonly ConfigDiagnostic[];
12
+ export declare function validateFrameworkConfig(value: unknown): readonly AvConfigDiagnostic[];