@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
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
export const FIELD_CHECK_SUBJECTS = {
|
|
2
|
+
string: "string",
|
|
3
|
+
int: "number",
|
|
4
|
+
float: "number",
|
|
5
|
+
bigint: "bigint",
|
|
6
|
+
decimal: "decimal",
|
|
7
|
+
datetime: "datetime",
|
|
8
|
+
bytes: "bytes",
|
|
9
|
+
};
|
|
10
|
+
const DATE_SOURCE = "(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))";
|
|
11
|
+
const HHMM = "(?:[01]\\d|2[0-3]):[0-5]\\d";
|
|
12
|
+
const IPV6_ALPHABET = /^[0-9a-fA-F:.]+$/;
|
|
13
|
+
const CREDIT_CARD = /^\d(?:[ -]?\d){11,18}$/;
|
|
14
|
+
const IBAN = /^[A-Z]{2}(?!00|01|99)\d{2}[A-Z0-9]{11,30}$/;
|
|
15
|
+
const FORMAT_PATTERNS = {
|
|
16
|
+
email: /^(?:[A-Za-z0-9_'+-]+\.)*[A-Za-z0-9_'+-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9-]*\.)+[A-Za-z]{2,}$/,
|
|
17
|
+
emoji: new RegExp("^(?=[\\s\\S]*[\\p{Extended_Pictographic}\\p{Regional_Indicator}\\u20E3])[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$", "u"),
|
|
18
|
+
uuid: /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/,
|
|
19
|
+
guid: /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/,
|
|
20
|
+
nanoid: /^[a-zA-Z0-9_-]{21}$/,
|
|
21
|
+
cuid: /^[cC][0-9a-z]{6,}$/,
|
|
22
|
+
cuid2: /^[0-9a-z]+$/,
|
|
23
|
+
ulid: /^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$/,
|
|
24
|
+
xid: /^[0-9a-vA-V]{20}$/,
|
|
25
|
+
ksuid: /^[A-Za-z0-9]{27}$/,
|
|
26
|
+
datetime: new RegExp(`^${DATE_SOURCE}T(?:${HHMM}:[0-5]\\d(?:\\.\\d+)?(?:Z))$`),
|
|
27
|
+
date: new RegExp(`^${DATE_SOURCE}$`),
|
|
28
|
+
time: new RegExp(`^${HHMM}(?::[0-5]\\d(?:\\.\\d+)?)?$`),
|
|
29
|
+
duration: /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/,
|
|
30
|
+
ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,
|
|
31
|
+
cidrv4: /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/,
|
|
32
|
+
e164: /^\+[1-9]\d{6,14}$/,
|
|
33
|
+
};
|
|
34
|
+
const platform = globalThis;
|
|
35
|
+
function canParseUrl(input) {
|
|
36
|
+
const Url = platform.URL;
|
|
37
|
+
if (Url === undefined) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
if (typeof Url.canParse === "function") {
|
|
42
|
+
return Url.canParse(input);
|
|
43
|
+
}
|
|
44
|
+
new Url(input);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function decodeBase64(value) {
|
|
52
|
+
if (platform.atob === undefined) {
|
|
53
|
+
throw new TypeError("No atob is available here.");
|
|
54
|
+
}
|
|
55
|
+
return platform.atob(value);
|
|
56
|
+
}
|
|
57
|
+
function isIpv6(value) {
|
|
58
|
+
return IPV6_ALPHABET.test(value) && canParseUrl(`http://[${value}]`);
|
|
59
|
+
}
|
|
60
|
+
function isCidrv6(value) {
|
|
61
|
+
const parts = value.split("/");
|
|
62
|
+
if (parts.length !== 2) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const [address, prefix] = parts;
|
|
66
|
+
const bits = Number(prefix);
|
|
67
|
+
return (prefix !== "" &&
|
|
68
|
+
`${bits}` === prefix &&
|
|
69
|
+
bits >= 0 &&
|
|
70
|
+
bits <= 128 &&
|
|
71
|
+
isIpv6(address));
|
|
72
|
+
}
|
|
73
|
+
function isBase64(value) {
|
|
74
|
+
if (value === "") {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
if (/\s/.test(value) || value.length % 4 !== 0) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
decodeBase64(value);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function isBase64Url(value) {
|
|
89
|
+
if (!/^[A-Za-z0-9_-]*$/.test(value)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
const base64 = value.replace(/[-_]/g, (char) => (char === "-" ? "+" : "/"));
|
|
93
|
+
return isBase64(base64.padEnd(Math.ceil(base64.length / 4) * 4, "="));
|
|
94
|
+
}
|
|
95
|
+
function isLuhn(digits) {
|
|
96
|
+
let length = digits.length;
|
|
97
|
+
let bit = 1;
|
|
98
|
+
let sum = 0;
|
|
99
|
+
while (length) {
|
|
100
|
+
const value = digits.charCodeAt(--length) - 48;
|
|
101
|
+
bit ^= 1;
|
|
102
|
+
sum += bit ? ([0, 2, 4, 6, 8, 1, 3, 5, 7, 9][value] ?? 0) : value;
|
|
103
|
+
}
|
|
104
|
+
return sum % 10 === 0;
|
|
105
|
+
}
|
|
106
|
+
function isIbanChecksum(iban) {
|
|
107
|
+
let remainder = 0;
|
|
108
|
+
const step = (code) => {
|
|
109
|
+
remainder =
|
|
110
|
+
(code >= 65
|
|
111
|
+
? remainder * 100 + (code - 55)
|
|
112
|
+
: remainder * 10 + (code - 48)) % 97;
|
|
113
|
+
};
|
|
114
|
+
for (let index = 4; index < iban.length; index += 1) {
|
|
115
|
+
step(iban.charCodeAt(index));
|
|
116
|
+
}
|
|
117
|
+
for (let index = 0; index < 4; index += 1) {
|
|
118
|
+
step(iban.charCodeAt(index));
|
|
119
|
+
}
|
|
120
|
+
return remainder === 1;
|
|
121
|
+
}
|
|
122
|
+
function isJwt(token) {
|
|
123
|
+
try {
|
|
124
|
+
const parts = token.split(".");
|
|
125
|
+
if (parts.length !== 3 || !parts[0]) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
const header = JSON.parse(decodeBase64(parts[0]));
|
|
129
|
+
if ("typ" in header && header.typ !== "JWT") {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
return Boolean(header.alg);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function isJsonString(value) {
|
|
139
|
+
try {
|
|
140
|
+
JSON.parse(value);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function matchesFormat(format, value) {
|
|
148
|
+
switch (format) {
|
|
149
|
+
case "url":
|
|
150
|
+
return canParseUrl(value.trim());
|
|
151
|
+
case "ipv6":
|
|
152
|
+
return isIpv6(value);
|
|
153
|
+
case "cidrv6":
|
|
154
|
+
return isCidrv6(value);
|
|
155
|
+
case "base64":
|
|
156
|
+
return isBase64(value);
|
|
157
|
+
case "base64url":
|
|
158
|
+
return isBase64Url(value);
|
|
159
|
+
case "credit_card":
|
|
160
|
+
return CREDIT_CARD.test(value) && isLuhn(value.replace(/[- ]/g, ""));
|
|
161
|
+
case "iban":
|
|
162
|
+
return IBAN.test(value) && isIbanChecksum(value);
|
|
163
|
+
case "jwt":
|
|
164
|
+
return isJwt(value);
|
|
165
|
+
case "json_string":
|
|
166
|
+
return isJsonString(value);
|
|
167
|
+
default: {
|
|
168
|
+
return FORMAT_PATTERNS[format]?.test(value) === true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const DECIMAL = /^(-?)(\d+)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
|
173
|
+
function decimalParts(text) {
|
|
174
|
+
const match = DECIMAL.exec(text);
|
|
175
|
+
if (match === null) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
const [, sign, whole = "", fraction = "", power = "0"] = match;
|
|
179
|
+
const all = `${whole}${fraction}`;
|
|
180
|
+
const leading = all.length - all.replace(/^0+/, "").length;
|
|
181
|
+
const digits = all.slice(leading).replace(/0+$/, "");
|
|
182
|
+
if (digits === "") {
|
|
183
|
+
return { negative: false, digits: "", exponent: 0 };
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
negative: sign === "-",
|
|
187
|
+
digits,
|
|
188
|
+
exponent: whole.length - 1 - leading + Number(power),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function compareDecimals(a, b) {
|
|
192
|
+
const signOf = (parts) => parts.digits === "" ? 0 : parts.negative ? -1 : 1;
|
|
193
|
+
if (signOf(a) !== signOf(b)) {
|
|
194
|
+
return Math.sign(signOf(a) - signOf(b));
|
|
195
|
+
}
|
|
196
|
+
if (signOf(a) === 0) {
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
199
|
+
let magnitude = 0;
|
|
200
|
+
if (a.exponent !== b.exponent) {
|
|
201
|
+
magnitude = a.exponent > b.exponent ? 1 : -1;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const width = Math.max(a.digits.length, b.digits.length);
|
|
205
|
+
const left = a.digits.padEnd(width, "0");
|
|
206
|
+
const right = b.digits.padEnd(width, "0");
|
|
207
|
+
magnitude = left === right ? 0 : left > right ? 1 : -1;
|
|
208
|
+
}
|
|
209
|
+
return a.negative ? -magnitude : magnitude;
|
|
210
|
+
}
|
|
211
|
+
function modPow(base, power, modulus) {
|
|
212
|
+
let result = BigInt(1) % modulus;
|
|
213
|
+
let factor = base % modulus;
|
|
214
|
+
let remaining = power;
|
|
215
|
+
while (remaining > 0) {
|
|
216
|
+
if (remaining % 2 === 1) {
|
|
217
|
+
result = (result * factor) % modulus;
|
|
218
|
+
}
|
|
219
|
+
factor = (factor * factor) % modulus;
|
|
220
|
+
remaining = Math.floor(remaining / 2);
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
function isDecimalMultiple(a, b) {
|
|
225
|
+
if (b.digits === "") {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
if (a.digits === "") {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
const scaleA = a.exponent - (a.digits.length - 1);
|
|
232
|
+
const scaleB = b.exponent - (b.digits.length - 1);
|
|
233
|
+
if (!Number.isSafeInteger(scaleA) || !Number.isSafeInteger(scaleB)) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
const mantissaA = BigInt(a.digits);
|
|
237
|
+
const mantissaB = BigInt(b.digits);
|
|
238
|
+
if (scaleA >= scaleB) {
|
|
239
|
+
return (((mantissaA % mantissaB) *
|
|
240
|
+
modPow(BigInt(10), scaleA - scaleB, mantissaB)) %
|
|
241
|
+
mantissaB ===
|
|
242
|
+
BigInt(0));
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
function floatRemainder(value, step) {
|
|
247
|
+
const ratio = value / step;
|
|
248
|
+
const rounded = Math.round(ratio);
|
|
249
|
+
const tolerance = 4 * Number.EPSILON * Math.max(Math.abs(ratio), 1);
|
|
250
|
+
return Math.abs(ratio - rounded) < tolerance ? 0 : ratio - rounded;
|
|
251
|
+
}
|
|
252
|
+
function codePoints(value) {
|
|
253
|
+
let count = value.length;
|
|
254
|
+
for (let index = 0; index < value.length - 1; index += 1) {
|
|
255
|
+
if ((value.charCodeAt(index) & 0xfc00) === 0xd800 &&
|
|
256
|
+
(value.charCodeAt(index + 1) & 0xfc00) === 0xdc00) {
|
|
257
|
+
count -= 1;
|
|
258
|
+
index += 1;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return count;
|
|
262
|
+
}
|
|
263
|
+
const patterns = new WeakMap();
|
|
264
|
+
function patternOf(check) {
|
|
265
|
+
let pattern = patterns.get(check);
|
|
266
|
+
if (pattern === undefined) {
|
|
267
|
+
pattern = new RegExp(check.pattern.source, check.pattern.flags);
|
|
268
|
+
patterns.set(check, pattern);
|
|
269
|
+
}
|
|
270
|
+
pattern.lastIndex = 0;
|
|
271
|
+
return pattern;
|
|
272
|
+
}
|
|
273
|
+
function passesFormat(check, value) {
|
|
274
|
+
switch (check.format) {
|
|
275
|
+
case "regex":
|
|
276
|
+
return patternOf(check).test(value);
|
|
277
|
+
case "includes":
|
|
278
|
+
return value.includes(check.includes);
|
|
279
|
+
case "starts_with":
|
|
280
|
+
return value.startsWith(check.prefix);
|
|
281
|
+
case "ends_with":
|
|
282
|
+
return value.endsWith(check.suffix);
|
|
283
|
+
case "lowercase":
|
|
284
|
+
return /^[^A-Z]*$/.test(value);
|
|
285
|
+
case "uppercase":
|
|
286
|
+
return /^[^a-z]*$/.test(value);
|
|
287
|
+
default:
|
|
288
|
+
return matchesFormat(check.format, value);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function compareToBound(value, bound, subject) {
|
|
292
|
+
switch (subject) {
|
|
293
|
+
case "number":
|
|
294
|
+
return typeof value === "number" && typeof bound === "number"
|
|
295
|
+
? Math.sign(value - bound)
|
|
296
|
+
: undefined;
|
|
297
|
+
case "bigint": {
|
|
298
|
+
if (typeof value !== "bigint") {
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
const limit = BigInt(bound);
|
|
302
|
+
return value === limit ? 0 : value > limit ? 1 : -1;
|
|
303
|
+
}
|
|
304
|
+
case "decimal": {
|
|
305
|
+
const left = decimalParts(String(value));
|
|
306
|
+
const right = decimalParts(String(bound));
|
|
307
|
+
return left === undefined || right === undefined
|
|
308
|
+
? undefined
|
|
309
|
+
: compareDecimals(left, right);
|
|
310
|
+
}
|
|
311
|
+
case "datetime":
|
|
312
|
+
return value instanceof Date
|
|
313
|
+
? Math.sign(value.getTime() - Date.parse(String(bound)))
|
|
314
|
+
: undefined;
|
|
315
|
+
default:
|
|
316
|
+
return undefined;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function isMultiple(value, step, subject) {
|
|
320
|
+
switch (subject) {
|
|
321
|
+
case "number":
|
|
322
|
+
return typeof value === "number" && typeof step === "number"
|
|
323
|
+
? floatRemainder(value, step) === 0
|
|
324
|
+
: undefined;
|
|
325
|
+
case "bigint": {
|
|
326
|
+
if (typeof value !== "bigint") {
|
|
327
|
+
return undefined;
|
|
328
|
+
}
|
|
329
|
+
const divisor = BigInt(step);
|
|
330
|
+
return divisor !== BigInt(0) && value % divisor === BigInt(0);
|
|
331
|
+
}
|
|
332
|
+
case "decimal": {
|
|
333
|
+
const left = decimalParts(String(value));
|
|
334
|
+
const right = decimalParts(String(step));
|
|
335
|
+
return left === undefined || right === undefined
|
|
336
|
+
? undefined
|
|
337
|
+
: isDecimalMultiple(left, right);
|
|
338
|
+
}
|
|
339
|
+
default:
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
export function passesFieldCheck(check, value, subject) {
|
|
344
|
+
switch (check.check) {
|
|
345
|
+
case "less_than":
|
|
346
|
+
case "greater_than": {
|
|
347
|
+
const order = compareToBound(value, check.value, subject);
|
|
348
|
+
if (order === undefined) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
const signed = check.check === "less_than" ? -order : order;
|
|
352
|
+
return signed > 0 || (check.inclusive && signed === 0);
|
|
353
|
+
}
|
|
354
|
+
case "multiple_of":
|
|
355
|
+
return isMultiple(value, check.value, subject) ?? true;
|
|
356
|
+
case "max_length":
|
|
357
|
+
case "min_length":
|
|
358
|
+
case "length_equals": {
|
|
359
|
+
const length = Array.isArray(value)
|
|
360
|
+
? value.length
|
|
361
|
+
: typeof value === "string"
|
|
362
|
+
? codePoints(value)
|
|
363
|
+
: undefined;
|
|
364
|
+
if (length === undefined) {
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
return check.check === "max_length"
|
|
368
|
+
? length <= check.maximum
|
|
369
|
+
: check.check === "min_length"
|
|
370
|
+
? length >= check.minimum
|
|
371
|
+
: length === check.length;
|
|
372
|
+
}
|
|
373
|
+
case "string_format":
|
|
374
|
+
return typeof value === "string" ? passesFormat(check, value) : true;
|
|
375
|
+
case "max_size":
|
|
376
|
+
case "min_size":
|
|
377
|
+
case "size_equals": {
|
|
378
|
+
if (!(value instanceof Uint8Array)) {
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
const size = value.byteLength;
|
|
382
|
+
return check.check === "max_size"
|
|
383
|
+
? size <= check.maximum
|
|
384
|
+
: check.check === "min_size"
|
|
385
|
+
? size >= check.minimum
|
|
386
|
+
: size === check.size;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const FORMAT_LABELS = {
|
|
391
|
+
email: "an email address",
|
|
392
|
+
url: "a URL",
|
|
393
|
+
emoji: "emoji",
|
|
394
|
+
uuid: "a UUID",
|
|
395
|
+
guid: "a GUID",
|
|
396
|
+
nanoid: "a Nano ID",
|
|
397
|
+
cuid: "a CUID",
|
|
398
|
+
cuid2: "a CUID2",
|
|
399
|
+
ulid: "a ULID",
|
|
400
|
+
xid: "an XID",
|
|
401
|
+
ksuid: "a KSUID",
|
|
402
|
+
datetime: "an ISO 8601 date-time in UTC",
|
|
403
|
+
date: "an ISO 8601 date",
|
|
404
|
+
time: "an ISO 8601 time",
|
|
405
|
+
duration: "an ISO 8601 duration",
|
|
406
|
+
ipv4: "an IPv4 address",
|
|
407
|
+
ipv6: "an IPv6 address",
|
|
408
|
+
cidrv4: "an IPv4 CIDR block",
|
|
409
|
+
cidrv6: "an IPv6 CIDR block",
|
|
410
|
+
base64: "base64",
|
|
411
|
+
base64url: "base64url",
|
|
412
|
+
json_string: "a JSON string",
|
|
413
|
+
e164: "an E.164 phone number",
|
|
414
|
+
credit_card: "a credit card number",
|
|
415
|
+
iban: "an IBAN",
|
|
416
|
+
jwt: "a JWT",
|
|
417
|
+
};
|
|
418
|
+
function plural(count, one, many) {
|
|
419
|
+
return `${count} ${count === 1 ? one : many}`;
|
|
420
|
+
}
|
|
421
|
+
function formatMessage(check) {
|
|
422
|
+
switch (check.format) {
|
|
423
|
+
case "regex":
|
|
424
|
+
return `Value must match the pattern /${check.pattern.source}/${check.pattern.flags}.`;
|
|
425
|
+
case "includes":
|
|
426
|
+
return `Value must include ${JSON.stringify(check.includes)}.`;
|
|
427
|
+
case "starts_with":
|
|
428
|
+
return `Value must start with ${JSON.stringify(check.prefix)}.`;
|
|
429
|
+
case "ends_with":
|
|
430
|
+
return `Value must end with ${JSON.stringify(check.suffix)}.`;
|
|
431
|
+
case "lowercase":
|
|
432
|
+
return "Value must be lowercase.";
|
|
433
|
+
case "uppercase":
|
|
434
|
+
return "Value must be uppercase.";
|
|
435
|
+
default:
|
|
436
|
+
return `Value must be ${FORMAT_LABELS[check.format]}.`;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function boundMessage(check, subject) {
|
|
440
|
+
const bound = String(check.value);
|
|
441
|
+
if (subject === "datetime") {
|
|
442
|
+
return check.check === "less_than"
|
|
443
|
+
? `Value must be ${check.inclusive ? "on or before" : "before"} ${bound}.`
|
|
444
|
+
: `Value must be ${check.inclusive ? "on or after" : "after"} ${bound}.`;
|
|
445
|
+
}
|
|
446
|
+
return check.check === "less_than"
|
|
447
|
+
? `Value must be ${check.inclusive ? "at most" : "less than"} ${bound}.`
|
|
448
|
+
: `Value must be ${check.inclusive ? "at least" : "greater than"} ${bound}.`;
|
|
449
|
+
}
|
|
450
|
+
function messageOf(check, subject) {
|
|
451
|
+
switch (check.check) {
|
|
452
|
+
case "less_than":
|
|
453
|
+
case "greater_than":
|
|
454
|
+
return boundMessage(check, subject);
|
|
455
|
+
case "multiple_of":
|
|
456
|
+
return `Value must be a multiple of ${check.value}.`;
|
|
457
|
+
case "max_length":
|
|
458
|
+
return check.list === true
|
|
459
|
+
? `List must have at most ${plural(check.maximum, "entry", "entries")}.`
|
|
460
|
+
: `Value must be at most ${plural(check.maximum, "character", "characters")} long.`;
|
|
461
|
+
case "min_length":
|
|
462
|
+
return check.list === true
|
|
463
|
+
? `List must have at least ${plural(check.minimum, "entry", "entries")}.`
|
|
464
|
+
: `Value must be at least ${plural(check.minimum, "character", "characters")} long.`;
|
|
465
|
+
case "length_equals":
|
|
466
|
+
return `Value must be exactly ${plural(check.length, "character", "characters")} long.`;
|
|
467
|
+
case "string_format":
|
|
468
|
+
return formatMessage(check);
|
|
469
|
+
case "max_size":
|
|
470
|
+
return `Value must be at most ${plural(check.maximum, "byte", "bytes")}.`;
|
|
471
|
+
case "min_size":
|
|
472
|
+
return `Value must be at least ${plural(check.minimum, "byte", "bytes")}.`;
|
|
473
|
+
case "size_equals":
|
|
474
|
+
return `Value must be exactly ${plural(check.size, "byte", "bytes")}.`;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
export function fieldCheckIssue(check, subject, path) {
|
|
478
|
+
const { check: name, ...params } = check;
|
|
479
|
+
const code = name === "string_format" ? "V1003" : "V1004";
|
|
480
|
+
return {
|
|
481
|
+
code,
|
|
482
|
+
path,
|
|
483
|
+
message: messageOf(check, subject),
|
|
484
|
+
check: name,
|
|
485
|
+
params,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
export function fieldCheckIssues(checks, value, subject, path, list) {
|
|
489
|
+
if (checks.length === 0 || value === null || value === undefined) {
|
|
490
|
+
return [];
|
|
491
|
+
}
|
|
492
|
+
const issues = [];
|
|
493
|
+
if (list && Array.isArray(value)) {
|
|
494
|
+
for (const check of checks) {
|
|
495
|
+
if (isListCheck(check) && !passesFieldCheck(check, value, subject)) {
|
|
496
|
+
issues.push(fieldCheckIssue(check, subject, path));
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
for (const [index, entry] of value.entries()) {
|
|
500
|
+
issues.push(...entryCheckIssues(checks, entry, subject, [...path, index]));
|
|
501
|
+
}
|
|
502
|
+
return issues;
|
|
503
|
+
}
|
|
504
|
+
return entryCheckIssues(checks, value, subject, path);
|
|
505
|
+
}
|
|
506
|
+
export function entryCheckIssues(checks, value, subject, path) {
|
|
507
|
+
if (value === null || value === undefined) {
|
|
508
|
+
return [];
|
|
509
|
+
}
|
|
510
|
+
const issues = [];
|
|
511
|
+
for (const check of checks) {
|
|
512
|
+
if (!isListCheck(check) && !passesFieldCheck(check, value, subject)) {
|
|
513
|
+
issues.push(fieldCheckIssue(check, subject, path));
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return issues;
|
|
517
|
+
}
|
|
518
|
+
function isListCheck(check) {
|
|
519
|
+
return ((check.check === "max_length" || check.check === "min_length") &&
|
|
520
|
+
check.list === true);
|
|
521
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
|
+
import type { AvAdapterFieldKey } from "../adapters/adapter-resource.js";
|
|
3
|
+
import type { AvConfigAny } from "../config/any-framework-config.js";
|
|
4
|
+
import type { AvEffectiveFieldKey } from "../config/effective-fields.js";
|
|
5
|
+
import type { AvConfigResourceKey } from "../config/framework-field-definition.js";
|
|
6
|
+
import type { AvComputeReads } from "../framework/operation-facade.js";
|
|
7
|
+
import type { AvContext } from "./pipeline.js";
|
|
8
|
+
import type { AvDeepReadonly } from "./readonly-value.js";
|
|
9
|
+
import type { AvState } from "./request-state.js";
|
|
10
|
+
/**
|
|
11
|
+
* The ctx a compute stage is told: the operation's `$` facts, a read-only view
|
|
12
|
+
* of the request's `$state`, and reads only (`ctx.<Resource>.find.<variant>(args)`,
|
|
13
|
+
* `find.count` included).
|
|
14
|
+
*/
|
|
15
|
+
export type AvComputeContext<M extends AvAdapterModel = AvAdapterModel> = AvComputeReads<M> & Pick<AvContext<M>, "$operation" | "$args" | "$origin" | "$requestId" | "$transport" | "$contract"> & {
|
|
16
|
+
/** The request's state, read-only: a write throws a `TypeError`. */
|
|
17
|
+
readonly $state: AvDeepReadonly<AvState>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Computes a field's value when a row is created, whether or not the caller sent
|
|
21
|
+
* it. It receives the incoming `data` and returns the value to store; returning
|
|
22
|
+
* `undefined` keeps the current value.
|
|
23
|
+
*/
|
|
24
|
+
export type AvComputeCreate<M extends AvAdapterModel = AvAdapterModel> = (context: {
|
|
25
|
+
readonly field: string;
|
|
26
|
+
readonly value: unknown;
|
|
27
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
28
|
+
readonly ctx: AvComputeContext<M>;
|
|
29
|
+
}) => unknown | Promise<unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* Computes a field's value when a row is updated, whether or not the caller sent
|
|
32
|
+
* it. It receives the incoming `data` and returns the value to store; returning
|
|
33
|
+
* `undefined` keeps the current value.
|
|
34
|
+
*/
|
|
35
|
+
export type AvComputeUpdate<M extends AvAdapterModel = AvAdapterModel> = (context: {
|
|
36
|
+
readonly field: string;
|
|
37
|
+
readonly value: unknown;
|
|
38
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
39
|
+
readonly ctx: AvComputeContext<M>;
|
|
40
|
+
}) => unknown | Promise<unknown>;
|
|
41
|
+
/**
|
|
42
|
+
* Computes a field's value when a row is read. It receives the stored `record`
|
|
43
|
+
* and returns the value to return; returning `undefined` keeps the current value.
|
|
44
|
+
*/
|
|
45
|
+
export type ComputeReadFunction<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny, R extends AvConfigResourceKey<M> = AvConfigResourceKey<M>> = (context: {
|
|
46
|
+
readonly field: AvEffectiveFieldKey<M, Cfg, R>;
|
|
47
|
+
readonly value: unknown;
|
|
48
|
+
readonly record: Readonly<Record<AvEffectiveFieldKey<M, Cfg, R>, unknown>>;
|
|
49
|
+
readonly ctx: AvComputeContext<M>;
|
|
50
|
+
}) => unknown | Promise<unknown>;
|
|
51
|
+
/** The fields of Resource `R` the adapter stores as scalars: what `dependsOn` may name. */
|
|
52
|
+
type StoredScalarKey<M extends AvAdapterModel, R extends AvConfigResourceKey<M>> = string extends AvAdapterFieldKey<M, R> ? string : {
|
|
53
|
+
[F in AvAdapterFieldKey<M, R>]: M["resources"][R]["fields"][F] extends {
|
|
54
|
+
readonly kind: "scalar";
|
|
55
|
+
} ? F : never;
|
|
56
|
+
}[AvAdapterFieldKey<M, R>];
|
|
57
|
+
/**
|
|
58
|
+
* A read compute stage: a compute function, or `{ compute, dependsOn }` naming
|
|
59
|
+
* the fields it reads.
|
|
60
|
+
*/
|
|
61
|
+
export type AvComputeRead<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny, R extends AvConfigResourceKey<M> = AvConfigResourceKey<M>> = ComputeReadFunction<M, Cfg, R> | {
|
|
62
|
+
readonly dependsOn?: readonly StoredScalarKey<M, R>[];
|
|
63
|
+
readonly compute: ComputeReadFunction<M, Cfg, R>;
|
|
64
|
+
};
|
|
65
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ResolvedPipelineTree } from "../config/pipeline-tree.resolver.js";
|
|
2
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
3
|
+
/** One origin's field-stage dispatch, planned at startup. */
|
|
4
|
+
export type FieldStagePlan = {
|
|
5
|
+
/** Whether any Resource registers a field pipe. */
|
|
6
|
+
readonly anyPipes: boolean;
|
|
7
|
+
/** Whether any Resource registers a guard a nested target runs: its own, its family's or a field write guard. */
|
|
8
|
+
readonly nestedGuards: boolean;
|
|
9
|
+
/** `resource`'s fields with write guards, in the Resource's field order. */
|
|
10
|
+
readonly guarded: (resource: string) => readonly string[];
|
|
11
|
+
/** `resource`'s fields with field pipes, in the Resource's field order. */
|
|
12
|
+
readonly piped: (resource: string) => readonly string[];
|
|
13
|
+
};
|
|
14
|
+
/** Plans the field-stage dispatch of `tree` under `contract`. */
|
|
15
|
+
export declare function planFieldStages(tree: ResolvedPipelineTree, contract: AvContract): FieldStagePlan;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { stagedFieldsOf } from "./field-stage.runtime.js";
|
|
2
|
+
const NONE = Object.freeze([]);
|
|
3
|
+
export function planFieldStages(tree, contract) {
|
|
4
|
+
const guarded = new Map();
|
|
5
|
+
const piped = new Map();
|
|
6
|
+
let nestedGuards = false;
|
|
7
|
+
for (const [resource, pipelines] of Object.entries(tree.resources)) {
|
|
8
|
+
const guards = stagedFieldsOf(contract, resource, pipelines.fields, "guards");
|
|
9
|
+
const pipes = stagedFieldsOf(contract, resource, pipelines.fields, "pipes");
|
|
10
|
+
if (guards.length > 0) {
|
|
11
|
+
guarded.set(resource, Object.freeze([...guards]));
|
|
12
|
+
}
|
|
13
|
+
if (pipes.length > 0) {
|
|
14
|
+
piped.set(resource, Object.freeze([...pipes]));
|
|
15
|
+
}
|
|
16
|
+
nestedGuards ||=
|
|
17
|
+
guards.length > 0 ||
|
|
18
|
+
pipelines.pipelines.some((level) => level.guards.length > 0) ||
|
|
19
|
+
Object.values(pipelines.families).some((family) => family.pipelines.some((level) => level.guards.length > 0));
|
|
20
|
+
}
|
|
21
|
+
return Object.freeze({
|
|
22
|
+
anyPipes: piped.size > 0,
|
|
23
|
+
nestedGuards,
|
|
24
|
+
guarded: (resource) => guarded.get(resource) ?? NONE,
|
|
25
|
+
piped: (resource) => piped.get(resource) ?? NONE,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ResolvedFieldStages } from "../config/pipeline-tree.resolver.js";
|
|
2
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
3
|
+
import type { AvOperationFamily } from "../operations/operation-identity.js";
|
|
4
|
+
import type { AvContext } from "./pipeline.js";
|
|
5
|
+
export type Path = readonly (string | number)[];
|
|
6
|
+
type UnknownRecord = Readonly<Record<string, unknown>>;
|
|
7
|
+
/** A plain object: what a write record, or a directive's operand, is. */
|
|
8
|
+
export declare function isPlainRecord(value: unknown): value is UnknownRecord;
|
|
9
|
+
/** The containers a family writes, by argument key. */
|
|
10
|
+
export declare const WRITE_KEYS: Readonly<Partial<Record<AvOperationFamily, readonly string[]>>>;
|
|
11
|
+
/** The fields of `resource` with stages, in the Resource's field order. */
|
|
12
|
+
export declare function stagedFieldsOf(contract: AvContract, resource: string, stages: Readonly<Record<string, ResolvedFieldStages>>, kind: "pipes" | "guards"): readonly string[];
|
|
13
|
+
/** The value at `path` in `args`, or `undefined` when nothing is there. */
|
|
14
|
+
export declare function valueAt(args: unknown, path: Path): unknown;
|
|
15
|
+
/** `args` with the record at `path` replaced, every container on the way copied. */
|
|
16
|
+
export declare function replaceAt(args: unknown, path: Path, record: UnknownRecord): unknown;
|
|
17
|
+
type PipedFields = {
|
|
18
|
+
readonly args: unknown;
|
|
19
|
+
/** Whether a field pipe returned a value: the arguments must be held to the server's rules again. */
|
|
20
|
+
readonly changed: boolean;
|
|
21
|
+
};
|
|
22
|
+
/** The paths of the top-level data records of a create, update or upsert. */
|
|
23
|
+
export declare function writeRecordPathsOf(family: AvOperationFamily, args: unknown): readonly Path[];
|
|
24
|
+
/**
|
|
25
|
+
* Runs the field pipes of every sent field `select` admits, in the records at
|
|
26
|
+
* `records`, field by field in the Resource's order, root's pipes then
|
|
27
|
+
* overlay's. A pipe returning `undefined` keeps the value. The arguments are
|
|
28
|
+
* copied where a value changes, never written.
|
|
29
|
+
*/
|
|
30
|
+
export declare function pipeSentFields(stages: Readonly<Record<string, ResolvedFieldStages>>, fields: readonly string[], records: readonly Path[], args: unknown, select: (path: Path) => boolean): Promise<PipedFields>;
|
|
31
|
+
/**
|
|
32
|
+
* Runs the write guards of every sent field in the records at `records`, field
|
|
33
|
+
* by field in the Resource's order and, for several records, record by record;
|
|
34
|
+
* `false` as soon as one refuses.
|
|
35
|
+
*/
|
|
36
|
+
export declare function guardSentFields(stages: Readonly<Record<string, ResolvedFieldStages>>, fields: readonly string[], records: readonly Path[], args: unknown, context: () => AvContext): Promise<boolean>;
|
|
37
|
+
export {};
|