@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,6 +1,6 @@
|
|
|
1
1
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
2
|
import { advertisedDirectivesAt } from "../contracts/field.js";
|
|
3
|
-
import { NESTED_WRITE_SCOPE, resolveWriteScope, } from "../operations/write-scope.resolver.js";
|
|
3
|
+
import { LOOPBACK_WRITE_SCOPE, NESTED_WRITE_SCOPE, resolveWriteScope, } from "../operations/write-scope.resolver.js";
|
|
4
4
|
import { isRelationMutationDirective, RELATION_MUTATION_RECORD_SITES, } from "./mutation-planner.js";
|
|
5
5
|
function isRecord(value) {
|
|
6
6
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -8,10 +8,6 @@ function isRecord(value) {
|
|
|
8
8
|
function written(record, key) {
|
|
9
9
|
return Object.hasOwn(record, key) && record[key] !== undefined;
|
|
10
10
|
}
|
|
11
|
-
function requirementsOf(table, resource) {
|
|
12
|
-
const listed = Object.hasOwn(table, resource) ? table[resource] : undefined;
|
|
13
|
-
return Array.isArray(listed) ? listed : [];
|
|
14
|
-
}
|
|
15
11
|
function edgesOf(table, resource) {
|
|
16
12
|
const listed = Object.hasOwn(table, resource) ? table[resource] : undefined;
|
|
17
13
|
return Array.isArray(listed) ? listed : [];
|
|
@@ -19,16 +15,6 @@ function edgesOf(table, resource) {
|
|
|
19
15
|
function referencesOf(edge) {
|
|
20
16
|
return Array.isArray(edge.references) ? edge.references : [];
|
|
21
17
|
}
|
|
22
|
-
function referenceFieldsOf(table, resource, relation) {
|
|
23
|
-
const edge = edgesOf(table, resource).find((candidate) => candidate.field === relation);
|
|
24
|
-
return edge === undefined ? [] : referencesOf(edge);
|
|
25
|
-
}
|
|
26
|
-
function storeSupplied(contract, resource, field) {
|
|
27
|
-
const found = lookupField(lookupResource(contract, resource), field);
|
|
28
|
-
return (found?.kind === "scalar" &&
|
|
29
|
-
(found.lifecycle.includes("DEFAULTED") ||
|
|
30
|
-
found.lifecycle.includes("GENERATED_ON_CREATE")));
|
|
31
|
-
}
|
|
32
18
|
function creatableScalar(contract, resource, field) {
|
|
33
19
|
const found = lookupField(lookupResource(contract, resource), field);
|
|
34
20
|
return found?.kind === "scalar" && found.capabilities.create !== undefined;
|
|
@@ -38,53 +24,104 @@ function creatableRelation(contract, resource, relation, scope) {
|
|
|
38
24
|
return (found?.kind === "relation" &&
|
|
39
25
|
advertisedDirectivesAt(found.capabilities.create, scope) !== undefined);
|
|
40
26
|
}
|
|
27
|
+
function blockedByPosition(contract, resource, relation, scope) {
|
|
28
|
+
return (scope !== NESTED_WRITE_SCOPE &&
|
|
29
|
+
creatableRelation(contract, resource, relation, NESTED_WRITE_SCOPE) &&
|
|
30
|
+
!creatableRelation(contract, resource, relation, scope));
|
|
31
|
+
}
|
|
32
|
+
function requirementsOf(contract, resource) {
|
|
33
|
+
const found = lookupResource(contract, resource)?.createRequirements;
|
|
34
|
+
return isRecord(found) ? found : undefined;
|
|
35
|
+
}
|
|
36
|
+
function namesOf(value) {
|
|
37
|
+
return Array.isArray(value)
|
|
38
|
+
? value.filter((name) => typeof name === "string")
|
|
39
|
+
: [];
|
|
40
|
+
}
|
|
41
|
+
function suppliedThrough(requirements, via) {
|
|
42
|
+
if (via === undefined || !isRecord(requirements.parentSupplies)) {
|
|
43
|
+
return new Set();
|
|
44
|
+
}
|
|
45
|
+
const byRelation = Object.hasOwn(requirements.parentSupplies, via.resource)
|
|
46
|
+
? requirements.parentSupplies[via.resource]
|
|
47
|
+
: undefined;
|
|
48
|
+
if (!isRecord(byRelation) || !Object.hasOwn(byRelation, via.relation)) {
|
|
49
|
+
return new Set();
|
|
50
|
+
}
|
|
51
|
+
return new Set(namesOf(byRelation[via.relation]));
|
|
52
|
+
}
|
|
53
|
+
function missingIssue(path, resource, field, relation, or = []) {
|
|
54
|
+
return {
|
|
55
|
+
code: "V1000",
|
|
56
|
+
path: [...path, field],
|
|
57
|
+
message: relation
|
|
58
|
+
? `Relation "${field}" is required to create ${resource}${or.length > 0 ? `: write it, or ${or.map((name) => `"${name}"`).join(" and ")}` : ""}.`
|
|
59
|
+
: `Field "${field}" is required to create ${resource}.`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
41
62
|
function checkCreateRecord(context, resource, record, path, scope, via) {
|
|
42
63
|
if (!isRecord(record)) {
|
|
43
64
|
return;
|
|
44
65
|
}
|
|
66
|
+
if (context.computed !== undefined) {
|
|
67
|
+
computedRequirementGaps(context, resource, record, path, via);
|
|
68
|
+
walkNestedCreates(context, resource, record, path);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
45
71
|
const { contract, issues } = context;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
const looped = loopbackWrites(context, resource, record, path, via, "create");
|
|
73
|
+
const conflicted = looped.size > 0
|
|
74
|
+
? looped
|
|
75
|
+
: referenceConflicts(context, resource, record, path);
|
|
76
|
+
if (looped.size === 0) {
|
|
77
|
+
mixedReferenceWrites(context, resource, record, path, conflicted);
|
|
78
|
+
}
|
|
79
|
+
const requirements = requirementsOf(contract, resource);
|
|
80
|
+
if (requirements !== undefined) {
|
|
81
|
+
const supplied = suppliedThrough(requirements, via);
|
|
82
|
+
for (const field of namesOf(requirements.required)) {
|
|
83
|
+
if (supplied.has(field) || written(record, field)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (creatableScalar(contract, resource, field)) {
|
|
87
|
+
issues.push(missingIssue(path, resource, field, false));
|
|
88
|
+
}
|
|
89
|
+
else if (!conflicted.has(field) &&
|
|
90
|
+
creatableRelation(contract, resource, field, scope)) {
|
|
91
|
+
issues.push(missingIssue(path, resource, field, true));
|
|
92
|
+
}
|
|
93
|
+
else if (blockedByPosition(contract, resource, field, scope)) {
|
|
94
|
+
const edge = edgesOf(context.references, resource).find((candidate) => candidate.field === field);
|
|
95
|
+
const references = edge === undefined ? [] : referencesOf(edge);
|
|
96
|
+
if (!references.some((name) => written(record, name))) {
|
|
97
|
+
issues.push(missingIssue(path, resource, references[0] ?? field, false));
|
|
98
|
+
}
|
|
57
99
|
}
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
if (conflicted.has(requirement.relation)) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
if (via !== undefined &&
|
|
64
|
-
requirement.inverse?.resource === via.resource &&
|
|
65
|
-
requirement.inverse.relation === via.relation) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
const orFields = referenceFieldsOf(context.references, resource, requirement.relation).filter((field) => !storeSupplied(contract, resource, field));
|
|
69
|
-
if (written(record, requirement.relation) ||
|
|
70
|
-
(orFields.length > 0 && orFields.every((field) => written(record, field)))) {
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (creatableRelation(contract, resource, requirement.relation, scope)) {
|
|
74
|
-
issues.push({
|
|
75
|
-
code: "V1000",
|
|
76
|
-
path: [...path, requirement.relation],
|
|
77
|
-
message: `Relation "${requirement.relation}" is required to create ${resource}${orFields.length > 0 ? `: write it, or ${orFields.map((field) => `"${field}"`).join(" and ")}` : ""}.`,
|
|
78
|
-
});
|
|
79
|
-
continue;
|
|
80
100
|
}
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
101
|
+
const groups = Array.isArray(requirements.oneOf) ? requirements.oneOf : [];
|
|
102
|
+
for (const group of groups) {
|
|
103
|
+
const [relation, ...references] = namesOf(group);
|
|
104
|
+
if (relation === undefined ||
|
|
105
|
+
references.length === 0 ||
|
|
106
|
+
conflicted.has(relation) ||
|
|
107
|
+
supplied.has(relation) ||
|
|
108
|
+
references.some((field) => supplied.has(field)) ||
|
|
109
|
+
written(record, relation) ||
|
|
110
|
+
references.every((field) => written(record, field))) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (creatableRelation(contract, resource, relation, scope)) {
|
|
114
|
+
issues.push(missingIssue(path, resource, relation, true, references));
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const missing = references.find((field) => !written(record, field) &&
|
|
118
|
+
creatableScalar(contract, resource, field)) ??
|
|
119
|
+
(blockedByPosition(contract, resource, relation, scope)
|
|
120
|
+
? references.find((field) => !written(record, field))
|
|
121
|
+
: undefined);
|
|
122
|
+
if (missing !== undefined) {
|
|
123
|
+
issues.push(missingIssue(path, resource, missing, false));
|
|
124
|
+
}
|
|
88
125
|
}
|
|
89
126
|
}
|
|
90
127
|
walkNestedCreates(context, resource, record, path);
|
|
@@ -130,14 +167,93 @@ function mixedReferenceWrites(context, resource, record, path, conflicted) {
|
|
|
130
167
|
});
|
|
131
168
|
}
|
|
132
169
|
}
|
|
133
|
-
function checkUpdateRecord(context, resource, record, path) {
|
|
170
|
+
function checkUpdateRecord(context, resource, record, path, via) {
|
|
134
171
|
if (!isRecord(record)) {
|
|
135
172
|
return;
|
|
136
173
|
}
|
|
137
|
-
|
|
138
|
-
|
|
174
|
+
if (context.computed === undefined &&
|
|
175
|
+
loopbackWrites(context, resource, record, path, via, "update").size === 0) {
|
|
176
|
+
const conflicted = referenceConflicts(context, resource, record, path);
|
|
177
|
+
mixedReferenceWrites(context, resource, record, path, conflicted);
|
|
178
|
+
}
|
|
139
179
|
walkNestedCreates(context, resource, record, path);
|
|
140
180
|
}
|
|
181
|
+
function loopbackWrites(context, resource, record, path, via, stage) {
|
|
182
|
+
const refused = new Set();
|
|
183
|
+
if (via === undefined) {
|
|
184
|
+
return refused;
|
|
185
|
+
}
|
|
186
|
+
const { contract } = context;
|
|
187
|
+
const edge = lookupField(lookupResource(contract, via.resource), via.relation);
|
|
188
|
+
if (edge?.kind !== "relation" || typeof edge.inverse !== "string") {
|
|
189
|
+
return refused;
|
|
190
|
+
}
|
|
191
|
+
const inverse = edge.inverse;
|
|
192
|
+
const other = lookupField(lookupResource(contract, resource), inverse);
|
|
193
|
+
if (other?.kind === "relation" &&
|
|
194
|
+
advertisedDirectivesAt(other.capabilities[stage], LOOPBACK_WRITE_SCOPE) !==
|
|
195
|
+
undefined) {
|
|
196
|
+
return refused;
|
|
197
|
+
}
|
|
198
|
+
const references = edgesOf(context.references, resource).find((candidate) => candidate.field === inverse) ?? undefined;
|
|
199
|
+
for (const field of [
|
|
200
|
+
inverse,
|
|
201
|
+
...(references === undefined ? [] : referencesOf(references)),
|
|
202
|
+
]) {
|
|
203
|
+
if (!written(record, field)) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
refused.add(field);
|
|
207
|
+
context.issues.push({
|
|
208
|
+
code: "V1012",
|
|
209
|
+
path: [...path, field],
|
|
210
|
+
message: field === inverse
|
|
211
|
+
? `Relation "${field}" is the relation this ${resource} is written through, from its other end ("${via.resource}.${via.relation}"): the write it sits in supplies it.`
|
|
212
|
+
: `Field "${field}" holds the reference of "${inverse}", the relation this ${resource} is written through ("${via.resource}.${via.relation}"): the write it sits in supplies it.`,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return refused;
|
|
216
|
+
}
|
|
217
|
+
function computedRequirementGaps(context, resource, record, path, via) {
|
|
218
|
+
const reader = context.computed;
|
|
219
|
+
const computed = reader?.computed(resource);
|
|
220
|
+
const stated = reader?.stated(resource);
|
|
221
|
+
if (computed === undefined || computed.size === 0 || stated === undefined) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const supplied = suppliedThrough(stated, via);
|
|
225
|
+
const gap = (field) => {
|
|
226
|
+
context.gaps?.push({
|
|
227
|
+
resource,
|
|
228
|
+
field,
|
|
229
|
+
issue: {
|
|
230
|
+
code: "V1000",
|
|
231
|
+
path: [...path, field],
|
|
232
|
+
message: `compute.create on ${resource}.${field} returned undefined for a required field.`,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
for (const field of namesOf(stated.required)) {
|
|
237
|
+
if (computed.has(field) &&
|
|
238
|
+
!supplied.has(field) &&
|
|
239
|
+
!written(record, field)) {
|
|
240
|
+
gap(field);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
const groups = Array.isArray(stated.oneOf) ? stated.oneOf : [];
|
|
244
|
+
for (const group of groups) {
|
|
245
|
+
const [relation, ...references] = namesOf(group);
|
|
246
|
+
const left = references.find((field) => computed.has(field) && !written(record, field));
|
|
247
|
+
if (relation === undefined ||
|
|
248
|
+
left === undefined ||
|
|
249
|
+
supplied.has(relation) ||
|
|
250
|
+
references.some((field) => supplied.has(field)) ||
|
|
251
|
+
written(record, relation)) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
gap(left);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
141
257
|
function walkNestedCreates(context, resource, record, path) {
|
|
142
258
|
if (!isRecord(record)) {
|
|
143
259
|
return;
|
|
@@ -169,7 +285,7 @@ function walkNestedCreates(context, resource, record, path) {
|
|
|
169
285
|
checkCreateRecord(context, field.target, siteRecord, sitePath, NESTED_WRITE_SCOPE, via);
|
|
170
286
|
}
|
|
171
287
|
else {
|
|
172
|
-
checkUpdateRecord(context, field.target, siteRecord, sitePath);
|
|
288
|
+
checkUpdateRecord(context, field.target, siteRecord, sitePath, via);
|
|
173
289
|
}
|
|
174
290
|
}
|
|
175
291
|
}
|
|
@@ -177,21 +293,52 @@ function walkNestedCreates(context, resource, record, path) {
|
|
|
177
293
|
}
|
|
178
294
|
}
|
|
179
295
|
export function recordWriteFactsOf(adapter) {
|
|
296
|
+
const resources = adapter.model?.resources ?? {};
|
|
180
297
|
return {
|
|
181
|
-
requirements: adapter.createRequirements ?? {},
|
|
182
298
|
references: adapter.referentialActions ?? {},
|
|
299
|
+
stated: (resource) => {
|
|
300
|
+
const found = Object.hasOwn(resources, resource)
|
|
301
|
+
? resources[resource]
|
|
302
|
+
: undefined;
|
|
303
|
+
const stated = isRecord(found) ? found.createRequirements : undefined;
|
|
304
|
+
return isRecord(stated) ? stated : undefined;
|
|
305
|
+
},
|
|
183
306
|
};
|
|
184
307
|
}
|
|
185
308
|
export function createRequirementIssues(contract, facts, request, args, argumentsPath) {
|
|
186
|
-
if (!isRecord(args)) {
|
|
187
|
-
return [];
|
|
188
|
-
}
|
|
189
309
|
const context = {
|
|
190
310
|
contract,
|
|
191
|
-
requirements: facts.requirements,
|
|
192
311
|
references: facts.references,
|
|
193
312
|
issues: [],
|
|
194
313
|
};
|
|
314
|
+
walkOperation(context, request, args, argumentsPath);
|
|
315
|
+
return context.issues;
|
|
316
|
+
}
|
|
317
|
+
export function preliminaryRecordIssues(contract, facts, request, args, argumentsPath) {
|
|
318
|
+
const context = {
|
|
319
|
+
contract,
|
|
320
|
+
references: facts.references,
|
|
321
|
+
issues: [],
|
|
322
|
+
};
|
|
323
|
+
walkOperation(context, request, args, argumentsPath);
|
|
324
|
+
return context.issues;
|
|
325
|
+
}
|
|
326
|
+
export function computedRequirementGapsOf(contract, facts, request, args, argumentsPath, computed) {
|
|
327
|
+
const gaps = [];
|
|
328
|
+
walkOperation({
|
|
329
|
+
contract,
|
|
330
|
+
references: facts.references,
|
|
331
|
+
issues: [],
|
|
332
|
+
computed: { stated: facts.stated, computed },
|
|
333
|
+
gaps,
|
|
334
|
+
}, request, args, argumentsPath);
|
|
335
|
+
return gaps;
|
|
336
|
+
}
|
|
337
|
+
function walkOperation(context, request, args, argumentsPath) {
|
|
338
|
+
if (!isRecord(args)) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const contract = context.contract;
|
|
195
342
|
const scope = resolveWriteScope(lookupResource(contract, request.resource), request);
|
|
196
343
|
if (request.family === "create" && written(args, "data")) {
|
|
197
344
|
const data = args.data;
|
|
@@ -206,16 +353,9 @@ export function createRequirementIssues(contract, facts, request, args, argument
|
|
|
206
353
|
}
|
|
207
354
|
if (request.family === "upsert") {
|
|
208
355
|
checkCreateRecord(context, request.resource, args.create, [...argumentsPath, "create"], scope, undefined);
|
|
209
|
-
checkUpdateRecord(context, request.resource, args.update, [
|
|
210
|
-
...argumentsPath,
|
|
211
|
-
"update",
|
|
212
|
-
]);
|
|
356
|
+
checkUpdateRecord(context, request.resource, args.update, [...argumentsPath, "update"], undefined);
|
|
213
357
|
}
|
|
214
358
|
if (request.family === "update") {
|
|
215
|
-
checkUpdateRecord(context, request.resource, args.data, [
|
|
216
|
-
...argumentsPath,
|
|
217
|
-
"data",
|
|
218
|
-
]);
|
|
359
|
+
checkUpdateRecord(context, request.resource, args.data, [...argumentsPath, "data"], undefined);
|
|
219
360
|
}
|
|
220
|
-
return context.issues;
|
|
221
361
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* An exact decimal value, independent of any database driver's decimal class.
|
|
3
|
-
* Results carry `decimal` fields as `
|
|
3
|
+
* Results carry `decimal` fields as `AvDecimal`.
|
|
4
4
|
*/
|
|
5
|
-
export declare class
|
|
5
|
+
export declare class AvDecimal {
|
|
6
6
|
#private;
|
|
7
7
|
constructor(value: string);
|
|
8
8
|
toString(): string;
|
package/dist/runtime/decimal.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { AvRequestOrigin } from "../config/config-layer.js";
|
|
2
|
+
import type { AvOperationFamily } from "../operations/operation-identity.js";
|
|
3
3
|
import type { FrameworkTransactionRequest } from "../transactions/transaction-request.js";
|
|
4
4
|
import type { FrameworkOperationRequest } from "./operation-request.js";
|
|
5
|
-
import type
|
|
5
|
+
import { type AvOperationErrorCode, type AvOperationFailureResponse } from "./operation-response.js";
|
|
6
6
|
/**
|
|
7
7
|
* One unplanned failure of an operation: the raw error, the code the caller
|
|
8
|
-
* received, and the operation and request it happened in
|
|
9
|
-
* deliberate internal failure, marked `deliberate`. Server-side only:
|
|
8
|
+
* received, and the operation and request it happened in. It can also be a
|
|
9
|
+
* developer's deliberate internal failure, marked `deliberate`. Server-side only:
|
|
10
10
|
* diagnostics are never sent to the caller.
|
|
11
11
|
*/
|
|
12
|
-
export type
|
|
12
|
+
export type AvOperationDiagnostic = {
|
|
13
13
|
readonly kind: "operation";
|
|
14
14
|
readonly error: unknown;
|
|
15
|
-
readonly code:
|
|
16
|
-
readonly origin:
|
|
15
|
+
readonly code: AvOperationErrorCode;
|
|
16
|
+
readonly origin: AvRequestOrigin;
|
|
17
17
|
readonly resource: string;
|
|
18
|
-
readonly family:
|
|
18
|
+
readonly family: AvOperationFamily;
|
|
19
19
|
readonly variant: string;
|
|
20
20
|
readonly requestId: string;
|
|
21
21
|
readonly operation?: number;
|
|
22
22
|
/**
|
|
23
|
-
* `true` when `error` is
|
|
24
|
-
* callback, a
|
|
23
|
+
* `true` when `error` is an `AvError` its thrower (a pipeline
|
|
24
|
+
* callback, a compute stage, a filter or an Adapter) raised deliberately with an
|
|
25
25
|
* internal (`A3xxx`) code: the developer's own failure, whose message and
|
|
26
26
|
* issues the caller never receives. Absent for a failure the framework did not
|
|
27
27
|
* expect.
|
|
@@ -32,48 +32,75 @@ export type OperationDiagnostic = {
|
|
|
32
32
|
* One unplanned failure of a transaction: the raw error, the code the caller
|
|
33
33
|
* received, and the step it is blamed on (`operation`) when there is one.
|
|
34
34
|
*/
|
|
35
|
-
export type
|
|
35
|
+
export type AvTransactionDiagnostic = {
|
|
36
36
|
readonly kind: "transaction";
|
|
37
37
|
readonly error: unknown;
|
|
38
|
-
readonly code:
|
|
39
|
-
readonly origin:
|
|
38
|
+
readonly code: AvOperationErrorCode;
|
|
39
|
+
readonly origin: AvRequestOrigin;
|
|
40
40
|
readonly requestId: string;
|
|
41
41
|
readonly operation?: number;
|
|
42
42
|
/**
|
|
43
43
|
* Never present: only an operation diagnostic is marked `deliberate`. Declared
|
|
44
|
-
* so the mark can be read on any {@link
|
|
44
|
+
* so the mark can be read on any {@link AvDiagnostic}.
|
|
45
45
|
*/
|
|
46
46
|
readonly deliberate?: never;
|
|
47
47
|
};
|
|
48
|
-
/**
|
|
49
|
-
|
|
48
|
+
/**
|
|
49
|
+
* One unplanned failure of the MCP endpoint itself, outside any tool call's
|
|
50
|
+
* operation: the raw error, answered `500` with no detail, or `401` when it is
|
|
51
|
+
* the throw of `mcp.authorization.verify`.
|
|
52
|
+
*/
|
|
53
|
+
export type AvMcpDiagnostic = {
|
|
54
|
+
readonly kind: "mcp";
|
|
55
|
+
readonly error: unknown;
|
|
56
|
+
/** Always `A3000`: an internal failure, with nothing more specific to say. */
|
|
57
|
+
readonly code: "A3000";
|
|
58
|
+
readonly origin: "agent";
|
|
59
|
+
/** Minted for the report: the MCP request carries no Aventara request id. */
|
|
60
|
+
readonly requestId: string;
|
|
61
|
+
/** Never present: no operation of a plan is involved. */
|
|
62
|
+
readonly operation?: never;
|
|
63
|
+
/** Never present: only an operation diagnostic is marked `deliberate`. */
|
|
64
|
+
readonly deliberate?: never;
|
|
65
|
+
};
|
|
66
|
+
/** One diagnostic: of an operation, of a transaction as a whole, or of the MCP endpoint. */
|
|
67
|
+
export type AvDiagnostic = AvOperationDiagnostic | AvTransactionDiagnostic | AvMcpDiagnostic;
|
|
50
68
|
/**
|
|
51
69
|
* Receives a diagnostic for every unplanned failure. Set once, as the root
|
|
52
70
|
* configuration's `diagnostics`.
|
|
53
71
|
*/
|
|
54
|
-
export type
|
|
72
|
+
export type AvDiagnosticsSink = (diagnostic: AvDiagnostic) => void | Promise<void>;
|
|
55
73
|
/**
|
|
56
74
|
* The channel as the runtime holds it: bound to one request, told the raw
|
|
57
75
|
* error and the code being emitted. Total by construction — it returns
|
|
58
76
|
* before the sink has finished and swallows everything the sink does.
|
|
59
77
|
*/
|
|
60
|
-
export type DiagnosticsReporter = (error: unknown, code:
|
|
78
|
+
export type DiagnosticsReporter = (error: unknown, code: AvOperationErrorCode, marks?: DiagnosticMarks) => void;
|
|
61
79
|
/** What a report states about its error beyond the code: today, whether it was deliberate. */
|
|
62
|
-
export type DiagnosticMarks = Pick<
|
|
80
|
+
export type DiagnosticMarks = Pick<AvOperationDiagnostic, "deliberate">;
|
|
63
81
|
/** The identifying half of a diagnostic, captured once per request. */
|
|
64
|
-
type OperationDiagnosticIdentity = Omit<
|
|
65
|
-
type TransactionDiagnosticIdentity = Omit<
|
|
82
|
+
type OperationDiagnosticIdentity = Omit<AvOperationDiagnostic, "error" | "code">;
|
|
83
|
+
type TransactionDiagnosticIdentity = Omit<AvTransactionDiagnostic, "error" | "code">;
|
|
66
84
|
/** The diagnostics channel bound to one diagnostic identity. */
|
|
67
|
-
export declare function createReporter(sink:
|
|
85
|
+
export declare function createReporter(sink: AvDiagnosticsSink | undefined, identity: OperationDiagnosticIdentity | TransactionDiagnosticIdentity): DiagnosticsReporter;
|
|
86
|
+
/**
|
|
87
|
+
* The MCP endpoint's failure channel for `framework`: each call reports one
|
|
88
|
+
* {@link AvMcpDiagnostic} to its configured sink, under a minted request id, and
|
|
89
|
+
* answers the response the caller receives instead: the generic `A3000`, which
|
|
90
|
+
* carries nothing of the error. Total: it returns before the sink has finished
|
|
91
|
+
* and swallows everything the sink does. A Framework without a sink gets a
|
|
92
|
+
* channel that observes nothing and still answers the `A3000`.
|
|
93
|
+
*/
|
|
94
|
+
export declare function mcpFailureReporterOf(framework: object): (error: unknown) => AvOperationFailureResponse;
|
|
68
95
|
/** Records the sink `framework` was configured with; called once, at construction. */
|
|
69
|
-
export declare function recordDiagnosticsSink(framework: object, sink:
|
|
96
|
+
export declare function recordDiagnosticsSink(framework: object, sink: AvDiagnosticsSink | undefined): void;
|
|
70
97
|
/** The sink `framework` was configured with, or `undefined` for none. */
|
|
71
|
-
export declare function diagnosticsSinkOf(framework: object):
|
|
98
|
+
export declare function diagnosticsSinkOf(framework: object): AvDiagnosticsSink | undefined;
|
|
72
99
|
/**
|
|
73
100
|
* Binds the configured sink to one operation request. The sink is not awaited,
|
|
74
101
|
* and nothing it throws or rejects with reaches the response.
|
|
75
102
|
*/
|
|
76
|
-
export declare function createDiagnosticsReporter(sink:
|
|
103
|
+
export declare function createDiagnosticsReporter(sink: AvDiagnosticsSink | undefined, request: FrameworkOperationRequest, operation?: number): DiagnosticsReporter;
|
|
77
104
|
/** The diagnostics channel of one transaction request. */
|
|
78
105
|
export type TransactionDiagnosticsChannel = {
|
|
79
106
|
/** A plan-level report; `operation` attributes it to a recorded failing index. */
|
|
@@ -82,5 +109,5 @@ export type TransactionDiagnosticsChannel = {
|
|
|
82
109
|
readonly operation: (request: FrameworkOperationRequest, operation: number) => DiagnosticsReporter;
|
|
83
110
|
};
|
|
84
111
|
/** Binds the configured sink to one transaction request and its plan operations. */
|
|
85
|
-
export declare function createTransactionDiagnosticsChannel(sink:
|
|
112
|
+
export declare function createTransactionDiagnosticsChannel(sink: AvDiagnosticsSink | undefined, request: FrameworkTransactionRequest): TransactionDiagnosticsChannel;
|
|
86
113
|
export {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { internalFailure, } from "./operation-response.js";
|
|
2
|
+
import { requestIdOf } from "./request-id.js";
|
|
1
3
|
const IGNORE_DIAGNOSTIC = () => undefined;
|
|
2
4
|
function isThenable(value) {
|
|
3
5
|
if ((typeof value !== "object" || value === null) &&
|
|
@@ -30,6 +32,28 @@ export function createReporter(sink, identity) {
|
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
const CONFIGURED_SINKS = new WeakMap();
|
|
35
|
+
export function mcpFailureReporterOf(framework) {
|
|
36
|
+
const sink = CONFIGURED_SINKS.get(framework);
|
|
37
|
+
return (error) => {
|
|
38
|
+
if (sink !== undefined) {
|
|
39
|
+
try {
|
|
40
|
+
const settled = sink({
|
|
41
|
+
kind: "mcp",
|
|
42
|
+
error,
|
|
43
|
+
code: "A3000",
|
|
44
|
+
origin: "agent",
|
|
45
|
+
requestId: requestIdOf(undefined),
|
|
46
|
+
});
|
|
47
|
+
if (isThenable(settled)) {
|
|
48
|
+
settled.then(undefined, () => undefined);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return internalFailure();
|
|
55
|
+
};
|
|
56
|
+
}
|
|
33
57
|
export function recordDiagnosticsSink(framework, sink) {
|
|
34
58
|
if (sink !== undefined) {
|
|
35
59
|
CONFIGURED_SINKS.set(framework, sink);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DiagnosticsReporter } from "./diagnostics-reporter.js";
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
2
|
+
import { AvError } from "./framework-error.js";
|
|
3
|
+
import type { AvCause, AvOperationErrorCode, AvOperationFailureResponse } from "./operation-response.js";
|
|
4
|
+
import type { AvContext } from "./pipeline.js";
|
|
4
5
|
/** Where an unexpected post-validation exception originated. */
|
|
5
6
|
export type FailureOrigin = "adapter" | "runtime";
|
|
6
7
|
/** The one generic Adapter-failure text; every unexpected A3001 carries it. */
|
|
@@ -39,18 +40,74 @@ export type CallerArgumentsView = {
|
|
|
39
40
|
* framework's text for its code and reported to the diagnostics channel.
|
|
40
41
|
*/
|
|
41
42
|
export declare const MAX_DEVELOPER_ISSUE_MESSAGE_LENGTH = 1000;
|
|
43
|
+
/** The stable outcome a thrower chose, once the boundary has vetted it. */
|
|
44
|
+
type DeliberateOutcome = {
|
|
45
|
+
readonly code: AvOperationErrorCode;
|
|
46
|
+
readonly cause: AvCause;
|
|
47
|
+
/**
|
|
48
|
+
* Every issue code, issue path and developer issue message the boundary could
|
|
49
|
+
* not vouch for, raw and in supplied order.
|
|
50
|
+
*/
|
|
51
|
+
readonly unvouched: readonly unknown[];
|
|
52
|
+
};
|
|
42
53
|
/**
|
|
43
54
|
* Final framework sanitization, shared by every boundary. A deliberate
|
|
44
|
-
* {@link
|
|
55
|
+
* {@link AvError} carries its own stable outcome; anything else is
|
|
45
56
|
* replaced by a generic cause so no provider text, stack, path, or secret
|
|
46
57
|
* can cross the response boundary. Total: it never throws.
|
|
47
58
|
*/
|
|
48
|
-
export declare function sanitizeOperationFailure(error: unknown, origin: FailureOrigin, report: DiagnosticsReporter, view: CallerArgumentsView):
|
|
59
|
+
export declare function sanitizeOperationFailure(error: unknown, origin: FailureOrigin, report: DiagnosticsReporter, view: CallerArgumentsView): AvOperationFailureResponse;
|
|
60
|
+
/**
|
|
61
|
+
* A filter over the context its stage is told: an operation's `AvFilter`,
|
|
62
|
+
* or a Resource transaction filter, whose context is the plan.
|
|
63
|
+
*/
|
|
64
|
+
type FilterOf<Context> = (error: unknown, context: Context) => AvError | undefined | Promise<AvError | undefined>;
|
|
49
65
|
/**
|
|
50
66
|
* Post-validation exception flow: effective filters are stored as `[root...,
|
|
51
67
|
* scoped...]`, so reverse iteration tries scoped filters in reverse registration
|
|
52
|
-
* order, then root filters in reverse
|
|
53
|
-
*
|
|
54
|
-
*
|
|
68
|
+
* order, then root filters in reverse. An error they leave unhandled goes to
|
|
69
|
+
* `outer` when there is one (a transaction step's: its Resource transaction
|
|
70
|
+
* filters, run once the transaction interceptors have unwound), else to final
|
|
71
|
+
* sanitization. A filter handles an error only by returning a {@link AvError};
|
|
72
|
+
* returning `undefined` or throwing leaves the original error unhandled.
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveOperationFailure<Context = AvContext>(error: unknown, filters: readonly FilterOf<Context>[], context: Context, boundary: AdapterBoundary, report: DiagnosticsReporter, view: CallerArgumentsView, outer?: OuterFailureLayer): Promise<AvOperationFailureResponse>;
|
|
75
|
+
/**
|
|
76
|
+
* An error a step's own filters left unhandled, with what answering it later
|
|
77
|
+
* needs: the caller's arguments as the step held them, the step's Adapter
|
|
78
|
+
* boundary (whose identity says whose words the error is) and its reporter.
|
|
79
|
+
*/
|
|
80
|
+
export type UnhandledFailure = {
|
|
81
|
+
readonly error: unknown;
|
|
82
|
+
readonly view: CallerArgumentsView;
|
|
83
|
+
readonly boundary: AdapterBoundary;
|
|
84
|
+
readonly report: DiagnosticsReporter;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Where a transaction step hands an error its own filters left unhandled. It
|
|
88
|
+
* records the error and answers a provisional failure, which fails the step; the
|
|
89
|
+
* transaction replaces it with the transaction filters' answer.
|
|
55
90
|
*/
|
|
56
|
-
export
|
|
91
|
+
export type OuterFailureLayer = {
|
|
92
|
+
readonly defer: (failure: UnhandledFailure) => AvOperationFailureResponse;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* An unhandled step error through `chain` (the transaction filters, the first
|
|
96
|
+
* that handles it wins), then final sanitization.
|
|
97
|
+
*/
|
|
98
|
+
export declare function resolveUnhandledFailure(failure: UnhandledFailure, chain: FilterChain): Promise<AvOperationFailureResponse>;
|
|
99
|
+
/**
|
|
100
|
+
* A chain of filters and the context they are told, tried in reverse: the first
|
|
101
|
+
* that returns an {@link AvError} handles the error.
|
|
102
|
+
*/
|
|
103
|
+
export type FilterChain = {
|
|
104
|
+
readonly attempt: (error: unknown, view: CallerArgumentsView, boundary: AdapterBoundary) => Promise<FilteredOutcome | undefined>;
|
|
105
|
+
};
|
|
106
|
+
/** The chain of `filters` (stored outer to inner, tried in reverse), told `context`. */
|
|
107
|
+
export declare function filterChain<Context>(filters: readonly FilterOf<Context>[], context: Context): FilterChain;
|
|
108
|
+
/** What a filter returned, and the deliberate outcome it vets as. */
|
|
109
|
+
type FilteredOutcome = {
|
|
110
|
+
readonly returned: unknown;
|
|
111
|
+
readonly outcome: DeliberateOutcome;
|
|
112
|
+
};
|
|
113
|
+
export {};
|