@aventara/core 0.1.0-pilot.0 → 0.1.0-pilot.2
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.
- package/README.md +3 -3
- package/dist/adapters/adapter-field.d.ts +4 -4
- package/dist/adapters/adapter-resource.d.ts +10 -12
- package/dist/adapters/adapter.interface.d.ts +20 -10
- package/dist/compiler/contract-compiler-diagnostic.d.ts +3 -4
- package/dist/compiler/contract.compiler.d.ts +5 -4
- package/dist/compiler/contract.compiler.js +0 -132
- package/dist/config/config.resolver.d.ts +2 -2
- package/dist/config/config.resolver.js +0 -5
- package/dist/config/config.validator.d.ts +3 -3
- package/dist/config/config.validator.js +0 -8
- package/dist/config/define-fields.d.ts +2 -7
- package/dist/config/define-fields.js +0 -15
- package/dist/config/effective-fields.d.ts +4 -8
- package/dist/config/entrypoint.normalizer.d.ts +7 -7
- package/dist/config/entrypoint.normalizer.js +0 -22
- package/dist/config/framework-behaviors-config.d.ts +6 -6
- package/dist/config/framework-config.d.ts +3 -5
- package/dist/config/framework-restrictions-config.d.ts +19 -29
- package/dist/config/pipeline-config.d.ts +8 -18
- package/dist/contracts/capability.d.ts +18 -21
- package/dist/contracts/capability.js +0 -75
- package/dist/contracts/client-contract-structure.validator.d.ts +15 -22
- package/dist/contracts/client-contract-structure.validator.js +0 -27
- package/dist/contracts/contract-canonicalizer.js +0 -96
- package/dist/contracts/contract-hash.js +0 -2
- package/dist/contracts/contract-limits.js +0 -1
- package/dist/contracts/contract-lookup.js +0 -10
- package/dist/contracts/contract-protocol.js +0 -10
- package/dist/contracts/field.d.ts +23 -26
- package/dist/contracts/field.js +0 -107
- package/dist/contracts/lifecycle-trait.js +0 -5
- package/dist/contracts/resource-operations.d.ts +17 -18
- package/dist/contracts/resource-operations.js +0 -63
- package/dist/contracts/scalar-value-type.d.ts +12 -22
- package/dist/contracts/scalar.js +0 -1
- package/dist/contracts/wire-scalar-format.d.ts +20 -20
- package/dist/contracts/wire-scalar-format.js +0 -26
- package/dist/framework/contract-view.d.ts +7 -8
- package/dist/framework/framework-construction.error.js +0 -1
- package/dist/framework/framework.d.ts +26 -27
- package/dist/framework/framework.factory.js +0 -49
- package/dist/framework/operation-facade.js +0 -17
- package/dist/operations/operation-arguments.d.ts +36 -46
- package/dist/operations/operation-boolean-nodes.js +0 -16
- package/dist/operations/operation-call.d.ts +4 -9
- package/dist/operations/operation-identity.js +0 -1
- package/dist/operations/operation-nesting.js +0 -5
- package/dist/operations/operation-result.d.ts +4 -4
- package/dist/operations/operation-validator-core.d.ts +2 -2
- package/dist/operations/operation-validator-core.js +6 -71
- package/dist/operations/operation-validator.d.ts +4 -4
- package/dist/operations/operation-validator.js +0 -12
- package/dist/operations/projection-scope.resolver.d.ts +8 -10
- package/dist/operations/projection-scope.resolver.js +0 -35
- package/dist/operations/validation-code.d.ts +11 -18
- package/dist/operations/validation-code.js +0 -24
- package/dist/operations/write-scope.resolver.d.ts +4 -7
- package/dist/operations/write-scope.resolver.js +0 -37
- package/dist/protocol/absent-route.responder.d.ts +33 -48
- package/dist/protocol/absent-route.responder.js +13 -57
- package/dist/protocol/av-protocol.d.ts +6 -6
- package/dist/protocol/av-protocol.js +0 -10
- package/dist/protocol/contract-document.responder.d.ts +15 -18
- package/dist/protocol/contract-document.responder.js +0 -33
- package/dist/protocol/http-request.decoder.d.ts +55 -61
- package/dist/protocol/http-request.decoder.js +0 -62
- package/dist/protocol/http-request.reader.d.ts +12 -13
- package/dist/protocol/http-request.reader.js +0 -45
- package/dist/protocol/http-response.encoder.d.ts +17 -18
- package/dist/protocol/http-response.encoder.js +0 -59
- package/dist/protocol/http-status.table.d.ts +7 -11
- package/dist/protocol/http-status.table.js +1 -15
- package/dist/protocol/index.d.ts +5 -5
- package/dist/protocol/index.js +0 -9
- package/dist/protocol/operation-response.guard.d.ts +12 -19
- package/dist/protocol/operation-response.guard.js +0 -29
- package/dist/protocol/protocol-failure.d.ts +26 -23
- package/dist/protocol/protocol-failure.js +6 -6
- package/dist/protocol/protocol-headers.d.ts +30 -27
- package/dist/protocol/protocol-headers.js +3 -61
- package/dist/protocol/protocol-surface.d.ts +25 -29
- package/dist/protocol/protocol-surface.js +0 -19
- package/dist/protocol/protocol.binder.d.ts +58 -71
- package/dist/protocol/protocol.binder.js +0 -8
- package/dist/protocol/protocol.handler.d.ts +28 -32
- package/dist/protocol/protocol.handler.js +0 -43
- package/dist/runtime/computed-read-runtime.js +0 -29
- package/dist/runtime/create-requirement.d.ts +65 -0
- package/dist/runtime/create-requirement.js +141 -0
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +0 -8
- package/dist/runtime/diagnostics-reporter.d.ts +6 -6
- package/dist/runtime/diagnostics-reporter.js +0 -35
- package/dist/runtime/error-boundary.d.ts +3 -3
- package/dist/runtime/error-boundary.js +2 -167
- package/dist/runtime/execution-options.d.ts +4 -4
- package/dist/runtime/field-behavior.d.ts +6 -9
- package/dist/runtime/framework-error.js +0 -4
- package/dist/runtime/mutation-planner.d.ts +5 -6
- package/dist/runtime/mutation-planner.js +0 -23
- package/dist/runtime/operation-response.d.ts +1 -1
- package/dist/runtime/operation-response.js +1 -17
- package/dist/runtime/operation-runtime.d.ts +24 -22
- package/dist/runtime/operation-runtime.js +18 -52
- package/dist/runtime/outcome-mapper.js +0 -22
- package/dist/runtime/output-validator.js +0 -1
- package/dist/runtime/pipe-output.validator.d.ts +48 -0
- package/dist/runtime/pipe-output.validator.js +79 -0
- package/dist/runtime/pipeline.d.ts +20 -26
- package/dist/runtime/referential-action.d.ts +14 -19
- package/dist/runtime/referential-action.js +0 -23
- package/dist/runtime/request-id.js +0 -21
- package/dist/runtime/scalar-runtime.d.ts +14 -16
- package/dist/runtime/scalar-runtime.js +12 -57
- package/dist/transactions/deferred-operation.d.ts +9 -14
- package/dist/transactions/operation-arguments-encoder.d.ts +0 -1
- package/dist/transactions/operation-arguments-encoder.js +0 -14
- package/dist/transactions/operation-fingerprint.js +0 -1
- package/dist/transactions/transaction-envelope.js +0 -14
- package/dist/transactions/transaction-integrity-error.d.ts +10 -11
- package/dist/transactions/transaction-integrity-error.js +0 -5
- package/dist/transactions/transaction-plan-assembler.d.ts +0 -1
- package/dist/transactions/transaction-plan-assembler.js +0 -35
- package/dist/transactions/transaction-plan-validator.d.ts +5 -5
- package/dist/transactions/transaction-plan-validator.js +0 -63
- package/dist/transactions/transaction-reference-resolver.d.ts +12 -13
- package/dist/transactions/transaction-reference-resolver.js +0 -16
- package/dist/transactions/transaction-reference-validator.js +0 -8
- package/dist/transactions/transaction-reference.d.ts +19 -43
- package/dist/transactions/transaction-reference.js +0 -11
- package/dist/transactions/transaction-request.d.ts +4 -5
- package/dist/transactions/transaction-response.d.ts +1 -1
- package/dist/transactions/transaction-runtime.d.ts +2 -3
- package/dist/transactions/transaction-runtime.js +5 -44
- package/dist/transactions/transaction-slot-path-error.d.ts +10 -11
- package/dist/transactions/transaction-slot-path-error.js +0 -7
- package/dist/transactions/transaction-slot-writer.d.ts +12 -12
- package/dist/transactions/transaction-slot-writer.js +0 -34
- package/package.json +2 -2
|
@@ -48,9 +48,10 @@ export type ValidatedTransactionPlan = {
|
|
|
48
48
|
/**
|
|
49
49
|
* What validating a plan needs beyond one operation's pipeline: the cascade
|
|
50
50
|
* closure over the Adapter's referential actions, resolved once when the
|
|
51
|
-
* Framework is constructed.
|
|
51
|
+
* Framework is constructed. The create requirements are not among them: they
|
|
52
|
+
* are checked when each operation runs, after its pipes.
|
|
52
53
|
*/
|
|
53
|
-
export type TransactionPlanDependencies<M extends AdapterModel> = OperationPipelineDependencies<M> & {
|
|
54
|
+
export type TransactionPlanDependencies<M extends AdapterModel> = Omit<OperationPipelineDependencies<M>, "createRequirements"> & {
|
|
54
55
|
readonly cascades: CascadeClosure;
|
|
55
56
|
};
|
|
56
57
|
export type TransactionPlanValidationResult = {
|
|
@@ -62,9 +63,8 @@ export type TransactionPlanValidationResult = {
|
|
|
62
63
|
};
|
|
63
64
|
/**
|
|
64
65
|
* The refusal of a plan on a Contract without transaction plans (`A2002`, one
|
|
65
|
-
* `V1006` at `["operations"]`). The one spelling — the protocol's absence
|
|
66
|
-
*
|
|
67
|
-
* envelope too.
|
|
66
|
+
* `V1006` at `["operations"]`). The one spelling — the protocol's absence answer
|
|
67
|
+
* for `/_transactions` is this envelope too.
|
|
68
68
|
*/
|
|
69
69
|
export declare function transactionsUnavailableFailure(): OperationFailureResponse;
|
|
70
70
|
/**
|
|
@@ -48,7 +48,6 @@ function syntheticRequest(origin, requestId, resource, identity, args) {
|
|
|
48
48
|
: { transport: origin.transport }),
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
/** The origin the untyped seam gives every operation: the request's own. */
|
|
52
51
|
function requestOrigin(request) {
|
|
53
52
|
return request.scope === "application"
|
|
54
53
|
? { scope: "application" }
|
|
@@ -60,12 +59,6 @@ function requestOrigin(request) {
|
|
|
60
59
|
: { transport: request.transport }),
|
|
61
60
|
};
|
|
62
61
|
}
|
|
63
|
-
/**
|
|
64
|
-
* The Contracts a plan's operations run under: one per distinct origin. A
|
|
65
|
-
* plan-level gate — the transaction capability, the operation-count limit — holds
|
|
66
|
-
* only when it holds in every one of them, since every step runs inside the same
|
|
67
|
-
* Adapter transaction.
|
|
68
|
-
*/
|
|
69
62
|
function originContracts(contracts, origins) {
|
|
70
63
|
const layers = new Set(origins.map((origin) => origin.scope));
|
|
71
64
|
return [...layers].map((scope) => scope === "application" ? contracts.application : contracts.client);
|
|
@@ -89,9 +82,6 @@ function collectDataCandidates(contract, resourceName, data, path, candidates) {
|
|
|
89
82
|
}
|
|
90
83
|
function collectCandidates(contract, request, index, args) {
|
|
91
84
|
const candidates = [];
|
|
92
|
-
// The same address the response boundary resolves a thrower-supplied issue
|
|
93
|
-
// path against: one source of truth for where a plan operation's arguments
|
|
94
|
-
// live in a path.
|
|
95
85
|
const root = planOperationArgumentsPath(index);
|
|
96
86
|
if (request.family === "create") {
|
|
97
87
|
const data = lookupOwn(args, "data");
|
|
@@ -116,14 +106,6 @@ function collectCandidates(contract, request, index, args) {
|
|
|
116
106
|
}
|
|
117
107
|
return candidates;
|
|
118
108
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Every relation field an operation's arguments traverse — in projections,
|
|
121
|
-
* filters, orderings and nested writes alike — with the Resource each one
|
|
122
|
-
* reaches. A key that names a relation of the Resource in hand switches to its
|
|
123
|
-
* target; a key that names a scalar is a value and is not entered; any other key
|
|
124
|
-
* (an argument keyword, a logical or relation operator, a directive) keeps the
|
|
125
|
-
* Resource in hand. A string entry of an array is a bare projection entry.
|
|
126
|
-
*/
|
|
127
109
|
function* relationTraversals(contract, resourceName, value, path) {
|
|
128
110
|
const resource = lookupResource(contract, resourceName);
|
|
129
111
|
if (resource === undefined) {
|
|
@@ -157,7 +139,6 @@ function* relationTraversals(contract, resourceName, value, path) {
|
|
|
157
139
|
}
|
|
158
140
|
}
|
|
159
141
|
}
|
|
160
|
-
/** Every relation the operation's arguments traverse, from each argument's root. */
|
|
161
142
|
function* operationTraversals(contract, request, index) {
|
|
162
143
|
if (!isObject(request.arguments)) {
|
|
163
144
|
return;
|
|
@@ -170,10 +151,6 @@ function* operationTraversals(contract, request, index) {
|
|
|
170
151
|
]);
|
|
171
152
|
}
|
|
172
153
|
}
|
|
173
|
-
/**
|
|
174
|
-
* The Resources whose rows the operation deletes directly: its own Resource for
|
|
175
|
-
* the `delete` family, and the target of every nested `$delete`.
|
|
176
|
-
*/
|
|
177
154
|
function deletedResources(contract, request, index) {
|
|
178
155
|
const deleted = request.family === "delete" ? [request.resource] : [];
|
|
179
156
|
for (const traversal of operationTraversals(contract, request, index)) {
|
|
@@ -184,14 +161,6 @@ function deletedResources(contract, request, index) {
|
|
|
184
161
|
}
|
|
185
162
|
return deleted;
|
|
186
163
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Where an operation depends on rows of a Resource an earlier step's cascade
|
|
189
|
-
* removed, or `undefined`. Every operation but a `create` addresses existing rows
|
|
190
|
-
* of its own Resource, so its own Resource is checked first, at the wire
|
|
191
|
-
* location that names it; then every relation its arguments traverse, at that
|
|
192
|
-
* relation's own wire location. A `create` adds rows and depends on none of its
|
|
193
|
-
* own Resource's, so only its arguments' relations are checked.
|
|
194
|
-
*/
|
|
195
164
|
function cascadeDependency(contract, request, index, cascaded) {
|
|
196
165
|
if (cascaded.size === 0) {
|
|
197
166
|
return undefined;
|
|
@@ -206,12 +175,6 @@ function cascadeDependency(contract, request, index, cascaded) {
|
|
|
206
175
|
}
|
|
207
176
|
return undefined;
|
|
208
177
|
}
|
|
209
|
-
/**
|
|
210
|
-
* The refusal of a plan on a Contract without transaction plans (`A2002`, one
|
|
211
|
-
* `V1006` at `["operations"]`). The one spelling — the protocol's absence
|
|
212
|
-
* answer for `/_transactions` (`@aventara/core/protocol`, Q2's O3) is this
|
|
213
|
-
* envelope too.
|
|
214
|
-
*/
|
|
215
178
|
export function transactionsUnavailableFailure() {
|
|
216
179
|
const message = "Transaction plans are not available on the active Contract.";
|
|
217
180
|
return operationFailure("A2002", {
|
|
@@ -219,23 +182,6 @@ export function transactionsUnavailableFailure() {
|
|
|
219
182
|
issues: [validationIssue("V1006", ["operations"], message)],
|
|
220
183
|
});
|
|
221
184
|
}
|
|
222
|
-
/**
|
|
223
|
-
* Whole-plan Framework Validation Layer for transaction structure and identity.
|
|
224
|
-
*
|
|
225
|
-
* `origins` states each operation's origin by index, for a plan whose steps do
|
|
226
|
-
* not all share the request's (the typed runner's mixed plans). Absent — the
|
|
227
|
-
* untyped seam — every operation takes the request's own origin. Each operation
|
|
228
|
-
* is validated against its own origin's Contract.
|
|
229
|
-
*
|
|
230
|
-
* A plan is also refused when a step depends on rows an earlier step's cascade
|
|
231
|
-
* removed (`V1019`, plan-scoped: a lone operation that cascades is not a
|
|
232
|
-
* defect, since nothing follows it). The analysis runs over every step whatever
|
|
233
|
-
* its origin — one plan runs in one Adapter transaction, so a client step's
|
|
234
|
-
* read sees an application step's cascade — and reads each step against its own
|
|
235
|
-
* origin's Contract. It is a planning answer, given before any provider statement
|
|
236
|
-
* is issued, and as conservative as the facts it has: a plan cannot know which
|
|
237
|
-
* rows a delete will match, so it refuses at the granularity of a Resource.
|
|
238
|
-
*/
|
|
239
185
|
export async function validateTransactionPlan(dependencies, request, origins) {
|
|
240
186
|
const protocolFailure = validateProtocolIdentity(dependencies.contracts, request);
|
|
241
187
|
if (protocolFailure !== undefined) {
|
|
@@ -284,7 +230,6 @@ export async function validateTransactionPlan(dependencies, request, origins) {
|
|
|
284
230
|
};
|
|
285
231
|
}
|
|
286
232
|
const validated = [];
|
|
287
|
-
// The Resources whose rows the cascades of steps validated so far may remove.
|
|
288
233
|
const cascaded = new Set();
|
|
289
234
|
for (let index = 0; index < operationCount; index += 1) {
|
|
290
235
|
const operationEntry = inspectTransactionOperationEntry(operations, index);
|
|
@@ -389,17 +334,9 @@ export async function validateTransactionPlan(dependencies, request, origins) {
|
|
|
389
334
|
});
|
|
390
335
|
}
|
|
391
336
|
catch (error) {
|
|
392
|
-
// D-722: only the canonicalizer's rejection of a caller-supplied value
|
|
393
|
-
// is caller-attributable. Encoder, digest, and every other failure is
|
|
394
|
-
// framework-owned and reaches the totality guard (A3000 + diagnostics).
|
|
395
337
|
if (!(error instanceof CanonicalJsonError)) {
|
|
396
338
|
throw error;
|
|
397
339
|
}
|
|
398
|
-
// The standalone argument spelling, not planOperationArgumentsPath(index):
|
|
399
|
-
// the issue is already attributed by cause.operation, and the shorter
|
|
400
|
-
// path is pinned by "maps remaining non-canonical fingerprint input to
|
|
401
|
-
// D-722". Register row F-722 owns whether it should become the in-plan
|
|
402
|
-
// spelling; changing it here would change a caller-visible path.
|
|
403
340
|
return {
|
|
404
341
|
ok: false,
|
|
405
342
|
response: structuralFailure(validationIssue("V1001", OPERATION_ARGUMENTS_PATH, "Invalid runtime/wire type."), index),
|
|
@@ -9,19 +9,18 @@ export type ResolvedTransactionArguments = {
|
|
|
9
9
|
readonly issues: readonly ValidationIssue[];
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
|
-
* Substitutes every validated `$ref` placeholder of one operation from the
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* operation mutating its arguments cannot alter the source's committed result.
|
|
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.
|
|
23
22
|
*
|
|
24
|
-
* Reading final data runs developer-produced accessors; a throw from here is
|
|
25
|
-
*
|
|
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.
|
|
26
25
|
*/
|
|
27
26
|
export declare function resolveTransactionReferences(operation: ValidatedTransactionOperation, results: readonly unknown[]): ResolvedTransactionArguments;
|
|
@@ -4,22 +4,6 @@ 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
|
-
/**
|
|
8
|
-
* Substitutes every validated `$ref` placeholder of one operation from the
|
|
9
|
-
* results ledger: each earlier operation's final `data`, exactly the value at
|
|
10
|
-
* its index in the `A1009` results array (DA-8, D-708). Validation already proved index, source
|
|
11
|
-
* fingerprint, projected path and type, and none of that is re-run here
|
|
12
|
-
* (C-756); only what can change at runtime is checked. A `null` or non-record
|
|
13
|
-
* source, or a source lacking the referenced own key, resolves to no value
|
|
14
|
-
* (`V1018`, DA-2, DA-4) at the full reference path. The result is a fresh
|
|
15
|
-
* argument graph: only the ancestors of substituted slots are cloned, so the
|
|
16
|
-
* validated plan is never mutated, and every substituted value is a
|
|
17
|
-
* framework-owned copy of the source's value (DA-25), so a dependent
|
|
18
|
-
* operation mutating its arguments cannot alter the source's committed result.
|
|
19
|
-
*
|
|
20
|
-
* Reading final data runs developer-produced accessors; a throw from here is
|
|
21
|
-
* the framework's own per-operation failure (DA-23), classified by the caller.
|
|
22
|
-
*/
|
|
23
7
|
export function resolveTransactionReferences(operation, results) {
|
|
24
8
|
const substitutions = [];
|
|
25
9
|
for (const slot of operation.references) {
|
|
@@ -10,11 +10,6 @@ function failure(rejection, operation) {
|
|
|
10
10
|
response: transactionOperationFailure(mapValidationOutcome([rejection]), operation),
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
14
|
-
* Inspects one control record. A non-record value, arrays included, is
|
|
15
|
-
* classified by the caller's `nonRecordIssue`; reflection failures are
|
|
16
|
-
* contained as `V1001` at the record path.
|
|
17
|
-
*/
|
|
18
13
|
function inspectControlObject(value, allowed, path, nonRecordIssue) {
|
|
19
14
|
if (typeof value !== "object" || value === null) {
|
|
20
15
|
return { ok: false, issue: nonRecordIssue };
|
|
@@ -168,7 +163,6 @@ function sameType(source, destination) {
|
|
|
168
163
|
}
|
|
169
164
|
const CANDIDATE_KEYS = new Set(["$ref"]);
|
|
170
165
|
const REFERENCE_KEYS = new Set(["operation", "fingerprint", "path"]);
|
|
171
|
-
/** Validates every passive reference candidate before operation fingerprinting. */
|
|
172
166
|
export function validateTransactionReferences(operation, earlier) {
|
|
173
167
|
const references = [];
|
|
174
168
|
for (const slot of operation.candidates) {
|
|
@@ -236,8 +230,6 @@ export function validateTransactionReferences(operation, earlier) {
|
|
|
236
230
|
if (projection === undefined || !projection.requested.includes(segment)) {
|
|
237
231
|
return failure(validationIssue("V1010", pathPath, "Transaction reference path is not present in the source projection."), operation.index);
|
|
238
232
|
}
|
|
239
|
-
// The source's own Contract: in a plan that mixes origins, a source field the
|
|
240
|
-
// referencing step's layer hides is still the source's to read.
|
|
241
233
|
const sourceField = lookupField(lookupResource(source.contract, projection.resource), segment);
|
|
242
234
|
if (sourceField === undefined) {
|
|
243
235
|
return failure(validationIssue("V1010", pathPath, "Transaction reference path is not present in the source projection."), operation.index);
|
|
@@ -29,79 +29,55 @@ export type TransactionReferenceCandidateRoute = {
|
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
31
31
|
* Total descriptor-only routing for a scalar value at a transaction-reference
|
|
32
|
-
* position.
|
|
33
|
-
* full wire path instead of losing them to ordinary scalar validation.
|
|
32
|
+
* position.
|
|
34
33
|
*/
|
|
35
34
|
export declare function routeTransactionReferenceCandidate(value: unknown): TransactionReferenceCandidateRoute;
|
|
36
|
-
/** Broad routing guard only; validation of `$ref` members belongs to Task 7. */
|
|
37
35
|
export declare function isTransactionReferenceCandidate(value: unknown): value is TransactionReferenceCandidate;
|
|
38
36
|
/**
|
|
39
|
-
* Narrows a structurally complete `$ref` object.
|
|
40
|
-
* (index ordering, source fingerprint, path existence, and type) stays in
|
|
41
|
-
* the transaction reference validator.
|
|
37
|
+
* Narrows a structurally complete `$ref` object.
|
|
42
38
|
*/
|
|
43
39
|
export declare function isTransactionReferenceObject(value: unknown): value is TransactionReference;
|
|
44
40
|
/**
|
|
45
|
-
* A scalar mutation value inside a plan: the value itself, or a reference to
|
|
46
|
-
*
|
|
41
|
+
* A scalar mutation value inside a plan: the value itself, or a reference to an
|
|
42
|
+
* earlier operation's field of that same type.
|
|
47
43
|
*/
|
|
48
44
|
export type TransactionScalarValue<Value> = Value | TransactionReference<Value>;
|
|
49
45
|
/**
|
|
50
|
-
*
|
|
51
|
-
* value the caller writes, `ReferenceForms` for the value a `$ref` carries. A
|
|
52
|
-
* reference carries its source's final data, which every scope returns in the
|
|
46
|
+
* A reference carries its source's final data, which every scope returns in the
|
|
53
47
|
* application forms; so a client-origin builder writes wire forms and still takes
|
|
54
|
-
* a `$ref` typed by the application form of the same Contract field — strict
|
|
55
|
-
*
|
|
56
|
-
*
|
|
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}.
|
|
57
51
|
*/
|
|
58
52
|
type ReferenceableValue<Value, ReferenceValue> = Value | TransactionReference<ReferenceValue>;
|
|
59
|
-
/**
|
|
60
|
-
* `Data`'s member `Key`, or `never` when it has none: the reference half of a
|
|
61
|
-
* DA-3 position reads the same key under the reference forms, where an
|
|
62
|
-
* intersection index (`Data[Key & keyof Data]`) would make the generic
|
|
63
|
-
* declaration below relate two deferred `keyof`s of the whole data type — the
|
|
64
|
-
* same answer, measured at ≈47,000 instantiations of `packages/core`'s own check.
|
|
65
|
-
*/
|
|
66
53
|
type MemberOf<Data, Key> = Key extends keyof Data ? Data[Key] : never;
|
|
67
54
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* with neither form stated; the typed builders state both.
|
|
55
|
+
* The exported {@link TransactionCreateDataInput} is it with neither form stated;
|
|
56
|
+
* the typed builders state both.
|
|
71
57
|
*/
|
|
72
58
|
export type ReferenceableCreateData<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope, Forms extends ScalarForms, ReferenceForms extends ScalarForms> = Readonly<{
|
|
73
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>>;
|
|
74
60
|
}>;
|
|
75
|
-
/** `UpdateDataInput` with DA-3 reference positions opened; see {@link ReferenceableCreateData}. */
|
|
76
61
|
export type ReferenceableUpdateData<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope, Forms extends ScalarForms, ReferenceForms extends ScalarForms> = Readonly<{
|
|
77
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>>;
|
|
78
63
|
}>;
|
|
79
64
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* keeps its relation mutation action, where a `$ref` is an ordinary invalid
|
|
83
|
-
* value.
|
|
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.
|
|
84
67
|
*
|
|
85
|
-
* The position is the standalone surface's, read the same way: both surfaces
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* `CreateDataInput`.
|
|
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`.
|
|
90
72
|
*/
|
|
91
73
|
export type TransactionCreateDataInput<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope = "nested"> = ReferenceableCreateData<C, K, Scope, ScalarForms, ScalarForms>;
|
|
92
74
|
/**
|
|
93
|
-
*
|
|
94
|
-
* write position. See {@link TransactionCreateDataInput}.
|
|
75
|
+
* See {@link TransactionCreateDataInput}.
|
|
95
76
|
*/
|
|
96
77
|
export type TransactionUpdateDataInput<C extends Contract, K extends ResourceKey<C>, Scope extends WriteScope = "nested"> = ReferenceableUpdateData<C, K, Scope, ScalarForms, ScalarForms>;
|
|
97
78
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* mutation-data positions, and bound at the same write position per variant as
|
|
101
|
-
* `OperationArgumentMap` — the four flat bulk writes (`create.many`,
|
|
102
|
-
* `create.count`, `update.many`, `update.count`) in `"bulkWrite"`, every other
|
|
103
|
-
* data argument in `"nested"`. The typed builders read it with both forms stated;
|
|
104
|
-
* the exported {@link TransactionOperationArgumentsFor} is it with neither.
|
|
79
|
+
* The typed builders read it with both forms stated; the exported {@link
|
|
80
|
+
* TransactionOperationArgumentsFor} is it with neither.
|
|
105
81
|
*/
|
|
106
82
|
export type ReferenceableArgumentsFor<C extends Contract, K extends ResourceKey<C>, I extends OperationIdentity, Forms extends ScalarForms, ReferenceForms extends ScalarForms> = I extends {
|
|
107
83
|
family: "create";
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { isOperationFingerprint } from "./operation-fingerprint.js";
|
|
2
2
|
const ORDINARY_ROUTE = { kind: "ordinary" };
|
|
3
|
-
/**
|
|
4
|
-
* Total descriptor-only routing for a scalar value at a transaction-reference
|
|
5
|
-
* position. Reflection failures stay candidates so Task 7 can report their
|
|
6
|
-
* full wire path instead of losing them to ordinary scalar validation.
|
|
7
|
-
*/
|
|
8
3
|
export function routeTransactionReferenceCandidate(value) {
|
|
9
4
|
if (value === null || typeof value !== "object") {
|
|
10
5
|
return ORDINARY_ROUTE;
|
|
@@ -30,15 +25,9 @@ export function routeTransactionReferenceCandidate(value) {
|
|
|
30
25
|
return { kind: "reflection-failure", candidate: value };
|
|
31
26
|
}
|
|
32
27
|
}
|
|
33
|
-
/** Broad routing guard only; validation of `$ref` members belongs to Task 7. */
|
|
34
28
|
export function isTransactionReferenceCandidate(value) {
|
|
35
29
|
return routeTransactionReferenceCandidate(value).kind === "candidate";
|
|
36
30
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Narrows a structurally complete `$ref` object. DA-15 semantic validation
|
|
39
|
-
* (index ordering, source fingerprint, path existence, and type) stays in
|
|
40
|
-
* the transaction reference validator.
|
|
41
|
-
*/
|
|
42
31
|
export function isTransactionReferenceObject(value) {
|
|
43
32
|
const route = routeTransactionReferenceCandidate(value);
|
|
44
33
|
if (route.kind !== "candidate" ||
|
|
@@ -16,11 +16,10 @@ export type ClientTransactionRequest = TransactionRequestBase & {
|
|
|
16
16
|
};
|
|
17
17
|
export type FrameworkTransactionRequest = ApplicationTransactionRequest | ClientTransactionRequest;
|
|
18
18
|
/**
|
|
19
|
-
* The origin one plan operation runs under
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* request; the typed runner states one per handle.
|
|
19
|
+
* The origin one plan operation runs under: its own layer's Contract, its own
|
|
20
|
+
* 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.
|
|
24
23
|
*
|
|
25
24
|
* Internal to the transaction runtime, and deliberately not a member of the
|
|
26
25
|
* request: the public seam's request cannot smuggle a per-operation origin.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OperationFailureResponse } from "../runtime/operation-response.js";
|
|
2
2
|
/**
|
|
3
|
-
* A committed plan
|
|
3
|
+
* A committed plan: each operation's final `data`, in plan order.
|
|
4
4
|
*
|
|
5
5
|
* `T` mirrors `OperationResponse<T>`: the untyped seam (`executeTransaction`)
|
|
6
6
|
* answers the default `readonly unknown[]`, and the typed runner
|
|
@@ -14,8 +14,7 @@ import type { TransactionResponse } from "./transaction-response.js";
|
|
|
14
14
|
export type FrameworkTransactionExecutor = (request: FrameworkTransactionRequest, diagnostics: TransactionDiagnosticsChannel, origins?: readonly TransactionOperationOrigin[]) => Promise<TransactionResponse>;
|
|
15
15
|
/**
|
|
16
16
|
* Validates a whole plan through the Framework Validation Layer, then runs it
|
|
17
|
-
* inside exactly one Adapter transaction. Guards, pipes, hooks and
|
|
18
|
-
*
|
|
19
|
-
* open (DA-6, §14.5).
|
|
17
|
+
* inside exactly one Adapter transaction. Guards, pipes, hooks and interceptors of
|
|
18
|
+
* every plan operation run while the provider transaction is open.
|
|
20
19
|
*/
|
|
21
20
|
export declare function createTransactionRuntime<M extends AdapterModel>(dependencies: OperationRuntimeDependencies<M>): FrameworkTransactionExecutor;
|
|
@@ -7,26 +7,13 @@ import { TransactionIntegrityError } from "./transaction-integrity-error.js";
|
|
|
7
7
|
import { validateTransactionPlan } from "./transaction-plan-validator.js";
|
|
8
8
|
import { resolveTransactionReferences } from "./transaction-reference-resolver.js";
|
|
9
9
|
import { transactionCommitted, transactionInfrastructureFailure, transactionOperationFailure, } from "./transaction-response.js";
|
|
10
|
-
/**
|
|
11
|
-
* The framework-owned rollback request (D-707). It is thrown out of the
|
|
12
|
-
* Adapter transaction callback only after an operation failure is recorded,
|
|
13
|
-
* and a rejection is recognized as it solely by identity — never by message,
|
|
14
|
-
* shape or class (C-750). It is a control signal, not a failure, so it never
|
|
15
|
-
* reaches diagnostics.
|
|
16
|
-
*/
|
|
17
10
|
const TRANSACTION_ABORT = Object.freeze({ reason: "aventara-transaction-abort" });
|
|
18
|
-
/**
|
|
19
|
-
* Validates a whole plan through the Framework Validation Layer, then runs it
|
|
20
|
-
* inside exactly one Adapter transaction. Guards, pipes, hooks and
|
|
21
|
-
* interceptors of every plan operation run while the provider transaction is
|
|
22
|
-
* open (DA-6, §14.5).
|
|
23
|
-
*/
|
|
24
11
|
export function createTransactionRuntime(dependencies) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
const { adapter, ...runtimeDependencies } = dependencies;
|
|
13
|
+
const pipelineDependencies = {
|
|
14
|
+
...runtimeDependencies,
|
|
15
|
+
createRequirements: adapter.createRequirements ?? {},
|
|
16
|
+
};
|
|
30
17
|
const planDependencies = {
|
|
31
18
|
...pipelineDependencies,
|
|
32
19
|
cascades: resolveCascadeClosure(adapter.referentialActions),
|
|
@@ -39,18 +26,6 @@ export function createTransactionRuntime(dependencies) {
|
|
|
39
26
|
return executeTransactionPlan(adapter, pipelineDependencies, validation.plan, diagnostics);
|
|
40
27
|
};
|
|
41
28
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Runs an accepted plan strictly sequentially inside one Adapter transaction
|
|
44
|
-
* callback and maps how that transaction settled:
|
|
45
|
-
*
|
|
46
|
-
* - resolved with every operation completed → `A1009` with the ledger;
|
|
47
|
-
* - rejected with the abort sentinel after a recorded failure → that
|
|
48
|
-
* operation's own outcome with `cause.operation`, including an unexpected
|
|
49
|
-
* throw from the framework's own per-operation work (`A3000`, DA-23);
|
|
50
|
-
* - any other rejection → `A3002` and a diagnostic;
|
|
51
|
-
* - a transaction that breaks the Adapter contract (DA-24) → `A3002` and a
|
|
52
|
-
* {@link TransactionIntegrityError} diagnostic, never the sentinel.
|
|
53
|
-
*/
|
|
54
29
|
async function executeTransactionPlan(adapter, dependencies, plan, diagnostics) {
|
|
55
30
|
const ledger = { results: [], failure: undefined };
|
|
56
31
|
const infrastructureFailure = (error) => {
|
|
@@ -58,23 +33,9 @@ async function executeTransactionPlan(adapter, dependencies, plan, diagnostics)
|
|
|
58
33
|
diagnostics.transaction(operation)(error, "A3002");
|
|
59
34
|
return transactionInfrastructureFailure(operation);
|
|
60
35
|
};
|
|
61
|
-
// Unreachable by construction (D-712): a declared "interactive" capability
|
|
62
|
-
// without a transaction function fails createFramework. Kept because the
|
|
63
|
-
// Adapter object stays reachable and mutable after construction.
|
|
64
36
|
if (typeof adapter.transaction !== "function") {
|
|
65
37
|
return infrastructureFailure(new TransactionIntegrityError("transaction-unavailable"));
|
|
66
38
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Everything the framework does for one plan operation inside the
|
|
69
|
-
* callback: reference resolution, which reads the source's final data and
|
|
70
|
-
* writes the substituted slots, then the operation's own pipeline. The
|
|
71
|
-
* pipeline's result is the operation's outcome; anything the framework's
|
|
72
|
-
* own work throws is that operation's `A3000` failure, reported with its
|
|
73
|
-
* identity and index (DA-23). The boundary is structural — it encloses
|
|
74
|
-
* only this work, never the Adapter transaction call — and the rollback
|
|
75
|
-
* request is thrown by the caller after it returns, so the sentinel never
|
|
76
|
-
* crosses it.
|
|
77
|
-
*/
|
|
78
39
|
const runPlanOperation = async (operation, executor) => {
|
|
79
40
|
const report = diagnostics.operation(operation.request, operation.index);
|
|
80
41
|
try {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The ways a transaction slot path can fail to name a member of the argument
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* outcome from error text).
|
|
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.
|
|
8
7
|
*
|
|
9
8
|
* - `slot-prefix`: the path does not begin `["operations", <this operation>,
|
|
10
9
|
* "args", <member>]`, or the view itself is not an object.
|
|
@@ -13,11 +12,11 @@
|
|
|
13
12
|
*/
|
|
14
13
|
export type TransactionSlotPathViolation = "slot-prefix" | "absent-member" | "non-object-ancestor";
|
|
15
14
|
/**
|
|
16
|
-
* The framework-owned failure thrown when a slot path does not name a member
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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.
|
|
21
20
|
*/
|
|
22
21
|
export declare class TransactionSlotPathError extends Error {
|
|
23
22
|
readonly violation: TransactionSlotPathViolation;
|
|
@@ -3,13 +3,6 @@ const TRANSACTION_SLOT_PATH_MESSAGES = {
|
|
|
3
3
|
"absent-member": "Transaction slot path names an absent member of the operation arguments.",
|
|
4
4
|
"non-object-ancestor": "Transaction slot path descends through a non-object value.",
|
|
5
5
|
};
|
|
6
|
-
/**
|
|
7
|
-
* The framework-owned failure thrown when a slot path does not name a member
|
|
8
|
-
* of the argument view. It never reaches the wire: inside a plan's
|
|
9
|
-
* transaction callback it becomes that operation's `A3000` (DA-23), during
|
|
10
|
-
* validation the totality guard's `A3000`. It reaches a diagnostics sink as
|
|
11
|
-
* the raw `error`, where the violation discriminates the three defects.
|
|
12
|
-
*/
|
|
13
6
|
export class TransactionSlotPathError extends Error {
|
|
14
7
|
violation;
|
|
15
8
|
constructor(violation) {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The one owner of writing a value at a transaction slot path. Validation
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* The one owner of writing a value at a transaction slot path. Validation installs
|
|
3
|
+
* framework-owned `$ref` control snapshots through it and execution installs
|
|
4
|
+
* resolved final data through it, so both argument views are produced by the same
|
|
5
|
+
* ancestor-cloning walker.
|
|
6
6
|
*
|
|
7
7
|
* Slot paths are collected once, from the validated semantic argument view.
|
|
8
|
-
* Validation then writes them into two views: that semantic view, where the
|
|
9
|
-
*
|
|
10
|
-
* (`operation.request.arguments`), where the same path is asserted rather
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
8
|
+
* Validation then writes them into two views: that semantic view, where the path
|
|
9
|
+
* is known to name a member, and the raw wire view
|
|
10
|
+
* (`operation.request.arguments`), where the same path is asserted rather than
|
|
11
|
+
* established. It holds there because a slot names a scalar leaf key inside
|
|
12
|
+
* top-level mutation data and Framework Validation Layer normalization preserves
|
|
13
|
+
* that `data`-leaf key structure. A path that does not name a member of the view
|
|
14
|
+
* being written is therefore a framework defect either way, and fails loudly
|
|
15
|
+
* rather than being skipped.
|
|
16
16
|
*/
|
|
17
17
|
type Path = readonly (string | number)[];
|
|
18
18
|
/** One value to install at a full transaction slot path. */
|
|
@@ -1,34 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The one owner of writing a value at a transaction slot path. Validation
|
|
3
|
-
* installs framework-owned `$ref` control snapshots through it (DA-20) and
|
|
4
|
-
* execution installs resolved final data through it (DA-8), so both argument
|
|
5
|
-
* views are produced by the same ancestor-cloning walker.
|
|
6
|
-
*
|
|
7
|
-
* Slot paths are collected once, from the validated semantic argument view.
|
|
8
|
-
* Validation then writes them into two views: that semantic view, where the
|
|
9
|
-
* path is known to name a member, and the raw wire view
|
|
10
|
-
* (`operation.request.arguments`), where the same path is asserted rather
|
|
11
|
-
* than established. It holds there because a slot names a scalar leaf key
|
|
12
|
-
* inside top-level mutation data (DA-3) and Framework Validation Layer
|
|
13
|
-
* normalization preserves that `data`-leaf key structure. A path that does
|
|
14
|
-
* not name a member of the view being written is therefore a framework
|
|
15
|
-
* defect either way, and fails loudly rather than being skipped.
|
|
16
|
-
*/
|
|
17
1
|
import { TransactionSlotPathError } from "./transaction-slot-path-error.js";
|
|
18
|
-
/**
|
|
19
|
-
* A path that does not name a member of the view being written is a framework
|
|
20
|
-
* defect, for either view (see the module note).
|
|
21
|
-
* Skipping it would leave the original value in place — at execution a `$ref`
|
|
22
|
-
* placeholder handed to guards, pipes and the Adapter — so it fails loudly
|
|
23
|
-
* instead: inside a plan's transaction callback that is the operation's own
|
|
24
|
-
* `A3000` failure (DA-23), during validation the totality guard's `A3000`.
|
|
25
|
-
* The violation discriminates the defect for whoever catches it, so no caller
|
|
26
|
-
* has to read message text.
|
|
27
|
-
*/
|
|
28
2
|
function slotPathMismatch(violation) {
|
|
29
3
|
throw new TransactionSlotPathError(violation);
|
|
30
4
|
}
|
|
31
|
-
/** Clones one container, copying sibling descriptors verbatim and replacing one property. */
|
|
32
5
|
function cloneContainerWithReplacement(container, property, replacement) {
|
|
33
6
|
const array = Array.isArray(container);
|
|
34
7
|
const prototype = Object.getPrototypeOf(container);
|
|
@@ -63,7 +36,6 @@ function cloneContainerWithReplacement(container, property, replacement) {
|
|
|
63
36
|
}
|
|
64
37
|
return clone;
|
|
65
38
|
}
|
|
66
|
-
/** Replaces the value below one container member, cloning only that container. */
|
|
67
39
|
function replaceValueInContainer(container, property, tail, replacement) {
|
|
68
40
|
const descriptor = Object.getOwnPropertyDescriptor(container, property);
|
|
69
41
|
if (descriptor === undefined) {
|
|
@@ -82,12 +54,6 @@ function replaceValueAtPath(value, path, replacement) {
|
|
|
82
54
|
}
|
|
83
55
|
return replaceValueInContainer(value, String(head), tail, replacement);
|
|
84
56
|
}
|
|
85
|
-
/**
|
|
86
|
-
* Installs values at transaction slot paths into one argument view: validated
|
|
87
|
-
* control snapshots at validation, resolved final data at execution. A slot
|
|
88
|
-
* path always names a member below `args`, so the view keeps its own
|
|
89
|
-
* container kind and prototype; only the ancestors of each slot are cloned.
|
|
90
|
-
*/
|
|
91
57
|
export function replaceTransactionSlotValues(value, operation, slots) {
|
|
92
58
|
let materialized = value;
|
|
93
59
|
for (const slot of slots) {
|