@aventara/core 1.0.0-rc.0 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1140 -0
- package/README.md +224 -57
- package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
- package/dist/adapters/adapter-field.d.ts +11 -11
- package/dist/adapters/adapter-identifier.d.ts +6 -6
- package/dist/adapters/adapter-model.d.ts +9 -9
- package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
- package/dist/adapters/adapter-operation.d.ts +3 -3
- package/dist/adapters/adapter-resource.d.ts +18 -9
- package/dist/adapters/adapter-sql-statement.d.ts +19 -0
- package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
- package/dist/adapters/adapter.interface.d.ts +49 -29
- package/dist/avz/avz-check.factory.d.ts +83 -0
- package/dist/avz/avz-check.factory.js +116 -0
- package/dist/avz/avz-check.registry.d.ts +35 -0
- package/dist/avz/avz-check.registry.js +9 -0
- package/dist/avz/avz.d.ts +203 -0
- package/dist/{json → avz}/avz.js +150 -8
- package/dist/{json → avz}/index.d.ts +2 -1
- package/dist/{json → avz}/json-shape.registry.d.ts +7 -7
- package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
- package/dist/{json → avz}/zod-issue.translator.js +7 -0
- package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
- package/dist/compiler/contract.compiler.d.ts +18 -18
- package/dist/compiler/contract.compiler.js +548 -441
- package/dist/compiler/create-requirements.projector.d.ts +49 -0
- package/dist/compiler/create-requirements.projector.js +423 -0
- package/dist/compiler/field-validator.compiler.d.ts +47 -0
- package/dist/compiler/field-validator.compiler.js +238 -0
- package/dist/config/any-framework-config.d.ts +19 -12
- package/dist/config/config-diagnostic.d.ts +11 -4
- package/dist/config/config-layer.d.ts +15 -6
- package/dist/config/config.resolver.d.ts +74 -31
- package/dist/config/config.resolver.js +108 -44
- package/dist/config/config.validator.d.ts +7 -7
- package/dist/config/config.validator.js +581 -72
- package/dist/config/define-resource.d.ts +57 -0
- package/dist/config/define-resource.js +14 -0
- package/dist/config/effective-fields.d.ts +19 -23
- package/dist/config/entrypoint.normalizer.d.ts +1 -1
- package/dist/config/exact-framework-config.d.ts +280 -0
- package/dist/config/field-compute.resolver.d.ts +19 -0
- package/dist/config/field-compute.resolver.js +115 -0
- package/dist/config/field-pipeline-config.d.ts +47 -0
- package/dist/config/forced-operation.validator.d.ts +10 -0
- package/dist/config/forced-operation.validator.js +66 -0
- package/dist/config/framework-config.d.ts +110 -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 +116 -0
- package/dist/config/framework-resources-config.js +1 -0
- package/dist/config/pipeline-config.d.ts +56 -20
- package/dist/config/pipeline-tree.resolver.d.ts +79 -0
- package/dist/config/pipeline-tree.resolver.js +220 -0
- package/dist/config/stage-type.eraser.d.ts +65 -0
- package/dist/config/stage-type.eraser.js +1 -0
- package/dist/contracts/capability.d.ts +11 -11
- package/dist/contracts/client-contract-structure.validator.d.ts +323 -28
- package/dist/contracts/client-contract-structure.validator.js +152 -8
- package/dist/contracts/contract-canonicalizer.d.ts +19 -3
- package/dist/contracts/contract-canonicalizer.js +141 -28
- package/dist/contracts/contract-hash.d.ts +12 -7
- package/dist/contracts/contract-hash.js +3 -2
- package/dist/contracts/contract-limits.d.ts +4 -1
- package/dist/contracts/contract-limits.js +1 -0
- package/dist/contracts/contract-lookup.d.ts +5 -5
- package/dist/contracts/contract-protocol.d.ts +4 -4
- package/dist/contracts/contract.d.ts +24 -16
- package/dist/contracts/create-requirements.d.ts +35 -0
- package/dist/contracts/create-requirements.js +1 -0
- package/dist/contracts/enum-definition.d.ts +1 -1
- package/dist/contracts/field-check.d.ts +101 -0
- package/dist/contracts/field-check.js +1 -0
- package/dist/contracts/field.d.ts +52 -42
- package/dist/contracts/identifier.d.ts +4 -4
- package/dist/contracts/json-shape.d.ts +12 -1
- package/dist/contracts/lifecycle-trait.d.ts +2 -2
- package/dist/contracts/resource-operations.d.ts +28 -28
- package/dist/contracts/resource.d.ts +15 -9
- package/dist/contracts/scalar-value-type.d.ts +15 -15
- package/dist/contracts/scalar.d.ts +3 -3
- package/dist/contracts/transaction-capability.d.ts +1 -1
- package/dist/contracts/wire-scalar-format.d.ts +4 -4
- package/dist/framework/contract-view.d.ts +213 -147
- package/dist/framework/framework-construction.error.d.ts +10 -10
- package/dist/framework/framework-construction.error.js +2 -2
- package/dist/framework/framework.d.ts +47 -23
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +40 -20
- package/dist/framework/operation-facade.d.ts +123 -52
- package/dist/framework/operation-facade.js +9 -1
- package/dist/index.d.ts +55 -50
- package/dist/index.js +6 -6
- package/dist/internal.d.ts +15 -10
- package/dist/internal.js +3 -1
- package/dist/operations/operation-arguments.d.ts +267 -202
- package/dist/operations/operation-call.d.ts +27 -28
- package/dist/operations/operation-identity.d.ts +10 -10
- package/dist/operations/operation-result.d.ts +21 -21
- package/dist/operations/operation-validator-core.d.ts +6 -6
- package/dist/operations/operation-validator-core.js +13 -2
- package/dist/operations/operation-validator.d.ts +9 -9
- package/dist/operations/projection-scope.resolver.d.ts +6 -6
- package/dist/operations/structural-limits.walker.d.ts +6 -6
- package/dist/operations/structural-limits.walker.js +145 -0
- package/dist/operations/validation-code.d.ts +11 -6
- package/dist/operations/validation-code.js +4 -0
- package/dist/operations/write-scope.resolver.d.ts +6 -6
- package/dist/protocol/absent-route.responder.d.ts +13 -12
- package/dist/protocol/absent-route.responder.js +19 -19
- package/dist/protocol/contract-document.responder.d.ts +3 -3
- package/dist/protocol/contract-document.responder.js +2 -2
- package/dist/protocol/http-request.decoder.d.ts +17 -13
- package/dist/protocol/http-request.decoder.js +10 -10
- package/dist/protocol/http-request.reader.d.ts +3 -3
- package/dist/protocol/http-response.encoder.d.ts +4 -4
- package/dist/protocol/http-response.encoder.js +94 -55
- package/dist/protocol/http-status.table.d.ts +2 -2
- package/dist/protocol/operation-response.guard.d.ts +2 -2
- package/dist/protocol/protocol-surface.d.ts +4 -4
- package/dist/protocol/protocol.binder.d.ts +50 -27
- package/dist/protocol/protocol.binder.js +12 -9
- package/dist/protocol/protocol.handler.d.ts +22 -13
- package/dist/protocol/protocol.handler.js +44 -9
- 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 +5 -5
- package/dist/runtime/caller-data.copier.js +13 -13
- package/dist/runtime/caller-data.door.d.ts +6 -6
- package/dist/runtime/caller-data.door.js +6 -4
- package/dist/runtime/computed-read-runtime.d.ts +7 -6
- package/dist/runtime/computed-read-runtime.js +61 -48
- package/dist/runtime/computed-value.error.d.ts +6 -6
- package/dist/runtime/computed-value.error.js +3 -3
- package/dist/runtime/context-executor.runtime.d.ts +59 -0
- package/dist/runtime/context-executor.runtime.js +275 -0
- package/dist/runtime/create-requirement.d.ts +10 -81
- package/dist/runtime/create-requirement.js +80 -57
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +1 -1
- package/dist/runtime/diagnostics-reporter.d.ts +53 -27
- package/dist/runtime/diagnostics-reporter.js +24 -0
- package/dist/runtime/error-boundary.d.ts +65 -8
- package/dist/runtime/error-boundary.js +45 -19
- package/dist/runtime/execution-options.d.ts +10 -2
- package/dist/runtime/field-check.evaluator.d.ts +29 -0
- package/dist/runtime/field-check.evaluator.js +521 -0
- package/dist/runtime/field-compute.d.ts +64 -0
- package/dist/runtime/field-compute.js +1 -0
- package/dist/runtime/field-stage.plan.d.ts +15 -0
- package/dist/runtime/field-stage.plan.js +27 -0
- package/dist/runtime/field-stage.runtime.d.ts +35 -0
- package/dist/runtime/field-stage.runtime.js +143 -0
- package/dist/runtime/field-validator.runtime.d.ts +11 -0
- package/dist/runtime/field-validator.runtime.js +87 -0
- package/dist/runtime/framework-error-class.table.d.ts +33 -0
- package/dist/runtime/framework-error-class.table.js +25 -0
- package/dist/runtime/framework-error.d.ts +68 -8
- package/dist/runtime/framework-error.factory.d.ts +4 -0
- package/dist/runtime/framework-error.factory.js +15 -0
- package/dist/runtime/framework-error.js +23 -2
- package/dist/runtime/interceptor-next.error.d.ts +5 -0
- package/dist/runtime/interceptor-next.error.js +6 -0
- package/dist/runtime/json-value.d.ts +3 -3
- package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
- package/dist/runtime/level-lifecycle.runtime.js +42 -0
- package/dist/runtime/misuse-reporter.d.ts +12 -12
- package/dist/runtime/mutation-planner.d.ts +19 -10
- package/dist/runtime/mutation-planner.js +54 -30
- package/dist/runtime/nested-write.walker.d.ts +32 -0
- package/dist/runtime/nested-write.walker.js +73 -0
- package/dist/runtime/operation-request.d.ts +33 -6
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +113 -25
- package/dist/runtime/operation-runtime.js +395 -74
- package/dist/runtime/outcome-mapper.d.ts +16 -5
- package/dist/runtime/outcome-mapper.js +23 -6
- package/dist/runtime/output-validator.d.ts +10 -10
- package/dist/runtime/output-validator.js +3 -3
- package/dist/runtime/owned-execution.registry.d.ts +6 -6
- package/dist/runtime/pipe-output.validator.d.ts +33 -18
- package/dist/runtime/pipe-output.validator.js +12 -12
- package/dist/runtime/pipeline.d.ts +196 -34
- package/dist/runtime/readonly-value.d.ts +32 -0
- package/dist/runtime/readonly-value.js +141 -0
- package/dist/runtime/request-envelope.validator.d.ts +3 -3
- package/dist/runtime/request-envelope.validator.js +12 -7
- package/dist/runtime/request-id.d.ts +1 -1
- package/dist/runtime/request-state.d.ts +14 -0
- package/dist/runtime/request-state.js +1 -0
- package/dist/runtime/request-state.resolver.d.ts +12 -0
- package/dist/runtime/request-state.resolver.js +20 -0
- package/dist/runtime/scalar-runtime.d.ts +31 -16
- package/dist/runtime/scalar-runtime.js +16 -18
- package/dist/transactions/deferred-operation.d.ts +35 -20
- package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
- package/dist/transactions/operation-arguments-encoder.js +2 -2
- package/dist/transactions/sql-statement.d.ts +77 -0
- package/dist/transactions/sql-statement.js +47 -0
- package/dist/transactions/sql-statement.validator.d.ts +44 -0
- package/dist/transactions/sql-statement.validator.js +134 -0
- package/dist/transactions/transaction-envelope.d.ts +4 -4
- package/dist/transactions/transaction-integrity-error.d.ts +6 -6
- package/dist/transactions/transaction-integrity-error.js +5 -2
- package/dist/transactions/transaction-plan-assembler.d.ts +21 -11
- package/dist/transactions/transaction-plan-assembler.js +148 -34
- package/dist/transactions/transaction-plan-validator.d.ts +29 -20
- package/dist/transactions/transaction-plan-validator.js +70 -38
- package/dist/transactions/transaction-reference-collector.d.ts +5 -5
- package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
- package/dist/transactions/transaction-reference-resolver.js +26 -14
- package/dist/transactions/transaction-reference-validator.d.ts +34 -4
- package/dist/transactions/transaction-reference-validator.js +58 -26
- package/dist/transactions/transaction-reference.d.ts +13 -13
- package/dist/transactions/transaction-request.d.ts +18 -5
- package/dist/transactions/transaction-response.d.ts +6 -6
- package/dist/transactions/transaction-runtime.d.ts +8 -7
- package/dist/transactions/transaction-runtime.js +166 -50
- package/dist/transactions/transaction-settlement.runtime.d.ts +51 -0
- package/dist/transactions/transaction-settlement.runtime.js +120 -0
- package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
- package/dist/transactions/transaction-slot-path-error.js +2 -2
- package/dist/transactions/transaction-slot-writer.js +2 -2
- package/dist/transactions/transaction-stage.runtime.d.ts +81 -0
- package/dist/transactions/transaction-stage.runtime.js +123 -0
- package/package.json +6 -5
- 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,64 @@
|
|
|
1
|
+
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
|
+
import type { AvAdapterFieldKey } from "../adapters/adapter-resource.js";
|
|
3
|
+
import type { AvConfigAny } from "../config/any-framework-config.js";
|
|
4
|
+
import type { AvEffectiveFieldKey } from "../config/effective-fields.js";
|
|
5
|
+
import type { AvConfigResourceKey } from "../config/framework-field-definition.js";
|
|
6
|
+
import type { AvComputeReads } from "../framework/operation-facade.js";
|
|
7
|
+
import type { AvContext } from "./pipeline.js";
|
|
8
|
+
import type { AvDeepReadonly } from "./readonly-value.js";
|
|
9
|
+
import type { AvState } from "./request-state.js";
|
|
10
|
+
/**
|
|
11
|
+
* The ctx a compute stage is told: the operation's `$` facts, a read-only view
|
|
12
|
+
* of the request's `$state`, and reads only (`ctx.<Resource>.find.<variant>(args)`,
|
|
13
|
+
* `find.count` included).
|
|
14
|
+
*/
|
|
15
|
+
export type AvComputeContext<M extends AvAdapterModel = AvAdapterModel> = AvComputeReads<M> & Pick<AvContext<M>, "$operation" | "$args" | "$origin" | "$requestId" | "$transport" | "$contract"> & {
|
|
16
|
+
/** The request's state, read-only: a write throws a `TypeError`. */
|
|
17
|
+
readonly $state: AvDeepReadonly<AvState>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* What a write-stage compute callback is told about the field it is computing.
|
|
21
|
+
*/
|
|
22
|
+
type ComputedWriteContext<M extends AvAdapterModel> = {
|
|
23
|
+
readonly field: string;
|
|
24
|
+
readonly value: unknown;
|
|
25
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
26
|
+
readonly ctx: AvComputeContext<M>;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Computes a field's value when a row is created, whether or not the caller sent
|
|
30
|
+
* it. It receives the incoming `data` and returns the value to store; returning
|
|
31
|
+
* `undefined` keeps the current value.
|
|
32
|
+
*/
|
|
33
|
+
export type AvComputeCreate<M extends AvAdapterModel = AvAdapterModel> = (context: ComputedWriteContext<M>) => unknown | Promise<unknown>;
|
|
34
|
+
/**
|
|
35
|
+
* Computes a field's value when a row is updated, whether or not the caller sent
|
|
36
|
+
* it. It receives the incoming `data` and returns the value to store; returning
|
|
37
|
+
* `undefined` keeps the current value.
|
|
38
|
+
*/
|
|
39
|
+
export type AvComputeUpdate<M extends AvAdapterModel = AvAdapterModel> = (context: ComputedWriteContext<M>) => unknown | Promise<unknown>;
|
|
40
|
+
/**
|
|
41
|
+
* Computes a field's value when a row is read. It receives the stored `record`
|
|
42
|
+
* and returns the value to return; returning `undefined` keeps the current value.
|
|
43
|
+
*/
|
|
44
|
+
export type ComputeReadFunction<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny, R extends AvConfigResourceKey<M> = AvConfigResourceKey<M>> = (context: {
|
|
45
|
+
readonly field: AvEffectiveFieldKey<M, Cfg, R>;
|
|
46
|
+
readonly value: unknown;
|
|
47
|
+
readonly record: Readonly<Record<AvEffectiveFieldKey<M, Cfg, R>, unknown>>;
|
|
48
|
+
readonly ctx: AvComputeContext<M>;
|
|
49
|
+
}) => unknown | Promise<unknown>;
|
|
50
|
+
/** The fields of Resource `R` the adapter stores as scalars: what `dependsOn` may name. */
|
|
51
|
+
type StoredScalarKey<M extends AvAdapterModel, R extends AvConfigResourceKey<M>> = string extends AvAdapterFieldKey<M, R> ? string : {
|
|
52
|
+
[F in AvAdapterFieldKey<M, R>]: M["resources"][R]["fields"][F] extends {
|
|
53
|
+
readonly kind: "scalar";
|
|
54
|
+
} ? F : never;
|
|
55
|
+
}[AvAdapterFieldKey<M, R>];
|
|
56
|
+
/**
|
|
57
|
+
* A read compute stage: a compute function, or `{ compute, dependsOn }` naming
|
|
58
|
+
* the fields it reads.
|
|
59
|
+
*/
|
|
60
|
+
export type AvComputeRead<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny, R extends AvConfigResourceKey<M> = AvConfigResourceKey<M>> = ComputeReadFunction<M, Cfg, R> | {
|
|
61
|
+
readonly dependsOn?: readonly StoredScalarKey<M, R>[];
|
|
62
|
+
readonly compute: ComputeReadFunction<M, Cfg, R>;
|
|
63
|
+
};
|
|
64
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ResolvedPipelineTree } from "../config/pipeline-tree.resolver.js";
|
|
2
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
3
|
+
/** One origin's field-stage dispatch, planned at startup. */
|
|
4
|
+
export type FieldStagePlan = {
|
|
5
|
+
/** Whether any Resource registers a field pipe. */
|
|
6
|
+
readonly anyPipes: boolean;
|
|
7
|
+
/** Whether any Resource registers a guard a nested target runs: its own, its family's or a field write guard. */
|
|
8
|
+
readonly nestedGuards: boolean;
|
|
9
|
+
/** `resource`'s fields with write guards, in the Resource's field order. */
|
|
10
|
+
readonly guarded: (resource: string) => readonly string[];
|
|
11
|
+
/** `resource`'s fields with field pipes, in the Resource's field order. */
|
|
12
|
+
readonly piped: (resource: string) => readonly string[];
|
|
13
|
+
};
|
|
14
|
+
/** Plans the field-stage dispatch of `tree` under `contract`. */
|
|
15
|
+
export declare function planFieldStages(tree: ResolvedPipelineTree, contract: AvContract): FieldStagePlan;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { stagedFieldsOf } from "./field-stage.runtime.js";
|
|
2
|
+
const NONE = Object.freeze([]);
|
|
3
|
+
export function planFieldStages(tree, contract) {
|
|
4
|
+
const guarded = new Map();
|
|
5
|
+
const piped = new Map();
|
|
6
|
+
let nestedGuards = false;
|
|
7
|
+
for (const [resource, pipelines] of Object.entries(tree.resources)) {
|
|
8
|
+
const guards = stagedFieldsOf(contract, resource, pipelines.fields, "guards");
|
|
9
|
+
const pipes = stagedFieldsOf(contract, resource, pipelines.fields, "pipes");
|
|
10
|
+
if (guards.length > 0) {
|
|
11
|
+
guarded.set(resource, Object.freeze([...guards]));
|
|
12
|
+
}
|
|
13
|
+
if (pipes.length > 0) {
|
|
14
|
+
piped.set(resource, Object.freeze([...pipes]));
|
|
15
|
+
}
|
|
16
|
+
nestedGuards ||=
|
|
17
|
+
guards.length > 0 ||
|
|
18
|
+
pipelines.pipelines.some((level) => level.guards.length > 0) ||
|
|
19
|
+
Object.values(pipelines.families).some((family) => family.pipelines.some((level) => level.guards.length > 0));
|
|
20
|
+
}
|
|
21
|
+
return Object.freeze({
|
|
22
|
+
anyPipes: piped.size > 0,
|
|
23
|
+
nestedGuards,
|
|
24
|
+
guarded: (resource) => guarded.get(resource) ?? NONE,
|
|
25
|
+
piped: (resource) => piped.get(resource) ?? NONE,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ResolvedFieldStages } from "../config/pipeline-tree.resolver.js";
|
|
2
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
3
|
+
import type { AvOperationFamily } from "../operations/operation-identity.js";
|
|
4
|
+
import type { AvContext } from "./pipeline.js";
|
|
5
|
+
export type Path = readonly (string | number)[];
|
|
6
|
+
type UnknownRecord = Readonly<Record<string, unknown>>;
|
|
7
|
+
/** A plain object: what a write record, or a directive's operand, is. */
|
|
8
|
+
export declare function isPlainRecord(value: unknown): value is UnknownRecord;
|
|
9
|
+
/** The fields of `resource` with stages, in the Resource's field order. */
|
|
10
|
+
export declare function stagedFieldsOf(contract: AvContract, resource: string, stages: Readonly<Record<string, ResolvedFieldStages>>, kind: "pipes" | "guards"): readonly string[];
|
|
11
|
+
/** The value at `path` in `args`, or `undefined` when nothing is there. */
|
|
12
|
+
export declare function valueAt(args: unknown, path: Path): unknown;
|
|
13
|
+
/** `args` with the record at `path` replaced, every container on the way copied. */
|
|
14
|
+
export declare function replaceAt(args: unknown, path: Path, record: UnknownRecord): unknown;
|
|
15
|
+
export type PipedFields = {
|
|
16
|
+
readonly args: unknown;
|
|
17
|
+
/** Whether a field pipe returned a value: the arguments must be held to the server's rules again. */
|
|
18
|
+
readonly changed: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** The paths of the top-level data records of a create, update or upsert. */
|
|
21
|
+
export declare function writeRecordPathsOf(family: AvOperationFamily, args: unknown): readonly Path[];
|
|
22
|
+
/**
|
|
23
|
+
* Runs the field pipes of every sent field `select` admits, in the records at
|
|
24
|
+
* `records`, field by field in the Resource's order, root's pipes then
|
|
25
|
+
* overlay's. A pipe returning `undefined` keeps the value. The arguments are
|
|
26
|
+
* copied where a value changes, never written.
|
|
27
|
+
*/
|
|
28
|
+
export declare function pipeSentFields(stages: Readonly<Record<string, ResolvedFieldStages>>, fields: readonly string[], records: readonly Path[], args: unknown, select: (path: Path) => boolean): Promise<PipedFields>;
|
|
29
|
+
/**
|
|
30
|
+
* Runs the write guards of every sent field in the records at `records`, field
|
|
31
|
+
* by field in the Resource's order and, for several records, record by record;
|
|
32
|
+
* `false` as soon as one refuses.
|
|
33
|
+
*/
|
|
34
|
+
export declare function guardSentFields(stages: Readonly<Record<string, ResolvedFieldStages>>, fields: readonly string[], records: readonly Path[], args: unknown, context: () => AvContext): Promise<boolean>;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export function isPlainRecord(value) {
|
|
2
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
const prototype = Object.getPrototypeOf(value);
|
|
6
|
+
return prototype === Object.prototype || prototype === null;
|
|
7
|
+
}
|
|
8
|
+
const WRITE_KEYS = {
|
|
9
|
+
create: ["data"],
|
|
10
|
+
update: ["data"],
|
|
11
|
+
upsert: ["create", "update"],
|
|
12
|
+
};
|
|
13
|
+
function writeRecordsOf(family, args) {
|
|
14
|
+
const keys = WRITE_KEYS[family];
|
|
15
|
+
if (keys === undefined || !isPlainRecord(args)) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
const records = [];
|
|
19
|
+
for (const key of keys) {
|
|
20
|
+
if (!Object.hasOwn(args, key)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const value = args[key];
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
for (const [index, entry] of value.entries()) {
|
|
26
|
+
if (isPlainRecord(entry)) {
|
|
27
|
+
records.push({ path: [key, index], record: entry });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else if (isPlainRecord(value)) {
|
|
32
|
+
records.push({ path: [key], record: value });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return records;
|
|
36
|
+
}
|
|
37
|
+
function sends(record, field) {
|
|
38
|
+
return Object.hasOwn(record, field) && record[field] !== undefined;
|
|
39
|
+
}
|
|
40
|
+
function isDirective(value) {
|
|
41
|
+
return (isPlainRecord(value) &&
|
|
42
|
+
Object.keys(value).some((key) => key.startsWith("$")));
|
|
43
|
+
}
|
|
44
|
+
export function stagedFieldsOf(contract, resource, stages, kind) {
|
|
45
|
+
const fields = Object.hasOwn(contract.resources, resource)
|
|
46
|
+
? contract.resources[resource]?.fields
|
|
47
|
+
: undefined;
|
|
48
|
+
if (fields === undefined) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
return Object.keys(fields).filter((field) => Object.hasOwn(stages, field) && (stages[field]?.[kind].length ?? 0) > 0);
|
|
52
|
+
}
|
|
53
|
+
export function valueAt(args, path) {
|
|
54
|
+
let current = args;
|
|
55
|
+
for (const key of path) {
|
|
56
|
+
if (Array.isArray(current) && typeof key === "number") {
|
|
57
|
+
current = current[key];
|
|
58
|
+
}
|
|
59
|
+
else if (isPlainRecord(current) && Object.hasOwn(current, key)) {
|
|
60
|
+
current = current[key];
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return current;
|
|
67
|
+
}
|
|
68
|
+
export function replaceAt(args, path, record) {
|
|
69
|
+
const [head, ...rest] = path;
|
|
70
|
+
if (head === undefined) {
|
|
71
|
+
return record;
|
|
72
|
+
}
|
|
73
|
+
if (Array.isArray(args)) {
|
|
74
|
+
const copy = [...args];
|
|
75
|
+
copy[head] = replaceAt(copy[head], rest, record);
|
|
76
|
+
return copy;
|
|
77
|
+
}
|
|
78
|
+
const container = args;
|
|
79
|
+
return {
|
|
80
|
+
...container,
|
|
81
|
+
[head]: replaceAt(container[head], rest, record),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function writeRecordPathsOf(family, args) {
|
|
85
|
+
return writeRecordsOf(family, args).map((entry) => entry.path);
|
|
86
|
+
}
|
|
87
|
+
export async function pipeSentFields(stages, fields, records, args, select) {
|
|
88
|
+
if (fields.length === 0) {
|
|
89
|
+
return { args, changed: false };
|
|
90
|
+
}
|
|
91
|
+
let current = args;
|
|
92
|
+
let changed = false;
|
|
93
|
+
for (const path of records) {
|
|
94
|
+
const record = valueAt(current, path);
|
|
95
|
+
if (!isPlainRecord(record)) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
let piped;
|
|
99
|
+
for (const field of fields) {
|
|
100
|
+
if (!sends(record, field) ||
|
|
101
|
+
isDirective(record[field]) ||
|
|
102
|
+
!select([...path, field])) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
let value = record[field];
|
|
106
|
+
for (const pipe of stages[field]?.pipes ?? []) {
|
|
107
|
+
const next = await pipe(value);
|
|
108
|
+
if (next !== undefined) {
|
|
109
|
+
value = next;
|
|
110
|
+
changed = true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (value !== record[field]) {
|
|
114
|
+
piped ??= { ...record };
|
|
115
|
+
piped[field] = value;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (piped !== undefined) {
|
|
119
|
+
current = replaceAt(current, path, piped);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { args: current, changed };
|
|
123
|
+
}
|
|
124
|
+
export async function guardSentFields(stages, fields, records, args, context) {
|
|
125
|
+
if (fields.length === 0) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
const sent = records.map((path) => valueAt(args, path)).filter(isPlainRecord);
|
|
129
|
+
for (const field of fields) {
|
|
130
|
+
for (const record of sent) {
|
|
131
|
+
if (!sends(record, field)) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
for (const guard of stages[field]?.guards ?? []) {
|
|
135
|
+
const told = context();
|
|
136
|
+
if ((await guard(record[field], told)) === false) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
3
|
+
import { type Path } from "./field-stage.runtime.js";
|
|
4
|
+
import type { OperationExecutionRequest } from "./operation-request.js";
|
|
5
|
+
import type { ReferentialActionTable } from "./referential-action.js";
|
|
6
|
+
/**
|
|
7
|
+
* Every way the sent fields `select` admits break their validators: the
|
|
8
|
+
* operation's own records, then each nested write target's. Paths are the
|
|
9
|
+
* request's: `argumentsPath` and then the value's place in the arguments.
|
|
10
|
+
*/
|
|
11
|
+
export declare function fieldValidatorIssues(contract: AvContract, references: ReferentialActionTable, request: OperationExecutionRequest, args: unknown, argumentsPath: Path, select: (path: Path) => boolean): readonly AvValidationIssue[];
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { validatedFieldsOf, } from "../compiler/field-validator.compiler.js";
|
|
2
|
+
import { entryCheckIssues, fieldCheckIssues } from "./field-check.evaluator.js";
|
|
3
|
+
import { isPlainRecord, valueAt, writeRecordPathsOf, } from "./field-stage.runtime.js";
|
|
4
|
+
import { nestedWriteTargetsOf } from "./nested-write.walker.js";
|
|
5
|
+
import { jsonShapeIssues } from "./scalar-runtime.js";
|
|
6
|
+
function isDirective(value) {
|
|
7
|
+
return (isPlainRecord(value) &&
|
|
8
|
+
Object.keys(value).some((key) => key.startsWith("$")));
|
|
9
|
+
}
|
|
10
|
+
function rulesOf(contract, compiled, resource, name) {
|
|
11
|
+
const fields = Object.hasOwn(contract.resources, resource)
|
|
12
|
+
? contract.resources[resource]?.fields
|
|
13
|
+
: undefined;
|
|
14
|
+
const field = fields !== undefined && Object.hasOwn(fields, name)
|
|
15
|
+
? fields[name]
|
|
16
|
+
: undefined;
|
|
17
|
+
if (field?.kind === "scalar" && field.json !== undefined) {
|
|
18
|
+
return { kind: "shape", field };
|
|
19
|
+
}
|
|
20
|
+
const checks = Object.hasOwn(compiled, name) ? compiled[name] : undefined;
|
|
21
|
+
return checks === undefined
|
|
22
|
+
? undefined
|
|
23
|
+
: { kind: "checks", compiled: checks };
|
|
24
|
+
}
|
|
25
|
+
function valueIssues(rules, value, at) {
|
|
26
|
+
if (rules.kind === "shape") {
|
|
27
|
+
return jsonShapeIssues(rules.field, value, at);
|
|
28
|
+
}
|
|
29
|
+
const { compiled } = rules;
|
|
30
|
+
return fieldCheckIssues(compiled.checks, value, compiled.subject ?? "string", at, compiled.list);
|
|
31
|
+
}
|
|
32
|
+
function entryIssues(rules, entry, at) {
|
|
33
|
+
if (rules.kind === "shape") {
|
|
34
|
+
return jsonShapeIssues(rules.field, entry, at, "entry");
|
|
35
|
+
}
|
|
36
|
+
const { compiled } = rules;
|
|
37
|
+
return entryCheckIssues(compiled.checks, entry, compiled.subject ?? "string", at);
|
|
38
|
+
}
|
|
39
|
+
function recordIssues(contract, resource, records, args, argumentsPath, select) {
|
|
40
|
+
const compiled = validatedFieldsOf(contract, resource);
|
|
41
|
+
const issues = [];
|
|
42
|
+
for (const path of records) {
|
|
43
|
+
const record = valueAt(args, path);
|
|
44
|
+
if (!isPlainRecord(record)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
for (const name of Object.keys(record)) {
|
|
48
|
+
const rules = rulesOf(contract, compiled, resource, name);
|
|
49
|
+
if (rules === undefined) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const fieldPath = [...path, name];
|
|
53
|
+
const value = record[name];
|
|
54
|
+
const at = [...argumentsPath, ...fieldPath];
|
|
55
|
+
if (!isDirective(value)) {
|
|
56
|
+
if (select(fieldPath)) {
|
|
57
|
+
issues.push(...valueIssues(rules, value, at));
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const list = rules.kind === "shape" ? rules.field.list : rules.compiled.list;
|
|
62
|
+
if (!list || !Object.hasOwn(value, "$push")) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const operand = value.$push;
|
|
66
|
+
const pushed = Array.isArray(operand)
|
|
67
|
+
? operand.map((entry, index) => ({
|
|
68
|
+
entry,
|
|
69
|
+
path: [...fieldPath, "$push", index],
|
|
70
|
+
}))
|
|
71
|
+
: [{ entry: operand, path: [...fieldPath, "$push"] }];
|
|
72
|
+
for (const { entry, path: entryPath } of pushed) {
|
|
73
|
+
if (!isDirective(entry) && (select(fieldPath) || select(entryPath))) {
|
|
74
|
+
issues.push(...entryIssues(rules, entry, [...argumentsPath, ...entryPath]));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return issues;
|
|
80
|
+
}
|
|
81
|
+
export function fieldValidatorIssues(contract, references, request, args, argumentsPath, select) {
|
|
82
|
+
const issues = recordIssues(contract, request.resource, writeRecordPathsOf(request.family, args), args, argumentsPath, select);
|
|
83
|
+
for (const target of nestedWriteTargetsOf(contract, references, request, args)) {
|
|
84
|
+
issues.push(...recordIssues(contract, target.resource, target.records.map((site) => site.path), args, argumentsPath, select));
|
|
85
|
+
}
|
|
86
|
+
return issues;
|
|
87
|
+
}
|
|
@@ -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,32 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class AvError extends Error {
|
|
2
|
+
name = "AvError";
|
|
2
3
|
code;
|
|
3
4
|
cause;
|
|
4
5
|
constructor(code, cause) {
|
|
5
6
|
const normalizedCause = typeof cause === "string" ? { message: cause } : cause;
|
|
6
7
|
super(normalizedCause.message);
|
|
7
|
-
this.name = "FrameworkError";
|
|
8
8
|
this.code = code;
|
|
9
9
|
this.cause = normalizedCause;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
+
export class AvValidationError extends AvError {
|
|
13
|
+
name = "AvValidationError";
|
|
14
|
+
}
|
|
15
|
+
export class AvNotFoundError extends AvError {
|
|
16
|
+
name = "AvNotFoundError";
|
|
17
|
+
}
|
|
18
|
+
export class AvConflictError extends AvError {
|
|
19
|
+
name = "AvConflictError";
|
|
20
|
+
}
|
|
21
|
+
export class AvAuthError extends AvError {
|
|
22
|
+
name = "AvAuthError";
|
|
23
|
+
}
|
|
24
|
+
export class AvInternalError extends AvError {
|
|
25
|
+
name = "AvInternalError";
|
|
26
|
+
}
|
|
27
|
+
export class AvProtocolError extends AvError {
|
|
28
|
+
name = "AvProtocolError";
|
|
29
|
+
}
|
|
30
|
+
export class AvContractMismatchError extends AvError {
|
|
31
|
+
name = "AvContractMismatchError";
|
|
32
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
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
|
|
4
|
+
* A `Date`, a `bigint`, a `Uint8Array`, a {@link AvDecimal}, any other class
|
|
5
5
|
* instance and an `undefined` property are refused (`V1001`), as are a
|
|
6
6
|
* non-finite `number` (`V1004`) and a cycle (`V1001`).
|
|
7
7
|
*
|
|
@@ -10,6 +10,6 @@
|
|
|
10
10
|
* A `json` field's value is this without its top-level `null`: a field-level
|
|
11
11
|
* `null` is the field's absence, which only `nullable: true` admits.
|
|
12
12
|
*/
|
|
13
|
-
export type
|
|
14
|
-
readonly [key: string]:
|
|
13
|
+
export type AvJsonValue = string | number | boolean | null | readonly AvJsonValue[] | {
|
|
14
|
+
readonly [key: string]: AvJsonValue;
|
|
15
15
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** One level's lifecycle registrations, as an operation or a transaction level holds them. */
|
|
2
|
+
export 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). An after hook is told a deep-frozen copy of
|
|
21
|
+
* 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>;
|