@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
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { frozenCopy } from "./readonly-value.js";
|
|
2
|
+
export function isPlainRecord(value) {
|
|
3
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
const prototype = Object.getPrototypeOf(value);
|
|
7
|
+
return prototype === Object.prototype || prototype === null;
|
|
8
|
+
}
|
|
9
|
+
export const WRITE_KEYS = {
|
|
10
|
+
create: ["data"],
|
|
11
|
+
update: ["data"],
|
|
12
|
+
upsert: ["create", "update"],
|
|
13
|
+
};
|
|
14
|
+
function writeRecordsOf(family, args) {
|
|
15
|
+
const keys = WRITE_KEYS[family];
|
|
16
|
+
if (keys === undefined || !isPlainRecord(args)) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const records = [];
|
|
20
|
+
for (const key of keys) {
|
|
21
|
+
if (!Object.hasOwn(args, key)) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const value = args[key];
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
for (const [index, entry] of value.entries()) {
|
|
27
|
+
if (isPlainRecord(entry)) {
|
|
28
|
+
records.push({ path: [key, index], record: entry });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (isPlainRecord(value)) {
|
|
33
|
+
records.push({ path: [key], record: value });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return records;
|
|
37
|
+
}
|
|
38
|
+
function sends(record, field) {
|
|
39
|
+
return Object.hasOwn(record, field) && record[field] !== undefined;
|
|
40
|
+
}
|
|
41
|
+
function isDirective(value) {
|
|
42
|
+
return (isPlainRecord(value) &&
|
|
43
|
+
Object.keys(value).some((key) => key.startsWith("$")));
|
|
44
|
+
}
|
|
45
|
+
export function stagedFieldsOf(contract, resource, stages, kind) {
|
|
46
|
+
const fields = Object.hasOwn(contract.resources, resource)
|
|
47
|
+
? contract.resources[resource]?.fields
|
|
48
|
+
: undefined;
|
|
49
|
+
if (fields === undefined) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
return Object.keys(fields).filter((field) => Object.hasOwn(stages, field) && (stages[field]?.[kind].length ?? 0) > 0);
|
|
53
|
+
}
|
|
54
|
+
export function valueAt(args, path) {
|
|
55
|
+
let current = args;
|
|
56
|
+
for (const key of path) {
|
|
57
|
+
if (Array.isArray(current) && typeof key === "number") {
|
|
58
|
+
current = current[key];
|
|
59
|
+
}
|
|
60
|
+
else if (isPlainRecord(current) && Object.hasOwn(current, key)) {
|
|
61
|
+
current = current[key];
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return current;
|
|
68
|
+
}
|
|
69
|
+
export function replaceAt(args, path, record) {
|
|
70
|
+
const [head, ...rest] = path;
|
|
71
|
+
if (head === undefined) {
|
|
72
|
+
return record;
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(args)) {
|
|
75
|
+
const copy = [...args];
|
|
76
|
+
copy[head] = replaceAt(copy[head], rest, record);
|
|
77
|
+
return copy;
|
|
78
|
+
}
|
|
79
|
+
const container = args;
|
|
80
|
+
return {
|
|
81
|
+
...container,
|
|
82
|
+
[head]: replaceAt(container[head], rest, record),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export function writeRecordPathsOf(family, args) {
|
|
86
|
+
return writeRecordsOf(family, args).map((entry) => entry.path);
|
|
87
|
+
}
|
|
88
|
+
export async function pipeSentFields(stages, fields, records, args, select) {
|
|
89
|
+
if (fields.length === 0) {
|
|
90
|
+
return { args, changed: false };
|
|
91
|
+
}
|
|
92
|
+
let current = args;
|
|
93
|
+
let changed = false;
|
|
94
|
+
for (const path of records) {
|
|
95
|
+
const record = valueAt(current, path);
|
|
96
|
+
if (!isPlainRecord(record)) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
let piped;
|
|
100
|
+
for (const field of fields) {
|
|
101
|
+
if (!sends(record, field) ||
|
|
102
|
+
isDirective(record[field]) ||
|
|
103
|
+
!select([...path, field])) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
let value = record[field];
|
|
107
|
+
for (const pipe of stages[field]?.pipes ?? []) {
|
|
108
|
+
const told = frozenCopy(value);
|
|
109
|
+
const next = await pipe(told);
|
|
110
|
+
if (next !== undefined) {
|
|
111
|
+
if (next !== told) {
|
|
112
|
+
value = next;
|
|
113
|
+
}
|
|
114
|
+
changed = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (value !== record[field]) {
|
|
118
|
+
piped ??= { ...record };
|
|
119
|
+
piped[field] = value;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (piped !== undefined) {
|
|
123
|
+
current = replaceAt(current, path, piped);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { args: current, changed };
|
|
127
|
+
}
|
|
128
|
+
export async function guardSentFields(stages, fields, records, args, context) {
|
|
129
|
+
if (fields.length === 0) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
const sent = records.map((path) => valueAt(args, path)).filter(isPlainRecord);
|
|
133
|
+
for (const field of fields) {
|
|
134
|
+
for (const record of sent) {
|
|
135
|
+
if (!sends(record, field)) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
for (const guard of stages[field]?.guards ?? []) {
|
|
139
|
+
const told = context();
|
|
140
|
+
if ((await guard(frozenCopy(record[field]), told)) === false) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
3
|
+
import { AvComputedValueError } from "./computed-value.error.js";
|
|
4
|
+
import { type Path } from "./field-stage.runtime.js";
|
|
5
|
+
import type { OperationExecutionRequest } from "./operation-request.js";
|
|
6
|
+
import type { ReferentialActionTable } from "./referential-action.js";
|
|
7
|
+
/** The write phase of a record: a created row (an upsert's `create` branch too) or an updated one. */
|
|
8
|
+
type WriteStage = "create" | "update";
|
|
9
|
+
/**
|
|
10
|
+
* The fields a judgment leaves for later: a plan step's (or a forced call's)
|
|
11
|
+
* literal values are judged before BEGIN, except a field a write compute stage
|
|
12
|
+
* of that phase may still change, which is judged after write compute.
|
|
13
|
+
*/
|
|
14
|
+
type DeferredField = (resource: string, stage: WriteStage, field: string) => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Every way the sent fields `select` admits break their validators: the
|
|
17
|
+
* operation's own records, then each nested write target's. Paths are the
|
|
18
|
+
* request's: `argumentsPath` and then the value's place in the arguments.
|
|
19
|
+
*/
|
|
20
|
+
export declare function fieldValidatorIssues(contract: AvContract, references: ReferentialActionTable, request: OperationExecutionRequest, args: unknown, argumentsPath: Path, select: (path: Path) => boolean, deferred?: DeferredField): readonly AvValidationIssue[];
|
|
21
|
+
/**
|
|
22
|
+
* The server's defect when a value written to a field the active layer hides
|
|
23
|
+
* breaks its validators or its Json shape, or `undefined`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function hiddenFieldRefusal(contracts: {
|
|
26
|
+
readonly core: AvContract;
|
|
27
|
+
readonly active: AvContract;
|
|
28
|
+
}, references: ReferentialActionTable, request: OperationExecutionRequest, args: unknown, argumentsPath: Path): AvComputedValueError | undefined;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { hasFieldValidators, validatedFieldsOf, } from "../compiler/field-validator.compiler.js";
|
|
2
|
+
import { AvComputedValueError } from "./computed-value.error.js";
|
|
3
|
+
import { entryCheckIssues, fieldCheckIssues } from "./field-check.evaluator.js";
|
|
4
|
+
import { isPlainRecord, valueAt, writeRecordPathsOf, } from "./field-stage.runtime.js";
|
|
5
|
+
import { nestedWriteTargetsOf } from "./nested-write.walker.js";
|
|
6
|
+
import { jsonShapeIssues } from "./scalar-runtime.js";
|
|
7
|
+
function isDirective(value) {
|
|
8
|
+
return (isPlainRecord(value) &&
|
|
9
|
+
Object.keys(value).some((key) => key.startsWith("$")));
|
|
10
|
+
}
|
|
11
|
+
function rulesOf(contract, compiled, resource, name) {
|
|
12
|
+
const fields = Object.hasOwn(contract.resources, resource)
|
|
13
|
+
? contract.resources[resource]?.fields
|
|
14
|
+
: undefined;
|
|
15
|
+
const field = fields !== undefined && Object.hasOwn(fields, name)
|
|
16
|
+
? fields[name]
|
|
17
|
+
: undefined;
|
|
18
|
+
if (field === undefined) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
if (field.kind === "scalar" && field.json !== undefined) {
|
|
22
|
+
return { kind: "shape", field };
|
|
23
|
+
}
|
|
24
|
+
const checks = Object.hasOwn(compiled, name) ? compiled[name] : undefined;
|
|
25
|
+
return checks === undefined
|
|
26
|
+
? undefined
|
|
27
|
+
: { kind: "checks", compiled: checks };
|
|
28
|
+
}
|
|
29
|
+
function valueIssues(rules, value, at) {
|
|
30
|
+
if (rules.kind === "shape") {
|
|
31
|
+
return jsonShapeIssues(rules.field, value, at);
|
|
32
|
+
}
|
|
33
|
+
const { compiled } = rules;
|
|
34
|
+
return fieldCheckIssues(compiled.checks, value, compiled.subject ?? "string", at, compiled.list);
|
|
35
|
+
}
|
|
36
|
+
function entryIssues(rules, entry, at) {
|
|
37
|
+
if (rules.kind === "shape") {
|
|
38
|
+
return jsonShapeIssues(rules.field, entry, at, "entry");
|
|
39
|
+
}
|
|
40
|
+
const { compiled } = rules;
|
|
41
|
+
return entryCheckIssues(compiled.checks, entry, compiled.subject ?? "string", at);
|
|
42
|
+
}
|
|
43
|
+
function recordIssues(contract, resource, records, args, argumentsPath, select, deferred) {
|
|
44
|
+
const compiled = validatedFieldsOf(contract, resource);
|
|
45
|
+
const issues = [];
|
|
46
|
+
for (const { path, stage } of records) {
|
|
47
|
+
const record = valueAt(args, path);
|
|
48
|
+
if (!isPlainRecord(record)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
for (const name of Object.keys(record)) {
|
|
52
|
+
const rules = rulesOf(contract, compiled, resource, name);
|
|
53
|
+
if (rules === undefined || deferred?.(resource, stage, name) === true) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const fieldPath = [...path, name];
|
|
57
|
+
const value = record[name];
|
|
58
|
+
const at = [...argumentsPath, ...fieldPath];
|
|
59
|
+
if (!isDirective(value)) {
|
|
60
|
+
if (select(fieldPath)) {
|
|
61
|
+
issues.push(...valueIssues(rules, value, at));
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const list = rules.kind === "shape" ? rules.field.list : rules.compiled.list;
|
|
66
|
+
if (!list || !Object.hasOwn(value, "$push")) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const operand = value.$push;
|
|
70
|
+
const pushed = Array.isArray(operand)
|
|
71
|
+
? operand.map((entry, index) => ({
|
|
72
|
+
entry,
|
|
73
|
+
path: [...fieldPath, "$push", index],
|
|
74
|
+
}))
|
|
75
|
+
: [{ entry: operand, path: [...fieldPath, "$push"] }];
|
|
76
|
+
for (const { entry, path: entryPath } of pushed) {
|
|
77
|
+
if (!isDirective(entry) && (select(fieldPath) || select(entryPath))) {
|
|
78
|
+
issues.push(...entryIssues(rules, entry, [...argumentsPath, ...entryPath]));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return issues;
|
|
84
|
+
}
|
|
85
|
+
export function fieldValidatorIssues(contract, references, request, args, argumentsPath, select, deferred) {
|
|
86
|
+
const issues = recordIssues(contract, request.resource, writeRecordPathsOf(request.family, args).map((path) => ({
|
|
87
|
+
path,
|
|
88
|
+
stage: request.family === "create" || path[0] === "create"
|
|
89
|
+
? "create"
|
|
90
|
+
: "update",
|
|
91
|
+
})), args, argumentsPath, select, deferred);
|
|
92
|
+
for (const target of nestedWriteTargetsOf(contract, references, request, args)) {
|
|
93
|
+
issues.push(...recordIssues(contract, target.resource, target.records, args, argumentsPath, select, deferred));
|
|
94
|
+
}
|
|
95
|
+
return issues;
|
|
96
|
+
}
|
|
97
|
+
function holdsField(contract, resource, field) {
|
|
98
|
+
const fields = Object.hasOwn(contract.resources, resource)
|
|
99
|
+
? contract.resources[resource]?.fields
|
|
100
|
+
: undefined;
|
|
101
|
+
return fields !== undefined && Object.hasOwn(fields, field);
|
|
102
|
+
}
|
|
103
|
+
export function hiddenFieldRefusal(contracts, references, request, args, argumentsPath) {
|
|
104
|
+
const { core, active } = contracts;
|
|
105
|
+
if (core === active || !hasFieldValidators(core)) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
const judged = [];
|
|
109
|
+
const issues = fieldValidatorIssues(core, references, request, args, argumentsPath, () => true, (resource, stage, field) => {
|
|
110
|
+
if (holdsField(active, resource, field)) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
judged.push({ resource, stage, field });
|
|
114
|
+
return false;
|
|
115
|
+
});
|
|
116
|
+
const [first] = issues;
|
|
117
|
+
if (first === undefined) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
const path = first.path ?? [];
|
|
121
|
+
const at = judged.find(({ field }) => path.includes(field)) ?? judged[0];
|
|
122
|
+
if (at === undefined) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
return new AvComputedValueError(at.resource, at.field, at.stage, issues, `compute.${at.stage} on ${at.resource}.${at.field}, a field the ${request.origin} layer hides, returned a value its validators refuse (${first.code}: ${first.message})`);
|
|
126
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AvOperationErrorCode } from "./operation-response.js";
|
|
2
|
+
/** The `AvError` subclass every error code is thrown as, by class name. */
|
|
3
|
+
export declare const FRAMEWORK_ERROR_CLASS_OF: {
|
|
4
|
+
readonly A2000: "AvProtocolError";
|
|
5
|
+
readonly A2001: "AvProtocolError";
|
|
6
|
+
readonly A2002: "AvProtocolError";
|
|
7
|
+
readonly A2003: "AvNotFoundError";
|
|
8
|
+
readonly A2004: "AvValidationError";
|
|
9
|
+
readonly A2005: "AvContractMismatchError";
|
|
10
|
+
readonly A2006: "AvProtocolError";
|
|
11
|
+
readonly A2007: "AvValidationError";
|
|
12
|
+
readonly A2008: "AvConflictError";
|
|
13
|
+
readonly A2009: "AvValidationError";
|
|
14
|
+
readonly A2010: "AvProtocolError";
|
|
15
|
+
readonly A2011: "AvProtocolError";
|
|
16
|
+
readonly A2012: "AvProtocolError";
|
|
17
|
+
readonly A2013: "AvConflictError";
|
|
18
|
+
readonly A2014: "AvConflictError";
|
|
19
|
+
readonly A3000: "AvInternalError";
|
|
20
|
+
readonly A3001: "AvInternalError";
|
|
21
|
+
readonly A3002: "AvInternalError";
|
|
22
|
+
readonly A3003: "AvInternalError";
|
|
23
|
+
readonly A3004: "AvInternalError";
|
|
24
|
+
readonly A4000: "AvAuthError";
|
|
25
|
+
readonly A4001: "AvAuthError";
|
|
26
|
+
readonly A4002: "AvAuthError";
|
|
27
|
+
};
|
|
28
|
+
/** The name of one `AvError` subclass. */
|
|
29
|
+
export type AvErrorClassName = (typeof FRAMEWORK_ERROR_CLASS_OF)[AvOperationErrorCode];
|
|
30
|
+
/** The error codes `AvError` subclass `N` is thrown for. */
|
|
31
|
+
export type AvErrorCodeOf<N extends AvErrorClassName> = {
|
|
32
|
+
readonly [C in AvOperationErrorCode]: (typeof FRAMEWORK_ERROR_CLASS_OF)[C] extends N ? C : never;
|
|
33
|
+
}[AvOperationErrorCode];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const FRAMEWORK_ERROR_CLASS_OF = {
|
|
2
|
+
A2000: "AvProtocolError",
|
|
3
|
+
A2001: "AvProtocolError",
|
|
4
|
+
A2002: "AvProtocolError",
|
|
5
|
+
A2003: "AvNotFoundError",
|
|
6
|
+
A2004: "AvValidationError",
|
|
7
|
+
A2005: "AvContractMismatchError",
|
|
8
|
+
A2006: "AvProtocolError",
|
|
9
|
+
A2007: "AvValidationError",
|
|
10
|
+
A2008: "AvConflictError",
|
|
11
|
+
A2009: "AvValidationError",
|
|
12
|
+
A2010: "AvProtocolError",
|
|
13
|
+
A2011: "AvProtocolError",
|
|
14
|
+
A2012: "AvProtocolError",
|
|
15
|
+
A2013: "AvConflictError",
|
|
16
|
+
A2014: "AvConflictError",
|
|
17
|
+
A3000: "AvInternalError",
|
|
18
|
+
A3001: "AvInternalError",
|
|
19
|
+
A3002: "AvInternalError",
|
|
20
|
+
A3003: "AvInternalError",
|
|
21
|
+
A3004: "AvInternalError",
|
|
22
|
+
A4000: "AvAuthError",
|
|
23
|
+
A4001: "AvAuthError",
|
|
24
|
+
A4002: "AvAuthError",
|
|
25
|
+
};
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AvErrorCodeOf } from "./framework-error-class.table.js";
|
|
2
|
+
import type { AvCause, AvOperationErrorCode } from "./operation-response.js";
|
|
2
3
|
/**
|
|
3
|
-
* Throw from a pipeline,
|
|
4
|
-
* framework error code and cause.
|
|
4
|
+
* Throw from a pipeline, compute stage or Adapter to answer the request with one
|
|
5
|
+
* framework error code and cause. Every in-process call that fails
|
|
6
|
+
* (`framework.application`, `framework.client`, `framework.transaction`, a ctx
|
|
7
|
+
* call) throws one too, as the subclass of its code's class:
|
|
8
|
+
* {@link AvValidationError}, {@link AvNotFoundError}, {@link AvConflictError},
|
|
9
|
+
* {@link AvAuthError}, {@link AvInternalError}, {@link AvProtocolError} or
|
|
10
|
+
* {@link AvContractMismatchError}. Branch on the class or on `code`, never on the
|
|
11
|
+
* message.
|
|
5
12
|
*
|
|
6
13
|
* For any code outside `A3xxx`, `cause.message` is sent to the caller exactly as
|
|
7
14
|
* written: put nothing in it you would not show the caller (no database text,
|
|
8
15
|
* SQL, stack, path or secret). So is each issue's `message`, when your own code
|
|
9
|
-
* (a pipe, guard, hook, interceptor, filter or
|
|
16
|
+
* (a pipe, guard, hook, interceptor, filter or compute stage) throws it and it is not
|
|
10
17
|
* blank and at most 1,000 characters; otherwise, and for an issue an Adapter
|
|
11
18
|
* throws, the caller receives the framework's own text for the issue's code. An
|
|
12
19
|
* issue's `code` must be a validation code (`V1000` and up) and its `path` must
|
|
@@ -15,8 +22,61 @@ import type { Cause, OperationErrorCode } from "./operation-response.js";
|
|
|
15
22
|
* message instead, and nothing of the cause; the error itself reaches the root
|
|
16
23
|
* `diagnostics` sink once, marked `deliberate: true`.
|
|
17
24
|
*/
|
|
18
|
-
export declare class
|
|
19
|
-
readonly
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
export declare class AvError<C extends AvOperationErrorCode = AvOperationErrorCode> extends Error {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
/** The outcome code. Branch on this, never on the message. */
|
|
28
|
+
readonly code: C;
|
|
29
|
+
/** The cause: its message, and its issues or failing step when there are any. */
|
|
30
|
+
readonly cause: AvCause;
|
|
31
|
+
constructor(code: C, cause: AvCause | string);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The request broke a Contract rule: a field, type, capability, projection,
|
|
35
|
+
* reference or limit. The cause's issues say which, by code and path. Thrown for
|
|
36
|
+
* A2004, A2007 and A2009.
|
|
37
|
+
*/
|
|
38
|
+
export declare class AvValidationError extends AvError<AvErrorCodeOf<"AvValidationError">> {
|
|
39
|
+
readonly name: string;
|
|
40
|
+
}
|
|
41
|
+
/** A strict unique target does not exist. Thrown for A2003. */
|
|
42
|
+
export declare class AvNotFoundError extends AvError<AvErrorCodeOf<"AvNotFoundError">> {
|
|
43
|
+
readonly name: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The operation conflicted with stored state, and nothing was written. A2008
|
|
47
|
+
* fails the same way if sent again; A2013 and A2014 may succeed if sent again,
|
|
48
|
+
* and no retry is automatic. Thrown for A2008, A2013 and A2014.
|
|
49
|
+
*/
|
|
50
|
+
export declare class AvConflictError extends AvError<AvErrorCodeOf<"AvConflictError">> {
|
|
51
|
+
readonly name: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The caller is not authenticated, or is not permitted to run the operation.
|
|
55
|
+
* Thrown for A4000, A4001 and A4002.
|
|
56
|
+
*/
|
|
57
|
+
export declare class AvAuthError extends AvError<AvErrorCodeOf<"AvAuthError">> {
|
|
58
|
+
readonly name: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The server failed. Nothing in its cause is actionable; the diagnostics are in
|
|
62
|
+
* the `diagnostics` sink. Thrown for A3000 to A3004.
|
|
63
|
+
*/
|
|
64
|
+
export declare class AvInternalError extends AvError<AvErrorCodeOf<"AvInternalError">> {
|
|
65
|
+
readonly name: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The request was not one the server could route or interpret: an unknown
|
|
69
|
+
* Resource or operation, a protocol version it does not speak, or a body, media
|
|
70
|
+
* type, size or method it refuses. Thrown for A2000, A2001, A2002, A2006, A2010,
|
|
71
|
+
* A2011 and A2012.
|
|
72
|
+
*/
|
|
73
|
+
export declare class AvProtocolError extends AvError<AvErrorCodeOf<"AvProtocolError">> {
|
|
74
|
+
readonly name: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The caller's ClientContract hash is not the one the server serves (a stale
|
|
78
|
+
* generated client). Thrown for A2005.
|
|
79
|
+
*/
|
|
80
|
+
export declare class AvContractMismatchError extends AvError<AvErrorCodeOf<"AvContractMismatchError">> {
|
|
81
|
+
readonly name: string;
|
|
22
82
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type AvError } from "./framework-error.js";
|
|
2
|
+
import type { AvOperationFailureResponse } from "./operation-response.js";
|
|
3
|
+
/** The `AvError` subclass a failure response throws in process, with its code and cause. */
|
|
4
|
+
export declare function thrownFailure(response: AvOperationFailureResponse): AvError;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AvAuthError, AvConflictError, AvContractMismatchError, AvInternalError, AvNotFoundError, AvProtocolError, AvValidationError, } from "./framework-error.js";
|
|
2
|
+
import { FRAMEWORK_ERROR_CLASS_OF, } from "./framework-error-class.table.js";
|
|
3
|
+
const ERROR_CLASSES = {
|
|
4
|
+
AvAuthError,
|
|
5
|
+
AvConflictError,
|
|
6
|
+
AvContractMismatchError,
|
|
7
|
+
AvInternalError,
|
|
8
|
+
AvNotFoundError,
|
|
9
|
+
AvProtocolError,
|
|
10
|
+
AvValidationError,
|
|
11
|
+
};
|
|
12
|
+
export function thrownFailure(response) {
|
|
13
|
+
const ErrorClass = ERROR_CLASSES[FRAMEWORK_ERROR_CLASS_OF[response.code]];
|
|
14
|
+
return new ErrorClass(response.code, response.cause);
|
|
15
|
+
}
|
|
@@ -1,11 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
import { brandCoreClass } from "./core-class.brand.js";
|
|
2
|
+
export class AvError extends Error {
|
|
3
|
+
name = "AvError";
|
|
2
4
|
code;
|
|
3
5
|
cause;
|
|
4
6
|
constructor(code, cause) {
|
|
5
7
|
const normalizedCause = typeof cause === "string" ? { message: cause } : cause;
|
|
6
8
|
super(normalizedCause.message);
|
|
7
|
-
this.name = "FrameworkError";
|
|
8
9
|
this.code = code;
|
|
9
10
|
this.cause = normalizedCause;
|
|
10
11
|
}
|
|
11
12
|
}
|
|
13
|
+
export class AvValidationError extends AvError {
|
|
14
|
+
name = "AvValidationError";
|
|
15
|
+
}
|
|
16
|
+
export class AvNotFoundError extends AvError {
|
|
17
|
+
name = "AvNotFoundError";
|
|
18
|
+
}
|
|
19
|
+
export class AvConflictError extends AvError {
|
|
20
|
+
name = "AvConflictError";
|
|
21
|
+
}
|
|
22
|
+
export class AvAuthError extends AvError {
|
|
23
|
+
name = "AvAuthError";
|
|
24
|
+
}
|
|
25
|
+
export class AvInternalError extends AvError {
|
|
26
|
+
name = "AvInternalError";
|
|
27
|
+
}
|
|
28
|
+
export class AvProtocolError extends AvError {
|
|
29
|
+
name = "AvProtocolError";
|
|
30
|
+
}
|
|
31
|
+
export class AvContractMismatchError extends AvError {
|
|
32
|
+
name = "AvContractMismatchError";
|
|
33
|
+
}
|
|
34
|
+
brandCoreClass(AvError, "AvError");
|
|
35
|
+
brandCoreClass(AvValidationError, "AvValidationError");
|
|
36
|
+
brandCoreClass(AvNotFoundError, "AvNotFoundError");
|
|
37
|
+
brandCoreClass(AvConflictError, "AvConflictError");
|
|
38
|
+
brandCoreClass(AvAuthError, "AvAuthError");
|
|
39
|
+
brandCoreClass(AvInternalError, "AvInternalError");
|
|
40
|
+
brandCoreClass(AvProtocolError, "AvProtocolError");
|
|
41
|
+
brandCoreClass(AvContractMismatchError, "AvContractMismatchError");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emits a framework warning: through `process.emitWarning` (type
|
|
3
|
+
* `AventaraWarning`, `code` as given) where the runtime has it, else through
|
|
4
|
+
* `console.warn`. A warning changes no behaviour.
|
|
5
|
+
*/
|
|
6
|
+
export declare function emitFrameworkWarning(message: string, code: string): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function emitFrameworkWarning(message, code) {
|
|
2
|
+
const emitWarning = globalThis.process?.emitWarning;
|
|
3
|
+
if (typeof emitWarning === "function") {
|
|
4
|
+
emitWarning(message, { type: "AventaraWarning", code });
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
globalThis.console?.warn(`AventaraWarning: ${message}`);
|
|
8
|
+
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A JSON value: the form of the `json` scalar, in arguments and results.
|
|
3
3
|
*
|
|
4
|
-
* A `Date`, a `bigint`, a `Uint8Array`, a {@link
|
|
5
|
-
* instance
|
|
6
|
-
*
|
|
4
|
+
* A `Date`, a `bigint`, a `Uint8Array`, a {@link AvDecimal} and any other class
|
|
5
|
+
* instance are refused (`V1001`), as are a non-finite `number` (`V1004`) and a
|
|
6
|
+
* cycle (`V1001`). An `undefined` inside the value is what JSON makes of it: a key
|
|
7
|
+
* holding it is left out, an array element holding it (or a hole) is `null`. The
|
|
8
|
+
* type admits a key holding `undefined`, so an object with an optional property is
|
|
9
|
+
* a JSON value; an array element stays typed without it, as JSON has no such
|
|
10
|
+
* value.
|
|
7
11
|
*
|
|
8
|
-
* Results are fresh plain copies, so mutating one is safe
|
|
12
|
+
* Results are fresh plain copies, so mutating one is safe; a result never holds a
|
|
13
|
+
* key whose value is `undefined`.
|
|
9
14
|
*
|
|
10
15
|
* A `json` field's value is this without its top-level `null`: a field-level
|
|
11
16
|
* `null` is the field's absence, which only `nullable: true` admits.
|
|
12
17
|
*/
|
|
13
|
-
export type
|
|
14
|
-
readonly [key: string]:
|
|
18
|
+
export type AvJsonValue = string | number | boolean | null | readonly AvJsonValue[] | {
|
|
19
|
+
readonly [key: string]: AvJsonValue | undefined;
|
|
15
20
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** One level's lifecycle registrations, as an operation or a transaction level holds them. */
|
|
2
|
+
type LifecycleLevel<Context> = {
|
|
3
|
+
readonly hooks: {
|
|
4
|
+
readonly before: readonly ((context: Context) => unknown)[];
|
|
5
|
+
readonly after: readonly ((result: unknown, context: Context) => unknown)[];
|
|
6
|
+
};
|
|
7
|
+
readonly interceptors: readonly ((context: Context, next: () => Promise<unknown>) => Promise<unknown>)[];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The record of a `next()` called more than once: the first refusal, kept so a
|
|
11
|
+
* caller can refuse the whole call even when the interceptor swallowed it.
|
|
12
|
+
*/
|
|
13
|
+
export type NextReuse<Refusal extends Error = Error> = {
|
|
14
|
+
refusal: Refusal | undefined;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Runs `levels`' lifecycle around `inner`: every interceptor, outer to inner,
|
|
18
|
+
* around every before hook, `inner`, and every after hook. `settle` turns what
|
|
19
|
+
* `inner` or an interceptor below resolved into what the stage above sees (the
|
|
20
|
+
* operation read-materializes it). Each after hook is told its own deep-frozen
|
|
21
|
+
* copy of the result; the result itself goes on to the interceptors, which may answer a
|
|
22
|
+
* different one. Every `next()` is single use: a second call rejects with
|
|
23
|
+
* `refuse()`'s error, recorded in `reuse`, and runs nothing.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runLevelLifecycle<Context, Refusal extends Error>(levels: readonly LifecycleLevel<Context>[], context: () => Context, inner: () => Promise<unknown>, settle: (result: unknown) => Promise<unknown>, reuse: NextReuse<Refusal>, refuse: () => Refusal): Promise<unknown>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { frozenCopy } from "./readonly-value.js";
|
|
2
|
+
export async function runLevelLifecycle(levels, context, inner, settle, reuse, refuse) {
|
|
3
|
+
const once = (run) => {
|
|
4
|
+
let called = false;
|
|
5
|
+
return () => {
|
|
6
|
+
if (called) {
|
|
7
|
+
const refusal = refuse();
|
|
8
|
+
reuse.refusal ??= refusal;
|
|
9
|
+
return Promise.reject(refusal);
|
|
10
|
+
}
|
|
11
|
+
called = true;
|
|
12
|
+
return run();
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
const hooked = async () => {
|
|
16
|
+
for (const level of levels) {
|
|
17
|
+
for (const hook of level.hooks.before) {
|
|
18
|
+
await hook(context());
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const result = await settle(await inner());
|
|
22
|
+
const after = [...levels].reverse().flatMap((level) => level.hooks.after);
|
|
23
|
+
const settled = after.length > 0 ? frozenCopy(result, true) : undefined;
|
|
24
|
+
for (const [index, hook] of after.entries()) {
|
|
25
|
+
await hook(index === after.length - 1 ? settled : frozenCopy(settled), context());
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
const interceptors = levels.flatMap((level) => level.interceptors);
|
|
30
|
+
let next = hooked;
|
|
31
|
+
for (let index = interceptors.length - 1; index >= 0; index -= 1) {
|
|
32
|
+
const interceptor = interceptors[index];
|
|
33
|
+
if (interceptor === undefined) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const continuation = once(next);
|
|
37
|
+
next = () => interceptor(context(), async () => settle(await continuation()));
|
|
38
|
+
}
|
|
39
|
+
return next();
|
|
40
|
+
}
|