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

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 (261) hide show
  1. package/CHANGELOG.md +1022 -16
  2. package/ERRORS.md +142 -0
  3. package/README.md +330 -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 +281 -31
  19. package/dist/compiler/create-requirements.projector.js +1 -3
  20. package/dist/compiler/field-validator.compiler.js +1 -3
  21. package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
  22. package/dist/compiler/managed-elsewhere.projector.js +179 -0
  23. package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
  24. package/dist/compiler/managed-elsewhere.validator.js +74 -0
  25. package/dist/config/cache-stage.factory.d.ts +24 -0
  26. package/dist/config/cache-stage.factory.js +3 -0
  27. package/dist/config/computed-fields.d.ts +62 -0
  28. package/dist/config/computed-fields.js +73 -0
  29. package/dist/config/config-diagnostic.guidance.d.ts +6 -0
  30. package/dist/config/config-diagnostic.guidance.js +32 -0
  31. package/dist/config/config.resolver.d.ts +24 -0
  32. package/dist/config/config.resolver.js +66 -7
  33. package/dist/config/config.validator.js +283 -21
  34. package/dist/config/define-resource.d.ts +1 -5
  35. package/dist/config/entrypoint.normalizer.d.ts +3 -2
  36. package/dist/config/exact-framework-config.d.ts +73 -22
  37. package/dist/config/field-compute.resolver.d.ts +2 -0
  38. package/dist/config/field-compute.resolver.js +9 -3
  39. package/dist/config/framework-config.d.ts +53 -15
  40. package/dist/config/framework-resources-config.d.ts +25 -14
  41. package/dist/config/pipeline-config.d.ts +20 -4
  42. package/dist/config/pipeline-tree.resolver.d.ts +2 -2
  43. package/dist/config/pipeline-tree.resolver.js +2 -3
  44. package/dist/contracts/access-route.rules.d.ts +10 -0
  45. package/dist/contracts/access-route.rules.js +45 -0
  46. package/dist/contracts/canonical-json.writer.d.ts +7 -0
  47. package/dist/contracts/canonical-json.writer.js +55 -0
  48. package/dist/contracts/capability.d.ts +26 -1
  49. package/dist/contracts/capability.js +20 -0
  50. package/dist/contracts/client-contract-structure.validator.d.ts +365 -89
  51. package/dist/contracts/client-contract-structure.validator.js +49 -2
  52. package/dist/contracts/contract-access.d.ts +29 -0
  53. package/dist/contracts/contract-access.js +1 -0
  54. package/dist/contracts/contract-canonicalizer.d.ts +9 -1
  55. package/dist/contracts/contract-canonicalizer.js +35 -4
  56. package/dist/contracts/contract-hash.d.ts +0 -1
  57. package/dist/contracts/contract-hash.js +1 -1
  58. package/dist/contracts/contract-limits.d.ts +6 -0
  59. package/dist/contracts/contract-limits.js +2 -0
  60. package/dist/contracts/contract.d.ts +42 -1
  61. package/dist/contracts/field.d.ts +58 -1
  62. package/dist/contracts/json-schema.projector.d.ts +11 -0
  63. package/dist/contracts/json-schema.projector.js +76 -0
  64. package/dist/contracts/scalar-value-type.d.ts +3 -1
  65. package/dist/framework/access-facade.d.ts +116 -0
  66. package/dist/framework/access-facade.js +118 -0
  67. package/dist/framework/contract-view.d.ts +120 -16
  68. package/dist/framework/framework-construction.error.d.ts +14 -4
  69. package/dist/framework/framework-construction.error.js +18 -2
  70. package/dist/framework/framework.d.ts +26 -5
  71. package/dist/framework/framework.factory.d.ts +1 -1
  72. package/dist/framework/framework.factory.js +145 -24
  73. package/dist/framework/operation-facade.d.ts +141 -13
  74. package/dist/framework/operation-facade.js +9 -1
  75. package/dist/framework/operation-set.runner.d.ts +47 -0
  76. package/dist/framework/operation-set.runner.js +168 -0
  77. package/dist/index.d.ts +19 -5
  78. package/dist/index.js +3 -0
  79. package/dist/internal.d.ts +9 -2
  80. package/dist/internal.js +8 -0
  81. package/dist/operations/database-refusal.d.ts +51 -0
  82. package/dist/operations/database-refusal.js +45 -0
  83. package/dist/operations/operation-arguments.d.ts +148 -60
  84. package/dist/operations/operation-call.d.ts +9 -5
  85. package/dist/operations/operation-result.d.ts +6 -4
  86. package/dist/operations/operation-validator-core.js +160 -39
  87. package/dist/operations/operation-validator.d.ts +1 -1
  88. package/dist/operations/structural-limits.walker.d.ts +1 -1
  89. package/dist/operations/structural-limits.walker.js +1 -3
  90. package/dist/operations/validation-code.guidance.d.ts +6 -0
  91. package/dist/operations/validation-code.guidance.js +90 -0
  92. package/dist/operations/write-scope.resolver.d.ts +4 -0
  93. package/dist/operations/write-scope.resolver.js +2 -0
  94. package/dist/policy/access-provider.interface.d.ts +91 -0
  95. package/dist/policy/access-provider.interface.js +1 -0
  96. package/dist/policy/access-provider.registry.d.ts +17 -0
  97. package/dist/policy/access-provider.registry.js +15 -0
  98. package/dist/policy/access-question.d.ts +20 -0
  99. package/dist/policy/access-question.js +1 -0
  100. package/dist/policy/access-question.registry.d.ts +5 -0
  101. package/dist/policy/access-question.registry.js +19 -0
  102. package/dist/policy/access-question.runtime.d.ts +36 -0
  103. package/dist/policy/access-question.runtime.js +295 -0
  104. package/dist/policy/access-verb.table.d.ts +56 -0
  105. package/dist/policy/access-verb.table.js +21 -0
  106. package/dist/policy/access-verbs.d.ts +46 -0
  107. package/dist/policy/access-verbs.js +1 -0
  108. package/dist/policy/policy-admission.d.ts +20 -0
  109. package/dist/policy/policy-admission.js +407 -0
  110. package/dist/policy/policy-after-update.runtime.d.ts +79 -0
  111. package/dist/policy/policy-after-update.runtime.js +206 -0
  112. package/dist/policy/policy-condition.d.ts +15 -0
  113. package/dist/policy/policy-condition.js +36 -0
  114. package/dist/policy/policy-engine.d.ts +205 -0
  115. package/dist/policy/policy-engine.js +1 -0
  116. package/dist/policy/policy-named-rows.d.ts +18 -0
  117. package/dist/policy/policy-named-rows.js +51 -0
  118. package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
  119. package/dist/policy/policy-nested-write.runtime.js +536 -0
  120. package/dist/policy/policy-read.runtime.d.ts +81 -0
  121. package/dist/policy/policy-read.runtime.js +501 -0
  122. package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
  123. package/dist/policy/policy-reference-write.runtime.js +336 -0
  124. package/dist/policy/policy-request.d.ts +72 -0
  125. package/dist/policy/policy-request.js +115 -0
  126. package/dist/policy/policy-session.d.ts +106 -0
  127. package/dist/policy/policy-session.js +293 -0
  128. package/dist/policy/policy-startup.validator.d.ts +10 -0
  129. package/dist/policy/policy-startup.validator.js +112 -0
  130. package/dist/policy/policy-write.runtime.d.ts +39 -0
  131. package/dist/policy/policy-write.runtime.js +530 -0
  132. package/dist/prebuilt/core-version.generated.d.ts +2 -0
  133. package/dist/prebuilt/core-version.generated.js +1 -0
  134. package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
  135. package/dist/prebuilt/prebuilt-changes.js +63 -0
  136. package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
  137. package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
  138. package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
  139. package/dist/prebuilt/prebuilt-contracts.js +1 -0
  140. package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
  141. package/dist/prebuilt/prebuilt-contracts.loader.js +75 -0
  142. package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
  143. package/dist/prebuilt/prebuilt-inputs.fingerprint.js +227 -0
  144. package/dist/protocol/absent-route.responder.d.ts +49 -14
  145. package/dist/protocol/absent-route.responder.js +92 -15
  146. package/dist/protocol/contract-document.responder.d.ts +9 -1
  147. package/dist/protocol/contract-document.responder.js +3 -2
  148. package/dist/protocol/http-request.decoder.d.ts +52 -3
  149. package/dist/protocol/http-request.decoder.js +45 -6
  150. package/dist/protocol/http-request.reader.d.ts +10 -3
  151. package/dist/protocol/http-request.reader.js +12 -2
  152. package/dist/protocol/http-response.encoder.d.ts +12 -0
  153. package/dist/protocol/http-response.encoder.js +17 -3
  154. package/dist/protocol/operation-response.guard.js +1 -3
  155. package/dist/protocol/operation-set.decoder.d.ts +48 -0
  156. package/dist/protocol/operation-set.decoder.js +185 -0
  157. package/dist/protocol/operation-set.handler.d.ts +27 -0
  158. package/dist/protocol/operation-set.handler.js +179 -0
  159. package/dist/protocol/protocol-headers.d.ts +12 -3
  160. package/dist/protocol/protocol-headers.js +12 -5
  161. package/dist/protocol/protocol-surface.d.ts +16 -3
  162. package/dist/protocol/protocol-surface.js +41 -1
  163. package/dist/protocol/protocol.binder.d.ts +52 -1
  164. package/dist/protocol/protocol.binder.js +6 -1
  165. package/dist/protocol/protocol.handler.d.ts +45 -1
  166. package/dist/protocol/protocol.handler.js +164 -19
  167. package/dist/protocol/read-cache.responder.d.ts +26 -0
  168. package/dist/protocol/read-cache.responder.js +47 -0
  169. package/dist/protocol/read-query.codec.d.ts +34 -0
  170. package/dist/protocol/read-query.codec.js +125 -0
  171. package/dist/runtime/caller-data.copier.d.ts +18 -3
  172. package/dist/runtime/caller-data.copier.js +21 -8
  173. package/dist/runtime/caller-data.door.d.ts +13 -6
  174. package/dist/runtime/computed-read-runtime.d.ts +6 -1
  175. package/dist/runtime/computed-read-runtime.js +229 -48
  176. package/dist/runtime/computed-value.error.d.ts +3 -2
  177. package/dist/runtime/computed-value.error.js +3 -2
  178. package/dist/runtime/context-executor.runtime.d.ts +4 -3
  179. package/dist/runtime/context-executor.runtime.js +4 -2
  180. package/dist/runtime/core-class.brand.d.ts +10 -0
  181. package/dist/runtime/core-class.brand.js +21 -0
  182. package/dist/runtime/create-requirement.d.ts +31 -5
  183. package/dist/runtime/create-requirement.js +130 -24
  184. package/dist/runtime/decimal.d.ts +14 -0
  185. package/dist/runtime/decimal.js +21 -0
  186. package/dist/runtime/diagnostics-reporter.d.ts +49 -9
  187. package/dist/runtime/diagnostics-reporter.js +16 -9
  188. package/dist/runtime/error-boundary.d.ts +9 -2
  189. package/dist/runtime/error-boundary.js +12 -0
  190. package/dist/runtime/error-guidance.d.ts +12 -0
  191. package/dist/runtime/error-guidance.js +1 -0
  192. package/dist/runtime/error.catalog.d.ts +49 -0
  193. package/dist/runtime/error.catalog.js +49 -0
  194. package/dist/runtime/execution-options.d.ts +8 -0
  195. package/dist/runtime/field-check.evaluator.d.ts +0 -2
  196. package/dist/runtime/field-check.evaluator.js +1 -1
  197. package/dist/runtime/field-compute.d.ts +11 -10
  198. package/dist/runtime/field-stage.runtime.d.ts +3 -3
  199. package/dist/runtime/field-stage.runtime.js +9 -11
  200. package/dist/runtime/field-validator.runtime.d.ts +19 -1
  201. package/dist/runtime/field-validator.runtime.js +49 -9
  202. package/dist/runtime/framework-error.js +9 -0
  203. package/dist/runtime/framework-warning.emitter.d.ts +6 -0
  204. package/dist/runtime/framework-warning.emitter.js +8 -0
  205. package/dist/runtime/json-value.d.ts +10 -5
  206. package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
  207. package/dist/runtime/level-lifecycle.runtime.js +3 -5
  208. package/dist/runtime/mutation-planner.d.ts +1 -6
  209. package/dist/runtime/mutation-planner.js +4 -17
  210. package/dist/runtime/nested-write.walker.js +2 -1
  211. package/dist/runtime/operation-code.guidance.d.ts +6 -0
  212. package/dist/runtime/operation-code.guidance.js +167 -0
  213. package/dist/runtime/operation-request.d.ts +16 -9
  214. package/dist/runtime/operation-runtime.d.ts +35 -17
  215. package/dist/runtime/operation-runtime.js +220 -49
  216. package/dist/runtime/outcome-mapper.d.ts +2 -1
  217. package/dist/runtime/output-validator.d.ts +1 -1
  218. package/dist/runtime/output-validator.js +1 -3
  219. package/dist/runtime/owned-execution.registry.d.ts +34 -4
  220. package/dist/runtime/pipe-output.validator.d.ts +10 -0
  221. package/dist/runtime/pipe-output.validator.js +4 -2
  222. package/dist/runtime/pipeline.d.ts +52 -23
  223. package/dist/runtime/readonly-value.d.ts +20 -5
  224. package/dist/runtime/readonly-value.js +74 -26
  225. package/dist/runtime/record.guard.d.ts +14 -0
  226. package/dist/runtime/record.guard.js +10 -0
  227. package/dist/runtime/referential-action.d.ts +1 -1
  228. package/dist/runtime/request-envelope.validator.js +13 -10
  229. package/dist/runtime/scalar-runtime.d.ts +4 -21
  230. package/dist/runtime/scalar-runtime.js +91 -31
  231. package/dist/runtime/thenable.guard.d.ts +7 -0
  232. package/dist/runtime/thenable.guard.js +5 -0
  233. package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
  234. package/dist/runtime/unsent-value.normalizer.js +129 -0
  235. package/dist/transactions/operation-arguments-encoder.js +9 -10
  236. package/dist/transactions/operation-fingerprint.js +2 -2
  237. package/dist/transactions/sql-statement.d.ts +10 -2
  238. package/dist/transactions/sql-statement.validator.d.ts +2 -2
  239. package/dist/transactions/sql-statement.validator.js +40 -6
  240. package/dist/transactions/transaction-envelope.d.ts +5 -4
  241. package/dist/transactions/transaction-integrity-error.js +2 -0
  242. package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
  243. package/dist/transactions/transaction-plan-assembler.js +49 -17
  244. package/dist/transactions/transaction-plan-validator.d.ts +23 -7
  245. package/dist/transactions/transaction-plan-validator.js +31 -7
  246. package/dist/transactions/transaction-reference-collector.js +8 -10
  247. package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
  248. package/dist/transactions/transaction-reference-resolver.js +1 -3
  249. package/dist/transactions/transaction-reference-validator.d.ts +43 -3
  250. package/dist/transactions/transaction-reference-validator.js +83 -57
  251. package/dist/transactions/transaction-reference.d.ts +1 -1
  252. package/dist/transactions/transaction-reference.js +5 -0
  253. package/dist/transactions/transaction-request.d.ts +8 -8
  254. package/dist/transactions/transaction-runtime.d.ts +5 -2
  255. package/dist/transactions/transaction-runtime.js +108 -27
  256. package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
  257. package/dist/transactions/transaction-slot-path-error.js +2 -0
  258. package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
  259. package/dist/transactions/transaction-stage.runtime.js +8 -7
  260. package/package.json +6 -5
  261. package/src/runtime/field-check.evaluator.ts +1 -1
@@ -1,14 +1,16 @@
1
1
  import type { AvContracts } from "../compiler/contract.compiler.js";
2
2
  import type { AvOperationIdentity } from "../operations/operation-identity.js";
3
- import type { AvCallerDataError } from "../runtime/caller-data.copier.js";
3
+ import { AvCallerDataError } from "../runtime/caller-data.copier.js";
4
4
  import type { MisuseReporter } from "../runtime/misuse-reporter.js";
5
- import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
5
+ import type { AvRequestProtocol } from "../runtime/operation-request.js";
6
6
  import type { AvOperationFailureResponse } from "../runtime/operation-response.js";
7
7
  import type { AvOperation, OperationFingerprint } from "./deferred-operation.js";
8
8
  import type { PlannedSqlStatement } from "./sql-statement.js";
9
9
  import type { TransactionOperationOrigin } from "./transaction-request.js";
10
10
  /** The origin a handle's builder gives it. */
11
11
  type HandleOrigin = "application" | "client";
12
+ /** The scalar forms a builder takes its arguments in. */
13
+ type ArgumentForms = "wire" | "application";
12
14
  /** One wire node, exactly as the transaction runtime receives it. */
13
15
  type WireOperationNode = {
14
16
  readonly resource: string;
@@ -37,8 +39,13 @@ export type AssembledTransactionPlan = {
37
39
  readonly response: AvOperationFailureResponse;
38
40
  };
39
41
  export type TransactionPlanAssembler = {
40
- /** Defers one operation into a handle; nothing runs. */
41
- defer(origin: HandleOrigin, resource: string, identity: AvOperationIdentity, args: unknown): AvOperation<unknown>;
42
+ /**
43
+ * Defers one operation into a handle; nothing runs. `forms` says which scalar
44
+ * forms a client-origin handle's arguments are in: `"wire"` (`clientTx`, the
45
+ * default) or `"application"` (`serverClientTx`), encoded into the wire forms
46
+ * from the builder's copy.
47
+ */
48
+ defer(origin: HandleOrigin, resource: string, identity: AvOperationIdentity, args: unknown, forms?: ArgumentForms): AvOperation<unknown>;
42
49
  /** Defers one `appTx.$sql` statement into a handle; nothing runs. */
43
50
  deferSql(strings: unknown, values: readonly unknown[]): AvOperation<unknown>;
44
51
  /** Binds a list of handles into the passive plan, or refuses it. */
@@ -49,5 +56,5 @@ export type TransactionPlanAssembler = {
49
56
  * handle, so a handle another instance built — typed against another model,
50
57
  * bound to other Contracts — is refused rather than run.
51
58
  */
52
- export declare function createTransactionPlanAssembler(contracts: AvContracts, protocol: ClientProtocolIdentity, misuse: MisuseReporter): TransactionPlanAssembler;
59
+ export declare function createTransactionPlanAssembler(contracts: AvContracts, protocol: AvRequestProtocol, misuse: MisuseReporter): TransactionPlanAssembler;
53
60
  export {};
@@ -1,19 +1,16 @@
1
1
  import { VALIDATION_CODE_MESSAGES, validationIssue, } from "../operations/validation-code.js";
2
+ import { AvCallerDataError, } from "../runtime/caller-data.copier.js";
2
3
  import { copyAtDoor, refuseCallerData } from "../runtime/caller-data.door.js";
3
4
  import { operationFailure } from "../runtime/operation-response.js";
4
5
  import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
6
+ import { isPlainRecord } from "../runtime/record.guard.js";
7
+ import { withoutUnsentWriteValues } from "../runtime/unsent-value.normalizer.js";
5
8
  import { encodeOperationArgumentsForWire } from "./operation-arguments-encoder.js";
6
9
  import { computeOperationFingerprint } from "./operation-fingerprint.js";
7
10
  import { readSqlTemplate } from "./sql-statement.js";
11
+ import { routeTransactionReferenceCandidate } from "./transaction-reference.js";
8
12
  import { transactionOperationFailure } from "./transaction-response.js";
9
13
  const SQL_STEP_NODE = Object.freeze({ fingerprint: null });
10
- function isPlainRecord(value) {
11
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
12
- return false;
13
- }
14
- const prototype = Object.getPrototypeOf(value);
15
- return prototype === Object.prototype || prototype === null;
16
- }
17
14
  const KEEP = Symbol("keep");
18
15
  function rebuildArguments(root, leaf) {
19
16
  const pathOf = (parent, key) => () => {
@@ -46,6 +43,9 @@ function rebuildArguments(root, leaf) {
46
43
  if (!Array.isArray(value) && !isPlainRecord(value)) {
47
44
  return { value };
48
45
  }
46
+ if (Object.hasOwn(value, "$ref")) {
47
+ return { value };
48
+ }
49
49
  if (ancestors.has(value)) {
50
50
  return { value };
51
51
  }
@@ -92,15 +92,17 @@ function operationEntryFailure(operation, message) {
92
92
  function referenceFailure(issue, operation) {
93
93
  return transactionOperationFailure(mapValidationOutcome([issue]), operation);
94
94
  }
95
+ const STEP_REFERENCE_MIRROR = (value) => Object.hasOwn(value, "$ref");
95
96
  export function createTransactionPlanAssembler(contracts, protocol, misuse) {
96
97
  const handles = new WeakMap();
97
98
  const placeholders = new WeakMap();
98
99
  const originOf = (origin) => origin === "application"
99
100
  ? { origin: "application" }
100
101
  : { origin: "client", protocol };
101
- const snapshot = (args) => {
102
+ const snapshot = (args, mirror) => {
102
103
  const copy = copyAtDoor(args, {
103
104
  keep: (value) => placeholders.has(value),
105
+ ...(mirror === undefined ? {} : { mirror }),
104
106
  });
105
107
  return copy.ok ? { args: copy.value } : { args: {}, refused: copy.error };
106
108
  };
@@ -131,15 +133,43 @@ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
131
133
  handles.set(handle, record);
132
134
  return handle;
133
135
  };
134
- const defer = (origin, resource, identity, args) => createHandle({
135
- kind: "operation",
136
- origin,
137
- resource,
138
- identity,
139
- ...snapshot(args),
140
- });
136
+ const defer = (origin, resource, identity, args, forms = "wire") => {
137
+ const snapped = snapshot(args, STEP_REFERENCE_MIRROR);
138
+ let copy = snapped;
139
+ if (origin === "client" &&
140
+ forms === "application" &&
141
+ snapped.refused === undefined) {
142
+ try {
143
+ copy = {
144
+ args: encodeOperationArgumentsForWire(contracts.client, { resource, ...identity }, snapped.args),
145
+ };
146
+ }
147
+ catch (error) {
148
+ if (!(error instanceof AvCallerDataError)) {
149
+ throw error;
150
+ }
151
+ }
152
+ }
153
+ let sent = copy.args;
154
+ try {
155
+ sent = withoutUnsentWriteValues(origin === "application" ? contracts.application : contracts.client, { resource, family: identity.family }, copy.args);
156
+ }
157
+ catch (error) {
158
+ if (!(error instanceof AvCallerDataError)) {
159
+ throw error;
160
+ }
161
+ }
162
+ return createHandle({
163
+ kind: "operation",
164
+ origin,
165
+ resource,
166
+ identity,
167
+ ...copy,
168
+ args: sent,
169
+ });
170
+ };
141
171
  const deferSql = (strings, values) => {
142
- const copy = snapshot(values);
172
+ const copy = snapshot(values, STEP_REFERENCE_MIRROR);
143
173
  return createHandle({
144
174
  kind: "sql",
145
175
  strings: readSqlTemplate(strings, values.length),
@@ -153,7 +183,9 @@ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
153
183
  const sites = placeholderSites(value);
154
184
  const [site] = sites;
155
185
  if (site === undefined) {
156
- return { kind: "value", value };
186
+ return routeTransactionReferenceCandidate(value).kind === "ordinary"
187
+ ? { kind: "value", value }
188
+ : { kind: "candidate", candidate: value };
157
189
  }
158
190
  if (site.path.length > 0) {
159
191
  return { kind: "misplaced-reference", path: site.path };
@@ -4,7 +4,7 @@ import type { AvScalarField } from "../contracts/field.js";
4
4
  import type { SemanticOperationArguments } from "../operations/operation-validator.js";
5
5
  import { AvCallerDataError } from "../runtime/caller-data.copier.js";
6
6
  import { type ReadProjectionPlan } from "../runtime/computed-read-runtime.js";
7
- import type { FrameworkOperationRequest } from "../runtime/operation-request.js";
7
+ import type { AvOperationRequest } from "../runtime/operation-request.js";
8
8
  import type { AvOperationFailureResponse } from "../runtime/operation-response.js";
9
9
  import type { OperationPipelineDependencies } from "../runtime/operation-runtime.js";
10
10
  import type { CascadeClosure } from "../runtime/referential-action.js";
@@ -13,7 +13,7 @@ import type { PlannedSqlStatement, ValidatedSqlStatement } from "./sql-statement
13
13
  import type { AvTransactionReference } from "./transaction-reference.js";
14
14
  import { type TransactionSlotShape } from "./transaction-reference.js";
15
15
  import { type TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
16
- import type { FrameworkTransactionRequest, TransactionOperationOrigin } from "./transaction-request.js";
16
+ import type { AvTransactionRequest, TransactionOperationOrigin } from "./transaction-request.js";
17
17
  /**
18
18
  * Where a plan's step arguments came from, so the validator knows whether to copy
19
19
  * them at the door (see `ArgumentsSource`):
@@ -34,6 +34,22 @@ export type PlanArguments = {
34
34
  readonly refused?: ReadonlyMap<number, AvCallerDataError>;
35
35
  readonly statements?: ReadonlyMap<number, PlannedSqlStatement>;
36
36
  };
37
+ /** A plan taken at a call, and the steps whose arguments could not be copied. */
38
+ type CapturedPlan = {
39
+ readonly plan: unknown;
40
+ readonly refused: ReadonlyMap<number, AvCallerDataError>;
41
+ };
42
+ /**
43
+ * A host's parsed plan taken at `protocol.handleTransaction`'s call, before its first
44
+ * await (rc.2, e2e batch 2): its structure mirrored by descriptors, which is how this
45
+ * validator inspects it — so no getter it refuses runs, and every accessor stays one
46
+ * for it to refuse — and each step's `args` copied as {@link captureSteps} copies a
47
+ * caller's, its `$ref` control objects mirrored. Run as an `"owned"` plan with
48
+ * `refused`, it is answered exactly as the plan the host held at the call. A plan
49
+ * that is no object, or cannot be reflected, is returned as it is: nothing in it can
50
+ * change.
51
+ */
52
+ export declare function capturePlanAtCall(plan: unknown): CapturedPlan;
37
53
  export type { TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
38
54
  /** One validated Transaction Slot: where it is, what it holds, and its reference. */
39
55
  export type TransactionReferenceSlot = {
@@ -49,7 +65,7 @@ export type TransactionReferenceSlot = {
49
65
  };
50
66
  export type CandidateTransactionOperation = {
51
67
  readonly index: number;
52
- readonly request: FrameworkOperationRequest;
68
+ readonly request: AvOperationRequest;
53
69
  readonly arguments: SemanticOperationArguments;
54
70
  readonly projection: ReadProjectionPlan | undefined;
55
71
  readonly declaredFingerprint: unknown;
@@ -58,7 +74,7 @@ export type CandidateTransactionOperation = {
58
74
  export type ValidatedTransactionOperation = {
59
75
  readonly kind: "operation";
60
76
  readonly index: number;
61
- readonly request: FrameworkOperationRequest;
77
+ readonly request: AvOperationRequest;
62
78
  /**
63
79
  * The Contract of this operation's origin, which is the plan's: the one it was
64
80
  * validated against, the one it runs under, and the one a later `$ref` reads its
@@ -81,12 +97,12 @@ export type ValidatedTransactionPlan = {
81
97
  * Framework is constructed. The record-write facts are not among them: they
82
98
  * are checked when each operation runs, after its pipes.
83
99
  */
84
- export type TransactionPlanDependencies<M extends AvAdapterModel> = Omit<OperationPipelineDependencies<M>, "recordWrites" | "contexts" | "fieldStages"> & {
100
+ type TransactionPlanDependencies<M extends AvAdapterModel> = Omit<OperationPipelineDependencies<M>, "recordWrites" | "contexts" | "fieldStages"> & {
85
101
  readonly cascades: CascadeClosure;
86
102
  /** Whether the Adapter declares `sqlStatements`: read once, at construction. */
87
103
  readonly sqlStatements: boolean;
88
104
  };
89
- export type TransactionPlanValidationResult = {
105
+ type TransactionPlanValidationResult = {
90
106
  readonly ok: true;
91
107
  readonly plan: ValidatedTransactionPlan;
92
108
  } | {
@@ -102,4 +118,4 @@ export declare function transactionsUnavailableFailure(): AvOperationFailureResp
102
118
  /**
103
119
  * Whole-plan Framework Validation Layer for transaction structure and identity.
104
120
  */
105
- export declare function validateTransactionPlan<M extends AvAdapterModel>(dependencies: TransactionPlanDependencies<M>, request: FrameworkTransactionRequest, origins?: readonly TransactionOperationOrigin[], planArguments?: PlanArguments): Promise<TransactionPlanValidationResult>;
121
+ export declare function validateTransactionPlan<M extends AvAdapterModel>(dependencies: TransactionPlanDependencies<M>, request: AvTransactionRequest, origins?: readonly TransactionOperationOrigin[], planArguments?: PlanArguments): Promise<TransactionPlanValidationResult>;
@@ -4,7 +4,7 @@ import { parseOperationIdentity } from "../operations/operation-identity.js";
4
4
  import { findOperationAvailabilityIssue, operationUnavailableIssue, unavailableOperationKey, } from "../operations/operation-validator.js";
5
5
  import { resourceUnavailableIssue } from "../operations/operation-validator-core.js";
6
6
  import { VALIDATION_CODE_MESSAGES, validationIssue, } from "../operations/validation-code.js";
7
- import { AvCallerDataError, locateCallerDataError, } from "../runtime/caller-data.copier.js";
7
+ import { AvCallerDataError, locateCallerDataError, mirrorCallerData, } from "../runtime/caller-data.copier.js";
8
8
  import { copyAtDoor, misuseIdentityOf, refuseCallerData, } from "../runtime/caller-data.door.js";
9
9
  import { planReadOperation, } from "../runtime/computed-read-runtime.js";
10
10
  import { planOperationArgumentsPath, planStepPath, } from "../runtime/error-boundary.js";
@@ -12,6 +12,7 @@ import { createMisuseReporter } from "../runtime/misuse-reporter.js";
12
12
  import { operationFailure } from "../runtime/operation-response.js";
13
13
  import { activeContract, validateOperationRequest, validateProtocolIdentity, } from "../runtime/operation-runtime.js";
14
14
  import { mapValidationOutcome, VALIDATION_OUTCOME_MESSAGES, } from "../runtime/outcome-mapper.js";
15
+ import { isRecord } from "../runtime/record.guard.js";
15
16
  import { encodeOperationArgumentsForWire } from "./operation-arguments-encoder.js";
16
17
  import { computeOperationFingerprint, isOperationFingerprint, } from "./operation-fingerprint.js";
17
18
  import { validateSqlStatement } from "./sql-statement.validator.js";
@@ -24,6 +25,32 @@ const CALLER_PLAN = { source: "caller" };
24
25
  const STEP_ARGUMENTS_POLICY = {
25
26
  mirror: (value) => Object.hasOwn(value, "$ref"),
26
27
  };
28
+ export function capturePlanAtCall(plan) {
29
+ const refused = new Map();
30
+ if (typeof plan !== "object" || plan === null) {
31
+ return { plan, refused };
32
+ }
33
+ try {
34
+ const mirrored = mirrorCallerData(plan, {
35
+ copyAt: (path) => path.length === 3 &&
36
+ path[0] === "operations" &&
37
+ typeof path[1] === "number" &&
38
+ path[2] === "args"
39
+ ? STEP_ARGUMENTS_POLICY
40
+ : undefined,
41
+ refused: (path, error) => {
42
+ refused.set(path[1], error);
43
+ },
44
+ });
45
+ return { plan: mirrored, refused };
46
+ }
47
+ catch (error) {
48
+ if (error instanceof AvCallerDataError) {
49
+ return { plan, refused };
50
+ }
51
+ throw error;
52
+ }
53
+ }
27
54
  function captureSteps(operations, operationCount, planArguments) {
28
55
  const steps = [];
29
56
  const statements = planArguments.source === "owned" ? planArguments.statements : undefined;
@@ -78,9 +105,6 @@ const OPERATION_KEYS = [
78
105
  "args",
79
106
  "fingerprint",
80
107
  ];
81
- function isObject(value) {
82
- return typeof value === "object" && value !== null && !Array.isArray(value);
83
- }
84
108
  function operationKeyFailure(contract, step, operation) {
85
109
  const { resource, family, variant } = step;
86
110
  const issue = typeof family === "string" && typeof variant === "string"
@@ -173,7 +197,7 @@ function* relationTraversals(contract, resourceName, value, path) {
173
197
  }
174
198
  return;
175
199
  }
176
- if (!isObject(value)) {
200
+ if (!isRecord(value)) {
177
201
  return;
178
202
  }
179
203
  for (const [key, entry] of Object.entries(value)) {
@@ -189,7 +213,7 @@ function* relationTraversals(contract, resourceName, value, path) {
189
213
  }
190
214
  }
191
215
  function* operationTraversals(contract, request, index) {
192
- if (!isObject(request.arguments)) {
216
+ if (!isRecord(request.arguments)) {
193
217
  return;
194
218
  }
195
219
  const root = planOperationArgumentsPath(index);
@@ -203,7 +227,7 @@ function* operationTraversals(contract, request, index) {
203
227
  function deletedResources(contract, request, index) {
204
228
  const deleted = request.family === "delete" ? [request.resource] : [];
205
229
  for (const traversal of operationTraversals(contract, request, index)) {
206
- if (isObject(traversal.value) &&
230
+ if (isRecord(traversal.value) &&
207
231
  Object.hasOwn(traversal.value, "$delete")) {
208
232
  deleted.push(traversal.field.target);
209
233
  }
@@ -1,10 +1,8 @@
1
1
  import { lookupField, lookupOwn, lookupResource, } from "../contracts/contract-lookup.js";
2
2
  import { planOperationArgumentsPath } from "../runtime/error-boundary.js";
3
- import { isPlainRecord, referenceOperandShape, } from "../runtime/scalar-runtime.js";
3
+ import { isPlainRecord, isRecord } from "../runtime/record.guard.js";
4
+ import { referenceOperandShape } from "../runtime/scalar-runtime.js";
4
5
  import { routeTransactionReferenceCandidate, } from "./transaction-reference.js";
5
- function isObject(value) {
6
- return typeof value === "object" && value !== null && !Array.isArray(value);
7
- }
8
6
  function at(position, ...segments) {
9
7
  return { ...position, path: [...position.path, ...segments] };
10
8
  }
@@ -23,7 +21,7 @@ function collectValue(field, shape, value, path, candidates, written = false) {
23
21
  return true;
24
22
  }
25
23
  function collectKey(position, selector, candidates) {
26
- if (!isObject(selector)) {
24
+ if (!isRecord(selector)) {
27
25
  return;
28
26
  }
29
27
  const resource = lookupResource(position.contract, position.resource);
@@ -61,7 +59,7 @@ function collectScalarFilter(field, filter, path, candidates) {
61
59
  }
62
60
  }
63
61
  function collectWhere(position, where, candidates) {
64
- if (!isObject(where)) {
62
+ if (!isRecord(where)) {
65
63
  return;
66
64
  }
67
65
  const resource = lookupResource(position.contract, position.resource);
@@ -87,7 +85,7 @@ function collectWhere(position, where, candidates) {
87
85
  if (field.cardinality === "one") {
88
86
  collectWhere(target, value, candidates);
89
87
  }
90
- else if (isObject(value)) {
88
+ else if (isRecord(value)) {
91
89
  for (const operator of ["some", "every", "none"]) {
92
90
  if (Object.hasOwn(value, operator)) {
93
91
  collectWhere(at(target, operator), value[operator], candidates);
@@ -107,7 +105,7 @@ function eachEntry(position, operand, visit) {
107
105
  visit(position, operand);
108
106
  }
109
107
  function collectRelationDirectives(position, edge, value, candidates) {
110
- if (!isObject(value)) {
108
+ if (!isRecord(value)) {
111
109
  return;
112
110
  }
113
111
  const target = { ...position, resource: edge.target };
@@ -129,7 +127,7 @@ function collectRelationDirectives(position, edge, value, candidates) {
129
127
  case "$delete":
130
128
  case "$upsert":
131
129
  eachEntry(directivePosition, operand, (entryPosition, entry) => {
132
- if (!isObject(entry)) {
130
+ if (!isRecord(entry)) {
133
131
  return;
134
132
  }
135
133
  const where = at(entryPosition, "where");
@@ -150,7 +148,7 @@ function collectRelationDirectives(position, edge, value, candidates) {
150
148
  }
151
149
  }
152
150
  function collectData(position, data, candidates) {
153
- if (!isObject(data)) {
151
+ if (!isRecord(data)) {
154
152
  return;
155
153
  }
156
154
  const resource = lookupResource(position.contract, position.resource);
@@ -3,14 +3,14 @@ import type { SemanticOperationArguments } from "../operations/operation-validat
3
3
  import type { AvValidationIssue } from "../operations/validation-code.js";
4
4
  import type { ValidatedSqlStatement } from "./sql-statement.js";
5
5
  import type { ValidatedTransactionOperation } from "./transaction-plan-validator.js";
6
- export type ResolvedTransactionArguments = {
6
+ type ResolvedTransactionArguments = {
7
7
  readonly ok: true;
8
8
  readonly arguments: SemanticOperationArguments;
9
9
  } | {
10
10
  readonly ok: false;
11
11
  readonly issues: readonly AvValidationIssue[];
12
12
  };
13
- export type ResolvedSqlStatement = {
13
+ type ResolvedSqlStatement = {
14
14
  readonly ok: true;
15
15
  readonly statement: AvAdapterSqlStatement;
16
16
  } | {
@@ -38,3 +38,4 @@ export declare function resolveSqlStatement(statement: ValidatedSqlStatement, re
38
38
  * alter the source's committed result.
39
39
  */
40
40
  export declare function resolveTransactionReferences(operation: ValidatedTransactionOperation, results: readonly unknown[]): ResolvedTransactionArguments;
41
+ export {};
@@ -1,9 +1,7 @@
1
1
  import { validationIssue } from "../operations/validation-code.js";
2
+ import { isRecord } from "../runtime/record.guard.js";
2
3
  import { copyScalarFieldValue } from "../runtime/scalar-runtime.js";
3
4
  import { replaceTransactionSlotValues } from "./transaction-slot-writer.js";
4
- function isRecord(value) {
5
- return typeof value === "object" && value !== null && !Array.isArray(value);
6
- }
7
5
  function unresolvedIssue(path) {
8
6
  return validationIssue("V1018", [...path, "$ref", "path"], "Transaction reference resolved to no value.");
9
7
  }
@@ -2,7 +2,9 @@ import type { AvContract } from "../contracts/contract.js";
2
2
  import type { AvField } from "../contracts/field.js";
3
3
  import type { AvValidationIssue } from "../operations/validation-code.js";
4
4
  import type { AvOperationFailureResponse } from "../runtime/operation-response.js";
5
+ import type { OperationFingerprint } from "./deferred-operation.js";
5
6
  import type { CandidateTransactionOperation, TransactionReferenceSlot, ValidatedTransactionStep } from "./transaction-plan-validator.js";
7
+ import type { TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
6
8
  type Path = readonly (string | number)[];
7
9
  type ReferenceValidationResult = {
8
10
  readonly ok: true;
@@ -20,10 +22,8 @@ export declare function invalidSourceIndexIssue(operationPath: Path): AvValidati
20
22
  * integer naming a step before the referencing one (`V1016`).
21
23
  */
22
24
  export declare function referenceSourceAt(earlier: readonly ValidatedTransactionStep[], sourceIndex: unknown, referencingIndex: number): ValidatedTransactionStep | undefined;
23
- /** The `V1010` refusal of a reference whose source is an `appTx.$sql` step. */
24
- export declare function sqlSourceIssue(pathPath: Path): AvValidationIssue;
25
25
  /** The field a reference reads from its source step, or why it cannot read one. */
26
- export type ReferenceSourceRead = {
26
+ type ReferenceSourceRead = {
27
27
  readonly ok: true;
28
28
  readonly field: AvField<AvContract>;
29
29
  } | {
@@ -39,6 +39,46 @@ export type ReferenceSourceRead = {
39
39
  * the source's to read. Assignability to a destination is the caller's.
40
40
  */
41
41
  export declare function referenceSourceField(source: ValidatedTransactionStep, segment: string, pathPath: Path): ReferenceSourceRead;
42
+ /** A `$ref` control object read through: its source step, field and fingerprint. */
43
+ type ReferenceCandidateInspection = {
44
+ readonly ok: true;
45
+ readonly source: Extract<ValidatedTransactionStep, {
46
+ kind: "operation";
47
+ }>;
48
+ readonly segment: string;
49
+ readonly fingerprint: OperationFingerprint;
50
+ readonly field: AvField<AvContract>;
51
+ /** The candidate's `path` member's own path, where a type refusal stands. */
52
+ readonly pathPath: Path;
53
+ } | {
54
+ readonly ok: false;
55
+ readonly issue: AvValidationIssue;
56
+ };
57
+ /**
58
+ * Inspects one `$ref` control object standing at `slotPath` of step
59
+ * `referencingIndex`, through property descriptors only: its shape, its source
60
+ * step (an earlier one, never a SQL step), the source's fingerprint and the one
61
+ * field its path reads from the source's projection. Assignability to the
62
+ * destination is the caller's. Shared by an operation step's slots and an
63
+ * `appTx.$sql` value, so both refuse a malformed reference alike.
64
+ */
65
+ export declare function inspectReferenceCandidate(candidate: unknown, slotPath: Path, earlier: readonly ValidatedTransactionStep[], referencingIndex: number): ReferenceCandidateInspection;
66
+ /** The validated slots of a step's candidates, or the first one's refusal. */
67
+ type ReferenceSlotsValidation = {
68
+ readonly ok: true;
69
+ readonly references: readonly TransactionReferenceSlot[];
70
+ } | {
71
+ readonly ok: false;
72
+ readonly issue: AvValidationIssue;
73
+ };
74
+ /**
75
+ * Judges every `$ref` candidate of step `index` by the Framework Validation
76
+ * Layer's reference rules — its shape, an earlier non-SQL source step, that
77
+ * step's fingerprint, a field of its single-row projection, and type
78
+ * compatibility with the slot it stands in — and answers the validated slots,
79
+ * or the first refusal.
80
+ */
81
+ export declare function validateReferenceSlots(candidates: readonly TransactionReferenceCandidateSlot[], earlier: readonly ValidatedTransactionStep[], index: number): ReferenceSlotsValidation;
42
82
  /** Validates every passive reference candidate before operation fingerprinting. */
43
83
  export declare function validateTransactionReferences(operation: CandidateTransactionOperation, earlier: readonly ValidatedTransactionStep[]): ReferenceValidationResult;
44
84
  export {};
@@ -179,7 +179,7 @@ export function referenceSourceAt(earlier, sourceIndex, referencingIndex) {
179
179
  ? source
180
180
  : undefined;
181
181
  }
182
- export function sqlSourceIssue(pathPath) {
182
+ function sqlSourceIssue(pathPath) {
183
183
  return validationIssue("V1010", pathPath, "Transaction reference source is a SQL step, whose rows cannot be referenced.");
184
184
  }
185
185
  export function referenceSourceField(source, segment, pathPath) {
@@ -212,66 +212,84 @@ export function referenceSourceField(source, segment, pathPath) {
212
212
  }
213
213
  const CANDIDATE_KEYS = new Set(["$ref"]);
214
214
  const REFERENCE_KEYS = new Set(["operation", "fingerprint", "path"]);
215
- export function validateTransactionReferences(operation, earlier) {
215
+ export function inspectReferenceCandidate(candidate, slotPath, earlier, referencingIndex) {
216
+ const refused = (issue) => ({ ok: false, issue });
217
+ const candidateInspection = inspectControlObject(candidate, CANDIDATE_KEYS, slotPath, validationIssue("V1001", slotPath, "Reference control value must be an object."));
218
+ if (!candidateInspection.ok) {
219
+ return refused(candidateInspection.issue);
220
+ }
221
+ const refPath = [...slotPath, "$ref"];
222
+ const refProperty = inspectOwnDataProperty(candidateInspection.value, "$ref", refPath, "V1001", slotPath);
223
+ if (!refProperty.ok) {
224
+ return refused(refProperty.issue);
225
+ }
226
+ const operationPath = [...refPath, "operation"];
227
+ const referenceInspection = inspectControlObject(refProperty.value, REFERENCE_KEYS, refPath, validationIssue("V1016", operationPath, "Transaction reference operation index is invalid."));
228
+ if (!referenceInspection.ok) {
229
+ return refused(referenceInspection.issue);
230
+ }
231
+ const sourceIndexProperty = inspectOwnDataProperty(referenceInspection.value, "operation", operationPath, "V1016", refPath);
232
+ if (!sourceIndexProperty.ok) {
233
+ return refused(sourceIndexProperty.issue);
234
+ }
235
+ const source = referenceSourceAt(earlier, sourceIndexProperty.value, referencingIndex);
236
+ if (source === undefined) {
237
+ return refused(invalidSourceIndexIssue(operationPath));
238
+ }
239
+ if (source.kind === "sql") {
240
+ return refused(sqlSourceIssue([...refPath, "path"]));
241
+ }
242
+ const fingerprintPath = [...refPath, "fingerprint"];
243
+ const fingerprintProperty = inspectOwnDataProperty(referenceInspection.value, "fingerprint", fingerprintPath, "V1000", refPath);
244
+ if (!fingerprintProperty.ok) {
245
+ return refused(fingerprintProperty.issue);
246
+ }
247
+ const fingerprint = fingerprintProperty.value;
248
+ if (!isOperationFingerprint(fingerprint) ||
249
+ fingerprint !== source.fingerprint) {
250
+ return refused(validationIssue("V1017", fingerprintPath, "Transaction reference fingerprint does not match its source operation."));
251
+ }
252
+ const pathPath = [...refPath, "path"];
253
+ const pathProperty = inspectOwnDataProperty(referenceInspection.value, "path", pathPath, "V1010", refPath);
254
+ if (!pathProperty.ok) {
255
+ return refused(pathProperty.issue);
256
+ }
257
+ const pathInspection = inspectPathTuple(pathProperty.value, pathPath);
258
+ if (!pathInspection.ok) {
259
+ return refused(pathInspection.issue);
260
+ }
261
+ const { segment } = pathInspection;
262
+ if (containsUnpairedSurrogate(segment)) {
263
+ return refused(validationIssue("V1010", pathPath, "Transaction reference path contains invalid Unicode."));
264
+ }
265
+ const sourceRead = referenceSourceField(source, segment, pathPath);
266
+ if (!sourceRead.ok) {
267
+ return refused(sourceRead.issue);
268
+ }
269
+ return {
270
+ ok: true,
271
+ source,
272
+ segment,
273
+ fingerprint,
274
+ field: sourceRead.field,
275
+ pathPath,
276
+ };
277
+ }
278
+ export function validateReferenceSlots(candidates, earlier, index) {
216
279
  const references = [];
217
- for (const slot of operation.candidates) {
218
- const candidateInspection = inspectControlObject(slot.candidate, CANDIDATE_KEYS, slot.path, validationIssue("V1001", slot.path, "Reference control value must be an object."));
219
- if (!candidateInspection.ok) {
220
- return failure(candidateInspection.issue, operation.index);
280
+ for (const slot of candidates) {
281
+ const inspection = inspectReferenceCandidate(slot.candidate, slot.path, earlier, index);
282
+ if (!inspection.ok) {
283
+ return inspection;
221
284
  }
222
- const refPath = [...slot.path, "$ref"];
223
- const refProperty = inspectOwnDataProperty(candidateInspection.value, "$ref", refPath, "V1001", slot.path);
224
- if (!refProperty.ok) {
225
- return failure(refProperty.issue, operation.index);
226
- }
227
- const operationPath = [...refPath, "operation"];
228
- const referenceInspection = inspectControlObject(refProperty.value, REFERENCE_KEYS, refPath, validationIssue("V1016", operationPath, "Transaction reference operation index is invalid."));
229
- if (!referenceInspection.ok) {
230
- return failure(referenceInspection.issue, operation.index);
231
- }
232
- const sourceIndexProperty = inspectOwnDataProperty(referenceInspection.value, "operation", operationPath, "V1016", refPath);
233
- if (!sourceIndexProperty.ok) {
234
- return failure(sourceIndexProperty.issue, operation.index);
235
- }
236
- const sourceIndex = sourceIndexProperty.value;
237
- const source = referenceSourceAt(earlier, sourceIndex, operation.index);
238
- if (source === undefined) {
239
- return failure(invalidSourceIndexIssue(operationPath), operation.index);
240
- }
241
- if (source.kind === "sql") {
242
- return failure(sqlSourceIssue([...refPath, "path"]), operation.index);
243
- }
244
- const fingerprintPath = [...refPath, "fingerprint"];
245
- const fingerprintProperty = inspectOwnDataProperty(referenceInspection.value, "fingerprint", fingerprintPath, "V1000", refPath);
246
- if (!fingerprintProperty.ok) {
247
- return failure(fingerprintProperty.issue, operation.index);
248
- }
249
- const fingerprint = fingerprintProperty.value;
250
- if (!isOperationFingerprint(fingerprint) ||
251
- fingerprint !== source.fingerprint) {
252
- return failure(validationIssue("V1017", fingerprintPath, "Transaction reference fingerprint does not match its source operation."), operation.index);
253
- }
254
- const pathPath = [...refPath, "path"];
255
- const pathProperty = inspectOwnDataProperty(referenceInspection.value, "path", pathPath, "V1010", refPath);
256
- if (!pathProperty.ok) {
257
- return failure(pathProperty.issue, operation.index);
258
- }
259
- const pathInspection = inspectPathTuple(pathProperty.value, pathPath);
260
- if (!pathInspection.ok) {
261
- return failure(pathInspection.issue, operation.index);
262
- }
263
- const { segment } = pathInspection;
264
- if (containsUnpairedSurrogate(segment)) {
265
- return failure(validationIssue("V1010", pathPath, "Transaction reference path contains invalid Unicode."), operation.index);
266
- }
267
- const sourceRead = referenceSourceField(source, segment, pathPath);
268
- if (!sourceRead.ok) {
269
- return failure(sourceRead.issue, operation.index);
270
- }
271
- const sourceField = sourceRead.field;
285
+ const { source, segment, fingerprint, pathPath } = inspection;
286
+ const sourceField = inspection.field;
272
287
  if (sourceField.kind !== "scalar" ||
273
288
  !isAssignable(sourceField, slot.field, slot.shape)) {
274
- return failure(validationIssue("V1011", pathPath, "Transaction reference source type is not assignable to its destination."), operation.index);
289
+ return {
290
+ ok: false,
291
+ issue: validationIssue("V1011", pathPath, "Transaction reference source type is not assignable to its destination."),
292
+ };
275
293
  }
276
294
  const reference = Object.freeze({
277
295
  $ref: Object.freeze({
@@ -289,6 +307,14 @@ export function validateTransactionReferences(operation, earlier) {
289
307
  reference,
290
308
  });
291
309
  }
310
+ return { ok: true, references };
311
+ }
312
+ export function validateTransactionReferences(operation, earlier) {
313
+ const validation = validateReferenceSlots(operation.candidates, earlier, operation.index);
314
+ if (!validation.ok) {
315
+ return failure(validation.issue, operation.index);
316
+ }
317
+ const { references } = validation;
292
318
  const controls = references.map((slot) => ({
293
319
  path: slot.path,
294
320
  value: slot.reference,