@aventara/core 0.1.0-pilot.3 → 0.1.0-pilot.4
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/dist/adapters/adapter-discovery-diagnostic.d.ts +2 -0
- package/dist/adapters/adapter-field.d.ts +3 -26
- package/dist/adapters/adapter-identifier.d.ts +1 -11
- package/dist/adapters/adapter-model.d.ts +4 -0
- package/dist/adapters/adapter-operation-executor.interface.d.ts +5 -1
- package/dist/adapters/adapter-resource.d.ts +7 -28
- package/dist/adapters/adapter.interface.d.ts +21 -26
- package/dist/compiler/contract-compiler-diagnostic.d.ts +2 -0
- package/dist/compiler/contract.compiler.d.ts +11 -22
- package/dist/config/any-framework-config.d.ts +5 -26
- package/dist/config/config-diagnostic.d.ts +2 -0
- package/dist/config/config-layer.d.ts +6 -19
- package/dist/config/config.resolver.d.ts +6 -14
- package/dist/config/config.validator.d.ts +6 -3
- package/dist/config/define-fields.d.ts +6 -46
- package/dist/config/effective-fields.d.ts +6 -29
- package/dist/config/entrypoint.normalizer.d.ts +6 -18
- package/dist/config/framework-behaviors-config.d.ts +11 -10
- package/dist/config/framework-config.d.ts +15 -15
- package/dist/config/framework-fields-config.d.ts +14 -7
- package/dist/config/framework-restrictions-config.d.ts +41 -61
- package/dist/config/pipeline-config.d.ts +7 -17
- package/dist/contracts/capability.d.ts +13 -49
- package/dist/contracts/client-contract-structure.validator.d.ts +7 -53
- package/dist/contracts/contract-canonicalizer.d.ts +4 -6
- package/dist/contracts/contract-hash.d.ts +3 -2
- package/dist/contracts/contract-limits.d.ts +7 -1
- package/dist/contracts/contract-protocol.d.ts +7 -8
- package/dist/contracts/contract.d.ts +13 -4
- package/dist/contracts/enum-definition.d.ts +2 -0
- package/dist/contracts/field.d.ts +30 -167
- package/dist/contracts/identifier.d.ts +1 -16
- package/dist/contracts/lifecycle-trait.d.ts +4 -3
- package/dist/contracts/resource-operations.d.ts +2 -62
- package/dist/contracts/resource.d.ts +2 -0
- package/dist/contracts/scalar-value-type.d.ts +16 -47
- package/dist/contracts/scalar.d.ts +4 -3
- package/dist/contracts/transaction-capability.d.ts +2 -0
- package/dist/contracts/wire-scalar-format.d.ts +6 -21
- package/dist/framework/contract-view.d.ts +30 -113
- package/dist/framework/framework-construction.error.d.ts +6 -1
- package/dist/framework/framework.d.ts +31 -46
- package/dist/framework/framework.factory.d.ts +3 -17
- package/dist/framework/operation-facade.d.ts +3 -7
- package/dist/operations/operation-arguments.d.ts +52 -207
- package/dist/operations/operation-call.d.ts +13 -15
- package/dist/operations/operation-identity.d.ts +4 -2
- package/dist/operations/operation-result.d.ts +15 -61
- package/dist/operations/operation-validator-core.d.ts +5 -4
- package/dist/operations/operation-validator.d.ts +5 -7
- package/dist/operations/projection-scope.resolver.d.ts +0 -10
- package/dist/operations/validation-code.d.ts +5 -17
- package/dist/operations/write-scope.resolver.d.ts +3 -28
- package/dist/protocol/absent-route.responder.d.ts +23 -38
- package/dist/protocol/av-protocol.d.ts +2 -8
- package/dist/protocol/contract-document.responder.d.ts +5 -18
- package/dist/protocol/http-request.decoder.d.ts +12 -59
- package/dist/protocol/http-request.reader.d.ts +5 -5
- package/dist/protocol/http-response.encoder.d.ts +14 -20
- package/dist/protocol/http-status.table.d.ts +0 -8
- package/dist/protocol/index.d.ts +2 -7
- package/dist/protocol/operation-response.guard.d.ts +0 -15
- package/dist/protocol/protocol-failure.d.ts +8 -27
- package/dist/protocol/protocol-headers.d.ts +15 -42
- package/dist/protocol/protocol-surface.d.ts +0 -22
- package/dist/protocol/protocol.binder.d.ts +16 -26
- package/dist/protocol/protocol.handler.d.ts +15 -23
- package/dist/runtime/decimal.d.ts +5 -3
- package/dist/runtime/diagnostics-reporter.d.ts +14 -34
- package/dist/runtime/error-boundary.d.ts +6 -10
- package/dist/runtime/execution-options.d.ts +3 -7
- package/dist/runtime/field-behavior.d.ts +12 -19
- package/dist/runtime/framework-error.d.ts +2 -2
- package/dist/runtime/json-value.d.ts +7 -15
- package/dist/runtime/mutation-planner.d.ts +6 -12
- package/dist/runtime/operation-request.d.ts +7 -0
- package/dist/runtime/operation-response.d.ts +18 -23
- package/dist/runtime/operation-runtime.d.ts +12 -27
- package/dist/runtime/pipeline.d.ts +14 -29
- package/dist/runtime/referential-action.d.ts +1 -26
- package/dist/runtime/request-id.d.ts +3 -10
- package/dist/runtime/scalar-runtime.d.ts +12 -12
- package/dist/transactions/deferred-operation.d.ts +10 -21
- package/dist/transactions/operation-arguments-encoder.d.ts +1 -0
- package/dist/transactions/operation-fingerprint.d.ts +3 -1
- package/dist/transactions/transaction-envelope.d.ts +2 -4
- package/dist/transactions/transaction-integrity-error.d.ts +4 -15
- package/dist/transactions/transaction-plan-assembler.d.ts +1 -0
- package/dist/transactions/transaction-plan-validator.d.ts +3 -17
- package/dist/transactions/transaction-reference-resolver.d.ts +9 -12
- package/dist/transactions/transaction-reference.d.ts +23 -28
- package/dist/transactions/transaction-request.d.ts +3 -5
- package/dist/transactions/transaction-response.d.ts +5 -7
- package/dist/transactions/transaction-runtime.d.ts +3 -3
- package/dist/transactions/transaction-slot-path-error.d.ts +5 -15
- package/dist/transactions/transaction-slot-writer.d.ts +3 -13
- package/package.json +1 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/** Codes of {@link AdapterDiscoveryDiagnostic}. */
|
|
1
2
|
export type AdapterDiscoveryDiagnosticCode = "DISCOVERY_TRANSACTION_CAPABILITY_MISMATCH";
|
|
3
|
+
/** A problem found in what the adapter discovered, reported at framework construction. */
|
|
2
4
|
export type AdapterDiscoveryDiagnostic = {
|
|
3
5
|
readonly code: AdapterDiscoveryDiagnosticCode;
|
|
4
6
|
readonly path: "adapter.transactions";
|
|
@@ -3,13 +3,7 @@ import type { LifecycleTrait } from "../contracts/lifecycle-trait.js";
|
|
|
3
3
|
import type { AdapterModel } from "./adapter-model.js";
|
|
4
4
|
/** Provider-observable lifecycle facts available during adapter discovery. */
|
|
5
5
|
export type AdapterLifecycleTrait = Extract<LifecycleTrait, "DEFAULTED" | "GENERATED_ON_CREATE" | "GENERATED_ON_UPDATE">;
|
|
6
|
-
/**
|
|
7
|
-
* Scalar-shaped provider field expressed only in Aventara vocabulary.
|
|
8
|
-
*
|
|
9
|
-
* Scalar capabilities carry no scope qualifier, measured and not assumed: all six
|
|
10
|
-
* members are uniform across every operation variant on both pilot engines, so a
|
|
11
|
-
* discoverer has nothing per-position to answer here.
|
|
12
|
-
*/
|
|
6
|
+
/** Scalar-shaped provider field expressed only in Aventara vocabulary. */
|
|
13
7
|
export type AdapterScalarField<M extends AdapterModel> = {
|
|
14
8
|
readonly kind: "scalar";
|
|
15
9
|
readonly type: {
|
|
@@ -23,25 +17,7 @@ export type AdapterScalarField<M extends AdapterModel> = {
|
|
|
23
17
|
readonly lifecycle: readonly AdapterLifecycleTrait[];
|
|
24
18
|
readonly capabilities: ScalarFieldCapabilities;
|
|
25
19
|
};
|
|
26
|
-
/**
|
|
27
|
-
* Provider relation edge; the target AdapterResource owns object shape.
|
|
28
|
-
*
|
|
29
|
-
* The capabilities are the Contract's own {@link RelationFieldCapabilities}, scope
|
|
30
|
-
* qualifier included, and that sharing is the point: the ADAPTER is the only party
|
|
31
|
-
* that can measure which argument positions a relation is reachable in, because
|
|
32
|
-
* the answer depends on which provider call each operation variant is routed to.
|
|
33
|
-
* Core tabulating it would be a tabulated provider fact and would be wrong for the
|
|
34
|
-
* next adapter.
|
|
35
|
-
*
|
|
36
|
-
* The qualifier is OPTIONAL at this boundary, as it is in the Contract: an adapter
|
|
37
|
-
* that has not measured the axis states the unqualified answer and is believed,
|
|
38
|
-
* which is what keeps a surface that predates the measurement meaningful rather
|
|
39
|
-
* than silently narrowed.
|
|
40
|
-
*
|
|
41
|
-
* **A scope qualifies the TOP LEVEL of an argument only** — the measurement and
|
|
42
|
-
* the reason are recorded on `ProjectionScope`, and a discoverer that narrows
|
|
43
|
-
* recursively would advertise less than the provider accepts.
|
|
44
|
-
*/
|
|
20
|
+
/** A discovered relation field; the `target` Resource describes the related row. */
|
|
45
21
|
export type AdapterRelationField<M extends AdapterModel> = {
|
|
46
22
|
readonly kind: "relation";
|
|
47
23
|
readonly target: Extract<keyof M["resources"], string>;
|
|
@@ -49,4 +25,5 @@ export type AdapterRelationField<M extends AdapterModel> = {
|
|
|
49
25
|
readonly nullable: boolean;
|
|
50
26
|
readonly capabilities: RelationFieldCapabilities;
|
|
51
27
|
};
|
|
28
|
+
/** One field the adapter discovered: a scalar or a relation. */
|
|
52
29
|
export type AdapterField<M extends AdapterModel> = AdapterScalarField<M> | AdapterRelationField<M>;
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import type { AdapterField } from "./adapter-field.js";
|
|
2
2
|
import type { AdapterModel } from "./adapter-model.js";
|
|
3
|
-
/**
|
|
4
|
-
* Keys of `TFields` whose discovered field can be scalar-shaped.
|
|
5
|
-
*
|
|
6
|
-
* `TFields[K]` is an indexed access, not a naked type parameter, so a bare
|
|
7
|
-
* conditional would not distribute over a union-valued field. With the
|
|
8
|
-
* abstract `AdapterFieldMap` default every key maps to the whole
|
|
9
|
-
* `AdapterField` union, which is not a subtype of the scalar branch, so the
|
|
10
|
-
* bare form collapses to `never` and makes `AdapterIdentifier` uninhabitable.
|
|
11
|
-
* `Extract` selects the scalar branch out of the union instead, so a key is
|
|
12
|
-
* kept unless it is provably relation-only.
|
|
13
|
-
*/
|
|
3
|
+
/** Keys of `TFields` whose discovered field can be scalar-shaped. */
|
|
14
4
|
export type AdapterScalarFieldKey<TFields extends Readonly<Record<string, AdapterField<AdapterModel>>>> = Extract<{
|
|
15
5
|
[K in keyof TFields]: [
|
|
16
6
|
Extract<TFields[K], {
|
|
@@ -7,8 +7,12 @@ import type { AdapterResource } from "./adapter-resource.js";
|
|
|
7
7
|
* Contract compilation is applied.
|
|
8
8
|
*/
|
|
9
9
|
export interface AdapterModel {
|
|
10
|
+
/** The scalar types the data source supports. */
|
|
10
11
|
readonly scalars: ScalarRegistry;
|
|
12
|
+
/** The enums the data source declares, by name. */
|
|
11
13
|
readonly enums: Readonly<Record<string, EnumDefinition>>;
|
|
14
|
+
/** The discovered Resources, by name. */
|
|
12
15
|
readonly resources: Readonly<Record<string, AdapterResource<this>>>;
|
|
16
|
+
/** Whether the adapter can run interactive transactions. */
|
|
13
17
|
readonly transactions: TransactionCapability;
|
|
14
18
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { AdapterModel } from "./adapter-model.js";
|
|
2
2
|
import type { AdapterOperation } from "./adapter-operation.js";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Executes one operation against the provider, directly or inside a provider
|
|
5
|
+
* transaction.
|
|
6
|
+
*/
|
|
4
7
|
export interface AdapterOperationExecutor<M extends AdapterModel = AdapterModel> {
|
|
8
|
+
/** Runs one validated operation and resolves its raw result. */
|
|
5
9
|
execute(operation: AdapterOperation<M>): Promise<unknown>;
|
|
6
10
|
}
|
|
@@ -2,40 +2,19 @@ import type { ResourceOperations } from "../contracts/resource-operations.js";
|
|
|
2
2
|
import type { AdapterField } from "./adapter-field.js";
|
|
3
3
|
import type { AdapterIdentifier } from "./adapter-identifier.js";
|
|
4
4
|
import type { AdapterModel } from "./adapter-model.js";
|
|
5
|
+
/** A discovered Resource's fields, by name. */
|
|
5
6
|
export type AdapterFieldMap<M extends AdapterModel> = Readonly<Record<string, AdapterField<M>>>;
|
|
6
7
|
/**
|
|
7
|
-
* The field names the adapter discovered for `R
|
|
8
|
-
*
|
|
9
|
-
* This is the lower layer of `EffectiveFieldKey`, in
|
|
10
|
-
* `config/effective-fields.ts`: everything the provider already knows about,
|
|
11
|
-
* before any configuration is applied. Named in prose rather than with a
|
|
12
|
-
* `{@link}` because a resolvable link would need an import, and `adapters/`
|
|
13
|
-
* must not reach into `config/`.
|
|
14
|
-
*
|
|
15
|
-
* `R`'s constraint is written out rather than imported as
|
|
16
|
-
* `FrameworkResourceKey<M>` — the identical type — because `adapters/` owns
|
|
17
|
-
* the Base layer and must not depend on `config/`.
|
|
8
|
+
* The field names the adapter discovered for Resource `R`, before any
|
|
9
|
+
* configuration adds to them.
|
|
18
10
|
*/
|
|
19
11
|
export type AdapterFieldKey<M extends AdapterModel, R extends Extract<keyof M["resources"], string>> = Extract<keyof M["resources"][R]["fields"], string>;
|
|
20
|
-
/**
|
|
21
|
-
* Provider-discovered facts for one Aventara Resource candidate.
|
|
22
|
-
*
|
|
23
|
-
* `TFields` is never supplied by a caller — every in-repo site writes
|
|
24
|
-
* `AdapterResource<M>` — but it is **load-bearing and must not be inlined**. It is
|
|
25
|
-
* the indirection that keeps `M` out of this type's body.
|
|
26
|
-
*
|
|
27
|
-
* `AdapterField<M>` is invariant in `M` (it reads `keyof M["scalars"]` and `keyof
|
|
28
|
-
* M["resources"]`). If `M` reached the body, `AdapterResource` would acquire an
|
|
29
|
-
* invariant variance marker, and every concrete model would stop satisfying the
|
|
30
|
-
* self-typed `AdapterModel.resources: Readonly<Record<string,
|
|
31
|
-
* AdapterResource<this>>>` constraint. Measured: 43 type errors across the adapter
|
|
32
|
-
* and index type tests, and identically 43 whether the parameter is deleted or
|
|
33
|
-
* merely bypassed — so it is the body occurrence that matters, not the arity.
|
|
34
|
-
*
|
|
35
|
-
* Deleting it is not a cleanup.
|
|
36
|
-
*/
|
|
12
|
+
/** Provider-discovered facts for one Aventara Resource candidate. */
|
|
37
13
|
export type AdapterResource<M extends AdapterModel, TFields extends AdapterFieldMap<M> = AdapterFieldMap<M>> = {
|
|
14
|
+
/** The Resource's fields, by name. */
|
|
38
15
|
readonly fields: TFields;
|
|
16
|
+
/** The field tuples that identify at most one row. */
|
|
39
17
|
readonly identifiers: readonly AdapterIdentifier<TFields>[];
|
|
18
|
+
/** The standard operations the data source can run for this Resource. */
|
|
40
19
|
readonly operations: ResourceOperations;
|
|
41
20
|
};
|
|
@@ -5,47 +5,42 @@ import type { AdapterOperationExecutor } from "./adapter-operation-executor.inte
|
|
|
5
5
|
/** Provider-specific implementation of Aventara discovery and execution. */
|
|
6
6
|
export interface Adapter<M extends AdapterModel = AdapterModel> extends AdapterOperationExecutor<M> {
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
* synchronously
|
|
10
|
-
* call: the model is a settled fact of the constructed adapter, so it
|
|
11
|
-
* cannot fail, change, or be observed twice during construction.
|
|
8
|
+
* What the adapter discovered about the data source, in Aventara's vocabulary.
|
|
9
|
+
* Read once, synchronously, when the framework is constructed.
|
|
12
10
|
*/
|
|
13
11
|
readonly model: M;
|
|
14
12
|
/**
|
|
15
13
|
* Optional referential actions: for each Resource that holds a reference,
|
|
16
|
-
* what deleting a referenced row does to its rows
|
|
17
|
-
*
|
|
18
|
-
* like `model`, and never part of a Contract or its hash.
|
|
14
|
+
* what deleting a referenced row does to its rows. Read once when the
|
|
15
|
+
* framework is constructed; never part of a Contract or its hash.
|
|
19
16
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* `R`**.
|
|
17
|
+
* An edge listed under Resource `R` says **deleting a `target` row does
|
|
18
|
+
* `onDelete` to rows of `R`**.
|
|
23
19
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
20
|
+
* When absent, no cascade is planned and no transaction plan is refused
|
|
21
|
+
* because of one (`V1019`).
|
|
26
22
|
*/
|
|
27
23
|
readonly referentialActions?: ReferentialActionTable;
|
|
28
24
|
/**
|
|
29
25
|
* Optional create requirements: for each Resource, the values its store
|
|
30
|
-
* cannot create a row without
|
|
31
|
-
*
|
|
32
|
-
* like `model`, and never part of a Contract or its hash.
|
|
26
|
+
* cannot create a row without. Read once when the framework is constructed;
|
|
27
|
+
* never part of a Contract or its hash.
|
|
33
28
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
29
|
+
* When absent, creates are not checked for missing values before they reach
|
|
30
|
+
* the store.
|
|
36
31
|
*/
|
|
37
32
|
readonly createRequirements?: CreateRequirementTable;
|
|
38
33
|
/**
|
|
39
|
-
* Optional callback transaction capability, required exactly when the
|
|
40
|
-
* model declares `transactions: "interactive"`. The callback
|
|
41
|
-
* transaction-scoped operation executor, never the provider
|
|
42
|
-
* every operation of a plan executes through it.
|
|
34
|
+
* Optional callback transaction capability, required exactly when the
|
|
35
|
+
* discovered model declares `transactions: "interactive"`. The callback
|
|
36
|
+
* receives only a transaction-scoped operation executor, never the provider
|
|
37
|
+
* client itself, and every operation of a plan executes through it.
|
|
43
38
|
*
|
|
44
|
-
* The implementation
|
|
45
|
-
* never a wrapper — and
|
|
46
|
-
* implied by that rejection.
|
|
47
|
-
*
|
|
48
|
-
*
|
|
39
|
+
* The implementation must reject with the exact value `work` threw — by identity,
|
|
40
|
+
* never a wrapper — and must not resolve after `work` rejected; rollback is
|
|
41
|
+
* implied by that rejection. Guards, pipes, hooks and interceptors of every plan
|
|
42
|
+
* operation run inside `work` while the provider transaction is open, so they must
|
|
43
|
+
* not perform network I/O or unrelated slow work.
|
|
49
44
|
*/
|
|
50
45
|
transaction?<T>(work: (executor: AdapterOperationExecutor<M>) => Promise<T>): Promise<T>;
|
|
51
46
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** Codes of {@link ContractCompilerDiagnostic}. */
|
|
1
2
|
export type ContractCompilerDiagnosticCode = "COMPILER_UNKNOWN_RESOURCE" | "COMPILER_UNKNOWN_FIELD" | "COMPILER_RELATION_FIELD_CONFIG_UNSUPPORTED" | "COMPILER_INCOMPLETE_FIELD" | "COMPILER_STRUCTURAL_FIELD_OVERRIDE" | "COMPILER_MISSING_SCALAR" | "COMPILER_MISSING_ENUM" | "COMPILER_DANGLING_RELATION" | "COMPILER_UNAVAILABLE_OPERATION" | "COMPILER_UNAVAILABLE_CAPABILITY" | "COMPILER_INVALID_LIFECYCLE" | "COMPILER_MISSING_READ_BEHAVIOR" | "COMPILER_INVALID_BEHAVIOR_DEPENDENCY"
|
|
2
3
|
/**
|
|
3
4
|
* The finished, hashed client projection is not a structurally valid
|
|
@@ -6,6 +7,7 @@ export type ContractCompilerDiagnosticCode = "COMPILER_UNKNOWN_RESOURCE" | "COMP
|
|
|
6
7
|
* (`$.enums.status.values[1]`).
|
|
7
8
|
*/
|
|
8
9
|
| "COMPILER_INVALID_CLIENT_CONTRACT";
|
|
10
|
+
/** One reason a configuration could not be compiled into Contracts. */
|
|
9
11
|
export type ContractCompilerDiagnostic = {
|
|
10
12
|
readonly code: ContractCompilerDiagnosticCode;
|
|
11
13
|
readonly path: string;
|
|
@@ -2,11 +2,16 @@ import type { AdapterModel } from "../adapters/adapter-model.js";
|
|
|
2
2
|
import type { ResolvedFrameworkConfig } from "../config/config.resolver.js";
|
|
3
3
|
import type { ApplicationContract, ClientContract, CoreContract } from "../contracts/contract.js";
|
|
4
4
|
import type { ContractCompilerDiagnostic } from "./contract-compiler-diagnostic.js";
|
|
5
|
+
/** The Core, Application and Client Contracts compiled from one configuration. */
|
|
5
6
|
export type FrameworkContracts = {
|
|
6
7
|
readonly core: CoreContract;
|
|
7
8
|
readonly application: ApplicationContract;
|
|
8
9
|
readonly client: ClientContract;
|
|
9
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* The result of {@link compileContracts}: the three Contracts, or the
|
|
13
|
+
* diagnostics that stopped compilation.
|
|
14
|
+
*/
|
|
10
15
|
export type ContractCompilationResult = {
|
|
11
16
|
readonly ok: true;
|
|
12
17
|
readonly contracts: FrameworkContracts;
|
|
@@ -16,28 +21,12 @@ export type ContractCompilationResult = {
|
|
|
16
21
|
};
|
|
17
22
|
/**
|
|
18
23
|
* Whether writing `configured` VERBATIM as capability member `key` would advertise
|
|
19
|
-
* something `baseline` does not — the question the `fields` walk asks before it
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* Answered on the member's AXIS, off the same `satisfies`-pinned table the
|
|
23
|
-
* restriction walk and the output gate read, and the baseline is read through the
|
|
24
|
-
* shape's own owners: {@link holdsAt} for a position list, the `…At` readers for a
|
|
25
|
-
* scope-qualified token arm. Never off the runtime shape of the value: an
|
|
26
|
-
* object-shaped arm used to match no branch and pass unexamined, and `true` was
|
|
27
|
-
* compared to the baseline with `!== true`, which reads a qualified baseline as
|
|
28
|
-
* *not advertised* even where it holds in every position.
|
|
29
|
-
*
|
|
30
|
-
* The unqualified forms keep their meaning: `true` and a bare token list claim
|
|
31
|
-
* every position on the axis, so either one over a qualified baseline is an
|
|
32
|
-
* addition — writing it verbatim would widen the member.
|
|
33
|
-
*
|
|
34
|
-
* A key no axis covers, and a value its axis does not admit, are not additions;
|
|
35
|
-
* they are unrepresentable, and the output gate ({@link
|
|
36
|
-
* validateCapabilityRepresentation}) is the one place that says so. So is a
|
|
37
|
-
* position off the axis.
|
|
38
|
-
*
|
|
39
|
-
* Exported for its unit test only; it is not part of the package surface.
|
|
24
|
+
* something `baseline` does not — the question the `fields` walk asks before it copies
|
|
25
|
+
* a value onto an adapter field.
|
|
40
26
|
*/
|
|
41
27
|
export declare function capabilityAddsBaseline(fieldKind: "scalar" | "relation", baseline: Readonly<Record<string, unknown>>, key: string, configured: unknown): boolean;
|
|
42
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Compiles the Core Contract from the adapter model and the root
|
|
30
|
+
* configuration, then the Application and Client Contracts from it.
|
|
31
|
+
*/
|
|
43
32
|
export declare function compileContracts<M extends AdapterModel>(model: M, config: ResolvedFrameworkConfig<M>): Promise<ContractCompilationResult>;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A `fields` block whose resource and field names are both unconstrained.
|
|
3
|
-
*
|
|
4
|
-
* The `undefined` in the value position is required, not incidental: under
|
|
5
|
-
* `exactOptionalPropertyTypes` a real `fields` block is a `Partial` record,
|
|
6
|
-
* so its values include `undefined` and it would not otherwise be assignable
|
|
7
|
-
* to the widest block.
|
|
8
|
-
*/
|
|
1
|
+
/** A `fields` block whose resource and field names are both unconstrained. */
|
|
9
2
|
export type AnyFieldsBlock = Readonly<Record<string, Readonly<Record<string, unknown>> | undefined>>;
|
|
10
3
|
/** The widest scope overlay: a `fields` block, and anything else. */
|
|
11
4
|
export type AnyScopeConfig = {
|
|
@@ -13,24 +6,10 @@ export type AnyScopeConfig = {
|
|
|
13
6
|
readonly fields?: AnyFieldsBlock;
|
|
14
7
|
};
|
|
15
8
|
/**
|
|
16
|
-
* The widest
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* `createFramework`. Because it constrains nothing, a `FrameworkConfig<M>`
|
|
21
|
-
* written without a `Cfg` argument behaves exactly as it did before `Cfg`
|
|
22
|
-
* existed: narrowing below the resource key is opt-in, never imposed.
|
|
23
|
-
*
|
|
24
|
-
* `Cfg` is the authored configuration literal itself, not a shape the
|
|
25
|
-
* framework validates. Its only job is to carry the field names the
|
|
26
|
-
* configuration adds — at the root layer and at each scope overlay — so that
|
|
27
|
-
* a resource's effective field-key set is computable from the adapter model
|
|
28
|
-
* plus the configuration alone, and never from a compiled Contract.
|
|
29
|
-
*
|
|
30
|
-
* The index signature is what makes "widest" true. Without it this is a weak
|
|
31
|
-
* type, and a configuration that happens to declare no `fields`,
|
|
32
|
-
* `application` or `client` would have no property in common with it and be
|
|
33
|
-
* rejected — the opposite of the intended default.
|
|
9
|
+
* The widest configuration type: every resource admits every field name. It
|
|
10
|
+
* is the default `Cfg` of `FrameworkConfig`, `Framework` and
|
|
11
|
+
* `createFramework`; pass your own configuration's type instead to get field
|
|
12
|
+
* names checked.
|
|
34
13
|
*/
|
|
35
14
|
export type AnyFrameworkConfig = {
|
|
36
15
|
readonly [key: string]: unknown;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/** Codes of {@link ConfigDiagnostic}. */
|
|
1
2
|
export type ConfigDiagnosticCode = "CONFIG_REQUIRED" | "CONFIG_UNKNOWN_PROPERTY" | "CONFIG_INVALID_TYPE" | "CONFIG_INVALID_VALUE";
|
|
3
|
+
/** One problem found in a configuration, at its path. */
|
|
2
4
|
export type ConfigDiagnostic = {
|
|
3
5
|
readonly code: ConfigDiagnosticCode;
|
|
4
6
|
readonly path: string;
|
|
@@ -1,25 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* One layer of the configuration
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Application and Client Contracts.
|
|
6
|
-
*
|
|
7
|
-
* The one source of truth for the layer set. {@link RequestOrigin} is derived
|
|
8
|
-
* from it rather than declared beside it, so the two cannot drift.
|
|
9
|
-
*
|
|
10
|
-
* Deliberately not named `…Scope`: that word already carries several unrelated
|
|
11
|
-
* meanings in this package (the framework scope configuration, the pipeline
|
|
12
|
-
* `scope`, and the capability positions `ProjectionScope`/`WriteScope`), and a
|
|
13
|
-
* layer of the configuration tree is none of them.
|
|
2
|
+
* One layer of the configuration: `root` is the configuration's own top level
|
|
3
|
+
* and compiles to the Core Contract; `application` and `client` are overlays
|
|
4
|
+
* on top of it and compile to the Application and Client Contracts.
|
|
14
5
|
*/
|
|
15
6
|
export type ConfigLayer = "root" | "application" | "client";
|
|
16
7
|
/**
|
|
17
|
-
* The layers a request can
|
|
18
|
-
* `
|
|
19
|
-
*
|
|
20
|
-
* not an origin.
|
|
21
|
-
*
|
|
22
|
-
* It is also the set of overlays a configuration may declare, because each
|
|
23
|
-
* origin sees exactly the root layer plus its own overlay.
|
|
8
|
+
* The layers a request can come from: `application` (in-process calls) or
|
|
9
|
+
* `client` (remote calls). Each sees the root configuration plus its own
|
|
10
|
+
* overlay.
|
|
24
11
|
*/
|
|
25
12
|
export type RequestOrigin = Exclude<ConfigLayer, "root">;
|
|
@@ -7,33 +7,25 @@ import type { FrameworkConfig, FrameworkLimitsConfig } from "./framework-config.
|
|
|
7
7
|
import type { FrameworkFieldsConfig } from "./framework-fields-config.js";
|
|
8
8
|
import type { FrameworkRestrictionsConfig } from "./framework-restrictions-config.js";
|
|
9
9
|
import type { ResolvedPipelineConfig } from "./pipeline-config.js";
|
|
10
|
+
/** One resolved layer of the configuration: root, application or client. */
|
|
10
11
|
export type ResolvedFrameworkScopeConfig<M extends AdapterModel = AdapterModel> = {
|
|
11
12
|
readonly fields: FrameworkFieldsConfig<M> | undefined;
|
|
12
|
-
/**
|
|
13
|
-
* The **erased** behaviors view, deliberately not `FrameworkBehaviorsConfig<M>`.
|
|
14
|
-
*
|
|
15
|
-
* A compute context carries `resource: R`, so a behavior bound to one
|
|
16
|
-
* Resource is a callback that accepts only that Resource's name. That makes
|
|
17
|
-
* `FrameworkBehaviorsConfig<M>` contravariant in the Resource key and *not*
|
|
18
|
-
* a subtype of the widest instantiation — correctly so. The runtime dispatches
|
|
19
|
-
* by string key and can never recover which literal it holds, so it consumes
|
|
20
|
-
* behaviors erased, exactly as it consumes the compiled Contract: narrowing is
|
|
21
|
-
* an authoring-time affordance, and resolution is the boundary where it ends.
|
|
22
|
-
*/
|
|
13
|
+
/** The behaviors configuration, with Resource and field keys as plain strings. */
|
|
23
14
|
readonly behaviors: FrameworkBehaviorsConfig | undefined;
|
|
24
15
|
readonly restrictions: FrameworkRestrictionsConfig<M> | undefined;
|
|
25
16
|
readonly limits: FrameworkLimitsConfig | undefined;
|
|
26
17
|
readonly pipelines: ResolvedPipelineConfig;
|
|
27
18
|
readonly transactions: TransactionCapability | undefined;
|
|
28
19
|
};
|
|
20
|
+
/** A configuration after defaults and overlays are resolved, before compilation. */
|
|
29
21
|
export type ResolvedFrameworkConfig<M extends AdapterModel = AdapterModel> = {
|
|
30
22
|
/**
|
|
31
|
-
* The mount path in its canonical form: `""` at the root, otherwise
|
|
32
|
-
*
|
|
23
|
+
* The mount path in its canonical form: `""` at the root, otherwise
|
|
24
|
+
* `/seg(/seg)*`.
|
|
33
25
|
*/
|
|
34
26
|
readonly entrypoint: string;
|
|
35
27
|
readonly adapter: Adapter<M>;
|
|
36
|
-
/**
|
|
28
|
+
/** The diagnostics sink, from the root configuration only. */
|
|
37
29
|
readonly diagnostics: FrameworkDiagnosticsSink | undefined;
|
|
38
30
|
readonly root: ResolvedFrameworkScopeConfig<M>;
|
|
39
31
|
readonly application: ResolvedFrameworkScopeConfig<M>;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ConfigDiagnostic } from "./config-diagnostic.js";
|
|
2
2
|
/**
|
|
3
3
|
* The refusal of an entrypoint whose mount path is not canonical, from the
|
|
4
|
-
* normalizer's message: it names the defect and the rule — never the value, which
|
|
5
|
-
*
|
|
4
|
+
* normalizer's message: it names the defect and the rule — never the value, which may
|
|
5
|
+
* carry credentials.
|
|
6
6
|
*/
|
|
7
7
|
export declare function entrypointRefusalDiagnostic(message: string): ConfigDiagnostic;
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Checks the structure of a configuration object and reports each problem as
|
|
10
|
+
* a {@link ConfigDiagnostic}.
|
|
11
|
+
*/
|
|
9
12
|
export declare function validateFrameworkConfig(value: unknown): readonly ConfigDiagnostic[];
|
|
@@ -2,55 +2,26 @@ import type { AdapterModel } from "../adapters/adapter-model.js";
|
|
|
2
2
|
import type { AdapterFieldKey } from "../adapters/adapter-resource.js";
|
|
3
3
|
import type { FrameworkResourceKey, FrameworkScalarFieldConfig, FrameworkScalarTypeRef } from "./framework-fields-config.js";
|
|
4
4
|
/**
|
|
5
|
-
* What
|
|
6
|
-
*
|
|
7
|
-
* Everything in {@link FrameworkScalarFieldConfig} except `type`: the adapter
|
|
8
|
-
* owns a discovered field's scalar/enum identity, so restating it here would
|
|
9
|
-
* create a second source of truth for a fact discovery already settled.
|
|
10
|
-
* `type?: never` rather than an omission so the rejection is a pointed
|
|
11
|
-
* assignability error at the offending property, not a whole-object one.
|
|
5
|
+
* What a configuration may say about a field the adapter already discovered:
|
|
6
|
+
* everything in {@link FrameworkScalarFieldConfig} except `type`.
|
|
12
7
|
*/
|
|
13
8
|
export type KnownScalarFieldConfig<M extends AdapterModel = AdapterModel> = Omit<FrameworkScalarFieldConfig<M>, "type"> & {
|
|
14
9
|
readonly type?: never;
|
|
15
10
|
};
|
|
16
11
|
/**
|
|
17
|
-
* A scalar field the configuration adds, which the adapter
|
|
18
|
-
*
|
|
19
|
-
* Nothing upstream can supply the structural leaves for a name that exists
|
|
20
|
-
* nowhere in the provider, so `type`, `nullable` and `list` are required
|
|
21
|
-
* here while they stay optional on the augmentation shape.
|
|
12
|
+
* A scalar field the configuration adds, which the adapter did not discover.
|
|
13
|
+
* `type`, `nullable` and `list` are required.
|
|
22
14
|
*/
|
|
23
15
|
export type AddedScalarFieldConfig<M extends AdapterModel = AdapterModel> = Omit<FrameworkScalarFieldConfig<M>, "type" | "nullable" | "list"> & {
|
|
24
16
|
readonly type: FrameworkScalarTypeRef<M>;
|
|
25
17
|
readonly nullable: boolean;
|
|
26
18
|
readonly list: boolean;
|
|
27
19
|
};
|
|
28
|
-
/**
|
|
29
|
-
* The shape one authored field name admits, by what the adapter knows of it.
|
|
30
|
-
*
|
|
31
|
-
* Where there is no discovered key set to discriminate on, the answer is today's
|
|
32
|
-
* undivided {@link FrameworkScalarFieldConfig}.
|
|
33
|
-
*/
|
|
20
|
+
/** The shape one authored field name admits, by what the adapter knows of it. */
|
|
34
21
|
type ScalarFieldConfigFor<M extends AdapterModel, R extends FrameworkResourceKey<M>, F> = string extends AdapterFieldKey<M, R> ? FrameworkScalarFieldConfig<M> : F extends AdapterFieldKey<M, R> ? M["resources"][R]["fields"][F] extends {
|
|
35
22
|
readonly kind: "relation";
|
|
36
23
|
} ? never : KnownScalarFieldConfig<M> : AddedScalarFieldConfig<M>;
|
|
37
|
-
/**
|
|
38
|
-
* The constraint an authored `fields` block is checked against, keyed on the
|
|
39
|
-
* block's **own** names.
|
|
40
|
-
*
|
|
41
|
-
* `Self` is the literal being checked, which is why {@link defineFields} is
|
|
42
|
-
* F-bounded: a `satisfies FrameworkFieldsConfig<M>` annotation maps the
|
|
43
|
-
* value shape over an open key set, which collapses to a single index
|
|
44
|
-
* signature, and an index signature cannot tell a discovered name from an
|
|
45
|
-
* added one. The three buckets are only reachable from a mapped type keyed
|
|
46
|
-
* on `keyof Self`.
|
|
47
|
-
*
|
|
48
|
-
* The self-reference is legal here despite the workstream's stopping rule 3
|
|
49
|
-
* because the `fields` block carries no callbacks: nothing inside it needs
|
|
50
|
-
* contextual typing, so there is no inference to collapse. A callback
|
|
51
|
-
* appearing in this block is the signal that this encoding has stopped
|
|
52
|
-
* being safe.
|
|
53
|
-
*/
|
|
24
|
+
/** The shape an authored `fields` block is checked against, keyed on its own names. */
|
|
54
25
|
export type FrameworkFieldsShape<M extends AdapterModel, Self> = {
|
|
55
26
|
readonly [R in keyof Self]: R extends FrameworkResourceKey<M> ? {
|
|
56
27
|
readonly [F in keyof Self[R]]: ScalarFieldConfigFor<M, R, F>;
|
|
@@ -59,17 +30,6 @@ export type FrameworkFieldsShape<M extends AdapterModel, Self> = {
|
|
|
59
30
|
/**
|
|
60
31
|
* Authors stage 1 of a configuration: the `fields` block, checked against
|
|
61
32
|
* what the adapter discovered and returned unwidened.
|
|
62
|
-
*
|
|
63
|
-
* The returned literal is stage 2's `Cfg` fields block, so the names it adds
|
|
64
|
-
* are nameable from `restrictions`, `behaviors` and `dependsOn`.
|
|
65
|
-
*
|
|
66
|
-
* `M` is bound by the **model value**, not a type argument: TypeScript has
|
|
67
|
-
* no partial type-argument inference, so `defineFields<M>({ … })` would
|
|
68
|
-
* force `Self` to be written out by hand. The model is already a value at
|
|
69
|
-
* the authoring site, so binding it there costs nothing.
|
|
70
|
-
*
|
|
71
|
-
* The model argument is type-level only — the returned block is the authored
|
|
72
|
-
* one, unchanged.
|
|
73
33
|
*/
|
|
74
34
|
export declare function defineFields<M extends AdapterModel, const Self extends FrameworkFieldsShape<M, Self>>(_model: M, fields: Self): Self;
|
|
75
35
|
export {};
|
|
@@ -13,41 +13,18 @@ import type { FrameworkResourceKey } from "./framework-fields-config.js";
|
|
|
13
13
|
type FieldsBlockOf<Layer> = Layer extends {
|
|
14
14
|
readonly fields?: infer Block;
|
|
15
15
|
} ? Block extends AnyFieldsBlock ? Block : never : never;
|
|
16
|
-
/**
|
|
17
|
-
* The field names a single `fields` block declares for `R`.
|
|
18
|
-
*
|
|
19
|
-
* The `[Block] extends [never]` guard is load-bearing, not defensive: `keyof
|
|
20
|
-
* never` is `string | number | symbol`, so a layer with no `fields` block
|
|
21
|
-
* would otherwise widen the whole effective key set back to `string` and
|
|
22
|
-
* silently erase every narrowing downstream of it.
|
|
23
|
-
*/
|
|
16
|
+
/** The field names a single `fields` block declares for `R`. */
|
|
24
17
|
type FieldsBlockKey<Block, R extends string> = [Block] extends [never] ? never : R extends keyof Block ? Extract<keyof NonNullable<Block[R]>, string> : never;
|
|
25
|
-
/**
|
|
26
|
-
* The field names `Cfg`'s own root `fields` block adds for `R`.
|
|
27
|
-
*
|
|
28
|
-
* Under the default `Cfg` this degenerates to `string`: `AnyFieldsBlock` maps
|
|
29
|
-
* every resource name to an open record, so the effective key set widens back to
|
|
30
|
-
* an index-signature-compatible `string` and today's wide acceptance is preserved.
|
|
31
|
-
*/
|
|
18
|
+
/** The field names the configuration's root `fields` block adds to Resource `R`. */
|
|
32
19
|
export type ConfigFieldKey<M extends AdapterModel, Cfg, R extends FrameworkResourceKey<M>> = FieldsBlockKey<FieldsBlockOf<Cfg>, R>;
|
|
33
|
-
/**
|
|
34
|
-
* The single answer to "what are `R`'s field names under this configuration".
|
|
35
|
-
*
|
|
36
|
-
* Nothing else in the framework may compute a field-key set; `restrictions`,
|
|
37
|
-
* `behaviors` and `dependsOn` all key on this type.
|
|
38
|
-
*
|
|
39
|
-
* There is deliberately no subtraction here. A `HiddenFieldKey` subtraction would
|
|
40
|
-
* contradict the Accepted ADR and must not be reintroduced.
|
|
41
|
-
*/
|
|
20
|
+
/** The single answer to "what are `R`'s field names under this configuration". */
|
|
42
21
|
export type EffectiveFieldKey<M extends AdapterModel, Cfg, R extends FrameworkResourceKey<M>> = AdapterFieldKey<M, R> | ConfigFieldKey<M, Cfg, R>;
|
|
43
22
|
/** The overlay `Cfg` carries for `Origin`, or `never` when it declares none. */
|
|
44
23
|
type OriginOverlayOf<Cfg, Origin extends RequestOrigin> = Origin extends keyof Cfg ? NonNullable<Cfg[Origin]> : never;
|
|
45
24
|
/**
|
|
46
|
-
* `R`'s
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Origins are siblings, never parents: an overlay contributes to its own origin
|
|
50
|
-
* only, so a name added under `client` is not visible under `application`.
|
|
25
|
+
* `R`'s field names as seen from one request origin: the root layer plus
|
|
26
|
+
* whatever the `application` or `client` overlay adds. A name added under
|
|
27
|
+
* `client` is not visible under `application`, and the other way round.
|
|
51
28
|
*/
|
|
52
29
|
export type EffectiveFieldKeyAt<M extends AdapterModel, Cfg, R extends FrameworkResourceKey<M>, Origin extends RequestOrigin> = EffectiveFieldKey<M, Cfg, R> | FieldsBlockKey<FieldsBlockOf<OriginOverlayOf<Cfg, Origin>>, R>;
|
|
53
30
|
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The framework entrypoint's mount path, in its one canonical form: `""` at the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* The framework entrypoint's mount path, in its one canonical form: `""` at the root,
|
|
3
|
+
* otherwise `/seg(/seg)*` — one leading slash, no trailing slash, no empty segment.
|
|
4
|
+
* Root is the empty string, not `"/"`, so a route joins onto it by concatenation with
|
|
5
|
+
* no special case.
|
|
6
6
|
*/
|
|
7
7
|
export type EntrypointPath = "" | `/${string}`;
|
|
8
8
|
/**
|
|
@@ -26,19 +26,7 @@ export type EntrypointNormalization = {
|
|
|
26
26
|
readonly message: string;
|
|
27
27
|
};
|
|
28
28
|
/**
|
|
29
|
-
* `AvProtocol.normalizeEntrypoint` — a mount path, as written, to its canonical
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* The one source of the rule: config resolution stores the canonical form as
|
|
33
|
-
* `framework.entrypoint`, config validation turns a refusal into a `CONFIG_`
|
|
34
|
-
* diagnostic, and the client generator's `resolveEntrypoint` hands it the mount
|
|
35
|
-
* path of the URL it is given — as written, before a URL parser has trimmed,
|
|
36
|
-
* resolved or percent-encoded anything. Execution code reads it from here;
|
|
37
|
-
* `@aventara/core/protocol` re-exports it, and the main entry does not.
|
|
38
|
-
*
|
|
39
|
-
* Checked in order, so each value has one reason: whitespace, a scheme (`://`), a
|
|
40
|
-
* query, a fragment, a `..` or `.` segment (either separator, `%2e` spelling
|
|
41
|
-
* included), a backslash, a non-ASCII character, a `%`, and finally any other
|
|
42
|
-
* character outside RFC 3986's `pchar`.
|
|
29
|
+
* `AvProtocol.normalizeEntrypoint` — a mount path, as written, to its canonical form
|
|
30
|
+
* or a refusal.
|
|
43
31
|
*/
|
|
44
32
|
export declare function normalizeEntrypoint(value: string): EntrypointNormalization;
|
|
@@ -3,27 +3,28 @@ import type { ComputedReadBehavior, ComputeOnCreate, ComputeOnUpdate } from "../
|
|
|
3
3
|
import type { AnyFrameworkConfig } from "./any-framework-config.js";
|
|
4
4
|
import type { EffectiveFieldKey } from "./effective-fields.js";
|
|
5
5
|
import type { FrameworkResourceKey } from "./framework-fields-config.js";
|
|
6
|
+
/** A read behavior: a compute function, or one declaring the fields it reads. */
|
|
6
7
|
export type FrameworkReadBehavior<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig, R extends FrameworkResourceKey<M> = FrameworkResourceKey<M>> = ComputedReadBehavior<M, Cfg, R>;
|
|
8
|
+
/**
|
|
9
|
+
* A field's behaviors: a value computed on create, on update, or on read.
|
|
10
|
+
* `false` turns off a behavior set at an outer layer.
|
|
11
|
+
*/
|
|
7
12
|
export type FrameworkFieldBehaviorConfig<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig, R extends FrameworkResourceKey<M> = FrameworkResourceKey<M>> = {
|
|
13
|
+
/** Computes the field's value when a row is created. */
|
|
8
14
|
readonly create?: false | ComputeOnCreate<M, Cfg, R>;
|
|
15
|
+
/** Computes the field's value when a row is updated. */
|
|
9
16
|
readonly update?: false | ComputeOnUpdate<M, Cfg, R>;
|
|
17
|
+
/** Computes the field's value when a row is read. */
|
|
10
18
|
readonly read?: false | FrameworkReadBehavior<M, Cfg, R>;
|
|
11
19
|
};
|
|
12
|
-
/**
|
|
13
|
-
* Executable behavior bindings for one Resource, keyed on the single effective
|
|
14
|
-
* field-key answer.
|
|
15
|
-
*
|
|
16
|
-
* `Partial` is required, not cosmetic: a mapped type over a literal key set would
|
|
17
|
-
* otherwise demand a binding for every field of the Resource. Under the default
|
|
18
|
-
* `Cfg` the key set is `string`, the mapped half collapses to one index signature
|
|
19
|
-
* and today's wide acceptance is preserved.
|
|
20
|
-
*/
|
|
20
|
+
/** Behaviors for one Resource's fields. */
|
|
21
21
|
export type FrameworkResourceBehaviorsConfig<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig, R extends FrameworkResourceKey<M> = FrameworkResourceKey<M>> = {
|
|
22
|
+
/** Behaviors per field name. */
|
|
22
23
|
readonly fields: Readonly<Partial<{
|
|
23
24
|
[F in EffectiveFieldKey<M, Cfg, R>]: FrameworkFieldBehaviorConfig<M, Cfg, R>;
|
|
24
25
|
}>>;
|
|
25
26
|
};
|
|
26
|
-
/**
|
|
27
|
+
/** Server-side behaviors, per Resource. */
|
|
27
28
|
export type FrameworkBehaviorsConfig<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig> = Readonly<Partial<{
|
|
28
29
|
[R in FrameworkResourceKey<M>]: FrameworkResourceBehaviorsConfig<M, Cfg, R>;
|
|
29
30
|
}>>;
|