@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,57 @@
|
|
|
1
|
+
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
|
+
import type { AvConfigAny } from "./any-framework-config.js";
|
|
3
|
+
import type { ExactOverlayResource, ExactRootResource } from "./exact-framework-config.js";
|
|
4
|
+
import type { AvConfigResourceKey } from "./framework-field-definition.js";
|
|
5
|
+
import type { AvConfigResource } from "./framework-resources-config.js";
|
|
6
|
+
import type { ErasedOverlayBlocks, ErasedResourceBlock } from "./stage-type.eraser.js";
|
|
7
|
+
/** A configuration whose root `resources` is `{ [R]: Block }`. */
|
|
8
|
+
type ResourceBlockConfig<R extends string, Block> = {
|
|
9
|
+
readonly resources: {
|
|
10
|
+
readonly [K in R]: Block;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/** The layers above the root a Resource may carry blocks for. */
|
|
14
|
+
type OverlayLayer = "application" | "client" | "agent";
|
|
15
|
+
/** A Resource's overlay blocks, as authored: either, both or neither. */
|
|
16
|
+
type ResourceOverlays = {
|
|
17
|
+
readonly [L in OverlayLayer]?: unknown;
|
|
18
|
+
};
|
|
19
|
+
/** The overlay blocks `Overlays`, each checked against the root `Block`. */
|
|
20
|
+
type CheckedOverlays<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, Block, Overlays> = {
|
|
21
|
+
readonly [L in keyof Overlays]: L extends OverlayLayer ? NoInfer<AvConfigResource<M, ResourceBlockConfig<R, Block>, R, "overlay"> & ExactOverlayResource<M, ResourceBlockConfig<R, Block>, R, Overlays[L]>> : never;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* What {@link defineResource} returns: `root`, and `application`, `client` and
|
|
25
|
+
* `agent` exactly when they were given, each `{ [R]: block }` to spread into that
|
|
26
|
+
* layer's `resources`. Each block is as authored, with every stage list typed by
|
|
27
|
+
* its public stage type (`readonly AvGuard[]`, `readonly AvPipe[]`, …).
|
|
28
|
+
*/
|
|
29
|
+
export type AvDefinedResource<R extends string, Block, Overlays> = {
|
|
30
|
+
readonly [L in "root" | Extract<keyof Overlays, OverlayLayer>]: {
|
|
31
|
+
readonly [K in R]: L extends keyof Overlays ? Overlays[L] : Block;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Defines one Resource's configuration on its own: its root block (pipelines,
|
|
36
|
+
* operations, transactions and fields, typed as `resources.<R>` is typed in
|
|
37
|
+
* place) and, optionally, its `application`, `client` and `agent` blocks (typed
|
|
38
|
+
* as `application.resources.<R>`, `client.resources.<R>` and
|
|
39
|
+
* `agent.resources.<R>` are: stages only, no `definition`, and every field the
|
|
40
|
+
* model or the root block has). Returns
|
|
41
|
+
* `{ root, application?, client?, agent? }`, each `{ [R]: block }` to spread into its
|
|
42
|
+
* layer's `resources`; a layer without a block is left out.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* export const post = defineResource<Model>()(
|
|
47
|
+
* "Post",
|
|
48
|
+
* { fields: { title: { pipelines: { pipes: [trim] } } } },
|
|
49
|
+
* { client: { pipelines: { guards: [signedIn] } } },
|
|
50
|
+
* );
|
|
51
|
+
* // aventara.config.ts
|
|
52
|
+
* resources: { ...post.root, ...payment.root },
|
|
53
|
+
* client: { resources: { ...post.client } },
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function defineResource<M extends AvAdapterModel>(): <const R extends AvConfigResourceKey<M>, const Block = AvConfigResource<M, AvConfigAny, R, "root">, const Overlays extends ResourceOverlays = Record<never, never>>(resource: R, block: Block & NoInfer<AvConfigResource<M, ResourceBlockConfig<R, Block>, R, "root"> & ExactRootResource<M, R, Block>>, overlays?: Overlays & CheckedOverlays<M, R, Block, Overlays>) => AvDefinedResource<R, ErasedResourceBlock<Block>, ErasedOverlayBlocks<Overlays>>;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function defineResource() {
|
|
2
|
+
return (resource, block, overlays) => {
|
|
3
|
+
const defined = {
|
|
4
|
+
root: { [resource]: block },
|
|
5
|
+
};
|
|
6
|
+
for (const layer of ["application", "client", "agent"]) {
|
|
7
|
+
const overlay = overlays?.[layer];
|
|
8
|
+
if (overlay !== undefined) {
|
|
9
|
+
defined[layer] = { [resource]: overlay };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return defined;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { RequestOrigin } from "./config-layer.js";
|
|
5
|
-
import type { FrameworkResourceKey } from "./framework-fields-config.js";
|
|
1
|
+
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
|
+
import type { AvAdapterFieldKey } from "../adapters/adapter-resource.js";
|
|
3
|
+
import type { AvConfigResourceKey } from "./framework-field-definition.js";
|
|
6
4
|
/**
|
|
7
|
-
* The `
|
|
5
|
+
* The root `resources` block a configuration owns, or `never` when it has
|
|
6
|
+
* none.
|
|
8
7
|
*
|
|
9
8
|
* `Cfg` is an authored literal, not a validated shape, so the block is read
|
|
10
|
-
* structurally. A
|
|
11
|
-
*
|
|
9
|
+
* structurally. A configuration without a `resources` property infers
|
|
10
|
+
* `unknown`, which is no object, so it contributes nothing.
|
|
12
11
|
*/
|
|
13
|
-
type
|
|
14
|
-
readonly
|
|
15
|
-
} ? Block extends
|
|
16
|
-
/** The field names
|
|
17
|
-
type
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
/** The single answer to "what are `R`'s field names under this configuration". */
|
|
21
|
-
export type EffectiveFieldKey<M extends AdapterModel, Cfg, R extends FrameworkResourceKey<M>> = AdapterFieldKey<M, R> | ConfigFieldKey<M, Cfg, R>;
|
|
22
|
-
/** The overlay `Cfg` carries for `Origin`, or `never` when it declares none. */
|
|
23
|
-
type OriginOverlayOf<Cfg, Origin extends RequestOrigin> = Origin extends keyof Cfg ? NonNullable<Cfg[Origin]> : never;
|
|
12
|
+
type ResourcesBlockOf<Cfg> = Cfg extends {
|
|
13
|
+
readonly resources?: infer Block;
|
|
14
|
+
} ? Block extends object ? Block : never : never;
|
|
15
|
+
/** The field names the root `resources.<R>.fields` block names for `R`. */
|
|
16
|
+
type ResourcesBlockFieldKey<Block, R extends string> = [Block] extends [never] ? never : R extends keyof Block ? NonNullable<Block[R]> extends {
|
|
17
|
+
readonly fields?: infer Fields;
|
|
18
|
+
} ? Extract<keyof NonNullable<Fields>, string> : never : never;
|
|
24
19
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* `client` is not visible under `application`, and the other way round.
|
|
20
|
+
* The field names the configuration's root `resources.<R>.fields` block
|
|
21
|
+
* names: its configured fields, and any discovered field it configures.
|
|
28
22
|
*/
|
|
29
|
-
export type
|
|
23
|
+
export type AvConfigFieldKey<M extends AvAdapterModel, Cfg, R extends AvConfigResourceKey<M>> = ResourcesBlockFieldKey<ResourcesBlockOf<Cfg>, R>;
|
|
24
|
+
/** The single answer to "what are `R`'s field names under this configuration". */
|
|
25
|
+
export type AvEffectiveFieldKey<M extends AvAdapterModel, Cfg, R extends AvConfigResourceKey<M>> = AvAdapterFieldKey<M, R> | AvConfigFieldKey<M, Cfg, R>;
|
|
30
26
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* A mount path (the server's `api` or `mcp` path, a client entrypoint's path), in its one canonical form: `""` at the root,
|
|
3
3
|
* otherwise `/seg(/seg)*` — one leading slash, no trailing slash, no empty segment.
|
|
4
4
|
* Root is the empty string, not `"/"`, so a route joins onto it by concatenation with
|
|
5
5
|
* no special case.
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
|
+
import type { AvAdapterFieldKey } from "../adapters/adapter-resource.js";
|
|
3
|
+
import type { AvScalarFieldCapabilities } from "../contracts/field.js";
|
|
4
|
+
import type { OverlayViewResources, RootViewResources } from "../framework/contract-view.js";
|
|
5
|
+
import type { AvEffectiveFieldKey } from "./effective-fields.js";
|
|
6
|
+
import type { AvConfigResourceKey } from "./framework-field-definition.js";
|
|
7
|
+
import type { AvConfigLayerKind } from "./framework-resources-config.js";
|
|
8
|
+
/** A key whose value this walk does not open. */
|
|
9
|
+
type Leaf = true;
|
|
10
|
+
type PipelinesSchema = {
|
|
11
|
+
readonly guards: Leaf;
|
|
12
|
+
readonly pipes: Leaf;
|
|
13
|
+
readonly hooks: {
|
|
14
|
+
readonly before: Leaf;
|
|
15
|
+
readonly after: Leaf;
|
|
16
|
+
};
|
|
17
|
+
readonly interceptors: Leaf;
|
|
18
|
+
readonly filters: Leaf;
|
|
19
|
+
};
|
|
20
|
+
type LimitsSchema = {
|
|
21
|
+
readonly maxRequestBytes: Leaf;
|
|
22
|
+
readonly maxNestingDepth: Leaf;
|
|
23
|
+
readonly maxListLimit: Leaf;
|
|
24
|
+
readonly maxTransactionOperations: Leaf;
|
|
25
|
+
readonly maxBooleanNodes: Leaf;
|
|
26
|
+
readonly maxJsonDepth: Leaf;
|
|
27
|
+
};
|
|
28
|
+
type LevelSchema = {
|
|
29
|
+
readonly pipelines: PipelinesSchema;
|
|
30
|
+
readonly forceTransaction: Leaf;
|
|
31
|
+
};
|
|
32
|
+
type Operations<M extends AvAdapterModel, R extends AvConfigResourceKey<M>> = M["resources"][R]["operations"];
|
|
33
|
+
type OperationsSchema<M extends AvAdapterModel, R extends AvConfigResourceKey<M>> = {
|
|
34
|
+
readonly [F in keyof Operations<M, R>]: LevelSchema & {
|
|
35
|
+
readonly [V in keyof NonNullable<Operations<M, R>[F]>]: LevelSchema;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
type CapabilitySchema<Capabilities> = {
|
|
39
|
+
readonly [K in keyof Capabilities]-?: Leaf;
|
|
40
|
+
};
|
|
41
|
+
type DefinitionSchema = {
|
|
42
|
+
readonly type: Leaf;
|
|
43
|
+
readonly nullable: Leaf;
|
|
44
|
+
readonly list: Leaf;
|
|
45
|
+
readonly lifecycle: Leaf;
|
|
46
|
+
readonly format: Leaf;
|
|
47
|
+
readonly capabilities: CapabilitySchema<AvScalarFieldCapabilities>;
|
|
48
|
+
readonly json: Leaf;
|
|
49
|
+
};
|
|
50
|
+
type ScalarPipelinesSchema = {
|
|
51
|
+
readonly validators: Leaf;
|
|
52
|
+
readonly pipes: Leaf;
|
|
53
|
+
readonly compute: {
|
|
54
|
+
readonly create: Leaf;
|
|
55
|
+
readonly read: {
|
|
56
|
+
readonly dependsOn: Leaf;
|
|
57
|
+
readonly compute: Leaf;
|
|
58
|
+
};
|
|
59
|
+
readonly update: Leaf;
|
|
60
|
+
};
|
|
61
|
+
readonly guards: Leaf;
|
|
62
|
+
};
|
|
63
|
+
type RelationPipelinesSchema = {
|
|
64
|
+
readonly guards: Leaf;
|
|
65
|
+
};
|
|
66
|
+
type ScalarFieldSchema = {
|
|
67
|
+
readonly pipelines: ScalarPipelinesSchema;
|
|
68
|
+
};
|
|
69
|
+
type RelationFieldSchema = {
|
|
70
|
+
readonly pipelines: RelationPipelinesSchema;
|
|
71
|
+
};
|
|
72
|
+
type RootScalarFieldSchema = ScalarFieldSchema & {
|
|
73
|
+
readonly definition: DefinitionSchema;
|
|
74
|
+
};
|
|
75
|
+
type RootRelationFieldSchema = RelationFieldSchema & {
|
|
76
|
+
readonly definition: DefinitionSchema;
|
|
77
|
+
};
|
|
78
|
+
/** A field entry's keys: a relation takes write guards only; only the root defines. */
|
|
79
|
+
type FieldSchema<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, F, Kind extends AvConfigLayerKind> = F extends AvAdapterFieldKey<M, R> ? M["resources"][R]["fields"][F] extends {
|
|
80
|
+
readonly kind: "relation";
|
|
81
|
+
} ? Kind extends "root" ? RootRelationFieldSchema : RelationFieldSchema : Kind extends "root" ? RootScalarFieldSchema : ScalarFieldSchema : Kind extends "root" ? RootScalarFieldSchema : ScalarFieldSchema;
|
|
82
|
+
declare const otherKeys: unique symbol;
|
|
83
|
+
type ResourceSchema<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, Fields> = {
|
|
84
|
+
readonly pipelines: PipelinesSchema;
|
|
85
|
+
readonly operations: OperationsSchema<M, R>;
|
|
86
|
+
readonly transactions: {
|
|
87
|
+
readonly pipelines: PipelinesSchema;
|
|
88
|
+
};
|
|
89
|
+
readonly fields: Fields;
|
|
90
|
+
};
|
|
91
|
+
/** A layer's fields of Resource `R`, named by `FieldName`. */
|
|
92
|
+
type FieldsSchema<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, Kind extends AvConfigLayerKind, FieldName> = {
|
|
93
|
+
readonly [F in FieldName & string]: FieldSchema<M, R, F, Kind>;
|
|
94
|
+
};
|
|
95
|
+
declare const listOf: unique symbol;
|
|
96
|
+
/** The names a list at this place may hold. */
|
|
97
|
+
type ListOf<Names> = {
|
|
98
|
+
readonly [listOf]: Names;
|
|
99
|
+
};
|
|
100
|
+
/** The tokens one capability member lists, its position qualifier aside. */
|
|
101
|
+
type TokenOf<Member> = Member extends {
|
|
102
|
+
readonly scopes: unknown;
|
|
103
|
+
} ? {
|
|
104
|
+
[K in keyof Member]: K extends "scopes" ? never : Member[K] extends readonly (infer Token)[] ? Token : never;
|
|
105
|
+
}[keyof Member] : Member extends readonly (infer Token)[] ? Token : never;
|
|
106
|
+
/** A field's exemption against its capabilities: their names, and each one's tokens. */
|
|
107
|
+
type CapabilityExemptionSchema<Caps> = ListOf<Exclude<keyof Caps, "nestedWriteFilter">> & {
|
|
108
|
+
readonly [K in Exclude<keyof Caps, "nestedWriteFilter">]-?: ListOf<TokenOf<NonNullable<Caps[K]>>>;
|
|
109
|
+
};
|
|
110
|
+
type FieldExemptionSchema<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, F> = F extends AvAdapterFieldKey<M, R> ? M["resources"][R]["fields"][F] extends {
|
|
111
|
+
readonly kind: "relation";
|
|
112
|
+
readonly capabilities: infer Caps;
|
|
113
|
+
} ? CapabilityExemptionSchema<Caps> : M["resources"][R]["fields"][F] extends {
|
|
114
|
+
readonly capabilities: infer Caps;
|
|
115
|
+
} ? CapabilityExemptionSchema<Caps & {
|
|
116
|
+
readonly select?: true;
|
|
117
|
+
}> : ListOf<keyof AvScalarFieldCapabilities> & CapabilitySchema<AvScalarFieldCapabilities> : ListOf<keyof AvScalarFieldCapabilities> & CapabilitySchema<AvScalarFieldCapabilities>;
|
|
118
|
+
/** A Resource's operations exemption against the operations it offers. */
|
|
119
|
+
type OperationsExemptionSchema<Ops> = ListOf<keyof Ops> & {
|
|
120
|
+
readonly [F in keyof Ops]-?: ListOf<keyof NonNullable<Ops[F]>> & {
|
|
121
|
+
readonly [V in keyof NonNullable<Ops[F]>]: Leaf;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
type ExemptionsSchema<M extends AvAdapterModel, Cfg> = {
|
|
125
|
+
readonly resources: {
|
|
126
|
+
readonly [R in AvConfigResourceKey<M>]: {
|
|
127
|
+
readonly operations: OperationsExemptionSchema<Operations<M, R>>;
|
|
128
|
+
readonly fields: {
|
|
129
|
+
readonly [F in AvEffectiveFieldKey<M, Cfg, R>]: FieldExemptionSchema<M, R, F>;
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
/** A Pick overlay's exemptions, against the root's view. */
|
|
135
|
+
type PickExemptionsSchema<Resources> = {
|
|
136
|
+
readonly resources: {
|
|
137
|
+
readonly [R in keyof Resources]: {
|
|
138
|
+
readonly operations: OperationsExemptionSchema<Resources[R] extends {
|
|
139
|
+
readonly operations: infer Ops;
|
|
140
|
+
} ? Ops : never>;
|
|
141
|
+
readonly fields: {
|
|
142
|
+
readonly [F in keyof (Resources[R] extends {
|
|
143
|
+
readonly fields: infer Fields;
|
|
144
|
+
} ? Fields : never)]: CapabilityExemptionSchema<(Resources[R] extends {
|
|
145
|
+
readonly fields: infer Fields;
|
|
146
|
+
} ? Fields : never)[F] extends {
|
|
147
|
+
readonly capabilities: infer Caps;
|
|
148
|
+
} ? Caps : never>;
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
/** A layer's own configuration: `application`, `client` or `agent`. */
|
|
154
|
+
type OverlayOf<Cfg, Layer extends "application" | "client" | "agent"> = (Cfg & {
|
|
155
|
+
readonly [L in Layer]?: unknown;
|
|
156
|
+
})[Layer];
|
|
157
|
+
/** An overlay's exemptions schema, by the overlay's own `exposed`. */
|
|
158
|
+
type OverlayExemptionsSchema<M extends AvAdapterModel, Cfg, Overlay> = Overlay extends {
|
|
159
|
+
readonly exposed: false;
|
|
160
|
+
} ? PickExemptionsSchema<RootViewResources<M, Cfg>> : ExemptionsSchema<M, Cfg>;
|
|
161
|
+
type LayerKeysSchema = {
|
|
162
|
+
readonly exposed: Leaf;
|
|
163
|
+
readonly transactionsStyle: Leaf;
|
|
164
|
+
readonly limits: LimitsSchema;
|
|
165
|
+
readonly pipelines: PipelinesSchema;
|
|
166
|
+
};
|
|
167
|
+
type RootResourcesSchema<M extends AvAdapterModel> = {
|
|
168
|
+
readonly [R in AvConfigResourceKey<M>]: ResourceSchema<M, R, FieldsSchema<M, R, "root", AvAdapterFieldKey<M, R>> & {
|
|
169
|
+
readonly [otherKeys]: RootScalarFieldSchema;
|
|
170
|
+
}>;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* One root `resources.<R>` block, checked key by key as
|
|
174
|
+
* {@link AvConfigExact} checks it in place.
|
|
175
|
+
*/
|
|
176
|
+
export type ExactRootResource<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, Block> = Exact<RootResourcesSchema<M>[R], Block>;
|
|
177
|
+
/**
|
|
178
|
+
* One overlay `resources.<R>` block, checked key by key as
|
|
179
|
+
* {@link AvConfigExact} checks it in place, its field names read from `Cfg`.
|
|
180
|
+
*/
|
|
181
|
+
export type ExactOverlayResource<M extends AvAdapterModel, Cfg, R extends AvConfigResourceKey<M>, Block> = Exact<ResourceSchema<M, R, FieldsSchema<M, R, "overlay", AvEffectiveFieldKey<M, Cfg, R>>>, Block>;
|
|
182
|
+
type OverlaySchema<M extends AvAdapterModel, Cfg, Layer extends "application" | "client"> = LayerKeysSchema & {
|
|
183
|
+
readonly resources: {
|
|
184
|
+
readonly [R in AvConfigResourceKey<M>]: ResourceSchema<M, R, FieldsSchema<M, R, "overlay", AvEffectiveFieldKey<M, Cfg, R>>>;
|
|
185
|
+
};
|
|
186
|
+
readonly exemptions: OverlayExemptionsSchema<M, Cfg, OverlayOf<Cfg, Layer>>;
|
|
187
|
+
};
|
|
188
|
+
type McpSchema = {
|
|
189
|
+
readonly path: Leaf;
|
|
190
|
+
readonly authorization: {
|
|
191
|
+
readonly servers: Leaf;
|
|
192
|
+
readonly verify: Leaf;
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
/** The layer the agent extends, as authored: `"client"` when it states none. */
|
|
196
|
+
type AgentParentOf<Cfg> = OverlayOf<Cfg, "agent"> extends {
|
|
197
|
+
readonly extends: infer Parent;
|
|
198
|
+
} ? Parent : "client";
|
|
199
|
+
/** A Pick agent's exemptions, against the view of the layer it extends. */
|
|
200
|
+
type AgentPickExemptionsSchema<M extends AvAdapterModel, Cfg, Parent> = Parent extends "application" | "client" ? [Parent] extends ["application"] | ["client"] ? PickExemptionsSchema<OverlayViewResources<M, Cfg, Parent>> : PickExemptionsSchema<RootViewResources<M, Cfg>> : PickExemptionsSchema<RootViewResources<M, Cfg>>;
|
|
201
|
+
type AgentSchema<M extends AvAdapterModel, Cfg> = LayerKeysSchema & {
|
|
202
|
+
readonly extends: Leaf;
|
|
203
|
+
readonly resources: {
|
|
204
|
+
readonly [R in AvConfigResourceKey<M>]: ResourceSchema<M, R, FieldsSchema<M, R, "overlay", AvEffectiveFieldKey<M, Cfg, R>>>;
|
|
205
|
+
};
|
|
206
|
+
readonly exemptions: OverlayOf<Cfg, "agent"> extends {
|
|
207
|
+
readonly exposed: false;
|
|
208
|
+
} ? AgentPickExemptionsSchema<M, Cfg, AgentParentOf<Cfg>> : ExemptionsSchema<M, Cfg>;
|
|
209
|
+
};
|
|
210
|
+
type RootSchema<M extends AvAdapterModel, Cfg> = LayerKeysSchema & {
|
|
211
|
+
readonly api: Leaf;
|
|
212
|
+
readonly mcp: McpSchema;
|
|
213
|
+
readonly adapter: Leaf;
|
|
214
|
+
readonly diagnostics: Leaf;
|
|
215
|
+
readonly misuse: Leaf;
|
|
216
|
+
readonly resources: RootResourcesSchema<M>;
|
|
217
|
+
readonly exemptions: ExemptionsSchema<M, Cfg>;
|
|
218
|
+
readonly application: OverlaySchema<M, Cfg, "application">;
|
|
219
|
+
readonly client: OverlaySchema<M, Cfg, "client">;
|
|
220
|
+
readonly agent: AgentSchema<M, Cfg>;
|
|
221
|
+
};
|
|
222
|
+
/** `V` with every key schema `S` lacks mapped to `never`; every leaf `unknown`. */
|
|
223
|
+
type Exact<S, V> = [S] extends [Leaf] ? unknown : V extends readonly unknown[] ? S extends ListOf<infer Names> ? readonly Names[] : unknown : V extends (...args: any) => any ? unknown : V extends object ? string extends keyof V ? unknown : {
|
|
224
|
+
readonly [K in keyof V]: K extends keyof S ? Exact<S[K], V[K]> : typeof otherKeys extends keyof S ? Exact<S[typeof otherKeys], V[K]> : never;
|
|
225
|
+
} : unknown;
|
|
226
|
+
/**
|
|
227
|
+
* The authored configuration `Cfg`, checked key by key: a key no level of the
|
|
228
|
+
* configuration admits is `never`, a type error at the key. Such a key is a moved
|
|
229
|
+
* rc.0 key, a `definition` in an overlay, a stage a relation field does not take,
|
|
230
|
+
* or a name the model and the root do not have.
|
|
231
|
+
*/
|
|
232
|
+
export type AvConfigExact<M extends AvAdapterModel, Cfg> = Exact<RootSchema<M, Cfg>, Cfg> & ExposedWithExemptions<Cfg, "application"> & ExposedWithExemptions<Cfg, "client"> & ExposedWithExemptions<Cfg, "agent"> & ForceNeedsTransactions<M, Cfg>;
|
|
233
|
+
/** A layer's own literal `transactionsStyle`, `undefined` when it states none. */
|
|
234
|
+
type StyleOf<Layer> = Layer extends {
|
|
235
|
+
readonly transactionsStyle: infer Style;
|
|
236
|
+
} ? Style : undefined;
|
|
237
|
+
/** Whether one origin's effective `transactionsStyle` is certainly `"none"`. */
|
|
238
|
+
type CertainlyNone<M extends AvAdapterModel, Cfg, Layer extends "application" | "client"> = [M["transactions"]] extends ["none"] ? true : [StyleOf<OverlayOf<Cfg, Layer>>] extends [undefined] ? [StyleOf<Cfg>] extends ["none"] ? true : false : [StyleOf<OverlayOf<Cfg, Layer>>] extends ["none"] ? true : false;
|
|
239
|
+
/** A `resources` tree in which no family or variant may set `forceTransaction: true`. */
|
|
240
|
+
type UnforcedResources<M extends AvAdapterModel> = {
|
|
241
|
+
readonly resources?: {
|
|
242
|
+
readonly [R in AvConfigResourceKey<M>]?: {
|
|
243
|
+
readonly operations?: {
|
|
244
|
+
readonly [F in keyof Operations<M, R>]?: {
|
|
245
|
+
readonly forceTransaction?: false;
|
|
246
|
+
} & {
|
|
247
|
+
readonly [V in keyof NonNullable<Operations<M, R>[F]>]?: {
|
|
248
|
+
readonly forceTransaction?: false;
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
/** Refuses `forceTransaction: true` where the effective style is certainly `"none"`. */
|
|
256
|
+
type ForceNeedsTransactions<M extends AvAdapterModel, Cfg> = string extends keyof Cfg ? unknown : ForcedLayers<M, Cfg>;
|
|
257
|
+
/** Whether the agent's effective `transactionsStyle` is certainly `"none"`. */
|
|
258
|
+
type AgentCertainlyNone<M extends AvAdapterModel, Cfg> = [
|
|
259
|
+
M["transactions"]
|
|
260
|
+
] extends ["none"] ? true : [StyleOf<OverlayOf<Cfg, "agent">>] extends [undefined] ? [AgentParentOf<Cfg>] extends ["application"] ? CertainlyNone<M, Cfg, "application"> : [AgentParentOf<Cfg>] extends ["client"] ? CertainlyNone<M, Cfg, "client"> : [AgentParentOf<Cfg>] extends ["root"] ? [StyleOf<Cfg>] extends ["none"] ? true : false : false : [StyleOf<OverlayOf<Cfg, "agent">>] extends ["none"] ? true : false;
|
|
261
|
+
type ForcedLayers<M extends AvAdapterModel, Cfg> = (AgentCertainlyNone<M, Cfg> extends true ? {
|
|
262
|
+
readonly agent?: UnforcedResources<M>;
|
|
263
|
+
} : unknown) & (CertainlyNone<M, Cfg, "application"> extends true ? CertainlyNone<M, Cfg, "client"> extends true ? UnforcedResources<M> : unknown : unknown) & (CertainlyNone<M, Cfg, "application"> extends true ? {
|
|
264
|
+
readonly application?: UnforcedResources<M>;
|
|
265
|
+
} : unknown) & (CertainlyNone<M, Cfg, "client"> extends true ? {
|
|
266
|
+
readonly client?: UnforcedResources<M>;
|
|
267
|
+
} : unknown);
|
|
268
|
+
/** Requires an overlay's `exposed` when the overlay states `exemptions`. */
|
|
269
|
+
type ExposedWithExemptions<Cfg, Layer extends "application" | "client" | "agent"> = Cfg extends {
|
|
270
|
+
readonly [L in Layer]: infer Overlay;
|
|
271
|
+
} ? Overlay extends {
|
|
272
|
+
readonly exemptions: unknown;
|
|
273
|
+
} ? Overlay extends {
|
|
274
|
+
readonly exposed: unknown;
|
|
275
|
+
} ? unknown : {
|
|
276
|
+
readonly [L in Layer]: {
|
|
277
|
+
readonly exposed: boolean;
|
|
278
|
+
};
|
|
279
|
+
} : unknown : unknown;
|
|
280
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AvComputeCreate, AvComputeRead, AvComputeUpdate } from "../runtime/field-compute.js";
|
|
2
|
+
/** One field's compute stages for one origin, each phase already chained. */
|
|
3
|
+
export type ResolvedFieldCompute = {
|
|
4
|
+
readonly create?: AvComputeCreate;
|
|
5
|
+
readonly update?: AvComputeUpdate;
|
|
6
|
+
readonly read?: AvComputeRead;
|
|
7
|
+
};
|
|
8
|
+
/** Compute stages for one origin, by Resource and field name. */
|
|
9
|
+
export type ResolvedComputeConfig = Readonly<Record<string, Readonly<Record<string, ResolvedFieldCompute>>>>;
|
|
10
|
+
/**
|
|
11
|
+
* One layer's compute stages, read off its `resources` tree: per Resource, per
|
|
12
|
+
* field, its `pipelines.compute`. Only phases a layer states are present.
|
|
13
|
+
*/
|
|
14
|
+
export declare function computeOfLayer(resources: unknown): ResolvedComputeConfig;
|
|
15
|
+
/**
|
|
16
|
+
* The compute stages that run for one origin: the root's, then the overlay's,
|
|
17
|
+
* chained phase by phase. Nothing is disabled from below.
|
|
18
|
+
*/
|
|
19
|
+
export declare function chainCompute(root: ResolvedComputeConfig, overlay: ResolvedComputeConfig): ResolvedComputeConfig;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
function chainWrite(root, overlay) {
|
|
2
|
+
if (root === undefined || overlay === undefined) {
|
|
3
|
+
return root ?? overlay;
|
|
4
|
+
}
|
|
5
|
+
return async (context) => {
|
|
6
|
+
const first = await root(context);
|
|
7
|
+
if (first === undefined) {
|
|
8
|
+
return overlay(context);
|
|
9
|
+
}
|
|
10
|
+
const second = await overlay({
|
|
11
|
+
...context,
|
|
12
|
+
value: first,
|
|
13
|
+
data: { ...context.data, [context.field]: first },
|
|
14
|
+
});
|
|
15
|
+
return second === undefined ? first : second;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function readCompute(stage) {
|
|
19
|
+
return typeof stage === "function" ? stage : stage.compute;
|
|
20
|
+
}
|
|
21
|
+
function readDependencies(stage) {
|
|
22
|
+
return typeof stage === "function" ? [] : (stage.dependsOn ?? []);
|
|
23
|
+
}
|
|
24
|
+
function chainRead(root, overlay) {
|
|
25
|
+
if (root === undefined || overlay === undefined) {
|
|
26
|
+
return root ?? overlay;
|
|
27
|
+
}
|
|
28
|
+
const rootCompute = readCompute(root);
|
|
29
|
+
const overlayCompute = readCompute(overlay);
|
|
30
|
+
const compute = async (context) => {
|
|
31
|
+
const first = await rootCompute(context);
|
|
32
|
+
if (first === undefined) {
|
|
33
|
+
return overlayCompute(context);
|
|
34
|
+
}
|
|
35
|
+
const second = await overlayCompute({
|
|
36
|
+
...context,
|
|
37
|
+
value: first,
|
|
38
|
+
record: { ...context.record, [context.field]: first },
|
|
39
|
+
});
|
|
40
|
+
return second === undefined ? first : second;
|
|
41
|
+
};
|
|
42
|
+
const dependsOn = [
|
|
43
|
+
...new Set([...readDependencies(root), ...readDependencies(overlay)]),
|
|
44
|
+
];
|
|
45
|
+
return typeof root === "function" && typeof overlay === "function"
|
|
46
|
+
? compute
|
|
47
|
+
: { dependsOn, compute };
|
|
48
|
+
}
|
|
49
|
+
function isRecord(value) {
|
|
50
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
51
|
+
}
|
|
52
|
+
export function computeOfLayer(resources) {
|
|
53
|
+
const result = {};
|
|
54
|
+
if (!isRecord(resources)) {
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
for (const [resourceName, resource] of Object.entries(resources)) {
|
|
58
|
+
if (!isRecord(resource) || !isRecord(resource.fields)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (const [fieldName, field] of Object.entries(resource.fields)) {
|
|
62
|
+
if (!isRecord(field) || !isRecord(field.pipelines)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const compute = field.pipelines.compute;
|
|
66
|
+
if (!isRecord(compute)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const phases = {};
|
|
70
|
+
if (compute.create !== undefined) {
|
|
71
|
+
phases.create = compute.create;
|
|
72
|
+
}
|
|
73
|
+
if (compute.update !== undefined) {
|
|
74
|
+
phases.update = compute.update;
|
|
75
|
+
}
|
|
76
|
+
if (compute.read !== undefined) {
|
|
77
|
+
phases.read = compute.read;
|
|
78
|
+
}
|
|
79
|
+
if (Object.keys(phases).length === 0) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
result[resourceName] ??= {};
|
|
83
|
+
result[resourceName][fieldName] = phases;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
export function chainCompute(root, overlay) {
|
|
89
|
+
const result = {};
|
|
90
|
+
for (const resourceName of new Set([
|
|
91
|
+
...Object.keys(root),
|
|
92
|
+
...Object.keys(overlay),
|
|
93
|
+
])) {
|
|
94
|
+
const rootFields = root[resourceName] ?? {};
|
|
95
|
+
const overlayFields = overlay[resourceName] ?? {};
|
|
96
|
+
const fields = {};
|
|
97
|
+
for (const fieldName of new Set([
|
|
98
|
+
...Object.keys(rootFields),
|
|
99
|
+
...Object.keys(overlayFields),
|
|
100
|
+
])) {
|
|
101
|
+
const rootField = rootFields[fieldName] ?? {};
|
|
102
|
+
const overlayField = overlayFields[fieldName] ?? {};
|
|
103
|
+
const create = chainWrite(rootField.create, overlayField.create);
|
|
104
|
+
const update = chainWrite(rootField.update, overlayField.update);
|
|
105
|
+
const read = chainRead(rootField.read, overlayField.read);
|
|
106
|
+
fields[fieldName] = {
|
|
107
|
+
...(create !== undefined ? { create } : {}),
|
|
108
|
+
...(update !== undefined ? { update } : {}),
|
|
109
|
+
...(read !== undefined ? { read } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
result[resourceName] = fields;
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
|
+
import type { AvZCheck } from "../avz/avz-check.registry.js";
|
|
3
|
+
import type { AvComputeCreate, AvComputeRead, AvComputeUpdate } from "../runtime/field-compute.js";
|
|
4
|
+
import type { AvFieldGuard, AvFieldPipe } from "../runtime/pipeline.js";
|
|
5
|
+
import type { AvConfigAny } from "./any-framework-config.js";
|
|
6
|
+
import type { AvConfigResourceKey } from "./framework-field-definition.js";
|
|
7
|
+
export type { AvZCheck } from "../avz/avz-check.registry.js";
|
|
8
|
+
/**
|
|
9
|
+
* A scalar field's computed values, one stage per phase: `create` and `update`
|
|
10
|
+
* run before the write, `read` on each returned record.
|
|
11
|
+
*/
|
|
12
|
+
export type AvFieldCompute<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny, R extends AvConfigResourceKey<M> = AvConfigResourceKey<M>> = {
|
|
13
|
+
/** Computes the value on every create; an upsert's create branch included. */
|
|
14
|
+
readonly create?: AvComputeCreate<M>;
|
|
15
|
+
/** Computes the value on every read of a returned record. */
|
|
16
|
+
readonly read?: AvComputeRead<M, Cfg, R>;
|
|
17
|
+
/** Computes the value on every update; an upsert's update branch included. */
|
|
18
|
+
readonly update?: AvComputeUpdate<M>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A scalar field's stages: validators, field pipes, compute and write guards.
|
|
22
|
+
* `Check` is the checks the field takes (any, when the field's type is not
|
|
23
|
+
* known here).
|
|
24
|
+
*/
|
|
25
|
+
export type AvScalarFieldPipeline<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny, R extends AvConfigResourceKey<M> = AvConfigResourceKey<M>, Check extends AvZCheck = AvZCheck> = {
|
|
26
|
+
/**
|
|
27
|
+
* Declarative checks on the value, built with `AvZ` and carried in the Contract;
|
|
28
|
+
* root's, then the overlay's. On a list field `AvZ.minItems` and `AvZ.maxItems`
|
|
29
|
+
* check the list and every other check each entry.
|
|
30
|
+
*/
|
|
31
|
+
readonly validators?: readonly Check[];
|
|
32
|
+
/**
|
|
33
|
+
* Pure transforms of the sent value: value in, value out, no context. They run
|
|
34
|
+
* after the operation's pipes and before the validators; in a transaction, on
|
|
35
|
+
* literal values before it opens and on a `$ref` value at its step.
|
|
36
|
+
*/
|
|
37
|
+
readonly pipes?: readonly AvFieldPipe[];
|
|
38
|
+
/** The field's computed values. */
|
|
39
|
+
readonly compute?: AvFieldCompute<M, Cfg, R>;
|
|
40
|
+
/** Write-only admission: run when the caller sends the field. */
|
|
41
|
+
readonly guards?: readonly AvFieldGuard<NoInfer<M>, R>[];
|
|
42
|
+
};
|
|
43
|
+
/** A relation field's stages: write guards only. */
|
|
44
|
+
export type AvRelationFieldPipeline<M extends AvAdapterModel = AvAdapterModel, R extends string = AvConfigResourceKey<M>> = {
|
|
45
|
+
/** Write-only admission: run for every write through the relation. */
|
|
46
|
+
readonly guards?: readonly AvFieldGuard<NoInfer<M>, R>[];
|
|
47
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AvContracts } from "../compiler/contract.compiler.js";
|
|
2
|
+
import type { AvConfigDiagnostic } from "./config-diagnostic.js";
|
|
3
|
+
type LayerRecord = Readonly<Record<string, unknown>>;
|
|
4
|
+
/**
|
|
5
|
+
* The `forceTransaction` settings a forced call could not honour: one
|
|
6
|
+
* `CONFIG_INVALID_VALUE` per configuration path, naming every origin whose
|
|
7
|
+
* Contract offers the operation without transactions.
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateForcedOperations(config: LayerRecord, contracts: AvContracts): readonly AvConfigDiagnostic[];
|
|
10
|
+
export {};
|