@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
@@ -0,0 +1,204 @@
1
+ import { lookupField, lookupOwn, lookupResource, } from "../contracts/contract-lookup.js";
2
+ import { planOperationArgumentsPath } from "../runtime/error-boundary.js";
3
+ import { isPlainRecord, referenceOperandShape, } from "../runtime/scalar-runtime.js";
4
+ import { routeTransactionReferenceCandidate, } from "./transaction-reference.js";
5
+ function isObject(value) {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
8
+ function at(position, ...segments) {
9
+ return { ...position, path: [...position.path, ...segments] };
10
+ }
11
+ function collectValue(field, shape, value, path, candidates, written = false) {
12
+ const route = routeTransactionReferenceCandidate(value);
13
+ if (route.kind === "ordinary") {
14
+ return false;
15
+ }
16
+ candidates.push({
17
+ path,
18
+ field,
19
+ shape,
20
+ written,
21
+ candidate: route.candidate,
22
+ });
23
+ return true;
24
+ }
25
+ function collectKey(position, selector, candidates) {
26
+ if (!isObject(selector)) {
27
+ return;
28
+ }
29
+ const resource = lookupResource(position.contract, position.resource);
30
+ for (const [fieldName, value] of Object.entries(selector)) {
31
+ const field = lookupField(resource, fieldName);
32
+ if (field?.kind === "scalar") {
33
+ collectValue(field, "nonNullValue", value, [...position.path, fieldName], candidates);
34
+ }
35
+ }
36
+ }
37
+ function collectKeys(position, selectors, candidates) {
38
+ if (Array.isArray(selectors)) {
39
+ selectors.forEach((selector, index) => {
40
+ collectKey(at(position, index), selector, candidates);
41
+ });
42
+ return;
43
+ }
44
+ collectKey(position, selectors, candidates);
45
+ }
46
+ function collectScalarFilter(field, filter, path, candidates) {
47
+ if (collectValue(field, "value", filter, path, candidates) ||
48
+ !isPlainRecord(filter)) {
49
+ return;
50
+ }
51
+ for (const [operator, operand] of Object.entries(filter)) {
52
+ const operandPath = [...path, operator];
53
+ if (operator === "not") {
54
+ collectScalarFilter(field, operand, operandPath, candidates);
55
+ continue;
56
+ }
57
+ const shape = referenceOperandShape(operator);
58
+ if (shape !== undefined) {
59
+ collectValue(field, shape, operand, operandPath, candidates);
60
+ }
61
+ }
62
+ }
63
+ function collectWhere(position, where, candidates) {
64
+ if (!isObject(where)) {
65
+ return;
66
+ }
67
+ const resource = lookupResource(position.contract, position.resource);
68
+ for (const [key, value] of Object.entries(where)) {
69
+ if (key === "AND" || key === "OR") {
70
+ if (Array.isArray(value)) {
71
+ value.forEach((entry, index) => {
72
+ collectWhere(at(position, key, index), entry, candidates);
73
+ });
74
+ }
75
+ continue;
76
+ }
77
+ if (key === "NOT") {
78
+ collectWhere(at(position, key), value, candidates);
79
+ continue;
80
+ }
81
+ const field = lookupField(resource, key);
82
+ if (field?.kind === "scalar") {
83
+ collectScalarFilter(field, value, [...position.path, key], candidates);
84
+ }
85
+ else if (field?.kind === "relation") {
86
+ const target = { ...at(position, key), resource: field.target };
87
+ if (field.cardinality === "one") {
88
+ collectWhere(target, value, candidates);
89
+ }
90
+ else if (isObject(value)) {
91
+ for (const operator of ["some", "every", "none"]) {
92
+ if (Object.hasOwn(value, operator)) {
93
+ collectWhere(at(target, operator), value[operator], candidates);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ function eachEntry(position, operand, visit) {
101
+ if (Array.isArray(operand)) {
102
+ operand.forEach((entry, index) => {
103
+ visit(at(position, index), entry);
104
+ });
105
+ return;
106
+ }
107
+ visit(position, operand);
108
+ }
109
+ function collectRelationDirectives(position, edge, value, candidates) {
110
+ if (!isObject(value)) {
111
+ return;
112
+ }
113
+ const target = { ...position, resource: edge.target };
114
+ for (const [directive, operand] of Object.entries(value)) {
115
+ const directivePosition = at(target, directive);
116
+ switch (directive) {
117
+ case "$connect":
118
+ case "$disconnect":
119
+ case "$set":
120
+ collectKeys(directivePosition, operand, candidates);
121
+ break;
122
+ case "$create":
123
+ eachEntry(directivePosition, operand, (entryPosition, entry) => {
124
+ collectData(entryPosition, entry, candidates);
125
+ });
126
+ break;
127
+ case "$connectOrCreate":
128
+ case "$update":
129
+ case "$delete":
130
+ case "$upsert":
131
+ eachEntry(directivePosition, operand, (entryPosition, entry) => {
132
+ if (!isObject(entry)) {
133
+ return;
134
+ }
135
+ const where = at(entryPosition, "where");
136
+ if (directive === "$update" || directive === "$delete") {
137
+ collectWhere(where, entry.where, candidates);
138
+ }
139
+ else {
140
+ collectKey(where, entry.where, candidates);
141
+ }
142
+ for (const branch of ["create", "update", "data"]) {
143
+ if (Object.hasOwn(entry, branch)) {
144
+ collectData(at(entryPosition, branch), entry[branch], candidates);
145
+ }
146
+ }
147
+ });
148
+ break;
149
+ }
150
+ }
151
+ }
152
+ function collectData(position, data, candidates) {
153
+ if (!isObject(data)) {
154
+ return;
155
+ }
156
+ const resource = lookupResource(position.contract, position.resource);
157
+ for (const [fieldName, value] of Object.entries(data)) {
158
+ const field = lookupField(resource, fieldName);
159
+ if (field?.kind === "scalar") {
160
+ collectValue(field, "value", value, [...position.path, fieldName], candidates, true);
161
+ }
162
+ else if (field?.kind === "relation") {
163
+ collectRelationDirectives(at(position, fieldName), field, value, candidates);
164
+ }
165
+ }
166
+ }
167
+ export function collectTransactionReferenceCandidates(contract, request, index, args) {
168
+ const candidates = [];
169
+ const root = {
170
+ contract,
171
+ resource: request.resource,
172
+ path: planOperationArgumentsPath(index),
173
+ };
174
+ const where = lookupOwn(args, "where");
175
+ if (request.variant === "unique") {
176
+ collectKey(at(root, "where"), where, candidates);
177
+ }
178
+ else {
179
+ collectWhere(at(root, "where"), where, candidates);
180
+ }
181
+ collectKey(at(root, "cursor"), lookupOwn(args, "cursor"), candidates);
182
+ if (request.family === "create") {
183
+ const data = lookupOwn(args, "data");
184
+ if (request.variant === "many" || request.variant === "count") {
185
+ if (Array.isArray(data)) {
186
+ data.forEach((entry, dataIndex) => {
187
+ collectData(at(root, "data", dataIndex), entry, candidates);
188
+ });
189
+ }
190
+ }
191
+ else {
192
+ collectData(at(root, "data"), data, candidates);
193
+ }
194
+ }
195
+ else if (request.family === "update") {
196
+ collectData(at(root, "data"), lookupOwn(args, "data"), candidates);
197
+ }
198
+ else if (request.family === "upsert") {
199
+ for (const stage of ["create", "update"]) {
200
+ collectData(at(root, stage), lookupOwn(args, stage), candidates);
201
+ }
202
+ }
203
+ return candidates;
204
+ }
@@ -10,17 +10,14 @@ export type ResolvedTransactionArguments = {
10
10
  };
11
11
  /**
12
12
  * Substitutes every validated `$ref` placeholder of one operation from the results
13
- * ledger: each earlier operation's final `data`, exactly the value at its index in
14
- * the `A1009` results array. Validation already proved index, source fingerprint,
15
- * projected path and type, and none of that is re-run here; only what can change
16
- * at runtime is checked. A `null` or non-record source, or a source lacking the
17
- * referenced own key, resolves to no value at the full reference path. The result
18
- * is a fresh argument graph: only the ancestors of substituted slots are cloned,
19
- * so the validated plan is never mutated, and every substituted value is a
20
- * framework-owned copy of the source's value, so a dependent operation mutating
21
- * its arguments cannot alter the source's committed result.
22
- *
23
- * Reading final data runs developer-produced accessors; a throw from here is the
24
- * framework's own per-operation failure, classified by the caller.
13
+ * ledger: each earlier operation's final `data`, exactly the value at its index in the
14
+ * `A1009` results array. Validation already proved index, source fingerprint,
15
+ * projected path and type, and none of that is re-run here; only what can change at
16
+ * runtime is checked. A `null` or non-record source, or a source lacking the
17
+ * referenced own key, resolves to no value at the full reference path. The result is a
18
+ * fresh argument graph: only the ancestors of substituted slots are cloned, so the
19
+ * validated plan is never mutated, and every substituted value is a framework-owned
20
+ * copy of the source's value, so a dependent operation mutating its arguments cannot
21
+ * alter the source's committed result.
25
22
  */
26
23
  export declare function resolveTransactionReferences(operation: ValidatedTransactionOperation, results: readonly unknown[]): ResolvedTransactionArguments;
@@ -1,11 +1,12 @@
1
1
  import { validationIssue } from "../operations/validation-code.js";
2
- import { copyScalarFieldValue } from "../runtime/scalar-runtime.js";
2
+ import { copyScalarFieldValue, jsonShapeIssues, } from "../runtime/scalar-runtime.js";
3
3
  import { replaceTransactionSlotValues } from "./transaction-slot-writer.js";
4
4
  function isRecord(value) {
5
5
  return typeof value === "object" && value !== null && !Array.isArray(value);
6
6
  }
7
7
  export function resolveTransactionReferences(operation, results) {
8
8
  const substitutions = [];
9
+ const shapeIssues = [];
9
10
  for (const slot of operation.references) {
10
11
  const { operation: source, path: [segment], } = slot.reference.$ref;
11
12
  const row = results[source];
@@ -17,10 +18,14 @@ export function resolveTransactionReferences(operation, results) {
17
18
  ],
18
19
  };
19
20
  }
20
- substitutions.push({
21
- path: slot.path,
22
- value: copyScalarFieldValue(slot.field, row[segment]),
23
- });
21
+ const value = copyScalarFieldValue(slot.source, row[segment]);
22
+ if (slot.written) {
23
+ shapeIssues.push(...jsonShapeIssues(slot.field, value, slot.path));
24
+ }
25
+ substitutions.push({ path: slot.path, value });
26
+ }
27
+ if (shapeIssues.length > 0) {
28
+ return { ok: false, issues: shapeIssues };
24
29
  }
25
30
  return {
26
31
  ok: true,
@@ -141,25 +141,28 @@ function containsUnpairedSurrogate(value) {
141
141
  }
142
142
  return false;
143
143
  }
144
- function sameType(source, destination) {
144
+ function sameScalar(source, destination) {
145
145
  if ("scalar" in source.type) {
146
- if (!("scalar" in destination.type)) {
147
- return false;
148
- }
149
- if (source.type.scalar !== destination.type.scalar) {
150
- return false;
151
- }
146
+ return ("scalar" in destination.type &&
147
+ source.type.scalar === destination.type.scalar);
152
148
  }
153
- else {
154
- if (!("enum" in destination.type)) {
155
- return false;
156
- }
157
- if (source.type.enum !== destination.type.enum) {
158
- return false;
159
- }
149
+ return ("enum" in destination.type && source.type.enum === destination.type.enum);
150
+ }
151
+ function isAssignable(source, destination, shape) {
152
+ if (!sameScalar(source, destination)) {
153
+ return false;
154
+ }
155
+ switch (shape) {
156
+ case "value":
157
+ return (source.list === destination.list &&
158
+ !(source.nullable && !destination.nullable));
159
+ case "nonNullValue":
160
+ return source.list === destination.list && !source.nullable;
161
+ case "entry":
162
+ return !source.list && !source.nullable;
163
+ case "entries":
164
+ return source.list && !source.nullable;
160
165
  }
161
- return (source.list === destination.list &&
162
- !(source.nullable && !destination.nullable));
163
166
  }
164
167
  const CANDIDATE_KEYS = new Set(["$ref"]);
165
168
  const REFERENCE_KEYS = new Set(["operation", "fingerprint", "path"]);
@@ -234,7 +237,8 @@ export function validateTransactionReferences(operation, earlier) {
234
237
  if (sourceField === undefined) {
235
238
  return failure(validationIssue("V1010", pathPath, "Transaction reference path is not present in the source projection."), operation.index);
236
239
  }
237
- if (sourceField.kind !== "scalar" || !sameType(sourceField, slot.field)) {
240
+ if (sourceField.kind !== "scalar" ||
241
+ !isAssignable(sourceField, slot.field, slot.shape)) {
238
242
  return failure(validationIssue("V1011", pathPath, "Transaction reference source type is not assignable to its destination."), operation.index);
239
243
  }
240
244
  const reference = Object.freeze({
@@ -247,6 +251,9 @@ export function validateTransactionReferences(operation, earlier) {
247
251
  references.push({
248
252
  path: Object.freeze([...slot.path]),
249
253
  field: slot.field,
254
+ shape: slot.shape,
255
+ written: slot.written,
256
+ source: sourceField,
250
257
  reference,
251
258
  });
252
259
  }
@@ -1,13 +1,18 @@
1
1
  import type { WriteScope } from "../contracts/capability.js";
2
2
  import type { Contract } from "../contracts/contract.js";
3
3
  import type { ScalarForms } from "../contracts/scalar-value-type.js";
4
- import type { CreateDataInput, OperationArgumentsFor, ResourceKey, UpdateDataInput, WritableRelationKey } from "../operations/operation-arguments.js";
4
+ import type { CreateDataInput, OperationArgumentsFor, ResourceKey, UpdateDataInput } from "../operations/operation-arguments.js";
5
5
  import type { OperationIdentity } from "../operations/operation-identity.js";
6
6
  import type { OperationFingerprint } from "./deferred-operation.js";
7
7
  declare const REFERENCE_VALUE: unique symbol;
8
+ /** Any object with a `$ref` key, before it is validated as a reference. */
8
9
  export type TransactionReferenceCandidate = {
9
10
  readonly $ref: unknown;
10
11
  } & Readonly<Record<string, unknown>>;
12
+ /**
13
+ * A reference to a field of an earlier operation's result in the same
14
+ * transaction plan: `{ $ref: { operation, fingerprint, path } }`.
15
+ */
11
16
  export type TransactionReference<Value = unknown> = {
12
17
  readonly $ref: {
13
18
  readonly operation: number;
@@ -16,6 +21,7 @@ export type TransactionReference<Value = unknown> = {
16
21
  };
17
22
  readonly [REFERENCE_VALUE]?: Value;
18
23
  };
24
+ /** Whether a value is an ordinary value or a `$ref` candidate. */
19
25
  export type TransactionReferenceCandidateRoute = {
20
26
  readonly kind: "ordinary";
21
27
  } | {
@@ -27,15 +33,11 @@ export type TransactionReferenceCandidateRoute = {
27
33
  readonly kind: "reflection-failure";
28
34
  readonly candidate: unknown;
29
35
  };
30
- /**
31
- * Total descriptor-only routing for a scalar value at a transaction-reference
32
- * position.
33
- */
36
+ /** Whether a scalar value at a reference position is an ordinary value or a `$ref` candidate. */
34
37
  export declare function routeTransactionReferenceCandidate(value: unknown): TransactionReferenceCandidateRoute;
38
+ /** Whether `value` is an object with a `$ref` key; it is not validated here. */
35
39
  export declare function isTransactionReferenceCandidate(value: unknown): value is TransactionReferenceCandidate;
36
- /**
37
- * Narrows a structurally complete `$ref` object.
38
- */
40
+ /** Whether `value` is a complete `$ref` object. */
39
41
  export declare function isTransactionReferenceObject(value: unknown): value is TransactionReference;
40
42
  /**
41
43
  * A scalar mutation value inside a plan: the value itself, or a reference to an
@@ -43,68 +45,33 @@ export declare function isTransactionReferenceObject(value: unknown): value is T
43
45
  */
44
46
  export type TransactionScalarValue<Value> = Value | TransactionReference<Value>;
45
47
  /**
46
- * A reference carries its source's final data, which every scope returns in the
47
- * application forms; so a client-origin builder writes wire forms and still takes
48
- * a `$ref` typed by the application form of the same Contract field — strict type
49
- * compatibility compares Contract field types, never their forms. Unstated, both
50
- * are the same map and this is {@link TransactionScalarValue}.
51
- */
52
- type ReferenceableValue<Value, ReferenceValue> = Value | TransactionReference<ReferenceValue>;
53
- type MemberOf<Data, Key> = Key extends keyof Data ? Data[Key] : never;
54
- /**
55
- * The exported {@link TransactionCreateDataInput} is it with neither form stated;
56
- * the typed builders state both.
57
- */
58
- export type ReferenceableCreateData<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope, Forms extends ScalarForms, ReferenceForms extends ScalarForms> = Readonly<{
59
- [F in keyof CreateDataInput<C, K, Scope, Forms>]: F extends WritableRelationKey<C, K, "create", Scope> ? CreateDataInput<C, K, Scope, Forms>[F] : ReferenceableValue<CreateDataInput<C, K, Scope, Forms>[F], MemberOf<CreateDataInput<C, K, Scope, ReferenceForms>, F>>;
60
- }>;
61
- export type ReferenceableUpdateData<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope, Forms extends ScalarForms, ReferenceForms extends ScalarForms> = Readonly<{
62
- [F in keyof UpdateDataInput<C, K, Scope, Forms>]: F extends WritableRelationKey<C, K, "update", Scope> ? UpdateDataInput<C, K, Scope, Forms>[F] : ReferenceableValue<UpdateDataInput<C, K, Scope, Forms>[F], MemberOf<UpdateDataInput<C, K, Scope, ReferenceForms>, F>>;
63
- }>;
64
- /**
65
- * Only top-level scalar fields accept a `$ref`; a relation field keeps its
66
- * relation mutation action, where a `$ref` is an ordinary invalid value.
48
+ * What a Transaction Slot holds of its destination field, which decides the source
49
+ * fields a reference there accepts — always the same scalar or enum, no coercion:
67
50
  *
68
- * The position is the standalone surface's, read the same way: both surfaces read
69
- * one capability value and differ only in where they bind it, so a plan's flat
70
- * bulk write refuses a nested-only relation exactly as `create.many` does outside
71
- * a plan. The default is the unrestricted position, as on `CreateDataInput`.
51
+ * - `"value"` — the field's whole value, where a `null` means something: a mutation
52
+ * value, or an equality filter (`null` matches the rows the field is unset on). A
53
+ * nullable source only into a nullable field.
54
+ * - `"nonNullValue"` — the field's whole value, where a `null` identifies or orders
55
+ * nothing: a unique key, a `cursor`, an ordering or text comparison. The source is
56
+ * never nullable.
57
+ * - `"entry"` — one entry of a list field (`has`): a non-null, non-list source.
58
+ * - `"entries"` — a list of entries (`in`, `notIn`, `hasEvery`, `hasSome`): a
59
+ * non-null list source.
72
60
  */
73
- export type TransactionCreateDataInput<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope = "nested"> = ReferenceableCreateData<C, K, Scope, ScalarForms, ScalarForms>;
61
+ export type TransactionSlotShape = "value" | "nonNullValue" | "entry" | "entries";
74
62
  /**
75
- * See {@link TransactionCreateDataInput}.
63
+ * Create data inside a transaction plan, at one write position: its scalar values
64
+ * and the unique keys its relation directives name may hold a `$ref`. The default
65
+ * is the unrestricted position, as on `CreateDataInput`.
76
66
  */
77
- export type TransactionUpdateDataInput<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope = "nested"> = ReferenceableUpdateData<C, K, Scope, ScalarForms, ScalarForms>;
67
+ export type TransactionCreateDataInput<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope = "nested"> = CreateDataInput<C, K, Scope, ScalarForms, ScalarForms>;
68
+ /** Update data inside a transaction plan. See {@link TransactionCreateDataInput}. */
69
+ export type TransactionUpdateDataInput<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope = "nested"> = UpdateDataInput<C, K, Scope, ScalarForms, ScalarForms>;
78
70
  /**
79
- * The typed builders read it with both forms stated; the exported {@link
80
- * TransactionOperationArgumentsFor} is it with neither.
71
+ * Operation arguments inside a transaction plan, under one value form and one
72
+ * reference form: `OperationArgumentsFor` with its reference positions opened.
81
73
  */
82
- export type ReferenceableArgumentsFor<C extends Contract, K extends ResourceKey<C>, I extends OperationIdentity, Forms extends ScalarForms, ReferenceForms extends ScalarForms> = I extends {
83
- family: "create";
84
- variant: "one";
85
- } ? Omit<OperationArgumentsFor<C, K, I, Forms>, "data"> & {
86
- data: ReferenceableCreateData<C, K, "nested", Forms, ReferenceForms>;
87
- } : I extends {
88
- family: "create";
89
- variant: "many" | "count";
90
- } ? Omit<OperationArgumentsFor<C, K, I, Forms>, "data"> & {
91
- data: readonly ReferenceableCreateData<C, K, "bulkWrite", Forms, ReferenceForms>[];
92
- } : I extends {
93
- family: "update";
94
- variant: "first" | "unique";
95
- } ? Omit<OperationArgumentsFor<C, K, I, Forms>, "data"> & {
96
- data: ReferenceableUpdateData<C, K, "nested", Forms, ReferenceForms>;
97
- } : I extends {
98
- family: "update";
99
- variant: "many" | "count";
100
- } ? Omit<OperationArgumentsFor<C, K, I, Forms>, "data"> & {
101
- data: ReferenceableUpdateData<C, K, "bulkWrite", Forms, ReferenceForms>;
102
- } : I extends {
103
- family: "upsert";
104
- } ? Omit<OperationArgumentsFor<C, K, I, Forms>, "create" | "update"> & {
105
- create: ReferenceableCreateData<C, K, "nested", Forms, ReferenceForms>;
106
- update: ReferenceableUpdateData<C, K, "nested", Forms, ReferenceForms>;
107
- } : OperationArgumentsFor<C, K, I, Forms>;
74
+ export type ReferenceableArgumentsFor<C extends Contract, K extends ResourceKey<C>, I extends OperationIdentity, Forms extends ScalarForms, ReferenceForms extends ScalarForms> = OperationArgumentsFor<C, K, I, Forms, ReferenceForms>;
108
75
  /** Operation arguments inside a transaction plan, no scalar form stated. */
109
76
  export type TransactionOperationArgumentsFor<C extends Contract, K extends ResourceKey<C>, I extends OperationIdentity> = ReferenceableArgumentsFor<C, K, I, ScalarForms, ScalarForms>;
110
77
  export {};
@@ -4,25 +4,23 @@ type TransactionRequestBase = {
4
4
  readonly requestId: string;
5
5
  readonly plan: unknown;
6
6
  };
7
+ /** An in-process transaction request, run under the Application Contract. */
7
8
  export type ApplicationTransactionRequest = TransactionRequestBase & {
8
- readonly scope: "application";
9
+ readonly origin: "application";
9
10
  readonly protocol?: never;
10
11
  readonly transport?: never;
11
12
  };
13
+ /** A remote transaction request, run under the Client Contract. */
12
14
  export type ClientTransactionRequest = TransactionRequestBase & {
13
- readonly scope: "client";
15
+ readonly origin: "client";
14
16
  readonly protocol: ClientProtocolIdentity;
15
17
  readonly transport?: PipelineTransportContext;
16
18
  };
19
+ /** One transaction request, as `framework.executeTransaction` takes it. */
17
20
  export type FrameworkTransactionRequest = ApplicationTransactionRequest | ClientTransactionRequest;
18
21
  /**
19
22
  * The origin one plan operation runs under: its own layer's Contract, its own
20
23
  * pipelines, and — for a client step — the protocol identity it is accepted with.
21
- * The untyped seam derives every operation's origin from the request; the typed
22
- * runner states one per handle.
23
- *
24
- * Internal to the transaction runtime, and deliberately not a member of the
25
- * request: the public seam's request cannot smuggle a per-operation origin.
26
24
  */
27
- export type TransactionOperationOrigin = Pick<ApplicationTransactionRequest, "scope"> | Pick<ClientTransactionRequest, "scope" | "protocol" | "transport">;
25
+ export type TransactionOperationOrigin = Pick<ApplicationTransactionRequest, "origin"> | Pick<ClientTransactionRequest, "origin" | "protocol" | "transport">;
28
26
  export {};
@@ -1,17 +1,20 @@
1
1
  import type { OperationFailureResponse } from "../runtime/operation-response.js";
2
- /**
3
- * A committed plan: each operation's final `data`, in plan order.
4
- *
5
- * `T` mirrors `OperationResponse<T>`: the untyped seam (`executeTransaction`)
6
- * answers the default `readonly unknown[]`, and the typed runner
7
- * (`framework.transaction`) supplies the per-position tuple its handles derive.
8
- */
2
+ /** A committed plan: each operation's final `data`, in plan order. */
9
3
  export type TransactionCommittedResponse<T = readonly unknown[]> = {
10
4
  readonly data: T;
11
5
  readonly code: "A1009";
12
6
  readonly cause: null;
13
7
  };
8
+ /** What a transaction answers: committed (`A1009`) or a failure. */
14
9
  export type TransactionResponse = TransactionCommittedResponse | OperationFailureResponse;
10
+ /** Builds the committed response. */
15
11
  export declare function transactionCommitted(results: readonly unknown[]): TransactionCommittedResponse;
12
+ /**
13
+ * Builds the failure response of a plan step: the step named in
14
+ * `cause.operation`, and each issue at its full plan location —
15
+ * `["operations", operation, "args", …]` for the step's arguments,
16
+ * `["operations", operation, …]` for the step itself.
17
+ */
16
18
  export declare function transactionOperationFailure(failure: OperationFailureResponse, operation: number): OperationFailureResponse;
19
+ /** Builds the `A3002` response for a transaction that itself failed. */
17
20
  export declare function transactionInfrastructureFailure(operation?: number): OperationFailureResponse;
@@ -1,13 +1,36 @@
1
+ import { OPERATION_ARGUMENTS_PATH, planOperationArgumentsPath, planStepPath, } from "../runtime/error-boundary.js";
1
2
  import { operationFailure } from "../runtime/operation-response.js";
2
3
  export function transactionCommitted(results) {
3
4
  return { data: results, code: "A1009", cause: null };
4
5
  }
5
6
  export function transactionOperationFailure(failure, operation) {
7
+ const { issues, ...cause } = failure.cause;
6
8
  return operationFailure(failure.code, {
7
- ...failure.cause,
9
+ ...cause,
10
+ ...(issues === undefined
11
+ ? {}
12
+ : { issues: issues.map((issue) => atPlanLocation(issue, operation)) }),
8
13
  operation,
9
14
  });
10
15
  }
16
+ function isPlanLocated(path) {
17
+ return path[0] === "operations" && typeof path[1] === "number";
18
+ }
19
+ function atPlanLocation(issue, operation) {
20
+ const { path } = issue;
21
+ if (path === undefined || isPlanLocated(path)) {
22
+ return issue;
23
+ }
24
+ return {
25
+ ...issue,
26
+ path: path[0] === OPERATION_ARGUMENTS_PATH[0]
27
+ ? [
28
+ ...planOperationArgumentsPath(operation),
29
+ ...path.slice(OPERATION_ARGUMENTS_PATH.length),
30
+ ]
31
+ : [...planStepPath(operation), ...path],
32
+ };
33
+ }
11
34
  export function transactionInfrastructureFailure(operation) {
12
35
  return operationFailure("A3002", {
13
36
  message: "Transaction failed.",
@@ -1,6 +1,7 @@
1
1
  import type { AdapterModel } from "../adapters/adapter-model.js";
2
2
  import type { TransactionDiagnosticsChannel } from "../runtime/diagnostics-reporter.js";
3
3
  import type { OperationRuntimeDependencies } from "../runtime/operation-runtime.js";
4
+ import type { PlanArguments } from "./transaction-plan-validator.js";
4
5
  import type { FrameworkTransactionRequest, TransactionOperationOrigin } from "./transaction-request.js";
5
6
  import type { TransactionResponse } from "./transaction-response.js";
6
7
  /**
@@ -9,12 +10,13 @@ import type { TransactionResponse } from "./transaction-response.js";
9
10
  * hands it in, so every report of a plan travels the same route.
10
11
  *
11
12
  * `origins`, when given, states each operation's own origin (the typed
12
- * runner's mixed plans); see `validateTransactionPlan`.
13
+ * runner's mixed plans), and `planArguments` whether the steps' arguments are
14
+ * copied at the door; see `validateTransactionPlan`.
13
15
  */
14
- export type FrameworkTransactionExecutor = (request: FrameworkTransactionRequest, diagnostics: TransactionDiagnosticsChannel, origins?: readonly TransactionOperationOrigin[]) => Promise<TransactionResponse>;
16
+ export type FrameworkTransactionExecutor = (request: FrameworkTransactionRequest, diagnostics: TransactionDiagnosticsChannel, origins: readonly TransactionOperationOrigin[] | undefined, planArguments: PlanArguments) => Promise<TransactionResponse>;
15
17
  /**
16
- * Validates a whole plan through the Framework Validation Layer, then runs it
17
- * inside exactly one Adapter transaction. Guards, pipes, hooks and interceptors of
18
- * every plan operation run while the provider transaction is open.
18
+ * Validates a whole plan through the Framework Validation Layer, then runs it inside
19
+ * exactly one Adapter transaction. Guards, pipes, hooks and interceptors of every plan
20
+ * operation run while the provider transaction is open.
19
21
  */
20
22
  export declare function createTransactionRuntime<M extends AdapterModel>(dependencies: OperationRuntimeDependencies<M>): FrameworkTransactionExecutor;
@@ -1,3 +1,4 @@
1
+ import { recordWriteFactsOf } from "../runtime/create-requirement.js";
1
2
  import { planOperationArgumentsPath } from "../runtime/error-boundary.js";
2
3
  import { internalFailure } from "../runtime/operation-response.js";
3
4
  import { executeValidatedOperation } from "../runtime/operation-runtime.js";
@@ -12,14 +13,14 @@ export function createTransactionRuntime(dependencies) {
12
13
  const { adapter, ...runtimeDependencies } = dependencies;
13
14
  const pipelineDependencies = {
14
15
  ...runtimeDependencies,
15
- createRequirements: adapter.createRequirements ?? {},
16
+ recordWrites: recordWriteFactsOf(adapter),
16
17
  };
17
18
  const planDependencies = {
18
19
  ...pipelineDependencies,
19
20
  cascades: resolveCascadeClosure(adapter.referentialActions),
20
21
  };
21
- return async (request, diagnostics, origins) => {
22
- const validation = await validateTransactionPlan(planDependencies, request, origins);
22
+ return async (request, diagnostics, origins, planArguments) => {
23
+ const validation = await validateTransactionPlan(planDependencies, request, origins, planArguments);
23
24
  if (!validation.ok) {
24
25
  return validation.response;
25
26
  }
@@ -1,22 +1,12 @@
1
1
  /**
2
- * The ways a transaction slot path can fail to name a member of the argument view
3
- * it is written into. Every slot path was collected from an argument view by the
4
- * plan validator, so any of these is a framework defect rather than a caller
5
- * error; the violation is the only thing that tells them apart, so it is
6
- * structured data rather than message text.
7
- *
8
- * - `slot-prefix`: the path does not begin `["operations", <this operation>,
9
- * "args", <member>]`, or the view itself is not an object.
10
- * - `absent-member`: a segment names no own member of its container.
11
- * - `non-object-ancestor`: a segment descends through a non-object value.
2
+ * The ways a transaction slot path can fail to name a member of its argument
3
+ * view. Each is a framework defect, not a caller error.
12
4
  */
13
5
  export type TransactionSlotPathViolation = "slot-prefix" | "absent-member" | "non-object-ancestor";
14
6
  /**
15
- * The framework-owned failure thrown when a slot path does not name a member of
16
- * the argument view. It never reaches the wire: inside a plan's transaction
17
- * callback it becomes that operation's `A3000`, during validation the totality
18
- * guard's `A3000`. It reaches a diagnostics sink as the raw `error`, where the
19
- * violation discriminates the three defects.
7
+ * Thrown internally when a slot path does not name a member of its argument
8
+ * view; the caller receives `A3000`, and the diagnostics sink receives this
9
+ * error.
20
10
  */
21
11
  export declare class TransactionSlotPathError extends Error {
22
12
  readonly violation: TransactionSlotPathViolation;