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