@aventara/core 0.1.0-pilot.4 → 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 +1478 -0
- package/README.md +275 -11
- 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 +17 -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 -25
- 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/avz/avz.js +354 -0
- package/dist/avz/index.d.ts +7 -0
- package/dist/avz/index.js +1 -0
- package/dist/avz/json-shape.registry.d.ts +22 -0
- package/dist/avz/json-shape.registry.js +16 -0
- package/dist/avz/zod-issue.translator.d.ts +57 -0
- package/dist/avz/zod-issue.translator.js +149 -0
- package/dist/compiler/contract-compiler-diagnostic.d.ts +37 -5
- package/dist/compiler/contract.compiler.d.ts +18 -18
- package/dist/compiler/contract.compiler.js +595 -421
- 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 +75 -29
- package/dist/config/config.resolver.js +109 -44
- package/dist/config/config.validator.d.ts +7 -7
- package/dist/config/config.validator.js +586 -71
- 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 +111 -37
- 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 +344 -29
- package/dist/contracts/client-contract-structure.validator.js +248 -7
- package/dist/contracts/contract-canonicalizer.d.ts +19 -3
- package/dist/contracts/contract-canonicalizer.js +172 -27
- 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 +31 -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 +61 -41
- package/dist/contracts/identifier.d.ts +4 -4
- package/dist/contracts/json-shape.d.ts +76 -0
- package/dist/contracts/json-shape.js +1 -0
- package/dist/contracts/lifecycle-trait.d.ts +2 -2
- 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 +28 -28
- package/dist/contracts/resource.d.ts +15 -9
- package/dist/contracts/scalar-value-type.d.ts +25 -14
- 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 +234 -63
- 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 +50 -24
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +95 -32
- package/dist/framework/operation-facade.d.ts +123 -52
- package/dist/framework/operation-facade.js +9 -1
- package/dist/index.d.ts +55 -82
- package/dist/index.js +6 -26
- package/dist/internal.d.ts +40 -0
- package/dist/internal.js +18 -0
- package/dist/operations/operation-arguments.d.ts +316 -201
- package/dist/operations/operation-call.d.ts +27 -28
- package/dist/operations/operation-identity.d.ts +12 -10
- package/dist/operations/operation-identity.js +3 -0
- 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 +41 -12
- package/dist/operations/operation-validator.d.ts +24 -9
- package/dist/operations/operation-validator.js +26 -10
- package/dist/operations/projection-scope.resolver.d.ts +7 -7
- package/dist/operations/structural-limits.walker.d.ts +19 -0
- package/dist/operations/structural-limits.walker.js +489 -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 -11
- package/dist/protocol/absent-route.responder.js +42 -16
- 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 +23 -13
- package/dist/protocol/http-request.decoder.js +19 -11
- 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 +52 -27
- package/dist/protocol/protocol.binder.js +14 -9
- package/dist/protocol/protocol.handler.d.ts +28 -15
- package/dist/protocol/protocol.handler.js +55 -10
- 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 +67 -0
- package/dist/runtime/computed-read-runtime.d.ts +7 -6
- package/dist/runtime/computed-read-runtime.js +61 -55
- package/dist/runtime/computed-value.error.d.ts +13 -0
- package/dist/runtime/computed-value.error.js +9 -0
- 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 +22 -57
- package/dist/runtime/create-requirement.js +140 -37
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +1 -1
- package/dist/runtime/diagnostics-reporter.d.ts +64 -22
- package/dist/runtime/diagnostics-reporter.js +35 -4
- package/dist/runtime/error-boundary.d.ts +73 -8
- package/dist/runtime/error-boundary.js +104 -48
- 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 +79 -7
- 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 +32 -0
- package/dist/runtime/misuse-reporter.js +19 -0
- package/dist/runtime/mutation-planner.d.ts +19 -10
- package/dist/runtime/mutation-planner.js +62 -36
- 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 +35 -15
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +125 -30
- package/dist/runtime/operation-runtime.js +423 -83
- package/dist/runtime/outcome-mapper.d.ts +16 -5
- package/dist/runtime/outcome-mapper.js +35 -8
- package/dist/runtime/output-validator.d.ts +16 -6
- package/dist/runtime/output-validator.js +12 -1
- package/dist/runtime/owned-execution.registry.d.ts +13 -0
- package/dist/runtime/owned-execution.registry.js +7 -0
- 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 +202 -28
- package/dist/runtime/readonly-value.d.ts +32 -0
- package/dist/runtime/readonly-value.js +141 -0
- package/dist/runtime/referential-action.d.ts +7 -0
- package/dist/runtime/request-envelope.validator.d.ts +5 -0
- package/dist/runtime/request-envelope.validator.js +123 -0
- 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 +56 -13
- package/dist/runtime/scalar-runtime.js +167 -86
- 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 +23 -9
- package/dist/transactions/transaction-plan-assembler.js +195 -82
- package/dist/transactions/transaction-plan-validator.d.ts +53 -21
- package/dist/transactions/transaction-plan-validator.js +246 -163
- 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 +19 -2
- package/dist/transactions/transaction-reference-resolver.js +27 -10
- package/dist/transactions/transaction-reference-validator.d.ts +34 -4
- package/dist/transactions/transaction-reference-validator.js +82 -43
- package/dist/transactions/transaction-reference.d.ts +30 -58
- package/dist/transactions/transaction-request.d.ts +20 -7
- package/dist/transactions/transaction-response.d.ts +12 -7
- package/dist/transactions/transaction-response.js +24 -1
- package/dist/transactions/transaction-runtime.d.ts +11 -8
- package/dist/transactions/transaction-runtime.js +167 -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 +18 -3
- package/src/runtime/field-check.evaluator.ts +720 -0
- package/dist/config/define-fields.d.ts +0 -35
- 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 -36
- package/dist/config/framework-restrictions-config.d.ts +0 -142
- 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
- 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/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
- /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
2
|
import type { ScalarForms } from "../contracts/scalar-value-type.js";
|
|
3
|
-
import type {
|
|
4
|
-
import type { Operation } from "../transactions/deferred-operation.js";
|
|
3
|
+
import type { AvOperation } from "../transactions/deferred-operation.js";
|
|
5
4
|
import type { ReferenceableArgumentsFor } from "../transactions/transaction-reference.js";
|
|
6
|
-
import type {
|
|
7
|
-
import type {
|
|
5
|
+
import type { AvOperationArgumentsFor, AvResourceKey } from "./operation-arguments.js";
|
|
6
|
+
import type { AvOperationFamily, AvOperationIdentity, AvOperationVariant } from "./operation-identity.js";
|
|
8
7
|
import type { AdmittedOperationResult } from "./operation-result.js";
|
|
9
8
|
type ProjectionKey = "select" | "include";
|
|
9
|
+
/** The origin of a deferred handle's builder (`AvOperationHandle`). */
|
|
10
|
+
type HandleOrigin = "application" | "client";
|
|
11
|
+
type AnyOrigin = any;
|
|
10
12
|
type SelectOf<Args> = Args extends {
|
|
11
13
|
readonly select?: infer Select;
|
|
12
14
|
} ? Exclude<Select, undefined> : never;
|
|
@@ -30,15 +32,15 @@ type InferredProjection<Select, Include> = [Select] extends [never] ? [Include]
|
|
|
30
32
|
type ArgumentList<Rest, Parameter> = Record<never, never> extends Rest ? [args?: Parameter] : [args: Parameter];
|
|
31
33
|
/** A direct call's parameters: the argument, then the caller's per-call options. */
|
|
32
34
|
type CallArgumentList<Rest, Parameter, Options> = Record<never, never> extends Rest ? [args?: Parameter, options?: Options] : [args: Parameter, options?: Options];
|
|
33
|
-
type ResourceOperationsOf<C extends
|
|
35
|
+
type ResourceOperationsOf<C extends AvContract, R extends AvResourceKey<C>> = C["resources"][R]["operations"];
|
|
34
36
|
/**
|
|
35
37
|
* The operations Contract `C` advertises: one property per Resource, one per
|
|
36
38
|
* family under it, one identity per variant under that.
|
|
37
39
|
*/
|
|
38
|
-
export type
|
|
39
|
-
readonly [R in
|
|
40
|
-
readonly [F in Extract<keyof ResourceOperationsOf<C, R>,
|
|
41
|
-
readonly [V in Extract<keyof NonNullable<ResourceOperationsOf<C, R>[F]>,
|
|
40
|
+
export type AvOperationGrammar<C extends AvContract> = {
|
|
41
|
+
readonly [R in AvResourceKey<C>]: {
|
|
42
|
+
readonly [F in Extract<keyof ResourceOperationsOf<C, R>, AvOperationFamily>]: {
|
|
43
|
+
readonly [V in Extract<keyof NonNullable<ResourceOperationsOf<C, R>[F]>, AvOperationVariant<F>>]: Extract<AvOperationIdentity, {
|
|
42
44
|
readonly family: F;
|
|
43
45
|
readonly variant: V;
|
|
44
46
|
}>;
|
|
@@ -50,33 +52,30 @@ export type OperationGrammar<C extends Contract> = {
|
|
|
50
52
|
* This is the value a committed transaction or a remote call returns for the
|
|
51
53
|
* operation.
|
|
52
54
|
*/
|
|
53
|
-
export type
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*/
|
|
59
|
-
type Settled<Settlement extends "response" | "data", I extends OperationIdentity, Result> = Settlement extends "data" ? OperationSlot<I, Result> : OperationResponse<Result>;
|
|
60
|
-
type ProjectingCall<C extends Contract, R extends ResourceKey<C>, I extends OperationIdentity, Args, ResultForms extends ScalarForms, Settlement extends "response" | "data", Options> = <const Select extends SelectOf<Args> = never, const Include extends IncludeOf<Args> = never>(...args: CallArgumentList<Omit<Args, ProjectionKey>, Omit<Args, ProjectionKey> & ProjectionArgument<Select, Include>, Options>) => Promise<Settled<Settlement, I, AdmittedOperationResult<C, R, I, InferredProjection<Select, Include>, ResultForms>>>;
|
|
61
|
-
type PlainCall<C extends Contract, R extends ResourceKey<C>, I extends OperationIdentity, Args, ResultForms extends ScalarForms, Settlement extends "response" | "data", Options> = (...args: CallArgumentList<Args, Args, Options>) => Promise<Settled<Settlement, I, AdmittedOperationResult<C, R, I, unknown, ResultForms>>>;
|
|
55
|
+
export type AvOperationSlot<I extends AvOperationIdentity, Result> = I["variant"] extends "first" ? Result | null : Result;
|
|
56
|
+
/** What a direct call resolves: the slot, every failure thrown. */
|
|
57
|
+
type Settled<I extends AvOperationIdentity, Result> = AvOperationSlot<I, Result>;
|
|
58
|
+
type ProjectingCall<C extends AvContract, R extends AvResourceKey<C>, I extends AvOperationIdentity, Args, ResultForms extends ScalarForms, Options> = <const Select extends SelectOf<Args> = never, const Include extends IncludeOf<Args> = never>(...args: CallArgumentList<Omit<Args, ProjectionKey>, Omit<Args, ProjectionKey> & ProjectionArgument<Select, Include>, Options>) => Promise<Settled<I, AdmittedOperationResult<C, R, I, InferredProjection<Select, Include>, ResultForms>>>;
|
|
59
|
+
type PlainCall<C extends AvContract, R extends AvResourceKey<C>, I extends AvOperationIdentity, Args, ResultForms extends ScalarForms, Options> = (...args: CallArgumentList<Args, Args, Options>) => Promise<Settled<I, AdmittedOperationResult<C, R, I, unknown, ResultForms>>>;
|
|
62
60
|
/**
|
|
63
61
|
* One direct call: its arguments in `Forms`, its result in `ResultForms`,
|
|
64
|
-
* resolving
|
|
62
|
+
* resolving the slot and throwing every failure, taking `Options` per call. It is generic in its
|
|
65
63
|
* projection when it carries one.
|
|
66
64
|
*/
|
|
67
|
-
export type
|
|
65
|
+
export type AvOperationCall<C extends AvContract, R extends AvResourceKey<C>, I extends AvOperationIdentity, Forms extends ScalarForms, ResultForms extends ScalarForms, Options> = "select" extends keyof AvOperationArgumentsFor<C, R, I, Forms> ? ProjectingCall<C, R, I, AvOperationArgumentsFor<C, R, I, Forms>, ResultForms, Options> : PlainCall<C, R, I, AvOperationArgumentsFor<C, R, I, Forms>, ResultForms, Options>;
|
|
68
66
|
/**
|
|
69
67
|
* A deferred operation's arguments: `Forms`, with reference positions opened to a
|
|
70
68
|
* `$ref` typed in `ResultForms` — the forms the source's final data is read in, so a
|
|
71
69
|
* reference carries what its source resolves.
|
|
72
70
|
*/
|
|
73
|
-
type DeferredArguments<C extends
|
|
74
|
-
type DeferredProjectingCall<C extends
|
|
75
|
-
type DeferredPlainCall<C extends
|
|
71
|
+
type DeferredArguments<C extends AvContract, R extends AvResourceKey<C>, I extends AvOperationIdentity, Forms extends ScalarForms, ResultForms extends ScalarForms> = ReferenceableArgumentsFor<C, R, I, Forms, ResultForms>;
|
|
72
|
+
type DeferredProjectingCall<C extends AvContract, R extends AvResourceKey<C>, I extends AvOperationIdentity, Args, ResultForms extends ScalarForms, Origin extends HandleOrigin> = <const Select extends SelectOf<Args> = never, const Include extends IncludeOf<Args> = never>(...args: ArgumentList<Omit<Args, ProjectionKey>, Omit<Args, ProjectionKey> & ProjectionArgument<Select, Include>>) => AvOperation<AvOperationSlot<I, AdmittedOperationResult<C, R, I, InferredProjection<Select, Include>, ResultForms>>, Origin>;
|
|
73
|
+
type DeferredPlainCall<C extends AvContract, R extends AvResourceKey<C>, I extends AvOperationIdentity, Args, ResultForms extends ScalarForms, Origin extends HandleOrigin> = (...args: ArgumentList<Args, Args>) => AvOperation<AvOperationSlot<I, AdmittedOperationResult<C, R, I, unknown, ResultForms>>, Origin>;
|
|
76
74
|
/**
|
|
77
|
-
* One deferred operation: a handle typed `
|
|
78
|
-
* present exactly where the result is one row. A handle is not a
|
|
79
|
-
* options.
|
|
75
|
+
* One deferred operation: a handle typed `AvOperation<AvOperationSlot<…>, Origin>`,
|
|
76
|
+
* with `$ref` present exactly where the result is one row. A handle is not a
|
|
77
|
+
* request and takes no options. `Origin` is the builder's: a transaction's
|
|
78
|
+
* handles all share one.
|
|
80
79
|
*/
|
|
81
|
-
export type
|
|
80
|
+
export type AvDeferredOperationCall<C extends AvContract, R extends AvResourceKey<C>, I extends AvOperationIdentity, Forms extends ScalarForms, ResultForms extends ScalarForms, Origin extends HandleOrigin = AnyOrigin> = "select" extends keyof DeferredArguments<C, R, I, Forms, ResultForms> ? DeferredProjectingCall<C, R, I, DeferredArguments<C, R, I, Forms, ResultForms>, ResultForms, Origin> : DeferredPlainCall<C, R, I, DeferredArguments<C, R, I, Forms, ResultForms>, ResultForms, Origin>;
|
|
82
81
|
export {};
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AvResourceOperations } from "../contracts/resource-operations.js";
|
|
2
2
|
/** A standard operation family: `find`, `create`, `update`, `delete` or `upsert`. */
|
|
3
|
-
export type
|
|
3
|
+
export type AvOperationFamily = Extract<keyof AvResourceOperations, string>;
|
|
4
4
|
/** The variants of operation family `F`, such as `many` or `unique`. */
|
|
5
|
-
export type
|
|
5
|
+
export type AvOperationVariant<F extends AvOperationFamily> = Extract<keyof NonNullable<AvResourceOperations[F]>, string>;
|
|
6
6
|
/** A standard operation's `family` and `variant`. */
|
|
7
|
-
export type
|
|
8
|
-
[F in
|
|
9
|
-
[V in
|
|
7
|
+
export type AvOperationIdentity = {
|
|
8
|
+
[F in AvOperationFamily]: {
|
|
9
|
+
[V in AvOperationVariant<F>]: {
|
|
10
10
|
readonly family: F;
|
|
11
11
|
readonly variant: V;
|
|
12
12
|
};
|
|
13
|
-
}[
|
|
14
|
-
}[
|
|
15
|
-
/** Parses a family and variant into an {@link
|
|
16
|
-
export declare function parseOperationIdentity(family: string, variant: string):
|
|
13
|
+
}[AvOperationVariant<F>];
|
|
14
|
+
}[AvOperationFamily];
|
|
15
|
+
/** Parses a family and variant into an {@link AvOperationIdentity}, or `undefined` when they name no standard operation. */
|
|
16
|
+
export declare function parseOperationIdentity(family: string, variant: string): AvOperationIdentity | undefined;
|
|
17
|
+
/** Whether `family` names one of the standard operation families. */
|
|
18
|
+
export declare function isOperationFamily(family: string): boolean;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
6
|
-
type FieldOf<C extends
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import type { AvRelationField, AvScalarField } from "../contracts/field.js";
|
|
3
|
+
import type { AvApplicationScalarForms, AvScalarValueType, ScalarForms } from "../contracts/scalar-value-type.js";
|
|
4
|
+
import type { AvFieldKey, AvOperationArgumentsFor, AvResourceKey } from "./operation-arguments.js";
|
|
5
|
+
import type { AvOperationIdentity } from "./operation-identity.js";
|
|
6
|
+
type FieldOf<C extends AvContract, K extends AvResourceKey<C>, F extends AvFieldKey<C, K>> = C["resources"][K]["fields"][F];
|
|
7
7
|
/**
|
|
8
8
|
* The fields returned when no projection is given: the scalars whose `select`
|
|
9
9
|
* is exactly `true`. A write-only field never appears.
|
|
10
10
|
*/
|
|
11
|
-
type DefaultKey<C extends
|
|
12
|
-
[F in
|
|
11
|
+
type DefaultKey<C extends AvContract, K extends AvResourceKey<C>> = {
|
|
12
|
+
[F in AvFieldKey<C, K>]: FieldOf<C, K, F> extends {
|
|
13
13
|
readonly kind: "scalar";
|
|
14
14
|
readonly capabilities: {
|
|
15
15
|
readonly select: true;
|
|
16
16
|
};
|
|
17
17
|
} ? F : never;
|
|
18
|
-
}[
|
|
18
|
+
}[AvFieldKey<C, K>];
|
|
19
19
|
/** The field one projection entry names: a bare key, or a relation entry's key. */
|
|
20
20
|
type EntryKey<Entry> = Entry extends string ? Entry : Entry extends object ? Extract<keyof Entry, string> : never;
|
|
21
21
|
/**
|
|
@@ -31,26 +31,26 @@ type EntryArguments<Entry, F extends string> = Entry extends object ? Entry exte
|
|
|
31
31
|
* `Entries` carries the relation entries' own arguments down; the scalar branch
|
|
32
32
|
* ignores them.
|
|
33
33
|
*/
|
|
34
|
-
type ProjectedFields<C extends
|
|
35
|
-
readonly [F in Keys]: FieldOf<C, K, F> extends
|
|
34
|
+
type ProjectedFields<C extends AvContract, K extends AvResourceKey<C>, Keys extends AvFieldKey<C, K>, Entries, Forms extends ScalarForms> = {
|
|
35
|
+
readonly [F in Keys]: FieldOf<C, K, F> extends AvScalarField<C> ? AvScalarValueType<C, FieldOf<C, K, F>, Forms> : FieldOf<C, K, F> extends AvRelationField<C> ? RelationResult<C, Extract<FieldOf<C, K, F>["target"], AvResourceKey<C>>, FieldOf<C, K, F>, EntryArguments<Entries, F>, Forms> : never;
|
|
36
36
|
};
|
|
37
37
|
/**
|
|
38
38
|
* One projection level: `select` returns exactly its entries, `include` the
|
|
39
39
|
* default fields plus the named relations, and no projection the default fields.
|
|
40
40
|
*/
|
|
41
|
-
type ProjectedRecord<C extends
|
|
41
|
+
type ProjectedRecord<C extends AvContract, K extends AvResourceKey<C>, Arguments, Forms extends ScalarForms> = [Arguments] extends [never] ? ProjectedFields<C, K, DefaultKey<C, K>, never, Forms> : [Arguments] extends [{
|
|
42
42
|
readonly select: readonly (infer Entry)[];
|
|
43
|
-
}] ? ProjectedFields<C, K, Extract<EntryKey<Entry>,
|
|
43
|
+
}] ? ProjectedFields<C, K, Extract<EntryKey<Entry>, AvFieldKey<C, K>>, Entry, Forms> : [Arguments] extends [{
|
|
44
44
|
readonly include: readonly (infer Entry)[];
|
|
45
|
-
}] ? ProjectedFields<C, K, DefaultKey<C, K> | Extract<EntryKey<Entry>,
|
|
45
|
+
}] ? ProjectedFields<C, K, DefaultKey<C, K> | Extract<EntryKey<Entry>, AvFieldKey<C, K>>, Entry, Forms> : ProjectedFields<C, K, DefaultKey<C, K>, never, Forms>;
|
|
46
46
|
/**
|
|
47
47
|
* A to-many entry whose `select` asks for `$count`: the value is an object with
|
|
48
48
|
* the rows and the count, not the row array.
|
|
49
49
|
*/
|
|
50
|
-
type CountEnvelope<C extends
|
|
50
|
+
type CountEnvelope<C extends AvContract, Target extends AvResourceKey<C>, Entry, Forms extends ScalarForms> = [Exclude<Entry, "$count">] extends [never] ? {
|
|
51
51
|
readonly count: number;
|
|
52
52
|
} : {
|
|
53
|
-
readonly data: readonly ProjectedFields<C, Target, Extract<EntryKey<Entry>,
|
|
53
|
+
readonly data: readonly ProjectedFields<C, Target, Extract<EntryKey<Entry>, AvFieldKey<C, Target>>, Exclude<Entry, "$count">, Forms>[];
|
|
54
54
|
readonly count: number;
|
|
55
55
|
};
|
|
56
56
|
/** The entries of an argument's own `select`, or `never` when it has none. */
|
|
@@ -61,16 +61,16 @@ type SelectEntry<Arguments> = Arguments extends {
|
|
|
61
61
|
* The value of one relation entry. A to-many entry is the rows-and-count object
|
|
62
62
|
* when its own `select` asks for `$count`; otherwise the row array.
|
|
63
63
|
*/
|
|
64
|
-
type RelationResult<C extends
|
|
64
|
+
type RelationResult<C extends AvContract, Target extends AvResourceKey<C>, Relation extends AvRelationField<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);
|
|
65
65
|
/**
|
|
66
|
-
* The value a standard operation returns in `
|
|
66
|
+
* The value a standard operation returns in `AvOperationResponse.data` on success,
|
|
67
67
|
* derived from the Contract, the Resource, the operation identity and the projection
|
|
68
68
|
* argument.
|
|
69
69
|
*/
|
|
70
|
-
export type
|
|
70
|
+
export type AvOperationResultFor<C extends AvContract, K extends AvResourceKey<C>, I extends AvOperationIdentity, Args extends AvOperationArgumentsFor<C, K, I>, Forms extends ScalarForms = AvApplicationScalarForms> = AdmittedOperationResult<C, K, I, Args, Forms>;
|
|
71
71
|
/**
|
|
72
|
-
* {@link
|
|
72
|
+
* {@link AvOperationResultFor}, for a projection already checked against the
|
|
73
73
|
* operation's argument type.
|
|
74
74
|
*/
|
|
75
|
-
export type AdmittedOperationResult<C extends
|
|
75
|
+
export type AdmittedOperationResult<C extends AvContract, K extends AvResourceKey<C>, I extends AvOperationIdentity, Args, Forms extends ScalarForms = AvApplicationScalarForms> = I["variant"] extends "count" ? number : I["variant"] extends "many" ? readonly ProjectedRecord<C, K, Args, Forms>[] : ProjectedRecord<C, K, Args, Forms>;
|
|
76
76
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import { type AvOperationIdentity } from "./operation-identity.js";
|
|
3
|
+
import type { AvValidationIssue } from "./validation-code.js";
|
|
4
4
|
/** An operation's arguments as an object, before validation. */
|
|
5
5
|
export type SemanticOperationArguments = Readonly<Record<string, unknown>>;
|
|
6
6
|
type OperationValidationSuccess = {
|
|
@@ -9,7 +9,7 @@ type OperationValidationSuccess = {
|
|
|
9
9
|
};
|
|
10
10
|
type OperationValidationFailure = {
|
|
11
11
|
readonly ok: false;
|
|
12
|
-
readonly issues: readonly
|
|
12
|
+
readonly issues: readonly AvValidationIssue[];
|
|
13
13
|
};
|
|
14
14
|
/** The answer of {@link validateOperationArguments}: success, or the issues found. */
|
|
15
15
|
export type OperationValidationResult = OperationValidationSuccess | OperationValidationFailure;
|
|
@@ -21,8 +21,8 @@ export type OperationValidationOptions = {
|
|
|
21
21
|
* Contract does not have (`V1005` at `["resource"]`, rolling up to `A2001`). The one
|
|
22
22
|
* spelling — the protocol's absence answers build theirs with it.
|
|
23
23
|
*/
|
|
24
|
-
export declare function resourceUnavailableIssue(resource: string):
|
|
25
|
-
export declare function validateOperationArguments(contract:
|
|
24
|
+
export declare function resourceUnavailableIssue(resource: string): AvValidationIssue;
|
|
25
|
+
export declare function validateOperationArguments(contract: AvContract, request: AvOperationIdentity & {
|
|
26
26
|
readonly resource: string;
|
|
27
27
|
readonly arguments: unknown;
|
|
28
28
|
}, options?: OperationValidationOptions): OperationValidationResult;
|
|
@@ -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) {
|
|
@@ -152,12 +153,15 @@ function checkDepth(contract, state, depth) {
|
|
|
152
153
|
}
|
|
153
154
|
return false;
|
|
154
155
|
}
|
|
155
|
-
function validateScalarFilter(fieldName, field, value, path, state) {
|
|
156
|
+
function validateScalarFilter(contract, fieldName, field, value, path, state, depth) {
|
|
156
157
|
const supported = field.capabilities.filter;
|
|
157
158
|
if (supported === undefined) {
|
|
158
159
|
addIssue(state.issues, "V1006", path, `Filtering is not available on field "${fieldName}".`);
|
|
159
160
|
return;
|
|
160
161
|
}
|
|
162
|
+
validateScalarCondition(contract, fieldName, field, supported, value, path, state, depth);
|
|
163
|
+
}
|
|
164
|
+
function validateScalarCondition(contract, fieldName, field, supported, value, path, state, depth) {
|
|
161
165
|
if (value === null) {
|
|
162
166
|
if (!field.nullable) {
|
|
163
167
|
addIssue(state.issues, "V1001", path, `Field "${fieldName}" is not nullable.`);
|
|
@@ -168,6 +172,13 @@ function validateScalarFilter(fieldName, field, value, path, state) {
|
|
|
168
172
|
}
|
|
169
173
|
return;
|
|
170
174
|
}
|
|
175
|
+
if (state.transactionReferences === true &&
|
|
176
|
+
routeTransactionReferenceCandidate(value).kind !== "ordinary") {
|
|
177
|
+
if (!includes(supported, "equals")) {
|
|
178
|
+
addIssue(state.issues, "V1006", path, `Equality filtering is not available on field "${fieldName}".`);
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
171
182
|
if (!isPlainRecord(value)) {
|
|
172
183
|
if (!includes(supported, "equals")) {
|
|
173
184
|
addIssue(state.issues, "V1006", path, `Equality filtering is not available on field "${fieldName}".`);
|
|
@@ -182,6 +193,14 @@ function validateScalarFilter(fieldName, field, value, path, state) {
|
|
|
182
193
|
for (const operator of operators) {
|
|
183
194
|
if (!includes(supported, operator)) {
|
|
184
195
|
addIssue(state.issues, "V1006", [...path, operator], `Filter operator "${operator}" is not available on field "${fieldName}".`);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (operator === "not") {
|
|
199
|
+
const operand = value[operator];
|
|
200
|
+
if (isPlainRecord(operand) && !checkDepth(contract, state, depth + 1)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
validateScalarCondition(contract, fieldName, field, supported, operand, [...path, operator], state, isPlainRecord(operand) ? depth + 1 : depth);
|
|
185
204
|
}
|
|
186
205
|
}
|
|
187
206
|
}
|
|
@@ -268,7 +287,10 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
|
268
287
|
}
|
|
269
288
|
const fieldPath = [...path, key];
|
|
270
289
|
if (field.kind === "scalar") {
|
|
271
|
-
validateScalarFilter(key, field, value, fieldPath, state);
|
|
290
|
+
validateScalarFilter(contract, key, field, value, fieldPath, state, depth);
|
|
291
|
+
}
|
|
292
|
+
else if (state.scalarOnly === true) {
|
|
293
|
+
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.`);
|
|
272
294
|
}
|
|
273
295
|
else {
|
|
274
296
|
validateRelationFilter(contract, key, field, value, fieldPath, state, depth);
|
|
@@ -570,7 +592,7 @@ function validateScalarMutation(fieldName, field, value, stage, path, issues, tr
|
|
|
570
592
|
}
|
|
571
593
|
}
|
|
572
594
|
}
|
|
573
|
-
function validateRelationMutationEntry(contract, edge, directive, value, path, issues) {
|
|
595
|
+
function validateRelationMutationEntry(contract, edge, directive, value, path, issues, transactionReferences) {
|
|
574
596
|
const target = edge.target;
|
|
575
597
|
if (edge.cardinality === "one" && Array.isArray(value)) {
|
|
576
598
|
addIssue(issues, "V1012", path, `To-one relation directive "${directive}" does not accept arrays.`);
|
|
@@ -619,7 +641,7 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
619
641
|
if (directive === "$create") {
|
|
620
642
|
const entries = edge.cardinality === "many" && Array.isArray(value) ? value : [value];
|
|
621
643
|
for (const entry of entries) {
|
|
622
|
-
validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, path, issues);
|
|
644
|
+
validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, path, issues, transactionReferences);
|
|
623
645
|
}
|
|
624
646
|
return;
|
|
625
647
|
}
|
|
@@ -631,7 +653,7 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
631
653
|
continue;
|
|
632
654
|
}
|
|
633
655
|
validateUniqueSelector(contract, target, entry.where, [...path, "where"], issues);
|
|
634
|
-
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues);
|
|
656
|
+
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues, transactionReferences);
|
|
635
657
|
}
|
|
636
658
|
return;
|
|
637
659
|
}
|
|
@@ -650,13 +672,15 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
650
672
|
const state = {
|
|
651
673
|
issues,
|
|
652
674
|
structuralRoot: [...path, "where"],
|
|
675
|
+
transactionReferences,
|
|
676
|
+
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
653
677
|
booleanFilterNodes: 0,
|
|
654
678
|
nestingExceeded: false,
|
|
655
679
|
booleanNodesExceeded: false,
|
|
656
680
|
};
|
|
657
681
|
validateWhere(contract, target, entry.where, [...path, "where"], state, 1);
|
|
658
682
|
}
|
|
659
|
-
validateMutationData(contract, target, entry.data, "update", NESTED_WRITE_SCOPE, [...path, "data"], issues);
|
|
683
|
+
validateMutationData(contract, target, entry.data, "update", NESTED_WRITE_SCOPE, [...path, "data"], issues, transactionReferences);
|
|
660
684
|
}
|
|
661
685
|
return;
|
|
662
686
|
}
|
|
@@ -671,6 +695,8 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
671
695
|
const state = {
|
|
672
696
|
issues,
|
|
673
697
|
structuralRoot: [...path, "where"],
|
|
698
|
+
transactionReferences,
|
|
699
|
+
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
674
700
|
booleanFilterNodes: 0,
|
|
675
701
|
nestingExceeded: false,
|
|
676
702
|
booleanNodesExceeded: false,
|
|
@@ -685,6 +711,8 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
685
711
|
const state = {
|
|
686
712
|
issues,
|
|
687
713
|
structuralRoot: [...path, "where"],
|
|
714
|
+
transactionReferences,
|
|
715
|
+
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
688
716
|
booleanFilterNodes: 0,
|
|
689
717
|
nestingExceeded: false,
|
|
690
718
|
booleanNodesExceeded: false,
|
|
@@ -707,12 +735,12 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
707
735
|
if ("where" in entry) {
|
|
708
736
|
validateUniqueSelector(contract, target, entry.where, [...path, "where"], issues);
|
|
709
737
|
}
|
|
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);
|
|
738
|
+
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues, transactionReferences);
|
|
739
|
+
validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...path, "update"], issues, transactionReferences);
|
|
712
740
|
}
|
|
713
741
|
}
|
|
714
742
|
}
|
|
715
|
-
function validateRelationMutation(contract, fieldName, field, value, stage, scope, path, issues) {
|
|
743
|
+
function validateRelationMutation(contract, fieldName, field, value, stage, scope, path, issues, transactionReferences) {
|
|
716
744
|
const directives = advertisedDirectivesAt(field.capabilities[stage], scope);
|
|
717
745
|
if (directives === undefined) {
|
|
718
746
|
addIssue(issues, "V1006", path, `Relation "${fieldName}" is not writable during ${stage}.`);
|
|
@@ -728,7 +756,7 @@ function validateRelationMutation(contract, fieldName, field, value, stage, scop
|
|
|
728
756
|
addIssue(issues, "V1006", directivePath, `Relation mutation directive "${directive}" is not available on relation "${fieldName}".`);
|
|
729
757
|
continue;
|
|
730
758
|
}
|
|
731
|
-
validateRelationMutationEntry(contract, field, directive, directiveValue, directivePath, issues);
|
|
759
|
+
validateRelationMutationEntry(contract, field, directive, directiveValue, directivePath, issues, transactionReferences);
|
|
732
760
|
}
|
|
733
761
|
}
|
|
734
762
|
function validateMutationData(contract, resourceName, data, stage, scope, path, issues, transactionReferences = false) {
|
|
@@ -752,7 +780,7 @@ function validateMutationData(contract, resourceName, data, stage, scope, path,
|
|
|
752
780
|
validateScalarMutation(fieldName, field, value, stage, fieldPath, issues, transactionReferences);
|
|
753
781
|
}
|
|
754
782
|
else {
|
|
755
|
-
validateRelationMutation(contract, fieldName, field, value, stage, scope, fieldPath, issues);
|
|
783
|
+
validateRelationMutation(contract, fieldName, field, value, stage, scope, fieldPath, issues, transactionReferences);
|
|
756
784
|
}
|
|
757
785
|
}
|
|
758
786
|
}
|
|
@@ -830,6 +858,7 @@ export function validateOperationArguments(contract, request, options) {
|
|
|
830
858
|
const state = {
|
|
831
859
|
issues,
|
|
832
860
|
structuralRoot: ["arguments", "where"],
|
|
861
|
+
transactionReferences: options?.transactionReferences === true,
|
|
833
862
|
booleanFilterNodes: 0,
|
|
834
863
|
nestingExceeded: false,
|
|
835
864
|
booleanNodesExceeded: false,
|
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import { type AvOperationIdentity } from "./operation-identity.js";
|
|
3
3
|
import { type OperationValidationOptions, type OperationValidationResult } from "./operation-validator-core.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type { AvValidationIssue } 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: AvContract, 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
|
-
*
|
|
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.
|
|
11
17
|
*/
|
|
12
|
-
export declare function operationUnavailableIssue(request: {
|
|
18
|
+
export declare function operationUnavailableIssue(contract: AvContract, request: {
|
|
13
19
|
readonly resource: string;
|
|
14
20
|
readonly family: string;
|
|
15
21
|
readonly variant: string;
|
|
16
|
-
}):
|
|
22
|
+
}): AvValidationIssue;
|
|
23
|
+
/**
|
|
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: AvContract, request: AvOperationIdentity & {
|
|
30
|
+
readonly resource: string;
|
|
31
|
+
}): AvValidationIssue | undefined;
|
|
17
32
|
/**
|
|
18
33
|
* Validates one standard operation's arguments against a Contract. Operation
|
|
19
34
|
* availability and request limits are checked before the arguments' grammar.
|
|
20
35
|
*/
|
|
21
|
-
export declare function validateOperationArguments(contract:
|
|
36
|
+
export declare function validateOperationArguments(contract: AvContract, request: AvOperationIdentity & {
|
|
22
37
|
readonly resource: string;
|
|
23
38
|
readonly arguments: unknown;
|
|
24
39
|
}, options?: OperationValidationOptions): OperationValidationResult;
|
|
@@ -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,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
1
|
+
import type { AvProjectionScope } from "../contracts/capability.js";
|
|
2
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
3
|
+
import type { AvResource } from "../contracts/resource.js";
|
|
4
|
+
import type { AvOperationIdentity } from "./operation-identity.js";
|
|
5
5
|
/**
|
|
6
6
|
* Which projection position one request's **top-level** projection arguments sit
|
|
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
|
|
@@ -21,9 +21,9 @@ import type { OperationIdentity } from "./operation-identity.js";
|
|
|
21
21
|
* answering `"record"` for one keeps this function a projection question rather
|
|
22
22
|
* than a second, weaker copy of the availability gate.
|
|
23
23
|
*/
|
|
24
|
-
export declare function resolveProjectionScope(resource:
|
|
24
|
+
export declare function resolveProjectionScope(resource: AvResource<AvContract> | undefined, request: AvOperationIdentity): AvProjectionScope;
|
|
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
28
|
*/
|
|
29
|
-
export declare const NESTED_PROJECTION_SCOPE:
|
|
29
|
+
export declare const NESTED_PROJECTION_SCOPE: AvProjectionScope;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import type { AvOperationIdentity } from "./operation-identity.js";
|
|
3
|
+
import type { AvValidationIssue } 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: AvValidationIssue | undefined;
|
|
9
|
+
/** The boolean-node issue, when there is no nesting issue. */
|
|
10
|
+
readonly booleanNodes: AvValidationIssue | 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: AvContract, request: AvOperationIdentity & {
|
|
17
|
+
readonly resource: string;
|
|
18
|
+
}, args: Readable): StructuralLimitsFinding;
|
|
19
|
+
export {};
|