@aventara/core 0.1.0-pilot.3 → 1.0.0-rc.0
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 +338 -0
- package/README.md +100 -3
- 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 +12 -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 +25 -26
- package/dist/compiler/contract-compiler-diagnostic.d.ts +8 -0
- package/dist/compiler/contract.compiler.d.ts +11 -22
- package/dist/compiler/contract.compiler.js +67 -0
- 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 +9 -14
- package/dist/config/config.resolver.js +1 -0
- package/dist/config/config.validator.d.ts +6 -3
- package/dist/config/config.validator.js +6 -0
- package/dist/config/define-fields.d.ts +15 -48
- 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 +19 -16
- package/dist/config/framework-fields-config.d.ts +20 -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 +28 -54
- package/dist/contracts/client-contract-structure.validator.js +99 -2
- package/dist/contracts/contract-canonicalizer.d.ts +4 -6
- package/dist/contracts/contract-canonicalizer.js +32 -0
- 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 +20 -4
- package/dist/contracts/enum-definition.d.ts +2 -0
- package/dist/contracts/field.d.ts +40 -167
- package/dist/contracts/identifier.d.ts +1 -16
- package/dist/contracts/json-shape.d.ts +65 -0
- package/dist/contracts/json-shape.js +1 -0
- package/dist/contracts/lifecycle-trait.d.ts +4 -3
- package/dist/contracts/reference-write-limit.d.ts +7 -0
- package/dist/contracts/reference-write-limit.js +1 -0
- 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 +28 -48
- 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 +152 -130
- package/dist/framework/framework-construction.error.d.ts +6 -1
- package/dist/framework/framework.d.ts +33 -46
- package/dist/framework/framework.factory.d.ts +3 -17
- package/dist/framework/framework.factory.js +56 -13
- package/dist/framework/operation-facade.d.ts +3 -7
- package/dist/index.d.ts +8 -40
- package/dist/index.js +0 -20
- package/dist/internal.d.ts +35 -0
- package/dist/internal.js +16 -0
- package/dist/json/avz.d.ts +96 -0
- package/dist/json/avz.js +212 -0
- package/dist/json/index.d.ts +6 -0
- package/dist/json/index.js +1 -0
- package/dist/json/json-shape.registry.d.ts +22 -0
- package/dist/json/json-shape.registry.js +16 -0
- package/dist/json/zod-issue.translator.d.ts +51 -0
- package/dist/json/zod-issue.translator.js +142 -0
- package/dist/operations/operation-arguments.d.ts +198 -303
- package/dist/operations/operation-call.d.ts +13 -15
- package/dist/operations/operation-identity.d.ts +6 -2
- package/dist/operations/operation-identity.js +3 -0
- package/dist/operations/operation-result.d.ts +15 -61
- package/dist/operations/operation-validator-core.d.ts +6 -5
- package/dist/operations/operation-validator-core.js +28 -10
- package/dist/operations/operation-validator.d.ts +22 -9
- package/dist/operations/operation-validator.js +26 -10
- package/dist/operations/projection-scope.resolver.d.ts +1 -11
- package/dist/operations/structural-limits.walker.d.ts +19 -0
- package/dist/operations/structural-limits.walker.js +344 -0
- 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 +25 -39
- package/dist/protocol/absent-route.responder.js +32 -6
- 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 +18 -59
- package/dist/protocol/http-request.decoder.js +11 -3
- 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 +19 -27
- package/dist/protocol/protocol.binder.js +3 -1
- package/dist/protocol/protocol.handler.d.ts +19 -23
- package/dist/protocol/protocol.handler.js +14 -4
- package/dist/protocol/unmounted-route.error.d.ts +19 -0
- package/dist/protocol/unmounted-route.error.js +10 -0
- package/dist/runtime/caller-data.copier.d.ts +59 -0
- package/dist/runtime/caller-data.copier.js +470 -0
- package/dist/runtime/caller-data.door.d.ts +56 -0
- package/dist/runtime/caller-data.door.js +65 -0
- package/dist/runtime/computed-read-runtime.js +3 -10
- package/dist/runtime/computed-value.error.d.ts +13 -0
- package/dist/runtime/computed-value.error.js +9 -0
- package/dist/runtime/create-requirement.d.ts +43 -7
- package/dist/runtime/create-requirement.js +89 -9
- package/dist/runtime/decimal.d.ts +5 -3
- package/dist/runtime/diagnostics-reporter.d.ts +33 -37
- package/dist/runtime/diagnostics-reporter.js +11 -4
- package/dist/runtime/error-boundary.d.ts +14 -10
- package/dist/runtime/error-boundary.js +65 -35
- package/dist/runtime/execution-options.d.ts +3 -7
- package/dist/runtime/field-behavior.d.ts +14 -21
- package/dist/runtime/framework-error.d.ts +14 -2
- package/dist/runtime/json-value.d.ts +7 -15
- package/dist/runtime/misuse-reporter.d.ts +32 -0
- package/dist/runtime/misuse-reporter.js +19 -0
- package/dist/runtime/mutation-planner.d.ts +6 -12
- package/dist/runtime/mutation-planner.js +13 -11
- package/dist/runtime/operation-request.d.ts +11 -11
- package/dist/runtime/operation-response.d.ts +18 -23
- package/dist/runtime/operation-runtime.d.ts +25 -33
- package/dist/runtime/operation-runtime.js +37 -18
- package/dist/runtime/outcome-mapper.js +12 -2
- package/dist/runtime/output-validator.d.ts +10 -0
- package/dist/runtime/output-validator.js +11 -0
- package/dist/runtime/owned-execution.registry.d.ts +13 -0
- package/dist/runtime/owned-execution.registry.js +7 -0
- package/dist/runtime/pipeline.d.ts +33 -36
- package/dist/runtime/referential-action.d.ts +8 -26
- package/dist/runtime/request-envelope.validator.d.ts +5 -0
- package/dist/runtime/request-envelope.validator.js +118 -0
- package/dist/runtime/request-id.d.ts +3 -10
- package/dist/runtime/scalar-runtime.d.ts +42 -14
- package/dist/runtime/scalar-runtime.js +162 -79
- 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 +6 -1
- package/dist/transactions/transaction-plan-assembler.js +74 -75
- package/dist/transactions/transaction-plan-validator.d.ts +33 -24
- package/dist/transactions/transaction-plan-validator.js +204 -153
- package/dist/transactions/transaction-reference-collector.d.ts +30 -0
- package/dist/transactions/transaction-reference-collector.js +204 -0
- package/dist/transactions/transaction-reference-resolver.d.ts +9 -12
- package/dist/transactions/transaction-reference-resolver.js +10 -5
- package/dist/transactions/transaction-reference-validator.js +24 -17
- package/dist/transactions/transaction-reference.d.ts +31 -64
- package/dist/transactions/transaction-request.d.ts +6 -8
- package/dist/transactions/transaction-response.d.ts +10 -7
- package/dist/transactions/transaction-response.js +24 -1
- package/dist/transactions/transaction-runtime.d.ts +7 -5
- package/dist/transactions/transaction-runtime.js +4 -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 +17 -3
- package/dist/operations/operation-boolean-nodes.d.ts +0 -11
- package/dist/operations/operation-boolean-nodes.js +0 -283
- package/dist/operations/operation-nesting.d.ts +0 -8
- package/dist/operations/operation-nesting.js +0 -307
|
@@ -13,12 +13,7 @@ type SelectOf<Args> = Args extends {
|
|
|
13
13
|
type IncludeOf<Args> = Args extends {
|
|
14
14
|
readonly include?: infer Include;
|
|
15
15
|
} ? Exclude<Include, undefined> : never;
|
|
16
|
-
/**
|
|
17
|
-
* The projection argument, held apart so the caller's literal is inferred and
|
|
18
|
-
* nothing else is: only `select`/`include` drive the result, and every other
|
|
19
|
-
* argument stays a plain declared type, which keeps its contextual typing and its
|
|
20
|
-
* excess-property check.
|
|
21
|
-
*/
|
|
16
|
+
/** The projection argument (`select`/`include`) of a call, which decides its result type. */
|
|
22
17
|
type ProjectionArgument<Select, Include> = {
|
|
23
18
|
readonly select?: Select;
|
|
24
19
|
readonly include?: never;
|
|
@@ -37,10 +32,8 @@ type ArgumentList<Rest, Parameter> = Record<never, never> extends Rest ? [args?:
|
|
|
37
32
|
type CallArgumentList<Rest, Parameter, Options> = Record<never, never> extends Rest ? [args?: Parameter, options?: Options] : [args: Parameter, options?: Options];
|
|
38
33
|
type ResourceOperationsOf<C extends Contract, R extends ResourceKey<C>> = C["resources"][R]["operations"];
|
|
39
34
|
/**
|
|
40
|
-
* The
|
|
41
|
-
*
|
|
42
|
-
* The one source every surface maps its calls over, so which operations exist is
|
|
43
|
-
* decided once.
|
|
35
|
+
* The operations Contract `C` advertises: one property per Resource, one per
|
|
36
|
+
* family under it, one identity per variant under that.
|
|
44
37
|
*/
|
|
45
38
|
export type OperationGrammar<C extends Contract> = {
|
|
46
39
|
readonly [R in ResourceKey<C>]: {
|
|
@@ -53,9 +46,9 @@ export type OperationGrammar<C extends Contract> = {
|
|
|
53
46
|
};
|
|
54
47
|
};
|
|
55
48
|
/**
|
|
56
|
-
* An operation's slot: its result, except that a first-style miss
|
|
57
|
-
*
|
|
58
|
-
*
|
|
49
|
+
* An operation's slot: its result, except that a first-style miss is `null`.
|
|
50
|
+
* This is the value a committed transaction or a remote call returns for the
|
|
51
|
+
* operation.
|
|
59
52
|
*/
|
|
60
53
|
export type OperationSlot<I extends OperationIdentity, Result> = I["variant"] extends "first" ? Result | null : Result;
|
|
61
54
|
/**
|
|
@@ -72,13 +65,18 @@ type PlainCall<C extends Contract, R extends ResourceKey<C>, I extends Operation
|
|
|
72
65
|
* projection when it carries one.
|
|
73
66
|
*/
|
|
74
67
|
export type OperationCall<C extends Contract, R extends ResourceKey<C>, I extends OperationIdentity, Forms extends ScalarForms, ResultForms extends ScalarForms, Settlement extends "response" | "data", Options> = "select" extends keyof OperationArgumentsFor<C, R, I, Forms> ? ProjectingCall<C, R, I, OperationArgumentsFor<C, R, I, Forms>, ResultForms, Settlement, Options> : PlainCall<C, R, I, OperationArgumentsFor<C, R, I, Forms>, ResultForms, Settlement, Options>;
|
|
68
|
+
/**
|
|
69
|
+
* A deferred operation's arguments: `Forms`, with reference positions opened to a
|
|
70
|
+
* `$ref` typed in `ResultForms` — the forms the source's final data is read in, so a
|
|
71
|
+
* reference carries what its source resolves.
|
|
72
|
+
*/
|
|
75
73
|
type DeferredArguments<C extends Contract, R extends ResourceKey<C>, I extends OperationIdentity, Forms extends ScalarForms, ResultForms extends ScalarForms> = ReferenceableArgumentsFor<C, R, I, Forms, ResultForms>;
|
|
76
74
|
type DeferredProjectingCall<C extends Contract, R extends ResourceKey<C>, I extends OperationIdentity, Args, ResultForms extends ScalarForms> = <const Select extends SelectOf<Args> = never, const Include extends IncludeOf<Args> = never>(...args: ArgumentList<Omit<Args, ProjectionKey>, Omit<Args, ProjectionKey> & ProjectionArgument<Select, Include>>) => Operation<OperationSlot<I, AdmittedOperationResult<C, R, I, InferredProjection<Select, Include>, ResultForms>>>;
|
|
77
75
|
type DeferredPlainCall<C extends Contract, R extends ResourceKey<C>, I extends OperationIdentity, Args, ResultForms extends ScalarForms> = (...args: ArgumentList<Args, Args>) => Operation<OperationSlot<I, AdmittedOperationResult<C, R, I, unknown, ResultForms>>>;
|
|
78
76
|
/**
|
|
79
77
|
* One deferred operation: a handle typed `Operation<OperationSlot<…>>` — `$ref`
|
|
80
|
-
* present exactly where the result is one row. A handle is not a request and takes
|
|
81
|
-
*
|
|
78
|
+
* present exactly where the result is one row. A handle is not a request and takes no
|
|
79
|
+
* options.
|
|
82
80
|
*/
|
|
83
81
|
export type DeferredOperationCall<C extends Contract, R extends ResourceKey<C>, I extends OperationIdentity, Forms extends ScalarForms, ResultForms extends ScalarForms> = "select" extends keyof DeferredArguments<C, R, I, Forms, ResultForms> ? DeferredProjectingCall<C, R, I, DeferredArguments<C, R, I, Forms, ResultForms>, ResultForms> : DeferredPlainCall<C, R, I, DeferredArguments<C, R, I, Forms, ResultForms>, ResultForms>;
|
|
84
82
|
export {};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ResourceOperations } from "../contracts/resource-operations.js";
|
|
2
|
+
/** A standard operation family: `find`, `create`, `update`, `delete` or `upsert`. */
|
|
2
3
|
export type OperationFamily = Extract<keyof ResourceOperations, string>;
|
|
4
|
+
/** The variants of operation family `F`, such as `many` or `unique`. */
|
|
3
5
|
export type OperationVariant<F extends OperationFamily> = Extract<keyof NonNullable<ResourceOperations[F]>, string>;
|
|
4
|
-
/**
|
|
6
|
+
/** A standard operation's `family` and `variant`. */
|
|
5
7
|
export type OperationIdentity = {
|
|
6
8
|
[F in OperationFamily]: {
|
|
7
9
|
[V in OperationVariant<F>]: {
|
|
@@ -10,5 +12,7 @@ export type OperationIdentity = {
|
|
|
10
12
|
};
|
|
11
13
|
}[OperationVariant<F>];
|
|
12
14
|
}[OperationFamily];
|
|
13
|
-
/** Parses
|
|
15
|
+
/** Parses a family and variant into an {@link OperationIdentity}, or `undefined` when they name no standard operation. */
|
|
14
16
|
export declare function parseOperationIdentity(family: string, variant: string): OperationIdentity | undefined;
|
|
17
|
+
/** Whether `family` names one of the standard operation families. */
|
|
18
|
+
export declare function isOperationFamily(family: string): boolean;
|
|
@@ -5,11 +5,8 @@ import type { FieldKey, OperationArgumentsFor, ResourceKey } from "./operation-a
|
|
|
5
5
|
import type { OperationIdentity } from "./operation-identity.js";
|
|
6
6
|
type FieldOf<C extends Contract, K extends ResourceKey<C>, F extends FieldKey<C, K>> = C["resources"][K]["fields"][F];
|
|
7
7
|
/**
|
|
8
|
-
* The
|
|
9
|
-
*
|
|
10
|
-
* Strict, as the runtime is: an absent member, `false`, and a member the Contract
|
|
11
|
-
* widened to `boolean` are all left out, so a write-only field never appears and a
|
|
12
|
-
* widened Contract under-promises rather than over-promises.
|
|
8
|
+
* The fields returned when no projection is given: the scalars whose `select`
|
|
9
|
+
* is exactly `true`. A write-only field never appears.
|
|
13
10
|
*/
|
|
14
11
|
type DefaultKey<C extends Contract, K extends ResourceKey<C>> = {
|
|
15
12
|
[F in FieldKey<C, K>]: FieldOf<C, K, F> extends {
|
|
@@ -19,16 +16,11 @@ type DefaultKey<C extends Contract, K extends ResourceKey<C>> = {
|
|
|
19
16
|
};
|
|
20
17
|
} ? F : never;
|
|
21
18
|
}[FieldKey<C, K>];
|
|
22
|
-
/**
|
|
23
|
-
* The field one projection entry names: a bare key, or a relation entry's key.
|
|
24
|
-
* `$count` passes through and is dropped where every caller intersects the result
|
|
25
|
-
* with the Resource's field keys, which is the one place that knows what a field is.
|
|
26
|
-
*/
|
|
19
|
+
/** The field one projection entry names: a bare key, or a relation entry's key. */
|
|
27
20
|
type EntryKey<Entry> = Entry extends string ? Entry : Entry extends object ? Extract<keyof Entry, string> : never;
|
|
28
21
|
/**
|
|
29
22
|
* The argument object a relation entry carries for field `F`, or `never` when
|
|
30
|
-
* the relation is only named.
|
|
31
|
-
* matching its own apparent members (`"length"` would otherwise).
|
|
23
|
+
* the relation is only named.
|
|
32
24
|
*/
|
|
33
25
|
type EntryArguments<Entry, F extends string> = Entry extends object ? Entry extends {
|
|
34
26
|
readonly [Key in F]: infer Arguments;
|
|
@@ -43,12 +35,8 @@ type ProjectedFields<C extends Contract, K extends ResourceKey<C>, Keys extends
|
|
|
43
35
|
readonly [F in Keys]: FieldOf<C, K, F> extends ScalarField<C> ? ScalarValueType<C, FieldOf<C, K, F>, Forms> : FieldOf<C, K, F> extends RelationField<C> ? RelationResult<C, Extract<FieldOf<C, K, F>["target"], ResourceKey<C>>, FieldOf<C, K, F>, EntryArguments<Entries, F>, Forms> : never;
|
|
44
36
|
};
|
|
45
37
|
/**
|
|
46
|
-
* One projection level: `select`
|
|
47
|
-
* plus the named relations, and
|
|
48
|
-
*
|
|
49
|
-
* An absent argument (`never`, from {@link EntryArguments}) is tested first and
|
|
50
|
-
* explicitly: it would otherwise distribute to `never`, and inside a one-tuple it
|
|
51
|
-
* would match the `select` arm, because `never` extends everything.
|
|
38
|
+
* One projection level: `select` returns exactly its entries, `include` the
|
|
39
|
+
* default fields plus the named relations, and no projection the default fields.
|
|
52
40
|
*/
|
|
53
41
|
type ProjectedRecord<C extends Contract, K extends ResourceKey<C>, Arguments, Forms extends ScalarForms> = [Arguments] extends [never] ? ProjectedFields<C, K, DefaultKey<C, K>, never, Forms> : [Arguments] extends [{
|
|
54
42
|
readonly select: readonly (infer Entry)[];
|
|
@@ -56,10 +44,8 @@ type ProjectedRecord<C extends Contract, K extends ResourceKey<C>, Arguments, Fo
|
|
|
56
44
|
readonly include: readonly (infer Entry)[];
|
|
57
45
|
}] ? ProjectedFields<C, K, DefaultKey<C, K> | Extract<EntryKey<Entry>, FieldKey<C, K>>, Entry, Forms> : ProjectedFields<C, K, DefaultKey<C, K>, never, Forms>;
|
|
58
46
|
/**
|
|
59
|
-
* A to-many entry whose `select` asks for `$count`: the
|
|
60
|
-
*
|
|
61
|
-
* the row fields are separated here because they are separate facts — the rows
|
|
62
|
-
* are the target's projection, the count is the parent's reducer.
|
|
47
|
+
* A to-many entry whose `select` asks for `$count`: the value is an object with
|
|
48
|
+
* the rows and the count, not the row array.
|
|
63
49
|
*/
|
|
64
50
|
type CountEnvelope<C extends Contract, Target extends ResourceKey<C>, Entry, Forms extends ScalarForms> = [Exclude<Entry, "$count">] extends [never] ? {
|
|
65
51
|
readonly count: number;
|
|
@@ -67,56 +53,24 @@ type CountEnvelope<C extends Contract, Target extends ResourceKey<C>, Entry, For
|
|
|
67
53
|
readonly data: readonly ProjectedFields<C, Target, Extract<EntryKey<Entry>, FieldKey<C, Target>>, Exclude<Entry, "$count">, Forms>[];
|
|
68
54
|
readonly count: number;
|
|
69
55
|
};
|
|
70
|
-
/**
|
|
71
|
-
* The entries of an argument's own `select`, or `never` when it has none.
|
|
72
|
-
* Distributive on purpose: an absent argument (`never`) has no entries.
|
|
73
|
-
*/
|
|
56
|
+
/** The entries of an argument's own `select`, or `never` when it has none. */
|
|
74
57
|
type SelectEntry<Arguments> = Arguments extends {
|
|
75
58
|
readonly select: readonly (infer Entry)[];
|
|
76
59
|
} ? Entry : never;
|
|
77
60
|
/**
|
|
78
|
-
* The value of one relation entry.
|
|
79
|
-
*
|
|
80
|
-
* The nested projection is the target's own, at every depth: a scope qualifies
|
|
81
|
-
* the top level of a projection only (`contracts/capability.ts`
|
|
82
|
-
* `ProjectionScope`), and the argument constraint on {@link OperationResultFor}
|
|
83
|
-
* has already admitted the entry at the position it sits in.
|
|
84
|
-
*
|
|
85
|
-
* A to-many entry is the envelope exactly when its own `select` carries `$count`;
|
|
86
|
-
* otherwise — no argument, `include`, or a `select` without the reducer — it is
|
|
87
|
-
* the row array.
|
|
61
|
+
* The value of one relation entry. A to-many entry is the rows-and-count object
|
|
62
|
+
* when its own `select` asks for `$count`; otherwise the row array.
|
|
88
63
|
*/
|
|
89
64
|
type RelationResult<C extends Contract, Target extends ResourceKey<C>, Relation extends RelationField<C>, Arguments, Forms extends ScalarForms> = Relation["cardinality"] extends "many" ? [Extract<SelectEntry<Arguments>, "$count">] extends [never] ? readonly ProjectedRecord<C, Target, Arguments, Forms>[] : CountEnvelope<C, Target, SelectEntry<Arguments>, Forms> : ProjectedRecord<C, Target, Arguments, Forms> | (true extends Relation["nullable"] ? null : never);
|
|
90
65
|
/**
|
|
91
66
|
* The value a standard operation returns in `OperationResponse.data` on success,
|
|
92
|
-
* derived from the Contract, the Resource, the operation identity and the
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* - `count` → `number`;
|
|
96
|
-
* - `many` → `readonly Record[]`;
|
|
97
|
-
* - `first`, `unique`, `one` → the record. **Not `| null`:** absence is an
|
|
98
|
-
* outcome, not a value — `A1001` answers `data: null` for a first-style miss and
|
|
99
|
-
* `A2003` refuses a strict unique one (`runtime/outcome-mapper.ts`
|
|
100
|
-
* `OUTCOME_TABLE`) — so folding `null` into the record would count it twice.
|
|
101
|
-
*
|
|
102
|
-
* `Args` is constrained to the operation's own argument type, so a projection
|
|
103
|
-
* entry the Contract does not advertise at that position — a write-only field, an
|
|
104
|
-
* unadvertised `$count`, a relation outside a bulk write's ceiling — is refused
|
|
105
|
-
* here instead of typed as present.
|
|
106
|
-
*
|
|
107
|
-
* `Forms` is the scalar-form map. It defaults to the application forms, which are
|
|
108
|
-
* what a framework-produced value is in either scope; a transport or a generated
|
|
109
|
-
* client passes the wire forms and gets the same derivation.
|
|
67
|
+
* derived from the Contract, the Resource, the operation identity and the projection
|
|
68
|
+
* argument.
|
|
110
69
|
*/
|
|
111
70
|
export type OperationResultFor<C extends Contract, K extends ResourceKey<C>, I extends OperationIdentity, Args extends OperationArgumentsFor<C, K, I>, Forms extends ScalarForms = ApplicationScalarForms> = AdmittedOperationResult<C, K, I, Args, Forms>;
|
|
112
71
|
/**
|
|
113
|
-
* {@link OperationResultFor}
|
|
114
|
-
*
|
|
115
|
-
* application façade, which constrains its inferred `select`/`include` at the
|
|
116
|
-
* call. It reads only the projection, so a caller holding just that need not
|
|
117
|
-
* compute the whole argument object a second time to satisfy the constraint.
|
|
118
|
-
*
|
|
119
|
-
* Not exported from the package: one public spelling of the result rule.
|
|
72
|
+
* {@link OperationResultFor}, for a projection already checked against the
|
|
73
|
+
* operation's argument type.
|
|
120
74
|
*/
|
|
121
75
|
export type AdmittedOperationResult<C extends Contract, K extends ResourceKey<C>, I extends OperationIdentity, Args, Forms extends ScalarForms = ApplicationScalarForms> = I["variant"] extends "count" ? number : I["variant"] extends "many" ? readonly ProjectedRecord<C, K, Args, Forms>[] : ProjectedRecord<C, K, Args, Forms>;
|
|
122
76
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Contract } from "../contracts/contract.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type OperationIdentity } from "./operation-identity.js";
|
|
3
3
|
import type { ValidationIssue } from "./validation-code.js";
|
|
4
|
+
/** An operation's arguments as an object, before validation. */
|
|
4
5
|
export type SemanticOperationArguments = Readonly<Record<string, unknown>>;
|
|
5
6
|
type OperationValidationSuccess = {
|
|
6
7
|
readonly ok: true;
|
|
@@ -10,15 +11,15 @@ type OperationValidationFailure = {
|
|
|
10
11
|
readonly ok: false;
|
|
11
12
|
readonly issues: readonly ValidationIssue[];
|
|
12
13
|
};
|
|
14
|
+
/** The answer of {@link validateOperationArguments}: success, or the issues found. */
|
|
13
15
|
export type OperationValidationResult = OperationValidationSuccess | OperationValidationFailure;
|
|
14
16
|
export type OperationValidationOptions = {
|
|
15
17
|
readonly transactionReferences?: boolean;
|
|
16
18
|
};
|
|
17
19
|
/**
|
|
18
|
-
* The Framework Validation Layer's issue for a request naming a Resource the
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* it.
|
|
20
|
+
* The Framework Validation Layer's issue for a request naming a Resource the active
|
|
21
|
+
* Contract does not have (`V1005` at `["resource"]`, rolling up to `A2001`). The one
|
|
22
|
+
* spelling — the protocol's absence answers build theirs with it.
|
|
22
23
|
*/
|
|
23
24
|
export declare function resourceUnavailableIssue(resource: string): ValidationIssue;
|
|
24
25
|
export declare function validateOperationArguments(contract: Contract, request: OperationIdentity & {
|
|
@@ -2,6 +2,7 @@ import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
|
2
2
|
import { advertisedDirectivesAt, advertisedReducers, advertisedReducersAt, holdsAt, } from "../contracts/field.js";
|
|
3
3
|
import { isPlainRecord } from "../runtime/scalar-runtime.js";
|
|
4
4
|
import { routeTransactionReferenceCandidate } from "../transactions/transaction-reference.js";
|
|
5
|
+
import { isOperationFamily, } from "./operation-identity.js";
|
|
5
6
|
import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
|
|
6
7
|
import { NESTED_WRITE_SCOPE, resolveWriteScope, } from "./write-scope.resolver.js";
|
|
7
8
|
const OPERATION_ARGUMENT_RULES = {
|
|
@@ -111,7 +112,7 @@ function validateTopLevelArguments(request, args) {
|
|
|
111
112
|
const rule = OPERATION_ARGUMENT_RULES[key];
|
|
112
113
|
const issues = [];
|
|
113
114
|
if (rule === undefined) {
|
|
114
|
-
addIssue(issues, "V1001", ["
|
|
115
|
+
addIssue(issues, "V1001", [isOperationFamily(request.family) ? "variant" : "family"], `Operation "${key}" is not part of the standard operation grammar.`);
|
|
115
116
|
return issues;
|
|
116
117
|
}
|
|
117
118
|
for (const required of rule.required) {
|
|
@@ -168,6 +169,13 @@ function validateScalarFilter(fieldName, field, value, path, state) {
|
|
|
168
169
|
}
|
|
169
170
|
return;
|
|
170
171
|
}
|
|
172
|
+
if (state.transactionReferences === true &&
|
|
173
|
+
routeTransactionReferenceCandidate(value).kind !== "ordinary") {
|
|
174
|
+
if (!includes(supported, "equals")) {
|
|
175
|
+
addIssue(state.issues, "V1006", path, `Equality filtering is not available on field "${fieldName}".`);
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
171
179
|
if (!isPlainRecord(value)) {
|
|
172
180
|
if (!includes(supported, "equals")) {
|
|
173
181
|
addIssue(state.issues, "V1006", path, `Equality filtering is not available on field "${fieldName}".`);
|
|
@@ -270,6 +278,9 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
|
270
278
|
if (field.kind === "scalar") {
|
|
271
279
|
validateScalarFilter(key, field, value, fieldPath, state);
|
|
272
280
|
}
|
|
281
|
+
else if (state.scalarOnly === true) {
|
|
282
|
+
addIssue(state.issues, "V1006", fieldPath, `Relation filter "${key}" is not available here: a nested $update or $delete filter on this relation takes scalar fields only.`);
|
|
283
|
+
}
|
|
273
284
|
else {
|
|
274
285
|
validateRelationFilter(contract, key, field, value, fieldPath, state, depth);
|
|
275
286
|
}
|
|
@@ -570,7 +581,7 @@ function validateScalarMutation(fieldName, field, value, stage, path, issues, tr
|
|
|
570
581
|
}
|
|
571
582
|
}
|
|
572
583
|
}
|
|
573
|
-
function validateRelationMutationEntry(contract, edge, directive, value, path, issues) {
|
|
584
|
+
function validateRelationMutationEntry(contract, edge, directive, value, path, issues, transactionReferences) {
|
|
574
585
|
const target = edge.target;
|
|
575
586
|
if (edge.cardinality === "one" && Array.isArray(value)) {
|
|
576
587
|
addIssue(issues, "V1012", path, `To-one relation directive "${directive}" does not accept arrays.`);
|
|
@@ -619,7 +630,7 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
619
630
|
if (directive === "$create") {
|
|
620
631
|
const entries = edge.cardinality === "many" && Array.isArray(value) ? value : [value];
|
|
621
632
|
for (const entry of entries) {
|
|
622
|
-
validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, path, issues);
|
|
633
|
+
validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, path, issues, transactionReferences);
|
|
623
634
|
}
|
|
624
635
|
return;
|
|
625
636
|
}
|
|
@@ -631,7 +642,7 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
631
642
|
continue;
|
|
632
643
|
}
|
|
633
644
|
validateUniqueSelector(contract, target, entry.where, [...path, "where"], issues);
|
|
634
|
-
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues);
|
|
645
|
+
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues, transactionReferences);
|
|
635
646
|
}
|
|
636
647
|
return;
|
|
637
648
|
}
|
|
@@ -650,13 +661,15 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
650
661
|
const state = {
|
|
651
662
|
issues,
|
|
652
663
|
structuralRoot: [...path, "where"],
|
|
664
|
+
transactionReferences,
|
|
665
|
+
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
653
666
|
booleanFilterNodes: 0,
|
|
654
667
|
nestingExceeded: false,
|
|
655
668
|
booleanNodesExceeded: false,
|
|
656
669
|
};
|
|
657
670
|
validateWhere(contract, target, entry.where, [...path, "where"], state, 1);
|
|
658
671
|
}
|
|
659
|
-
validateMutationData(contract, target, entry.data, "update", NESTED_WRITE_SCOPE, [...path, "data"], issues);
|
|
672
|
+
validateMutationData(contract, target, entry.data, "update", NESTED_WRITE_SCOPE, [...path, "data"], issues, transactionReferences);
|
|
660
673
|
}
|
|
661
674
|
return;
|
|
662
675
|
}
|
|
@@ -671,6 +684,8 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
671
684
|
const state = {
|
|
672
685
|
issues,
|
|
673
686
|
structuralRoot: [...path, "where"],
|
|
687
|
+
transactionReferences,
|
|
688
|
+
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
674
689
|
booleanFilterNodes: 0,
|
|
675
690
|
nestingExceeded: false,
|
|
676
691
|
booleanNodesExceeded: false,
|
|
@@ -685,6 +700,8 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
685
700
|
const state = {
|
|
686
701
|
issues,
|
|
687
702
|
structuralRoot: [...path, "where"],
|
|
703
|
+
transactionReferences,
|
|
704
|
+
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
688
705
|
booleanFilterNodes: 0,
|
|
689
706
|
nestingExceeded: false,
|
|
690
707
|
booleanNodesExceeded: false,
|
|
@@ -707,12 +724,12 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
707
724
|
if ("where" in entry) {
|
|
708
725
|
validateUniqueSelector(contract, target, entry.where, [...path, "where"], issues);
|
|
709
726
|
}
|
|
710
|
-
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues);
|
|
711
|
-
validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...path, "update"], issues);
|
|
727
|
+
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues, transactionReferences);
|
|
728
|
+
validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...path, "update"], issues, transactionReferences);
|
|
712
729
|
}
|
|
713
730
|
}
|
|
714
731
|
}
|
|
715
|
-
function validateRelationMutation(contract, fieldName, field, value, stage, scope, path, issues) {
|
|
732
|
+
function validateRelationMutation(contract, fieldName, field, value, stage, scope, path, issues, transactionReferences) {
|
|
716
733
|
const directives = advertisedDirectivesAt(field.capabilities[stage], scope);
|
|
717
734
|
if (directives === undefined) {
|
|
718
735
|
addIssue(issues, "V1006", path, `Relation "${fieldName}" is not writable during ${stage}.`);
|
|
@@ -728,7 +745,7 @@ function validateRelationMutation(contract, fieldName, field, value, stage, scop
|
|
|
728
745
|
addIssue(issues, "V1006", directivePath, `Relation mutation directive "${directive}" is not available on relation "${fieldName}".`);
|
|
729
746
|
continue;
|
|
730
747
|
}
|
|
731
|
-
validateRelationMutationEntry(contract, field, directive, directiveValue, directivePath, issues);
|
|
748
|
+
validateRelationMutationEntry(contract, field, directive, directiveValue, directivePath, issues, transactionReferences);
|
|
732
749
|
}
|
|
733
750
|
}
|
|
734
751
|
function validateMutationData(contract, resourceName, data, stage, scope, path, issues, transactionReferences = false) {
|
|
@@ -752,7 +769,7 @@ function validateMutationData(contract, resourceName, data, stage, scope, path,
|
|
|
752
769
|
validateScalarMutation(fieldName, field, value, stage, fieldPath, issues, transactionReferences);
|
|
753
770
|
}
|
|
754
771
|
else {
|
|
755
|
-
validateRelationMutation(contract, fieldName, field, value, stage, scope, fieldPath, issues);
|
|
772
|
+
validateRelationMutation(contract, fieldName, field, value, stage, scope, fieldPath, issues, transactionReferences);
|
|
756
773
|
}
|
|
757
774
|
}
|
|
758
775
|
}
|
|
@@ -830,6 +847,7 @@ export function validateOperationArguments(contract, request, options) {
|
|
|
830
847
|
const state = {
|
|
831
848
|
issues,
|
|
832
849
|
structuralRoot: ["arguments", "where"],
|
|
850
|
+
transactionReferences: options?.transactionReferences === true,
|
|
833
851
|
booleanFilterNodes: 0,
|
|
834
852
|
nestingExceeded: false,
|
|
835
853
|
booleanNodesExceeded: false,
|
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
import type { Contract } from "../contracts/contract.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type OperationIdentity } from "./operation-identity.js";
|
|
3
3
|
import { type OperationValidationOptions, type OperationValidationResult } from "./operation-validator-core.js";
|
|
4
4
|
import type { ValidationIssue } from "./validation-code.js";
|
|
5
5
|
export type { OperationValidationOptions, OperationValidationResult, SemanticOperationArguments, } from "./operation-validator-core.js";
|
|
6
|
+
/** The key of a request's operation identity that makes it unavailable. */
|
|
7
|
+
export declare function unavailableOperationKey(contract: Contract, request: {
|
|
8
|
+
readonly resource: string;
|
|
9
|
+
readonly family: string;
|
|
10
|
+
}): "family" | "variant";
|
|
6
11
|
/**
|
|
7
12
|
* The Framework Validation Layer's issue for a `(resource, family, variant)` the
|
|
8
|
-
* active Contract does not advertise on a Resource it has
|
|
9
|
-
* `
|
|
10
|
-
*
|
|
11
|
-
* answered.
|
|
13
|
+
* active Contract does not advertise on a Resource it has: `V1006`, rolling up to
|
|
14
|
+
* `A2002`, at the key that is wrong (`["family"]` or `["variant"]`, see
|
|
15
|
+
* {@link unavailableOperationKey}). The one spelling — the protocol's absence
|
|
16
|
+
* answers build theirs with it, so a caller cannot tell which layer answered.
|
|
12
17
|
*/
|
|
13
|
-
export declare function operationUnavailableIssue(request: {
|
|
18
|
+
export declare function operationUnavailableIssue(contract: Contract, request: {
|
|
14
19
|
readonly resource: string;
|
|
15
20
|
readonly family: string;
|
|
16
21
|
readonly variant: string;
|
|
17
22
|
}): ValidationIssue;
|
|
18
23
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
24
|
+
* The availability answer alone — `V1006` when the active Contract does not advertise
|
|
25
|
+
* the operation on a Resource it has — read from the request's identity, never its
|
|
26
|
+
* arguments. A door that refuses unreadable arguments asks this first, so an
|
|
27
|
+
* unadvertised operation answers `A2002` whatever its arguments hold.
|
|
28
|
+
*/
|
|
29
|
+
export declare function findOperationAvailabilityIssue(contract: Contract, request: OperationIdentity & {
|
|
30
|
+
readonly resource: string;
|
|
31
|
+
}): ValidationIssue | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Validates one standard operation's arguments against a Contract. Operation
|
|
34
|
+
* availability and request limits are checked before the arguments' grammar.
|
|
22
35
|
*/
|
|
23
36
|
export declare function validateOperationArguments(contract: Contract, request: OperationIdentity & {
|
|
24
37
|
readonly resource: string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { lookupOwn, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
2
|
import { isOperationVariantAvailable, } from "../contracts/resource-operations.js";
|
|
3
|
-
import {
|
|
4
|
-
import { findOperationNestingIssue } from "./operation-nesting.js";
|
|
3
|
+
import { isOperationFamily, } from "./operation-identity.js";
|
|
5
4
|
import { validateOperationArguments as validateSemanticOperationArguments, } from "./operation-validator-core.js";
|
|
5
|
+
import { findStructuralLimitIssues } from "./structural-limits.walker.js";
|
|
6
6
|
function isArgumentObject(value) {
|
|
7
7
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
8
|
}
|
|
@@ -15,13 +15,28 @@ function isOperationAvailable(contract, request) {
|
|
|
15
15
|
const family = lookupOwn(advertised, request.family);
|
|
16
16
|
return isOperationVariantAvailable(lookupOwn(family, request.variant));
|
|
17
17
|
}
|
|
18
|
-
export function
|
|
18
|
+
export function unavailableOperationKey(contract, request) {
|
|
19
|
+
if (!isOperationFamily(request.family)) {
|
|
20
|
+
return "family";
|
|
21
|
+
}
|
|
22
|
+
const variants = lookupOwn(lookupResource(contract, request.resource)?.operations, request.family);
|
|
23
|
+
return variants !== undefined &&
|
|
24
|
+
Object.keys(variants).some((variant) => isOperationVariantAvailable(lookupOwn(variants, variant)))
|
|
25
|
+
? "variant"
|
|
26
|
+
: "family";
|
|
27
|
+
}
|
|
28
|
+
export function operationUnavailableIssue(contract, request) {
|
|
19
29
|
return {
|
|
20
|
-
path: [
|
|
30
|
+
path: [unavailableOperationKey(contract, request)],
|
|
21
31
|
code: "V1006",
|
|
22
32
|
message: `Operation "${request.family}.${request.variant}" is not available on Resource "${request.resource}".`,
|
|
23
33
|
};
|
|
24
34
|
}
|
|
35
|
+
export function findOperationAvailabilityIssue(contract, request) {
|
|
36
|
+
return isOperationAvailable(contract, request)
|
|
37
|
+
? undefined
|
|
38
|
+
: operationUnavailableIssue(contract, request);
|
|
39
|
+
}
|
|
25
40
|
function hasGeneralRootWhere(request) {
|
|
26
41
|
if (!("where" in request.arguments)) {
|
|
27
42
|
return false;
|
|
@@ -33,15 +48,16 @@ function hasGeneralRootWhere(request) {
|
|
|
33
48
|
request.family === "upsert"));
|
|
34
49
|
}
|
|
35
50
|
export function validateOperationArguments(contract, request, options) {
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
const unavailable = findOperationAvailabilityIssue(contract, request);
|
|
52
|
+
if (unavailable !== undefined) {
|
|
53
|
+
return { ok: false, issues: [unavailable] };
|
|
38
54
|
}
|
|
39
55
|
if (isArgumentObject(request.arguments)) {
|
|
40
|
-
const
|
|
41
|
-
if (
|
|
42
|
-
return { ok: false, issues: [
|
|
56
|
+
const finding = findStructuralLimitIssues(contract, request, request.arguments);
|
|
57
|
+
if (finding.nesting !== undefined) {
|
|
58
|
+
return { ok: false, issues: [finding.nesting] };
|
|
43
59
|
}
|
|
44
|
-
const booleanNodeIssue =
|
|
60
|
+
const booleanNodeIssue = finding.booleanNodes;
|
|
45
61
|
if (booleanNodeIssue !== undefined) {
|
|
46
62
|
return {
|
|
47
63
|
ok: false,
|
|
@@ -7,7 +7,7 @@ import type { OperationIdentity } from "./operation-identity.js";
|
|
|
7
7
|
* in, read off the variant the Resource advertises.
|
|
8
8
|
*
|
|
9
9
|
* Two readers need the answer and they run one after the other over the same
|
|
10
|
-
* request — the `maxBooleanNodes`
|
|
10
|
+
* request — the `maxBooleanNodes` tally in `structural-limits.walker.ts`, then the
|
|
11
11
|
* grammar walk in `operation-validator-core.ts`. They must agree: a walk that
|
|
12
12
|
* resolved a wider scope than the validator would count nodes inside a projection
|
|
13
13
|
* the validator then refuses (harmless), and a walk that resolved a narrower one
|
|
@@ -25,15 +25,5 @@ export declare function resolveProjectionScope(resource: Resource<Contract> | un
|
|
|
25
25
|
/**
|
|
26
26
|
* The position a projection NESTED beneath an admitted relation sits in: the
|
|
27
27
|
* unrestricted one, at every depth, under every top-level scope.
|
|
28
|
-
*
|
|
29
|
-
* **Measured at runtime on both pilot engines, 2026-10-03** — not inferred from
|
|
30
|
-
* the types, which permit more than they accept. A bulk-returning write accepted
|
|
31
|
-
* `include: { <owned to-one>: { include: { <to-many>: true } } }` and populated
|
|
32
|
-
* the rows, while the same to-many asked for at the top level was refused
|
|
33
|
-
* outright. The generated types say why: a bulk projection types an admitted
|
|
34
|
-
* relation as the *unrestricted* projection argument, so the full surface returns
|
|
35
|
-
* one level in.
|
|
36
|
-
*
|
|
37
|
-
* Naming it is the point.
|
|
38
28
|
*/
|
|
39
29
|
export declare const NESTED_PROJECTION_SCOPE: ProjectionScope;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Contract } from "../contracts/contract.js";
|
|
2
|
+
import type { OperationIdentity } from "./operation-identity.js";
|
|
3
|
+
import type { ValidationIssue } from "./validation-code.js";
|
|
4
|
+
type Readable = Readonly<Record<string, unknown>>;
|
|
5
|
+
/** What one walk of an operation's arguments found. */
|
|
6
|
+
export type StructuralLimitsFinding = {
|
|
7
|
+
/** The nesting issue, which wins over any boolean-node issue. */
|
|
8
|
+
readonly nesting: ValidationIssue | undefined;
|
|
9
|
+
/** The boolean-node issue, when there is no nesting issue. */
|
|
10
|
+
readonly booleanNodes: ValidationIssue | undefined;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Enforces the structural limits on one operation's argument object: the nesting
|
|
14
|
+
* issue if there is one, otherwise the boolean-node issue if there is one.
|
|
15
|
+
*/
|
|
16
|
+
export declare function findStructuralLimitIssues(contract: Contract, request: OperationIdentity & {
|
|
17
|
+
readonly resource: string;
|
|
18
|
+
}, args: Readable): StructuralLimitsFinding;
|
|
19
|
+
export {};
|