@aventara/core 0.1.0-pilot.4 → 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 +1478 -0
- package/README.md +275 -11
- 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 +17 -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 -25
- 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/avz/avz.js +354 -0
- package/dist/avz/index.d.ts +7 -0
- package/dist/avz/index.js +1 -0
- package/dist/avz/json-shape.registry.d.ts +22 -0
- package/dist/avz/json-shape.registry.js +16 -0
- package/dist/avz/zod-issue.translator.d.ts +57 -0
- package/dist/avz/zod-issue.translator.js +149 -0
- package/dist/compiler/contract-compiler-diagnostic.d.ts +37 -5
- package/dist/compiler/contract.compiler.d.ts +18 -18
- package/dist/compiler/contract.compiler.js +595 -421
- 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 +75 -29
- package/dist/config/config.resolver.js +109 -44
- package/dist/config/config.validator.d.ts +7 -7
- package/dist/config/config.validator.js +586 -71
- 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 +111 -37
- 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 +344 -29
- package/dist/contracts/client-contract-structure.validator.js +248 -7
- package/dist/contracts/contract-canonicalizer.d.ts +19 -3
- package/dist/contracts/contract-canonicalizer.js +172 -27
- 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 +31 -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 +61 -41
- package/dist/contracts/identifier.d.ts +4 -4
- package/dist/contracts/json-shape.d.ts +76 -0
- package/dist/contracts/json-shape.js +1 -0
- package/dist/contracts/lifecycle-trait.d.ts +2 -2
- package/dist/contracts/reference-write-limit.d.ts +7 -0
- package/dist/contracts/reference-write-limit.js +1 -0
- 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 +25 -14
- 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 +234 -63
- 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 +50 -24
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +95 -32
- package/dist/framework/operation-facade.d.ts +123 -52
- package/dist/framework/operation-facade.js +9 -1
- package/dist/index.d.ts +55 -82
- package/dist/index.js +6 -26
- package/dist/internal.d.ts +40 -0
- package/dist/internal.js +18 -0
- package/dist/operations/operation-arguments.d.ts +316 -201
- package/dist/operations/operation-call.d.ts +27 -28
- package/dist/operations/operation-identity.d.ts +12 -10
- package/dist/operations/operation-identity.js +3 -0
- 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 +41 -12
- package/dist/operations/operation-validator.d.ts +24 -9
- package/dist/operations/operation-validator.js +26 -10
- package/dist/operations/projection-scope.resolver.d.ts +7 -7
- package/dist/operations/structural-limits.walker.d.ts +19 -0
- package/dist/operations/structural-limits.walker.js +489 -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 -11
- package/dist/protocol/absent-route.responder.js +42 -16
- 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 +23 -13
- package/dist/protocol/http-request.decoder.js +19 -11
- 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 +52 -27
- package/dist/protocol/protocol.binder.js +14 -9
- package/dist/protocol/protocol.handler.d.ts +28 -15
- package/dist/protocol/protocol.handler.js +55 -10
- package/dist/protocol/unmounted-route.error.d.ts +19 -0
- package/dist/protocol/unmounted-route.error.js +10 -0
- package/dist/runtime/caller-data.copier.d.ts +59 -0
- package/dist/runtime/caller-data.copier.js +470 -0
- package/dist/runtime/caller-data.door.d.ts +56 -0
- package/dist/runtime/caller-data.door.js +67 -0
- package/dist/runtime/computed-read-runtime.d.ts +7 -6
- package/dist/runtime/computed-read-runtime.js +61 -55
- package/dist/runtime/computed-value.error.d.ts +13 -0
- package/dist/runtime/computed-value.error.js +9 -0
- 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 +22 -57
- package/dist/runtime/create-requirement.js +140 -37
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +1 -1
- package/dist/runtime/diagnostics-reporter.d.ts +64 -22
- package/dist/runtime/diagnostics-reporter.js +35 -4
- package/dist/runtime/error-boundary.d.ts +73 -8
- package/dist/runtime/error-boundary.js +104 -48
- 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 +79 -7
- 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 +32 -0
- package/dist/runtime/misuse-reporter.js +19 -0
- package/dist/runtime/mutation-planner.d.ts +19 -10
- package/dist/runtime/mutation-planner.js +62 -36
- 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 +35 -15
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +125 -30
- package/dist/runtime/operation-runtime.js +423 -83
- package/dist/runtime/outcome-mapper.d.ts +16 -5
- package/dist/runtime/outcome-mapper.js +35 -8
- package/dist/runtime/output-validator.d.ts +16 -6
- package/dist/runtime/output-validator.js +12 -1
- package/dist/runtime/owned-execution.registry.d.ts +13 -0
- package/dist/runtime/owned-execution.registry.js +7 -0
- 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 +202 -28
- package/dist/runtime/readonly-value.d.ts +32 -0
- package/dist/runtime/readonly-value.js +141 -0
- package/dist/runtime/referential-action.d.ts +7 -0
- package/dist/runtime/request-envelope.validator.d.ts +5 -0
- package/dist/runtime/request-envelope.validator.js +123 -0
- 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 +56 -13
- package/dist/runtime/scalar-runtime.js +167 -86
- 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 +23 -9
- package/dist/transactions/transaction-plan-assembler.js +195 -82
- package/dist/transactions/transaction-plan-validator.d.ts +53 -21
- package/dist/transactions/transaction-plan-validator.js +246 -163
- package/dist/transactions/transaction-reference-collector.d.ts +30 -0
- package/dist/transactions/transaction-reference-collector.js +204 -0
- package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
- package/dist/transactions/transaction-reference-resolver.js +27 -10
- package/dist/transactions/transaction-reference-validator.d.ts +34 -4
- package/dist/transactions/transaction-reference-validator.js +82 -43
- package/dist/transactions/transaction-reference.d.ts +30 -58
- package/dist/transactions/transaction-request.d.ts +20 -7
- package/dist/transactions/transaction-response.d.ts +12 -7
- package/dist/transactions/transaction-response.js +24 -1
- package/dist/transactions/transaction-runtime.d.ts +11 -8
- package/dist/transactions/transaction-runtime.js +167 -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 +18 -3
- package/src/runtime/field-check.evaluator.ts +720 -0
- package/dist/config/define-fields.d.ts +0 -35
- 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 -36
- package/dist/config/framework-restrictions-config.d.ts +0 -142
- package/dist/operations/operation-boolean-nodes.d.ts +0 -11
- package/dist/operations/operation-boolean-nodes.js +0 -283
- package/dist/operations/operation-nesting.d.ts +0 -8
- package/dist/operations/operation-nesting.js +0 -307
- 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/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
- /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
|
@@ -1,17 +1,75 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { lookupField,
|
|
1
|
+
import { AvCanonicalJsonError } from "../contracts/contract-canonicalizer.js";
|
|
2
|
+
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
3
3
|
import { parseOperationIdentity } from "../operations/operation-identity.js";
|
|
4
|
+
import { findOperationAvailabilityIssue, operationUnavailableIssue, unavailableOperationKey, } from "../operations/operation-validator.js";
|
|
5
|
+
import { resourceUnavailableIssue } from "../operations/operation-validator-core.js";
|
|
4
6
|
import { VALIDATION_CODE_MESSAGES, validationIssue, } from "../operations/validation-code.js";
|
|
7
|
+
import { AvCallerDataError, locateCallerDataError, } from "../runtime/caller-data.copier.js";
|
|
8
|
+
import { copyAtDoor, misuseIdentityOf, refuseCallerData, } from "../runtime/caller-data.door.js";
|
|
5
9
|
import { planReadOperation, } from "../runtime/computed-read-runtime.js";
|
|
6
|
-
import {
|
|
10
|
+
import { planOperationArgumentsPath, planStepPath, } from "../runtime/error-boundary.js";
|
|
11
|
+
import { createMisuseReporter } from "../runtime/misuse-reporter.js";
|
|
7
12
|
import { operationFailure } from "../runtime/operation-response.js";
|
|
8
13
|
import { activeContract, validateOperationRequest, validateProtocolIdentity, } from "../runtime/operation-runtime.js";
|
|
14
|
+
import { mapValidationOutcome, VALIDATION_OUTCOME_MESSAGES, } from "../runtime/outcome-mapper.js";
|
|
9
15
|
import { encodeOperationArgumentsForWire } from "./operation-arguments-encoder.js";
|
|
10
16
|
import { computeOperationFingerprint, isOperationFingerprint, } from "./operation-fingerprint.js";
|
|
17
|
+
import { validateSqlStatement } from "./sql-statement.validator.js";
|
|
11
18
|
import { inspectTransactionEnvelope, inspectTransactionOperationEntry, inspectTransactionOperations, } from "./transaction-envelope.js";
|
|
12
|
-
import { routeTransactionReferenceCandidate } from "./transaction-reference.js";
|
|
19
|
+
import { routeTransactionReferenceCandidate, } from "./transaction-reference.js";
|
|
20
|
+
import { collectTransactionReferenceCandidates, } from "./transaction-reference-collector.js";
|
|
13
21
|
import { validateTransactionReferences } from "./transaction-reference-validator.js";
|
|
14
22
|
import { transactionOperationFailure } from "./transaction-response.js";
|
|
23
|
+
const CALLER_PLAN = { source: "caller" };
|
|
24
|
+
const STEP_ARGUMENTS_POLICY = {
|
|
25
|
+
mirror: (value) => Object.hasOwn(value, "$ref"),
|
|
26
|
+
};
|
|
27
|
+
function captureSteps(operations, operationCount, planArguments) {
|
|
28
|
+
const steps = [];
|
|
29
|
+
const statements = planArguments.source === "owned" ? planArguments.statements : undefined;
|
|
30
|
+
for (let index = 0; index < operationCount; index += 1) {
|
|
31
|
+
const statement = statements?.get(index);
|
|
32
|
+
if (statement !== undefined) {
|
|
33
|
+
steps.push({ ok: true, kind: "sql", statement });
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const operationEntry = inspectTransactionOperationEntry(operations, index);
|
|
37
|
+
if (!operationEntry.ok) {
|
|
38
|
+
steps.push({
|
|
39
|
+
ok: false,
|
|
40
|
+
response: structuralFailure(operationEntry.issue),
|
|
41
|
+
});
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
const nodeEnvelope = inspectTransactionEnvelope(operationEntry.value, {
|
|
45
|
+
required: OPERATION_KEYS,
|
|
46
|
+
invalidContainerPath: [],
|
|
47
|
+
invalidContainerMessage: "Operation node must be an object.",
|
|
48
|
+
});
|
|
49
|
+
if (!nodeEnvelope.ok) {
|
|
50
|
+
steps.push({
|
|
51
|
+
ok: false,
|
|
52
|
+
response: structuralFailure(nodeEnvelope.issue, index),
|
|
53
|
+
});
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
const node = nodeEnvelope.values;
|
|
57
|
+
const args = node.get("args");
|
|
58
|
+
const refused = planArguments.source === "owned"
|
|
59
|
+
? planArguments.refused?.get(index)
|
|
60
|
+
: undefined;
|
|
61
|
+
const copy = refused !== undefined
|
|
62
|
+
? { ok: false, error: refused }
|
|
63
|
+
: planArguments.source === "owned"
|
|
64
|
+
? { ok: true, value: args }
|
|
65
|
+
: copyAtDoor(args, STEP_ARGUMENTS_POLICY);
|
|
66
|
+
steps.push({ ok: true, kind: "operation", node, args: copy });
|
|
67
|
+
if (!copy.ok) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return steps;
|
|
72
|
+
}
|
|
15
73
|
const PLAN_KEYS = ["operations"];
|
|
16
74
|
const OPERATION_KEYS = [
|
|
17
75
|
"resource",
|
|
@@ -23,25 +81,44 @@ const OPERATION_KEYS = [
|
|
|
23
81
|
function isObject(value) {
|
|
24
82
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
83
|
}
|
|
84
|
+
function operationKeyFailure(contract, step, operation) {
|
|
85
|
+
const { resource, family, variant } = step;
|
|
86
|
+
const issue = typeof family === "string" && typeof variant === "string"
|
|
87
|
+
? operationUnavailableIssue(contract, { resource, family, variant })
|
|
88
|
+
: validationIssue("V1006", [
|
|
89
|
+
typeof family === "string"
|
|
90
|
+
? unavailableOperationKey(contract, { resource, family })
|
|
91
|
+
: "family",
|
|
92
|
+
], `Operation is not available on Resource "${resource}".`);
|
|
93
|
+
return transactionOperationFailure(mapValidationOutcome([issue]), operation);
|
|
94
|
+
}
|
|
26
95
|
function structuralFailure(rejection, operation) {
|
|
27
96
|
return operationFailure("A2004", {
|
|
28
97
|
message: "Transaction plan failed framework validation.",
|
|
29
|
-
issues: [
|
|
98
|
+
issues: [
|
|
99
|
+
operation === undefined || rejection.path === undefined
|
|
100
|
+
? rejection
|
|
101
|
+
: {
|
|
102
|
+
...rejection,
|
|
103
|
+
path: [...planStepPath(operation), ...rejection.path],
|
|
104
|
+
},
|
|
105
|
+
],
|
|
30
106
|
...(operation === undefined ? {} : { operation }),
|
|
31
107
|
});
|
|
32
108
|
}
|
|
33
|
-
function syntheticRequest(origin,
|
|
109
|
+
function syntheticRequest(origin, request, resource, identity, args) {
|
|
34
110
|
const common = {
|
|
35
|
-
requestId,
|
|
111
|
+
requestId: request.requestId,
|
|
112
|
+
...(request.state === undefined ? {} : { state: request.state }),
|
|
36
113
|
resource,
|
|
37
114
|
...identity,
|
|
38
115
|
arguments: args,
|
|
39
116
|
};
|
|
40
|
-
return origin.
|
|
41
|
-
? { ...common,
|
|
117
|
+
return origin.origin === "application"
|
|
118
|
+
? { ...common, origin: "application" }
|
|
42
119
|
: {
|
|
43
120
|
...common,
|
|
44
|
-
|
|
121
|
+
origin: origin.origin,
|
|
45
122
|
protocol: origin.protocol,
|
|
46
123
|
...(origin.transport === undefined
|
|
47
124
|
? {}
|
|
@@ -49,10 +126,10 @@ function syntheticRequest(origin, requestId, resource, identity, args) {
|
|
|
49
126
|
};
|
|
50
127
|
}
|
|
51
128
|
function requestOrigin(request) {
|
|
52
|
-
return request.
|
|
53
|
-
? {
|
|
129
|
+
return request.origin === "application"
|
|
130
|
+
? { origin: "application" }
|
|
54
131
|
: {
|
|
55
|
-
|
|
132
|
+
origin: request.origin,
|
|
56
133
|
protocol: request.protocol,
|
|
57
134
|
...(request.transport === undefined
|
|
58
135
|
? {}
|
|
@@ -60,55 +137,27 @@ function requestOrigin(request) {
|
|
|
60
137
|
};
|
|
61
138
|
}
|
|
62
139
|
function originContracts(contracts, origins) {
|
|
63
|
-
const layers = new Set(origins.map((origin) => origin
|
|
64
|
-
return [...layers].map((
|
|
140
|
+
const layers = new Set(origins.map(({ origin }) => origin));
|
|
141
|
+
return [...layers].map((origin) => contracts[origin]);
|
|
65
142
|
}
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function collectCandidates(contract, request, index, args) {
|
|
84
|
-
const candidates = [];
|
|
85
|
-
const root = planOperationArgumentsPath(index);
|
|
86
|
-
if (request.family === "create") {
|
|
87
|
-
const data = lookupOwn(args, "data");
|
|
88
|
-
if (request.variant === "many" || request.variant === "count") {
|
|
89
|
-
if (Array.isArray(data)) {
|
|
90
|
-
data.forEach((entry, dataIndex) => {
|
|
91
|
-
collectDataCandidates(contract, request.resource, entry, [...root, "data", dataIndex], candidates);
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
collectDataCandidates(contract, request.resource, data, [...root, "data"], candidates);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
else if (request.family === "update") {
|
|
100
|
-
collectDataCandidates(contract, request.resource, lookupOwn(args, "data"), [...root, "data"], candidates);
|
|
101
|
-
}
|
|
102
|
-
else if (request.family === "upsert") {
|
|
103
|
-
for (const stage of ["create", "update"]) {
|
|
104
|
-
collectDataCandidates(contract, request.resource, lookupOwn(args, stage), [...root, stage], candidates);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return candidates;
|
|
143
|
+
function mixedOriginFailure(origins) {
|
|
144
|
+
const [first] = origins ?? [];
|
|
145
|
+
const other = first === undefined
|
|
146
|
+
? -1
|
|
147
|
+
: (origins ?? []).findIndex(({ origin }) => origin !== first.origin);
|
|
148
|
+
return other === -1
|
|
149
|
+
? undefined
|
|
150
|
+
: transactionOperationFailure(operationFailure("A2004", {
|
|
151
|
+
message: "Transaction plan failed framework validation.",
|
|
152
|
+
issues: [
|
|
153
|
+
validationIssue("V1020", [], VALIDATION_CODE_MESSAGES.V1020),
|
|
154
|
+
],
|
|
155
|
+
}), other);
|
|
108
156
|
}
|
|
109
157
|
function* relationTraversals(contract, resourceName, value, path) {
|
|
110
158
|
const resource = lookupResource(contract, resourceName);
|
|
111
|
-
if (resource === undefined
|
|
159
|
+
if (resource === undefined ||
|
|
160
|
+
routeTransactionReferenceCandidate(value).kind !== "ordinary") {
|
|
112
161
|
return;
|
|
113
162
|
}
|
|
114
163
|
if (Array.isArray(value)) {
|
|
@@ -182,11 +231,15 @@ export function transactionsUnavailableFailure() {
|
|
|
182
231
|
issues: [validationIssue("V1006", ["operations"], message)],
|
|
183
232
|
});
|
|
184
233
|
}
|
|
185
|
-
export async function validateTransactionPlan(dependencies, request, origins) {
|
|
234
|
+
export async function validateTransactionPlan(dependencies, request, origins, planArguments = CALLER_PLAN) {
|
|
186
235
|
const protocolFailure = validateProtocolIdentity(dependencies.contracts, request);
|
|
187
236
|
if (protocolFailure !== undefined) {
|
|
188
237
|
return { ok: false, response: protocolFailure };
|
|
189
238
|
}
|
|
239
|
+
const mixed = mixedOriginFailure(origins);
|
|
240
|
+
if (mixed !== undefined) {
|
|
241
|
+
return { ok: false, response: mixed };
|
|
242
|
+
}
|
|
190
243
|
const ownOrigin = requestOrigin(request);
|
|
191
244
|
const originOf = (index) => origins?.[index] ?? ownOrigin;
|
|
192
245
|
const planContracts = origins === undefined || origins.length === 0
|
|
@@ -229,38 +282,37 @@ export async function validateTransactionPlan(dependencies, request, origins) {
|
|
|
229
282
|
}),
|
|
230
283
|
};
|
|
231
284
|
}
|
|
285
|
+
const steps = captureSteps(operations, operationCount, planArguments);
|
|
286
|
+
const misuse = createMisuseReporter(dependencies.config.misuse);
|
|
232
287
|
const validated = [];
|
|
233
288
|
const cascaded = new Set();
|
|
234
289
|
for (let index = 0; index < operationCount; index += 1) {
|
|
235
|
-
const
|
|
236
|
-
if (!
|
|
237
|
-
return {
|
|
238
|
-
ok: false,
|
|
239
|
-
response: structuralFailure(operationEntry.issue),
|
|
240
|
-
};
|
|
290
|
+
const step = steps[index];
|
|
291
|
+
if (!step.ok) {
|
|
292
|
+
return { ok: false, response: step.response };
|
|
241
293
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
294
|
+
if (step.kind === "sql") {
|
|
295
|
+
const statement = validateSqlStatement(step.statement, {
|
|
296
|
+
index,
|
|
297
|
+
earlier: validated,
|
|
298
|
+
available: dependencies.sqlStatements,
|
|
299
|
+
misuse,
|
|
300
|
+
});
|
|
301
|
+
if (!statement.ok) {
|
|
302
|
+
return statement;
|
|
303
|
+
}
|
|
304
|
+
validated.push(statement.statement);
|
|
305
|
+
continue;
|
|
252
306
|
}
|
|
253
|
-
const node =
|
|
307
|
+
const node = step.node;
|
|
254
308
|
const origin = originOf(index);
|
|
255
|
-
const contract = origin.
|
|
256
|
-
? dependencies.contracts.application
|
|
257
|
-
: dependencies.contracts.client;
|
|
309
|
+
const contract = dependencies.contracts[origin.origin];
|
|
258
310
|
const resourceValue = node.get("resource");
|
|
259
311
|
if (typeof resourceValue !== "string") {
|
|
260
312
|
return {
|
|
261
313
|
ok: false,
|
|
262
314
|
response: transactionOperationFailure(operationFailure("A2001", {
|
|
263
|
-
message:
|
|
315
|
+
message: VALIDATION_OUTCOME_MESSAGES.A2001,
|
|
264
316
|
issues: [
|
|
265
317
|
validationIssue("V1001", ["resource"], "resource must be a string."),
|
|
266
318
|
],
|
|
@@ -270,12 +322,7 @@ export async function validateTransactionPlan(dependencies, request, origins) {
|
|
|
270
322
|
if (lookupResource(contract, resourceValue) === undefined) {
|
|
271
323
|
return {
|
|
272
324
|
ok: false,
|
|
273
|
-
response: transactionOperationFailure(
|
|
274
|
-
message: "Operation arguments failed framework validation.",
|
|
275
|
-
issues: [
|
|
276
|
-
validationIssue("V1005", ["resource"], `Resource "${resourceValue}" is not available in the active Contract.`),
|
|
277
|
-
],
|
|
278
|
-
}), index),
|
|
325
|
+
response: transactionOperationFailure(mapValidationOutcome([resourceUnavailableIssue(resourceValue)]), index),
|
|
279
326
|
};
|
|
280
327
|
}
|
|
281
328
|
const family = node.get("family");
|
|
@@ -286,100 +333,136 @@ export async function validateTransactionPlan(dependencies, request, origins) {
|
|
|
286
333
|
if (identity === undefined) {
|
|
287
334
|
return {
|
|
288
335
|
ok: false,
|
|
289
|
-
response:
|
|
290
|
-
message: "Operation arguments failed framework validation.",
|
|
291
|
-
issues: [
|
|
292
|
-
validationIssue("V1006", ["operation"], "Operation is not part of the standard operation grammar."),
|
|
293
|
-
],
|
|
294
|
-
}), index),
|
|
336
|
+
response: operationKeyFailure(contract, { resource: resourceValue, family, variant }, index),
|
|
295
337
|
};
|
|
296
338
|
}
|
|
297
|
-
const
|
|
298
|
-
const
|
|
299
|
-
if (
|
|
339
|
+
const stepRequest = { resource: resourceValue, ...identity };
|
|
340
|
+
const unavailable = findOperationAvailabilityIssue(contract, stepRequest);
|
|
341
|
+
if (unavailable !== undefined) {
|
|
300
342
|
return {
|
|
301
343
|
ok: false,
|
|
302
|
-
response: transactionOperationFailure(
|
|
344
|
+
response: transactionOperationFailure(mapValidationOutcome([unavailable]), index),
|
|
303
345
|
};
|
|
304
346
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
347
|
+
if (!step.args.ok) {
|
|
348
|
+
return {
|
|
349
|
+
ok: false,
|
|
350
|
+
response: transactionOperationFailure(mapValidationOutcome([
|
|
351
|
+
refuseCallerData(step.args.error, planOperationArgumentsPath(index), {
|
|
352
|
+
...misuseIdentityOf({
|
|
353
|
+
...stepRequest,
|
|
354
|
+
origin: origin.origin,
|
|
355
|
+
}),
|
|
356
|
+
operation: index,
|
|
357
|
+
}, misuse),
|
|
358
|
+
]), index),
|
|
359
|
+
};
|
|
318
360
|
}
|
|
319
|
-
const validatedRequest = {
|
|
320
|
-
...candidate.request,
|
|
321
|
-
arguments: referenceValidation.requestArguments,
|
|
322
|
-
};
|
|
323
|
-
const validatedArguments = referenceValidation.arguments;
|
|
324
|
-
const wireArguments = origin.scope === "client"
|
|
325
|
-
? validatedRequest.arguments
|
|
326
|
-
: encodeOperationArgumentsForWire(contract, validatedRequest, validatedArguments);
|
|
327
|
-
let fingerprint;
|
|
328
361
|
try {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
362
|
+
const operationRequest = syntheticRequest(origin, request, resourceValue, identity, step.args.value);
|
|
363
|
+
const operationValidation = validateOperationRequest(contract, operationRequest, { transactionReferences: true });
|
|
364
|
+
if (!operationValidation.ok) {
|
|
365
|
+
return {
|
|
366
|
+
ok: false,
|
|
367
|
+
response: transactionOperationFailure(operationValidation.response, index),
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
const candidate = {
|
|
371
|
+
index,
|
|
372
|
+
request: operationRequest,
|
|
373
|
+
arguments: operationValidation.arguments,
|
|
374
|
+
projection: planReadOperation(dependencies.contracts.core, dependencies.config.adapter.model, contract, dependencies.config[origin.origin].compute, operationRequest, operationValidation.arguments).projection,
|
|
375
|
+
declaredFingerprint: node.get("fingerprint"),
|
|
376
|
+
candidates: collectTransactionReferenceCandidates(contract, operationRequest, index, operationValidation.arguments),
|
|
377
|
+
};
|
|
378
|
+
const referenceValidation = validateTransactionReferences(candidate, validated);
|
|
379
|
+
if (!referenceValidation.ok) {
|
|
380
|
+
return referenceValidation;
|
|
381
|
+
}
|
|
382
|
+
const validatedRequest = {
|
|
383
|
+
...candidate.request,
|
|
384
|
+
arguments: referenceValidation.requestArguments,
|
|
385
|
+
};
|
|
386
|
+
const validatedArguments = referenceValidation.arguments;
|
|
387
|
+
const wireArguments = origin.origin !== "application"
|
|
388
|
+
? validatedRequest.arguments
|
|
389
|
+
: encodeOperationArgumentsForWire(contract, validatedRequest, validatedArguments);
|
|
390
|
+
let fingerprint;
|
|
391
|
+
try {
|
|
392
|
+
fingerprint = await computeOperationFingerprint({
|
|
393
|
+
resource: validatedRequest.resource,
|
|
394
|
+
family: validatedRequest.family,
|
|
395
|
+
variant: validatedRequest.variant,
|
|
396
|
+
args: wireArguments,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
if (!(error instanceof AvCanonicalJsonError)) {
|
|
401
|
+
throw error;
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
ok: false,
|
|
405
|
+
response: structuralFailure(validationIssue("V1001", ["args"], "Invalid runtime/wire type."), index),
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
if (!isOperationFingerprint(candidate.declaredFingerprint) ||
|
|
409
|
+
candidate.declaredFingerprint !== fingerprint) {
|
|
410
|
+
return {
|
|
411
|
+
ok: false,
|
|
412
|
+
response: transactionOperationFailure(operationFailure("A2007", {
|
|
413
|
+
message: "Operation fingerprint does not match its arguments.",
|
|
414
|
+
issues: [
|
|
415
|
+
validationIssue("V1017", ["fingerprint"], "Operation fingerprint does not match its arguments."),
|
|
416
|
+
],
|
|
417
|
+
}), index),
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
const dependency = cascadeDependency(contract, validatedRequest, index, cascaded);
|
|
421
|
+
if (dependency !== undefined) {
|
|
422
|
+
return {
|
|
423
|
+
ok: false,
|
|
424
|
+
response: transactionOperationFailure(operationFailure("A2004", {
|
|
425
|
+
message: "Transaction plan failed framework validation.",
|
|
426
|
+
issues: [
|
|
427
|
+
validationIssue("V1019", dependency, VALIDATION_CODE_MESSAGES.V1019),
|
|
428
|
+
],
|
|
429
|
+
}), index),
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
for (const resource of deletedResources(contract, validatedRequest, index)) {
|
|
433
|
+
for (const removed of dependencies.cascades(resource)) {
|
|
434
|
+
cascaded.add(removed);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
validated.push({
|
|
438
|
+
kind: "operation",
|
|
439
|
+
index: candidate.index,
|
|
440
|
+
request: validatedRequest,
|
|
441
|
+
contract,
|
|
442
|
+
arguments: validatedArguments,
|
|
443
|
+
projection: candidate.projection,
|
|
444
|
+
fingerprint,
|
|
445
|
+
references: referenceValidation.references,
|
|
334
446
|
});
|
|
335
447
|
}
|
|
336
448
|
catch (error) {
|
|
337
|
-
if (!(error instanceof
|
|
449
|
+
if (!(error instanceof AvCallerDataError)) {
|
|
338
450
|
throw error;
|
|
339
451
|
}
|
|
340
452
|
return {
|
|
341
453
|
ok: false,
|
|
342
|
-
response:
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
validationIssue("V1017", ["fingerprint"], "Operation fingerprint does not match its arguments."),
|
|
353
|
-
],
|
|
354
|
-
}), index),
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
const dependency = cascadeDependency(contract, validatedRequest, index, cascaded);
|
|
358
|
-
if (dependency !== undefined) {
|
|
359
|
-
return {
|
|
360
|
-
ok: false,
|
|
361
|
-
response: transactionOperationFailure(operationFailure("A2004", {
|
|
362
|
-
message: "Transaction plan failed framework validation.",
|
|
363
|
-
issues: [
|
|
364
|
-
validationIssue("V1019", dependency, VALIDATION_CODE_MESSAGES.V1019),
|
|
365
|
-
],
|
|
366
|
-
}), index),
|
|
454
|
+
response: transactionOperationFailure(mapValidationOutcome([
|
|
455
|
+
refuseCallerData(locateCallerDataError(error, step.args.value), planOperationArgumentsPath(index), {
|
|
456
|
+
...misuseIdentityOf({
|
|
457
|
+
resource: resourceValue,
|
|
458
|
+
...identity,
|
|
459
|
+
origin: origin.origin,
|
|
460
|
+
}),
|
|
461
|
+
operation: index,
|
|
462
|
+
}, misuse),
|
|
463
|
+
]), index),
|
|
367
464
|
};
|
|
368
465
|
}
|
|
369
|
-
for (const resource of deletedResources(contract, validatedRequest, index)) {
|
|
370
|
-
for (const removed of dependencies.cascades(resource)) {
|
|
371
|
-
cascaded.add(removed);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
validated.push({
|
|
375
|
-
index: candidate.index,
|
|
376
|
-
request: validatedRequest,
|
|
377
|
-
contract,
|
|
378
|
-
arguments: validatedArguments,
|
|
379
|
-
projection: candidate.projection,
|
|
380
|
-
fingerprint,
|
|
381
|
-
references: referenceValidation.references,
|
|
382
|
-
});
|
|
383
466
|
}
|
|
384
467
|
return { ok: true, plan: { operations: validated } };
|
|
385
468
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import type { AvScalarField } from "../contracts/field.js";
|
|
3
|
+
import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
4
|
+
import type { SemanticOperationArguments } from "../operations/operation-validator.js";
|
|
5
|
+
import { type TransactionSlotShape } from "./transaction-reference.js";
|
|
6
|
+
type Path = readonly (string | number)[];
|
|
7
|
+
/** One `$ref` candidate found at a reference position, before it is validated. */
|
|
8
|
+
export type TransactionReferenceCandidateSlot = {
|
|
9
|
+
readonly path: Path;
|
|
10
|
+
readonly field: AvScalarField<AvContract>;
|
|
11
|
+
readonly shape: TransactionSlotShape;
|
|
12
|
+
/** The slot is a scalar value of mutation data: what it resolves to is written. */
|
|
13
|
+
readonly written: boolean;
|
|
14
|
+
readonly candidate: unknown;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Every `$ref` candidate at a reference position of one validated operation, with the
|
|
18
|
+
* full wire path, the destination field and the slot's shape. The positions: mutation
|
|
19
|
+
* data (`create`'s `data`, each `data[]` entry of a bulk create, `update`'s `data`,
|
|
20
|
+
* `upsert`'s `create`/`update`) at any depth — its scalar values, the unique keys its
|
|
21
|
+
* relation directives name, the `where` of `$update`/`$delete`/`$upsert`, and the data
|
|
22
|
+
* they nest — the `cursor`, and the step's own `where` at any depth.
|
|
23
|
+
*
|
|
24
|
+
* It reads the validated argument view, whose normalization keeps every key where
|
|
25
|
+
* the caller wrote it, so a slot path names the same member of the wire view.
|
|
26
|
+
*/
|
|
27
|
+
export declare function collectTransactionReferenceCandidates(contract: AvContract, request: AvOperationIdentity & {
|
|
28
|
+
readonly resource: string;
|
|
29
|
+
}, index: number, args: SemanticOperationArguments): readonly TransactionReferenceCandidateSlot[];
|
|
30
|
+
export {};
|