@aventara/core 1.0.0-rc.0 → 1.0.0-rc.10
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 +2068 -1
- package/ERRORS.md +142 -0
- package/README.md +485 -60
- package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
- package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
- package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
- package/dist/adapters/adapter-field.d.ts +33 -11
- package/dist/adapters/adapter-identifier.d.ts +15 -6
- package/dist/adapters/adapter-identifier.js +6 -1
- package/dist/adapters/adapter-model.d.ts +18 -9
- package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
- package/dist/adapters/adapter-operation.d.ts +21 -6
- package/dist/adapters/adapter-resource.d.ts +23 -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 +59 -29
- package/dist/avz/avz-check.factory.d.ts +83 -0
- package/dist/avz/avz-check.factory.js +116 -0
- package/dist/avz/avz-check.registry.d.ts +35 -0
- package/dist/avz/avz-check.registry.js +9 -0
- package/dist/avz/avz.d.ts +203 -0
- package/dist/{json → avz}/avz.js +150 -8
- package/dist/{json → avz}/index.d.ts +2 -1
- package/dist/{json → avz}/json-shape.registry.d.ts +9 -8
- package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
- package/dist/{json → avz}/zod-issue.translator.js +7 -0
- package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
- package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
- package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
- package/dist/compiler/contract.compiler.d.ts +23 -17
- package/dist/compiler/contract.compiler.js +753 -443
- 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/compiler/managed-elsewhere.projector.d.ts +52 -0
- package/dist/compiler/managed-elsewhere.projector.js +179 -0
- package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
- package/dist/compiler/managed-elsewhere.validator.js +74 -0
- package/dist/config/any-framework-config.d.ts +19 -12
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +73 -0
- package/dist/config/config-diagnostic.d.ts +11 -4
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/config-layer.d.ts +15 -6
- package/dist/config/config.resolver.d.ts +98 -31
- package/dist/config/config.resolver.js +173 -44
- package/dist/config/config.validator.d.ts +7 -7
- package/dist/config/config.validator.js +792 -69
- package/dist/config/define-resource.d.ts +53 -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 +4 -3
- package/dist/config/exact-framework-config.d.ts +325 -0
- package/dist/config/field-compute.resolver.d.ts +21 -0
- package/dist/config/field-compute.resolver.js +123 -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 +148 -39
- package/dist/config/framework-exemptions-config.d.ts +91 -0
- package/dist/config/framework-exemptions-config.js +1 -0
- package/dist/config/framework-field-definition.d.ts +78 -0
- package/dist/config/framework-field-definition.js +28 -0
- package/dist/config/framework-resources-config.d.ts +127 -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/access-route.rules.d.ts +10 -0
- package/dist/contracts/access-route.rules.js +45 -0
- package/dist/contracts/capability.d.ts +37 -12
- package/dist/contracts/capability.js +20 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +621 -114
- package/dist/contracts/client-contract-structure.validator.js +189 -10
- package/dist/contracts/contract-access.d.ts +29 -0
- package/dist/contracts/contract-access.js +1 -0
- package/dist/contracts/contract-canonicalizer.d.ts +27 -3
- package/dist/contracts/contract-canonicalizer.js +168 -29
- package/dist/contracts/contract-hash.d.ts +11 -7
- package/dist/contracts/contract-hash.js +4 -3
- 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 +51 -17
- 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 +109 -42
- package/dist/contracts/identifier.d.ts +4 -4
- package/dist/contracts/json-schema.projector.d.ts +11 -0
- package/dist/contracts/json-schema.projector.js +78 -0
- package/dist/contracts/json-shape.d.ts +12 -1
- package/dist/contracts/lifecycle-trait.d.ts +2 -2
- package/dist/contracts/resource-operations.d.ts +28 -28
- package/dist/contracts/resource.d.ts +15 -9
- package/dist/contracts/scalar-value-type.d.ts +17 -15
- package/dist/contracts/scalar.d.ts +3 -3
- package/dist/contracts/transaction-capability.d.ts +1 -1
- package/dist/contracts/wire-scalar-format.d.ts +4 -4
- package/dist/framework/access-facade.d.ts +116 -0
- package/dist/framework/access-facade.js +120 -0
- package/dist/framework/contract-view.d.ts +315 -145
- package/dist/framework/framework-construction.error.d.ts +21 -11
- package/dist/framework/framework-construction.error.js +20 -4
- package/dist/framework/framework.d.ts +71 -26
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +150 -38
- package/dist/framework/operation-facade.d.ts +192 -54
- package/dist/framework/operation-facade.js +10 -1
- package/dist/index.d.ts +67 -50
- package/dist/index.js +7 -6
- package/dist/internal.d.ts +20 -10
- package/dist/internal.js +9 -1
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +381 -228
- package/dist/operations/operation-call.d.ts +31 -28
- package/dist/operations/operation-identity.d.ts +10 -10
- package/dist/operations/operation-result.d.ts +25 -23
- package/dist/operations/operation-validator-core.d.ts +6 -6
- package/dist/operations/operation-validator-core.js +172 -38
- package/dist/operations/operation-validator.d.ts +10 -10
- package/dist/operations/projection-scope.resolver.d.ts +6 -6
- package/dist/operations/structural-limits.walker.d.ts +7 -7
- package/dist/operations/structural-limits.walker.js +145 -0
- package/dist/operations/validation-code.d.ts +11 -6
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/validation-code.js +4 -0
- package/dist/operations/write-scope.resolver.d.ts +10 -6
- package/dist/operations/write-scope.resolver.js +2 -0
- package/dist/policy/access-provider.interface.d.ts +91 -0
- package/dist/policy/access-provider.interface.js +1 -0
- package/dist/policy/access-provider.registry.d.ts +17 -0
- package/dist/policy/access-provider.registry.js +15 -0
- package/dist/policy/access-question.d.ts +20 -0
- package/dist/policy/access-question.js +1 -0
- package/dist/policy/access-question.registry.d.ts +5 -0
- package/dist/policy/access-question.registry.js +19 -0
- package/dist/policy/access-question.runtime.d.ts +36 -0
- package/dist/policy/access-question.runtime.js +297 -0
- package/dist/policy/access-verb.table.d.ts +56 -0
- package/dist/policy/access-verb.table.js +21 -0
- package/dist/policy/access-verbs.d.ts +46 -0
- package/dist/policy/access-verbs.js +1 -0
- package/dist/policy/policy-admission.d.ts +20 -0
- package/dist/policy/policy-admission.js +409 -0
- package/dist/policy/policy-after-update.runtime.d.ts +79 -0
- package/dist/policy/policy-after-update.runtime.js +208 -0
- package/dist/policy/policy-condition.d.ts +15 -0
- package/dist/policy/policy-condition.js +36 -0
- package/dist/policy/policy-engine.d.ts +205 -0
- package/dist/policy/policy-engine.js +1 -0
- package/dist/policy/policy-named-rows.d.ts +18 -0
- package/dist/policy/policy-named-rows.js +51 -0
- package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
- package/dist/policy/policy-nested-write.runtime.js +545 -0
- package/dist/policy/policy-read.runtime.d.ts +81 -0
- package/dist/policy/policy-read.runtime.js +503 -0
- package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
- package/dist/policy/policy-reference-write.runtime.js +345 -0
- package/dist/policy/policy-request.d.ts +41 -0
- package/dist/policy/policy-request.js +63 -0
- package/dist/policy/policy-session.d.ts +106 -0
- package/dist/policy/policy-session.js +295 -0
- package/dist/policy/policy-startup.validator.d.ts +10 -0
- package/dist/policy/policy-startup.validator.js +112 -0
- package/dist/policy/policy-write.runtime.d.ts +39 -0
- package/dist/policy/policy-write.runtime.js +532 -0
- package/dist/prebuilt/core-version.generated.d.ts +2 -0
- package/dist/prebuilt/core-version.generated.js +1 -0
- package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
- package/dist/prebuilt/prebuilt-changes.js +65 -0
- package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
- package/dist/prebuilt/prebuilt-contracts.js +1 -0
- package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
- package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
- package/dist/protocol/absent-route.responder.d.ts +17 -34
- package/dist/protocol/absent-route.responder.js +53 -20
- package/dist/protocol/contract-document.responder.d.ts +5 -4
- package/dist/protocol/contract-document.responder.js +2 -2
- package/dist/protocol/http-request.decoder.d.ts +33 -13
- package/dist/protocol/http-request.decoder.js +34 -11
- package/dist/protocol/http-request.reader.d.ts +9 -6
- package/dist/protocol/http-request.reader.js +1 -0
- 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-headers.d.ts +3 -3
- package/dist/protocol/protocol-surface.d.ts +10 -5
- package/dist/protocol/protocol-surface.js +7 -0
- package/dist/protocol/protocol.binder.d.ts +66 -28
- package/dist/protocol/protocol.binder.js +16 -10
- package/dist/protocol/protocol.handler.d.ts +34 -14
- package/dist/protocol/protocol.handler.js +122 -18
- package/dist/protocol/unmounted-route.error.d.ts +4 -4
- package/dist/protocol/unmounted-route.error.js +2 -2
- package/dist/runtime/caller-data.copier.d.ts +22 -7
- package/dist/runtime/caller-data.copier.js +30 -17
- package/dist/runtime/caller-data.door.d.ts +18 -11
- package/dist/runtime/caller-data.door.js +6 -4
- package/dist/runtime/computed-read-runtime.d.ts +12 -6
- package/dist/runtime/computed-read-runtime.js +271 -71
- package/dist/runtime/computed-value.error.d.ts +7 -6
- package/dist/runtime/computed-value.error.js +5 -4
- package/dist/runtime/context-executor.runtime.d.ts +60 -0
- package/dist/runtime/context-executor.runtime.js +277 -0
- package/dist/runtime/core-class.brand.d.ts +10 -0
- package/dist/runtime/core-class.brand.js +21 -0
- package/dist/runtime/create-requirement.d.ts +34 -79
- package/dist/runtime/create-requirement.js +205 -74
- package/dist/runtime/decimal.d.ts +16 -2
- package/dist/runtime/decimal.js +22 -1
- package/dist/runtime/diagnostics-reporter.d.ts +91 -30
- package/dist/runtime/diagnostics-reporter.js +37 -1
- package/dist/runtime/error-boundary.d.ts +73 -9
- package/dist/runtime/error-boundary.js +57 -19
- package/dist/runtime/error-guidance.d.ts +12 -0
- package/dist/runtime/error-guidance.js +1 -0
- package/dist/runtime/error.catalog.d.ts +49 -0
- package/dist/runtime/error.catalog.js +49 -0
- package/dist/runtime/execution-options.d.ts +18 -2
- package/dist/runtime/field-check.evaluator.d.ts +27 -0
- package/dist/runtime/field-check.evaluator.js +521 -0
- package/dist/runtime/field-compute.d.ts +65 -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 +37 -0
- package/dist/runtime/field-stage.runtime.js +147 -0
- package/dist/runtime/field-validator.runtime.d.ts +29 -0
- package/dist/runtime/field-validator.runtime.js +126 -0
- package/dist/runtime/framework-error-class.table.d.ts +33 -0
- package/dist/runtime/framework-error-class.table.js +25 -0
- package/dist/runtime/framework-error.d.ts +68 -8
- package/dist/runtime/framework-error.factory.d.ts +4 -0
- package/dist/runtime/framework-error.factory.js +15 -0
- package/dist/runtime/framework-error.js +32 -2
- package/dist/runtime/framework-warning.emitter.d.ts +6 -0
- package/dist/runtime/framework-warning.emitter.js +8 -0
- 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 +11 -6
- package/dist/runtime/level-lifecycle.runtime.d.ts +26 -0
- package/dist/runtime/level-lifecycle.runtime.js +40 -0
- package/dist/runtime/misuse-reporter.d.ts +12 -12
- package/dist/runtime/mutation-planner.d.ts +20 -16
- package/dist/runtime/mutation-planner.js +48 -35
- package/dist/runtime/nested-write.walker.d.ts +32 -0
- package/dist/runtime/nested-write.walker.js +73 -0
- package/dist/runtime/operation-code.guidance.d.ts +6 -0
- package/dist/runtime/operation-code.guidance.js +167 -0
- package/dist/runtime/operation-request.d.ts +45 -11
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +133 -27
- package/dist/runtime/operation-runtime.js +576 -84
- package/dist/runtime/outcome-mapper.d.ts +17 -5
- package/dist/runtime/outcome-mapper.js +23 -6
- package/dist/runtime/output-validator.d.ts +11 -11
- package/dist/runtime/output-validator.js +3 -3
- package/dist/runtime/owned-execution.registry.d.ts +16 -6
- package/dist/runtime/pipe-output.validator.d.ts +43 -18
- package/dist/runtime/pipe-output.validator.js +15 -13
- package/dist/runtime/pipeline.d.ts +221 -34
- package/dist/runtime/readonly-value.d.ts +47 -0
- package/dist/runtime/readonly-value.js +189 -0
- package/dist/runtime/referential-action.d.ts +1 -1
- package/dist/runtime/request-envelope.validator.d.ts +3 -3
- package/dist/runtime/request-envelope.validator.js +12 -7
- package/dist/runtime/request-id.d.ts +1 -1
- package/dist/runtime/request-state.d.ts +14 -0
- package/dist/runtime/request-state.js +1 -0
- package/dist/runtime/request-state.resolver.d.ts +12 -0
- package/dist/runtime/request-state.resolver.js +20 -0
- package/dist/runtime/scalar-runtime.d.ts +33 -25
- package/dist/runtime/scalar-runtime.js +105 -38
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- 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 +8 -3
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +85 -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 +167 -0
- package/dist/transactions/transaction-envelope.d.ts +9 -8
- package/dist/transactions/transaction-integrity-error.d.ts +6 -6
- package/dist/transactions/transaction-integrity-error.js +7 -2
- package/dist/transactions/transaction-plan-assembler.d.ts +30 -13
- package/dist/transactions/transaction-plan-assembler.js +184 -32
- package/dist/transactions/transaction-plan-validator.d.ts +50 -25
- package/dist/transactions/transaction-plan-validator.js +96 -38
- package/dist/transactions/transaction-reference-collector.d.ts +5 -5
- package/dist/transactions/transaction-reference-resolver.d.ts +21 -3
- package/dist/transactions/transaction-reference-resolver.js +26 -14
- package/dist/transactions/transaction-reference-validator.d.ts +74 -4
- package/dist/transactions/transaction-reference-validator.js +129 -71
- package/dist/transactions/transaction-reference.d.ts +14 -14
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +22 -9
- package/dist/transactions/transaction-response.d.ts +6 -6
- package/dist/transactions/transaction-runtime.d.ts +12 -8
- package/dist/transactions/transaction-runtime.js +218 -50
- package/dist/transactions/transaction-settlement.runtime.d.ts +52 -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 +4 -2
- package/dist/transactions/transaction-slot-writer.js +2 -2
- package/dist/transactions/transaction-stage.runtime.d.ts +83 -0
- package/dist/transactions/transaction-stage.runtime.js +126 -0
- package/package.json +11 -9
- package/src/runtime/field-check.evaluator.ts +720 -0
- package/dist/config/define-fields.d.ts +0 -42
- package/dist/config/define-fields.js +0 -3
- package/dist/config/framework-behaviors-config.d.ts +0 -30
- package/dist/config/framework-fields-config.d.ts +0 -42
- package/dist/config/framework-restrictions-config.d.ts +0 -142
- package/dist/json/avz.d.ts +0 -96
- package/dist/runtime/field-behavior.d.ts +0 -48
- /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
- /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
- /package/dist/{json → avz}/index.js +0 -0
- /package/dist/{json → avz}/json-shape.registry.js +0 -0
- /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
- /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { FILTER_MODES, toOneRelinkWithRewrite, } from "../contracts/capability.js";
|
|
1
2
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
3
|
import { advertisedDirectivesAt, advertisedReducers, advertisedReducersAt, holdsAt, } from "../contracts/field.js";
|
|
3
|
-
import { isPlainRecord } from "../runtime/scalar-runtime.js";
|
|
4
|
+
import { isPlainRecord, unsentReadValueIssue, } from "../runtime/scalar-runtime.js";
|
|
4
5
|
import { routeTransactionReferenceCandidate } from "../transactions/transaction-reference.js";
|
|
5
6
|
import { isOperationFamily, } from "./operation-identity.js";
|
|
6
7
|
import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
|
|
7
|
-
import { NESTED_WRITE_SCOPE, resolveWriteScope, } from "./write-scope.resolver.js";
|
|
8
|
+
import { NESTED_WRITE_SCOPE, resolveWriteScope, TO_MANY_UPDATE_WRITE_SCOPE, } from "./write-scope.resolver.js";
|
|
8
9
|
const OPERATION_ARGUMENT_RULES = {
|
|
9
10
|
"find.first": {
|
|
10
11
|
allowed: ["where", "orderBy", "select", "include"],
|
|
@@ -153,12 +154,15 @@ function checkDepth(contract, state, depth) {
|
|
|
153
154
|
}
|
|
154
155
|
return false;
|
|
155
156
|
}
|
|
156
|
-
function validateScalarFilter(fieldName, field, value, path, state) {
|
|
157
|
+
function validateScalarFilter(contract, fieldName, field, value, path, state, depth) {
|
|
157
158
|
const supported = field.capabilities.filter;
|
|
158
159
|
if (supported === undefined) {
|
|
159
160
|
addIssue(state.issues, "V1006", path, `Filtering is not available on field "${fieldName}".`);
|
|
160
161
|
return;
|
|
161
162
|
}
|
|
163
|
+
validateScalarCondition(contract, fieldName, field, supported, value, path, state, depth);
|
|
164
|
+
}
|
|
165
|
+
function validateScalarCondition(contract, fieldName, field, supported, value, path, state, depth) {
|
|
162
166
|
if (value === null) {
|
|
163
167
|
if (!field.nullable) {
|
|
164
168
|
addIssue(state.issues, "V1001", path, `Field "${fieldName}" is not nullable.`);
|
|
@@ -187,18 +191,74 @@ function validateScalarFilter(fieldName, field, value, path, state) {
|
|
|
187
191
|
addIssue(state.issues, "V1001", path, `Filter object for field "${fieldName}" must contain an operator.`);
|
|
188
192
|
return;
|
|
189
193
|
}
|
|
194
|
+
refuseDanglingQualifiers(fieldName, value, path, state);
|
|
190
195
|
for (const operator of operators) {
|
|
191
196
|
if (!includes(supported, operator)) {
|
|
192
197
|
addIssue(state.issues, "V1006", [...path, operator], `Filter operator "${operator}" is not available on field "${fieldName}".`);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (operator === "mode") {
|
|
201
|
+
refuseUnavailableMode(field, fieldName, value, path, state);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (operator === "not") {
|
|
205
|
+
const operand = value[operator];
|
|
206
|
+
if (isPlainRecord(operand) && !checkDepth(contract, state, depth + 1)) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
validateScalarCondition(contract, fieldName, field, supported, operand, [...path, operator], state, isPlainRecord(operand) ? depth + 1 : depth);
|
|
193
210
|
}
|
|
194
211
|
}
|
|
195
212
|
}
|
|
213
|
+
function refuseDanglingQualifiers(fieldName, level, path, state) {
|
|
214
|
+
const qualifiers = DANGLING_QUALIFIERS.filter((key) => Object.hasOwn(level, key));
|
|
215
|
+
if (qualifiers.length === 0) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const compares = Object.entries(level).some(([operator, operand]) => !includes(DANGLING_QUALIFIERS, operator) &&
|
|
219
|
+
!(operator === "not" && isNegatedOperatorObject(operand, state)));
|
|
220
|
+
if (compares) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
for (const qualifier of qualifiers) {
|
|
224
|
+
addIssue(state.issues, "V1001", [...path, qualifier], `${qualifier} on field "${fieldName}" qualifies no operator: write it next to the operator it applies to (inside "not" to apply to a negated one).`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const DANGLING_QUALIFIERS = ["mode", "path"];
|
|
228
|
+
function isNegatedOperatorObject(operand, state) {
|
|
229
|
+
return (isPlainRecord(operand) &&
|
|
230
|
+
!(state.transactionReferences === true &&
|
|
231
|
+
routeTransactionReferenceCandidate(operand).kind !== "ordinary"));
|
|
232
|
+
}
|
|
233
|
+
function refuseUnavailableMode(field, fieldName, level, path, state) {
|
|
234
|
+
const mode = level.mode;
|
|
235
|
+
if (mode === "default" ||
|
|
236
|
+
typeof mode !== "string" ||
|
|
237
|
+
!includes(FILTER_MODES, mode)) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const { filterModes = [], pathFilterModes } = field.capabilities;
|
|
241
|
+
const atPath = Object.hasOwn(level, "path") && pathFilterModes !== undefined;
|
|
242
|
+
if (includes(atPath ? pathFilterModes : filterModes, mode)) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const where = atPath
|
|
246
|
+
? " at a path"
|
|
247
|
+
: pathFilterModes !== undefined && includes(pathFilterModes, mode)
|
|
248
|
+
? " without a path"
|
|
249
|
+
: "";
|
|
250
|
+
addIssue(state.issues, "V1006", [...path, "mode"], `Filter mode "${mode}" is not available on field "${fieldName}"${where}.`);
|
|
251
|
+
}
|
|
196
252
|
function validateRelationFilter(contract, fieldName, field, value, path, state, depth) {
|
|
197
253
|
const supported = field.capabilities.filter;
|
|
198
254
|
if (supported === undefined) {
|
|
199
255
|
addIssue(state.issues, "V1006", path, `Filtering is not available on relation "${fieldName}".`);
|
|
200
256
|
return;
|
|
201
257
|
}
|
|
258
|
+
if (value === undefined) {
|
|
259
|
+
state.issues.push(unsentReadValueIssue(path));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
202
262
|
if (field.cardinality === "one") {
|
|
203
263
|
if (value === null) {
|
|
204
264
|
if (!field.nullable || !includes(supported, "null")) {
|
|
@@ -238,10 +298,26 @@ function validateRelationFilter(contract, fieldName, field, value, path, state,
|
|
|
238
298
|
validateWhere(contract, field.target, value[operator], [...path, operator], state, depth + 1);
|
|
239
299
|
}
|
|
240
300
|
}
|
|
301
|
+
const UNDEFINED_ARGUMENT_MESSAGES = {
|
|
302
|
+
where: "where must not be undefined: leave the key out to mean no filter.",
|
|
303
|
+
limit: "limit must not be undefined: leave the key out to mean no limit.",
|
|
304
|
+
offset: "offset must not be undefined: leave the key out to mean no offset.",
|
|
305
|
+
cursor: "cursor must not be undefined: leave the key out to mean no cursor.",
|
|
306
|
+
};
|
|
307
|
+
const EMPTY_BOOLEAN_NODE_MESSAGE = "A boolean node must hold a condition here: an empty one matches every row, and the write would reach more rows.";
|
|
308
|
+
function isEmptyBooleanNode(value) {
|
|
309
|
+
return Array.isArray(value)
|
|
310
|
+
? value.length === 0
|
|
311
|
+
: isRecord(value) && Object.keys(value).length === 0;
|
|
312
|
+
}
|
|
241
313
|
function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
242
314
|
if (!checkDepth(contract, state, depth)) {
|
|
243
315
|
return;
|
|
244
316
|
}
|
|
317
|
+
if (where === undefined) {
|
|
318
|
+
state.issues.push(unsentReadValueIssue(path));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
245
321
|
if (!isRecord(where)) {
|
|
246
322
|
addIssue(state.issues, "V1001", path, "where must be an object.");
|
|
247
323
|
return;
|
|
@@ -252,6 +328,13 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
|
252
328
|
return;
|
|
253
329
|
}
|
|
254
330
|
for (const [key, value] of Object.entries(where)) {
|
|
331
|
+
if (state.refuseEmptyNodes === true &&
|
|
332
|
+
(key === "AND" || key === "OR" || key === "NOT") &&
|
|
333
|
+
isEmptyBooleanNode(value)) {
|
|
334
|
+
countFilterNode(contract, state);
|
|
335
|
+
addIssue(state.issues, "V1001", [...path, key], EMPTY_BOOLEAN_NODE_MESSAGE);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
255
338
|
if (key === "AND" || key === "OR") {
|
|
256
339
|
countFilterNode(contract, state);
|
|
257
340
|
if (!Array.isArray(value)) {
|
|
@@ -259,6 +342,10 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
|
259
342
|
continue;
|
|
260
343
|
}
|
|
261
344
|
value.forEach((entry, index) => {
|
|
345
|
+
if (state.refuseEmptyNodes === true && isEmptyBooleanNode(entry)) {
|
|
346
|
+
addIssue(state.issues, "V1001", [...path, key, index], EMPTY_BOOLEAN_NODE_MESSAGE);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
262
349
|
validateWhere(contract, resourceName, entry, [...path, key, index], state, depth + 1);
|
|
263
350
|
});
|
|
264
351
|
continue;
|
|
@@ -276,7 +363,7 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
|
276
363
|
}
|
|
277
364
|
const fieldPath = [...path, key];
|
|
278
365
|
if (field.kind === "scalar") {
|
|
279
|
-
validateScalarFilter(key, field, value, fieldPath, state);
|
|
366
|
+
validateScalarFilter(contract, key, field, value, fieldPath, state, depth);
|
|
280
367
|
}
|
|
281
368
|
else if (state.scalarOnly === true) {
|
|
282
369
|
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.`);
|
|
@@ -355,7 +442,9 @@ function validateOrderBy(contract, resourceName, orderBy, path, issues) {
|
|
|
355
442
|
valueKeys[1] !== "sort" ||
|
|
356
443
|
(value.sort !== "asc" && value.sort !== "desc") ||
|
|
357
444
|
(value.nulls !== "first" && value.nulls !== "last")) {
|
|
358
|
-
addIssue(issues, "V1001", fieldPath,
|
|
445
|
+
addIssue(issues, "V1001", fieldPath, Object.hasOwn(value, "$ref")
|
|
446
|
+
? `A transaction reference cannot stand in orderBy: order "${fieldName}" by "asc", "desc" or { sort, nulls }.`
|
|
447
|
+
: `Null ordering for "${fieldName}" must be exactly { sort: "asc" | "desc", nulls: "first" | "last" }.`);
|
|
359
448
|
continue;
|
|
360
449
|
}
|
|
361
450
|
if (!field.nullable || field.capabilities.orderNulls !== true) {
|
|
@@ -382,6 +471,10 @@ function validateOrderBy(contract, resourceName, orderBy, path, issues) {
|
|
|
382
471
|
return analysis;
|
|
383
472
|
}
|
|
384
473
|
function validatePaginationValue(contract, name, value, path, issues) {
|
|
474
|
+
if (value === undefined) {
|
|
475
|
+
addIssue(issues, "V1001", path, UNDEFINED_ARGUMENT_MESSAGES[name]);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
385
478
|
if (!Number.isInteger(value) || typeof value !== "number" || value < 0) {
|
|
386
479
|
addIssue(issues, "V1001", path, `${name} must be a non-negative integer.`);
|
|
387
480
|
return;
|
|
@@ -391,6 +484,10 @@ function validatePaginationValue(contract, name, value, path, issues) {
|
|
|
391
484
|
}
|
|
392
485
|
}
|
|
393
486
|
function validateCursor(contract, resourceName, cursor, orderBy, path, issues) {
|
|
487
|
+
if (cursor === undefined) {
|
|
488
|
+
addIssue(issues, "V1009", path, UNDEFINED_ARGUMENT_MESSAGES.cursor);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
394
491
|
if (!isRecord(cursor) || orderBy === undefined) {
|
|
395
492
|
addIssue(issues, "V1009", path, "Cursor pagination requires an object cursor and explicit deterministic orderBy.");
|
|
396
493
|
return;
|
|
@@ -427,6 +524,12 @@ function validateProjection(contract, resourceName, mode, value, scope, path, is
|
|
|
427
524
|
}
|
|
428
525
|
value.forEach((entry, index) => {
|
|
429
526
|
const entryPath = [...path, index];
|
|
527
|
+
if (entry === "$defaults") {
|
|
528
|
+
if (mode !== "select") {
|
|
529
|
+
addIssue(issues, "V1008", entryPath, "$defaults is a select entry: include already returns the default fields.");
|
|
530
|
+
}
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
430
533
|
if (entry === "$count") {
|
|
431
534
|
if (mode !== "select" ||
|
|
432
535
|
reducerOwner?.edge.cardinality !== "many" ||
|
|
@@ -502,6 +605,9 @@ function validateRelationProjection(contract, edge, scope, value, path, issues)
|
|
|
502
605
|
if (!includes(edge.capabilities.filter, "nested")) {
|
|
503
606
|
addIssue(issues, "V1006", [...path, "where"], "Nested returned-relation filtering is not available on this edge.");
|
|
504
607
|
}
|
|
608
|
+
else if (value.where === undefined) {
|
|
609
|
+
addIssue(issues, "V1001", [...path, "where"], UNDEFINED_ARGUMENT_MESSAGES.where);
|
|
610
|
+
}
|
|
505
611
|
else {
|
|
506
612
|
const state = {
|
|
507
613
|
issues,
|
|
@@ -575,11 +681,16 @@ function validateScalarMutation(fieldName, field, value, stage, path, issues, tr
|
|
|
575
681
|
addIssue(issues, "V1001", path, "Scalar mutation action objects may contain only $-prefixed directive keys.");
|
|
576
682
|
return;
|
|
577
683
|
}
|
|
684
|
+
let unavailable = false;
|
|
578
685
|
for (const directive of directiveKeys) {
|
|
579
686
|
if (!includes(directives, directive)) {
|
|
687
|
+
unavailable = true;
|
|
580
688
|
addIssue(issues, "V1006", [...path, directive], `Mutation directive "${directive}" is not available on field "${fieldName}".`);
|
|
581
689
|
}
|
|
582
690
|
}
|
|
691
|
+
if (!unavailable && directiveKeys.length > 1) {
|
|
692
|
+
addIssue(issues, "V1001", path, "Scalar mutation action objects may contain only one directive.");
|
|
693
|
+
}
|
|
583
694
|
}
|
|
584
695
|
function validateRelationMutationEntry(contract, edge, directive, value, path, issues, transactionReferences) {
|
|
585
696
|
const target = edge.target;
|
|
@@ -599,8 +710,8 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
599
710
|
addIssue(issues, "V1012", path, "To-many $disconnect requires one or more unique identifiers.");
|
|
600
711
|
return;
|
|
601
712
|
}
|
|
602
|
-
for (const selector of
|
|
603
|
-
validateUniqueSelector(contract, target, selector,
|
|
713
|
+
for (const { entry: selector, at } of entriesOf(edge, value, path)) {
|
|
714
|
+
validateUniqueSelector(contract, target, selector, at, issues);
|
|
604
715
|
}
|
|
605
716
|
return;
|
|
606
717
|
}
|
|
@@ -615,82 +726,81 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
615
726
|
addIssue(issues, "V1012", path, "To-many $set requires an identifier array.");
|
|
616
727
|
return;
|
|
617
728
|
}
|
|
618
|
-
for (const selector of value) {
|
|
619
|
-
validateUniqueSelector(contract, target, selector,
|
|
729
|
+
for (const { entry: selector, at } of entriesOf(edge, value, path)) {
|
|
730
|
+
validateUniqueSelector(contract, target, selector, at, issues);
|
|
620
731
|
}
|
|
621
732
|
return;
|
|
622
733
|
}
|
|
623
734
|
if (directive === "$connect") {
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
validateUniqueSelector(contract, target, selector, path, issues);
|
|
735
|
+
for (const { entry: selector, at } of entriesOf(edge, value, path)) {
|
|
736
|
+
validateUniqueSelector(contract, target, selector, at, issues);
|
|
627
737
|
}
|
|
628
738
|
return;
|
|
629
739
|
}
|
|
630
740
|
if (directive === "$create") {
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, path, issues, transactionReferences);
|
|
741
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
742
|
+
validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, at, issues, transactionReferences);
|
|
634
743
|
}
|
|
635
744
|
return;
|
|
636
745
|
}
|
|
637
746
|
if (directive === "$connectOrCreate") {
|
|
638
|
-
const
|
|
639
|
-
for (const entry of entries) {
|
|
747
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
640
748
|
if (!isRecord(entry) || !("where" in entry) || !("create" in entry)) {
|
|
641
|
-
addIssue(issues, "V1012",
|
|
749
|
+
addIssue(issues, "V1012", at, "$connectOrCreate requires where and create.");
|
|
642
750
|
continue;
|
|
643
751
|
}
|
|
644
|
-
validateUniqueSelector(contract, target, entry.where, [...
|
|
645
|
-
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...
|
|
752
|
+
validateUniqueSelector(contract, target, entry.where, [...at, "where"], issues);
|
|
753
|
+
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...at, "create"], issues, transactionReferences);
|
|
646
754
|
}
|
|
647
755
|
return;
|
|
648
756
|
}
|
|
649
757
|
if (directive === "$update") {
|
|
650
|
-
const
|
|
651
|
-
for (const entry of entries) {
|
|
758
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
652
759
|
if (!isRecord(entry) || !("data" in entry)) {
|
|
653
|
-
addIssue(issues, "V1012",
|
|
760
|
+
addIssue(issues, "V1012", at, "$update requires a data object.");
|
|
654
761
|
continue;
|
|
655
762
|
}
|
|
656
763
|
if (edge.cardinality === "many" && !("where" in entry)) {
|
|
657
|
-
addIssue(issues, "V1012",
|
|
764
|
+
addIssue(issues, "V1012", at, "To-many $update requires where.");
|
|
658
765
|
continue;
|
|
659
766
|
}
|
|
660
767
|
if ("where" in entry) {
|
|
661
768
|
const state = {
|
|
662
769
|
issues,
|
|
663
|
-
structuralRoot: [...
|
|
770
|
+
structuralRoot: [...at, "where"],
|
|
664
771
|
transactionReferences,
|
|
665
772
|
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
773
|
+
...(edge.cardinality === "many" ? { refuseEmptyNodes: true } : {}),
|
|
666
774
|
booleanFilterNodes: 0,
|
|
667
775
|
nestingExceeded: false,
|
|
668
776
|
booleanNodesExceeded: false,
|
|
669
777
|
};
|
|
670
|
-
validateWhere(contract, target, entry.where, [...
|
|
778
|
+
validateWhere(contract, target, entry.where, [...at, "where"], state, 1);
|
|
671
779
|
}
|
|
672
|
-
validateMutationData(contract, target, entry.data, "update",
|
|
780
|
+
validateMutationData(contract, target, entry.data, "update", edge.cardinality === "many"
|
|
781
|
+
? TO_MANY_UPDATE_WRITE_SCOPE
|
|
782
|
+
: NESTED_WRITE_SCOPE, [...at, "data"], issues, transactionReferences);
|
|
673
783
|
}
|
|
674
784
|
return;
|
|
675
785
|
}
|
|
676
786
|
if (directive === "$delete") {
|
|
677
|
-
const
|
|
678
|
-
for (const entry of entries) {
|
|
787
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
679
788
|
if (edge.cardinality === "many") {
|
|
680
789
|
if (!isRecord(entry) || !("where" in entry)) {
|
|
681
|
-
addIssue(issues, "V1012",
|
|
790
|
+
addIssue(issues, "V1012", at, "To-many $delete requires where.");
|
|
682
791
|
continue;
|
|
683
792
|
}
|
|
684
793
|
const state = {
|
|
685
794
|
issues,
|
|
686
|
-
structuralRoot: [...
|
|
795
|
+
structuralRoot: [...at, "where"],
|
|
687
796
|
transactionReferences,
|
|
688
797
|
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
798
|
+
refuseEmptyNodes: true,
|
|
689
799
|
booleanFilterNodes: 0,
|
|
690
800
|
nestingExceeded: false,
|
|
691
801
|
booleanNodesExceeded: false,
|
|
692
802
|
};
|
|
693
|
-
validateWhere(contract, target, entry.where, [...
|
|
803
|
+
validateWhere(contract, target, entry.where, [...at, "where"], state, 1);
|
|
694
804
|
}
|
|
695
805
|
else if (entry !== true &&
|
|
696
806
|
(!isRecord(entry) || Object.keys(entry).some((key) => key !== "where"))) {
|
|
@@ -712,23 +822,34 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
712
822
|
return;
|
|
713
823
|
}
|
|
714
824
|
if (directive === "$upsert") {
|
|
715
|
-
const
|
|
716
|
-
for (const entry of entries) {
|
|
825
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
717
826
|
if (!isRecord(entry) ||
|
|
718
827
|
!("create" in entry) ||
|
|
719
828
|
!("update" in entry) ||
|
|
720
829
|
(edge.cardinality === "many" && !("where" in entry))) {
|
|
721
|
-
addIssue(issues, "V1012",
|
|
830
|
+
addIssue(issues, "V1012", at, "$upsert requires create/update and requires where on to-many relations.");
|
|
722
831
|
continue;
|
|
723
832
|
}
|
|
724
833
|
if ("where" in entry) {
|
|
725
|
-
validateUniqueSelector(contract, target, entry.where, [...
|
|
834
|
+
validateUniqueSelector(contract, target, entry.where, [...at, "where"], issues);
|
|
726
835
|
}
|
|
727
|
-
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...
|
|
728
|
-
validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...
|
|
836
|
+
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...at, "create"], issues, transactionReferences);
|
|
837
|
+
validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...at, "update"], issues, transactionReferences);
|
|
729
838
|
}
|
|
730
839
|
}
|
|
731
840
|
}
|
|
841
|
+
function entriesOf(edge, value, path) {
|
|
842
|
+
return edge.cardinality === "many" && Array.isArray(value)
|
|
843
|
+
? value.map((entry, index) => ({ entry, at: [...path, index] }))
|
|
844
|
+
: [{ entry: value, at: path }];
|
|
845
|
+
}
|
|
846
|
+
function refuseToOneRelinkWithRewrite(fieldName, field, value, path, issues) {
|
|
847
|
+
const paired = field.cardinality === "one" ? toOneRelinkWithRewrite(value) : undefined;
|
|
848
|
+
if (paired === undefined) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
addIssue(issues, "V1012", path, `To-one relation "${fieldName}" cannot combine ${paired.rewrite.join("/")} with ${paired.relink.join("/")} in one write: the row it would update is the newly linked one. Relink in one write and update in another.`);
|
|
852
|
+
}
|
|
732
853
|
function validateRelationMutation(contract, fieldName, field, value, stage, scope, path, issues, transactionReferences) {
|
|
733
854
|
const directives = advertisedDirectivesAt(field.capabilities[stage], scope);
|
|
734
855
|
if (directives === undefined) {
|
|
@@ -739,6 +860,7 @@ function validateRelationMutation(contract, fieldName, field, value, stage, scop
|
|
|
739
860
|
addIssue(issues, "V1012", path, `Relation "${fieldName}" mutation value must be a directive object.`);
|
|
740
861
|
return;
|
|
741
862
|
}
|
|
863
|
+
refuseToOneRelinkWithRewrite(fieldName, field, value, path, issues);
|
|
742
864
|
for (const [directive, directiveValue] of Object.entries(value)) {
|
|
743
865
|
const directivePath = [...path, directive];
|
|
744
866
|
if (!directive.startsWith("$") || !includes(directives, directive)) {
|
|
@@ -806,6 +928,14 @@ function validateMutationArguments(contract, resourceName, request, args, issues
|
|
|
806
928
|
}
|
|
807
929
|
}
|
|
808
930
|
}
|
|
931
|
+
function emptyNodeRefusalOf(request) {
|
|
932
|
+
return (request.family === "update" || request.family === "delete") &&
|
|
933
|
+
(request.variant === "many" ||
|
|
934
|
+
request.variant === "count" ||
|
|
935
|
+
request.variant === "first")
|
|
936
|
+
? { refuseEmptyNodes: true }
|
|
937
|
+
: {};
|
|
938
|
+
}
|
|
809
939
|
function isUniqueOperation(request) {
|
|
810
940
|
return (request.variant === "unique" &&
|
|
811
941
|
(request.family === "find" ||
|
|
@@ -843,11 +973,15 @@ export function validateOperationArguments(contract, request, options) {
|
|
|
843
973
|
if (isUniqueOperation(request)) {
|
|
844
974
|
validateUniqueSelector(contract, request.resource, request.arguments.where, ["arguments", "where"], issues);
|
|
845
975
|
}
|
|
976
|
+
else if (request.arguments.where === undefined) {
|
|
977
|
+
addIssue(issues, "V1001", ["arguments", "where"], UNDEFINED_ARGUMENT_MESSAGES.where);
|
|
978
|
+
}
|
|
846
979
|
else {
|
|
847
980
|
const state = {
|
|
848
981
|
issues,
|
|
849
982
|
structuralRoot: ["arguments", "where"],
|
|
850
983
|
transactionReferences: options?.transactionReferences === true,
|
|
984
|
+
...emptyNodeRefusalOf(request),
|
|
851
985
|
booleanFilterNodes: 0,
|
|
852
986
|
nestingExceeded: false,
|
|
853
987
|
booleanNodesExceeded: false,
|
|
@@ -1,10 +1,10 @@
|
|
|
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 {
|
|
5
|
-
export type { OperationValidationOptions,
|
|
4
|
+
import type { AvValidationIssue } from "./validation-code.js";
|
|
5
|
+
export type { OperationValidationOptions, SemanticOperationArguments, } from "./operation-validator-core.js";
|
|
6
6
|
/** The key of a request's operation identity that makes it unavailable. */
|
|
7
|
-
export declare function unavailableOperationKey(contract:
|
|
7
|
+
export declare function unavailableOperationKey(contract: AvContract, request: {
|
|
8
8
|
readonly resource: string;
|
|
9
9
|
readonly family: string;
|
|
10
10
|
}): "family" | "variant";
|
|
@@ -15,25 +15,25 @@ export declare function unavailableOperationKey(contract: Contract, request: {
|
|
|
15
15
|
* {@link unavailableOperationKey}). The one spelling — the protocol's absence
|
|
16
16
|
* answers build theirs with it, so a caller cannot tell which layer answered.
|
|
17
17
|
*/
|
|
18
|
-
export declare function operationUnavailableIssue(contract:
|
|
18
|
+
export declare function operationUnavailableIssue(contract: AvContract, request: {
|
|
19
19
|
readonly resource: string;
|
|
20
20
|
readonly family: string;
|
|
21
21
|
readonly variant: string;
|
|
22
|
-
}):
|
|
22
|
+
}): AvValidationIssue;
|
|
23
23
|
/**
|
|
24
24
|
* The availability answer alone — `V1006` when the active Contract does not advertise
|
|
25
25
|
* the operation on a Resource it has — read from the request's identity, never its
|
|
26
26
|
* arguments. A door that refuses unreadable arguments asks this first, so an
|
|
27
27
|
* unadvertised operation answers `A2002` whatever its arguments hold.
|
|
28
28
|
*/
|
|
29
|
-
export declare function findOperationAvailabilityIssue(contract:
|
|
29
|
+
export declare function findOperationAvailabilityIssue(contract: AvContract, request: AvOperationIdentity & {
|
|
30
30
|
readonly resource: string;
|
|
31
|
-
}):
|
|
31
|
+
}): AvValidationIssue | undefined;
|
|
32
32
|
/**
|
|
33
33
|
* Validates one standard operation's arguments against a Contract. Operation
|
|
34
34
|
* availability and request limits are checked before the arguments' grammar.
|
|
35
35
|
*/
|
|
36
|
-
export declare function validateOperationArguments(contract:
|
|
36
|
+
export declare function validateOperationArguments(contract: AvContract, request: AvOperationIdentity & {
|
|
37
37
|
readonly resource: string;
|
|
38
38
|
readonly arguments: unknown;
|
|
39
39
|
}, options?: OperationValidationOptions): OperationValidationResult;
|
|
@@ -1,7 +1,7 @@
|
|
|
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.
|
|
@@ -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;
|
|
@@ -1,19 +1,19 @@
|
|
|
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
|
type Readable = Readonly<Record<string, unknown>>;
|
|
5
5
|
/** What one walk of an operation's arguments found. */
|
|
6
|
-
|
|
6
|
+
type StructuralLimitsFinding = {
|
|
7
7
|
/** The nesting issue, which wins over any boolean-node issue. */
|
|
8
|
-
readonly nesting:
|
|
8
|
+
readonly nesting: AvValidationIssue | undefined;
|
|
9
9
|
/** The boolean-node issue, when there is no nesting issue. */
|
|
10
|
-
readonly booleanNodes:
|
|
10
|
+
readonly booleanNodes: AvValidationIssue | undefined;
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
13
|
* Enforces the structural limits on one operation's argument object: the nesting
|
|
14
14
|
* issue if there is one, otherwise the boolean-node issue if there is one.
|
|
15
15
|
*/
|
|
16
|
-
export declare function findStructuralLimitIssues(contract:
|
|
16
|
+
export declare function findStructuralLimitIssues(contract: AvContract, request: AvOperationIdentity & {
|
|
17
17
|
readonly resource: string;
|
|
18
18
|
}, args: Readable): StructuralLimitsFinding;
|
|
19
19
|
export {};
|