@aventara/core 1.0.0-rc.0 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1434 -0
- package/ERRORS.md +142 -0
- package/README.md +247 -57
- package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
- 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 +25 -11
- package/dist/adapters/adapter-identifier.d.ts +6 -6
- package/dist/adapters/adapter-model.d.ts +18 -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 +59 -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-diagnostic.guidance.d.ts +6 -0
- package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
- package/dist/compiler/contract.compiler.d.ts +18 -18
- package/dist/compiler/contract.compiler.js +637 -442
- 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/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +80 -0
- package/dist/config/config-diagnostic.d.ts +11 -4
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- 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 +308 -0
- package/dist/config/field-compute.resolver.d.ts +21 -0
- package/dist/config/field-compute.resolver.js +123 -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 -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 +122 -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 +21 -12
- package/dist/contracts/capability.js +2 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +388 -63
- package/dist/contracts/client-contract-structure.validator.js +156 -10
- package/dist/contracts/contract-canonicalizer.d.ts +26 -3
- package/dist/contracts/contract-canonicalizer.js +156 -29
- 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 +81 -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 +19 -10
- package/dist/framework/framework-construction.error.js +7 -3
- package/dist/framework/framework.d.ts +47 -23
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +49 -22
- package/dist/framework/operation-facade.d.ts +123 -52
- package/dist/framework/operation-facade.js +9 -1
- package/dist/index.d.ts +57 -50
- package/dist/index.js +7 -6
- package/dist/internal.d.ts +17 -10
- package/dist/internal.js +4 -1
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +343 -207
- 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 +99 -6
- 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.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/validation-code.js +4 -0
- package/dist/operations/write-scope.resolver.d.ts +10 -6
- package/dist/operations/write-scope.resolver.js +2 -0
- 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 +91 -17
- 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 +22 -5
- package/dist/runtime/caller-data.copier.js +31 -14
- package/dist/runtime/caller-data.door.d.ts +17 -11
- 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 +76 -50
- package/dist/runtime/computed-value.error.d.ts +7 -6
- package/dist/runtime/computed-value.error.js +5 -4
- 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 +44 -79
- package/dist/runtime/create-requirement.js +213 -73
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +1 -1
- package/dist/runtime/diagnostics-reporter.d.ts +54 -27
- package/dist/runtime/diagnostics-reporter.js +24 -0
- package/dist/runtime/error-boundary.d.ts +65 -8
- package/dist/runtime/error-boundary.js +49 -19
- 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 +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 +37 -0
- package/dist/runtime/field-stage.runtime.js +147 -0
- package/dist/runtime/field-validator.runtime.d.ts +19 -0
- package/dist/runtime/field-validator.runtime.js +92 -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 +11 -6
- package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
- package/dist/runtime/level-lifecycle.runtime.js +39 -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 +48 -35
- package/dist/runtime/nested-write.walker.d.ts +32 -0
- package/dist/runtime/nested-write.walker.js +73 -0
- 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 +33 -6
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +127 -25
- package/dist/runtime/operation-runtime.js +441 -78
- 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 +16 -6
- package/dist/runtime/pipe-output.validator.d.ts +43 -18
- package/dist/runtime/pipe-output.validator.js +15 -13
- package/dist/runtime/pipeline.d.ts +223 -34
- package/dist/runtime/readonly-value.d.ts +43 -0
- package/dist/runtime/readonly-value.js +150 -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 +35 -16
- package/dist/runtime/scalar-runtime.js +102 -34
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- 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/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +85 -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 +167 -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 +169 -32
- package/dist/transactions/transaction-plan-validator.d.ts +45 -20
- package/dist/transactions/transaction-plan-validator.js +96 -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 +76 -4
- package/dist/transactions/transaction-reference-validator.js +129 -71
- package/dist/transactions/transaction-reference.d.ts +13 -13
- package/dist/transactions/transaction-reference.js +5 -0
- 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 +191 -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 +82 -0
- package/dist/transactions/transaction-stage.runtime.js +126 -0
- package/package.json +9 -7
- 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
|
@@ -1,38 +1,154 @@
|
|
|
1
|
+
import { hasFieldValidators } from "../compiler/field-validator.compiler.js";
|
|
2
|
+
import { createComputedFields } from "../config/field-compute.resolver.js";
|
|
3
|
+
import { fieldStagesOf, isForcedOperation, nestedTargetLevels, operationLevels, rawPipelineTree, transactionLevelsOf, } from "../config/pipeline-tree.resolver.js";
|
|
1
4
|
import { AVENTARA_PROTOCOL_VERSION } from "../contracts/contract-protocol.js";
|
|
2
5
|
import { findOperationAvailabilityIssue, validateOperationArguments, } from "../operations/operation-validator.js";
|
|
6
|
+
import { transactionInfrastructureFailure } from "../transactions/transaction-response.js";
|
|
7
|
+
import { settleTransaction } from "../transactions/transaction-settlement.runtime.js";
|
|
8
|
+
import { TRANSACTION_PIPES, transactionFacts, } from "../transactions/transaction-stage.runtime.js";
|
|
3
9
|
import { copyAtDoor, misuseIdentityOf, refuseCallerData, } from "./caller-data.door.js";
|
|
4
10
|
import { materializeReadOperation, planReadOperation, } from "./computed-read-runtime.js";
|
|
5
|
-
import {
|
|
11
|
+
import { AvComputedValueError } from "./computed-value.error.js";
|
|
12
|
+
import { createContextExecutor, } from "./context-executor.runtime.js";
|
|
13
|
+
import { computedRequirementGapsOf, createRequirementIssues, preliminaryRecordIssues, recordWriteFactsOf, } from "./create-requirement.js";
|
|
14
|
+
import { createDiagnosticsReporter, } from "./diagnostics-reporter.js";
|
|
6
15
|
import { AdapterBoundary, OPERATION_ARGUMENTS_PATH, resolveOperationFailure, sanitizeOperationFailure, } from "./error-boundary.js";
|
|
16
|
+
import { planFieldStages } from "./field-stage.plan.js";
|
|
17
|
+
import { guardSentFields, pipeSentFields, valueAt, writeRecordPathsOf, } from "./field-stage.runtime.js";
|
|
18
|
+
import { fieldValidatorIssues } from "./field-validator.runtime.js";
|
|
19
|
+
import { thrownFailure } from "./framework-error.factory.js";
|
|
20
|
+
import { AvInterceptorNextError } from "./interceptor-next.error.js";
|
|
21
|
+
import { runLevelLifecycle, } from "./level-lifecycle.runtime.js";
|
|
7
22
|
import { createMisuseReporter, } from "./misuse-reporter.js";
|
|
8
|
-
import {
|
|
23
|
+
import { applyNestedWriteCompute, applyWriteCompute, stripVirtualMutationInput, } from "./mutation-planner.js";
|
|
24
|
+
import { nestedWriteTargetsOf, } from "./nested-write.walker.js";
|
|
9
25
|
import { internalFailure, operationFailure } from "./operation-response.js";
|
|
10
|
-
import { mapOperationOutcome, mapValidationOutcome } from "./outcome-mapper.js";
|
|
11
|
-
import {
|
|
12
|
-
import { refusePipeOutput } from "./pipe-output.validator.js";
|
|
26
|
+
import { mapOperationOutcome, mapValidationOutcome, uniqueMissFailure, } from "./outcome-mapper.js";
|
|
27
|
+
import { AvOutputValidationError, validateOperationOutput, } from "./output-validator.js";
|
|
28
|
+
import { AvPipeOutputError, PIPE_OUTPUT_FAILURE_MESSAGE, refusePipeOutput, refuseStageOutput, } from "./pipe-output.validator.js";
|
|
29
|
+
import { deepFreeze, frozenCopy } from "./readonly-value.js";
|
|
30
|
+
import { requestStateOf } from "./request-state.resolver.js";
|
|
13
31
|
import { normalizeOperationScalarValues, } from "./scalar-runtime.js";
|
|
32
|
+
import { withoutUnsentWriteValues } from "./unsent-value.normalizer.js";
|
|
33
|
+
function scopeOf(request, binding) {
|
|
34
|
+
return {
|
|
35
|
+
requestId: request.requestId,
|
|
36
|
+
transaction: binding?.kind === "transaction" ? binding.executor : undefined,
|
|
37
|
+
state: request.state,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function withRequestState(request) {
|
|
41
|
+
return { ...request, state: requestStateOf(request.state) };
|
|
42
|
+
}
|
|
43
|
+
export function createPipelineDependencies(dependencies, model) {
|
|
44
|
+
const misuse = createMisuseReporter(dependencies.config.misuse);
|
|
45
|
+
const recordWrites = recordWriteFactsOf({
|
|
46
|
+
...(dependencies.adapter.referentialActions === undefined
|
|
47
|
+
? {}
|
|
48
|
+
: { referentialActions: dependencies.adapter.referentialActions }),
|
|
49
|
+
model,
|
|
50
|
+
});
|
|
51
|
+
const contexts = createContextExecutor({
|
|
52
|
+
model,
|
|
53
|
+
adapter: dependencies.adapter,
|
|
54
|
+
application: dependencies.contracts.application,
|
|
55
|
+
diagnostics: dependencies.config.diagnostics,
|
|
56
|
+
misuse,
|
|
57
|
+
run: (request, transaction) => executeContextCall(raw, dependencies, request, transaction, misuse),
|
|
58
|
+
});
|
|
59
|
+
const { contracts, config } = dependencies;
|
|
60
|
+
const pipeline = {
|
|
61
|
+
contracts,
|
|
62
|
+
config,
|
|
63
|
+
recordWrites,
|
|
64
|
+
contexts,
|
|
65
|
+
fieldStages: {
|
|
66
|
+
application: planFieldStages(config.application.pipelines, contracts.application),
|
|
67
|
+
client: planFieldStages(config.client.pipelines, contracts.client),
|
|
68
|
+
agent: planFieldStages(config.agent.pipelines, contracts.agent),
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
const rawTree = rawPipelineTree(config.application.pipelines);
|
|
72
|
+
const raw = {
|
|
73
|
+
...pipeline,
|
|
74
|
+
config: {
|
|
75
|
+
...config,
|
|
76
|
+
application: { ...config.application, pipelines: rawTree },
|
|
77
|
+
},
|
|
78
|
+
fieldStages: {
|
|
79
|
+
...pipeline.fieldStages,
|
|
80
|
+
application: planFieldStages(rawTree, contracts.application),
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
return pipeline;
|
|
84
|
+
}
|
|
85
|
+
async function executeContextCall(raw, dependencies, request, transaction, misuse) {
|
|
86
|
+
const report = createDiagnosticsReporter(dependencies.config.diagnostics, request);
|
|
87
|
+
try {
|
|
88
|
+
let validated;
|
|
89
|
+
try {
|
|
90
|
+
validated = validateOperation(dependencies, request, "caller", misuse);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return sanitizeOperationFailure(error, "runtime", report, {
|
|
94
|
+
path: OPERATION_ARGUMENTS_PATH,
|
|
95
|
+
arguments: request.arguments,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (!validated.ok) {
|
|
99
|
+
return validated.response;
|
|
100
|
+
}
|
|
101
|
+
const stateful = withRequestState(request);
|
|
102
|
+
const admitted = await admitOperation(raw, stateful, validated.contract, validated.arguments, OPERATION_ARGUMENTS_PATH, report, {
|
|
103
|
+
requestId: request.requestId,
|
|
104
|
+
transaction,
|
|
105
|
+
state: stateful.state,
|
|
106
|
+
});
|
|
107
|
+
if (!admitted.ok) {
|
|
108
|
+
return admitted.response;
|
|
109
|
+
}
|
|
110
|
+
return await executeAdmittedOperation(raw, stateful, validated.contract, admitted.args, OPERATION_ARGUMENTS_PATH, transaction === undefined
|
|
111
|
+
? { kind: "standalone", executor: dependencies.adapter }
|
|
112
|
+
: { kind: "transaction", executor: transaction }, report);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
report(error, "A3000");
|
|
116
|
+
return internalFailure();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
14
119
|
export function activeContract(contracts, request) {
|
|
15
|
-
return request.origin
|
|
16
|
-
? contracts.application
|
|
17
|
-
: contracts.client;
|
|
120
|
+
return contracts[request.origin];
|
|
18
121
|
}
|
|
19
122
|
function activeScopeConfig(config, request) {
|
|
20
|
-
return request.origin
|
|
123
|
+
return config[request.origin];
|
|
21
124
|
}
|
|
22
|
-
function
|
|
125
|
+
function operationFacts(contract, request, args) {
|
|
23
126
|
return {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
args,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
127
|
+
$operation: {
|
|
128
|
+
resource: request.resource,
|
|
129
|
+
family: request.family,
|
|
130
|
+
variant: request.variant,
|
|
131
|
+
},
|
|
132
|
+
$args: frozenCopy(args),
|
|
133
|
+
$origin: request.origin,
|
|
134
|
+
$requestId: request.requestId,
|
|
135
|
+
$contract: contract,
|
|
136
|
+
...(request.origin !== "application" && request.transport !== undefined
|
|
137
|
+
? { $transport: request.transport }
|
|
33
138
|
: {}),
|
|
34
139
|
};
|
|
35
140
|
}
|
|
141
|
+
function nestedFacts(contract, request, target, payload) {
|
|
142
|
+
return {
|
|
143
|
+
...operationFacts(contract, request, payload),
|
|
144
|
+
$operation: {
|
|
145
|
+
resource: target.resource,
|
|
146
|
+
family: target.family,
|
|
147
|
+
variant: "one",
|
|
148
|
+
nested: true,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
36
152
|
function forbidden() {
|
|
37
153
|
return operationFailure("A4001", {
|
|
38
154
|
message: "Operation denied by a framework guard.",
|
|
@@ -48,16 +164,11 @@ function outputAccepted(contract, request, projection, data, report) {
|
|
|
48
164
|
return false;
|
|
49
165
|
}
|
|
50
166
|
if (!validation.ok) {
|
|
51
|
-
report(new
|
|
167
|
+
report(new AvOutputValidationError(request, validation.issues), "A3000");
|
|
52
168
|
}
|
|
53
169
|
return validation.ok;
|
|
54
170
|
}
|
|
55
|
-
export function createOperationRuntime(dependencies) {
|
|
56
|
-
const pipelineDependencies = {
|
|
57
|
-
contracts: dependencies.contracts,
|
|
58
|
-
config: dependencies.config,
|
|
59
|
-
recordWrites: recordWriteFactsOf(dependencies.adapter),
|
|
60
|
-
};
|
|
171
|
+
export function createOperationRuntime(dependencies, pipelineDependencies) {
|
|
61
172
|
const misuse = createMisuseReporter(dependencies.config.misuse);
|
|
62
173
|
return async (request, report, source) => {
|
|
63
174
|
let validated;
|
|
@@ -73,7 +184,20 @@ export function createOperationRuntime(dependencies) {
|
|
|
73
184
|
if (!validated.ok) {
|
|
74
185
|
return validated.response;
|
|
75
186
|
}
|
|
76
|
-
|
|
187
|
+
const stateful = withRequestState(request);
|
|
188
|
+
const forced = isForcedOperation(activeScopeConfig(dependencies.config, request).pipelines, request);
|
|
189
|
+
const admitted = await admitOperation(pipelineDependencies, stateful, validated.contract, validated.arguments, OPERATION_ARGUMENTS_PATH, report, {
|
|
190
|
+
requestId: request.requestId,
|
|
191
|
+
transaction: undefined,
|
|
192
|
+
state: stateful.state,
|
|
193
|
+
}, forced ? FORCED_CALL : SINGLE_CALL);
|
|
194
|
+
if (!admitted.ok) {
|
|
195
|
+
return admitted.response;
|
|
196
|
+
}
|
|
197
|
+
if (forced) {
|
|
198
|
+
return executeForcedOperation(pipelineDependencies, dependencies.adapter, stateful, validated.contract, admitted.args, report);
|
|
199
|
+
}
|
|
200
|
+
return executeAdmittedOperation(pipelineDependencies, stateful, validated.contract, admitted.args, OPERATION_ARGUMENTS_PATH, { kind: "standalone", executor: dependencies.adapter }, report);
|
|
77
201
|
};
|
|
78
202
|
}
|
|
79
203
|
function validateOperation(dependencies, request, source, misuse) {
|
|
@@ -83,9 +207,11 @@ function validateOperation(dependencies, request, source, misuse) {
|
|
|
83
207
|
}
|
|
84
208
|
const contract = activeContract(dependencies.contracts, request);
|
|
85
209
|
let owned = request;
|
|
86
|
-
if (source
|
|
210
|
+
if (source !== "owned" &&
|
|
87
211
|
findOperationAvailabilityIssue(contract, request) === undefined) {
|
|
88
|
-
const copy =
|
|
212
|
+
const copy = source === "caller"
|
|
213
|
+
? copyAtDoor(request.arguments)
|
|
214
|
+
: { ok: false, error: source.refused };
|
|
89
215
|
if (!copy.ok) {
|
|
90
216
|
return rejected(mapValidationOutcome([
|
|
91
217
|
refuseCallerData(copy.error, OPERATION_ARGUMENTS_PATH, misuseIdentityOf(request), misuse),
|
|
@@ -100,24 +226,32 @@ function validateOperation(dependencies, request, source, misuse) {
|
|
|
100
226
|
return { ok: true, contract, arguments: validation.arguments };
|
|
101
227
|
}
|
|
102
228
|
export function validateProtocolIdentity(contracts, request) {
|
|
103
|
-
return request.origin === "
|
|
104
|
-
?
|
|
105
|
-
:
|
|
229
|
+
return request.origin === "application"
|
|
230
|
+
? undefined
|
|
231
|
+
: protocolIdentityFailure(contracts, request.protocol, request.origin);
|
|
106
232
|
}
|
|
107
|
-
export function protocolIdentityFailure(contracts, protocol) {
|
|
233
|
+
export function protocolIdentityFailure(contracts, protocol, origin) {
|
|
108
234
|
if (protocol.version !== AVENTARA_PROTOCOL_VERSION) {
|
|
109
235
|
return operationFailure("A2006", {
|
|
110
236
|
message: "Aventara protocol version does not match the server.",
|
|
111
237
|
});
|
|
112
238
|
}
|
|
113
|
-
if (protocol.hash !== contracts.
|
|
239
|
+
if (protocol.hash !== contracts[origin].protocol.hash) {
|
|
114
240
|
return operationFailure("A2005", {
|
|
115
|
-
message:
|
|
241
|
+
message: origin === "client"
|
|
242
|
+
? "Generated client contract does not match the server. Regenerate the client."
|
|
243
|
+
: "Agent contract does not match the server. Rebuild the agent's tools from the current Agent Contract.",
|
|
116
244
|
});
|
|
117
245
|
}
|
|
118
246
|
return undefined;
|
|
119
247
|
}
|
|
120
248
|
export function validateOperationRequest(contract, request, options, write = "copy") {
|
|
249
|
+
if (findOperationAvailabilityIssue(contract, request) === undefined) {
|
|
250
|
+
const sent = withoutUnsentWriteValues(contract, request, request.arguments);
|
|
251
|
+
if (sent !== request.arguments) {
|
|
252
|
+
request = { ...request, arguments: sent };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
121
255
|
const validation = validateOperationArguments(contract, request, options);
|
|
122
256
|
if (!validation.ok) {
|
|
123
257
|
return { ok: false, response: mapValidationOutcome(validation.issues) };
|
|
@@ -133,76 +267,305 @@ export function validateOperationRequest(contract, request, options, write = "co
|
|
|
133
267
|
function rejected(response) {
|
|
134
268
|
return { ok: false, response };
|
|
135
269
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
270
|
+
const FIELD_PIPES = "Field pipes";
|
|
271
|
+
export const STEP_PIPES = "Pipes";
|
|
272
|
+
export const EVERY_FIELD = () => true;
|
|
273
|
+
function filtersOf(levels) {
|
|
274
|
+
return levels.flatMap((level) => level.filters);
|
|
275
|
+
}
|
|
276
|
+
const SINGLE_CALL = { select: EVERY_FIELD };
|
|
277
|
+
const FORCED_CALL = { select: EVERY_FIELD, beforeBegin: true };
|
|
278
|
+
export async function admitOperation(dependencies, request, contract, args, argumentsPath, report, scope, admission = SINGLE_CALL) {
|
|
279
|
+
const contexts = dependencies.contexts;
|
|
280
|
+
const tree = activeScopeConfig(dependencies.config, request).pipelines;
|
|
281
|
+
const levels = operationLevels(tree, request);
|
|
282
|
+
const planned = dependencies.fieldStages[request.origin];
|
|
283
|
+
const guarded = planned.guarded(request.resource);
|
|
284
|
+
const contracts = { core: dependencies.contracts.core, active: contract };
|
|
285
|
+
let current = deepFreeze(args);
|
|
286
|
+
const context = () => contexts.operation(scope, operationFacts(contract, request, current));
|
|
287
|
+
const admit = async () => {
|
|
288
|
+
for (const level of levels) {
|
|
289
|
+
for (const guard of level.guards) {
|
|
290
|
+
if ((await guard(context())) === false) {
|
|
291
|
+
return { ok: false, response: forbidden() };
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (guarded.length > 0 &&
|
|
296
|
+
!(await guardSentFields(fieldStagesOf(tree, request.resource), guarded, writeRecordPathsOf(request.family, current), current, context))) {
|
|
297
|
+
return { ok: false, response: forbidden() };
|
|
298
|
+
}
|
|
299
|
+
for (const target of planned.nestedGuards
|
|
300
|
+
? nestedWriteTargetsOf(contract, dependencies.recordWrites.references, request, current)
|
|
301
|
+
: []) {
|
|
302
|
+
const told = () => contexts.operation(scope, nestedFacts(contract, request, target, valueAt(current, target.path)));
|
|
303
|
+
for (const level of nestedTargetLevels(tree, target.resource, target.family)) {
|
|
304
|
+
for (const guard of level.guards) {
|
|
305
|
+
if ((await guard(told())) === false) {
|
|
306
|
+
return { ok: false, response: forbidden() };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const targetGuarded = planned.guarded(target.resource);
|
|
311
|
+
if (targetGuarded.length > 0 &&
|
|
312
|
+
!(await guardSentFields(fieldStagesOf(tree, target.resource), targetGuarded, target.records.map((site) => site.path), current, told))) {
|
|
313
|
+
return { ok: false, response: forbidden() };
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
let piped = false;
|
|
317
|
+
let pipeIndex = 0;
|
|
318
|
+
for (const level of levels) {
|
|
319
|
+
for (const pipe of level.pipes) {
|
|
320
|
+
const told = frozenCopy(current);
|
|
321
|
+
const output = await pipe(told, context());
|
|
322
|
+
if (output !== undefined && output !== told && output !== current) {
|
|
323
|
+
const returned = withoutUnsentWriteValues(dependencies.contracts.core, request, output);
|
|
324
|
+
const refused = refusePipeOutput(contracts, request, returned, pipe, pipeIndex, admission.validation);
|
|
325
|
+
if (refused !== undefined) {
|
|
326
|
+
report(refused.error, "A3004");
|
|
327
|
+
return { ok: false, response: refused.response };
|
|
328
|
+
}
|
|
329
|
+
current = deepFreeze(returned);
|
|
330
|
+
piped = true;
|
|
331
|
+
}
|
|
332
|
+
pipeIndex += 1;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const fields = await runFieldInputStages(dependencies, request, contract, current, argumentsPath, report, admission);
|
|
336
|
+
if (!fields.ok) {
|
|
337
|
+
return fields;
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
ok: true,
|
|
341
|
+
args: deepFreeze(fields.args),
|
|
342
|
+
piped: piped || fields.piped,
|
|
343
|
+
};
|
|
344
|
+
};
|
|
345
|
+
const absent = preliminaryRecordIssues(contract, dependencies.recordWrites, request, current, argumentsPath);
|
|
346
|
+
if (absent.length > 0) {
|
|
347
|
+
return { ok: false, response: mapValidationOutcome(absent) };
|
|
348
|
+
}
|
|
141
349
|
try {
|
|
142
|
-
return await
|
|
350
|
+
return await admit();
|
|
143
351
|
}
|
|
144
352
|
catch (error) {
|
|
145
|
-
return
|
|
353
|
+
return {
|
|
354
|
+
ok: false,
|
|
355
|
+
response: await resolveOperationFailure(error, filtersOf(levels), context(), new AdapterBoundary(), report, { path: argumentsPath, arguments: current }),
|
|
356
|
+
};
|
|
146
357
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
358
|
+
}
|
|
359
|
+
async function runFieldInputStages(dependencies, request, contract, args, argumentsPath, report, admission) {
|
|
360
|
+
const scopeConfig = activeScopeConfig(dependencies.config, request);
|
|
361
|
+
const tree = scopeConfig.pipelines;
|
|
362
|
+
const planned = dependencies.fieldStages[request.origin];
|
|
363
|
+
const pipes = planned.anyPipes;
|
|
364
|
+
const judge = admission.beforeBegin === true && hasFieldValidators(contract);
|
|
365
|
+
if (!pipes && !judge) {
|
|
366
|
+
return { ok: true, args, piped: false };
|
|
367
|
+
}
|
|
368
|
+
let current = args;
|
|
369
|
+
let changed = false;
|
|
370
|
+
if (pipes) {
|
|
371
|
+
const pipedFields = planned.piped(request.resource);
|
|
372
|
+
let piped = pipedFields.length === 0
|
|
373
|
+
? { args: current, changed: false }
|
|
374
|
+
: await pipeSentFields(fieldStagesOf(tree, request.resource), pipedFields, writeRecordPathsOf(request.family, current), current, admission.select);
|
|
375
|
+
changed = piped.changed;
|
|
376
|
+
for (const target of nestedWriteTargetsOf(contract, dependencies.recordWrites.references, request, piped.args)) {
|
|
377
|
+
const targetPiped = planned.piped(target.resource);
|
|
378
|
+
if (targetPiped.length === 0) {
|
|
379
|
+
continue;
|
|
152
380
|
}
|
|
381
|
+
piped = await pipeSentFields(fieldStagesOf(tree, target.resource), targetPiped, target.records.map((site) => site.path), piped.args, admission.select);
|
|
382
|
+
changed ||= piped.changed;
|
|
153
383
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
384
|
+
current = piped.args;
|
|
385
|
+
if (changed) {
|
|
386
|
+
const refused = refuseStageOutput({ core: dependencies.contracts.core, active: contract }, request, current, FIELD_PIPES, admission.validation);
|
|
387
|
+
if (refused !== undefined) {
|
|
388
|
+
report(refused.error, "A3004");
|
|
389
|
+
return { ok: false, response: refused.response };
|
|
158
390
|
}
|
|
159
|
-
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (judge) {
|
|
394
|
+
const compute = scopeConfig.compute;
|
|
395
|
+
const broken = fieldValidatorIssues(contract, dependencies.recordWrites.references, request, current, argumentsPath, admission.select, (resource, stage, field) => {
|
|
396
|
+
const fields = compute !== undefined && Object.hasOwn(compute, resource)
|
|
397
|
+
? compute[resource]
|
|
398
|
+
: undefined;
|
|
399
|
+
const phases = fields !== undefined && Object.hasOwn(fields, field)
|
|
400
|
+
? fields[field]
|
|
401
|
+
: undefined;
|
|
402
|
+
return phases?.[stage] !== undefined;
|
|
403
|
+
});
|
|
404
|
+
if (broken.length > 0) {
|
|
405
|
+
return { ok: false, response: mapValidationOutcome(broken) };
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return { ok: true, args: current, piped: changed };
|
|
409
|
+
}
|
|
410
|
+
export async function prepareStep(dependencies, request, contract, args, argumentsPath, report, executor, changes, outer) {
|
|
411
|
+
let current = deepFreeze(withoutUnsentWriteValues(dependencies.contracts.core, request, args));
|
|
412
|
+
const scope = {
|
|
413
|
+
requestId: request.requestId,
|
|
414
|
+
transaction: executor,
|
|
415
|
+
state: request.state,
|
|
416
|
+
};
|
|
417
|
+
try {
|
|
418
|
+
const resolved = await runFieldInputStages(dependencies, request, contract, current, argumentsPath, report, { select: changes.written });
|
|
419
|
+
if (!resolved.ok) {
|
|
420
|
+
return resolved;
|
|
421
|
+
}
|
|
422
|
+
current = resolved.args;
|
|
423
|
+
const subject = changes.transactionPiped
|
|
424
|
+
? TRANSACTION_PIPES
|
|
425
|
+
: changes.pipedAroundReferences
|
|
426
|
+
? STEP_PIPES
|
|
427
|
+
: undefined;
|
|
428
|
+
if (subject !== undefined) {
|
|
429
|
+
const refused = refuseStageOutput({ core: dependencies.contracts.core, active: contract }, request, current, subject);
|
|
160
430
|
if (refused !== undefined) {
|
|
161
431
|
report(refused.error, "A3004");
|
|
162
|
-
return refused.response;
|
|
432
|
+
return { ok: false, response: refused.response };
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return { ok: true, args: deepFreeze(current), piped: resolved.piped };
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
return {
|
|
439
|
+
ok: false,
|
|
440
|
+
response: await resolveOperationFailure(error, filtersOf(operationLevels(activeScopeConfig(dependencies.config, request).pipelines, request)), dependencies.contexts.operation(scope, operationFacts(contract, request, current)), new AdapterBoundary(), report, { path: argumentsPath, arguments: current }, outer),
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
async function executeForcedOperation(dependencies, adapter, request, contract, args, report) {
|
|
445
|
+
const plan = [
|
|
446
|
+
{
|
|
447
|
+
resource: request.resource,
|
|
448
|
+
family: request.family,
|
|
449
|
+
variant: request.variant,
|
|
450
|
+
args,
|
|
451
|
+
},
|
|
452
|
+
];
|
|
453
|
+
const settled = await settleTransaction({
|
|
454
|
+
adapter,
|
|
455
|
+
levels: transactionLevelsOf(activeScopeConfig(dependencies.config, request).pipelines, request.resource),
|
|
456
|
+
plan,
|
|
457
|
+
contextOf: (current, executor) => dependencies.contexts.transaction({
|
|
458
|
+
requestId: request.requestId,
|
|
459
|
+
transaction: executor,
|
|
460
|
+
state: request.state,
|
|
461
|
+
}, transactionFacts(contract, request, current)),
|
|
462
|
+
failureView: { path: OPERATION_ARGUMENTS_PATH, arguments: args },
|
|
463
|
+
report,
|
|
464
|
+
runStep: async (_index, step, piped, executor, _results, outer) => {
|
|
465
|
+
let stepArguments = step.args;
|
|
466
|
+
if (piped) {
|
|
467
|
+
const prepared = await prepareStep(dependencies, request, contract, stepArguments, OPERATION_ARGUMENTS_PATH, report, executor, {
|
|
468
|
+
written: () => false,
|
|
469
|
+
transactionPiped: true,
|
|
470
|
+
pipedAroundReferences: false,
|
|
471
|
+
}, outer);
|
|
472
|
+
if (!prepared.ok) {
|
|
473
|
+
return prepared.response;
|
|
474
|
+
}
|
|
475
|
+
stepArguments = prepared.args;
|
|
163
476
|
}
|
|
477
|
+
return executeAdmittedOperation(dependencies, request, contract, stepArguments, OPERATION_ARGUMENTS_PATH, { kind: "transaction", executor, outer }, report);
|
|
478
|
+
},
|
|
479
|
+
});
|
|
480
|
+
switch (settled.kind) {
|
|
481
|
+
case "committed":
|
|
482
|
+
return settled.responses[0] ?? internalFailure();
|
|
483
|
+
case "rolled-back":
|
|
484
|
+
return settled.response;
|
|
485
|
+
case "broken":
|
|
486
|
+
report(settled.error, "A3002");
|
|
487
|
+
return transactionInfrastructureFailure();
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
export async function executeAdmittedOperation(dependencies, request, contract, admittedArguments, argumentsPath, binding, report) {
|
|
491
|
+
const { executor } = binding;
|
|
492
|
+
const scope = scopeOf(request, binding);
|
|
493
|
+
const contexts = dependencies.contexts;
|
|
494
|
+
const scopeConfig = activeScopeConfig(dependencies.config, request);
|
|
495
|
+
const levels = operationLevels(scopeConfig.pipelines, request);
|
|
496
|
+
const adapterBoundary = new AdapterBoundary();
|
|
497
|
+
const contracts = { core: dependencies.contracts.core, active: contract };
|
|
498
|
+
let args = deepFreeze(admittedArguments);
|
|
499
|
+
const context = () => contexts.operation(scope, operationFacts(contract, request, args));
|
|
500
|
+
const computeContext = () => contexts.compute(scope, operationFacts(contract, request, args));
|
|
501
|
+
const reuse = { refusal: undefined };
|
|
502
|
+
const refusedReuse = (refusal) => {
|
|
503
|
+
report(refusal, "A3000");
|
|
504
|
+
return internalFailure();
|
|
505
|
+
};
|
|
506
|
+
let response;
|
|
507
|
+
try {
|
|
508
|
+
response = await runLifecycle();
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
if (reuse.refusal !== undefined) {
|
|
512
|
+
return refusedReuse(reuse.refusal);
|
|
164
513
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
514
|
+
return resolveOperationFailure(error, filtersOf(levels), context(), adapterBoundary, report, { path: argumentsPath, arguments: args }, binding.kind === "transaction" ? binding.outer : undefined);
|
|
515
|
+
}
|
|
516
|
+
return reuse.refusal === undefined ? response : refusedReuse(reuse.refusal);
|
|
517
|
+
async function runLifecycle() {
|
|
518
|
+
let computed = await applyWriteCompute(contracts, scopeConfig.compute, request, args, computeContext);
|
|
519
|
+
computed = await applyNestedWriteCompute(contracts, scopeConfig.compute, computed, nestedWriteTargetsOf(contract, dependencies.recordWrites.references, request, computed), (target, payload) => contexts.compute(scope, nestedFacts(contract, request, target, payload)));
|
|
520
|
+
const broken = createRequirementIssues(contract, dependencies.recordWrites, request, computed, argumentsPath);
|
|
521
|
+
const [firstBroken] = broken;
|
|
522
|
+
if (firstBroken !== undefined) {
|
|
523
|
+
const what = firstBroken.code === "V1000"
|
|
524
|
+
? "dropped a required field"
|
|
525
|
+
: "wrote a reference twice";
|
|
526
|
+
report(new AvPipeOutputError(`Pipes or write compute ${what} of ${request.resource}.${request.family}.${request.variant} at "${(firstBroken.path ?? []).join(".")}" (${firstBroken.code}: ${firstBroken.message})`, broken), "A3004");
|
|
527
|
+
return operationFailure("A3004", {
|
|
528
|
+
message: PIPE_OUTPUT_FAILURE_MESSAGE,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
const unfilled = computedRequirementGapsOf(contract, dependencies.recordWrites, request, computed, argumentsPath, (resource) => createComputedFields(scopeConfig.compute, resource));
|
|
532
|
+
const [firstUnfilled] = unfilled;
|
|
533
|
+
if (firstUnfilled !== undefined) {
|
|
534
|
+
throw new AvComputedValueError(firstUnfilled.resource, firstUnfilled.field, "create", unfilled.map((gap) => gap.issue), `compute.create on ${firstUnfilled.resource}.${firstUnfilled.field} returned undefined for a required field`);
|
|
169
535
|
}
|
|
170
|
-
|
|
171
|
-
|
|
536
|
+
if (hasFieldValidators(contract)) {
|
|
537
|
+
const refused = fieldValidatorIssues(contract, dependencies.recordWrites.references, request, computed, argumentsPath, EVERY_FIELD);
|
|
538
|
+
if (refused.length > 0) {
|
|
539
|
+
return mapValidationOutcome(refused);
|
|
540
|
+
}
|
|
172
541
|
}
|
|
542
|
+
args = deepFreeze(computed);
|
|
173
543
|
let readMaterialized = false;
|
|
174
544
|
let executedReadPlan;
|
|
175
545
|
const materialize = async (data, plan) => {
|
|
176
546
|
readMaterialized = true;
|
|
177
547
|
executedReadPlan = plan;
|
|
178
|
-
return materializeReadOperation(contract, scopeConfig.
|
|
548
|
+
return materializeReadOperation(contract, scopeConfig.compute, request, plan, data, computeContext);
|
|
179
549
|
};
|
|
180
|
-
|
|
181
|
-
const readPlan = planReadOperation(dependencies.contracts.core, contract, scopeConfig.
|
|
182
|
-
const adapterArguments = await stripVirtualMutationInput(
|
|
550
|
+
const invoke = async () => {
|
|
551
|
+
const readPlan = planReadOperation(dependencies.contracts.core, dependencies.config.adapter.model, contract, scopeConfig.compute, request, args);
|
|
552
|
+
const adapterArguments = await stripVirtualMutationInput(contracts, request, readPlan.arguments);
|
|
183
553
|
const identity = request;
|
|
184
554
|
const adapterData = await adapterBoundary.execute(() => executor.execute({
|
|
185
555
|
...identity,
|
|
186
556
|
resource: request.resource,
|
|
187
557
|
arguments: adapterArguments,
|
|
188
558
|
}));
|
|
559
|
+
const miss = uniqueMissFailure(request, adapterData);
|
|
560
|
+
if (miss !== undefined) {
|
|
561
|
+
throw thrownFailure(miss);
|
|
562
|
+
}
|
|
189
563
|
return materialize(adapterData, readPlan);
|
|
190
564
|
};
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
const next = invoke;
|
|
197
|
-
invoke = () => interceptor(pipelineContext(contract, request, args), next);
|
|
198
|
-
}
|
|
199
|
-
let data = await invoke();
|
|
200
|
-
if (!readMaterialized) {
|
|
201
|
-
data = await materialize(data, planReadOperation(dependencies.contracts.core, contract, scopeConfig.behaviors, request, args));
|
|
202
|
-
}
|
|
203
|
-
for (const hook of pipelines.hooks.after) {
|
|
204
|
-
await hook(data, pipelineContext(contract, request, args));
|
|
205
|
-
}
|
|
565
|
+
const materialized = async (data) => readMaterialized
|
|
566
|
+
? data
|
|
567
|
+
: materialize(data, planReadOperation(dependencies.contracts.core, dependencies.config.adapter.model, contract, scopeConfig.compute, request, args));
|
|
568
|
+
const data = await materialized(await runLevelLifecycle(levels, context, invoke, materialized, reuse, () => new AvInterceptorNextError()));
|
|
206
569
|
if (!outputAccepted(contract, request, executedReadPlan?.projection, data, report)) {
|
|
207
570
|
return internalFailure();
|
|
208
571
|
}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
2
|
+
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
3
|
+
import type { AvOperationFailureResponse, AvOperationResponse } from "./operation-response.js";
|
|
4
|
+
/**
|
|
5
|
+
* The failure a strict unique operation's miss raises inside the pipeline, or
|
|
6
|
+
* `undefined` when `data` is a row, or the variant answers a miss with `null`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function uniqueMissFailure(operation: AvOperationIdentity, data: unknown): AvOperationFailureResponse | undefined;
|
|
4
9
|
/**
|
|
5
10
|
* Maps one validated operation result to its stable outcome envelope. The
|
|
6
11
|
* result must already have passed output validation, so `null` can only
|
|
7
12
|
* reach a variant whose cardinality admits it.
|
|
8
13
|
*/
|
|
9
|
-
export declare function mapOperationOutcome(operation:
|
|
14
|
+
export declare function mapOperationOutcome(operation: AvOperationIdentity, data: unknown): AvOperationResponse;
|
|
15
|
+
/** The A-codes a set of Framework Validation Layer issues can roll up to. */
|
|
16
|
+
export type ValidationOutcomeCode = "A2001" | "A2002" | "A2004" | "A2007" | "A2009";
|
|
17
|
+
/** The framework's top-level `cause.message` for each validation outcome code. */
|
|
18
|
+
export declare const VALIDATION_OUTCOME_MESSAGES: {
|
|
19
|
+
readonly [K in ValidationOutcomeCode]: string;
|
|
20
|
+
};
|
|
10
21
|
/** Maps framework validation issues to their stable failure envelope. */
|
|
11
|
-
export declare function mapValidationOutcome(issues: readonly
|
|
22
|
+
export declare function mapValidationOutcome(issues: readonly AvValidationIssue[]): AvOperationFailureResponse;
|