@aventara/core 0.1.0-pilot.3 → 1.0.0-rc.0

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 (167) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/README.md +100 -3
  3. package/dist/adapters/adapter-discovery-diagnostic.d.ts +2 -0
  4. package/dist/adapters/adapter-field.d.ts +3 -26
  5. package/dist/adapters/adapter-identifier.d.ts +1 -11
  6. package/dist/adapters/adapter-model.d.ts +12 -0
  7. package/dist/adapters/adapter-operation-executor.interface.d.ts +5 -1
  8. package/dist/adapters/adapter-resource.d.ts +7 -28
  9. package/dist/adapters/adapter.interface.d.ts +25 -26
  10. package/dist/compiler/contract-compiler-diagnostic.d.ts +8 -0
  11. package/dist/compiler/contract.compiler.d.ts +11 -22
  12. package/dist/compiler/contract.compiler.js +67 -0
  13. package/dist/config/any-framework-config.d.ts +5 -26
  14. package/dist/config/config-diagnostic.d.ts +2 -0
  15. package/dist/config/config-layer.d.ts +6 -19
  16. package/dist/config/config.resolver.d.ts +9 -14
  17. package/dist/config/config.resolver.js +1 -0
  18. package/dist/config/config.validator.d.ts +6 -3
  19. package/dist/config/config.validator.js +6 -0
  20. package/dist/config/define-fields.d.ts +15 -48
  21. package/dist/config/effective-fields.d.ts +6 -29
  22. package/dist/config/entrypoint.normalizer.d.ts +6 -18
  23. package/dist/config/framework-behaviors-config.d.ts +11 -10
  24. package/dist/config/framework-config.d.ts +19 -16
  25. package/dist/config/framework-fields-config.d.ts +20 -7
  26. package/dist/config/framework-restrictions-config.d.ts +41 -61
  27. package/dist/config/pipeline-config.d.ts +7 -17
  28. package/dist/contracts/capability.d.ts +13 -49
  29. package/dist/contracts/client-contract-structure.validator.d.ts +28 -54
  30. package/dist/contracts/client-contract-structure.validator.js +99 -2
  31. package/dist/contracts/contract-canonicalizer.d.ts +4 -6
  32. package/dist/contracts/contract-canonicalizer.js +32 -0
  33. package/dist/contracts/contract-hash.d.ts +3 -2
  34. package/dist/contracts/contract-limits.d.ts +7 -1
  35. package/dist/contracts/contract-protocol.d.ts +7 -8
  36. package/dist/contracts/contract.d.ts +20 -4
  37. package/dist/contracts/enum-definition.d.ts +2 -0
  38. package/dist/contracts/field.d.ts +40 -167
  39. package/dist/contracts/identifier.d.ts +1 -16
  40. package/dist/contracts/json-shape.d.ts +65 -0
  41. package/dist/contracts/json-shape.js +1 -0
  42. package/dist/contracts/lifecycle-trait.d.ts +4 -3
  43. package/dist/contracts/reference-write-limit.d.ts +7 -0
  44. package/dist/contracts/reference-write-limit.js +1 -0
  45. package/dist/contracts/resource-operations.d.ts +2 -62
  46. package/dist/contracts/resource.d.ts +2 -0
  47. package/dist/contracts/scalar-value-type.d.ts +28 -48
  48. package/dist/contracts/scalar.d.ts +4 -3
  49. package/dist/contracts/transaction-capability.d.ts +2 -0
  50. package/dist/contracts/wire-scalar-format.d.ts +6 -21
  51. package/dist/framework/contract-view.d.ts +152 -130
  52. package/dist/framework/framework-construction.error.d.ts +6 -1
  53. package/dist/framework/framework.d.ts +33 -46
  54. package/dist/framework/framework.factory.d.ts +3 -17
  55. package/dist/framework/framework.factory.js +56 -13
  56. package/dist/framework/operation-facade.d.ts +3 -7
  57. package/dist/index.d.ts +8 -40
  58. package/dist/index.js +0 -20
  59. package/dist/internal.d.ts +35 -0
  60. package/dist/internal.js +16 -0
  61. package/dist/json/avz.d.ts +96 -0
  62. package/dist/json/avz.js +212 -0
  63. package/dist/json/index.d.ts +6 -0
  64. package/dist/json/index.js +1 -0
  65. package/dist/json/json-shape.registry.d.ts +22 -0
  66. package/dist/json/json-shape.registry.js +16 -0
  67. package/dist/json/zod-issue.translator.d.ts +51 -0
  68. package/dist/json/zod-issue.translator.js +142 -0
  69. package/dist/operations/operation-arguments.d.ts +198 -303
  70. package/dist/operations/operation-call.d.ts +13 -15
  71. package/dist/operations/operation-identity.d.ts +6 -2
  72. package/dist/operations/operation-identity.js +3 -0
  73. package/dist/operations/operation-result.d.ts +15 -61
  74. package/dist/operations/operation-validator-core.d.ts +6 -5
  75. package/dist/operations/operation-validator-core.js +28 -10
  76. package/dist/operations/operation-validator.d.ts +22 -9
  77. package/dist/operations/operation-validator.js +26 -10
  78. package/dist/operations/projection-scope.resolver.d.ts +1 -11
  79. package/dist/operations/structural-limits.walker.d.ts +19 -0
  80. package/dist/operations/structural-limits.walker.js +344 -0
  81. package/dist/operations/validation-code.d.ts +5 -17
  82. package/dist/operations/write-scope.resolver.d.ts +3 -28
  83. package/dist/protocol/absent-route.responder.d.ts +25 -39
  84. package/dist/protocol/absent-route.responder.js +32 -6
  85. package/dist/protocol/av-protocol.d.ts +2 -8
  86. package/dist/protocol/contract-document.responder.d.ts +5 -18
  87. package/dist/protocol/http-request.decoder.d.ts +18 -59
  88. package/dist/protocol/http-request.decoder.js +11 -3
  89. package/dist/protocol/http-request.reader.d.ts +5 -5
  90. package/dist/protocol/http-response.encoder.d.ts +14 -20
  91. package/dist/protocol/http-status.table.d.ts +0 -8
  92. package/dist/protocol/index.d.ts +2 -7
  93. package/dist/protocol/operation-response.guard.d.ts +0 -15
  94. package/dist/protocol/protocol-failure.d.ts +8 -27
  95. package/dist/protocol/protocol-headers.d.ts +15 -42
  96. package/dist/protocol/protocol-surface.d.ts +0 -22
  97. package/dist/protocol/protocol.binder.d.ts +19 -27
  98. package/dist/protocol/protocol.binder.js +3 -1
  99. package/dist/protocol/protocol.handler.d.ts +19 -23
  100. package/dist/protocol/protocol.handler.js +14 -4
  101. package/dist/protocol/unmounted-route.error.d.ts +19 -0
  102. package/dist/protocol/unmounted-route.error.js +10 -0
  103. package/dist/runtime/caller-data.copier.d.ts +59 -0
  104. package/dist/runtime/caller-data.copier.js +470 -0
  105. package/dist/runtime/caller-data.door.d.ts +56 -0
  106. package/dist/runtime/caller-data.door.js +65 -0
  107. package/dist/runtime/computed-read-runtime.js +3 -10
  108. package/dist/runtime/computed-value.error.d.ts +13 -0
  109. package/dist/runtime/computed-value.error.js +9 -0
  110. package/dist/runtime/create-requirement.d.ts +43 -7
  111. package/dist/runtime/create-requirement.js +89 -9
  112. package/dist/runtime/decimal.d.ts +5 -3
  113. package/dist/runtime/diagnostics-reporter.d.ts +33 -37
  114. package/dist/runtime/diagnostics-reporter.js +11 -4
  115. package/dist/runtime/error-boundary.d.ts +14 -10
  116. package/dist/runtime/error-boundary.js +65 -35
  117. package/dist/runtime/execution-options.d.ts +3 -7
  118. package/dist/runtime/field-behavior.d.ts +14 -21
  119. package/dist/runtime/framework-error.d.ts +14 -2
  120. package/dist/runtime/json-value.d.ts +7 -15
  121. package/dist/runtime/misuse-reporter.d.ts +32 -0
  122. package/dist/runtime/misuse-reporter.js +19 -0
  123. package/dist/runtime/mutation-planner.d.ts +6 -12
  124. package/dist/runtime/mutation-planner.js +13 -11
  125. package/dist/runtime/operation-request.d.ts +11 -11
  126. package/dist/runtime/operation-response.d.ts +18 -23
  127. package/dist/runtime/operation-runtime.d.ts +25 -33
  128. package/dist/runtime/operation-runtime.js +37 -18
  129. package/dist/runtime/outcome-mapper.js +12 -2
  130. package/dist/runtime/output-validator.d.ts +10 -0
  131. package/dist/runtime/output-validator.js +11 -0
  132. package/dist/runtime/owned-execution.registry.d.ts +13 -0
  133. package/dist/runtime/owned-execution.registry.js +7 -0
  134. package/dist/runtime/pipeline.d.ts +33 -36
  135. package/dist/runtime/referential-action.d.ts +8 -26
  136. package/dist/runtime/request-envelope.validator.d.ts +5 -0
  137. package/dist/runtime/request-envelope.validator.js +118 -0
  138. package/dist/runtime/request-id.d.ts +3 -10
  139. package/dist/runtime/scalar-runtime.d.ts +42 -14
  140. package/dist/runtime/scalar-runtime.js +162 -79
  141. package/dist/transactions/deferred-operation.d.ts +10 -21
  142. package/dist/transactions/operation-arguments-encoder.d.ts +1 -0
  143. package/dist/transactions/operation-fingerprint.d.ts +3 -1
  144. package/dist/transactions/transaction-envelope.d.ts +2 -4
  145. package/dist/transactions/transaction-integrity-error.d.ts +4 -15
  146. package/dist/transactions/transaction-plan-assembler.d.ts +6 -1
  147. package/dist/transactions/transaction-plan-assembler.js +74 -75
  148. package/dist/transactions/transaction-plan-validator.d.ts +33 -24
  149. package/dist/transactions/transaction-plan-validator.js +204 -153
  150. package/dist/transactions/transaction-reference-collector.d.ts +30 -0
  151. package/dist/transactions/transaction-reference-collector.js +204 -0
  152. package/dist/transactions/transaction-reference-resolver.d.ts +9 -12
  153. package/dist/transactions/transaction-reference-resolver.js +10 -5
  154. package/dist/transactions/transaction-reference-validator.js +24 -17
  155. package/dist/transactions/transaction-reference.d.ts +31 -64
  156. package/dist/transactions/transaction-request.d.ts +6 -8
  157. package/dist/transactions/transaction-response.d.ts +10 -7
  158. package/dist/transactions/transaction-response.js +24 -1
  159. package/dist/transactions/transaction-runtime.d.ts +7 -5
  160. package/dist/transactions/transaction-runtime.js +4 -3
  161. package/dist/transactions/transaction-slot-path-error.d.ts +5 -15
  162. package/dist/transactions/transaction-slot-writer.d.ts +3 -13
  163. package/package.json +17 -3
  164. package/dist/operations/operation-boolean-nodes.d.ts +0 -11
  165. package/dist/operations/operation-boolean-nodes.js +0 -283
  166. package/dist/operations/operation-nesting.d.ts +0 -8
  167. package/dist/operations/operation-nesting.js +0 -307
@@ -3,6 +3,7 @@ import type { ExecutionOptions } from "../runtime/execution-options.js";
3
3
  import type { OperationFailureResponse } from "../runtime/operation-response.js";
4
4
  import type { TransactionReference } from "./transaction-reference.js";
5
5
  import type { TransactionCommittedResponse } from "./transaction-response.js";
6
+ /** An operation fingerprint: `fp1:` and a hash of the operation and its arguments. */
6
7
  export type OperationFingerprint = `fp1:${string}`;
7
8
  /** One serializable transaction-plan operation node. */
8
9
  export type DeferredOperation = OperationIdentity & {
@@ -10,36 +11,28 @@ export type DeferredOperation = OperationIdentity & {
10
11
  readonly args: unknown;
11
12
  readonly fingerprint: OperationFingerprint;
12
13
  };
14
+ /** A transaction plan: its operations, in the order they run. */
13
15
  export type TransactionPlan = {
14
16
  readonly operations: readonly DeferredOperation[];
15
17
  };
16
18
  declare const OPERATION_RESULT: unique symbol;
17
19
  declare const OPERATION_HANDLE: unique symbol;
18
- /**
19
- * Standard-library shapes that are objects but never a projected result row.
20
- * `ArrayBufferView` is TypeScript's shared structural base for every typed array
21
- * and `DataView`, so no constructor is enumerated and the declaration stays
22
- * portable ES2022 with no runtime dependency.
23
- */
20
+ /** Standard-library shapes that are objects but never a projected result row. */
24
21
  export type BuiltinNonRow = Date | RegExp | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | PromiseLike<unknown> | ArrayBufferView;
25
22
  /**
26
- * The single row behind a supplied result type, or `never` when the result is
27
- * not one referenceable row. Declaration-only: arrays, functions, the
28
- * `BuiltinNonRow` shapes, non-objects, and objects without a string key are
29
- * excluded without any `instanceof` test or `Record<string, unknown>` gate,
30
- * which ordinary interfaces would fail.
23
+ * The single row behind a result type, or `never` when the result is not one
24
+ * referenceable row.
31
25
  */
32
26
  export type SingleRowResult<T> = NonNullable<T> extends readonly unknown[] ? never : NonNullable<T> extends (...args: never[]) => unknown ? never : NonNullable<T> extends BuiltinNonRow ? never : NonNullable<T> extends object ? Extract<keyof NonNullable<T>, string> extends never ? never : NonNullable<T> : never;
33
27
  /** The field names a result row can be referenced by. */
34
28
  export type ReferenceableField<T> = Extract<keyof SingleRowResult<T>, string>;
29
+ /** Builds a `$ref` to one field of this handle's row, typed as that field. */
35
30
  export type ReferenceBuilder<T> = <F extends ReferenceableField<T>>(field: F) => TransactionReference<SingleRowResult<T>[F]>;
36
31
  /** Contributes `$ref` only where the result is a referenceable single row. */
37
32
  export type OperationReferenceSurface<T> = [SingleRowResult<T>] extends [never] ? {} : {
38
33
  readonly $ref: ReferenceBuilder<T>;
39
34
  };
40
- /**
41
- * An opaque deferred-operation handle.
42
- */
35
+ /** An opaque deferred-operation handle. */
43
36
  export type Operation<T> = {
44
37
  readonly [OPERATION_HANDLE]: true;
45
38
  readonly [OPERATION_RESULT]?: T;
@@ -49,13 +42,9 @@ export type TransactionResults<Ops extends readonly Operation<unknown>[]> = {
49
42
  readonly [I in keyof Ops]: Ops[I] extends Operation<infer R> ? R : never;
50
43
  };
51
44
  /**
52
- * The one typed transaction runner — `framework.transaction`'s own type. It infers
53
- * the handle tuple without `as const` at the call site, and resolves what the
54
- * runtime answers: the committed envelope (`A1009`) with each handle's result in
55
- * plan order, or the failure response. Never the bare result tuple.
56
- *
57
- * The second argument is the run's `ExecutionOptions`: its `requestId` is every
58
- * step's, under either origin. A handle takes none.
45
+ * `framework.transaction`'s type. It infers the handle tuple without `as const`
46
+ * and resolves the committed response (`A1009`) with each handle's result in
47
+ * plan order, or the failure response.
59
48
  */
60
49
  export type TransactionRunner = <const Ops extends readonly Operation<unknown>[]>(operations: Ops, options?: ExecutionOptions) => Promise<TransactionCommittedResponse<TransactionResults<Ops>> | OperationFailureResponse>;
61
50
  export {};
@@ -1,6 +1,7 @@
1
1
  import type { Contract } from "../contracts/contract.js";
2
2
  import type { OperationIdentity } from "../operations/operation-identity.js";
3
3
  import type { SemanticOperationArguments } from "../operations/operation-validator.js";
4
+ /** Encodes validated application arguments into the wire scalar form. */
4
5
  export declare function encodeOperationArgumentsForWire(contract: Contract, operation: OperationIdentity & {
5
6
  readonly resource: string;
6
7
  }, args: SemanticOperationArguments): unknown;
@@ -1,10 +1,12 @@
1
1
  import type { OperationFingerprint } from "./deferred-operation.js";
2
+ /** What an operation fingerprint is computed from. */
2
3
  export type OperationFingerprintNode = {
3
4
  readonly resource: string;
4
5
  readonly family: string;
5
6
  readonly variant: string;
6
7
  readonly args: unknown;
7
8
  };
9
+ /** Whether `value` is an operation fingerprint (`fp1:…`). */
8
10
  export declare function isOperationFingerprint(value: unknown): value is OperationFingerprint;
9
- /** Computes the v1 operation fingerprint from an already wire-form node. */
11
+ /** Computes an operation's fingerprint from its wire-form arguments. */
10
12
  export declare function computeOperationFingerprint(node: OperationFingerprintNode): Promise<OperationFingerprint>;
@@ -28,10 +28,8 @@ export type TransactionOperationEntryInspection = {
28
28
  readonly issue: ValidationIssue;
29
29
  };
30
30
  /**
31
- * Inspects the plan's operations tuple without dereferencing untrusted array
32
- * properties outside a reflection boundary. The caller uses the returned
33
- * length and per-index inspector rather than `operations.length` or
34
- * `operations[index]` directly.
31
+ * The caller uses the returned length and per-index inspector rather than
32
+ * `operations.length` or `operations[index]` directly.
35
33
  */
36
34
  export declare function inspectTransactionOperations(value: unknown): TransactionOperationsInspection;
37
35
  /** Reads one operations entry through its own data descriptor. */
@@ -1,22 +1,11 @@
1
1
  /**
2
- * The ways an Adapter transaction can break the contract the framework's plan
3
- * executor depends on. Each is answered `A3002`; the violation is the only thing
4
- * that tells them apart, so it is structured data rather than message text.
5
- *
6
- * - `transaction-unavailable`: the Adapter's `transaction` function is gone at
7
- * execution time.
8
- * - `resolved-after-abort`: the Adapter resolved although the framework threw its
9
- * rollback request.
10
- * - `resolved-incomplete`: the Adapter resolved before every plan operation ran,
11
- * so no committed `A1009` array exists.
12
- * - `foreign-abort`: the Adapter rejected with the framework's rollback request
13
- * although this plan never made one.
2
+ * The ways an Adapter transaction can break the framework's transaction
3
+ * contract. Each is answered `A3002`.
14
4
  */
15
5
  export type TransactionIntegrityViolation = "transaction-unavailable" | "resolved-after-abort" | "resolved-incomplete" | "foreign-abort";
16
6
  /**
17
- * The framework-owned failure reported to diagnostics when an Adapter
18
- * transaction violates its contract. It never reaches the wire: the response
19
- * is always the constant `A3002` envelope.
7
+ * Reported to diagnostics when an Adapter transaction breaks the framework's
8
+ * transaction contract. The caller receives `A3002`.
20
9
  */
21
10
  export declare class TransactionIntegrityError extends Error {
22
11
  readonly violation: TransactionIntegrityViolation;
@@ -1,10 +1,13 @@
1
1
  import type { FrameworkContracts } from "../compiler/contract.compiler.js";
2
2
  import type { RequestOrigin } from "../config/config-layer.js";
3
3
  import type { OperationIdentity } from "../operations/operation-identity.js";
4
+ import type { CallerDataError } from "../runtime/caller-data.copier.js";
5
+ import type { MisuseReporter } from "../runtime/misuse-reporter.js";
4
6
  import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
5
7
  import type { OperationFailureResponse } from "../runtime/operation-response.js";
6
8
  import type { Operation, OperationFingerprint } from "./deferred-operation.js";
7
9
  import type { TransactionOperationOrigin } from "./transaction-request.js";
10
+ /** One wire node, exactly as the transaction runtime receives it. */
8
11
  type WireOperationNode = {
9
12
  readonly resource: string;
10
13
  readonly family: string;
@@ -19,6 +22,8 @@ export type AssembledTransactionPlan = {
19
22
  };
20
23
  /** Each operation's own origin, by index (mixed plans). */
21
24
  readonly origins: readonly TransactionOperationOrigin[];
25
+ /** The steps whose arguments their builder could not copy, by index. */
26
+ readonly refused: ReadonlyMap<number, CallerDataError>;
22
27
  } | {
23
28
  readonly ok: false;
24
29
  readonly response: OperationFailureResponse;
@@ -34,5 +39,5 @@ export type TransactionPlanAssembler = {
34
39
  * handle, so a handle another instance built — typed against another model,
35
40
  * bound to other Contracts — is refused rather than run.
36
41
  */
37
- export declare function createTransactionPlanAssembler(contracts: FrameworkContracts, protocol: ClientProtocolIdentity): TransactionPlanAssembler;
42
+ export declare function createTransactionPlanAssembler(contracts: FrameworkContracts, protocol: ClientProtocolIdentity, misuse: MisuseReporter): TransactionPlanAssembler;
38
43
  export {};
@@ -1,4 +1,5 @@
1
1
  import { validationIssue } from "../operations/validation-code.js";
2
+ import { copyAtDoor, refuseCallerData } from "../runtime/caller-data.door.js";
2
3
  import { operationFailure } from "../runtime/operation-response.js";
3
4
  import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
4
5
  import { encodeOperationArgumentsForWire } from "./operation-arguments-encoder.js";
@@ -11,63 +12,63 @@ function isPlainRecord(value) {
11
12
  const prototype = Object.getPrototypeOf(value);
12
13
  return prototype === Object.prototype || prototype === null;
13
14
  }
14
- function referenceKeys(identity) {
15
- switch (identity.family) {
16
- case "create":
17
- case "update":
18
- return ["data"];
19
- case "upsert":
20
- return ["create", "update"];
21
- default:
22
- return [];
15
+ const KEEP = Symbol("keep");
16
+ function rebuildArguments(value, path, leaf, ancestors = new Set()) {
17
+ const replaced = leaf(value, path);
18
+ if (replaced !== KEEP) {
19
+ return replaced;
23
20
  }
24
- }
25
- function referenceContainers(identity, args) {
26
- if (!isPlainRecord(args)) {
27
- return [];
28
- }
29
- return referenceKeys(identity).flatMap((key) => {
30
- const value = args[key];
31
- if (Array.isArray(value)) {
32
- return value.flatMap((entry, index) => isPlainRecord(entry) ? [{ path: [key, index], record: entry }] : []);
33
- }
34
- return isPlainRecord(value) ? [{ path: [key], record: value }] : [];
35
- });
36
- }
37
- function replaceContainers(identity, args, rebuild) {
38
- if (!isPlainRecord(args)) {
39
- return args;
21
+ if (!Array.isArray(value) && !isPlainRecord(value)) {
22
+ return value;
40
23
  }
41
- const result = { ...args };
42
- for (const key of referenceKeys(identity)) {
43
- const value = args[key];
44
- if (Array.isArray(value)) {
45
- result[key] = value.map((entry, index) => isPlainRecord(entry)
46
- ? rebuild({ path: [key, index], record: entry })
47
- : entry);
48
- }
49
- else if (isPlainRecord(value)) {
50
- result[key] = rebuild({ path: [key], record: value });
51
- }
24
+ if (ancestors.has(value)) {
25
+ return value;
52
26
  }
53
- return result;
27
+ ancestors.add(value);
28
+ const rebuilt = Array.isArray(value)
29
+ ? value.map((entry, index) => rebuildArguments(entry, [...path, index], leaf, ancestors))
30
+ : Object.fromEntries(Object.entries(value).map(([key, entry]) => [
31
+ key,
32
+ rebuildArguments(entry, [...path, key], leaf, ancestors),
33
+ ]));
34
+ ancestors.delete(value);
35
+ return rebuilt;
54
36
  }
55
37
  function operationEntryFailure(operation, message) {
56
38
  return transactionOperationFailure(operationFailure("A2004", {
57
39
  message: "Transaction plan failed framework validation.",
58
- issues: [validationIssue("V1001", ["operation"], message)],
40
+ issues: [validationIssue("V1001", [], message)],
59
41
  }), operation);
60
42
  }
61
43
  function referenceFailure(issue, operation) {
62
44
  return transactionOperationFailure(mapValidationOutcome([issue]), operation);
63
45
  }
64
- export function createTransactionPlanAssembler(contracts, protocol) {
46
+ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
65
47
  const handles = new WeakMap();
66
48
  const placeholders = new WeakMap();
67
49
  const originOf = (origin) => origin === "application"
68
- ? { scope: "application" }
69
- : { scope: "client", protocol };
70
- const snapshot = (identity, args) => replaceContainers(identity, args, ({ record }) => ({ ...record }));
50
+ ? { origin: "application" }
51
+ : { origin: "client", protocol };
52
+ const snapshot = (args) => {
53
+ const copy = copyAtDoor(args, {
54
+ keep: (value) => placeholders.has(value),
55
+ });
56
+ return copy.ok ? { args: copy.value } : { args: {}, refused: copy.error };
57
+ };
58
+ const placeholderSites = (args) => {
59
+ const sites = [];
60
+ rebuildArguments(args, [], (value, path) => {
61
+ const placeholder = typeof value === "object" && value !== null
62
+ ? placeholders.get(value)
63
+ : undefined;
64
+ if (placeholder === undefined) {
65
+ return KEEP;
66
+ }
67
+ sites.push({ path, object: value, placeholder });
68
+ return value;
69
+ });
70
+ return sites;
71
+ };
71
72
  const defer = (origin, resource, identity, args) => {
72
73
  const handle = Object.freeze({
73
74
  $ref: (field) => {
@@ -82,11 +83,22 @@ export function createTransactionPlanAssembler(contracts, protocol) {
82
83
  origin,
83
84
  resource,
84
85
  identity,
85
- args: snapshot(identity, args),
86
+ ...snapshot(args),
86
87
  });
87
88
  return handle;
88
89
  };
89
- const assemble = async (operations) => {
90
+ const assemble = async (input) => {
91
+ const list = copyAtDoor(input, { keep: (value) => value !== input });
92
+ if (!list.ok) {
93
+ return {
94
+ ok: false,
95
+ response: operationFailure("A2004", {
96
+ message: "Transaction plan failed framework validation.",
97
+ issues: [refuseCallerData(list.error, ["operations"], {}, misuse)],
98
+ }),
99
+ };
100
+ }
101
+ const operations = list.value;
90
102
  if (!Array.isArray(operations)) {
91
103
  return {
92
104
  ok: false,
@@ -120,17 +132,12 @@ export function createTransactionPlanAssembler(contracts, protocol) {
120
132
  records.push(record);
121
133
  }
122
134
  for (const [index, record] of records.entries()) {
123
- for (const { path, record: container } of referenceContainers(record.identity, record.args)) {
124
- for (const [field, value] of Object.entries(container)) {
125
- const placeholder = typeof value === "object" && value !== null
126
- ? placeholders.get(value)
127
- : undefined;
128
- if (placeholder !== undefined && !positions.has(placeholder.source)) {
129
- return {
130
- ok: false,
131
- response: referenceFailure(validationIssue("V1010", ["operations", index, "args", ...path, field, "$ref"], "Transaction reference names an operation that is not in this transaction."), index),
132
- };
133
- }
135
+ for (const { path, placeholder } of placeholderSites(record.args)) {
136
+ if (!positions.has(placeholder.source)) {
137
+ return {
138
+ ok: false,
139
+ response: referenceFailure(validationIssue("V1010", ["operations", index, "args", ...path, "$ref"], "Transaction reference names an operation that is not in this transaction."), index),
140
+ };
134
141
  }
135
142
  }
136
143
  }
@@ -145,26 +152,17 @@ export function createTransactionPlanAssembler(contracts, protocol) {
145
152
  };
146
153
  const materialize = async (index) => {
147
154
  const record = records[index];
148
- const references = [];
149
- const args = replaceContainers(record.identity, record.args, ({ record: container }) => {
150
- const bound = { ...container };
151
- for (const [field, value] of Object.entries(container)) {
152
- const placeholder = typeof value === "object" && value !== null
153
- ? placeholders.get(value)
154
- : undefined;
155
- if (placeholder === undefined) {
156
- continue;
157
- }
158
- const operation = positions.get(placeholder.source);
159
- references.push(nodeAt(operation).then(({ fingerprint }) => {
160
- bound[field] = {
161
- $ref: { operation, fingerprint, path: [placeholder.field] },
162
- };
163
- }));
164
- }
165
- return bound;
166
- });
167
- await Promise.all(references);
155
+ const bound = new Map();
156
+ await Promise.all(placeholderSites(record.args).map(async ({ object, placeholder }) => {
157
+ const operation = positions.get(placeholder.source);
158
+ const { fingerprint } = await nodeAt(operation);
159
+ bound.set(object, {
160
+ $ref: { operation, fingerprint, path: [placeholder.field] },
161
+ });
162
+ }));
163
+ const args = rebuildArguments(record.args, [], (value) => typeof value === "object" && value !== null && bound.has(value)
164
+ ? bound.get(value)
165
+ : KEEP);
168
166
  return {
169
167
  resource: record.resource,
170
168
  family: record.identity.family,
@@ -195,6 +193,7 @@ export function createTransactionPlanAssembler(contracts, protocol) {
195
193
  operations: await Promise.all(records.map((_, index) => nodeAt(index))),
196
194
  },
197
195
  origins: records.map((record) => originOf(record.origin)),
196
+ refused: new Map(records.flatMap((record, index) => record.refused === undefined ? [] : [[index, record.refused]])),
198
197
  };
199
198
  };
200
199
  return { defer, assemble };
@@ -2,6 +2,7 @@ import type { AdapterModel } from "../adapters/adapter-model.js";
2
2
  import type { Contract } from "../contracts/contract.js";
3
3
  import type { ScalarField } from "../contracts/field.js";
4
4
  import type { SemanticOperationArguments } from "../operations/operation-validator.js";
5
+ import { CallerDataError } from "../runtime/caller-data.copier.js";
5
6
  import { type ReadProjectionPlan } from "../runtime/computed-read-runtime.js";
6
7
  import type { FrameworkOperationRequest } from "../runtime/operation-request.js";
7
8
  import type { OperationFailureResponse } from "../runtime/operation-response.js";
@@ -9,15 +10,37 @@ import type { OperationPipelineDependencies } from "../runtime/operation-runtime
9
10
  import type { CascadeClosure } from "../runtime/referential-action.js";
10
11
  import type { OperationFingerprint } from "./deferred-operation.js";
11
12
  import type { TransactionReference } from "./transaction-reference.js";
13
+ import { type TransactionSlotShape } from "./transaction-reference.js";
14
+ import { type TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
12
15
  import type { FrameworkTransactionRequest, TransactionOperationOrigin } from "./transaction-request.js";
13
- export type TransactionReferenceCandidateSlot = {
14
- readonly path: readonly (string | number)[];
15
- readonly field: ScalarField<Contract>;
16
- readonly candidate: unknown;
16
+ /**
17
+ * Where a plan's step arguments came from, so the validator knows whether to copy
18
+ * them at the door (see `ArgumentsSource`):
19
+ *
20
+ * - `"caller"` — `framework.executeTransaction`'s caller's own objects: every step's
21
+ * arguments are copied when the plan is handed in, before the validator's first
22
+ * await, so a step revoked or changed after the call is never read again;
23
+ * - `"owned"` — a plan the protocol decoder parsed, or the typed runner assembled
24
+ * from its builders' copies; `refused` names the steps whose arguments a builder
25
+ * could not copy, answered at their turn.
26
+ */
27
+ export type PlanArguments = {
28
+ readonly source: "caller";
29
+ } | {
30
+ readonly source: "owned";
31
+ readonly refused?: ReadonlyMap<number, CallerDataError>;
17
32
  };
33
+ export type { TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
34
+ /** One validated Transaction Slot: where it is, what it holds, and its reference. */
18
35
  export type TransactionReferenceSlot = {
19
36
  readonly path: readonly (string | number)[];
37
+ /** The destination field. */
20
38
  readonly field: ScalarField<Contract>;
39
+ readonly shape: TransactionSlotShape;
40
+ /** The slot is a scalar value of mutation data: what it resolves to is written. */
41
+ readonly written: boolean;
42
+ /** The source field, under its own step's Contract: what the slot receives. */
43
+ readonly source: ScalarField<Contract>;
21
44
  readonly reference: TransactionReference;
22
45
  };
23
46
  export type CandidateTransactionOperation = {
@@ -48,10 +71,10 @@ export type ValidatedTransactionPlan = {
48
71
  /**
49
72
  * What validating a plan needs beyond one operation's pipeline: the cascade
50
73
  * closure over the Adapter's referential actions, resolved once when the
51
- * Framework is constructed. The create requirements are not among them: they
74
+ * Framework is constructed. The record-write facts are not among them: they
52
75
  * are checked when each operation runs, after its pipes.
53
76
  */
54
- export type TransactionPlanDependencies<M extends AdapterModel> = Omit<OperationPipelineDependencies<M>, "createRequirements"> & {
77
+ export type TransactionPlanDependencies<M extends AdapterModel> = Omit<OperationPipelineDependencies<M>, "recordWrites"> & {
55
78
  readonly cascades: CascadeClosure;
56
79
  };
57
80
  export type TransactionPlanValidationResult = {
@@ -62,26 +85,12 @@ export type TransactionPlanValidationResult = {
62
85
  readonly response: OperationFailureResponse;
63
86
  };
64
87
  /**
65
- * The refusal of a plan on a Contract without transaction plans (`A2002`, one
66
- * `V1006` at `["operations"]`). The one spelling — the protocol's absence answer
67
- * for `/_transactions` is this envelope too.
88
+ * The refusal of a plan on a Contract without transaction plans (`A2002`, one `V1006`
89
+ * at `["operations"]`). The one spelling — the protocol's absence answer for
90
+ * `/_transactions` is this envelope too.
68
91
  */
69
92
  export declare function transactionsUnavailableFailure(): OperationFailureResponse;
70
93
  /**
71
94
  * Whole-plan Framework Validation Layer for transaction structure and identity.
72
- *
73
- * `origins` states each operation's origin by index, for a plan whose steps do
74
- * not all share the request's (the typed runner's mixed plans). Absent — the
75
- * untyped seam — every operation takes the request's own origin. Each operation
76
- * is validated against its own origin's Contract.
77
- *
78
- * A plan is also refused when a step depends on rows an earlier step's cascade
79
- * removed (`V1019`, plan-scoped: a lone operation that cascades is not a
80
- * defect, since nothing follows it). The analysis runs over every step whatever
81
- * its origin — one plan runs in one Adapter transaction, so a client step's
82
- * read sees an application step's cascade — and reads each step against its own
83
- * origin's Contract. It is a planning answer, given before any provider statement
84
- * is issued, and as conservative as the facts it has: a plan cannot know which
85
- * rows a delete will match, so it refuses at the granularity of a Resource.
86
95
  */
87
- export declare function validateTransactionPlan<M extends AdapterModel>(dependencies: TransactionPlanDependencies<M>, request: FrameworkTransactionRequest, origins?: readonly TransactionOperationOrigin[]): Promise<TransactionPlanValidationResult>;
96
+ export declare function validateTransactionPlan<M extends AdapterModel>(dependencies: TransactionPlanDependencies<M>, request: FrameworkTransactionRequest, origins?: readonly TransactionOperationOrigin[], planArguments?: PlanArguments): Promise<TransactionPlanValidationResult>;