@aventara/core 1.0.0-rc.0 → 1.0.0-rc.10
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 +2068 -1
- package/ERRORS.md +142 -0
- package/README.md +485 -60
- 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 +33 -11
- package/dist/adapters/adapter-identifier.d.ts +15 -6
- package/dist/adapters/adapter-identifier.js +6 -1
- 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 +21 -6
- package/dist/adapters/adapter-resource.d.ts +23 -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 +9 -8
- 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 +23 -17
- package/dist/compiler/contract.compiler.js +753 -443
- 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/compiler/managed-elsewhere.projector.d.ts +52 -0
- package/dist/compiler/managed-elsewhere.projector.js +179 -0
- package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
- package/dist/compiler/managed-elsewhere.validator.js +74 -0
- package/dist/config/any-framework-config.d.ts +19 -12
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +73 -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 +98 -31
- package/dist/config/config.resolver.js +173 -44
- package/dist/config/config.validator.d.ts +7 -7
- package/dist/config/config.validator.js +792 -69
- package/dist/config/define-resource.d.ts +53 -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 +4 -3
- package/dist/config/exact-framework-config.d.ts +325 -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 +148 -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 +127 -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/access-route.rules.d.ts +10 -0
- package/dist/contracts/access-route.rules.js +45 -0
- package/dist/contracts/capability.d.ts +37 -12
- package/dist/contracts/capability.js +20 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +621 -114
- package/dist/contracts/client-contract-structure.validator.js +189 -10
- package/dist/contracts/contract-access.d.ts +29 -0
- package/dist/contracts/contract-access.js +1 -0
- package/dist/contracts/contract-canonicalizer.d.ts +27 -3
- package/dist/contracts/contract-canonicalizer.js +168 -29
- package/dist/contracts/contract-hash.d.ts +11 -7
- package/dist/contracts/contract-hash.js +4 -3
- 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 +51 -17
- 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 +109 -42
- package/dist/contracts/identifier.d.ts +4 -4
- package/dist/contracts/json-schema.projector.d.ts +11 -0
- package/dist/contracts/json-schema.projector.js +78 -0
- 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 +17 -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/access-facade.d.ts +116 -0
- package/dist/framework/access-facade.js +120 -0
- package/dist/framework/contract-view.d.ts +315 -145
- package/dist/framework/framework-construction.error.d.ts +21 -11
- package/dist/framework/framework-construction.error.js +20 -4
- package/dist/framework/framework.d.ts +71 -26
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +150 -38
- package/dist/framework/operation-facade.d.ts +192 -54
- package/dist/framework/operation-facade.js +10 -1
- package/dist/index.d.ts +67 -50
- package/dist/index.js +7 -6
- package/dist/internal.d.ts +20 -10
- package/dist/internal.js +9 -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 +381 -228
- package/dist/operations/operation-call.d.ts +31 -28
- package/dist/operations/operation-identity.d.ts +10 -10
- package/dist/operations/operation-result.d.ts +25 -23
- package/dist/operations/operation-validator-core.d.ts +6 -6
- package/dist/operations/operation-validator-core.js +172 -38
- package/dist/operations/operation-validator.d.ts +10 -10
- package/dist/operations/projection-scope.resolver.d.ts +6 -6
- package/dist/operations/structural-limits.walker.d.ts +7 -7
- 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/policy/access-provider.interface.d.ts +91 -0
- package/dist/policy/access-provider.interface.js +1 -0
- package/dist/policy/access-provider.registry.d.ts +17 -0
- package/dist/policy/access-provider.registry.js +15 -0
- package/dist/policy/access-question.d.ts +20 -0
- package/dist/policy/access-question.js +1 -0
- package/dist/policy/access-question.registry.d.ts +5 -0
- package/dist/policy/access-question.registry.js +19 -0
- package/dist/policy/access-question.runtime.d.ts +36 -0
- package/dist/policy/access-question.runtime.js +297 -0
- package/dist/policy/access-verb.table.d.ts +56 -0
- package/dist/policy/access-verb.table.js +21 -0
- package/dist/policy/access-verbs.d.ts +46 -0
- package/dist/policy/access-verbs.js +1 -0
- package/dist/policy/policy-admission.d.ts +20 -0
- package/dist/policy/policy-admission.js +409 -0
- package/dist/policy/policy-after-update.runtime.d.ts +79 -0
- package/dist/policy/policy-after-update.runtime.js +208 -0
- package/dist/policy/policy-condition.d.ts +15 -0
- package/dist/policy/policy-condition.js +36 -0
- package/dist/policy/policy-engine.d.ts +205 -0
- package/dist/policy/policy-engine.js +1 -0
- package/dist/policy/policy-named-rows.d.ts +18 -0
- package/dist/policy/policy-named-rows.js +51 -0
- package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
- package/dist/policy/policy-nested-write.runtime.js +545 -0
- package/dist/policy/policy-read.runtime.d.ts +81 -0
- package/dist/policy/policy-read.runtime.js +503 -0
- package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
- package/dist/policy/policy-reference-write.runtime.js +345 -0
- package/dist/policy/policy-request.d.ts +41 -0
- package/dist/policy/policy-request.js +63 -0
- package/dist/policy/policy-session.d.ts +106 -0
- package/dist/policy/policy-session.js +295 -0
- package/dist/policy/policy-startup.validator.d.ts +10 -0
- package/dist/policy/policy-startup.validator.js +112 -0
- package/dist/policy/policy-write.runtime.d.ts +39 -0
- package/dist/policy/policy-write.runtime.js +532 -0
- package/dist/prebuilt/core-version.generated.d.ts +2 -0
- package/dist/prebuilt/core-version.generated.js +1 -0
- package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
- package/dist/prebuilt/prebuilt-changes.js +65 -0
- package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
- package/dist/prebuilt/prebuilt-contracts.js +1 -0
- package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
- package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
- package/dist/protocol/absent-route.responder.d.ts +17 -34
- package/dist/protocol/absent-route.responder.js +53 -20
- package/dist/protocol/contract-document.responder.d.ts +5 -4
- package/dist/protocol/contract-document.responder.js +2 -2
- package/dist/protocol/http-request.decoder.d.ts +33 -13
- package/dist/protocol/http-request.decoder.js +34 -11
- package/dist/protocol/http-request.reader.d.ts +9 -6
- package/dist/protocol/http-request.reader.js +1 -0
- 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-headers.d.ts +3 -3
- package/dist/protocol/protocol-surface.d.ts +10 -5
- package/dist/protocol/protocol-surface.js +7 -0
- package/dist/protocol/protocol.binder.d.ts +66 -28
- package/dist/protocol/protocol.binder.js +16 -10
- package/dist/protocol/protocol.handler.d.ts +34 -14
- package/dist/protocol/protocol.handler.js +122 -18
- 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 -7
- package/dist/runtime/caller-data.copier.js +30 -17
- package/dist/runtime/caller-data.door.d.ts +18 -11
- package/dist/runtime/caller-data.door.js +6 -4
- package/dist/runtime/computed-read-runtime.d.ts +12 -6
- package/dist/runtime/computed-read-runtime.js +271 -71
- 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 +60 -0
- package/dist/runtime/context-executor.runtime.js +277 -0
- package/dist/runtime/core-class.brand.d.ts +10 -0
- package/dist/runtime/core-class.brand.js +21 -0
- package/dist/runtime/create-requirement.d.ts +34 -79
- package/dist/runtime/create-requirement.js +205 -74
- package/dist/runtime/decimal.d.ts +16 -2
- package/dist/runtime/decimal.js +22 -1
- package/dist/runtime/diagnostics-reporter.d.ts +91 -30
- package/dist/runtime/diagnostics-reporter.js +37 -1
- package/dist/runtime/error-boundary.d.ts +73 -9
- package/dist/runtime/error-boundary.js +57 -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 +18 -2
- package/dist/runtime/field-check.evaluator.d.ts +27 -0
- package/dist/runtime/field-check.evaluator.js +521 -0
- package/dist/runtime/field-compute.d.ts +65 -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 +29 -0
- package/dist/runtime/field-validator.runtime.js +126 -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 +32 -2
- package/dist/runtime/framework-warning.emitter.d.ts +6 -0
- package/dist/runtime/framework-warning.emitter.js +8 -0
- 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 +26 -0
- package/dist/runtime/level-lifecycle.runtime.js +40 -0
- package/dist/runtime/misuse-reporter.d.ts +12 -12
- package/dist/runtime/mutation-planner.d.ts +20 -16
- 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 +45 -11
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +133 -27
- package/dist/runtime/operation-runtime.js +576 -84
- package/dist/runtime/outcome-mapper.d.ts +17 -5
- package/dist/runtime/outcome-mapper.js +23 -6
- package/dist/runtime/output-validator.d.ts +11 -11
- 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 +221 -34
- package/dist/runtime/readonly-value.d.ts +47 -0
- package/dist/runtime/readonly-value.js +189 -0
- package/dist/runtime/referential-action.d.ts +1 -1
- 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 +33 -25
- package/dist/runtime/scalar-runtime.js +105 -38
- 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 +8 -3
- 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 +9 -8
- package/dist/transactions/transaction-integrity-error.d.ts +6 -6
- package/dist/transactions/transaction-integrity-error.js +7 -2
- package/dist/transactions/transaction-plan-assembler.d.ts +30 -13
- package/dist/transactions/transaction-plan-assembler.js +184 -32
- package/dist/transactions/transaction-plan-validator.d.ts +50 -25
- 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 +21 -3
- package/dist/transactions/transaction-reference-resolver.js +26 -14
- package/dist/transactions/transaction-reference-validator.d.ts +74 -4
- package/dist/transactions/transaction-reference-validator.js +129 -71
- package/dist/transactions/transaction-reference.d.ts +14 -14
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +22 -9
- package/dist/transactions/transaction-response.d.ts +6 -6
- package/dist/transactions/transaction-runtime.d.ts +12 -8
- package/dist/transactions/transaction-runtime.js +218 -50
- package/dist/transactions/transaction-settlement.runtime.d.ts +52 -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 +4 -2
- package/dist/transactions/transaction-slot-writer.js +2 -2
- package/dist/transactions/transaction-stage.runtime.d.ts +83 -0
- package/dist/transactions/transaction-stage.runtime.js +126 -0
- package/package.json +11 -9
- 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,26 +8,12 @@ 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 : [];
|
|
18
14
|
}
|
|
19
15
|
function referencesOf(edge) {
|
|
20
|
-
return Array.isArray(edge.
|
|
21
|
-
}
|
|
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")));
|
|
16
|
+
return Array.isArray(edge.referenceFields) ? edge.referenceFields : [];
|
|
31
17
|
}
|
|
32
18
|
function creatableScalar(contract, resource, field) {
|
|
33
19
|
const found = lookupField(lookupResource(contract, resource), field);
|
|
@@ -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,43 @@ 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 computedRequirementGapsOf(contract, facts, request, args, argumentsPath, computed) {
|
|
318
|
+
const gaps = [];
|
|
319
|
+
walkOperation({
|
|
320
|
+
contract,
|
|
321
|
+
references: facts.references,
|
|
322
|
+
issues: [],
|
|
323
|
+
computed: { stated: facts.stated, computed },
|
|
324
|
+
gaps,
|
|
325
|
+
}, request, args, argumentsPath);
|
|
326
|
+
return gaps;
|
|
327
|
+
}
|
|
328
|
+
function walkOperation(context, request, args, argumentsPath) {
|
|
329
|
+
if (!isRecord(args)) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const contract = context.contract;
|
|
195
333
|
const scope = resolveWriteScope(lookupResource(contract, request.resource), request);
|
|
196
334
|
if (request.family === "create" && written(args, "data")) {
|
|
197
335
|
const data = args.data;
|
|
@@ -206,16 +344,9 @@ export function createRequirementIssues(contract, facts, request, args, argument
|
|
|
206
344
|
}
|
|
207
345
|
if (request.family === "upsert") {
|
|
208
346
|
checkCreateRecord(context, request.resource, args.create, [...argumentsPath, "create"], scope, undefined);
|
|
209
|
-
checkUpdateRecord(context, request.resource, args.update, [
|
|
210
|
-
...argumentsPath,
|
|
211
|
-
"update",
|
|
212
|
-
]);
|
|
347
|
+
checkUpdateRecord(context, request.resource, args.update, [...argumentsPath, "update"], undefined);
|
|
213
348
|
}
|
|
214
349
|
if (request.family === "update") {
|
|
215
|
-
checkUpdateRecord(context, request.resource, args.data, [
|
|
216
|
-
...argumentsPath,
|
|
217
|
-
"data",
|
|
218
|
-
]);
|
|
350
|
+
checkUpdateRecord(context, request.resource, args.data, [...argumentsPath, "data"], undefined);
|
|
219
351
|
}
|
|
220
|
-
return context.issues;
|
|
221
352
|
}
|
|
@@ -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;
|
|
@@ -12,3 +12,17 @@ export declare class Decimal {
|
|
|
12
12
|
*/
|
|
13
13
|
toJSON(): string;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether `value` is an `AvDecimal`, made by this copy of core or by another of
|
|
17
|
+
* its major: one `in`, for the hot paths that ask about every value.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isAvDecimal(value: unknown): value is AvDecimal;
|
|
20
|
+
/**
|
|
21
|
+
* The digits of `value`, read without running anything the caller could have put
|
|
22
|
+
* on it when this copy made it. Another copy's decimal is read through its own
|
|
23
|
+
* `toString`, which only that copy can answer; what it returns is checked as a
|
|
24
|
+
* decimal string, so the caller's copy keeps the grammar.
|
|
25
|
+
*
|
|
26
|
+
* @throws TypeError when another copy's decimal does not answer a decimal string.
|
|
27
|
+
*/
|
|
28
|
+
export declare function decimalDigitsOf(value: AvDecimal): string;
|
package/dist/runtime/decimal.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { WIRE_SCALAR_PATTERNS } from "../contracts/wire-scalar-format.js";
|
|
2
|
-
|
|
2
|
+
import { brandCoreClass, hasCoreBrand } from "./core-class.brand.js";
|
|
3
|
+
let ownDigitsOf;
|
|
4
|
+
export class AvDecimal {
|
|
3
5
|
#value;
|
|
6
|
+
static {
|
|
7
|
+
ownDigitsOf = (value) => (#value in value ? value.#value : undefined);
|
|
8
|
+
}
|
|
4
9
|
constructor(value) {
|
|
5
10
|
if (typeof value !== "string") {
|
|
6
11
|
throw new TypeError("Decimal value must be a string.");
|
|
@@ -17,3 +22,19 @@ export class Decimal {
|
|
|
17
22
|
return this.#value;
|
|
18
23
|
}
|
|
19
24
|
}
|
|
25
|
+
const DECIMAL_BRAND = brandCoreClass(AvDecimal, "AvDecimal");
|
|
26
|
+
export function isAvDecimal(value) {
|
|
27
|
+
return hasCoreBrand(value, DECIMAL_BRAND);
|
|
28
|
+
}
|
|
29
|
+
export function decimalDigitsOf(value) {
|
|
30
|
+
const own = ownDigitsOf(value);
|
|
31
|
+
if (own !== undefined) {
|
|
32
|
+
return own;
|
|
33
|
+
}
|
|
34
|
+
const digits = value.toString();
|
|
35
|
+
if (typeof digits !== "string" ||
|
|
36
|
+
!WIRE_SCALAR_PATTERNS.decimal.test(digits)) {
|
|
37
|
+
throw new TypeError("Decimal value must be a valid decimal string.");
|
|
38
|
+
}
|
|
39
|
+
return digits;
|
|
40
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import type
|
|
1
|
+
import type { AvRequestOrigin } from "../config/config-layer.js";
|
|
2
|
+
import type { AvOperationFamily } from "../operations/operation-identity.js";
|
|
3
|
+
import type { AvTransactionRequest } from "../transactions/transaction-request.js";
|
|
4
|
+
import type { AvOperationRequest } from "./operation-request.js";
|
|
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,55 +32,116 @@ 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
|
+
/**
|
|
67
|
+
* One unplanned failure of a `POST /_access/can` request: the raw error, the
|
|
68
|
+
* code the caller received, and, when one question met it, that question's
|
|
69
|
+
* index (`question`), Resource and action; none of the three when the batch
|
|
70
|
+
* as a whole failed.
|
|
71
|
+
*/
|
|
72
|
+
export type AvCanDiagnostic = {
|
|
73
|
+
readonly kind: "can";
|
|
74
|
+
readonly error: unknown;
|
|
75
|
+
readonly code: AvOperationErrorCode;
|
|
76
|
+
/** The route is the clients': an agent has no `can` route. */
|
|
77
|
+
readonly origin: "client";
|
|
78
|
+
readonly requestId: string;
|
|
79
|
+
/** Never present: no operation of a plan is involved (see `question`). */
|
|
80
|
+
readonly operation?: never;
|
|
81
|
+
/** Never present: only an operation diagnostic is marked `deliberate`. */
|
|
82
|
+
readonly deliberate?: never;
|
|
83
|
+
} & ({
|
|
84
|
+
/** The index of the question in `questions` the failure is blamed on. */
|
|
85
|
+
readonly question: number;
|
|
86
|
+
/** That question's Resource. */
|
|
87
|
+
readonly resource: string;
|
|
88
|
+
/** That question's action. */
|
|
89
|
+
readonly action: "read" | "create" | "update" | "delete";
|
|
90
|
+
} | {
|
|
91
|
+
readonly question?: never;
|
|
92
|
+
readonly resource?: never;
|
|
93
|
+
readonly action?: never;
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* One diagnostic: of an operation, of a transaction as a whole, of a `can`
|
|
97
|
+
* request, or of the MCP endpoint.
|
|
98
|
+
*/
|
|
99
|
+
export type AvDiagnostic = AvOperationDiagnostic | AvTransactionDiagnostic | AvCanDiagnostic | AvMcpDiagnostic;
|
|
50
100
|
/**
|
|
51
101
|
* Receives a diagnostic for every unplanned failure. Set once, as the root
|
|
52
102
|
* configuration's `diagnostics`.
|
|
53
103
|
*/
|
|
54
|
-
export type
|
|
104
|
+
export type AvDiagnosticsSink = (diagnostic: AvDiagnostic) => void | Promise<void>;
|
|
55
105
|
/**
|
|
56
106
|
* The channel as the runtime holds it: bound to one request, told the raw
|
|
57
107
|
* error and the code being emitted. Total by construction — it returns
|
|
58
108
|
* before the sink has finished and swallows everything the sink does.
|
|
59
109
|
*/
|
|
60
|
-
export type DiagnosticsReporter = (error: unknown, code:
|
|
110
|
+
export type DiagnosticsReporter = (error: unknown, code: AvOperationErrorCode, marks?: DiagnosticMarks) => void;
|
|
61
111
|
/** What a report states about its error beyond the code: today, whether it was deliberate. */
|
|
62
|
-
export type DiagnosticMarks = Pick<
|
|
112
|
+
export type DiagnosticMarks = Pick<AvOperationDiagnostic, "deliberate">;
|
|
63
113
|
/** The identifying half of a diagnostic, captured once per request. */
|
|
64
|
-
type OperationDiagnosticIdentity = Omit<
|
|
65
|
-
type TransactionDiagnosticIdentity = Omit<
|
|
114
|
+
type OperationDiagnosticIdentity = Omit<AvOperationDiagnostic, "error" | "code">;
|
|
115
|
+
type TransactionDiagnosticIdentity = Omit<AvTransactionDiagnostic, "error" | "code">;
|
|
116
|
+
/** A `can` request's identity: its batch's, or one question's. */
|
|
117
|
+
type CanDiagnosticIdentity = AvCanDiagnostic extends infer Diagnostic ? Diagnostic extends unknown ? Omit<Diagnostic, "error" | "code"> : never : never;
|
|
66
118
|
/** The diagnostics channel bound to one diagnostic identity. */
|
|
67
|
-
export declare function createReporter(sink:
|
|
119
|
+
export declare function createReporter(sink: AvDiagnosticsSink | undefined, identity: OperationDiagnosticIdentity | TransactionDiagnosticIdentity | CanDiagnosticIdentity): DiagnosticsReporter;
|
|
120
|
+
/**
|
|
121
|
+
* The MCP endpoint's failure channel for `framework`: each call reports one
|
|
122
|
+
* {@link AvMcpDiagnostic} to its configured sink, under a minted request id, and
|
|
123
|
+
* answers the response the caller receives instead: the generic `A3000`, which
|
|
124
|
+
* carries nothing of the error. Total: it returns before the sink has finished
|
|
125
|
+
* and swallows everything the sink does. A Framework without a sink gets a
|
|
126
|
+
* channel that observes nothing and still answers the `A3000`.
|
|
127
|
+
*/
|
|
128
|
+
export declare function mcpFailureReporterOf(framework: object): (error: unknown) => AvOperationFailureResponse;
|
|
68
129
|
/** Records the sink `framework` was configured with; called once, at construction. */
|
|
69
|
-
export declare function recordDiagnosticsSink(framework: object, sink:
|
|
130
|
+
export declare function recordDiagnosticsSink(framework: object, sink: AvDiagnosticsSink | undefined): void;
|
|
70
131
|
/** The sink `framework` was configured with, or `undefined` for none. */
|
|
71
|
-
export declare function diagnosticsSinkOf(framework: object):
|
|
132
|
+
export declare function diagnosticsSinkOf(framework: object): AvDiagnosticsSink | undefined;
|
|
72
133
|
/**
|
|
73
134
|
* Binds the configured sink to one operation request. The sink is not awaited,
|
|
74
135
|
* and nothing it throws or rejects with reaches the response.
|
|
75
136
|
*/
|
|
76
|
-
export declare function createDiagnosticsReporter(sink:
|
|
137
|
+
export declare function createDiagnosticsReporter(sink: AvDiagnosticsSink | undefined, request: AvOperationRequest, operation?: number): DiagnosticsReporter;
|
|
77
138
|
/** The diagnostics channel of one transaction request. */
|
|
78
139
|
export type TransactionDiagnosticsChannel = {
|
|
79
140
|
/** A plan-level report; `operation` attributes it to a recorded failing index. */
|
|
80
141
|
readonly transaction: (operation?: number) => DiagnosticsReporter;
|
|
81
142
|
/** A report carrying one plan operation's own identity and index. */
|
|
82
|
-
readonly operation: (request:
|
|
143
|
+
readonly operation: (request: AvOperationRequest, operation: number) => DiagnosticsReporter;
|
|
83
144
|
};
|
|
84
145
|
/** Binds the configured sink to one transaction request and its plan operations. */
|
|
85
|
-
export declare function createTransactionDiagnosticsChannel(sink:
|
|
146
|
+
export declare function createTransactionDiagnosticsChannel(sink: AvDiagnosticsSink | undefined, request: AvTransactionRequest): TransactionDiagnosticsChannel;
|
|
86
147
|
export {};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { coreBrandOf } from "./core-class.brand.js";
|
|
2
|
+
import { internalFailure, } from "./operation-response.js";
|
|
3
|
+
import { requestIdOf } from "./request-id.js";
|
|
1
4
|
const IGNORE_DIAGNOSTIC = () => undefined;
|
|
2
5
|
function isThenable(value) {
|
|
3
6
|
if ((typeof value !== "object" || value === null) &&
|
|
@@ -29,7 +32,40 @@ export function createReporter(sink, identity) {
|
|
|
29
32
|
}
|
|
30
33
|
};
|
|
31
34
|
}
|
|
32
|
-
const CONFIGURED_SINKS =
|
|
35
|
+
const CONFIGURED_SINKS = sharedSinkRegistry();
|
|
36
|
+
function sharedSinkRegistry() {
|
|
37
|
+
const key = coreBrandOf("diagnostics");
|
|
38
|
+
const holder = globalThis;
|
|
39
|
+
const existing = holder[key];
|
|
40
|
+
if (existing instanceof WeakMap) {
|
|
41
|
+
return existing;
|
|
42
|
+
}
|
|
43
|
+
const registry = new WeakMap();
|
|
44
|
+
Object.defineProperty(holder, key, { value: registry });
|
|
45
|
+
return registry;
|
|
46
|
+
}
|
|
47
|
+
export function mcpFailureReporterOf(framework) {
|
|
48
|
+
const sink = CONFIGURED_SINKS.get(framework);
|
|
49
|
+
return (error) => {
|
|
50
|
+
if (sink !== undefined) {
|
|
51
|
+
try {
|
|
52
|
+
const settled = sink({
|
|
53
|
+
kind: "mcp",
|
|
54
|
+
error,
|
|
55
|
+
code: "A3000",
|
|
56
|
+
origin: "agent",
|
|
57
|
+
requestId: requestIdOf(undefined),
|
|
58
|
+
});
|
|
59
|
+
if (isThenable(settled)) {
|
|
60
|
+
settled.then(undefined, () => undefined);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return internalFailure();
|
|
67
|
+
};
|
|
68
|
+
}
|
|
33
69
|
export function recordDiagnosticsSink(framework, sink) {
|
|
34
70
|
if (sink !== undefined) {
|
|
35
71
|
CONFIGURED_SINKS.set(framework, sink);
|