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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/CHANGELOG.md +1140 -0
  2. package/README.md +224 -57
  3. package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
  4. package/dist/adapters/adapter-field.d.ts +11 -11
  5. package/dist/adapters/adapter-identifier.d.ts +6 -6
  6. package/dist/adapters/adapter-model.d.ts +9 -9
  7. package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
  8. package/dist/adapters/adapter-operation.d.ts +3 -3
  9. package/dist/adapters/adapter-resource.d.ts +18 -9
  10. package/dist/adapters/adapter-sql-statement.d.ts +19 -0
  11. package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
  12. package/dist/adapters/adapter.interface.d.ts +49 -29
  13. package/dist/avz/avz-check.factory.d.ts +83 -0
  14. package/dist/avz/avz-check.factory.js +116 -0
  15. package/dist/avz/avz-check.registry.d.ts +35 -0
  16. package/dist/avz/avz-check.registry.js +9 -0
  17. package/dist/avz/avz.d.ts +203 -0
  18. package/dist/{json → avz}/avz.js +150 -8
  19. package/dist/{json → avz}/index.d.ts +2 -1
  20. package/dist/{json → avz}/json-shape.registry.d.ts +7 -7
  21. package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
  22. package/dist/{json → avz}/zod-issue.translator.js +7 -0
  23. package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
  24. package/dist/compiler/contract.compiler.d.ts +18 -18
  25. package/dist/compiler/contract.compiler.js +548 -441
  26. package/dist/compiler/create-requirements.projector.d.ts +49 -0
  27. package/dist/compiler/create-requirements.projector.js +423 -0
  28. package/dist/compiler/field-validator.compiler.d.ts +47 -0
  29. package/dist/compiler/field-validator.compiler.js +238 -0
  30. package/dist/config/any-framework-config.d.ts +19 -12
  31. package/dist/config/config-diagnostic.d.ts +11 -4
  32. package/dist/config/config-layer.d.ts +15 -6
  33. package/dist/config/config.resolver.d.ts +74 -31
  34. package/dist/config/config.resolver.js +108 -44
  35. package/dist/config/config.validator.d.ts +7 -7
  36. package/dist/config/config.validator.js +581 -72
  37. package/dist/config/define-resource.d.ts +57 -0
  38. package/dist/config/define-resource.js +14 -0
  39. package/dist/config/effective-fields.d.ts +19 -23
  40. package/dist/config/entrypoint.normalizer.d.ts +1 -1
  41. package/dist/config/exact-framework-config.d.ts +280 -0
  42. package/dist/config/field-compute.resolver.d.ts +19 -0
  43. package/dist/config/field-compute.resolver.js +115 -0
  44. package/dist/config/field-pipeline-config.d.ts +47 -0
  45. package/dist/config/forced-operation.validator.d.ts +10 -0
  46. package/dist/config/forced-operation.validator.js +66 -0
  47. package/dist/config/framework-config.d.ts +110 -39
  48. package/dist/config/framework-exemptions-config.d.ts +91 -0
  49. package/dist/config/framework-exemptions-config.js +1 -0
  50. package/dist/config/framework-field-definition.d.ts +78 -0
  51. package/dist/config/framework-field-definition.js +28 -0
  52. package/dist/config/framework-resources-config.d.ts +116 -0
  53. package/dist/config/framework-resources-config.js +1 -0
  54. package/dist/config/pipeline-config.d.ts +56 -20
  55. package/dist/config/pipeline-tree.resolver.d.ts +79 -0
  56. package/dist/config/pipeline-tree.resolver.js +220 -0
  57. package/dist/config/stage-type.eraser.d.ts +65 -0
  58. package/dist/config/stage-type.eraser.js +1 -0
  59. package/dist/contracts/capability.d.ts +11 -11
  60. package/dist/contracts/client-contract-structure.validator.d.ts +323 -28
  61. package/dist/contracts/client-contract-structure.validator.js +152 -8
  62. package/dist/contracts/contract-canonicalizer.d.ts +19 -3
  63. package/dist/contracts/contract-canonicalizer.js +141 -28
  64. package/dist/contracts/contract-hash.d.ts +12 -7
  65. package/dist/contracts/contract-hash.js +3 -2
  66. package/dist/contracts/contract-limits.d.ts +4 -1
  67. package/dist/contracts/contract-limits.js +1 -0
  68. package/dist/contracts/contract-lookup.d.ts +5 -5
  69. package/dist/contracts/contract-protocol.d.ts +4 -4
  70. package/dist/contracts/contract.d.ts +24 -16
  71. package/dist/contracts/create-requirements.d.ts +35 -0
  72. package/dist/contracts/create-requirements.js +1 -0
  73. package/dist/contracts/enum-definition.d.ts +1 -1
  74. package/dist/contracts/field-check.d.ts +101 -0
  75. package/dist/contracts/field-check.js +1 -0
  76. package/dist/contracts/field.d.ts +52 -42
  77. package/dist/contracts/identifier.d.ts +4 -4
  78. package/dist/contracts/json-shape.d.ts +12 -1
  79. package/dist/contracts/lifecycle-trait.d.ts +2 -2
  80. package/dist/contracts/resource-operations.d.ts +28 -28
  81. package/dist/contracts/resource.d.ts +15 -9
  82. package/dist/contracts/scalar-value-type.d.ts +15 -15
  83. package/dist/contracts/scalar.d.ts +3 -3
  84. package/dist/contracts/transaction-capability.d.ts +1 -1
  85. package/dist/contracts/wire-scalar-format.d.ts +4 -4
  86. package/dist/framework/contract-view.d.ts +213 -147
  87. package/dist/framework/framework-construction.error.d.ts +10 -10
  88. package/dist/framework/framework-construction.error.js +2 -2
  89. package/dist/framework/framework.d.ts +47 -23
  90. package/dist/framework/framework.factory.d.ts +8 -6
  91. package/dist/framework/framework.factory.js +40 -20
  92. package/dist/framework/operation-facade.d.ts +123 -52
  93. package/dist/framework/operation-facade.js +9 -1
  94. package/dist/index.d.ts +55 -50
  95. package/dist/index.js +6 -6
  96. package/dist/internal.d.ts +15 -10
  97. package/dist/internal.js +3 -1
  98. package/dist/operations/operation-arguments.d.ts +267 -202
  99. package/dist/operations/operation-call.d.ts +27 -28
  100. package/dist/operations/operation-identity.d.ts +10 -10
  101. package/dist/operations/operation-result.d.ts +21 -21
  102. package/dist/operations/operation-validator-core.d.ts +6 -6
  103. package/dist/operations/operation-validator-core.js +13 -2
  104. package/dist/operations/operation-validator.d.ts +9 -9
  105. package/dist/operations/projection-scope.resolver.d.ts +6 -6
  106. package/dist/operations/structural-limits.walker.d.ts +6 -6
  107. package/dist/operations/structural-limits.walker.js +145 -0
  108. package/dist/operations/validation-code.d.ts +11 -6
  109. package/dist/operations/validation-code.js +4 -0
  110. package/dist/operations/write-scope.resolver.d.ts +6 -6
  111. package/dist/protocol/absent-route.responder.d.ts +13 -12
  112. package/dist/protocol/absent-route.responder.js +19 -19
  113. package/dist/protocol/contract-document.responder.d.ts +3 -3
  114. package/dist/protocol/contract-document.responder.js +2 -2
  115. package/dist/protocol/http-request.decoder.d.ts +17 -13
  116. package/dist/protocol/http-request.decoder.js +10 -10
  117. package/dist/protocol/http-request.reader.d.ts +3 -3
  118. package/dist/protocol/http-response.encoder.d.ts +4 -4
  119. package/dist/protocol/http-response.encoder.js +94 -55
  120. package/dist/protocol/http-status.table.d.ts +2 -2
  121. package/dist/protocol/operation-response.guard.d.ts +2 -2
  122. package/dist/protocol/protocol-surface.d.ts +4 -4
  123. package/dist/protocol/protocol.binder.d.ts +50 -27
  124. package/dist/protocol/protocol.binder.js +12 -9
  125. package/dist/protocol/protocol.handler.d.ts +22 -13
  126. package/dist/protocol/protocol.handler.js +44 -9
  127. package/dist/protocol/unmounted-route.error.d.ts +4 -4
  128. package/dist/protocol/unmounted-route.error.js +2 -2
  129. package/dist/runtime/caller-data.copier.d.ts +5 -5
  130. package/dist/runtime/caller-data.copier.js +13 -13
  131. package/dist/runtime/caller-data.door.d.ts +6 -6
  132. package/dist/runtime/caller-data.door.js +6 -4
  133. package/dist/runtime/computed-read-runtime.d.ts +7 -6
  134. package/dist/runtime/computed-read-runtime.js +61 -48
  135. package/dist/runtime/computed-value.error.d.ts +6 -6
  136. package/dist/runtime/computed-value.error.js +3 -3
  137. package/dist/runtime/context-executor.runtime.d.ts +59 -0
  138. package/dist/runtime/context-executor.runtime.js +275 -0
  139. package/dist/runtime/create-requirement.d.ts +10 -81
  140. package/dist/runtime/create-requirement.js +80 -57
  141. package/dist/runtime/decimal.d.ts +2 -2
  142. package/dist/runtime/decimal.js +1 -1
  143. package/dist/runtime/diagnostics-reporter.d.ts +53 -27
  144. package/dist/runtime/diagnostics-reporter.js +24 -0
  145. package/dist/runtime/error-boundary.d.ts +65 -8
  146. package/dist/runtime/error-boundary.js +45 -19
  147. package/dist/runtime/execution-options.d.ts +10 -2
  148. package/dist/runtime/field-check.evaluator.d.ts +29 -0
  149. package/dist/runtime/field-check.evaluator.js +521 -0
  150. package/dist/runtime/field-compute.d.ts +64 -0
  151. package/dist/runtime/field-compute.js +1 -0
  152. package/dist/runtime/field-stage.plan.d.ts +15 -0
  153. package/dist/runtime/field-stage.plan.js +27 -0
  154. package/dist/runtime/field-stage.runtime.d.ts +35 -0
  155. package/dist/runtime/field-stage.runtime.js +143 -0
  156. package/dist/runtime/field-validator.runtime.d.ts +11 -0
  157. package/dist/runtime/field-validator.runtime.js +87 -0
  158. package/dist/runtime/framework-error-class.table.d.ts +33 -0
  159. package/dist/runtime/framework-error-class.table.js +25 -0
  160. package/dist/runtime/framework-error.d.ts +68 -8
  161. package/dist/runtime/framework-error.factory.d.ts +4 -0
  162. package/dist/runtime/framework-error.factory.js +15 -0
  163. package/dist/runtime/framework-error.js +23 -2
  164. package/dist/runtime/interceptor-next.error.d.ts +5 -0
  165. package/dist/runtime/interceptor-next.error.js +6 -0
  166. package/dist/runtime/json-value.d.ts +3 -3
  167. package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
  168. package/dist/runtime/level-lifecycle.runtime.js +42 -0
  169. package/dist/runtime/misuse-reporter.d.ts +12 -12
  170. package/dist/runtime/mutation-planner.d.ts +19 -10
  171. package/dist/runtime/mutation-planner.js +54 -30
  172. package/dist/runtime/nested-write.walker.d.ts +32 -0
  173. package/dist/runtime/nested-write.walker.js +73 -0
  174. package/dist/runtime/operation-request.d.ts +33 -6
  175. package/dist/runtime/operation-response.d.ts +17 -17
  176. package/dist/runtime/operation-runtime.d.ts +113 -25
  177. package/dist/runtime/operation-runtime.js +395 -74
  178. package/dist/runtime/outcome-mapper.d.ts +16 -5
  179. package/dist/runtime/outcome-mapper.js +23 -6
  180. package/dist/runtime/output-validator.d.ts +10 -10
  181. package/dist/runtime/output-validator.js +3 -3
  182. package/dist/runtime/owned-execution.registry.d.ts +6 -6
  183. package/dist/runtime/pipe-output.validator.d.ts +33 -18
  184. package/dist/runtime/pipe-output.validator.js +12 -12
  185. package/dist/runtime/pipeline.d.ts +196 -34
  186. package/dist/runtime/readonly-value.d.ts +32 -0
  187. package/dist/runtime/readonly-value.js +141 -0
  188. package/dist/runtime/request-envelope.validator.d.ts +3 -3
  189. package/dist/runtime/request-envelope.validator.js +12 -7
  190. package/dist/runtime/request-id.d.ts +1 -1
  191. package/dist/runtime/request-state.d.ts +14 -0
  192. package/dist/runtime/request-state.js +1 -0
  193. package/dist/runtime/request-state.resolver.d.ts +12 -0
  194. package/dist/runtime/request-state.resolver.js +20 -0
  195. package/dist/runtime/scalar-runtime.d.ts +31 -16
  196. package/dist/runtime/scalar-runtime.js +16 -18
  197. package/dist/transactions/deferred-operation.d.ts +35 -20
  198. package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
  199. package/dist/transactions/operation-arguments-encoder.js +2 -2
  200. package/dist/transactions/sql-statement.d.ts +77 -0
  201. package/dist/transactions/sql-statement.js +47 -0
  202. package/dist/transactions/sql-statement.validator.d.ts +44 -0
  203. package/dist/transactions/sql-statement.validator.js +134 -0
  204. package/dist/transactions/transaction-envelope.d.ts +4 -4
  205. package/dist/transactions/transaction-integrity-error.d.ts +6 -6
  206. package/dist/transactions/transaction-integrity-error.js +5 -2
  207. package/dist/transactions/transaction-plan-assembler.d.ts +21 -11
  208. package/dist/transactions/transaction-plan-assembler.js +148 -34
  209. package/dist/transactions/transaction-plan-validator.d.ts +29 -20
  210. package/dist/transactions/transaction-plan-validator.js +70 -38
  211. package/dist/transactions/transaction-reference-collector.d.ts +5 -5
  212. package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
  213. package/dist/transactions/transaction-reference-resolver.js +26 -14
  214. package/dist/transactions/transaction-reference-validator.d.ts +34 -4
  215. package/dist/transactions/transaction-reference-validator.js +58 -26
  216. package/dist/transactions/transaction-reference.d.ts +13 -13
  217. package/dist/transactions/transaction-request.d.ts +18 -5
  218. package/dist/transactions/transaction-response.d.ts +6 -6
  219. package/dist/transactions/transaction-runtime.d.ts +8 -7
  220. package/dist/transactions/transaction-runtime.js +166 -50
  221. package/dist/transactions/transaction-settlement.runtime.d.ts +51 -0
  222. package/dist/transactions/transaction-settlement.runtime.js +120 -0
  223. package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
  224. package/dist/transactions/transaction-slot-path-error.js +2 -2
  225. package/dist/transactions/transaction-slot-writer.js +2 -2
  226. package/dist/transactions/transaction-stage.runtime.d.ts +81 -0
  227. package/dist/transactions/transaction-stage.runtime.js +123 -0
  228. package/package.json +6 -5
  229. package/src/runtime/field-check.evaluator.ts +720 -0
  230. package/dist/config/define-fields.d.ts +0 -42
  231. package/dist/config/define-fields.js +0 -3
  232. package/dist/config/framework-behaviors-config.d.ts +0 -30
  233. package/dist/config/framework-fields-config.d.ts +0 -42
  234. package/dist/config/framework-restrictions-config.d.ts +0 -142
  235. package/dist/json/avz.d.ts +0 -96
  236. package/dist/runtime/field-behavior.d.ts +0 -48
  237. /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
  238. /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
  239. /package/dist/{json → avz}/index.js +0 -0
  240. /package/dist/{json → avz}/json-shape.registry.js +0 -0
  241. /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
  242. /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
@@ -0,0 +1,42 @@
1
+ import { frozenCopy } from "./readonly-value.js";
2
+ export async function runLevelLifecycle(levels, context, inner, settle, reuse, refuse) {
3
+ const once = (run) => {
4
+ let called = false;
5
+ return () => {
6
+ if (called) {
7
+ const refusal = refuse();
8
+ reuse.refusal ??= refusal;
9
+ return Promise.reject(refusal);
10
+ }
11
+ called = true;
12
+ return run();
13
+ };
14
+ };
15
+ const hooked = async () => {
16
+ for (const level of levels) {
17
+ for (const hook of level.hooks.before) {
18
+ await hook(context());
19
+ }
20
+ }
21
+ const result = await settle(await inner());
22
+ const after = [...levels].reverse().flatMap((level) => level.hooks.after);
23
+ if (after.length > 0) {
24
+ const told = frozenCopy(result);
25
+ for (const hook of after) {
26
+ await hook(told, context());
27
+ }
28
+ }
29
+ return result;
30
+ };
31
+ const interceptors = levels.flatMap((level) => level.interceptors);
32
+ let next = hooked;
33
+ for (let index = interceptors.length - 1; index >= 0; index -= 1) {
34
+ const interceptor = interceptors[index];
35
+ if (interceptor === undefined) {
36
+ continue;
37
+ }
38
+ const continuation = once(next);
39
+ next = () => interceptor(context(), async () => settle(await continuation()));
40
+ }
41
+ return next();
42
+ }
@@ -1,32 +1,32 @@
1
- import type { RequestOrigin } from "../config/config-layer.js";
2
- import type { OperationFamily } from "../operations/operation-identity.js";
1
+ import type { AvRequestOrigin } from "../config/config-layer.js";
2
+ import type { AvOperationFamily } from "../operations/operation-identity.js";
3
3
  /**
4
4
  * One caller value the framework refused because it could not be read
5
5
  * (`"unreadable-value"`: a revoked Proxy, a throwing getter or trap) or is not plain
6
- * data (`"non-plain-value"`: a class instance other than `Date`, `Decimal` or
6
+ * data (`"non-plain-value"`: a class instance other than `Date`, `AvDecimal` or
7
7
  * `Uint8Array`). The caller received `A2004` with one `V1001` at `path`.
8
8
  *
9
- * The operation's identity is present when the framework could read it — absent for
10
- * a request whose own envelope could not be read — and `operation` is the step's
9
+ * The operation's identity is present when the framework could read it (absent for
10
+ * a request whose own envelope could not be read), and `operation` is the step's
11
11
  * index in a transaction plan.
12
12
  */
13
- export type FrameworkMisuseEvent = {
13
+ export type AvMisuseEvent = {
14
14
  readonly kind: "unreadable-value" | "non-plain-value";
15
15
  /** The issue path the caller received. */
16
16
  readonly path: readonly (string | number)[];
17
- readonly origin?: RequestOrigin;
17
+ readonly origin?: AvRequestOrigin;
18
18
  readonly resource?: string;
19
- readonly family?: OperationFamily;
19
+ readonly family?: AvOperationFamily;
20
20
  readonly variant?: string;
21
21
  readonly operation?: number;
22
22
  };
23
23
  /**
24
- * Receives a {@link FrameworkMisuseEvent} for every caller value the framework
24
+ * Receives a {@link AvMisuseEvent} for every caller value the framework
25
25
  * refused as unreadable or not plain data. Set once, as the root configuration's
26
26
  * `misuse`. What it returns, throws or rejects with never reaches the response.
27
27
  */
28
- export type FrameworkMisuseSink = (event: FrameworkMisuseEvent) => void | Promise<void>;
28
+ export type AvMisuseSink = (event: AvMisuseEvent) => void | Promise<void>;
29
29
  /** The channel as the runtime holds it: total, never awaited. */
30
- export type MisuseReporter = (event: FrameworkMisuseEvent) => void;
30
+ export type MisuseReporter = (event: AvMisuseEvent) => void;
31
31
  /** Binds the configured sink; without one, nothing is observed. */
32
- export declare function createMisuseReporter(sink: FrameworkMisuseSink | undefined): MisuseReporter;
32
+ export declare function createMisuseReporter(sink: AvMisuseSink | undefined): MisuseReporter;
@@ -1,8 +1,9 @@
1
- import type { FrameworkBehaviorsConfig } from "../config/framework-behaviors-config.js";
2
- import type { RelationMutationDirective } from "../contracts/capability.js";
3
- import type { Contract, CoreContract } from "../contracts/contract.js";
1
+ import type { ResolvedComputeConfig } from "../config/field-compute.resolver.js";
2
+ import type { AvRelationMutationDirective } from "../contracts/capability.js";
3
+ import type { AvContract, AvContractCore } from "../contracts/contract.js";
4
+ import type { AvComputeContext } from "./field-compute.js";
5
+ import type { NestedWriteTarget } from "./nested-write.walker.js";
4
6
  import type { OperationExecutionRequest } from "./operation-request.js";
5
- import type { PipelineContext } from "./pipeline.js";
6
7
  /**
7
8
  * The two Contracts a write reads. The Core Contract decides what the Adapter is asked
8
9
  * to store; the active Contract adds the fields its scope declared under
@@ -10,11 +11,11 @@ import type { PipelineContext } from "./pipeline.js";
10
11
  * virtual: its behaviours run and its value is stripped before the Adapter call.
11
12
  */
12
13
  export type WriteContracts = {
13
- readonly core: CoreContract;
14
- readonly active: Contract;
14
+ readonly core: AvContractCore;
15
+ readonly active: AvContract;
15
16
  };
16
17
  type WriteStage = "create" | "update";
17
- type ContextFactory = (args: unknown) => PipelineContext;
18
+ type ContextFactory = (args: unknown) => AvComputeContext;
18
19
  export type RelationRecordSite = {
19
20
  readonly key: string | undefined;
20
21
  readonly stage: WriteStage;
@@ -53,9 +54,17 @@ export declare const RELATION_MUTATION_RECORD_SITES: {
53
54
  * membership, not an assertion: `Object.prototype` members resolve through the
54
55
  * prototype chain and would otherwise reach a site loop with a non-iterable.
55
56
  */
56
- export declare function isRelationMutationDirective(key: string): key is RelationMutationDirective;
57
- /** Apply effective computed create/update field behavior to post-pipe logical args. */
58
- export declare function applyWriteFieldBehaviors(contracts: WriteContracts, behaviors: FrameworkBehaviorsConfig | undefined, request: OperationExecutionRequest, args: unknown, contextFactory: ContextFactory): Promise<unknown>;
57
+ export declare function isRelationMutationDirective(key: string): key is AvRelationMutationDirective;
58
+ /** Apply the effective create/update compute stages to the post-pipe logical args. */
59
+ export declare function applyWriteCompute(contracts: WriteContracts, compute: ResolvedComputeConfig | undefined, request: OperationExecutionRequest, args: unknown, contextFactory: ContextFactory): Promise<unknown>;
60
+ /**
61
+ * Applies each nested target's write compute, in the targets' order, to its
62
+ * records: `compute.create` on a created row (an `$upsert`'s `create` branch
63
+ * too), `compute.update` on an updated one. Each target's stages are told
64
+ * `context(target, payload)`, the nested target's own context. The arguments
65
+ * are copied where a record changes, never written.
66
+ */
67
+ export declare function applyNestedWriteCompute(contracts: WriteContracts, compute: ResolvedComputeConfig | undefined, args: unknown, targets: readonly NestedWriteTarget[], context: (target: NestedWriteTarget, payload: unknown) => AvComputeContext): Promise<unknown>;
59
68
  /** Strip VIRTUAL scalar input only at the persistence boundary. */
60
69
  export declare function stripVirtualMutationInput(contracts: WriteContracts, request: OperationExecutionRequest, args: unknown): Promise<unknown>;
61
70
  export {};
@@ -1,5 +1,6 @@
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
+ import { replaceAt, valueAt } from "./field-stage.runtime.js";
3
4
  import { jsonShapeIssues, normalizeScalarFieldValue, } from "./scalar-runtime.js";
4
5
  function writeScalarField(contracts, resourceName, fieldName) {
5
6
  const field = lookupField(lookupResource(contracts.core, resourceName), fieldName) ??
@@ -33,7 +34,7 @@ function cloneRecord(value) {
33
34
  function relationEntries(value) {
34
35
  return Array.isArray(value) ? value : [value];
35
36
  }
36
- async function computeRecord(contracts, behaviors, request, resourceName, stage, data, contextFactory) {
37
+ async function computeRecord(contracts, compute, resourceName, stage, data, contextFactory) {
37
38
  if (!isRecord(data)) {
38
39
  return data;
39
40
  }
@@ -42,13 +43,13 @@ async function computeRecord(contracts, behaviors, request, resourceName, stage,
42
43
  return data;
43
44
  }
44
45
  const logicalData = cloneRecord(data);
45
- const resourceBehaviors = behaviors[resourceName]?.fields;
46
- if (resourceBehaviors !== undefined) {
47
- for (const [fieldName, fieldBehavior] of Object.entries(resourceBehaviors)) {
48
- if (fieldBehavior === undefined) {
46
+ const resourceCompute = compute[resourceName];
47
+ if (resourceCompute !== undefined) {
48
+ for (const [fieldName, fieldCompute] of Object.entries(resourceCompute)) {
49
+ if (fieldCompute === undefined) {
49
50
  continue;
50
51
  }
51
- const callback = fieldBehavior[stage];
52
+ const callback = fieldCompute[stage];
52
53
  if (typeof callback !== "function") {
53
54
  continue;
54
55
  }
@@ -56,40 +57,43 @@ async function computeRecord(contracts, behaviors, request, resourceName, stage,
56
57
  if (field === undefined) {
57
58
  continue;
58
59
  }
60
+ const snapshot = Object.freeze({ ...logicalData });
59
61
  const computed = await callback({
60
- origin: request.origin,
61
- resource: resourceName,
62
62
  field: fieldName,
63
- value: logicalData[fieldName],
64
- data: logicalData,
65
- operation: contextFactory(logicalData),
63
+ value: snapshot[fieldName],
64
+ data: snapshot,
65
+ ctx: contextFactory(snapshot),
66
66
  });
67
67
  if (computed === undefined) {
68
68
  continue;
69
69
  }
70
- const validation = normalizeScalarFieldValue(contracts.core, field, computed, "runtime", ["behaviors", resourceName, fieldName, stage]);
70
+ const validation = normalizeScalarFieldValue(contracts.core, field, computed, "runtime", [
71
+ "resources",
72
+ resourceName,
73
+ "fields",
74
+ fieldName,
75
+ "pipelines",
76
+ "compute",
77
+ stage,
78
+ ]);
71
79
  if (!validation.ok) {
72
- throw new ComputedValueError(resourceName, fieldName, stage, validation.issues);
80
+ throw new AvComputedValueError(resourceName, fieldName, stage, validation.issues);
73
81
  }
74
82
  const shapeIssues = jsonShapeIssues(field, validation.value, [
75
- "behaviors",
83
+ "resources",
76
84
  resourceName,
85
+ "fields",
77
86
  fieldName,
87
+ "pipelines",
88
+ "compute",
78
89
  stage,
79
90
  ]);
80
91
  if (shapeIssues.length > 0) {
81
- throw new ComputedValueError(resourceName, fieldName, stage, shapeIssues);
92
+ throw new AvComputedValueError(resourceName, fieldName, stage, shapeIssues);
82
93
  }
83
94
  logicalData[fieldName] = validation.value;
84
95
  }
85
96
  }
86
- for (const [fieldName, value] of Object.entries(logicalData)) {
87
- const field = lookupField(resource, fieldName);
88
- if (field?.kind !== "relation") {
89
- continue;
90
- }
91
- logicalData[fieldName] = await mapRelationMutationRecords(field, value, (targetResource, nestedStage, record) => computeRecord(contracts, behaviors, request, targetResource, nestedStage, record, contextFactory));
92
- }
93
97
  return logicalData;
94
98
  }
95
99
  async function mapRelationMutationRecords(relation, value, leaf) {
@@ -125,29 +129,49 @@ async function mapRelationMutationRecords(relation, value, leaf) {
125
129
  }
126
130
  return normalized;
127
131
  }
128
- export async function applyWriteFieldBehaviors(contracts, behaviors, request, args, contextFactory) {
129
- if (behaviors === undefined || !isRecord(args)) {
132
+ export async function applyWriteCompute(contracts, compute, request, args, contextFactory) {
133
+ if (compute === undefined || !isRecord(args)) {
130
134
  return args;
131
135
  }
132
136
  const logicalArgs = cloneRecord(args);
133
137
  if (request.family === "create" && "data" in logicalArgs) {
134
138
  logicalArgs.data = Array.isArray(logicalArgs.data)
135
- ? await Promise.all(logicalArgs.data.map((entry) => computeRecord(contracts, behaviors, request, request.resource, "create", entry, contextFactory)))
136
- : await computeRecord(contracts, behaviors, request, request.resource, "create", logicalArgs.data, contextFactory);
139
+ ? await Promise.all(logicalArgs.data.map((entry) => computeRecord(contracts, compute, request.resource, "create", entry, contextFactory)))
140
+ : await computeRecord(contracts, compute, request.resource, "create", logicalArgs.data, contextFactory);
137
141
  }
138
142
  if (request.family === "update" && "data" in logicalArgs) {
139
- logicalArgs.data = await computeRecord(contracts, behaviors, request, request.resource, "update", logicalArgs.data, contextFactory);
143
+ logicalArgs.data = await computeRecord(contracts, compute, request.resource, "update", logicalArgs.data, contextFactory);
140
144
  }
141
145
  if (request.family === "upsert") {
142
146
  if ("create" in logicalArgs) {
143
- logicalArgs.create = await computeRecord(contracts, behaviors, request, request.resource, "create", logicalArgs.create, contextFactory);
147
+ logicalArgs.create = await computeRecord(contracts, compute, request.resource, "create", logicalArgs.create, contextFactory);
144
148
  }
145
149
  if ("update" in logicalArgs) {
146
- logicalArgs.update = await computeRecord(contracts, behaviors, request, request.resource, "update", logicalArgs.update, contextFactory);
150
+ logicalArgs.update = await computeRecord(contracts, compute, request.resource, "update", logicalArgs.update, contextFactory);
147
151
  }
148
152
  }
149
153
  return logicalArgs;
150
154
  }
155
+ export async function applyNestedWriteCompute(contracts, compute, args, targets, context) {
156
+ if (compute === undefined) {
157
+ return args;
158
+ }
159
+ let current = args;
160
+ for (const target of targets) {
161
+ if (!Object.hasOwn(compute, target.resource)) {
162
+ continue;
163
+ }
164
+ for (const site of target.records) {
165
+ const record = valueAt(current, site.path);
166
+ if (!isRecord(record)) {
167
+ continue;
168
+ }
169
+ const computed = await computeRecord(contracts, compute, target.resource, site.stage, record, () => context(target, valueAt(current, target.path)));
170
+ current = replaceAt(current, site.path, computed);
171
+ }
172
+ }
173
+ return current;
174
+ }
151
175
  async function stripVirtualRecord(contracts, resourceName, data) {
152
176
  if (!isRecord(data)) {
153
177
  return data;
@@ -0,0 +1,32 @@
1
+ import type { AvContract } from "../contracts/contract.js";
2
+ import type { AvOperationIdentity } from "../operations/operation-identity.js";
3
+ import { type Path } from "./field-stage.runtime.js";
4
+ import type { ReferentialActionTable } from "./referential-action.js";
5
+ /** The family a nested target's stages are told, and its guards are drawn from. */
6
+ export type NestedTargetFamily = "create" | "update" | "delete";
7
+ /** One record of a nested target's data, and the write phase it is. */
8
+ export type NestedRecordSite = {
9
+ /** Where the record sits in the operation's arguments. */
10
+ readonly path: Path;
11
+ /** `create` for a created row (an `$upsert`'s `create` branch too), `update` otherwise. */
12
+ readonly stage: "create" | "update";
13
+ };
14
+ /** One nested write's target, in data order. */
15
+ export type NestedWriteTarget = {
16
+ /** The target Resource. */
17
+ readonly resource: string;
18
+ readonly family: NestedTargetFamily;
19
+ /** Where the directive's entry — the nested payload — sits in the arguments. */
20
+ readonly path: Path;
21
+ /** The entry's data records the target's field stages run on. */
22
+ readonly records: readonly NestedRecordSite[];
23
+ };
24
+ /**
25
+ * Every nested write target in an operation's arguments, depth first in data
26
+ * order: a target comes before the targets inside its own data, and before the
27
+ * next directive's. Empty for an operation with no write data. Total over
28
+ * malformed input.
29
+ */
30
+ export declare function nestedWriteTargetsOf(contract: AvContract, references: ReferentialActionTable, request: AvOperationIdentity & {
31
+ readonly resource: string;
32
+ }, args: unknown): readonly NestedWriteTarget[];
@@ -0,0 +1,73 @@
1
+ import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
+ import { isPlainRecord, valueAt, writeRecordPathsOf, } from "./field-stage.runtime.js";
3
+ import { isRelationMutationDirective, RELATION_MUTATION_RECORD_SITES, } from "./mutation-planner.js";
4
+ const DIRECTIVE_FAMILY = {
5
+ $create: "create",
6
+ $connectOrCreate: "create",
7
+ $update: "update",
8
+ $upsert: "update",
9
+ $delete: "delete",
10
+ $connect: "relation",
11
+ $disconnect: "relation",
12
+ $set: "relation",
13
+ };
14
+ function holdsReference(references, resource, relation) {
15
+ const edges = Object.hasOwn(references, resource)
16
+ ? references[resource]
17
+ : undefined;
18
+ return (Array.isArray(edges) &&
19
+ edges.some((edge) => edge.field === relation));
20
+ }
21
+ function walkRecord(context, resource, path, record) {
22
+ if (!isPlainRecord(record)) {
23
+ return;
24
+ }
25
+ const owner = lookupResource(context.contract, resource);
26
+ for (const [key, value] of Object.entries(record)) {
27
+ const field = lookupField(owner, key);
28
+ if (field?.kind !== "relation" || !isPlainRecord(value)) {
29
+ continue;
30
+ }
31
+ for (const [directive, operand] of Object.entries(value)) {
32
+ if (!isRelationMutationDirective(directive)) {
33
+ continue;
34
+ }
35
+ const mapped = DIRECTIVE_FAMILY[directive];
36
+ if (mapped === "relation" &&
37
+ field.cardinality === "one" &&
38
+ holdsReference(context.references, resource, key)) {
39
+ continue;
40
+ }
41
+ const family = mapped === "relation" ? "update" : mapped;
42
+ const entries = directive !== "$set" && Array.isArray(operand)
43
+ ? operand.map((_entry, index) => [index])
44
+ : [[]];
45
+ for (const at of entries) {
46
+ const entryPath = [...path, key, directive, ...at];
47
+ const records = [];
48
+ for (const site of RELATION_MUTATION_RECORD_SITES[directive]) {
49
+ const sitePath = site.key === undefined ? entryPath : [...entryPath, site.key];
50
+ if (isPlainRecord(valueAt(record, sitePath.slice(path.length)))) {
51
+ records.push({ path: sitePath, stage: site.stage });
52
+ }
53
+ }
54
+ context.targets.push({
55
+ resource: field.target,
56
+ family,
57
+ path: entryPath,
58
+ records,
59
+ });
60
+ for (const site of records) {
61
+ walkRecord(context, field.target, site.path, valueAt(record, site.path.slice(path.length)));
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ export function nestedWriteTargetsOf(contract, references, request, args) {
68
+ const context = { contract, references, targets: [] };
69
+ for (const path of writeRecordPathsOf(request.family, args)) {
70
+ walkRecord(context, request.resource, path, valueAt(args, path));
71
+ }
72
+ return context.targets;
73
+ }
@@ -1,14 +1,23 @@
1
- import type { OperationIdentity } from "../operations/operation-identity.js";
2
- import type { PipelineTransportContext } from "./pipeline.js";
3
- /** The protocol version and ClientContract hash a client says it was built for. */
1
+ import type { AvOperationIdentity } from "../operations/operation-identity.js";
2
+ import type { AvTransportContext } from "./pipeline.js";
3
+ import type { AvState } from "./request-state.js";
4
+ /**
5
+ * The protocol version and Contract hash a remote caller says it was built for:
6
+ * the Client Contract's for a client, the Agent Contract's for an agent.
7
+ */
4
8
  export type ClientProtocolIdentity = {
5
9
  readonly version: number;
6
10
  readonly hash: string;
7
11
  };
8
- type RuntimeOperationBase = OperationIdentity & {
12
+ type RuntimeOperationBase = AvOperationIdentity & {
9
13
  readonly resource: string;
10
14
  readonly arguments: unknown;
11
15
  readonly requestId: string;
16
+ /**
17
+ * The request's `ctx.$state`: every stage of it, and every ctx call they make,
18
+ * shares this one object. Omitted, it is a fresh `{}`.
19
+ */
20
+ readonly state?: AvState;
12
21
  };
13
22
  /** An in-process request, run under the Application Contract. */
14
23
  export type ApplicationOperationRequest = RuntimeOperationBase & {
@@ -23,10 +32,21 @@ export type ApplicationOperationRequest = RuntimeOperationBase & {
23
32
  export type ClientOperationRequest = RuntimeOperationBase & {
24
33
  readonly origin: "client";
25
34
  readonly protocol: ClientProtocolIdentity;
26
- readonly transport?: PipelineTransportContext;
35
+ readonly transport?: AvTransportContext;
27
36
  };
37
+ /**
38
+ * An AI agent's request, run under the Agent Contract; `protocol` is the
39
+ * identity of the Agent Contract the caller (an MCP server) was built from.
40
+ */
41
+ export type AgentOperationRequest = RuntimeOperationBase & {
42
+ readonly origin: "agent";
43
+ readonly protocol: ClientProtocolIdentity;
44
+ readonly transport?: AvTransportContext;
45
+ };
46
+ /** A request from outside the server: a client's or an agent's. */
47
+ export type RemoteOperationRequest = ClientOperationRequest | AgentOperationRequest;
28
48
  /** One operation request, as `framework.execute` takes it. */
29
- export type FrameworkOperationRequest = ApplicationOperationRequest | ClientOperationRequest;
49
+ export type FrameworkOperationRequest = ApplicationOperationRequest | ClientOperationRequest | AgentOperationRequest;
30
50
  type WithoutArguments<Request> = Request extends unknown ? Omit<Request, "arguments"> : never;
31
51
  /**
32
52
  * A request as every stage after the Framework Validation Layer sees it:
@@ -37,4 +57,11 @@ type WithoutArguments<Request> = Request extends unknown ? Omit<Request, "argume
37
57
  * correlations survive the omission.
38
58
  */
39
59
  export type OperationExecutionRequest = WithoutArguments<FrameworkOperationRequest>;
60
+ /**
61
+ * A request whose stages run: its `state` settled once, the seed or the `{}`
62
+ * the runtime made for it, so every stage is told the same object.
63
+ */
64
+ export type StatefulOperationRequest = OperationExecutionRequest & {
65
+ readonly state: AvState;
66
+ };
40
67
  export {};
@@ -1,50 +1,50 @@
1
- import type { ValidationIssue } from "../operations/validation-code.js";
1
+ import type { AvValidationIssue } from "../operations/validation-code.js";
2
2
  /** Every outcome code, as a runtime list. */
3
3
  export declare const OPERATION_CODES: readonly ["A1000", "A1001", "A1002", "A1003", "A1004", "A1005", "A1006", "A1007", "A1008", "A1009", "A2000", "A2001", "A2002", "A2003", "A2004", "A2005", "A2006", "A2007", "A2008", "A2009", "A2010", "A2011", "A2012", "A2013", "A2014", "A3000", "A3001", "A3002", "A3003", "A3004", "A4000", "A4001", "A4002"];
4
4
  /**
5
5
  * Every outcome code: `A1xxx` success, `A2xxx` caller error, `A3xxx` internal
6
6
  * failure, `A4xxx` authentication or permission denial.
7
7
  */
8
- export type OperationCode = (typeof OPERATION_CODES)[number];
8
+ export type AvOperationCode = (typeof OPERATION_CODES)[number];
9
9
  /** The success codes, `A1xxx`. */
10
- export type OperationSuccessCode = Extract<OperationCode, `A1${string}`>;
10
+ export type AvOperationSuccessCode = Extract<AvOperationCode, `A1${string}`>;
11
11
  /** Every outcome code that is not a success. */
12
- export type OperationErrorCode = Exclude<OperationCode, OperationSuccessCode>;
12
+ export type AvOperationErrorCode = Exclude<AvOperationCode, AvOperationSuccessCode>;
13
13
  /** Internal-failure family: nothing in the cause is caller-actionable. */
14
- export type OperationInternalErrorCode = Extract<OperationErrorCode, `A3${string}`>;
14
+ export type OperationInternalErrorCode = Extract<AvOperationErrorCode, `A3${string}`>;
15
15
  /** Why a request failed: a message, and the validation issues when there are any. */
16
- export type Cause = {
16
+ export type AvCause = {
17
17
  readonly message: string;
18
- readonly issues?: readonly ValidationIssue[];
18
+ readonly issues?: readonly AvValidationIssue[];
19
19
  readonly operation?: number;
20
20
  };
21
21
  /** The response envelope: `{ data, code, cause }`. */
22
- type OperationResponseEnvelope<TData, TCode extends OperationCode, TCause extends Cause | null> = {
22
+ type OperationResponseEnvelope<TData, TCode extends AvOperationCode, TCause extends AvCause | null> = {
23
23
  readonly data: TData;
24
24
  readonly code: TCode;
25
25
  readonly cause: TCause;
26
26
  };
27
27
  /** Success codes that carry response data (every success code but A1001). */
28
- export type OperationSuccessDataCode = Exclude<OperationSuccessCode, "A1001">;
28
+ export type AvOperationSuccessDataCode = Exclude<AvOperationSuccessCode, "A1001">;
29
29
  /** A success with data: `cause` is `null`. */
30
- export type OperationSuccessResponse<T> = OperationResponseEnvelope<T, OperationSuccessDataCode, null>;
30
+ export type AvOperationSuccessResponse<T> = OperationResponseEnvelope<T, AvOperationSuccessDataCode, null>;
31
31
  /** A success with no matching row (`A1001`): `data` and `cause` are `null`. */
32
- export type OperationNoMatchResponse = OperationResponseEnvelope<null, "A1001", null>;
32
+ export type AvOperationNoMatchResponse = OperationResponseEnvelope<null, "A1001", null>;
33
33
  /** A failure: `data` is `null` and `cause` says why. */
34
- export type OperationFailureResponse = OperationResponseEnvelope<null, OperationErrorCode, Cause>;
34
+ export type AvOperationFailureResponse = OperationResponseEnvelope<null, AvOperationErrorCode, AvCause>;
35
35
  /**
36
36
  * What an operation answers: success with data, a no-match success (`A1001`),
37
37
  * or a failure with a cause.
38
38
  */
39
- export type OperationResponse<T = unknown> = OperationSuccessResponse<T> | OperationNoMatchResponse | OperationFailureResponse;
39
+ export type AvOperationResponse<T = unknown> = AvOperationSuccessResponse<T> | AvOperationNoMatchResponse | AvOperationFailureResponse;
40
40
  /** Builds a success response with data. */
41
- export declare function operationSuccess<T>(data: T, code: OperationSuccessDataCode): OperationSuccessResponse<T>;
41
+ export declare function operationSuccess<T>(data: T, code: AvOperationSuccessDataCode): AvOperationSuccessResponse<T>;
42
42
  /** Builds the no-match success arm (A1001). */
43
- export declare function operationNoMatch(): OperationNoMatchResponse;
43
+ export declare function operationNoMatch(): AvOperationNoMatchResponse;
44
44
  /** Builds a failure response. */
45
- export declare function operationFailure(code: OperationErrorCode, cause: Cause): OperationFailureResponse;
45
+ export declare function operationFailure(code: AvOperationErrorCode, cause: AvCause): AvOperationFailureResponse;
46
46
  /** The one generic internal-failure text; every A3000 carries it. */
47
47
  export declare const INTERNAL_FAILURE_MESSAGE = "Internal framework error.";
48
48
  /** The response every internal failure (`A3000`) answers with. */
49
- export declare function internalFailure(): OperationFailureResponse;
49
+ export declare function internalFailure(): AvOperationFailureResponse;
50
50
  export {};