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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/CHANGELOG.md +943 -16
  2. package/ERRORS.md +142 -0
  3. package/README.md +274 -16
  4. package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
  5. package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
  6. package/dist/adapters/adapter-field.d.ts +22 -0
  7. package/dist/adapters/adapter-identifier.d.ts +9 -0
  8. package/dist/adapters/adapter-identifier.js +6 -1
  9. package/dist/adapters/adapter-model.d.ts +9 -0
  10. package/dist/adapters/adapter-operation.d.ts +18 -3
  11. package/dist/adapters/adapter-resource.d.ts +5 -0
  12. package/dist/adapters/adapter.interface.d.ts +10 -0
  13. package/dist/avz/avz.d.ts +1 -1
  14. package/dist/avz/json-shape.registry.d.ts +2 -1
  15. package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
  16. package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
  17. package/dist/compiler/contract.compiler.d.ts +6 -0
  18. package/dist/compiler/contract.compiler.js +227 -24
  19. package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
  20. package/dist/compiler/managed-elsewhere.projector.js +179 -0
  21. package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
  22. package/dist/compiler/managed-elsewhere.validator.js +74 -0
  23. package/dist/config/computed-fields.d.ts +62 -0
  24. package/dist/config/computed-fields.js +73 -0
  25. package/dist/config/config-diagnostic.guidance.d.ts +6 -0
  26. package/dist/config/config-diagnostic.guidance.js +32 -0
  27. package/dist/config/config.resolver.d.ts +24 -0
  28. package/dist/config/config.resolver.js +65 -0
  29. package/dist/config/config.validator.js +222 -8
  30. package/dist/config/define-resource.d.ts +1 -5
  31. package/dist/config/entrypoint.normalizer.d.ts +3 -2
  32. package/dist/config/exact-framework-config.d.ts +67 -22
  33. package/dist/config/field-compute.resolver.d.ts +2 -0
  34. package/dist/config/field-compute.resolver.js +8 -0
  35. package/dist/config/framework-config.d.ts +53 -15
  36. package/dist/config/framework-resources-config.d.ts +25 -14
  37. package/dist/config/pipeline-config.d.ts +4 -4
  38. package/dist/config/pipeline-tree.resolver.d.ts +2 -2
  39. package/dist/contracts/access-route.rules.d.ts +10 -0
  40. package/dist/contracts/access-route.rules.js +45 -0
  41. package/dist/contracts/capability.d.ts +26 -1
  42. package/dist/contracts/capability.js +20 -0
  43. package/dist/contracts/client-contract-structure.validator.d.ts +301 -89
  44. package/dist/contracts/client-contract-structure.validator.js +37 -2
  45. package/dist/contracts/contract-access.d.ts +29 -0
  46. package/dist/contracts/contract-access.js +1 -0
  47. package/dist/contracts/contract-canonicalizer.d.ts +9 -1
  48. package/dist/contracts/contract-canonicalizer.js +30 -4
  49. package/dist/contracts/contract-hash.d.ts +0 -1
  50. package/dist/contracts/contract-hash.js +1 -1
  51. package/dist/contracts/contract.d.ts +27 -1
  52. package/dist/contracts/field.d.ts +58 -1
  53. package/dist/contracts/json-schema.projector.d.ts +11 -0
  54. package/dist/contracts/json-schema.projector.js +78 -0
  55. package/dist/contracts/scalar-value-type.d.ts +3 -1
  56. package/dist/framework/access-facade.d.ts +116 -0
  57. package/dist/framework/access-facade.js +120 -0
  58. package/dist/framework/contract-view.d.ts +120 -16
  59. package/dist/framework/framework-construction.error.d.ts +14 -4
  60. package/dist/framework/framework-construction.error.js +18 -2
  61. package/dist/framework/framework.d.ts +26 -5
  62. package/dist/framework/framework.factory.d.ts +1 -1
  63. package/dist/framework/framework.factory.js +115 -23
  64. package/dist/framework/operation-facade.d.ts +80 -13
  65. package/dist/framework/operation-facade.js +2 -1
  66. package/dist/index.d.ts +17 -5
  67. package/dist/index.js +1 -0
  68. package/dist/internal.d.ts +7 -2
  69. package/dist/internal.js +6 -0
  70. package/dist/operations/database-refusal.d.ts +51 -0
  71. package/dist/operations/database-refusal.js +45 -0
  72. package/dist/operations/operation-arguments.d.ts +148 -60
  73. package/dist/operations/operation-call.d.ts +9 -5
  74. package/dist/operations/operation-result.d.ts +6 -4
  75. package/dist/operations/operation-validator-core.js +159 -36
  76. package/dist/operations/operation-validator.d.ts +1 -1
  77. package/dist/operations/structural-limits.walker.d.ts +1 -1
  78. package/dist/operations/validation-code.guidance.d.ts +6 -0
  79. package/dist/operations/validation-code.guidance.js +90 -0
  80. package/dist/operations/write-scope.resolver.d.ts +4 -0
  81. package/dist/operations/write-scope.resolver.js +2 -0
  82. package/dist/policy/access-provider.interface.d.ts +91 -0
  83. package/dist/policy/access-provider.interface.js +1 -0
  84. package/dist/policy/access-provider.registry.d.ts +17 -0
  85. package/dist/policy/access-provider.registry.js +15 -0
  86. package/dist/policy/access-question.d.ts +20 -0
  87. package/dist/policy/access-question.js +1 -0
  88. package/dist/policy/access-question.registry.d.ts +5 -0
  89. package/dist/policy/access-question.registry.js +19 -0
  90. package/dist/policy/access-question.runtime.d.ts +36 -0
  91. package/dist/policy/access-question.runtime.js +297 -0
  92. package/dist/policy/access-verb.table.d.ts +56 -0
  93. package/dist/policy/access-verb.table.js +21 -0
  94. package/dist/policy/access-verbs.d.ts +46 -0
  95. package/dist/policy/access-verbs.js +1 -0
  96. package/dist/policy/policy-admission.d.ts +20 -0
  97. package/dist/policy/policy-admission.js +409 -0
  98. package/dist/policy/policy-after-update.runtime.d.ts +79 -0
  99. package/dist/policy/policy-after-update.runtime.js +208 -0
  100. package/dist/policy/policy-condition.d.ts +15 -0
  101. package/dist/policy/policy-condition.js +36 -0
  102. package/dist/policy/policy-engine.d.ts +205 -0
  103. package/dist/policy/policy-engine.js +1 -0
  104. package/dist/policy/policy-named-rows.d.ts +18 -0
  105. package/dist/policy/policy-named-rows.js +51 -0
  106. package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
  107. package/dist/policy/policy-nested-write.runtime.js +545 -0
  108. package/dist/policy/policy-read.runtime.d.ts +81 -0
  109. package/dist/policy/policy-read.runtime.js +503 -0
  110. package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
  111. package/dist/policy/policy-reference-write.runtime.js +345 -0
  112. package/dist/policy/policy-request.d.ts +41 -0
  113. package/dist/policy/policy-request.js +63 -0
  114. package/dist/policy/policy-session.d.ts +106 -0
  115. package/dist/policy/policy-session.js +295 -0
  116. package/dist/policy/policy-startup.validator.d.ts +10 -0
  117. package/dist/policy/policy-startup.validator.js +112 -0
  118. package/dist/policy/policy-write.runtime.d.ts +39 -0
  119. package/dist/policy/policy-write.runtime.js +532 -0
  120. package/dist/prebuilt/core-version.generated.d.ts +2 -0
  121. package/dist/prebuilt/core-version.generated.js +1 -0
  122. package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
  123. package/dist/prebuilt/prebuilt-changes.js +65 -0
  124. package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
  125. package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
  126. package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
  127. package/dist/prebuilt/prebuilt-contracts.js +1 -0
  128. package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
  129. package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
  130. package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
  131. package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
  132. package/dist/protocol/absent-route.responder.d.ts +9 -27
  133. package/dist/protocol/absent-route.responder.js +36 -3
  134. package/dist/protocol/contract-document.responder.d.ts +2 -1
  135. package/dist/protocol/http-request.decoder.d.ts +19 -3
  136. package/dist/protocol/http-request.decoder.js +24 -1
  137. package/dist/protocol/http-request.reader.d.ts +6 -3
  138. package/dist/protocol/http-request.reader.js +1 -0
  139. package/dist/protocol/http-response.encoder.js +2 -2
  140. package/dist/protocol/protocol-headers.d.ts +3 -3
  141. package/dist/protocol/protocol-surface.d.ts +6 -1
  142. package/dist/protocol/protocol-surface.js +7 -0
  143. package/dist/protocol/protocol.binder.d.ts +16 -1
  144. package/dist/protocol/protocol.binder.js +4 -1
  145. package/dist/protocol/protocol.handler.d.ts +12 -1
  146. package/dist/protocol/protocol.handler.js +86 -17
  147. package/dist/runtime/caller-data.copier.d.ts +18 -3
  148. package/dist/runtime/caller-data.copier.js +21 -8
  149. package/dist/runtime/caller-data.door.d.ts +13 -6
  150. package/dist/runtime/computed-read-runtime.d.ts +6 -1
  151. package/dist/runtime/computed-read-runtime.js +232 -45
  152. package/dist/runtime/computed-value.error.d.ts +3 -2
  153. package/dist/runtime/computed-value.error.js +3 -2
  154. package/dist/runtime/context-executor.runtime.d.ts +4 -3
  155. package/dist/runtime/context-executor.runtime.js +4 -2
  156. package/dist/runtime/core-class.brand.d.ts +10 -0
  157. package/dist/runtime/core-class.brand.js +21 -0
  158. package/dist/runtime/create-requirement.d.ts +31 -5
  159. package/dist/runtime/create-requirement.js +129 -21
  160. package/dist/runtime/decimal.d.ts +14 -0
  161. package/dist/runtime/decimal.js +21 -0
  162. package/dist/runtime/diagnostics-reporter.d.ts +44 -9
  163. package/dist/runtime/diagnostics-reporter.js +13 -1
  164. package/dist/runtime/error-boundary.d.ts +9 -2
  165. package/dist/runtime/error-boundary.js +12 -0
  166. package/dist/runtime/error-guidance.d.ts +12 -0
  167. package/dist/runtime/error-guidance.js +1 -0
  168. package/dist/runtime/error.catalog.d.ts +49 -0
  169. package/dist/runtime/error.catalog.js +49 -0
  170. package/dist/runtime/execution-options.d.ts +8 -0
  171. package/dist/runtime/field-check.evaluator.d.ts +0 -2
  172. package/dist/runtime/field-check.evaluator.js +1 -1
  173. package/dist/runtime/field-compute.d.ts +11 -10
  174. package/dist/runtime/field-stage.runtime.d.ts +3 -1
  175. package/dist/runtime/field-stage.runtime.js +8 -4
  176. package/dist/runtime/field-validator.runtime.d.ts +19 -1
  177. package/dist/runtime/field-validator.runtime.js +47 -8
  178. package/dist/runtime/framework-error.js +9 -0
  179. package/dist/runtime/framework-warning.emitter.d.ts +6 -0
  180. package/dist/runtime/framework-warning.emitter.js +8 -0
  181. package/dist/runtime/json-value.d.ts +10 -5
  182. package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
  183. package/dist/runtime/level-lifecycle.runtime.js +3 -5
  184. package/dist/runtime/mutation-planner.d.ts +1 -6
  185. package/dist/runtime/mutation-planner.js +3 -14
  186. package/dist/runtime/operation-code.guidance.d.ts +6 -0
  187. package/dist/runtime/operation-code.guidance.js +167 -0
  188. package/dist/runtime/operation-request.d.ts +16 -9
  189. package/dist/runtime/operation-runtime.d.ts +35 -17
  190. package/dist/runtime/operation-runtime.js +220 -49
  191. package/dist/runtime/outcome-mapper.d.ts +2 -1
  192. package/dist/runtime/output-validator.d.ts +1 -1
  193. package/dist/runtime/owned-execution.registry.d.ts +13 -3
  194. package/dist/runtime/pipe-output.validator.d.ts +10 -0
  195. package/dist/runtime/pipe-output.validator.js +4 -2
  196. package/dist/runtime/pipeline.d.ts +47 -22
  197. package/dist/runtime/readonly-value.d.ts +20 -5
  198. package/dist/runtime/readonly-value.js +74 -26
  199. package/dist/runtime/referential-action.d.ts +1 -1
  200. package/dist/runtime/scalar-runtime.d.ts +4 -11
  201. package/dist/runtime/scalar-runtime.js +91 -22
  202. package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
  203. package/dist/runtime/unsent-value.normalizer.js +128 -0
  204. package/dist/transactions/operation-arguments-encoder.js +8 -3
  205. package/dist/transactions/operation-fingerprint.js +2 -2
  206. package/dist/transactions/sql-statement.d.ts +10 -2
  207. package/dist/transactions/sql-statement.validator.d.ts +2 -2
  208. package/dist/transactions/sql-statement.validator.js +38 -5
  209. package/dist/transactions/transaction-envelope.d.ts +5 -4
  210. package/dist/transactions/transaction-integrity-error.js +2 -0
  211. package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
  212. package/dist/transactions/transaction-plan-assembler.js +48 -10
  213. package/dist/transactions/transaction-plan-validator.d.ts +23 -7
  214. package/dist/transactions/transaction-plan-validator.js +27 -1
  215. package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
  216. package/dist/transactions/transaction-reference-validator.d.ts +43 -3
  217. package/dist/transactions/transaction-reference-validator.js +83 -57
  218. package/dist/transactions/transaction-reference.d.ts +1 -1
  219. package/dist/transactions/transaction-reference.js +5 -0
  220. package/dist/transactions/transaction-request.d.ts +8 -8
  221. package/dist/transactions/transaction-runtime.d.ts +5 -2
  222. package/dist/transactions/transaction-runtime.js +79 -27
  223. package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
  224. package/dist/transactions/transaction-slot-path-error.js +2 -0
  225. package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
  226. package/dist/transactions/transaction-stage.runtime.js +7 -4
  227. package/package.json +6 -5
  228. package/src/runtime/field-check.evaluator.ts +1 -1
@@ -1,5 +1,7 @@
1
+ import { adapterPrimaryIdentifier } from "../adapters/adapter-identifier.js";
1
2
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
3
  import { AvComputedValueError } from "./computed-value.error.js";
4
+ import { frozenCopy } from "./readonly-value.js";
3
5
  import { normalizeScalarFieldValue } from "./scalar-runtime.js";
4
6
  function isRecord(value) {
5
7
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -51,6 +53,11 @@ function addScalarProjection(core, model, active, compute, resourceName, fieldNa
51
53
  const stage = readCompute(compute?.[resourceName]?.[fieldName]?.read);
52
54
  if (stage !== undefined) {
53
55
  appendUnique(computed, fieldName);
56
+ if (stage.dependsOn.length === 0) {
57
+ for (const member of adapterPrimaryIdentifier(model, resourceName)) {
58
+ appendUniqueProjection(adapterSelect, member);
59
+ }
60
+ }
54
61
  for (const dependency of stage.dependsOn) {
55
62
  if (storedScalar(model, resourceName, dependency)) {
56
63
  appendUniqueProjection(adapterSelect, dependency);
@@ -77,18 +84,27 @@ function projectionEntry(entry) {
77
84
  function withoutProjectionChoice(value) {
78
85
  return Object.fromEntries(Object.entries(value).filter(([key]) => key !== "select" && key !== "include"));
79
86
  }
80
- function defaultProjectionLevel(core, model, active, compute, resourceName) {
87
+ export function defaultProjectionFields(active, resourceName) {
81
88
  const activeResource = lookupResource(active, resourceName);
89
+ if (activeResource === undefined) {
90
+ return [];
91
+ }
92
+ const fields = [];
93
+ for (const [fieldName, field] of Object.entries(activeResource.fields)) {
94
+ if (field.kind === "scalar" &&
95
+ field.capabilities.select === true &&
96
+ field.governed !== true) {
97
+ fields.push(fieldName);
98
+ }
99
+ }
100
+ return fields;
101
+ }
102
+ function defaultProjectionLevel(core, model, active, compute, resourceName) {
82
103
  const adapterSelect = [];
83
104
  const requested = [];
84
105
  const computed = [];
85
- if (activeResource !== undefined) {
86
- for (const [fieldName, field] of Object.entries(activeResource.fields)) {
87
- if (field.kind !== "scalar" || field.capabilities.select !== true) {
88
- continue;
89
- }
90
- addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed);
91
- }
106
+ for (const fieldName of defaultProjectionFields(active, resourceName)) {
107
+ addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed);
92
108
  }
93
109
  return {
94
110
  select: adapterSelect,
@@ -156,6 +172,12 @@ function planSelectLevel(core, model, active, compute, resourceName, select, col
156
172
  }
157
173
  for (const entry of select) {
158
174
  if (typeof entry === "string") {
175
+ if (entry === "$defaults") {
176
+ for (const fieldName of defaultProjectionFields(active, resourceName)) {
177
+ addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed);
178
+ }
179
+ continue;
180
+ }
159
181
  if (entry === "$count") {
160
182
  adapterSelect.push(entry);
161
183
  if (collectReducers) {
@@ -280,7 +302,175 @@ export function planReadOperation(core, model, active, compute, request, args) {
280
302
  materialize: defaults.plan.computed.length > 0,
281
303
  };
282
304
  }
283
- async function materializeRelation(active, compute, request, relation, value, contextFactory) {
305
+ function resolveReadLevel(active, compute, plan, tail) {
306
+ const resource = lookupResource(active, plan.resource);
307
+ if (resource === undefined) {
308
+ return undefined;
309
+ }
310
+ const stages = [];
311
+ for (const fieldName of plan.computed) {
312
+ const field = lookupField(resource, fieldName);
313
+ const stage = readCompute(compute?.[plan.resource]?.[fieldName]?.read);
314
+ if (field?.kind !== "scalar" || stage === undefined) {
315
+ continue;
316
+ }
317
+ stages.push({
318
+ field: fieldName,
319
+ definition: field,
320
+ compute: stage.compute,
321
+ });
322
+ }
323
+ const relations = [];
324
+ let restFree = true;
325
+ for (const relation of [...plan.relations].reverse()) {
326
+ const level = resolveReadLevel(active, compute, relation.projection, tail && restFree);
327
+ relations.unshift({ relation, level });
328
+ restFree &&= level?.computeFree ?? true;
329
+ }
330
+ return {
331
+ plan,
332
+ stages,
333
+ relations,
334
+ computeFree: stages.length === 0 && restFree,
335
+ atOnce: tail && stages.length <= 1 && restFree,
336
+ plainKeys: plan.requested.every((field) => !(field in Object.prototype)),
337
+ };
338
+ }
339
+ function isNestedContainer(value) {
340
+ return (value !== null &&
341
+ typeof value === "object" &&
342
+ !(value instanceof Date) &&
343
+ !(value instanceof Uint8Array));
344
+ }
345
+ function isThenable(value) {
346
+ return (value !== null &&
347
+ (typeof value === "object" || typeof value === "function") &&
348
+ typeof value.then === "function");
349
+ }
350
+ function setOwn(target, key, value) {
351
+ if (key in target) {
352
+ Object.defineProperty(target, key, {
353
+ value,
354
+ writable: true,
355
+ enumerable: true,
356
+ configurable: true,
357
+ });
358
+ return;
359
+ }
360
+ target[key] = value;
361
+ }
362
+ function answerOf(level, record) {
363
+ const answer = {};
364
+ for (const fieldName of level.plan.requested) {
365
+ if (!Object.hasOwn(record, fieldName)) {
366
+ continue;
367
+ }
368
+ if (level.plainKeys) {
369
+ answer[fieldName] = record[fieldName];
370
+ }
371
+ else {
372
+ setOwn(answer, fieldName, record[fieldName]);
373
+ }
374
+ }
375
+ return answer;
376
+ }
377
+ function heldReadValue(active, level, stage, value) {
378
+ const validation = normalizeScalarFieldValue(active, stage.definition, value, "runtime", [
379
+ "resources",
380
+ level.plan.resource,
381
+ "fields",
382
+ stage.field,
383
+ "pipelines",
384
+ "compute",
385
+ "read",
386
+ ]);
387
+ if (!validation.ok) {
388
+ throw new AvComputedValueError(level.plan.resource, stage.field, "read", validation.issues);
389
+ }
390
+ return validation.value;
391
+ }
392
+ function projectedAtOnce(level, value) {
393
+ if (!isRecord(value) || level === undefined) {
394
+ return value;
395
+ }
396
+ const record = { ...value };
397
+ relationsAtOnce(level, record);
398
+ return answerOf(level, record);
399
+ }
400
+ function relationsAtOnce(level, record) {
401
+ for (const { relation, level: nested } of level.relations) {
402
+ if (!Object.hasOwn(record, relation.field)) {
403
+ continue;
404
+ }
405
+ const value = record[relation.field];
406
+ if (value === null || value === undefined) {
407
+ continue;
408
+ }
409
+ if (relation.cardinality === "many") {
410
+ if (Array.isArray(value)) {
411
+ record[relation.field] = Array.from(value, (entry) => projectedAtOnce(nested, entry));
412
+ }
413
+ continue;
414
+ }
415
+ record[relation.field] = projectedAtOnce(nested, value);
416
+ }
417
+ }
418
+ function computedAtOnce(active, level, stage, value, contextFactory) {
419
+ const record = { ...value };
420
+ const view = frozenCopy(record);
421
+ let computedValue;
422
+ try {
423
+ computedValue = stage.compute({
424
+ field: stage.field,
425
+ value: view[stage.field],
426
+ record: view,
427
+ ctx: contextFactory(),
428
+ });
429
+ }
430
+ catch (error) {
431
+ return Promise.reject(error);
432
+ }
433
+ const finish = (returned) => {
434
+ if (returned !== undefined) {
435
+ record[stage.field] = heldReadValue(active, level, stage, returned);
436
+ }
437
+ relationsAtOnce(level, record);
438
+ return answerOf(level, record);
439
+ };
440
+ const later = (error) => Promise.resolve().then(() => {
441
+ throw error;
442
+ });
443
+ let waits;
444
+ try {
445
+ waits = isThenable(computedValue);
446
+ }
447
+ catch (error) {
448
+ return later(error);
449
+ }
450
+ if (waits) {
451
+ const pending = computedValue;
452
+ return (async () => finish(await pending))();
453
+ }
454
+ try {
455
+ return finish(computedValue);
456
+ }
457
+ catch (error) {
458
+ return later(error);
459
+ }
460
+ }
461
+ function materializeRecord(active, level, value, contextFactory) {
462
+ if (level?.atOnce !== true) {
463
+ return materializeInTurn(active, level, value, contextFactory);
464
+ }
465
+ if (!isRecord(value)) {
466
+ return value;
467
+ }
468
+ const [stage] = level.stages;
469
+ return stage === undefined
470
+ ? projectedAtOnce(level, value)
471
+ : computedAtOnce(active, level, stage, value, contextFactory);
472
+ }
473
+ async function materializeRelation(active, level, relation, value, contextFactory) {
284
474
  if (value === null || value === undefined) {
285
475
  return value;
286
476
  }
@@ -288,65 +478,62 @@ async function materializeRelation(active, compute, request, relation, value, co
288
478
  if (!Array.isArray(value)) {
289
479
  return value;
290
480
  }
291
- return Promise.all(value.map((entry) => materializeRecord(active, compute, request, relation.projection, entry, contextFactory)));
481
+ return Promise.all(value.map((entry) => materializeRecord(active, level, entry, contextFactory)));
292
482
  }
293
- return materializeRecord(active, compute, request, relation.projection, value, contextFactory);
483
+ return materializeRecord(active, level, value, contextFactory);
294
484
  }
295
- async function materializeRecord(active, compute, request, plan, value, contextFactory) {
296
- if (!isRecord(value)) {
297
- return value;
298
- }
299
- const resource = lookupResource(active, plan.resource);
300
- if (resource === undefined) {
485
+ async function materializeInTurn(active, level, value, contextFactory) {
486
+ if (!isRecord(value) || level === undefined) {
301
487
  return value;
302
488
  }
489
+ const { stages } = level;
303
490
  const record = { ...value };
304
- for (const fieldName of plan.computed) {
305
- const field = lookupField(resource, fieldName);
306
- const stage = readCompute(compute?.[plan.resource]?.[fieldName]?.read);
307
- if (field?.kind !== "scalar" || stage === undefined) {
308
- continue;
491
+ let told;
492
+ if (stages.length > 1) {
493
+ told = { ...record };
494
+ for (const key of Object.keys(told)) {
495
+ const nested = told[key];
496
+ if (isNestedContainer(nested)) {
497
+ told[key] = frozenCopy(nested, true);
498
+ }
309
499
  }
500
+ }
501
+ for (const stage of stages) {
502
+ const view = frozenCopy(told ?? record);
310
503
  const computedValue = await stage.compute({
311
- field: fieldName,
312
- value: record[fieldName],
313
- record,
504
+ field: stage.field,
505
+ value: view[stage.field],
506
+ record: view,
314
507
  ctx: contextFactory(),
315
508
  });
316
509
  if (computedValue === undefined) {
317
510
  continue;
318
511
  }
319
- const validation = normalizeScalarFieldValue(active, field, computedValue, "runtime", [
320
- "resources",
321
- plan.resource,
322
- "fields",
323
- fieldName,
324
- "pipelines",
325
- "compute",
326
- "read",
327
- ]);
328
- if (!validation.ok) {
329
- throw new AvComputedValueError(plan.resource, fieldName, "read", validation.issues);
512
+ const held = heldReadValue(active, level, stage, computedValue);
513
+ record[stage.field] = held;
514
+ if (told !== undefined) {
515
+ told[stage.field] = held;
330
516
  }
331
- record[fieldName] = validation.value;
332
517
  }
333
- for (const relation of plan.relations) {
518
+ for (const { relation, level: nested } of level.relations) {
334
519
  if (!Object.hasOwn(record, relation.field)) {
335
520
  continue;
336
521
  }
337
- record[relation.field] = await materializeRelation(active, compute, request, relation, record[relation.field], contextFactory);
522
+ record[relation.field] = await materializeRelation(active, nested, relation, record[relation.field], contextFactory);
338
523
  }
339
- return Object.fromEntries(plan.requested
340
- .filter((fieldName) => Object.hasOwn(record, fieldName))
341
- .map((fieldName) => [fieldName, record[fieldName]]));
524
+ return answerOf(level, record);
342
525
  }
343
- export async function materializeReadOperation(active, compute, request, plan, value, contextFactory) {
526
+ export async function materializeReadOperation(active, compute, _request, plan, value, contextFactory) {
344
527
  const projection = plan.projection;
345
528
  if (!plan.materialize || projection === undefined) {
346
529
  return value;
347
530
  }
531
+ const level = resolveReadLevel(active, compute, projection, true);
348
532
  if (Array.isArray(value)) {
349
- return Promise.all(value.map((entry) => materializeRecord(active, compute, request, projection, entry, contextFactory)));
533
+ const rows = value.map((entry) => materializeRecord(active, level, entry, contextFactory));
534
+ return rows.some((row) => row instanceof Promise)
535
+ ? Promise.all(rows)
536
+ : Array.from(rows);
350
537
  }
351
- return materializeRecord(active, compute, request, projection, value, contextFactory);
538
+ return materializeRecord(active, level, value, contextFactory);
352
539
  }
@@ -1,7 +1,8 @@
1
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
- * compute stage's return — is one its Contract refuses: the developer's broken code,
4
+ * compute stage's return — is one its Contract refuses, or a `compute.create`
5
+ * stage returned `undefined` for a field a create cannot do without (rc.2): the developer's broken code,
5
6
  * never the caller's. It is thrown, not a deliberate outcome, so the framework's
6
7
  * boundary answers the caller the generic `A3000` and reports this error, with the
7
8
  * issues, exactly once.
@@ -9,5 +10,5 @@ import type { AvValidationIssue } from "../operations/validation-code.js";
9
10
  export declare class AvComputedValueError extends Error {
10
11
  readonly issues: readonly AvValidationIssue[];
11
12
  readonly name = "AvComputedValueError";
12
- constructor(resource: string, field: string, stage: "read" | "create" | "update", issues: readonly AvValidationIssue[]);
13
+ constructor(resource: string, field: string, stage: "read" | "create" | "update", issues: readonly AvValidationIssue[], message?: string);
13
14
  }
@@ -1,9 +1,10 @@
1
1
  export class AvComputedValueError extends Error {
2
2
  issues;
3
3
  name = "AvComputedValueError";
4
- constructor(resource, field, stage, issues) {
4
+ constructor(resource, field, stage, issues, message) {
5
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})`}`);
6
+ super(message ??
7
+ `The compute.${stage} stage of ${resource}.${field} returned a value its Contract refuses${first === undefined ? "." : ` (${first.code}: ${first.message})`}`);
7
8
  this.issues = issues;
8
9
  }
9
10
  }
@@ -7,7 +7,7 @@ import type { AvOperationFamily } from "../operations/operation-identity.js";
7
7
  import { type AvDiagnosticsSink } from "./diagnostics-reporter.js";
8
8
  import type { AvComputeContext } from "./field-compute.js";
9
9
  import type { MisuseReporter } from "./misuse-reporter.js";
10
- import type { ApplicationOperationRequest } from "./operation-request.js";
10
+ import type { AvApplicationOperationRequest } from "./operation-request.js";
11
11
  import type { AvOperationResponse } from "./operation-response.js";
12
12
  import type { AvContext, AvTransactionContext, AvTransportContext } from "./pipeline.js";
13
13
  import type { AvState } from "./request-state.js";
@@ -35,8 +35,8 @@ export type ContextFacts = {
35
35
  readonly $args: unknown;
36
36
  };
37
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> = {
38
+ type RawOperationRunner<M extends AvAdapterModel> = (request: AvApplicationOperationRequest, transaction: AvAdapterTransactionExecutor<M> | undefined) => Promise<AvOperationResponse>;
39
+ type ContextExecutorDependencies<M extends AvAdapterModel> = {
40
40
  /** The model, as construction read it once: the ctx's Resources. */
41
41
  readonly model: M;
42
42
  readonly adapter: AvAdapter<M>;
@@ -57,3 +57,4 @@ export type ContextExecutor<M extends AvAdapterModel = AvAdapterModel> = {
57
57
  };
58
58
  /** Builds the ctx factory of one Framework over its model. */
59
59
  export declare function createContextExecutor<M extends AvAdapterModel>(dependencies: ContextExecutorDependencies<M>): ContextExecutor<M>;
60
+ export {};
@@ -195,9 +195,10 @@ export function createContextExecutor(dependencies) {
195
195
  const contextOf = (prototype, scope, facts, readOnly = false) => {
196
196
  const context = Object.create(prototype);
197
197
  Object.defineProperty(context, STATE, {
198
- value: { scope, facts, resources: new Map() },
198
+ value: { scope, facts, resources: undefined },
199
199
  });
200
- for (const [key, value] of Object.entries(facts)) {
200
+ for (const key of Object.keys(facts)) {
201
+ const value = facts[key];
201
202
  if (value !== undefined) {
202
203
  Object.defineProperty(context, key, { value, enumerable: true });
203
204
  }
@@ -232,6 +233,7 @@ export function createContextExecutor(dependencies) {
232
233
  Object.defineProperty(prototype, resource, {
233
234
  get() {
234
235
  const state = stateOf(this);
236
+ state.resources ??= new Map();
235
237
  let tree = state.resources.get(resource);
236
238
  if (tree === undefined) {
237
239
  tree = resourceTree(state.scope, resource, readOnly);
@@ -0,0 +1,10 @@
1
+ /** The registered symbol every copy of this major brands class `name` with. */
2
+ export declare function coreBrandOf(name: string): symbol;
3
+ /** Whether `value` carries `brand`, wherever it was made: one `in`. */
4
+ export declare function hasCoreBrand(value: unknown, brand: symbol): boolean;
5
+ /**
6
+ * Brands `type`'s prototype as `name` and makes `instanceof type` read the brand.
7
+ * A developer's own subclass of `type` inherits the static `Symbol.hasInstance`, so
8
+ * on any constructor but `type` itself it answers as `instanceof` always does.
9
+ */
10
+ export declare function brandCoreClass(type: abstract new (...args: never[]) => object, name: string): symbol;
@@ -0,0 +1,21 @@
1
+ import { CORE_VERSION } from "../prebuilt/core-version.generated.js";
2
+ const CORE_MAJOR = CORE_VERSION.slice(0, CORE_VERSION.indexOf("."));
3
+ export function coreBrandOf(name) {
4
+ return Symbol.for(`aventara.core.${name}@${CORE_MAJOR}`);
5
+ }
6
+ export function hasCoreBrand(value, brand) {
7
+ return typeof value === "object" && value !== null && brand in value;
8
+ }
9
+ const ordinaryHasInstance = Function.prototype[Symbol.hasInstance];
10
+ export function brandCoreClass(type, name) {
11
+ const brand = coreBrandOf(name);
12
+ Object.defineProperty(type.prototype, brand, { value: true });
13
+ Object.defineProperty(type, Symbol.hasInstance, {
14
+ value: function hasInstance(value) {
15
+ return this === type
16
+ ? hasCoreBrand(value, brand)
17
+ : ordinaryHasInstance.call(this, value);
18
+ },
19
+ });
20
+ return brand;
21
+ }
@@ -1,20 +1,32 @@
1
1
  import type { AvContract } from "../contracts/contract.js";
2
+ import type { AvCreateRequirements } from "../contracts/create-requirements.js";
2
3
  import type { AvOperationIdentity } from "../operations/operation-identity.js";
3
4
  import type { AvValidationIssue } from "../operations/validation-code.js";
4
5
  import type { ReferentialActionTable } from "./referential-action.js";
5
6
  type Path = readonly (string | number)[];
7
+ /** One required field a `compute.create` stage was to fill and left missing. */
8
+ type ComputedRequirementGap = {
9
+ readonly resource: string;
10
+ readonly field: string;
11
+ readonly issue: AvValidationIssue;
12
+ };
6
13
  /**
7
- * What the Adapter stated beside its model that the check reads: its
8
- * referential edges, for the fields that hold each reference. Read once when
9
- * the Framework is constructed. The requirements themselves are the active
10
- * Contract's.
14
+ * What the Adapter stated that the checks read: its referential edges, for the
15
+ * fields that hold each reference, and its own create requirements per
16
+ * Resource, before any layer projected them (what write compute must not leave
17
+ * missing). Read once when the Framework is constructed. The requirements the
18
+ * caller is held to are the active Contract's.
11
19
  */
12
20
  export type RecordWriteFacts = {
13
21
  readonly references: ReferentialActionTable;
22
+ readonly stated: (resource: string) => AvCreateRequirements | undefined;
14
23
  };
15
24
  /** The facts an Adapter stated, read off it once; an absent table states nothing. */
16
25
  export declare function recordWriteFactsOf(adapter: {
17
26
  readonly referentialActions?: ReferentialActionTable;
27
+ readonly model?: {
28
+ readonly resources: Readonly<Record<string, unknown>>;
29
+ };
18
30
  }): RecordWriteFacts;
19
31
  /**
20
32
  * The `V1000` issues for every create position in one operation's arguments
@@ -24,7 +36,21 @@ export declare function recordWriteFactsOf(adapter: {
24
36
  * reference both, in argument order. Empty when there are none. Total over
25
37
  * malformed input.
26
38
  */
27
- export declare function createRequirementIssues(contract: AvContract, facts: RecordWriteFacts, request: AvOperationIdentity & {
39
+ export declare function createRequirementIssues(contract: AvContract, facts: Pick<RecordWriteFacts, "references">, request: AvOperationIdentity & {
28
40
  readonly resource: string;
29
41
  }, args: unknown, argumentsPath: Path): readonly AvValidationIssue[];
42
+ /**
43
+ * Every required field a `compute.create` stage was to fill and that is still
44
+ * missing after write compute, at every create position of one operation's
45
+ * arguments (`create.*`'s `data`, `upsert`'s `create`, every nested create),
46
+ * in argument order, read against the Adapter's own statement of each
47
+ * Resource's create requirements; `computed` names the fields a Resource's
48
+ * `compute.create` stages fill.
49
+ * A field the parent supplies to a nested create, a group whose relation the
50
+ * record writes, and a value the caller sent are not missing. Empty when
51
+ * nothing is.
52
+ */
53
+ export declare function computedRequirementGapsOf(contract: AvContract, facts: RecordWriteFacts, request: AvOperationIdentity & {
54
+ readonly resource: string;
55
+ }, args: unknown, argumentsPath: Path, computed: (resource: string) => ReadonlySet<string>): readonly ComputedRequirementGap[];
30
56
  export {};