@aventara/core 0.1.0-pilot.4 → 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 (255) hide show
  1. package/CHANGELOG.md +1478 -0
  2. package/README.md +275 -11
  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 +17 -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 -25
  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/avz/avz.js +354 -0
  19. package/dist/avz/index.d.ts +7 -0
  20. package/dist/avz/index.js +1 -0
  21. package/dist/avz/json-shape.registry.d.ts +22 -0
  22. package/dist/avz/json-shape.registry.js +16 -0
  23. package/dist/avz/zod-issue.translator.d.ts +57 -0
  24. package/dist/avz/zod-issue.translator.js +149 -0
  25. package/dist/compiler/contract-compiler-diagnostic.d.ts +37 -5
  26. package/dist/compiler/contract.compiler.d.ts +18 -18
  27. package/dist/compiler/contract.compiler.js +595 -421
  28. package/dist/compiler/create-requirements.projector.d.ts +49 -0
  29. package/dist/compiler/create-requirements.projector.js +423 -0
  30. package/dist/compiler/field-validator.compiler.d.ts +47 -0
  31. package/dist/compiler/field-validator.compiler.js +238 -0
  32. package/dist/config/any-framework-config.d.ts +19 -12
  33. package/dist/config/config-diagnostic.d.ts +11 -4
  34. package/dist/config/config-layer.d.ts +15 -6
  35. package/dist/config/config.resolver.d.ts +75 -29
  36. package/dist/config/config.resolver.js +109 -44
  37. package/dist/config/config.validator.d.ts +7 -7
  38. package/dist/config/config.validator.js +586 -71
  39. package/dist/config/define-resource.d.ts +57 -0
  40. package/dist/config/define-resource.js +14 -0
  41. package/dist/config/effective-fields.d.ts +19 -23
  42. package/dist/config/entrypoint.normalizer.d.ts +1 -1
  43. package/dist/config/exact-framework-config.d.ts +280 -0
  44. package/dist/config/field-compute.resolver.d.ts +19 -0
  45. package/dist/config/field-compute.resolver.js +115 -0
  46. package/dist/config/field-pipeline-config.d.ts +47 -0
  47. package/dist/config/forced-operation.validator.d.ts +10 -0
  48. package/dist/config/forced-operation.validator.js +66 -0
  49. package/dist/config/framework-config.d.ts +111 -37
  50. package/dist/config/framework-exemptions-config.d.ts +91 -0
  51. package/dist/config/framework-exemptions-config.js +1 -0
  52. package/dist/config/framework-field-definition.d.ts +78 -0
  53. package/dist/config/framework-field-definition.js +28 -0
  54. package/dist/config/framework-resources-config.d.ts +116 -0
  55. package/dist/config/framework-resources-config.js +1 -0
  56. package/dist/config/pipeline-config.d.ts +56 -20
  57. package/dist/config/pipeline-tree.resolver.d.ts +79 -0
  58. package/dist/config/pipeline-tree.resolver.js +220 -0
  59. package/dist/config/stage-type.eraser.d.ts +65 -0
  60. package/dist/config/stage-type.eraser.js +1 -0
  61. package/dist/contracts/capability.d.ts +11 -11
  62. package/dist/contracts/client-contract-structure.validator.d.ts +344 -29
  63. package/dist/contracts/client-contract-structure.validator.js +248 -7
  64. package/dist/contracts/contract-canonicalizer.d.ts +19 -3
  65. package/dist/contracts/contract-canonicalizer.js +172 -27
  66. package/dist/contracts/contract-hash.d.ts +12 -7
  67. package/dist/contracts/contract-hash.js +3 -2
  68. package/dist/contracts/contract-limits.d.ts +4 -1
  69. package/dist/contracts/contract-limits.js +1 -0
  70. package/dist/contracts/contract-lookup.d.ts +5 -5
  71. package/dist/contracts/contract-protocol.d.ts +4 -4
  72. package/dist/contracts/contract.d.ts +31 -16
  73. package/dist/contracts/create-requirements.d.ts +35 -0
  74. package/dist/contracts/create-requirements.js +1 -0
  75. package/dist/contracts/enum-definition.d.ts +1 -1
  76. package/dist/contracts/field-check.d.ts +101 -0
  77. package/dist/contracts/field-check.js +1 -0
  78. package/dist/contracts/field.d.ts +61 -41
  79. package/dist/contracts/identifier.d.ts +4 -4
  80. package/dist/contracts/json-shape.d.ts +76 -0
  81. package/dist/contracts/json-shape.js +1 -0
  82. package/dist/contracts/lifecycle-trait.d.ts +2 -2
  83. package/dist/contracts/reference-write-limit.d.ts +7 -0
  84. package/dist/contracts/reference-write-limit.js +1 -0
  85. package/dist/contracts/resource-operations.d.ts +28 -28
  86. package/dist/contracts/resource.d.ts +15 -9
  87. package/dist/contracts/scalar-value-type.d.ts +25 -14
  88. package/dist/contracts/scalar.d.ts +3 -3
  89. package/dist/contracts/transaction-capability.d.ts +1 -1
  90. package/dist/contracts/wire-scalar-format.d.ts +4 -4
  91. package/dist/framework/contract-view.d.ts +234 -63
  92. package/dist/framework/framework-construction.error.d.ts +10 -10
  93. package/dist/framework/framework-construction.error.js +2 -2
  94. package/dist/framework/framework.d.ts +50 -24
  95. package/dist/framework/framework.factory.d.ts +8 -6
  96. package/dist/framework/framework.factory.js +95 -32
  97. package/dist/framework/operation-facade.d.ts +123 -52
  98. package/dist/framework/operation-facade.js +9 -1
  99. package/dist/index.d.ts +55 -82
  100. package/dist/index.js +6 -26
  101. package/dist/internal.d.ts +40 -0
  102. package/dist/internal.js +18 -0
  103. package/dist/operations/operation-arguments.d.ts +316 -201
  104. package/dist/operations/operation-call.d.ts +27 -28
  105. package/dist/operations/operation-identity.d.ts +12 -10
  106. package/dist/operations/operation-identity.js +3 -0
  107. package/dist/operations/operation-result.d.ts +21 -21
  108. package/dist/operations/operation-validator-core.d.ts +6 -6
  109. package/dist/operations/operation-validator-core.js +41 -12
  110. package/dist/operations/operation-validator.d.ts +24 -9
  111. package/dist/operations/operation-validator.js +26 -10
  112. package/dist/operations/projection-scope.resolver.d.ts +7 -7
  113. package/dist/operations/structural-limits.walker.d.ts +19 -0
  114. package/dist/operations/structural-limits.walker.js +489 -0
  115. package/dist/operations/validation-code.d.ts +11 -6
  116. package/dist/operations/validation-code.js +4 -0
  117. package/dist/operations/write-scope.resolver.d.ts +6 -6
  118. package/dist/protocol/absent-route.responder.d.ts +13 -11
  119. package/dist/protocol/absent-route.responder.js +42 -16
  120. package/dist/protocol/contract-document.responder.d.ts +3 -3
  121. package/dist/protocol/contract-document.responder.js +2 -2
  122. package/dist/protocol/http-request.decoder.d.ts +23 -13
  123. package/dist/protocol/http-request.decoder.js +19 -11
  124. package/dist/protocol/http-request.reader.d.ts +3 -3
  125. package/dist/protocol/http-response.encoder.d.ts +4 -4
  126. package/dist/protocol/http-response.encoder.js +94 -55
  127. package/dist/protocol/http-status.table.d.ts +2 -2
  128. package/dist/protocol/operation-response.guard.d.ts +2 -2
  129. package/dist/protocol/protocol-surface.d.ts +4 -4
  130. package/dist/protocol/protocol.binder.d.ts +52 -27
  131. package/dist/protocol/protocol.binder.js +14 -9
  132. package/dist/protocol/protocol.handler.d.ts +28 -15
  133. package/dist/protocol/protocol.handler.js +55 -10
  134. package/dist/protocol/unmounted-route.error.d.ts +19 -0
  135. package/dist/protocol/unmounted-route.error.js +10 -0
  136. package/dist/runtime/caller-data.copier.d.ts +59 -0
  137. package/dist/runtime/caller-data.copier.js +470 -0
  138. package/dist/runtime/caller-data.door.d.ts +56 -0
  139. package/dist/runtime/caller-data.door.js +67 -0
  140. package/dist/runtime/computed-read-runtime.d.ts +7 -6
  141. package/dist/runtime/computed-read-runtime.js +61 -55
  142. package/dist/runtime/computed-value.error.d.ts +13 -0
  143. package/dist/runtime/computed-value.error.js +9 -0
  144. package/dist/runtime/context-executor.runtime.d.ts +59 -0
  145. package/dist/runtime/context-executor.runtime.js +275 -0
  146. package/dist/runtime/create-requirement.d.ts +22 -57
  147. package/dist/runtime/create-requirement.js +140 -37
  148. package/dist/runtime/decimal.d.ts +2 -2
  149. package/dist/runtime/decimal.js +1 -1
  150. package/dist/runtime/diagnostics-reporter.d.ts +64 -22
  151. package/dist/runtime/diagnostics-reporter.js +35 -4
  152. package/dist/runtime/error-boundary.d.ts +73 -8
  153. package/dist/runtime/error-boundary.js +104 -48
  154. package/dist/runtime/execution-options.d.ts +10 -2
  155. package/dist/runtime/field-check.evaluator.d.ts +29 -0
  156. package/dist/runtime/field-check.evaluator.js +521 -0
  157. package/dist/runtime/field-compute.d.ts +64 -0
  158. package/dist/runtime/field-compute.js +1 -0
  159. package/dist/runtime/field-stage.plan.d.ts +15 -0
  160. package/dist/runtime/field-stage.plan.js +27 -0
  161. package/dist/runtime/field-stage.runtime.d.ts +35 -0
  162. package/dist/runtime/field-stage.runtime.js +143 -0
  163. package/dist/runtime/field-validator.runtime.d.ts +11 -0
  164. package/dist/runtime/field-validator.runtime.js +87 -0
  165. package/dist/runtime/framework-error-class.table.d.ts +33 -0
  166. package/dist/runtime/framework-error-class.table.js +25 -0
  167. package/dist/runtime/framework-error.d.ts +79 -7
  168. package/dist/runtime/framework-error.factory.d.ts +4 -0
  169. package/dist/runtime/framework-error.factory.js +15 -0
  170. package/dist/runtime/framework-error.js +23 -2
  171. package/dist/runtime/interceptor-next.error.d.ts +5 -0
  172. package/dist/runtime/interceptor-next.error.js +6 -0
  173. package/dist/runtime/json-value.d.ts +3 -3
  174. package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
  175. package/dist/runtime/level-lifecycle.runtime.js +42 -0
  176. package/dist/runtime/misuse-reporter.d.ts +32 -0
  177. package/dist/runtime/misuse-reporter.js +19 -0
  178. package/dist/runtime/mutation-planner.d.ts +19 -10
  179. package/dist/runtime/mutation-planner.js +62 -36
  180. package/dist/runtime/nested-write.walker.d.ts +32 -0
  181. package/dist/runtime/nested-write.walker.js +73 -0
  182. package/dist/runtime/operation-request.d.ts +35 -15
  183. package/dist/runtime/operation-response.d.ts +17 -17
  184. package/dist/runtime/operation-runtime.d.ts +125 -30
  185. package/dist/runtime/operation-runtime.js +423 -83
  186. package/dist/runtime/outcome-mapper.d.ts +16 -5
  187. package/dist/runtime/outcome-mapper.js +35 -8
  188. package/dist/runtime/output-validator.d.ts +16 -6
  189. package/dist/runtime/output-validator.js +12 -1
  190. package/dist/runtime/owned-execution.registry.d.ts +13 -0
  191. package/dist/runtime/owned-execution.registry.js +7 -0
  192. package/dist/runtime/pipe-output.validator.d.ts +33 -18
  193. package/dist/runtime/pipe-output.validator.js +12 -12
  194. package/dist/runtime/pipeline.d.ts +202 -28
  195. package/dist/runtime/readonly-value.d.ts +32 -0
  196. package/dist/runtime/readonly-value.js +141 -0
  197. package/dist/runtime/referential-action.d.ts +7 -0
  198. package/dist/runtime/request-envelope.validator.d.ts +5 -0
  199. package/dist/runtime/request-envelope.validator.js +123 -0
  200. package/dist/runtime/request-id.d.ts +1 -1
  201. package/dist/runtime/request-state.d.ts +14 -0
  202. package/dist/runtime/request-state.js +1 -0
  203. package/dist/runtime/request-state.resolver.d.ts +12 -0
  204. package/dist/runtime/request-state.resolver.js +20 -0
  205. package/dist/runtime/scalar-runtime.d.ts +56 -13
  206. package/dist/runtime/scalar-runtime.js +167 -86
  207. package/dist/transactions/deferred-operation.d.ts +35 -20
  208. package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
  209. package/dist/transactions/operation-arguments-encoder.js +2 -2
  210. package/dist/transactions/sql-statement.d.ts +77 -0
  211. package/dist/transactions/sql-statement.js +47 -0
  212. package/dist/transactions/sql-statement.validator.d.ts +44 -0
  213. package/dist/transactions/sql-statement.validator.js +134 -0
  214. package/dist/transactions/transaction-envelope.d.ts +4 -4
  215. package/dist/transactions/transaction-integrity-error.d.ts +6 -6
  216. package/dist/transactions/transaction-integrity-error.js +5 -2
  217. package/dist/transactions/transaction-plan-assembler.d.ts +23 -9
  218. package/dist/transactions/transaction-plan-assembler.js +195 -82
  219. package/dist/transactions/transaction-plan-validator.d.ts +53 -21
  220. package/dist/transactions/transaction-plan-validator.js +246 -163
  221. package/dist/transactions/transaction-reference-collector.d.ts +30 -0
  222. package/dist/transactions/transaction-reference-collector.js +204 -0
  223. package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
  224. package/dist/transactions/transaction-reference-resolver.js +27 -10
  225. package/dist/transactions/transaction-reference-validator.d.ts +34 -4
  226. package/dist/transactions/transaction-reference-validator.js +82 -43
  227. package/dist/transactions/transaction-reference.d.ts +30 -58
  228. package/dist/transactions/transaction-request.d.ts +20 -7
  229. package/dist/transactions/transaction-response.d.ts +12 -7
  230. package/dist/transactions/transaction-response.js +24 -1
  231. package/dist/transactions/transaction-runtime.d.ts +11 -8
  232. package/dist/transactions/transaction-runtime.js +167 -50
  233. package/dist/transactions/transaction-settlement.runtime.d.ts +51 -0
  234. package/dist/transactions/transaction-settlement.runtime.js +120 -0
  235. package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
  236. package/dist/transactions/transaction-slot-path-error.js +2 -2
  237. package/dist/transactions/transaction-slot-writer.js +2 -2
  238. package/dist/transactions/transaction-stage.runtime.d.ts +81 -0
  239. package/dist/transactions/transaction-stage.runtime.js +123 -0
  240. package/package.json +18 -3
  241. package/src/runtime/field-check.evaluator.ts +720 -0
  242. package/dist/config/define-fields.d.ts +0 -35
  243. package/dist/config/define-fields.js +0 -3
  244. package/dist/config/framework-behaviors-config.d.ts +0 -30
  245. package/dist/config/framework-fields-config.d.ts +0 -36
  246. package/dist/config/framework-restrictions-config.d.ts +0 -142
  247. package/dist/operations/operation-boolean-nodes.d.ts +0 -11
  248. package/dist/operations/operation-boolean-nodes.js +0 -283
  249. package/dist/operations/operation-nesting.d.ts +0 -8
  250. package/dist/operations/operation-nesting.js +0 -307
  251. package/dist/runtime/field-behavior.d.ts +0 -48
  252. /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
  253. /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
  254. /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
  255. /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
@@ -1,17 +1,14 @@
1
1
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
- import { FrameworkError } from "./framework-error.js";
3
- import { INTERNAL_FAILURE_MESSAGE } from "./operation-response.js";
2
+ import { AvComputedValueError } from "./computed-value.error.js";
4
3
  import { normalizeScalarFieldValue } from "./scalar-runtime.js";
5
4
  function isRecord(value) {
6
5
  return value !== null && typeof value === "object" && !Array.isArray(value);
7
6
  }
8
- function readBehavior(value) {
7
+ function readCompute(value) {
9
8
  if (typeof value === "function") {
10
9
  return { compute: value, dependsOn: [] };
11
10
  }
12
- if (value === undefined ||
13
- value === false ||
14
- typeof value.compute !== "function") {
11
+ if (value === undefined || typeof value.compute !== "function") {
15
12
  return undefined;
16
13
  }
17
14
  return {
@@ -19,6 +16,16 @@ function readBehavior(value) {
19
16
  dependsOn: value.dependsOn ?? [],
20
17
  };
21
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
+ }
22
29
  function appendUnique(values, value) {
23
30
  if (!values.includes(value)) {
24
31
  values.push(value);
@@ -35,18 +42,17 @@ function supportsProjection(request) {
35
42
  }
36
43
  return request.variant !== "count";
37
44
  }
38
- function addScalarProjection(core, active, behaviors, resourceName, fieldName, adapterSelect, requested, computed) {
45
+ function addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed) {
39
46
  const activeField = lookupField(lookupResource(active, resourceName), fieldName);
40
47
  if (activeField?.kind !== "scalar") {
41
48
  return;
42
49
  }
43
50
  appendUnique(requested, fieldName);
44
- const behavior = readBehavior(behaviors?.[resourceName]?.fields[fieldName]?.read);
45
- if (behavior !== undefined) {
51
+ const stage = readCompute(compute?.[resourceName]?.[fieldName]?.read);
52
+ if (stage !== undefined) {
46
53
  appendUnique(computed, fieldName);
47
- for (const dependency of behavior.dependsOn) {
48
- const dependencyField = lookupField(lookupResource(core, resourceName), dependency);
49
- if (dependencyField?.kind === "scalar") {
54
+ for (const dependency of stage.dependsOn) {
55
+ if (storedScalar(model, resourceName, dependency)) {
50
56
  appendUniqueProjection(adapterSelect, dependency);
51
57
  }
52
58
  }
@@ -71,7 +77,7 @@ function projectionEntry(entry) {
71
77
  function withoutProjectionChoice(value) {
72
78
  return Object.fromEntries(Object.entries(value).filter(([key]) => key !== "select" && key !== "include"));
73
79
  }
74
- function defaultProjectionLevel(core, active, behaviors, resourceName) {
80
+ function defaultProjectionLevel(core, model, active, compute, resourceName) {
75
81
  const activeResource = lookupResource(active, resourceName);
76
82
  const adapterSelect = [];
77
83
  const requested = [];
@@ -81,7 +87,7 @@ function defaultProjectionLevel(core, active, behaviors, resourceName) {
81
87
  if (field.kind !== "scalar" || field.capabilities.select !== true) {
82
88
  continue;
83
89
  }
84
- addScalarProjection(core, active, behaviors, resourceName, fieldName, adapterSelect, requested, computed);
90
+ addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed);
85
91
  }
86
92
  }
87
93
  return {
@@ -95,25 +101,25 @@ function defaultProjectionLevel(core, active, behaviors, resourceName) {
95
101
  },
96
102
  };
97
103
  }
98
- function planRelationProjection(core, active, behaviors, field, value) {
104
+ function planRelationProjection(core, model, active, compute, field, value) {
99
105
  if (!isRecord(value)) {
100
- return defaultProjectionLevel(core, active, behaviors, field.target);
106
+ return defaultProjectionLevel(core, model, active, compute, field.target);
101
107
  }
102
108
  if (Array.isArray(value.select)) {
103
- return planSelectLevel(core, active, behaviors, field.target, value.select, true);
109
+ return planSelectLevel(core, model, active, compute, field.target, value.select, true);
104
110
  }
105
111
  if (Array.isArray(value.include)) {
106
- return planIncludeLevel(core, active, behaviors, field.target, value.include);
112
+ return planIncludeLevel(core, model, active, compute, field.target, value.include);
107
113
  }
108
- return defaultProjectionLevel(core, active, behaviors, field.target);
114
+ return defaultProjectionLevel(core, model, active, compute, field.target);
109
115
  }
110
- function planRelationEntry(core, active, behaviors, resourceName, fieldName, value) {
116
+ function planRelationEntry(core, model, active, compute, resourceName, fieldName, value) {
111
117
  const activeField = lookupField(lookupResource(active, resourceName), fieldName);
112
118
  const coreField = lookupField(lookupResource(core, resourceName), fieldName);
113
119
  if (activeField?.kind !== "relation" || coreField?.kind !== "relation") {
114
120
  return undefined;
115
121
  }
116
- const nested = planRelationProjection(core, active, behaviors, coreField, value);
122
+ const nested = planRelationProjection(core, model, active, compute, coreField, value);
117
123
  return {
118
124
  adapterEntry: {
119
125
  [fieldName]: {
@@ -128,7 +134,7 @@ function planRelationEntry(core, active, behaviors, resourceName, fieldName, val
128
134
  },
129
135
  };
130
136
  }
131
- function planSelectLevel(core, active, behaviors, resourceName, select, collectReducers = false) {
137
+ function planSelectLevel(core, model, active, compute, resourceName, select, collectReducers = false) {
132
138
  const activeResource = lookupResource(active, resourceName);
133
139
  const coreResource = lookupResource(core, resourceName);
134
140
  const adapterSelect = [];
@@ -160,11 +166,11 @@ function planSelectLevel(core, active, behaviors, resourceName, select, collectR
160
166
  const activeField = lookupField(activeResource, entry);
161
167
  const coreField = lookupField(coreResource, entry);
162
168
  if (activeField?.kind === "scalar") {
163
- addScalarProjection(core, active, behaviors, resourceName, entry, adapterSelect, requested, computed);
169
+ addScalarProjection(core, model, active, compute, resourceName, entry, adapterSelect, requested, computed);
164
170
  continue;
165
171
  }
166
172
  if (activeField?.kind === "relation" && coreField?.kind === "relation") {
167
- const plannedRelation = planRelationEntry(core, active, behaviors, resourceName, entry, undefined);
173
+ const plannedRelation = planRelationEntry(core, model, active, compute, resourceName, entry, undefined);
168
174
  if (plannedRelation !== undefined) {
169
175
  appendUnique(requested, entry);
170
176
  adapterSelect.push(plannedRelation.adapterEntry);
@@ -181,7 +187,7 @@ function planSelectLevel(core, active, behaviors, resourceName, select, collectR
181
187
  continue;
182
188
  }
183
189
  const [fieldName, nestedValue] = relationEntry;
184
- const plannedRelation = planRelationEntry(core, active, behaviors, resourceName, fieldName, nestedValue);
190
+ const plannedRelation = planRelationEntry(core, model, active, compute, resourceName, fieldName, nestedValue);
185
191
  if (plannedRelation === undefined) {
186
192
  adapterSelect.push(entry);
187
193
  continue;
@@ -195,15 +201,15 @@ function planSelectLevel(core, active, behaviors, resourceName, select, collectR
195
201
  plan: { resource: resourceName, requested, computed, relations, reducers },
196
202
  };
197
203
  }
198
- function planIncludeLevel(core, active, behaviors, resourceName, include) {
199
- 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);
200
206
  const adapterSelect = [...defaults.select];
201
207
  const requested = [...defaults.plan.requested];
202
208
  const computed = [...defaults.plan.computed];
203
209
  const relations = [];
204
210
  for (const entry of include) {
205
211
  if (typeof entry === "string") {
206
- const plannedRelation = planRelationEntry(core, active, behaviors, resourceName, entry, undefined);
212
+ const plannedRelation = planRelationEntry(core, model, active, compute, resourceName, entry, undefined);
207
213
  if (plannedRelation === undefined) {
208
214
  continue;
209
215
  }
@@ -217,7 +223,7 @@ function planIncludeLevel(core, active, behaviors, resourceName, include) {
217
223
  continue;
218
224
  }
219
225
  const [fieldName, nestedValue] = relationEntry;
220
- const plannedRelation = planRelationEntry(core, active, behaviors, resourceName, fieldName, nestedValue);
226
+ const plannedRelation = planRelationEntry(core, model, active, compute, resourceName, fieldName, nestedValue);
221
227
  if (plannedRelation === undefined) {
222
228
  continue;
223
229
  }
@@ -242,7 +248,7 @@ function replaceWithInternalSelect(args, select) {
242
248
  internal.select = select;
243
249
  return internal;
244
250
  }
245
- export function planReadOperation(core, active, behaviors, request, args) {
251
+ export function planReadOperation(core, model, active, compute, request, args) {
246
252
  if (!isRecord(args) || !supportsProjection(request)) {
247
253
  return { arguments: args, projection: undefined, materialize: false };
248
254
  }
@@ -252,7 +258,7 @@ export function planReadOperation(core, active, behaviors, request, args) {
252
258
  return { arguments: args, projection: undefined, materialize: false };
253
259
  }
254
260
  if (Array.isArray(args.select)) {
255
- const planned = planSelectLevel(core, active, behaviors, request.resource, args.select);
261
+ const planned = planSelectLevel(core, model, active, compute, request.resource, args.select);
256
262
  return {
257
263
  arguments: replaceWithInternalSelect(args, planned.select),
258
264
  projection: planned.plan,
@@ -260,27 +266,21 @@ export function planReadOperation(core, active, behaviors, request, args) {
260
266
  };
261
267
  }
262
268
  if (Array.isArray(args.include)) {
263
- const planned = planIncludeLevel(core, active, behaviors, request.resource, args.include);
269
+ const planned = planIncludeLevel(core, model, active, compute, request.resource, args.include);
264
270
  return {
265
271
  arguments: replaceWithInternalSelect(args, planned.select),
266
272
  projection: planned.plan,
267
273
  materialize: true,
268
274
  };
269
275
  }
270
- const defaults = defaultProjectionLevel(core, active, behaviors, request.resource);
276
+ const defaults = defaultProjectionLevel(core, model, active, compute, request.resource);
271
277
  return {
272
278
  arguments: { ...args, select: defaults.select },
273
279
  projection: defaults.plan,
274
280
  materialize: defaults.plan.computed.length > 0,
275
281
  };
276
282
  }
277
- function behaviorFailure(issues) {
278
- throw new FrameworkError("A3000", {
279
- message: INTERNAL_FAILURE_MESSAGE,
280
- issues,
281
- });
282
- }
283
- async function materializeRelation(active, behaviors, request, relation, value, contextFactory) {
283
+ async function materializeRelation(active, compute, request, relation, value, contextFactory) {
284
284
  if (value === null || value === undefined) {
285
285
  return value;
286
286
  }
@@ -288,11 +288,11 @@ async function materializeRelation(active, behaviors, request, relation, value,
288
288
  if (!Array.isArray(value)) {
289
289
  return value;
290
290
  }
291
- 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)));
292
292
  }
293
- return materializeRecord(active, behaviors, request, relation.projection, value, contextFactory);
293
+ return materializeRecord(active, compute, request, relation.projection, value, contextFactory);
294
294
  }
295
- async function materializeRecord(active, behaviors, request, plan, value, contextFactory) {
295
+ async function materializeRecord(active, compute, request, plan, value, contextFactory) {
296
296
  if (!isRecord(value)) {
297
297
  return value;
298
298
  }
@@ -303,24 +303,30 @@ async function materializeRecord(active, behaviors, request, plan, value, contex
303
303
  const record = { ...value };
304
304
  for (const fieldName of plan.computed) {
305
305
  const field = lookupField(resource, fieldName);
306
- const behavior = readBehavior(behaviors?.[plan.resource]?.fields[fieldName]?.read);
307
- if (field?.kind !== "scalar" || behavior === undefined) {
306
+ const stage = readCompute(compute?.[plan.resource]?.[fieldName]?.read);
307
+ if (field?.kind !== "scalar" || stage === undefined) {
308
308
  continue;
309
309
  }
310
- const computedValue = await behavior.compute({
311
- scope: request.scope,
312
- resource: plan.resource,
310
+ const computedValue = await stage.compute({
313
311
  field: fieldName,
314
312
  value: record[fieldName],
315
313
  record,
316
- operation: contextFactory(),
314
+ ctx: contextFactory(),
317
315
  });
318
316
  if (computedValue === undefined) {
319
317
  continue;
320
318
  }
321
- 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
+ ]);
322
328
  if (!validation.ok) {
323
- behaviorFailure(validation.issues);
329
+ throw new AvComputedValueError(plan.resource, fieldName, "read", validation.issues);
324
330
  }
325
331
  record[fieldName] = validation.value;
326
332
  }
@@ -328,19 +334,19 @@ async function materializeRecord(active, behaviors, request, plan, value, contex
328
334
  if (!Object.hasOwn(record, relation.field)) {
329
335
  continue;
330
336
  }
331
- 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);
332
338
  }
333
339
  return Object.fromEntries(plan.requested
334
340
  .filter((fieldName) => Object.hasOwn(record, fieldName))
335
341
  .map((fieldName) => [fieldName, record[fieldName]]));
336
342
  }
337
- export async function materializeReadOperation(active, behaviors, request, plan, value, contextFactory) {
343
+ export async function materializeReadOperation(active, compute, request, plan, value, contextFactory) {
338
344
  const projection = plan.projection;
339
345
  if (!plan.materialize || projection === undefined) {
340
346
  return value;
341
347
  }
342
348
  if (Array.isArray(value)) {
343
- 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)));
344
350
  }
345
- return materializeRecord(active, behaviors, request, projection, value, contextFactory);
351
+ return materializeRecord(active, compute, request, projection, value, contextFactory);
346
352
  }
@@ -0,0 +1,13 @@
1
+ import type { AvValidationIssue } from "../operations/validation-code.js";
2
+ /**
3
+ * What the diagnostics channel receives when a computed value — a read or write
4
+ * compute stage's return — is one its Contract refuses: the developer's broken code,
5
+ * never the caller's. It is thrown, not a deliberate outcome, so the framework's
6
+ * boundary answers the caller the generic `A3000` and reports this error, with the
7
+ * issues, exactly once.
8
+ */
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
+ }
@@ -0,0 +1,9 @@
1
+ export class AvComputedValueError extends Error {
2
+ issues;
3
+ name = "AvComputedValueError";
4
+ constructor(resource, field, stage, issues) {
5
+ const [first] = issues;
6
+ super(`The compute.${stage} stage of ${resource}.${field} returned a value its Contract refuses${first === undefined ? "." : ` (${first.code}: ${first.message})`}`);
7
+ this.issues = issues;
8
+ }
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
+ }