@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
@@ -1,16 +1,14 @@
1
1
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
- import { ComputedValueError } from "./computed-value.error.js";
2
+ import { AvComputedValueError } from "./computed-value.error.js";
3
3
  import { normalizeScalarFieldValue } from "./scalar-runtime.js";
4
4
  function isRecord(value) {
5
5
  return value !== null && typeof value === "object" && !Array.isArray(value);
6
6
  }
7
- function readBehavior(value) {
7
+ function readCompute(value) {
8
8
  if (typeof value === "function") {
9
9
  return { compute: value, dependsOn: [] };
10
10
  }
11
- if (value === undefined ||
12
- value === false ||
13
- typeof value.compute !== "function") {
11
+ if (value === undefined || typeof value.compute !== "function") {
14
12
  return undefined;
15
13
  }
16
14
  return {
@@ -18,6 +16,16 @@ function readBehavior(value) {
18
16
  dependsOn: value.dependsOn ?? [],
19
17
  };
20
18
  }
19
+ function storedScalar(model, resource, field) {
20
+ const resources = model.resources;
21
+ const fields = Object.hasOwn(resources, resource)
22
+ ? resources[resource]?.fields
23
+ : undefined;
24
+ const entry = fields !== undefined && Object.hasOwn(fields, field)
25
+ ? fields[field]
26
+ : undefined;
27
+ return isRecord(entry) && entry.kind === "scalar";
28
+ }
21
29
  function appendUnique(values, value) {
22
30
  if (!values.includes(value)) {
23
31
  values.push(value);
@@ -34,18 +42,17 @@ function supportsProjection(request) {
34
42
  }
35
43
  return request.variant !== "count";
36
44
  }
37
- function addScalarProjection(core, active, behaviors, resourceName, fieldName, adapterSelect, requested, computed) {
45
+ function addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed) {
38
46
  const activeField = lookupField(lookupResource(active, resourceName), fieldName);
39
47
  if (activeField?.kind !== "scalar") {
40
48
  return;
41
49
  }
42
50
  appendUnique(requested, fieldName);
43
- const behavior = readBehavior(behaviors?.[resourceName]?.fields[fieldName]?.read);
44
- if (behavior !== undefined) {
51
+ const stage = readCompute(compute?.[resourceName]?.[fieldName]?.read);
52
+ if (stage !== undefined) {
45
53
  appendUnique(computed, fieldName);
46
- for (const dependency of behavior.dependsOn) {
47
- const dependencyField = lookupField(lookupResource(core, resourceName), dependency);
48
- if (dependencyField?.kind === "scalar") {
54
+ for (const dependency of stage.dependsOn) {
55
+ if (storedScalar(model, resourceName, dependency)) {
49
56
  appendUniqueProjection(adapterSelect, dependency);
50
57
  }
51
58
  }
@@ -70,7 +77,7 @@ function projectionEntry(entry) {
70
77
  function withoutProjectionChoice(value) {
71
78
  return Object.fromEntries(Object.entries(value).filter(([key]) => key !== "select" && key !== "include"));
72
79
  }
73
- function defaultProjectionLevel(core, active, behaviors, resourceName) {
80
+ function defaultProjectionLevel(core, model, active, compute, resourceName) {
74
81
  const activeResource = lookupResource(active, resourceName);
75
82
  const adapterSelect = [];
76
83
  const requested = [];
@@ -80,7 +87,7 @@ function defaultProjectionLevel(core, active, behaviors, resourceName) {
80
87
  if (field.kind !== "scalar" || field.capabilities.select !== true) {
81
88
  continue;
82
89
  }
83
- addScalarProjection(core, active, behaviors, resourceName, fieldName, adapterSelect, requested, computed);
90
+ addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed);
84
91
  }
85
92
  }
86
93
  return {
@@ -94,25 +101,25 @@ function defaultProjectionLevel(core, active, behaviors, resourceName) {
94
101
  },
95
102
  };
96
103
  }
97
- function planRelationProjection(core, active, behaviors, field, value) {
104
+ function planRelationProjection(core, model, active, compute, field, value) {
98
105
  if (!isRecord(value)) {
99
- return defaultProjectionLevel(core, active, behaviors, field.target);
106
+ return defaultProjectionLevel(core, model, active, compute, field.target);
100
107
  }
101
108
  if (Array.isArray(value.select)) {
102
- return planSelectLevel(core, active, behaviors, field.target, value.select, true);
109
+ return planSelectLevel(core, model, active, compute, field.target, value.select, true);
103
110
  }
104
111
  if (Array.isArray(value.include)) {
105
- return planIncludeLevel(core, active, behaviors, field.target, value.include);
112
+ return planIncludeLevel(core, model, active, compute, field.target, value.include);
106
113
  }
107
- return defaultProjectionLevel(core, active, behaviors, field.target);
114
+ return defaultProjectionLevel(core, model, active, compute, field.target);
108
115
  }
109
- function planRelationEntry(core, active, behaviors, resourceName, fieldName, value) {
116
+ function planRelationEntry(core, model, active, compute, resourceName, fieldName, value) {
110
117
  const activeField = lookupField(lookupResource(active, resourceName), fieldName);
111
118
  const coreField = lookupField(lookupResource(core, resourceName), fieldName);
112
119
  if (activeField?.kind !== "relation" || coreField?.kind !== "relation") {
113
120
  return undefined;
114
121
  }
115
- const nested = planRelationProjection(core, active, behaviors, coreField, value);
122
+ const nested = planRelationProjection(core, model, active, compute, coreField, value);
116
123
  return {
117
124
  adapterEntry: {
118
125
  [fieldName]: {
@@ -127,7 +134,7 @@ function planRelationEntry(core, active, behaviors, resourceName, fieldName, val
127
134
  },
128
135
  };
129
136
  }
130
- function planSelectLevel(core, active, behaviors, resourceName, select, collectReducers = false) {
137
+ function planSelectLevel(core, model, active, compute, resourceName, select, collectReducers = false) {
131
138
  const activeResource = lookupResource(active, resourceName);
132
139
  const coreResource = lookupResource(core, resourceName);
133
140
  const adapterSelect = [];
@@ -159,11 +166,11 @@ function planSelectLevel(core, active, behaviors, resourceName, select, collectR
159
166
  const activeField = lookupField(activeResource, entry);
160
167
  const coreField = lookupField(coreResource, entry);
161
168
  if (activeField?.kind === "scalar") {
162
- addScalarProjection(core, active, behaviors, resourceName, entry, adapterSelect, requested, computed);
169
+ addScalarProjection(core, model, active, compute, resourceName, entry, adapterSelect, requested, computed);
163
170
  continue;
164
171
  }
165
172
  if (activeField?.kind === "relation" && coreField?.kind === "relation") {
166
- const plannedRelation = planRelationEntry(core, active, behaviors, resourceName, entry, undefined);
173
+ const plannedRelation = planRelationEntry(core, model, active, compute, resourceName, entry, undefined);
167
174
  if (plannedRelation !== undefined) {
168
175
  appendUnique(requested, entry);
169
176
  adapterSelect.push(plannedRelation.adapterEntry);
@@ -180,7 +187,7 @@ function planSelectLevel(core, active, behaviors, resourceName, select, collectR
180
187
  continue;
181
188
  }
182
189
  const [fieldName, nestedValue] = relationEntry;
183
- const plannedRelation = planRelationEntry(core, active, behaviors, resourceName, fieldName, nestedValue);
190
+ const plannedRelation = planRelationEntry(core, model, active, compute, resourceName, fieldName, nestedValue);
184
191
  if (plannedRelation === undefined) {
185
192
  adapterSelect.push(entry);
186
193
  continue;
@@ -194,15 +201,15 @@ function planSelectLevel(core, active, behaviors, resourceName, select, collectR
194
201
  plan: { resource: resourceName, requested, computed, relations, reducers },
195
202
  };
196
203
  }
197
- function planIncludeLevel(core, active, behaviors, resourceName, include) {
198
- const defaults = defaultProjectionLevel(core, active, behaviors, resourceName);
204
+ function planIncludeLevel(core, model, active, compute, resourceName, include) {
205
+ const defaults = defaultProjectionLevel(core, model, active, compute, resourceName);
199
206
  const adapterSelect = [...defaults.select];
200
207
  const requested = [...defaults.plan.requested];
201
208
  const computed = [...defaults.plan.computed];
202
209
  const relations = [];
203
210
  for (const entry of include) {
204
211
  if (typeof entry === "string") {
205
- const plannedRelation = planRelationEntry(core, active, behaviors, resourceName, entry, undefined);
212
+ const plannedRelation = planRelationEntry(core, model, active, compute, resourceName, entry, undefined);
206
213
  if (plannedRelation === undefined) {
207
214
  continue;
208
215
  }
@@ -216,7 +223,7 @@ function planIncludeLevel(core, active, behaviors, resourceName, include) {
216
223
  continue;
217
224
  }
218
225
  const [fieldName, nestedValue] = relationEntry;
219
- const plannedRelation = planRelationEntry(core, active, behaviors, resourceName, fieldName, nestedValue);
226
+ const plannedRelation = planRelationEntry(core, model, active, compute, resourceName, fieldName, nestedValue);
220
227
  if (plannedRelation === undefined) {
221
228
  continue;
222
229
  }
@@ -241,7 +248,7 @@ function replaceWithInternalSelect(args, select) {
241
248
  internal.select = select;
242
249
  return internal;
243
250
  }
244
- export function planReadOperation(core, active, behaviors, request, args) {
251
+ export function planReadOperation(core, model, active, compute, request, args) {
245
252
  if (!isRecord(args) || !supportsProjection(request)) {
246
253
  return { arguments: args, projection: undefined, materialize: false };
247
254
  }
@@ -251,7 +258,7 @@ export function planReadOperation(core, active, behaviors, request, args) {
251
258
  return { arguments: args, projection: undefined, materialize: false };
252
259
  }
253
260
  if (Array.isArray(args.select)) {
254
- const planned = planSelectLevel(core, active, behaviors, request.resource, args.select);
261
+ const planned = planSelectLevel(core, model, active, compute, request.resource, args.select);
255
262
  return {
256
263
  arguments: replaceWithInternalSelect(args, planned.select),
257
264
  projection: planned.plan,
@@ -259,21 +266,21 @@ export function planReadOperation(core, active, behaviors, request, args) {
259
266
  };
260
267
  }
261
268
  if (Array.isArray(args.include)) {
262
- const planned = planIncludeLevel(core, active, behaviors, request.resource, args.include);
269
+ const planned = planIncludeLevel(core, model, active, compute, request.resource, args.include);
263
270
  return {
264
271
  arguments: replaceWithInternalSelect(args, planned.select),
265
272
  projection: planned.plan,
266
273
  materialize: true,
267
274
  };
268
275
  }
269
- const defaults = defaultProjectionLevel(core, active, behaviors, request.resource);
276
+ const defaults = defaultProjectionLevel(core, model, active, compute, request.resource);
270
277
  return {
271
278
  arguments: { ...args, select: defaults.select },
272
279
  projection: defaults.plan,
273
280
  materialize: defaults.plan.computed.length > 0,
274
281
  };
275
282
  }
276
- async function materializeRelation(active, behaviors, request, relation, value, contextFactory) {
283
+ async function materializeRelation(active, compute, request, relation, value, contextFactory) {
277
284
  if (value === null || value === undefined) {
278
285
  return value;
279
286
  }
@@ -281,11 +288,11 @@ async function materializeRelation(active, behaviors, request, relation, value,
281
288
  if (!Array.isArray(value)) {
282
289
  return value;
283
290
  }
284
- return Promise.all(value.map((entry) => materializeRecord(active, behaviors, request, relation.projection, entry, contextFactory)));
291
+ return Promise.all(value.map((entry) => materializeRecord(active, compute, request, relation.projection, entry, contextFactory)));
285
292
  }
286
- return materializeRecord(active, behaviors, request, relation.projection, value, contextFactory);
293
+ return materializeRecord(active, compute, request, relation.projection, value, contextFactory);
287
294
  }
288
- async function materializeRecord(active, behaviors, request, plan, value, contextFactory) {
295
+ async function materializeRecord(active, compute, request, plan, value, contextFactory) {
289
296
  if (!isRecord(value)) {
290
297
  return value;
291
298
  }
@@ -296,24 +303,30 @@ async function materializeRecord(active, behaviors, request, plan, value, contex
296
303
  const record = { ...value };
297
304
  for (const fieldName of plan.computed) {
298
305
  const field = lookupField(resource, fieldName);
299
- const behavior = readBehavior(behaviors?.[plan.resource]?.fields[fieldName]?.read);
300
- if (field?.kind !== "scalar" || behavior === undefined) {
306
+ const stage = readCompute(compute?.[plan.resource]?.[fieldName]?.read);
307
+ if (field?.kind !== "scalar" || stage === undefined) {
301
308
  continue;
302
309
  }
303
- const computedValue = await behavior.compute({
304
- origin: request.origin,
305
- resource: plan.resource,
310
+ const computedValue = await stage.compute({
306
311
  field: fieldName,
307
312
  value: record[fieldName],
308
313
  record,
309
- operation: contextFactory(),
314
+ ctx: contextFactory(),
310
315
  });
311
316
  if (computedValue === undefined) {
312
317
  continue;
313
318
  }
314
- const validation = normalizeScalarFieldValue(active, field, computedValue, "runtime", ["behaviors", plan.resource, fieldName, "read"]);
319
+ const validation = normalizeScalarFieldValue(active, field, computedValue, "runtime", [
320
+ "resources",
321
+ plan.resource,
322
+ "fields",
323
+ fieldName,
324
+ "pipelines",
325
+ "compute",
326
+ "read",
327
+ ]);
315
328
  if (!validation.ok) {
316
- throw new ComputedValueError(plan.resource, fieldName, "read", validation.issues);
329
+ throw new AvComputedValueError(plan.resource, fieldName, "read", validation.issues);
317
330
  }
318
331
  record[fieldName] = validation.value;
319
332
  }
@@ -321,19 +334,19 @@ async function materializeRecord(active, behaviors, request, plan, value, contex
321
334
  if (!Object.hasOwn(record, relation.field)) {
322
335
  continue;
323
336
  }
324
- record[relation.field] = await materializeRelation(active, behaviors, request, relation, record[relation.field], contextFactory);
337
+ record[relation.field] = await materializeRelation(active, compute, request, relation, record[relation.field], contextFactory);
325
338
  }
326
339
  return Object.fromEntries(plan.requested
327
340
  .filter((fieldName) => Object.hasOwn(record, fieldName))
328
341
  .map((fieldName) => [fieldName, record[fieldName]]));
329
342
  }
330
- export async function materializeReadOperation(active, behaviors, request, plan, value, contextFactory) {
343
+ export async function materializeReadOperation(active, compute, request, plan, value, contextFactory) {
331
344
  const projection = plan.projection;
332
345
  if (!plan.materialize || projection === undefined) {
333
346
  return value;
334
347
  }
335
348
  if (Array.isArray(value)) {
336
- return Promise.all(value.map((entry) => materializeRecord(active, behaviors, request, projection, entry, contextFactory)));
349
+ return Promise.all(value.map((entry) => materializeRecord(active, compute, request, projection, entry, contextFactory)));
337
350
  }
338
- return materializeRecord(active, behaviors, request, projection, value, contextFactory);
351
+ return materializeRecord(active, compute, request, projection, value, contextFactory);
339
352
  }
@@ -1,13 +1,13 @@
1
- import type { ValidationIssue } from "../operations/validation-code.js";
1
+ import type { AvValidationIssue } from "../operations/validation-code.js";
2
2
  /**
3
3
  * What the diagnostics channel receives when a computed value — a read or write
4
- * behavior's return — is one its Contract refuses: the developer's broken code,
4
+ * compute stage's return — is one its Contract refuses: the developer's broken code,
5
5
  * never the caller's. It is thrown, not a deliberate outcome, so the framework's
6
6
  * boundary answers the caller the generic `A3000` and reports this error, with the
7
7
  * issues, exactly once.
8
8
  */
9
- export declare class ComputedValueError extends Error {
10
- readonly issues: readonly ValidationIssue[];
11
- readonly name = "ComputedValueError";
12
- constructor(resource: string, field: string, stage: "read" | "create" | "update", issues: readonly ValidationIssue[]);
9
+ export declare class AvComputedValueError extends Error {
10
+ readonly issues: readonly AvValidationIssue[];
11
+ readonly name = "AvComputedValueError";
12
+ constructor(resource: string, field: string, stage: "read" | "create" | "update", issues: readonly AvValidationIssue[]);
13
13
  }
@@ -1,9 +1,9 @@
1
- export class ComputedValueError extends Error {
1
+ export class AvComputedValueError extends Error {
2
2
  issues;
3
- name = "ComputedValueError";
3
+ name = "AvComputedValueError";
4
4
  constructor(resource, field, stage, issues) {
5
5
  const [first] = issues;
6
- super(`The ${stage} behavior of ${resource}.${field} returned a value its Contract refuses${first === undefined ? "." : ` (${first.code}: ${first.message})`}`);
6
+ super(`The compute.${stage} stage of ${resource}.${field} returned a value its Contract refuses${first === undefined ? "." : ` (${first.code}: ${first.message})`}`);
7
7
  this.issues = issues;
8
8
  }
9
9
  }
@@ -0,0 +1,59 @@
1
+ import type { AvAdapter } from "../adapters/adapter.interface.js";
2
+ import type { AvAdapterModel } from "../adapters/adapter-model.js";
3
+ import type { AvAdapterTransactionExecutor } from "../adapters/adapter-transaction-executor.interface.js";
4
+ import type { AvRequestOrigin } from "../config/config-layer.js";
5
+ import type { AvContract } from "../contracts/contract.js";
6
+ import type { AvOperationFamily } from "../operations/operation-identity.js";
7
+ import { type AvDiagnosticsSink } from "./diagnostics-reporter.js";
8
+ import type { AvComputeContext } from "./field-compute.js";
9
+ import type { MisuseReporter } from "./misuse-reporter.js";
10
+ import type { ApplicationOperationRequest } from "./operation-request.js";
11
+ import type { AvOperationResponse } from "./operation-response.js";
12
+ import type { AvContext, AvTransactionContext, AvTransportContext } from "./pipeline.js";
13
+ import type { AvState } from "./request-state.js";
14
+ /** Where a ctx's calls run: inside the open transaction, or standalone. */
15
+ export type ExecutorScope<M extends AvAdapterModel = AvAdapterModel> = {
16
+ /** The request id every call of this ctx carries: its stage's request's. */
17
+ readonly requestId: string;
18
+ /** The open transaction's executor; `undefined` outside any transaction. */
19
+ readonly transaction: AvAdapterTransactionExecutor<M> | undefined;
20
+ /** The request's state, which every call of this ctx inherits. */
21
+ readonly state: AvState;
22
+ };
23
+ /** The `$` facts a ctx states, as own data properties. */
24
+ export type ContextFacts = {
25
+ readonly $origin: AvRequestOrigin;
26
+ readonly $requestId: string;
27
+ readonly $transport?: AvTransportContext;
28
+ readonly $contract: AvContract;
29
+ readonly $operation?: {
30
+ readonly resource: string;
31
+ readonly family: AvOperationFamily;
32
+ readonly variant: string;
33
+ readonly nested?: true;
34
+ };
35
+ readonly $args: unknown;
36
+ };
37
+ /** Runs one raw application-origin call in `transaction`, or standalone. Total. */
38
+ export type RawOperationRunner<M extends AvAdapterModel> = (request: ApplicationOperationRequest, transaction: AvAdapterTransactionExecutor<M> | undefined) => Promise<AvOperationResponse>;
39
+ export type ContextExecutorDependencies<M extends AvAdapterModel> = {
40
+ /** The model, as construction read it once: the ctx's Resources. */
41
+ readonly model: M;
42
+ readonly adapter: AvAdapter<M>;
43
+ /** The Application Contract: a `ctx.$transaction` needs its transactions. */
44
+ readonly application: AvContract;
45
+ readonly diagnostics: AvDiagnosticsSink | undefined;
46
+ readonly misuse: MisuseReporter;
47
+ readonly run: RawOperationRunner<M>;
48
+ };
49
+ /** Builds the ctx every stage is told. */
50
+ export type ContextExecutor<M extends AvAdapterModel = AvAdapterModel> = {
51
+ /** An operation stage's ctx: its facts and the full executor. */
52
+ readonly operation: (scope: ExecutorScope<M>, facts: ContextFacts) => AvContext;
53
+ /** A Resource transaction stage's ctx: the plan as `$args`, the full executor. */
54
+ readonly transaction: (scope: ExecutorScope<M>, facts: ContextFacts) => AvTransactionContext;
55
+ /** Compute's read-only ctx: the facts, and `find.*` reads only. */
56
+ readonly compute: (scope: ExecutorScope<M>, facts: ContextFacts) => AvComputeContext;
57
+ };
58
+ /** Builds the ctx factory of one Framework over its model. */
59
+ export declare function createContextExecutor<M extends AvAdapterModel>(dependencies: ContextExecutorDependencies<M>): ContextExecutor<M>;
@@ -0,0 +1,275 @@
1
+ import { isOperationVariantAvailable } from "../contracts/resource-operations.js";
2
+ import { parseOperationIdentity } from "../operations/operation-identity.js";
3
+ import { validationIssue } from "../operations/validation-code.js";
4
+ import { readSqlTemplate } from "../transactions/sql-statement.js";
5
+ import { normalizeSqlValue } from "../transactions/sql-statement.validator.js";
6
+ import { AvTransactionIntegrityError } from "../transactions/transaction-integrity-error.js";
7
+ import { transactionInfrastructureFailure } from "../transactions/transaction-response.js";
8
+ import { copyAtDoor, refuseCallerData } from "./caller-data.door.js";
9
+ import { createReporter, } from "./diagnostics-reporter.js";
10
+ import { AdapterBoundary, sanitizeOperationFailure } from "./error-boundary.js";
11
+ import { thrownFailure } from "./framework-error.factory.js";
12
+ import { operationFailure } from "./operation-response.js";
13
+ import { mapValidationOutcome } from "./outcome-mapper.js";
14
+ import { readonlyView } from "./readonly-value.js";
15
+ const COMPUTE_STATE = "Compute's ctx.$state";
16
+ const STATE = Symbol("aventara.context");
17
+ const READ_FAMILY = "find";
18
+ function readOnlyRefusal(member) {
19
+ return new TypeError(`Compute's ctx is read-only: ${member} is not available in a compute stage. Put effects on other rows in an after hook.`);
20
+ }
21
+ function refusedStatement(issues) {
22
+ return mapValidationOutcome(issues);
23
+ }
24
+ function unavailable(message) {
25
+ return operationFailure("A2002", {
26
+ message,
27
+ issues: [validationIssue("V1006", [], message)],
28
+ });
29
+ }
30
+ export function createContextExecutor(dependencies) {
31
+ const { adapter, misuse } = dependencies;
32
+ const model = dependencies.model;
33
+ const stateOf = (context) => context[STATE];
34
+ const reporterOf = (scope) => createReporter(dependencies.diagnostics, {
35
+ kind: "transaction",
36
+ origin: "application",
37
+ requestId: scope.requestId,
38
+ });
39
+ const call = async (scope, resource, identity, args) => {
40
+ const response = await dependencies.run({
41
+ ...identity,
42
+ origin: "application",
43
+ resource,
44
+ requestId: scope.requestId,
45
+ state: scope.state,
46
+ arguments: args === undefined ? {} : args,
47
+ }, scope.transaction);
48
+ if (response.cause !== null) {
49
+ throw thrownFailure(response);
50
+ }
51
+ return response.data;
52
+ };
53
+ const resourceTree = (scope, resource, readOnly) => {
54
+ const families = {};
55
+ const operations = model.resources[resource]?.operations ?? {};
56
+ for (const [family, variants] of Object.entries(operations)) {
57
+ if (readOnly && family !== READ_FAMILY) {
58
+ continue;
59
+ }
60
+ const leaves = {};
61
+ for (const [variant, availability] of Object.entries(variants ?? {})) {
62
+ const identity = parseOperationIdentity(family, variant);
63
+ if (identity !== undefined &&
64
+ isOperationVariantAvailable(availability)) {
65
+ leaves[variant] = (args) => call(scope, resource, identity, args);
66
+ }
67
+ }
68
+ families[family] = Object.freeze(leaves);
69
+ }
70
+ if (readOnly) {
71
+ const tree = Object.create(Object.prototype);
72
+ for (const [family, leaves] of Object.entries(families)) {
73
+ Object.defineProperty(tree, family, {
74
+ value: leaves,
75
+ enumerable: true,
76
+ });
77
+ }
78
+ for (const family of Object.keys(operations)) {
79
+ if (family === READ_FAMILY) {
80
+ continue;
81
+ }
82
+ Object.defineProperty(tree, family, {
83
+ get() {
84
+ throw readOnlyRefusal(`ctx.${resource}.${family}`);
85
+ },
86
+ enumerable: false,
87
+ });
88
+ }
89
+ return Object.freeze(tree);
90
+ }
91
+ return Object.freeze(families);
92
+ };
93
+ const statementOf = (strings, values) => {
94
+ if (adapter.sqlStatements !== true) {
95
+ return {
96
+ ok: false,
97
+ response: unavailable("SQL statements are not available on this Adapter."),
98
+ };
99
+ }
100
+ const text = readSqlTemplate(strings, values.length);
101
+ if (text === undefined) {
102
+ return {
103
+ ok: false,
104
+ response: refusedStatement([
105
+ validationIssue("V1001", ["strings"], "SQL must be written as a tagged template: ctx.$sql`…`."),
106
+ ]),
107
+ };
108
+ }
109
+ const copy = copyAtDoor([...values]);
110
+ if (!copy.ok) {
111
+ return {
112
+ ok: false,
113
+ response: refusedStatement([
114
+ refuseCallerData(copy.error, ["values"], { origin: "application" }, misuse),
115
+ ]),
116
+ };
117
+ }
118
+ const bound = [];
119
+ const issues = [];
120
+ for (const [position, value] of copy.value.entries()) {
121
+ const normalized = normalizeSqlValue(value, ["values", position]);
122
+ if (normalized.ok) {
123
+ bound.push(normalized.value);
124
+ }
125
+ else {
126
+ issues.push(...normalized.issues);
127
+ }
128
+ }
129
+ if (issues.length > 0) {
130
+ return { ok: false, response: refusedStatement(issues) };
131
+ }
132
+ return { ok: true, statement: { strings: text, values: bound } };
133
+ };
134
+ const executeStatement = async (runner, inTransaction, statement, report) => {
135
+ if (inTransaction && typeof runner.executeSql !== "function") {
136
+ const error = new AvTransactionIntegrityError("statement-unavailable");
137
+ report(error, "A3002");
138
+ throw thrownFailure(transactionInfrastructureFailure());
139
+ }
140
+ const boundary = new AdapterBoundary();
141
+ try {
142
+ return await boundary.execute(async () => {
143
+ if (typeof runner.executeSql !== "function") {
144
+ throw new TypeError("Adapter declares sqlStatements but has no executeSql.");
145
+ }
146
+ const rows = await runner.executeSql(statement);
147
+ if (!Array.isArray(rows)) {
148
+ throw new TypeError("Adapter executeSql must resolve the statement's rows as an array.");
149
+ }
150
+ return [...rows];
151
+ });
152
+ }
153
+ catch (error) {
154
+ throw thrownFailure(sanitizeOperationFailure(error, boundary.originOf(error), report, {
155
+ path: ["values"],
156
+ arguments: statement.values,
157
+ }));
158
+ }
159
+ };
160
+ const openTransaction = async (scope, work) => {
161
+ if (typeof adapter.transaction !== "function") {
162
+ throw thrownFailure(unavailable("Transactions are not available on this Adapter."));
163
+ }
164
+ let thrown;
165
+ try {
166
+ return await adapter.transaction(async (executor) => {
167
+ try {
168
+ return await work(executor);
169
+ }
170
+ catch (error) {
171
+ thrown = { error };
172
+ throw error;
173
+ }
174
+ });
175
+ }
176
+ catch (error) {
177
+ if (thrown !== undefined && error === thrown.error) {
178
+ throw error;
179
+ }
180
+ reporterOf(scope)(error, "A3002");
181
+ throw thrownFailure(transactionInfrastructureFailure());
182
+ }
183
+ };
184
+ const sql = async (scope, strings, values) => {
185
+ const prepared = statementOf(strings, values);
186
+ if (!prepared.ok) {
187
+ throw thrownFailure(prepared.response);
188
+ }
189
+ const report = reporterOf(scope);
190
+ const open = scope.transaction;
191
+ return open !== undefined
192
+ ? executeStatement(open, true, prepared.statement, report)
193
+ : executeStatement(adapter, false, prepared.statement, report);
194
+ };
195
+ const contextOf = (prototype, scope, facts, readOnly = false) => {
196
+ const context = Object.create(prototype);
197
+ Object.defineProperty(context, STATE, {
198
+ value: { scope, facts, resources: new Map() },
199
+ });
200
+ for (const [key, value] of Object.entries(facts)) {
201
+ if (value !== undefined) {
202
+ Object.defineProperty(context, key, { value, enumerable: true });
203
+ }
204
+ }
205
+ Object.defineProperty(context, "$state", {
206
+ value: readOnly ? readonlyView(scope.state, COMPUTE_STATE) : scope.state,
207
+ enumerable: true,
208
+ });
209
+ return context;
210
+ };
211
+ const transactionOf = (prototype) => (context, work) => {
212
+ const { scope, facts } = stateOf(context);
213
+ if (typeof work !== "function") {
214
+ return Promise.reject(new TypeError("ctx.$transaction takes an async callback: (tx) => …"));
215
+ }
216
+ const run = work;
217
+ if (scope.transaction !== undefined) {
218
+ return (async () => run(context))();
219
+ }
220
+ if (dependencies.application.transactions === "none") {
221
+ return Promise.reject(thrownFailure(unavailable("Transactions are not available on the application Contract.")));
222
+ }
223
+ return openTransaction(scope, (executor) => run(contextOf(prototype, {
224
+ requestId: scope.requestId,
225
+ transaction: executor,
226
+ state: scope.state,
227
+ }, facts)));
228
+ };
229
+ const prototypeOf = (readOnly) => {
230
+ const prototype = {};
231
+ for (const resource of Object.keys(model.resources)) {
232
+ Object.defineProperty(prototype, resource, {
233
+ get() {
234
+ const state = stateOf(this);
235
+ let tree = state.resources.get(resource);
236
+ if (tree === undefined) {
237
+ tree = resourceTree(state.scope, resource, readOnly);
238
+ state.resources.set(resource, tree);
239
+ }
240
+ return tree;
241
+ },
242
+ });
243
+ }
244
+ if (readOnly) {
245
+ for (const member of ["$sql", "$transaction"]) {
246
+ Object.defineProperty(prototype, member, {
247
+ get() {
248
+ throw readOnlyRefusal(`ctx.${member}`);
249
+ },
250
+ });
251
+ }
252
+ return Object.freeze(prototype);
253
+ }
254
+ const transaction = transactionOf(prototype);
255
+ Object.defineProperty(prototype, "$sql", {
256
+ get() {
257
+ const { scope } = stateOf(this);
258
+ return (strings, ...values) => sql(scope, strings, values);
259
+ },
260
+ });
261
+ Object.defineProperty(prototype, "$transaction", {
262
+ get() {
263
+ return (work) => transaction(this, work);
264
+ },
265
+ });
266
+ return Object.freeze(prototype);
267
+ };
268
+ const full = prototypeOf(false);
269
+ const reads = prototypeOf(true);
270
+ return {
271
+ operation: (scope, facts) => contextOf(full, scope, facts),
272
+ transaction: (scope, facts) => contextOf(full, scope, facts),
273
+ compute: (scope, facts) => contextOf(reads, scope, facts, true),
274
+ };
275
+ }