@aventara/core 1.0.0-rc.1 → 1.0.0-rc.3
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/CHANGELOG.md +341 -1
- package/ERRORS.md +142 -0
- package/README.md +24 -1
- package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
- package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
- package/dist/adapters/adapter-field.d.ts +14 -0
- package/dist/adapters/adapter-model.d.ts +9 -0
- package/dist/adapters/adapter.interface.d.ts +10 -0
- package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
- package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
- package/dist/compiler/contract.compiler.js +94 -6
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +80 -0
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/define-resource.d.ts +1 -1
- package/dist/config/exact-framework-config.d.ts +50 -20
- package/dist/config/field-compute.resolver.d.ts +2 -0
- package/dist/config/field-compute.resolver.js +8 -0
- package/dist/config/framework-config.d.ts +7 -6
- package/dist/config/framework-resources-config.d.ts +18 -12
- package/dist/config/pipeline-config.d.ts +4 -4
- package/dist/contracts/capability.d.ts +10 -1
- package/dist/contracts/capability.js +2 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +65 -35
- package/dist/contracts/client-contract-structure.validator.js +4 -2
- package/dist/contracts/contract-canonicalizer.d.ts +7 -0
- package/dist/contracts/contract-canonicalizer.js +18 -4
- package/dist/contracts/field.d.ts +30 -1
- package/dist/framework/contract-view.d.ts +4 -4
- package/dist/framework/framework-construction.error.d.ts +12 -3
- package/dist/framework/framework-construction.error.js +5 -1
- package/dist/framework/framework.factory.d.ts +1 -1
- package/dist/framework/framework.factory.js +9 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/internal.d.ts +2 -0
- package/dist/internal.js +1 -0
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +102 -31
- package/dist/operations/operation-validator-core.js +145 -36
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/write-scope.resolver.d.ts +4 -0
- package/dist/operations/write-scope.resolver.js +2 -0
- package/dist/protocol/protocol.handler.js +55 -16
- package/dist/runtime/caller-data.copier.d.ts +17 -0
- package/dist/runtime/caller-data.copier.js +18 -1
- package/dist/runtime/caller-data.door.d.ts +11 -5
- package/dist/runtime/computed-read-runtime.js +15 -2
- package/dist/runtime/computed-value.error.d.ts +3 -2
- package/dist/runtime/computed-value.error.js +3 -2
- package/dist/runtime/create-requirement.d.ts +41 -5
- package/dist/runtime/create-requirement.js +137 -20
- package/dist/runtime/diagnostics-reporter.d.ts +2 -1
- package/dist/runtime/error-boundary.js +4 -0
- package/dist/runtime/error-guidance.d.ts +12 -0
- package/dist/runtime/error-guidance.js +1 -0
- package/dist/runtime/error.catalog.d.ts +49 -0
- package/dist/runtime/error.catalog.js +49 -0
- package/dist/runtime/field-stage.runtime.d.ts +2 -0
- package/dist/runtime/field-stage.runtime.js +8 -4
- package/dist/runtime/field-validator.runtime.d.ts +18 -1
- package/dist/runtime/field-validator.runtime.js +47 -8
- package/dist/runtime/json-value.d.ts +10 -5
- package/dist/runtime/level-lifecycle.runtime.d.ts +2 -2
- package/dist/runtime/level-lifecycle.runtime.js +2 -5
- package/dist/runtime/mutation-planner.js +3 -14
- package/dist/runtime/operation-code.guidance.d.ts +6 -0
- package/dist/runtime/operation-code.guidance.js +167 -0
- package/dist/runtime/operation-runtime.d.ts +20 -6
- package/dist/runtime/operation-runtime.js +82 -36
- package/dist/runtime/owned-execution.registry.d.ts +12 -2
- package/dist/runtime/pipe-output.validator.d.ts +10 -0
- package/dist/runtime/pipe-output.validator.js +4 -2
- package/dist/runtime/pipeline.d.ts +35 -8
- package/dist/runtime/readonly-value.d.ts +14 -3
- package/dist/runtime/readonly-value.js +10 -1
- package/dist/runtime/scalar-runtime.d.ts +5 -1
- package/dist/runtime/scalar-runtime.js +86 -16
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +8 -0
- package/dist/transactions/sql-statement.validator.js +36 -3
- package/dist/transactions/transaction-plan-assembler.d.ts +1 -1
- package/dist/transactions/transaction-plan-assembler.js +33 -10
- package/dist/transactions/transaction-plan-validator.d.ts +16 -0
- package/dist/transactions/transaction-plan-validator.js +27 -1
- package/dist/transactions/transaction-reference-validator.d.ts +42 -0
- package/dist/transactions/transaction-reference-validator.js +82 -56
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-runtime.js +47 -22
- package/dist/transactions/transaction-stage.runtime.d.ts +2 -1
- package/dist/transactions/transaction-stage.runtime.js +7 -4
- package/package.json +4 -3
|
@@ -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;
|
|
@@ -39,6 +41,46 @@ export type ReferenceSourceRead = {
|
|
|
39
41
|
* the source's to read. Assignability to a destination is the caller's.
|
|
40
42
|
*/
|
|
41
43
|
export declare function referenceSourceField(source: ValidatedTransactionStep, segment: string, pathPath: Path): ReferenceSourceRead;
|
|
44
|
+
/** A `$ref` control object read through: its source step, field and fingerprint. */
|
|
45
|
+
export type ReferenceCandidateInspection = {
|
|
46
|
+
readonly ok: true;
|
|
47
|
+
readonly source: Extract<ValidatedTransactionStep, {
|
|
48
|
+
kind: "operation";
|
|
49
|
+
}>;
|
|
50
|
+
readonly segment: string;
|
|
51
|
+
readonly fingerprint: OperationFingerprint;
|
|
52
|
+
readonly field: AvField<AvContract>;
|
|
53
|
+
/** The candidate's `path` member's own path, where a type refusal stands. */
|
|
54
|
+
readonly pathPath: Path;
|
|
55
|
+
} | {
|
|
56
|
+
readonly ok: false;
|
|
57
|
+
readonly issue: AvValidationIssue;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Inspects one `$ref` control object standing at `slotPath` of step
|
|
61
|
+
* `referencingIndex`, through property descriptors only: its shape, its source
|
|
62
|
+
* step (an earlier one, never a SQL step), the source's fingerprint and the one
|
|
63
|
+
* field its path reads from the source's projection. Assignability to the
|
|
64
|
+
* destination is the caller's. Shared by an operation step's slots and an
|
|
65
|
+
* `appTx.$sql` value, so both refuse a malformed reference alike.
|
|
66
|
+
*/
|
|
67
|
+
export declare function inspectReferenceCandidate(candidate: unknown, slotPath: Path, earlier: readonly ValidatedTransactionStep[], referencingIndex: number): ReferenceCandidateInspection;
|
|
68
|
+
/** The validated slots of a step's candidates, or the first one's refusal. */
|
|
69
|
+
export type ReferenceSlotsValidation = {
|
|
70
|
+
readonly ok: true;
|
|
71
|
+
readonly references: readonly TransactionReferenceSlot[];
|
|
72
|
+
} | {
|
|
73
|
+
readonly ok: false;
|
|
74
|
+
readonly issue: AvValidationIssue;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Judges every `$ref` candidate of step `index` by the Framework Validation
|
|
78
|
+
* Layer's reference rules — its shape, an earlier non-SQL source step, that
|
|
79
|
+
* step's fingerprint, a field of its single-row projection, and type
|
|
80
|
+
* compatibility with the slot it stands in — and answers the validated slots,
|
|
81
|
+
* or the first refusal.
|
|
82
|
+
*/
|
|
83
|
+
export declare function validateReferenceSlots(candidates: readonly TransactionReferenceCandidateSlot[], earlier: readonly ValidatedTransactionStep[], index: number): ReferenceSlotsValidation;
|
|
42
84
|
/** Validates every passive reference candidate before operation fingerprinting. */
|
|
43
85
|
export declare function validateTransactionReferences(operation: CandidateTransactionOperation, earlier: readonly ValidatedTransactionStep[]): ReferenceValidationResult;
|
|
44
86
|
export {};
|
|
@@ -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
|
|
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
|
|
218
|
-
const
|
|
219
|
-
if (!
|
|
220
|
-
return
|
|
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
|
|
223
|
-
const
|
|
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
|
|
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,
|
|
@@ -14,6 +14,11 @@ export function routeTransactionReferenceCandidate(value) {
|
|
|
14
14
|
if (!ownKeys.includes("$ref") || referenceDescriptor === undefined) {
|
|
15
15
|
return ORDINARY_ROUTE;
|
|
16
16
|
}
|
|
17
|
+
if ("value" in referenceDescriptor &&
|
|
18
|
+
(referenceDescriptor.value === null ||
|
|
19
|
+
typeof referenceDescriptor.value !== "object")) {
|
|
20
|
+
return ORDINARY_ROUTE;
|
|
21
|
+
}
|
|
17
22
|
return {
|
|
18
23
|
kind: "candidate",
|
|
19
24
|
candidate: value,
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { transactionLevelsOf } from "../config/pipeline-tree.resolver.js";
|
|
2
2
|
import { AdapterBoundary, planOperationArgumentsPath, planStepPath, sanitizeOperationFailure, } from "../runtime/error-boundary.js";
|
|
3
|
-
import { isPlainRecord, valueAt } from "../runtime/field-stage.runtime.js";
|
|
4
3
|
import { internalFailure, operationSuccess, } from "../runtime/operation-response.js";
|
|
5
|
-
import { admitOperation, executeAdmittedOperation, prepareStep, withRequestState, } from "../runtime/operation-runtime.js";
|
|
4
|
+
import { admitOperation, EVERY_FIELD, executeAdmittedOperation, prepareStep, STEP_PIPES, withRequestState, } from "../runtime/operation-runtime.js";
|
|
6
5
|
import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
|
|
6
|
+
import { refusedStageOutput, serverContractFor, } from "../runtime/pipe-output.validator.js";
|
|
7
7
|
import { resolveCascadeClosure } from "../runtime/referential-action.js";
|
|
8
8
|
import { AvTransactionIntegrityError } from "./transaction-integrity-error.js";
|
|
9
9
|
import { validateTransactionPlan } from "./transaction-plan-validator.js";
|
|
10
|
+
import { collectTransactionReferenceCandidates } from "./transaction-reference-collector.js";
|
|
10
11
|
import { resolveSqlStatement, resolveTransactionReferences, } from "./transaction-reference-resolver.js";
|
|
12
|
+
import { validateReferenceSlots } from "./transaction-reference-validator.js";
|
|
11
13
|
import { transactionCommitted, transactionInfrastructureFailure, transactionOperationFailure, } from "./transaction-response.js";
|
|
12
14
|
import { settleTransaction } from "./transaction-settlement.runtime.js";
|
|
13
|
-
import { touchedTransactionLevels, transactionFacts, } from "./transaction-stage.runtime.js";
|
|
15
|
+
import { TRANSACTION_PIPES, touchedTransactionLevels, transactionFacts, } from "./transaction-stage.runtime.js";
|
|
14
16
|
export function createTransactionRuntime(dependencies, pipelineDependencies) {
|
|
15
17
|
const { adapter } = dependencies;
|
|
16
18
|
const planDependencies = {
|
|
@@ -59,39 +61,54 @@ function pathKey(path) {
|
|
|
59
61
|
function relativeSlotPath(operation, path) {
|
|
60
62
|
return path.slice(planOperationArgumentsPath(operation.index).length);
|
|
61
63
|
}
|
|
62
|
-
function
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
function standingReferences(core, operation, args, steps, subject) {
|
|
65
|
+
const candidates = collectTransactionReferenceCandidates(serverContractFor(core, operation.contract), operation.request, operation.index, args);
|
|
66
|
+
const validation = validateReferenceSlots(candidates, steps, operation.index);
|
|
67
|
+
if (validation.ok) {
|
|
68
|
+
return validation;
|
|
66
69
|
}
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
const { issue } = validation;
|
|
71
|
+
const refused = refusedStageOutput(operation.request, [
|
|
72
|
+
{
|
|
73
|
+
...issue,
|
|
74
|
+
path: ["arguments", ...relativeSlotPath(operation, issue.path ?? [])],
|
|
75
|
+
},
|
|
76
|
+
], subject);
|
|
77
|
+
if (refused === undefined) {
|
|
78
|
+
throw new TypeError("A refused reference produced no refusal.");
|
|
70
79
|
}
|
|
71
|
-
|
|
72
|
-
return (reference.operation === expected.operation &&
|
|
73
|
-
reference.path.length === 1 &&
|
|
74
|
-
reference.path[0] === expected.path[0]);
|
|
75
|
-
}
|
|
76
|
-
function slotKeys(operation) {
|
|
77
|
-
return new Set(operation.references.map((slot) => pathKey(relativeSlotPath(operation, slot.path))));
|
|
80
|
+
return { ok: false, ...refused };
|
|
78
81
|
}
|
|
79
82
|
async function executeTransactionPlan(adapter, dependencies, request, plan, state, diagnostics) {
|
|
80
83
|
const stateful = (operation) => ({ ...operation.request, state });
|
|
81
84
|
const admitted = [];
|
|
85
|
+
const standing = [];
|
|
82
86
|
for (const step of plan.operations) {
|
|
83
87
|
if (step.kind === "sql") {
|
|
84
88
|
admitted.push({ ok: true, args: undefined, piped: false });
|
|
89
|
+
standing.push([]);
|
|
85
90
|
continue;
|
|
86
91
|
}
|
|
87
|
-
const
|
|
88
|
-
const admission = await admitOperation(dependencies, stateful(step), step.contract, step.arguments, planOperationArgumentsPath(step.index),
|
|
89
|
-
select:
|
|
92
|
+
const report = diagnostics.operation(step.request, step.index);
|
|
93
|
+
const admission = await admitOperation(dependencies, stateful(step), step.contract, step.arguments, planOperationArgumentsPath(step.index), report, { requestId: request.requestId, transaction: undefined, state }, {
|
|
94
|
+
select: EVERY_FIELD,
|
|
90
95
|
validation: { transactionReferences: true },
|
|
96
|
+
beforeBegin: true,
|
|
91
97
|
});
|
|
92
98
|
if (!admission.ok) {
|
|
93
99
|
return transactionOperationFailure(admission.response, step.index);
|
|
94
100
|
}
|
|
101
|
+
if (!admission.piped) {
|
|
102
|
+
standing.push(step.references);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const references = standingReferences(dependencies.contracts.core, step, admission.args, plan.operations, STEP_PIPES);
|
|
106
|
+
if (!references.ok) {
|
|
107
|
+
report(references.error, "A3004");
|
|
108
|
+
return transactionOperationFailure(references.response, step.index);
|
|
109
|
+
}
|
|
110
|
+
standing.push(references.references);
|
|
111
|
+
}
|
|
95
112
|
admitted.push(admission);
|
|
96
113
|
}
|
|
97
114
|
const origin = planOrigin(request, plan);
|
|
@@ -103,7 +120,15 @@ async function executeTransactionPlan(adapter, dependencies, request, plan, stat
|
|
|
103
120
|
const argumentsPath = planOperationArgumentsPath(operation.index);
|
|
104
121
|
const stepRequest = stateful(operation);
|
|
105
122
|
try {
|
|
106
|
-
|
|
123
|
+
let live = standing[operation.index] ?? operation.references;
|
|
124
|
+
if (transactionPiped) {
|
|
125
|
+
const references = standingReferences(dependencies.contracts.core, operation, args, plan.operations, TRANSACTION_PIPES);
|
|
126
|
+
if (!references.ok) {
|
|
127
|
+
report(references.error, "A3004");
|
|
128
|
+
return references.response;
|
|
129
|
+
}
|
|
130
|
+
live = references.references;
|
|
131
|
+
}
|
|
107
132
|
const resolved = resolveTransactionReferences({
|
|
108
133
|
...operation,
|
|
109
134
|
arguments: args,
|
|
@@ -119,7 +144,7 @@ async function executeTransactionPlan(adapter, dependencies, request, plan, stat
|
|
|
119
144
|
written: (path) => written.has(pathKey(path)),
|
|
120
145
|
transactionPiped,
|
|
121
146
|
pipedAroundReferences: admitted[operation.index]?.piped === true &&
|
|
122
|
-
operation.references.length > 0,
|
|
147
|
+
(live.length > 0 || operation.references.length > 0),
|
|
123
148
|
}, outer);
|
|
124
149
|
if (!prepared.ok) {
|
|
125
150
|
return prepared.response;
|
|
@@ -23,7 +23,8 @@ export type TransactionStepView = AvTransactionStep;
|
|
|
23
23
|
export declare const TRANSACTION_PIPES = "Transaction pipes";
|
|
24
24
|
/**
|
|
25
25
|
* The `$` facts a transaction stage is told: the plan as `$args`, not one
|
|
26
|
-
* operation (`$operation` is absent).
|
|
26
|
+
* operation (`$operation` is absent). Each ctx holds its own frozen copy of the
|
|
27
|
+
* plan, a `Date` or a `Uint8Array` in a step's arguments fresh.
|
|
27
28
|
*/
|
|
28
29
|
export declare function transactionFacts(contract: AvContract, request: Pick<OperationExecutionRequest, "origin" | "requestId" | "transport">, plan: readonly TransactionStepView[]): ContextFacts;
|
|
29
30
|
/** How the transaction stages around a plan's steps ended. */
|
|
@@ -2,7 +2,7 @@ import { AdapterBoundary, resolveOperationFailure, } from "../runtime/error-boun
|
|
|
2
2
|
import { runLevelLifecycle, } from "../runtime/level-lifecycle.runtime.js";
|
|
3
3
|
import { operationFailure } from "../runtime/operation-response.js";
|
|
4
4
|
import { AvPipeOutputError, PIPE_OUTPUT_FAILURE_MESSAGE, } from "../runtime/pipe-output.validator.js";
|
|
5
|
-
import { deepFreeze } from "../runtime/readonly-value.js";
|
|
5
|
+
import { deepFreeze, frozenCopy } from "../runtime/readonly-value.js";
|
|
6
6
|
import { AvTransactionIntegrityError } from "./transaction-integrity-error.js";
|
|
7
7
|
export const TRANSACTION_ABORT = Object.freeze({ reason: "aventara-transaction-abort" });
|
|
8
8
|
export const TRANSACTION_PIPES = "Transaction pipes";
|
|
@@ -10,7 +10,7 @@ export function transactionFacts(contract, request, plan) {
|
|
|
10
10
|
return {
|
|
11
11
|
$contract: contract,
|
|
12
12
|
$origin: request.origin,
|
|
13
|
-
$args: plan,
|
|
13
|
+
$args: frozenCopy(plan),
|
|
14
14
|
$requestId: request.requestId,
|
|
15
15
|
...(request.origin !== "application" && request.transport !== undefined
|
|
16
16
|
? { $transport: request.transport }
|
|
@@ -86,8 +86,11 @@ export async function runTransactionStages(levels, plan, contextOf, runSteps) {
|
|
|
86
86
|
let pipeIndex = 0;
|
|
87
87
|
for (const level of levels) {
|
|
88
88
|
for (const pipe of level.pipes) {
|
|
89
|
-
const
|
|
90
|
-
|
|
89
|
+
const told = frozenCopy(current);
|
|
90
|
+
const returned = await pipe(told, contextOf(current));
|
|
91
|
+
if (returned !== undefined &&
|
|
92
|
+
returned !== told &&
|
|
93
|
+
returned !== current) {
|
|
91
94
|
const accepted = acceptPlan(current, returned, pipeIndex);
|
|
92
95
|
if (typeof accepted === "string") {
|
|
93
96
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aventara/core",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.3",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "Core runtime, contract compiler, and extension APIs for Aventara.",
|
|
6
6
|
"type": "module",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"files": [
|
|
35
35
|
"dist",
|
|
36
36
|
"src/runtime/field-check.evaluator.ts",
|
|
37
|
+
"ERRORS.md",
|
|
37
38
|
"LICENSE-ADDITIONAL-PERMISSION.md",
|
|
38
39
|
"CHANGELOG.md"
|
|
39
40
|
],
|
|
@@ -44,9 +45,9 @@
|
|
|
44
45
|
"access": "public"
|
|
45
46
|
},
|
|
46
47
|
"scripts": {
|
|
47
|
-
"build": "node ../../scripts/build/build-output.cleaner.ts dist && tsc -p tsconfig.json --removeComments --declaration false && tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/build/declaration-comments.sanitizer.ts dist",
|
|
48
|
+
"build": "node ../../scripts/build/build-output.cleaner.ts dist && tsc -p tsconfig.json --removeComments --declaration false && tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/build/declaration-comments.sanitizer.ts dist && node scripts/errors-markdown.generator.ts",
|
|
48
49
|
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
|
|
49
50
|
"test": "vitest run --typecheck --config ../../vitest.config.mts --root .",
|
|
50
|
-
"lint": "biome lint src"
|
|
51
|
+
"lint": "biome lint src scripts"
|
|
51
52
|
}
|
|
52
53
|
}
|