@aventara/core 1.0.0-rc.0 → 1.0.0-rc.1
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 +1140 -0
- package/README.md +224 -57
- package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
- package/dist/adapters/adapter-field.d.ts +11 -11
- package/dist/adapters/adapter-identifier.d.ts +6 -6
- package/dist/adapters/adapter-model.d.ts +9 -9
- package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
- package/dist/adapters/adapter-operation.d.ts +3 -3
- package/dist/adapters/adapter-resource.d.ts +18 -9
- package/dist/adapters/adapter-sql-statement.d.ts +19 -0
- package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
- package/dist/adapters/adapter.interface.d.ts +49 -29
- package/dist/avz/avz-check.factory.d.ts +83 -0
- package/dist/avz/avz-check.factory.js +116 -0
- package/dist/avz/avz-check.registry.d.ts +35 -0
- package/dist/avz/avz-check.registry.js +9 -0
- package/dist/avz/avz.d.ts +203 -0
- package/dist/{json → avz}/avz.js +150 -8
- package/dist/{json → avz}/index.d.ts +2 -1
- package/dist/{json → avz}/json-shape.registry.d.ts +7 -7
- package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
- package/dist/{json → avz}/zod-issue.translator.js +7 -0
- package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
- package/dist/compiler/contract.compiler.d.ts +18 -18
- package/dist/compiler/contract.compiler.js +548 -441
- package/dist/compiler/create-requirements.projector.d.ts +49 -0
- package/dist/compiler/create-requirements.projector.js +423 -0
- package/dist/compiler/field-validator.compiler.d.ts +47 -0
- package/dist/compiler/field-validator.compiler.js +238 -0
- package/dist/config/any-framework-config.d.ts +19 -12
- package/dist/config/config-diagnostic.d.ts +11 -4
- package/dist/config/config-layer.d.ts +15 -6
- package/dist/config/config.resolver.d.ts +74 -31
- package/dist/config/config.resolver.js +108 -44
- package/dist/config/config.validator.d.ts +7 -7
- package/dist/config/config.validator.js +581 -72
- package/dist/config/define-resource.d.ts +57 -0
- package/dist/config/define-resource.js +14 -0
- package/dist/config/effective-fields.d.ts +19 -23
- package/dist/config/entrypoint.normalizer.d.ts +1 -1
- package/dist/config/exact-framework-config.d.ts +280 -0
- package/dist/config/field-compute.resolver.d.ts +19 -0
- package/dist/config/field-compute.resolver.js +115 -0
- package/dist/config/field-pipeline-config.d.ts +47 -0
- package/dist/config/forced-operation.validator.d.ts +10 -0
- package/dist/config/forced-operation.validator.js +66 -0
- package/dist/config/framework-config.d.ts +110 -39
- package/dist/config/framework-exemptions-config.d.ts +91 -0
- package/dist/config/framework-exemptions-config.js +1 -0
- package/dist/config/framework-field-definition.d.ts +78 -0
- package/dist/config/framework-field-definition.js +28 -0
- package/dist/config/framework-resources-config.d.ts +116 -0
- package/dist/config/framework-resources-config.js +1 -0
- package/dist/config/pipeline-config.d.ts +56 -20
- package/dist/config/pipeline-tree.resolver.d.ts +79 -0
- package/dist/config/pipeline-tree.resolver.js +220 -0
- package/dist/config/stage-type.eraser.d.ts +65 -0
- package/dist/config/stage-type.eraser.js +1 -0
- package/dist/contracts/capability.d.ts +11 -11
- package/dist/contracts/client-contract-structure.validator.d.ts +323 -28
- package/dist/contracts/client-contract-structure.validator.js +152 -8
- package/dist/contracts/contract-canonicalizer.d.ts +19 -3
- package/dist/contracts/contract-canonicalizer.js +141 -28
- package/dist/contracts/contract-hash.d.ts +12 -7
- package/dist/contracts/contract-hash.js +3 -2
- package/dist/contracts/contract-limits.d.ts +4 -1
- package/dist/contracts/contract-limits.js +1 -0
- package/dist/contracts/contract-lookup.d.ts +5 -5
- package/dist/contracts/contract-protocol.d.ts +4 -4
- package/dist/contracts/contract.d.ts +24 -16
- package/dist/contracts/create-requirements.d.ts +35 -0
- package/dist/contracts/create-requirements.js +1 -0
- package/dist/contracts/enum-definition.d.ts +1 -1
- package/dist/contracts/field-check.d.ts +101 -0
- package/dist/contracts/field-check.js +1 -0
- package/dist/contracts/field.d.ts +52 -42
- package/dist/contracts/identifier.d.ts +4 -4
- package/dist/contracts/json-shape.d.ts +12 -1
- package/dist/contracts/lifecycle-trait.d.ts +2 -2
- package/dist/contracts/resource-operations.d.ts +28 -28
- package/dist/contracts/resource.d.ts +15 -9
- package/dist/contracts/scalar-value-type.d.ts +15 -15
- package/dist/contracts/scalar.d.ts +3 -3
- package/dist/contracts/transaction-capability.d.ts +1 -1
- package/dist/contracts/wire-scalar-format.d.ts +4 -4
- package/dist/framework/contract-view.d.ts +213 -147
- package/dist/framework/framework-construction.error.d.ts +10 -10
- package/dist/framework/framework-construction.error.js +2 -2
- package/dist/framework/framework.d.ts +47 -23
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +40 -20
- package/dist/framework/operation-facade.d.ts +123 -52
- package/dist/framework/operation-facade.js +9 -1
- package/dist/index.d.ts +55 -50
- package/dist/index.js +6 -6
- package/dist/internal.d.ts +15 -10
- package/dist/internal.js +3 -1
- package/dist/operations/operation-arguments.d.ts +267 -202
- package/dist/operations/operation-call.d.ts +27 -28
- package/dist/operations/operation-identity.d.ts +10 -10
- package/dist/operations/operation-result.d.ts +21 -21
- package/dist/operations/operation-validator-core.d.ts +6 -6
- package/dist/operations/operation-validator-core.js +13 -2
- package/dist/operations/operation-validator.d.ts +9 -9
- package/dist/operations/projection-scope.resolver.d.ts +6 -6
- package/dist/operations/structural-limits.walker.d.ts +6 -6
- package/dist/operations/structural-limits.walker.js +145 -0
- package/dist/operations/validation-code.d.ts +11 -6
- package/dist/operations/validation-code.js +4 -0
- package/dist/operations/write-scope.resolver.d.ts +6 -6
- package/dist/protocol/absent-route.responder.d.ts +13 -12
- package/dist/protocol/absent-route.responder.js +19 -19
- package/dist/protocol/contract-document.responder.d.ts +3 -3
- package/dist/protocol/contract-document.responder.js +2 -2
- package/dist/protocol/http-request.decoder.d.ts +17 -13
- package/dist/protocol/http-request.decoder.js +10 -10
- package/dist/protocol/http-request.reader.d.ts +3 -3
- package/dist/protocol/http-response.encoder.d.ts +4 -4
- package/dist/protocol/http-response.encoder.js +94 -55
- package/dist/protocol/http-status.table.d.ts +2 -2
- package/dist/protocol/operation-response.guard.d.ts +2 -2
- package/dist/protocol/protocol-surface.d.ts +4 -4
- package/dist/protocol/protocol.binder.d.ts +50 -27
- package/dist/protocol/protocol.binder.js +12 -9
- package/dist/protocol/protocol.handler.d.ts +22 -13
- package/dist/protocol/protocol.handler.js +44 -9
- package/dist/protocol/unmounted-route.error.d.ts +4 -4
- package/dist/protocol/unmounted-route.error.js +2 -2
- package/dist/runtime/caller-data.copier.d.ts +5 -5
- package/dist/runtime/caller-data.copier.js +13 -13
- package/dist/runtime/caller-data.door.d.ts +6 -6
- package/dist/runtime/caller-data.door.js +6 -4
- package/dist/runtime/computed-read-runtime.d.ts +7 -6
- package/dist/runtime/computed-read-runtime.js +61 -48
- package/dist/runtime/computed-value.error.d.ts +6 -6
- package/dist/runtime/computed-value.error.js +3 -3
- package/dist/runtime/context-executor.runtime.d.ts +59 -0
- package/dist/runtime/context-executor.runtime.js +275 -0
- package/dist/runtime/create-requirement.d.ts +10 -81
- package/dist/runtime/create-requirement.js +80 -57
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +1 -1
- package/dist/runtime/diagnostics-reporter.d.ts +53 -27
- package/dist/runtime/diagnostics-reporter.js +24 -0
- package/dist/runtime/error-boundary.d.ts +65 -8
- package/dist/runtime/error-boundary.js +45 -19
- package/dist/runtime/execution-options.d.ts +10 -2
- package/dist/runtime/field-check.evaluator.d.ts +29 -0
- package/dist/runtime/field-check.evaluator.js +521 -0
- package/dist/runtime/field-compute.d.ts +64 -0
- package/dist/runtime/field-compute.js +1 -0
- package/dist/runtime/field-stage.plan.d.ts +15 -0
- package/dist/runtime/field-stage.plan.js +27 -0
- package/dist/runtime/field-stage.runtime.d.ts +35 -0
- package/dist/runtime/field-stage.runtime.js +143 -0
- package/dist/runtime/field-validator.runtime.d.ts +11 -0
- package/dist/runtime/field-validator.runtime.js +87 -0
- package/dist/runtime/framework-error-class.table.d.ts +33 -0
- package/dist/runtime/framework-error-class.table.js +25 -0
- package/dist/runtime/framework-error.d.ts +68 -8
- package/dist/runtime/framework-error.factory.d.ts +4 -0
- package/dist/runtime/framework-error.factory.js +15 -0
- package/dist/runtime/framework-error.js +23 -2
- package/dist/runtime/interceptor-next.error.d.ts +5 -0
- package/dist/runtime/interceptor-next.error.js +6 -0
- package/dist/runtime/json-value.d.ts +3 -3
- package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
- package/dist/runtime/level-lifecycle.runtime.js +42 -0
- package/dist/runtime/misuse-reporter.d.ts +12 -12
- package/dist/runtime/mutation-planner.d.ts +19 -10
- package/dist/runtime/mutation-planner.js +54 -30
- package/dist/runtime/nested-write.walker.d.ts +32 -0
- package/dist/runtime/nested-write.walker.js +73 -0
- package/dist/runtime/operation-request.d.ts +33 -6
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +113 -25
- package/dist/runtime/operation-runtime.js +395 -74
- package/dist/runtime/outcome-mapper.d.ts +16 -5
- package/dist/runtime/outcome-mapper.js +23 -6
- package/dist/runtime/output-validator.d.ts +10 -10
- package/dist/runtime/output-validator.js +3 -3
- package/dist/runtime/owned-execution.registry.d.ts +6 -6
- package/dist/runtime/pipe-output.validator.d.ts +33 -18
- package/dist/runtime/pipe-output.validator.js +12 -12
- package/dist/runtime/pipeline.d.ts +196 -34
- package/dist/runtime/readonly-value.d.ts +32 -0
- package/dist/runtime/readonly-value.js +141 -0
- package/dist/runtime/request-envelope.validator.d.ts +3 -3
- package/dist/runtime/request-envelope.validator.js +12 -7
- package/dist/runtime/request-id.d.ts +1 -1
- package/dist/runtime/request-state.d.ts +14 -0
- package/dist/runtime/request-state.js +1 -0
- package/dist/runtime/request-state.resolver.d.ts +12 -0
- package/dist/runtime/request-state.resolver.js +20 -0
- package/dist/runtime/scalar-runtime.d.ts +31 -16
- package/dist/runtime/scalar-runtime.js +16 -18
- package/dist/transactions/deferred-operation.d.ts +35 -20
- package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
- package/dist/transactions/operation-arguments-encoder.js +2 -2
- package/dist/transactions/sql-statement.d.ts +77 -0
- package/dist/transactions/sql-statement.js +47 -0
- package/dist/transactions/sql-statement.validator.d.ts +44 -0
- package/dist/transactions/sql-statement.validator.js +134 -0
- package/dist/transactions/transaction-envelope.d.ts +4 -4
- package/dist/transactions/transaction-integrity-error.d.ts +6 -6
- package/dist/transactions/transaction-integrity-error.js +5 -2
- package/dist/transactions/transaction-plan-assembler.d.ts +21 -11
- package/dist/transactions/transaction-plan-assembler.js +148 -34
- package/dist/transactions/transaction-plan-validator.d.ts +29 -20
- package/dist/transactions/transaction-plan-validator.js +70 -38
- package/dist/transactions/transaction-reference-collector.d.ts +5 -5
- package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
- package/dist/transactions/transaction-reference-resolver.js +26 -14
- package/dist/transactions/transaction-reference-validator.d.ts +34 -4
- package/dist/transactions/transaction-reference-validator.js +58 -26
- package/dist/transactions/transaction-reference.d.ts +13 -13
- package/dist/transactions/transaction-request.d.ts +18 -5
- package/dist/transactions/transaction-response.d.ts +6 -6
- package/dist/transactions/transaction-runtime.d.ts +8 -7
- package/dist/transactions/transaction-runtime.js +166 -50
- package/dist/transactions/transaction-settlement.runtime.d.ts +51 -0
- package/dist/transactions/transaction-settlement.runtime.js +120 -0
- package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
- package/dist/transactions/transaction-slot-path-error.js +2 -2
- package/dist/transactions/transaction-slot-writer.js +2 -2
- package/dist/transactions/transaction-stage.runtime.d.ts +81 -0
- package/dist/transactions/transaction-stage.runtime.js +123 -0
- package/package.json +6 -5
- package/src/runtime/field-check.evaluator.ts +720 -0
- package/dist/config/define-fields.d.ts +0 -42
- package/dist/config/define-fields.js +0 -3
- package/dist/config/framework-behaviors-config.d.ts +0 -30
- package/dist/config/framework-fields-config.d.ts +0 -42
- package/dist/config/framework-restrictions-config.d.ts +0 -142
- package/dist/json/avz.d.ts +0 -96
- package/dist/runtime/field-behavior.d.ts +0 -48
- /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
- /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
- /package/dist/{json → avz}/index.js +0 -0
- /package/dist/{json → avz}/json-shape.registry.js +0 -0
- /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
- /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { validationIssue } from "../operations/validation-code.js";
|
|
2
|
+
import { refuseCallerData } from "../runtime/caller-data.door.js";
|
|
3
|
+
import { AvDecimal } from "../runtime/decimal.js";
|
|
4
|
+
import { planStepPath } from "../runtime/error-boundary.js";
|
|
5
|
+
import { operationFailure } from "../runtime/operation-response.js";
|
|
6
|
+
import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
|
|
7
|
+
import { isPlainRecord, normalizeJsonValue, } from "../runtime/scalar-runtime.js";
|
|
8
|
+
import { invalidSourceIndexIssue, referenceSourceAt, referenceSourceField, } from "./transaction-reference-validator.js";
|
|
9
|
+
import { transactionOperationFailure } from "./transaction-response.js";
|
|
10
|
+
function refused(issue, index) {
|
|
11
|
+
return {
|
|
12
|
+
ok: false,
|
|
13
|
+
response: transactionOperationFailure(mapValidationOutcome([issue]), index),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function normalizeSqlValue(value, path) {
|
|
17
|
+
if (value === null ||
|
|
18
|
+
typeof value === "string" ||
|
|
19
|
+
typeof value === "boolean" ||
|
|
20
|
+
typeof value === "bigint" ||
|
|
21
|
+
value instanceof AvDecimal ||
|
|
22
|
+
value instanceof Uint8Array) {
|
|
23
|
+
return { ok: true, value };
|
|
24
|
+
}
|
|
25
|
+
if (typeof value === "number") {
|
|
26
|
+
return Number.isFinite(value)
|
|
27
|
+
? { ok: true, value }
|
|
28
|
+
: {
|
|
29
|
+
ok: false,
|
|
30
|
+
issues: [
|
|
31
|
+
validationIssue("V1004", path, "Value must be a finite number."),
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (value instanceof Date) {
|
|
36
|
+
return Number.isNaN(value.getTime())
|
|
37
|
+
? {
|
|
38
|
+
ok: false,
|
|
39
|
+
issues: [
|
|
40
|
+
validationIssue("V1003", path, "Value must use a valid Date value."),
|
|
41
|
+
],
|
|
42
|
+
}
|
|
43
|
+
: { ok: true, value };
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(value) || isPlainRecord(value)) {
|
|
46
|
+
const json = normalizeJsonValue(value, path, new Set());
|
|
47
|
+
return json.ok
|
|
48
|
+
? { ok: true, value: json.value }
|
|
49
|
+
: { ok: false, issues: json.issues };
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
issues: [
|
|
54
|
+
validationIssue("V1001", path, "Value must be a string, number, boolean, bigint, null, Date, Decimal, Uint8Array or JSON value."),
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function validateSqlStatement(statement, context) {
|
|
59
|
+
const { index, earlier } = context;
|
|
60
|
+
if (!context.available) {
|
|
61
|
+
const message = "SQL statements are not available on this Adapter.";
|
|
62
|
+
return {
|
|
63
|
+
ok: false,
|
|
64
|
+
response: transactionOperationFailure(operationFailure("A2002", {
|
|
65
|
+
message,
|
|
66
|
+
issues: [validationIssue("V1006", [], message)],
|
|
67
|
+
}), index),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (statement.strings === undefined) {
|
|
71
|
+
return refused(validationIssue("V1001", ["strings"], "SQL must be written as a tagged template: framework.appTx.$sql`…`."), index);
|
|
72
|
+
}
|
|
73
|
+
if (statement.refused !== undefined) {
|
|
74
|
+
return refused(refuseCallerData(statement.refused, [...planStepPath(index), "values"], { origin: "application", operation: index }, context.misuse), index);
|
|
75
|
+
}
|
|
76
|
+
const values = [];
|
|
77
|
+
const issues = [];
|
|
78
|
+
for (const [position, planned] of statement.values.entries()) {
|
|
79
|
+
const path = ["values", position];
|
|
80
|
+
switch (planned.kind) {
|
|
81
|
+
case "misplaced-reference":
|
|
82
|
+
return refused(validationIssue("V1010", [...path, ...planned.path, "$ref"], "A transaction reference in a SQL step must be a whole value."), index);
|
|
83
|
+
case "reference": {
|
|
84
|
+
const source = referenceSourceAt(earlier, planned.operation, index);
|
|
85
|
+
if (source === undefined) {
|
|
86
|
+
return refused(invalidSourceIndexIssue([...path, "$ref", "operation"]), index);
|
|
87
|
+
}
|
|
88
|
+
const read = referenceSourceField(source, planned.field, [
|
|
89
|
+
...path,
|
|
90
|
+
"$ref",
|
|
91
|
+
"path",
|
|
92
|
+
]);
|
|
93
|
+
if (!read.ok) {
|
|
94
|
+
return refused(read.issue, index);
|
|
95
|
+
}
|
|
96
|
+
if (read.field.kind !== "scalar" || read.field.list) {
|
|
97
|
+
return refused(validationIssue("V1011", [...path, "$ref", "path"], "Transaction reference source is not a single scalar field."), index);
|
|
98
|
+
}
|
|
99
|
+
values.push({
|
|
100
|
+
kind: "reference",
|
|
101
|
+
operation: planned.operation,
|
|
102
|
+
field: planned.field,
|
|
103
|
+
source: read.field,
|
|
104
|
+
});
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case "value": {
|
|
108
|
+
const normalized = normalizeSqlValue(planned.value, path);
|
|
109
|
+
if (normalized.ok) {
|
|
110
|
+
values.push({ kind: "value", value: normalized.value });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
issues.push(...normalized.issues);
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (issues.length > 0) {
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
response: transactionOperationFailure(mapValidationOutcome(issues), index),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
ok: true,
|
|
127
|
+
statement: {
|
|
128
|
+
kind: "sql",
|
|
129
|
+
index,
|
|
130
|
+
strings: statement.strings,
|
|
131
|
+
values,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
2
2
|
export type TransactionEnvelopeSchema = {
|
|
3
3
|
readonly required: readonly string[];
|
|
4
4
|
readonly optional?: readonly string[];
|
|
@@ -10,7 +10,7 @@ export type TransactionEnvelopeInspection = {
|
|
|
10
10
|
readonly values: ReadonlyMap<string, unknown>;
|
|
11
11
|
} | {
|
|
12
12
|
readonly ok: false;
|
|
13
|
-
readonly issue:
|
|
13
|
+
readonly issue: AvValidationIssue;
|
|
14
14
|
};
|
|
15
15
|
export type TransactionOperationsInspection = {
|
|
16
16
|
readonly ok: true;
|
|
@@ -18,14 +18,14 @@ export type TransactionOperationsInspection = {
|
|
|
18
18
|
readonly length: number;
|
|
19
19
|
} | {
|
|
20
20
|
readonly ok: false;
|
|
21
|
-
readonly issue:
|
|
21
|
+
readonly issue: AvValidationIssue;
|
|
22
22
|
};
|
|
23
23
|
export type TransactionOperationEntryInspection = {
|
|
24
24
|
readonly ok: true;
|
|
25
25
|
readonly value: unknown;
|
|
26
26
|
} | {
|
|
27
27
|
readonly ok: false;
|
|
28
|
-
readonly issue:
|
|
28
|
+
readonly issue: AvValidationIssue;
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
31
31
|
* The caller uses the returned length and per-index inspector rather than
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The ways an Adapter transaction can break the
|
|
3
|
-
* contract. Each is answered `A3002
|
|
2
|
+
* The ways an Adapter transaction, or a stage running inside it, can break the
|
|
3
|
+
* framework's transaction contract. Each is answered `A3002` and rolls back.
|
|
4
4
|
*/
|
|
5
|
-
export type
|
|
5
|
+
export type AvTransactionIntegrityViolation = "transaction-unavailable" | "resolved-after-abort" | "resolved-incomplete" | "foreign-abort" | "statement-unavailable" | "next-called-twice" | "steps-not-run";
|
|
6
6
|
/**
|
|
7
7
|
* Reported to diagnostics when an Adapter transaction breaks the framework's
|
|
8
8
|
* transaction contract. The caller receives `A3002`.
|
|
9
9
|
*/
|
|
10
|
-
export declare class
|
|
11
|
-
readonly violation:
|
|
12
|
-
constructor(violation:
|
|
10
|
+
export declare class AvTransactionIntegrityError extends Error {
|
|
11
|
+
readonly violation: AvTransactionIntegrityViolation;
|
|
12
|
+
constructor(violation: AvTransactionIntegrityViolation);
|
|
13
13
|
}
|
|
@@ -3,12 +3,15 @@ const TRANSACTION_INTEGRITY_MESSAGES = {
|
|
|
3
3
|
"resolved-after-abort": "Adapter transaction resolved after the framework requested rollback.",
|
|
4
4
|
"resolved-incomplete": "Adapter transaction resolved before the plan completed.",
|
|
5
5
|
"foreign-abort": "Adapter transaction rejected with a rollback request this plan never made.",
|
|
6
|
+
"statement-unavailable": "Adapter declares sqlStatements but its transaction executor has no executeSql.",
|
|
7
|
+
"next-called-twice": "A transaction interceptor called next() more than once; next() runs the plan's steps once.",
|
|
8
|
+
"steps-not-run": "A transaction interceptor resolved without calling next(); the plan's steps never ran.",
|
|
6
9
|
};
|
|
7
|
-
export class
|
|
10
|
+
export class AvTransactionIntegrityError extends Error {
|
|
8
11
|
violation;
|
|
9
12
|
constructor(violation) {
|
|
10
13
|
super(TRANSACTION_INTEGRITY_MESSAGES[violation]);
|
|
11
|
-
this.name = "
|
|
14
|
+
this.name = "AvTransactionIntegrityError";
|
|
12
15
|
this.violation = violation;
|
|
13
16
|
}
|
|
14
17
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { CallerDataError } from "../runtime/caller-data.copier.js";
|
|
1
|
+
import type { AvContracts } from "../compiler/contract.compiler.js";
|
|
2
|
+
import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
3
|
+
import type { AvCallerDataError } from "../runtime/caller-data.copier.js";
|
|
5
4
|
import type { MisuseReporter } from "../runtime/misuse-reporter.js";
|
|
6
5
|
import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
6
|
+
import type { AvOperationFailureResponse } from "../runtime/operation-response.js";
|
|
7
|
+
import type { AvOperation, OperationFingerprint } from "./deferred-operation.js";
|
|
8
|
+
import type { PlannedSqlStatement } from "./sql-statement.js";
|
|
9
9
|
import type { TransactionOperationOrigin } from "./transaction-request.js";
|
|
10
|
+
/** The origin a handle's builder gives it. */
|
|
11
|
+
type HandleOrigin = "application" | "client";
|
|
10
12
|
/** One wire node, exactly as the transaction runtime receives it. */
|
|
11
13
|
type WireOperationNode = {
|
|
12
14
|
readonly resource: string;
|
|
@@ -15,22 +17,30 @@ type WireOperationNode = {
|
|
|
15
17
|
readonly args: unknown;
|
|
16
18
|
readonly fingerprint: OperationFingerprint | null;
|
|
17
19
|
};
|
|
20
|
+
declare const SQL_STEP_NODE: Readonly<{
|
|
21
|
+
fingerprint: null;
|
|
22
|
+
}>;
|
|
23
|
+
type PlanNode = WireOperationNode | typeof SQL_STEP_NODE;
|
|
18
24
|
export type AssembledTransactionPlan = {
|
|
19
25
|
readonly ok: true;
|
|
20
26
|
readonly plan: {
|
|
21
|
-
readonly operations: readonly
|
|
27
|
+
readonly operations: readonly PlanNode[];
|
|
22
28
|
};
|
|
23
29
|
/** Each operation's own origin, by index (mixed plans). */
|
|
24
30
|
readonly origins: readonly TransactionOperationOrigin[];
|
|
25
31
|
/** The steps whose arguments their builder could not copy, by index. */
|
|
26
|
-
readonly refused: ReadonlyMap<number,
|
|
32
|
+
readonly refused: ReadonlyMap<number, AvCallerDataError>;
|
|
33
|
+
/** The `appTx.$sql` steps, by index, with each `$ref` bound to its source's position. */
|
|
34
|
+
readonly statements: ReadonlyMap<number, PlannedSqlStatement>;
|
|
27
35
|
} | {
|
|
28
36
|
readonly ok: false;
|
|
29
|
-
readonly response:
|
|
37
|
+
readonly response: AvOperationFailureResponse;
|
|
30
38
|
};
|
|
31
39
|
export type TransactionPlanAssembler = {
|
|
32
40
|
/** Defers one operation into a handle; nothing runs. */
|
|
33
|
-
defer(origin:
|
|
41
|
+
defer(origin: HandleOrigin, resource: string, identity: AvOperationIdentity, args: unknown): AvOperation<unknown>;
|
|
42
|
+
/** Defers one `appTx.$sql` statement into a handle; nothing runs. */
|
|
43
|
+
deferSql(strings: unknown, values: readonly unknown[]): AvOperation<unknown>;
|
|
34
44
|
/** Binds a list of handles into the passive plan, or refuses it. */
|
|
35
45
|
assemble(operations: unknown): Promise<AssembledTransactionPlan>;
|
|
36
46
|
};
|
|
@@ -39,5 +49,5 @@ export type TransactionPlanAssembler = {
|
|
|
39
49
|
* handle, so a handle another instance built — typed against another model,
|
|
40
50
|
* bound to other Contracts — is refused rather than run.
|
|
41
51
|
*/
|
|
42
|
-
export declare function createTransactionPlanAssembler(contracts:
|
|
52
|
+
export declare function createTransactionPlanAssembler(contracts: AvContracts, protocol: ClientProtocolIdentity, misuse: MisuseReporter): TransactionPlanAssembler;
|
|
43
53
|
export {};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { validationIssue } from "../operations/validation-code.js";
|
|
1
|
+
import { VALIDATION_CODE_MESSAGES, validationIssue, } from "../operations/validation-code.js";
|
|
2
2
|
import { copyAtDoor, refuseCallerData } from "../runtime/caller-data.door.js";
|
|
3
3
|
import { operationFailure } from "../runtime/operation-response.js";
|
|
4
4
|
import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
|
|
5
5
|
import { encodeOperationArgumentsForWire } from "./operation-arguments-encoder.js";
|
|
6
6
|
import { computeOperationFingerprint } from "./operation-fingerprint.js";
|
|
7
|
+
import { readSqlTemplate } from "./sql-statement.js";
|
|
7
8
|
import { transactionOperationFailure } from "./transaction-response.js";
|
|
9
|
+
const SQL_STEP_NODE = Object.freeze({ fingerprint: null });
|
|
8
10
|
function isPlainRecord(value) {
|
|
9
11
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
10
12
|
return false;
|
|
@@ -13,26 +15,73 @@ function isPlainRecord(value) {
|
|
|
13
15
|
return prototype === Object.prototype || prototype === null;
|
|
14
16
|
}
|
|
15
17
|
const KEEP = Symbol("keep");
|
|
16
|
-
function rebuildArguments(
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
function rebuildArguments(root, leaf) {
|
|
19
|
+
const pathOf = (parent, key) => () => {
|
|
20
|
+
const segments = [];
|
|
21
|
+
if (key !== undefined) {
|
|
22
|
+
segments.push(key);
|
|
23
|
+
}
|
|
24
|
+
for (let frame = parent; frame?.key !== undefined; frame = frame.parent) {
|
|
25
|
+
segments.push(frame.key);
|
|
26
|
+
}
|
|
27
|
+
return segments.reverse();
|
|
28
|
+
};
|
|
29
|
+
const ancestors = new Set();
|
|
30
|
+
const finish = (frame) => {
|
|
31
|
+
ancestors.delete(frame.source);
|
|
32
|
+
if (!Array.isArray(frame.source)) {
|
|
33
|
+
return Object.fromEntries(frame.built);
|
|
34
|
+
}
|
|
35
|
+
const rebuilt = new Array(frame.source.length);
|
|
36
|
+
for (const [index, value] of frame.built) {
|
|
37
|
+
rebuilt[index] = value;
|
|
38
|
+
}
|
|
39
|
+
return rebuilt;
|
|
40
|
+
};
|
|
41
|
+
const enter = (value, parent, key) => {
|
|
42
|
+
const replaced = leaf(value, pathOf(parent, key));
|
|
43
|
+
if (replaced !== KEEP) {
|
|
44
|
+
return { value: replaced };
|
|
45
|
+
}
|
|
46
|
+
if (!Array.isArray(value) && !isPlainRecord(value)) {
|
|
47
|
+
return { value };
|
|
48
|
+
}
|
|
49
|
+
if (ancestors.has(value)) {
|
|
50
|
+
return { value };
|
|
51
|
+
}
|
|
52
|
+
ancestors.add(value);
|
|
53
|
+
const keys = Array.isArray(value)
|
|
54
|
+
? Object.keys(value).map(Number)
|
|
55
|
+
: Object.keys(value);
|
|
56
|
+
return { source: value, keys, built: [], parent, key, next: 0 };
|
|
57
|
+
};
|
|
58
|
+
const first = enter(root, undefined, undefined);
|
|
59
|
+
if (!("source" in first)) {
|
|
60
|
+
return first.value;
|
|
23
61
|
}
|
|
24
|
-
|
|
25
|
-
|
|
62
|
+
let frame = first;
|
|
63
|
+
for (;;) {
|
|
64
|
+
if (frame.next < frame.keys.length) {
|
|
65
|
+
const key = frame.keys[frame.next];
|
|
66
|
+
frame.next += 1;
|
|
67
|
+
const entry = frame.source[key];
|
|
68
|
+
const child = enter(entry, frame, key);
|
|
69
|
+
if ("source" in child) {
|
|
70
|
+
frame = child;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
frame.built.push([key, child.value]);
|
|
74
|
+
}
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const rebuilt = finish(frame);
|
|
78
|
+
const parent = frame.parent;
|
|
79
|
+
if (parent === undefined) {
|
|
80
|
+
return rebuilt;
|
|
81
|
+
}
|
|
82
|
+
parent.built.push([frame.key, rebuilt]);
|
|
83
|
+
frame = parent;
|
|
26
84
|
}
|
|
27
|
-
ancestors.add(value);
|
|
28
|
-
const rebuilt = Array.isArray(value)
|
|
29
|
-
? value.map((entry, index) => rebuildArguments(entry, [...path, index], leaf, ancestors))
|
|
30
|
-
: Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
31
|
-
key,
|
|
32
|
-
rebuildArguments(entry, [...path, key], leaf, ancestors),
|
|
33
|
-
]));
|
|
34
|
-
ancestors.delete(value);
|
|
35
|
-
return rebuilt;
|
|
36
85
|
}
|
|
37
86
|
function operationEntryFailure(operation, message) {
|
|
38
87
|
return transactionOperationFailure(operationFailure("A2004", {
|
|
@@ -57,19 +106,19 @@ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
|
|
|
57
106
|
};
|
|
58
107
|
const placeholderSites = (args) => {
|
|
59
108
|
const sites = [];
|
|
60
|
-
rebuildArguments(args,
|
|
109
|
+
rebuildArguments(args, (value, pathOf) => {
|
|
61
110
|
const placeholder = typeof value === "object" && value !== null
|
|
62
111
|
? placeholders.get(value)
|
|
63
112
|
: undefined;
|
|
64
113
|
if (placeholder === undefined) {
|
|
65
114
|
return KEEP;
|
|
66
115
|
}
|
|
67
|
-
sites.push({ path, object: value, placeholder });
|
|
116
|
+
sites.push({ path: pathOf(), object: value, placeholder });
|
|
68
117
|
return value;
|
|
69
118
|
});
|
|
70
119
|
return sites;
|
|
71
120
|
};
|
|
72
|
-
const
|
|
121
|
+
const createHandle = (record) => {
|
|
73
122
|
const handle = Object.freeze({
|
|
74
123
|
$ref: (field) => {
|
|
75
124
|
const placeholder = Object.freeze({
|
|
@@ -79,14 +128,48 @@ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
|
|
|
79
128
|
return placeholder;
|
|
80
129
|
},
|
|
81
130
|
});
|
|
82
|
-
handles.set(handle,
|
|
83
|
-
origin,
|
|
84
|
-
resource,
|
|
85
|
-
identity,
|
|
86
|
-
...snapshot(args),
|
|
87
|
-
});
|
|
131
|
+
handles.set(handle, record);
|
|
88
132
|
return handle;
|
|
89
133
|
};
|
|
134
|
+
const defer = (origin, resource, identity, args) => createHandle({
|
|
135
|
+
kind: "operation",
|
|
136
|
+
origin,
|
|
137
|
+
resource,
|
|
138
|
+
identity,
|
|
139
|
+
...snapshot(args),
|
|
140
|
+
});
|
|
141
|
+
const deferSql = (strings, values) => {
|
|
142
|
+
const copy = snapshot(values);
|
|
143
|
+
return createHandle({
|
|
144
|
+
kind: "sql",
|
|
145
|
+
strings: readSqlTemplate(strings, values.length),
|
|
146
|
+
values: Array.isArray(copy.args) ? copy.args : [],
|
|
147
|
+
...(copy.refused === undefined ? {} : { refused: copy.refused }),
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
const recordPlaceholderSites = (record) => placeholderSites(record.kind === "sql" ? record.values : record.args);
|
|
151
|
+
const planSqlStatement = (record, positions) => {
|
|
152
|
+
const values = record.values.map((value) => {
|
|
153
|
+
const sites = placeholderSites(value);
|
|
154
|
+
const [site] = sites;
|
|
155
|
+
if (site === undefined) {
|
|
156
|
+
return { kind: "value", value };
|
|
157
|
+
}
|
|
158
|
+
if (site.path.length > 0) {
|
|
159
|
+
return { kind: "misplaced-reference", path: site.path };
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
kind: "reference",
|
|
163
|
+
operation: positions.get(site.placeholder.source),
|
|
164
|
+
field: site.placeholder.field,
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
strings: record.strings,
|
|
169
|
+
values,
|
|
170
|
+
...(record.refused === undefined ? {} : { refused: record.refused }),
|
|
171
|
+
};
|
|
172
|
+
};
|
|
90
173
|
const assemble = async (input) => {
|
|
91
174
|
const list = copyAtDoor(input, { keep: (value) => value !== input });
|
|
92
175
|
if (!list.ok) {
|
|
@@ -131,12 +214,35 @@ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
|
|
|
131
214
|
positions.set(entry, index);
|
|
132
215
|
records.push(record);
|
|
133
216
|
}
|
|
217
|
+
const originOfRecord = (record) => record.kind === "sql" ? "application" : record.origin;
|
|
218
|
+
const [first] = records;
|
|
219
|
+
if (first !== undefined) {
|
|
220
|
+
const planOrigin = originOfRecord(first);
|
|
221
|
+
const other = records.findIndex((record) => originOfRecord(record) !== planOrigin);
|
|
222
|
+
if (other !== -1) {
|
|
223
|
+
return {
|
|
224
|
+
ok: false,
|
|
225
|
+
response: transactionOperationFailure(operationFailure("A2004", {
|
|
226
|
+
message: "Transaction plan failed framework validation.",
|
|
227
|
+
issues: [
|
|
228
|
+
validationIssue("V1020", [], VALIDATION_CODE_MESSAGES.V1020),
|
|
229
|
+
],
|
|
230
|
+
}), other),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
134
234
|
for (const [index, record] of records.entries()) {
|
|
135
|
-
for (const { path, placeholder } of
|
|
235
|
+
for (const { path, placeholder } of recordPlaceholderSites(record)) {
|
|
136
236
|
if (!positions.has(placeholder.source)) {
|
|
137
237
|
return {
|
|
138
238
|
ok: false,
|
|
139
|
-
response: referenceFailure(validationIssue("V1010", [
|
|
239
|
+
response: referenceFailure(validationIssue("V1010", [
|
|
240
|
+
"operations",
|
|
241
|
+
index,
|
|
242
|
+
record.kind === "sql" ? "values" : "args",
|
|
243
|
+
...path,
|
|
244
|
+
"$ref",
|
|
245
|
+
], "Transaction reference names an operation that is not in this transaction."), index),
|
|
140
246
|
};
|
|
141
247
|
}
|
|
142
248
|
}
|
|
@@ -152,6 +258,9 @@ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
|
|
|
152
258
|
};
|
|
153
259
|
const materialize = async (index) => {
|
|
154
260
|
const record = records[index];
|
|
261
|
+
if (record.kind === "sql") {
|
|
262
|
+
return SQL_STEP_NODE;
|
|
263
|
+
}
|
|
155
264
|
const bound = new Map();
|
|
156
265
|
await Promise.all(placeholderSites(record.args).map(async ({ object, placeholder }) => {
|
|
157
266
|
const operation = positions.get(placeholder.source);
|
|
@@ -160,7 +269,7 @@ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
|
|
|
160
269
|
$ref: { operation, fingerprint, path: [placeholder.field] },
|
|
161
270
|
});
|
|
162
271
|
}));
|
|
163
|
-
const args = rebuildArguments(record.args,
|
|
272
|
+
const args = rebuildArguments(record.args, (value) => typeof value === "object" && value !== null && bound.has(value)
|
|
164
273
|
? bound.get(value)
|
|
165
274
|
: KEEP);
|
|
166
275
|
return {
|
|
@@ -192,9 +301,14 @@ export function createTransactionPlanAssembler(contracts, protocol, misuse) {
|
|
|
192
301
|
plan: {
|
|
193
302
|
operations: await Promise.all(records.map((_, index) => nodeAt(index))),
|
|
194
303
|
},
|
|
195
|
-
origins: records.map((record) => originOf(record.origin)),
|
|
196
|
-
refused: new Map(records.flatMap((record, index) => record.
|
|
304
|
+
origins: records.map((record) => originOf(record.kind === "sql" ? "application" : record.origin)),
|
|
305
|
+
refused: new Map(records.flatMap((record, index) => record.kind === "sql" || record.refused === undefined
|
|
306
|
+
? []
|
|
307
|
+
: [[index, record.refused]])),
|
|
308
|
+
statements: new Map(records.flatMap((record, index) => record.kind === "sql"
|
|
309
|
+
? [[index, planSqlStatement(record, positions)]]
|
|
310
|
+
: [])),
|
|
197
311
|
};
|
|
198
312
|
};
|
|
199
|
-
return { defer, assemble };
|
|
313
|
+
return { defer, deferSql, assemble };
|
|
200
314
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
3
|
+
import type { AvScalarField } from "../contracts/field.js";
|
|
4
4
|
import type { SemanticOperationArguments } from "../operations/operation-validator.js";
|
|
5
|
-
import {
|
|
5
|
+
import { AvCallerDataError } from "../runtime/caller-data.copier.js";
|
|
6
6
|
import { type ReadProjectionPlan } from "../runtime/computed-read-runtime.js";
|
|
7
7
|
import type { FrameworkOperationRequest } from "../runtime/operation-request.js";
|
|
8
|
-
import type {
|
|
8
|
+
import type { AvOperationFailureResponse } from "../runtime/operation-response.js";
|
|
9
9
|
import type { OperationPipelineDependencies } from "../runtime/operation-runtime.js";
|
|
10
10
|
import type { CascadeClosure } from "../runtime/referential-action.js";
|
|
11
11
|
import type { OperationFingerprint } from "./deferred-operation.js";
|
|
12
|
-
import type {
|
|
12
|
+
import type { PlannedSqlStatement, ValidatedSqlStatement } from "./sql-statement.js";
|
|
13
|
+
import type { AvTransactionReference } from "./transaction-reference.js";
|
|
13
14
|
import { type TransactionSlotShape } from "./transaction-reference.js";
|
|
14
15
|
import { type TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
|
|
15
16
|
import type { FrameworkTransactionRequest, TransactionOperationOrigin } from "./transaction-request.js";
|
|
@@ -22,26 +23,29 @@ import type { FrameworkTransactionRequest, TransactionOperationOrigin } from "./
|
|
|
22
23
|
* await, so a step revoked or changed after the call is never read again;
|
|
23
24
|
* - `"owned"` — a plan the protocol decoder parsed, or the typed runner assembled
|
|
24
25
|
* from its builders' copies; `refused` names the steps whose arguments a builder
|
|
25
|
-
* could not copy, answered at their turn
|
|
26
|
+
* could not copy, answered at their turn, and `statements` the steps that are
|
|
27
|
+
* `appTx.$sql` statements, which only the typed runner builds: they have no wire
|
|
28
|
+
* form, so no plan a caller or a remote client hands in can hold one.
|
|
26
29
|
*/
|
|
27
30
|
export type PlanArguments = {
|
|
28
31
|
readonly source: "caller";
|
|
29
32
|
} | {
|
|
30
33
|
readonly source: "owned";
|
|
31
|
-
readonly refused?: ReadonlyMap<number,
|
|
34
|
+
readonly refused?: ReadonlyMap<number, AvCallerDataError>;
|
|
35
|
+
readonly statements?: ReadonlyMap<number, PlannedSqlStatement>;
|
|
32
36
|
};
|
|
33
37
|
export type { TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
|
|
34
38
|
/** One validated Transaction Slot: where it is, what it holds, and its reference. */
|
|
35
39
|
export type TransactionReferenceSlot = {
|
|
36
40
|
readonly path: readonly (string | number)[];
|
|
37
41
|
/** The destination field. */
|
|
38
|
-
readonly field:
|
|
42
|
+
readonly field: AvScalarField<AvContract>;
|
|
39
43
|
readonly shape: TransactionSlotShape;
|
|
40
44
|
/** The slot is a scalar value of mutation data: what it resolves to is written. */
|
|
41
45
|
readonly written: boolean;
|
|
42
46
|
/** The source field, under its own step's Contract: what the slot receives. */
|
|
43
|
-
readonly source:
|
|
44
|
-
readonly reference:
|
|
47
|
+
readonly source: AvScalarField<AvContract>;
|
|
48
|
+
readonly reference: AvTransactionReference;
|
|
45
49
|
};
|
|
46
50
|
export type CandidateTransactionOperation = {
|
|
47
51
|
readonly index: number;
|
|
@@ -52,21 +56,24 @@ export type CandidateTransactionOperation = {
|
|
|
52
56
|
readonly candidates: readonly TransactionReferenceCandidateSlot[];
|
|
53
57
|
};
|
|
54
58
|
export type ValidatedTransactionOperation = {
|
|
59
|
+
readonly kind: "operation";
|
|
55
60
|
readonly index: number;
|
|
56
61
|
readonly request: FrameworkOperationRequest;
|
|
57
62
|
/**
|
|
58
|
-
* The Contract of this operation's
|
|
59
|
-
* against, the one it runs under, and the one a later `$ref` reads its
|
|
60
|
-
* field from.
|
|
63
|
+
* The Contract of this operation's origin, which is the plan's: the one it was
|
|
64
|
+
* validated against, the one it runs under, and the one a later `$ref` reads its
|
|
65
|
+
* source field from.
|
|
61
66
|
*/
|
|
62
|
-
readonly contract:
|
|
67
|
+
readonly contract: AvContract;
|
|
63
68
|
readonly arguments: SemanticOperationArguments;
|
|
64
69
|
readonly projection: ReadProjectionPlan | undefined;
|
|
65
70
|
readonly fingerprint: OperationFingerprint;
|
|
66
71
|
readonly references: readonly TransactionReferenceSlot[];
|
|
67
72
|
};
|
|
73
|
+
/** One validated plan step: a standard operation, or an `appTx.$sql` statement. */
|
|
74
|
+
export type ValidatedTransactionStep = ValidatedTransactionOperation | ValidatedSqlStatement;
|
|
68
75
|
export type ValidatedTransactionPlan = {
|
|
69
|
-
readonly operations: readonly
|
|
76
|
+
readonly operations: readonly ValidatedTransactionStep[];
|
|
70
77
|
};
|
|
71
78
|
/**
|
|
72
79
|
* What validating a plan needs beyond one operation's pipeline: the cascade
|
|
@@ -74,23 +81,25 @@ export type ValidatedTransactionPlan = {
|
|
|
74
81
|
* Framework is constructed. The record-write facts are not among them: they
|
|
75
82
|
* are checked when each operation runs, after its pipes.
|
|
76
83
|
*/
|
|
77
|
-
export type TransactionPlanDependencies<M extends
|
|
84
|
+
export type TransactionPlanDependencies<M extends AvAdapterModel> = Omit<OperationPipelineDependencies<M>, "recordWrites" | "contexts" | "fieldStages"> & {
|
|
78
85
|
readonly cascades: CascadeClosure;
|
|
86
|
+
/** Whether the Adapter declares `sqlStatements`: read once, at construction. */
|
|
87
|
+
readonly sqlStatements: boolean;
|
|
79
88
|
};
|
|
80
89
|
export type TransactionPlanValidationResult = {
|
|
81
90
|
readonly ok: true;
|
|
82
91
|
readonly plan: ValidatedTransactionPlan;
|
|
83
92
|
} | {
|
|
84
93
|
readonly ok: false;
|
|
85
|
-
readonly response:
|
|
94
|
+
readonly response: AvOperationFailureResponse;
|
|
86
95
|
};
|
|
87
96
|
/**
|
|
88
97
|
* The refusal of a plan on a Contract without transaction plans (`A2002`, one `V1006`
|
|
89
98
|
* at `["operations"]`). The one spelling — the protocol's absence answer for
|
|
90
99
|
* `/_transactions` is this envelope too.
|
|
91
100
|
*/
|
|
92
|
-
export declare function transactionsUnavailableFailure():
|
|
101
|
+
export declare function transactionsUnavailableFailure(): AvOperationFailureResponse;
|
|
93
102
|
/**
|
|
94
103
|
* Whole-plan Framework Validation Layer for transaction structure and identity.
|
|
95
104
|
*/
|
|
96
|
-
export declare function validateTransactionPlan<M extends
|
|
105
|
+
export declare function validateTransactionPlan<M extends AvAdapterModel>(dependencies: TransactionPlanDependencies<M>, request: FrameworkTransactionRequest, origins?: readonly TransactionOperationOrigin[], planArguments?: PlanArguments): Promise<TransactionPlanValidationResult>;
|