@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,297 @@
|
|
|
1
|
+
import { adapterPrimaryIdentifier } from "../adapters/adapter-identifier.js";
|
|
2
|
+
import { lookupOwn, lookupResource } from "../contracts/contract-lookup.js";
|
|
3
|
+
import { isOperationVariantAvailable } from "../contracts/resource-operations.js";
|
|
4
|
+
import { resourceUnavailableIssue, validateOperationArguments, } from "../operations/operation-validator-core.js";
|
|
5
|
+
import { validationIssue, } from "../operations/validation-code.js";
|
|
6
|
+
import { copyAtDoor, refuseCallerData } from "../runtime/caller-data.door.js";
|
|
7
|
+
import { createReporter, } from "../runtime/diagnostics-reporter.js";
|
|
8
|
+
import { ADAPTER_FAILURE_MESSAGE, deliberateRefusalCode, } from "../runtime/error-boundary.js";
|
|
9
|
+
import { internalFailure, operationFailure, operationSuccess, } from "../runtime/operation-response.js";
|
|
10
|
+
import { VALIDATION_OUTCOME_MESSAGES } from "../runtime/outcome-mapper.js";
|
|
11
|
+
import { requestStateOf } from "../runtime/request-state.resolver.js";
|
|
12
|
+
import { normalizeOperationScalarValues } from "../runtime/scalar-runtime.js";
|
|
13
|
+
import { admitByPolicy } from "./policy-admission.js";
|
|
14
|
+
import { allOf, everyOf, whereOf } from "./policy-condition.js";
|
|
15
|
+
import { openRequestPolicy } from "./policy-request.js";
|
|
16
|
+
import { fieldAccess, } from "./policy-session.js";
|
|
17
|
+
const ACTIONS = ["read", "create", "update", "delete"];
|
|
18
|
+
const BODY_KEYS = new Set(["questions"]);
|
|
19
|
+
const QUESTION_KEYS = new Set([
|
|
20
|
+
"resource",
|
|
21
|
+
"action",
|
|
22
|
+
"where",
|
|
23
|
+
]);
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
const LIMIT_CODES = new Set([
|
|
28
|
+
"V1013",
|
|
29
|
+
"V1014",
|
|
30
|
+
"V1015",
|
|
31
|
+
"V1021",
|
|
32
|
+
]);
|
|
33
|
+
function refusal(issues) {
|
|
34
|
+
const code = issues.some((issue) => issue.code === "V1005" && issue.path?.[2] === "resource")
|
|
35
|
+
? "A2001"
|
|
36
|
+
: issues.some((issue) => LIMIT_CODES.has(issue.code))
|
|
37
|
+
? "A2009"
|
|
38
|
+
: "A2004";
|
|
39
|
+
return operationFailure(code, {
|
|
40
|
+
message: VALIDATION_OUTCOME_MESSAGES[code],
|
|
41
|
+
issues,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function unknownKeyIssues(record, allowed, path) {
|
|
45
|
+
return Object.keys(record)
|
|
46
|
+
.filter((key) => !allowed.has(key))
|
|
47
|
+
.map((key) => validationIssue("V1001", [...path, key], `Property "${key}" is not valid here.`));
|
|
48
|
+
}
|
|
49
|
+
function checkQuestion(active, origin, question, index) {
|
|
50
|
+
const at = ["questions", index];
|
|
51
|
+
if (!isRecord(question)) {
|
|
52
|
+
return [validationIssue("V1001", at, "Each question must be an object.")];
|
|
53
|
+
}
|
|
54
|
+
const issues = unknownKeyIssues(question, QUESTION_KEYS, at);
|
|
55
|
+
const { resource, action } = question;
|
|
56
|
+
let knownResource;
|
|
57
|
+
if (resource === undefined) {
|
|
58
|
+
issues.push(validationIssue("V1000", [...at, "resource"], 'Required property "resource" is missing.'));
|
|
59
|
+
}
|
|
60
|
+
else if (typeof resource !== "string") {
|
|
61
|
+
issues.push(validationIssue("V1001", [...at, "resource"], "resource must be a string."));
|
|
62
|
+
}
|
|
63
|
+
else if (lookupResource(active, resource) === undefined) {
|
|
64
|
+
const unavailable = resourceUnavailableIssue(resource);
|
|
65
|
+
issues.push({ ...unavailable, path: [...at, "resource"] });
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
knownResource = resource;
|
|
69
|
+
}
|
|
70
|
+
if (action === undefined) {
|
|
71
|
+
issues.push(validationIssue("V1000", [...at, "action"], 'Required property "action" is missing.'));
|
|
72
|
+
}
|
|
73
|
+
else if (typeof action !== "string") {
|
|
74
|
+
issues.push(validationIssue("V1001", [...at, "action"], "action must be a string."));
|
|
75
|
+
}
|
|
76
|
+
else if (!ACTIONS.includes(action)) {
|
|
77
|
+
issues.push(validationIssue("V1002", [...at, "action"], 'action must be one of "read", "create", "update" or "delete".'));
|
|
78
|
+
}
|
|
79
|
+
const where = !Object.hasOwn(question, "where")
|
|
80
|
+
? undefined
|
|
81
|
+
: action === "create"
|
|
82
|
+
? [
|
|
83
|
+
validationIssue("V1001", [...at, "where"], "A create question names no row: it takes no where."),
|
|
84
|
+
]
|
|
85
|
+
: checkedWhere(active, origin, knownResource, question.where, at);
|
|
86
|
+
if (Array.isArray(where)) {
|
|
87
|
+
issues.push(...where);
|
|
88
|
+
}
|
|
89
|
+
if (issues.length > 0 || knownResource === undefined) {
|
|
90
|
+
return issues;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
resource: knownResource,
|
|
94
|
+
action: action,
|
|
95
|
+
...(where === undefined ? {} : { where: where }),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function checkedWhere(active, origin, resource, where, at) {
|
|
99
|
+
if (resource === undefined) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const request = {
|
|
103
|
+
resource,
|
|
104
|
+
family: "find",
|
|
105
|
+
variant: "unique",
|
|
106
|
+
arguments: { where },
|
|
107
|
+
};
|
|
108
|
+
const validation = validateOperationArguments(active, request);
|
|
109
|
+
const normalized = validation.ok
|
|
110
|
+
? normalizeOperationScalarValues(active, {
|
|
111
|
+
...request,
|
|
112
|
+
arguments: validation.arguments,
|
|
113
|
+
}, origin)
|
|
114
|
+
: validation;
|
|
115
|
+
if (!normalized.ok) {
|
|
116
|
+
return normalized.issues.map((issue) => ({
|
|
117
|
+
...issue,
|
|
118
|
+
path: [...at, ...(issue.path ?? ["arguments", "where"]).slice(1)],
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
return normalized.arguments.where;
|
|
122
|
+
}
|
|
123
|
+
function checkQuestions(active, origin, body) {
|
|
124
|
+
if (!isRecord(body)) {
|
|
125
|
+
return refusal([
|
|
126
|
+
validationIssue("V1001", [], "The request body must be an object."),
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
const shape = unknownKeyIssues(body, BODY_KEYS, []);
|
|
130
|
+
if (!Object.hasOwn(body, "questions")) {
|
|
131
|
+
shape.push(validationIssue("V1000", ["questions"], 'Required property "questions" is missing.'));
|
|
132
|
+
}
|
|
133
|
+
else if (!Array.isArray(body.questions)) {
|
|
134
|
+
shape.push(validationIssue("V1001", ["questions"], "questions must be an array."));
|
|
135
|
+
}
|
|
136
|
+
if (shape.length > 0) {
|
|
137
|
+
return refusal(shape);
|
|
138
|
+
}
|
|
139
|
+
const questions = body.questions;
|
|
140
|
+
const limit = active.limits.maxListLimit;
|
|
141
|
+
if (questions.length > limit) {
|
|
142
|
+
return refusal([
|
|
143
|
+
validationIssue("V1014", ["questions"], `Question count exceeds maxListLimit (${limit}).`),
|
|
144
|
+
]);
|
|
145
|
+
}
|
|
146
|
+
const checked = [];
|
|
147
|
+
const issues = [];
|
|
148
|
+
questions.forEach((question, index) => {
|
|
149
|
+
const result = checkQuestion(active, origin, question, index);
|
|
150
|
+
if (Array.isArray(result)) {
|
|
151
|
+
issues.push(...result);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
checked.push(result);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
return issues.length > 0 ? refusal(issues) : checked;
|
|
158
|
+
}
|
|
159
|
+
function familyOf(action) {
|
|
160
|
+
return action === "read" ? "find" : action;
|
|
161
|
+
}
|
|
162
|
+
function advertised(active, question) {
|
|
163
|
+
const operations = lookupOwn(lookupResource(active, question.resource)?.operations, familyOf(question.action));
|
|
164
|
+
if (operations === undefined) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return question.where === undefined
|
|
168
|
+
? Object.keys(operations).some((variant) => isOperationVariantAvailable(lookupOwn(operations, variant)))
|
|
169
|
+
: isOperationVariantAvailable(lookupOwn(operations, "unique"));
|
|
170
|
+
}
|
|
171
|
+
async function answerQuestion(session, dependencies, active, question) {
|
|
172
|
+
if (!advertised(active, question)) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const { resource, action, where } = question;
|
|
176
|
+
const identifier = adapterPrimaryIdentifier(dependencies.adapter.model, resource);
|
|
177
|
+
const interactive = active.transactions === "interactive";
|
|
178
|
+
if (action === "update") {
|
|
179
|
+
const checkedAfter = session.checksAfter(resource, "update");
|
|
180
|
+
if ((!interactive && checkedAfter) ||
|
|
181
|
+
((interactive || checkedAfter) && identifier.length === 0)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (where === undefined) {
|
|
186
|
+
return session.can(resource, action);
|
|
187
|
+
}
|
|
188
|
+
if (action === "create") {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
const { core } = dependencies.contracts;
|
|
192
|
+
const refused = await admitByPolicy(session, core, active, {
|
|
193
|
+
resource,
|
|
194
|
+
family: action === "read" ? "find" : action,
|
|
195
|
+
variant: "unique",
|
|
196
|
+
}, { where, select: [...identifier] });
|
|
197
|
+
if (refused !== undefined) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
const read = await session.scope(resource, "read");
|
|
201
|
+
const scope = action === "read"
|
|
202
|
+
? read
|
|
203
|
+
: allOf(await session.scope(resource, action), read);
|
|
204
|
+
const fields = await session.fields(resource, { access: "read" });
|
|
205
|
+
const grants = identifier.flatMap((field) => {
|
|
206
|
+
const access = fieldAccess(core, resource, fields, field);
|
|
207
|
+
return typeof access === "object" ? [access] : [];
|
|
208
|
+
});
|
|
209
|
+
if (action === "update" && !interactive && grants.length > 0) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
const reach = everyOf([where, scope, ...grants]);
|
|
213
|
+
return reach !== false && session.exists(resource, whereOf(reach));
|
|
214
|
+
}
|
|
215
|
+
const CONCURRENT_QUESTIONS = 8;
|
|
216
|
+
async function answerAll(session, dependencies, active, questions) {
|
|
217
|
+
const settled = new Array(questions.length);
|
|
218
|
+
let next = 0;
|
|
219
|
+
const worker = async () => {
|
|
220
|
+
while (next < questions.length) {
|
|
221
|
+
const index = next;
|
|
222
|
+
next += 1;
|
|
223
|
+
try {
|
|
224
|
+
settled[index] = {
|
|
225
|
+
status: "fulfilled",
|
|
226
|
+
value: await answerQuestion(session, dependencies, active, questions[index]),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
catch (reason) {
|
|
230
|
+
settled[index] = { status: "rejected", reason };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
await Promise.all(Array.from({ length: Math.min(CONCURRENT_QUESTIONS, questions.length) }, worker));
|
|
235
|
+
return settled;
|
|
236
|
+
}
|
|
237
|
+
function isDeliberateRefusal(error) {
|
|
238
|
+
return deliberateRefusalCode(error) !== undefined;
|
|
239
|
+
}
|
|
240
|
+
function defectAnswer(dependencies, request, error, fromAdapter, blamed) {
|
|
241
|
+
createReporter(dependencies.diagnostics, {
|
|
242
|
+
kind: "can",
|
|
243
|
+
origin: "client",
|
|
244
|
+
requestId: request.requestId,
|
|
245
|
+
...(blamed === undefined
|
|
246
|
+
? {}
|
|
247
|
+
: {
|
|
248
|
+
question: blamed.index,
|
|
249
|
+
resource: blamed.question.resource,
|
|
250
|
+
action: blamed.question.action,
|
|
251
|
+
}),
|
|
252
|
+
})(error, fromAdapter ? "A3001" : "A3000");
|
|
253
|
+
return fromAdapter
|
|
254
|
+
? operationFailure("A3001", { message: ADAPTER_FAILURE_MESSAGE })
|
|
255
|
+
: internalFailure();
|
|
256
|
+
}
|
|
257
|
+
export function createAccessQuestionAnswerer(dependencies) {
|
|
258
|
+
return async (request) => {
|
|
259
|
+
const active = dependencies.contracts[request.origin];
|
|
260
|
+
const copy = copyAtDoor(request.body);
|
|
261
|
+
if (!copy.ok) {
|
|
262
|
+
return refusal([
|
|
263
|
+
refuseCallerData(copy.error, [], { origin: request.origin }, dependencies.misuse),
|
|
264
|
+
]);
|
|
265
|
+
}
|
|
266
|
+
const questions = checkQuestions(active, request.origin, copy.value);
|
|
267
|
+
if (!Array.isArray(questions)) {
|
|
268
|
+
return questions;
|
|
269
|
+
}
|
|
270
|
+
if (questions.length === 0) {
|
|
271
|
+
return operationSuccess([], "A1000");
|
|
272
|
+
}
|
|
273
|
+
let session;
|
|
274
|
+
try {
|
|
275
|
+
session = await openRequestPolicy(dependencies.policy, dependencies.contracts.core, { origin: request.origin, state: requestStateOf(request.state) }, undefined, dependencies.adapter);
|
|
276
|
+
if (session === undefined) {
|
|
277
|
+
throw new Error("The can route was reached on a Framework whose policy does not check its origin.");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
return defectAnswer(dependencies, request, error, false);
|
|
282
|
+
}
|
|
283
|
+
const settled = await answerAll(session, dependencies, active, questions);
|
|
284
|
+
const answers = [];
|
|
285
|
+
for (const [index, result] of settled.entries()) {
|
|
286
|
+
if (result.status === "rejected" && isDeliberateRefusal(result.reason)) {
|
|
287
|
+
answers.push(false);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (result.status === "rejected") {
|
|
291
|
+
return defectAnswer(dependencies, request, result.reason, session.execution.boundary.originOf(result.reason) === "adapter", { question: questions[index], index });
|
|
292
|
+
}
|
|
293
|
+
answers.push(result.value);
|
|
294
|
+
}
|
|
295
|
+
return operationSuccess(answers, "A1000");
|
|
296
|
+
};
|
|
297
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Each `$access` verb beside `can`, in `$access`'s order: whether it takes arguments, and what it resolves. */
|
|
2
|
+
export declare const ACCESS_VERBS: Readonly<{
|
|
3
|
+
readonly me: {
|
|
4
|
+
readonly args: false;
|
|
5
|
+
readonly resolves: "identity";
|
|
6
|
+
};
|
|
7
|
+
readonly signIn: {
|
|
8
|
+
readonly args: true;
|
|
9
|
+
readonly resolves: "answer";
|
|
10
|
+
};
|
|
11
|
+
readonly signUp: {
|
|
12
|
+
readonly args: true;
|
|
13
|
+
readonly resolves: "answer";
|
|
14
|
+
};
|
|
15
|
+
readonly signOut: {
|
|
16
|
+
readonly args: false;
|
|
17
|
+
readonly resolves: "nothing";
|
|
18
|
+
};
|
|
19
|
+
readonly resetPassword: {
|
|
20
|
+
readonly args: true;
|
|
21
|
+
readonly resolves: "nothing";
|
|
22
|
+
};
|
|
23
|
+
readonly switchUser: {
|
|
24
|
+
readonly args: true;
|
|
25
|
+
readonly resolves: "answer";
|
|
26
|
+
};
|
|
27
|
+
readonly lock: {
|
|
28
|
+
readonly args: false;
|
|
29
|
+
readonly resolves: "nothing";
|
|
30
|
+
};
|
|
31
|
+
readonly setPin: {
|
|
32
|
+
readonly args: true;
|
|
33
|
+
readonly resolves: "nothing";
|
|
34
|
+
};
|
|
35
|
+
readonly enrollDevice: {
|
|
36
|
+
readonly args: true;
|
|
37
|
+
readonly resolves: "answer";
|
|
38
|
+
};
|
|
39
|
+
readonly revokeDevice: {
|
|
40
|
+
readonly args: true;
|
|
41
|
+
readonly resolves: "nothing";
|
|
42
|
+
};
|
|
43
|
+
}>;
|
|
44
|
+
/** One verb's row of {@link ACCESS_VERBS}. */
|
|
45
|
+
export type AccessVerbShape = {
|
|
46
|
+
readonly args: boolean;
|
|
47
|
+
readonly resolves: "identity" | "answer" | "nothing";
|
|
48
|
+
};
|
|
49
|
+
/** A verb `$access` offers beside `can`. */
|
|
50
|
+
export type AccessVerbName = keyof typeof ACCESS_VERBS;
|
|
51
|
+
/** The verbs of {@link ACCESS_VERBS}, in `$access`'s order. */
|
|
52
|
+
export declare const ACCESS_VERB_NAMES: readonly AccessVerbName[];
|
|
53
|
+
/** The provider's `name` verb: its `verbs`' own enumerable member, else `undefined`. */
|
|
54
|
+
export declare function providerVerb<Verbs extends object, Name extends string>(verbs: Verbs, name: Name): (Name extends keyof Verbs ? Verbs[Name] : unknown) | undefined;
|
|
55
|
+
/** Whether `name` is one of `$access`'s verbs (an own key of the table, never `toString`). */
|
|
56
|
+
export declare function isAccessVerbName(name: string): name is AccessVerbName;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const ACCESS_VERBS = Object.freeze({
|
|
2
|
+
me: { args: false, resolves: "identity" },
|
|
3
|
+
signIn: { args: true, resolves: "answer" },
|
|
4
|
+
signUp: { args: true, resolves: "answer" },
|
|
5
|
+
signOut: { args: false, resolves: "nothing" },
|
|
6
|
+
resetPassword: { args: true, resolves: "nothing" },
|
|
7
|
+
switchUser: { args: true, resolves: "answer" },
|
|
8
|
+
lock: { args: false, resolves: "nothing" },
|
|
9
|
+
setPin: { args: true, resolves: "nothing" },
|
|
10
|
+
enrollDevice: { args: true, resolves: "answer" },
|
|
11
|
+
revokeDevice: { args: true, resolves: "nothing" },
|
|
12
|
+
});
|
|
13
|
+
export const ACCESS_VERB_NAMES = Object.freeze(Object.keys(ACCESS_VERBS));
|
|
14
|
+
export function providerVerb(verbs, name) {
|
|
15
|
+
return Object.prototype.propertyIsEnumerable.call(verbs, name)
|
|
16
|
+
? verbs[name]
|
|
17
|
+
: undefined;
|
|
18
|
+
}
|
|
19
|
+
export function isAccessVerbName(name) {
|
|
20
|
+
return Object.hasOwn(ACCESS_VERBS, name);
|
|
21
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `$access`: the policy's answers for the UI (`can`), and the Aventara Access
|
|
3
|
+
* verbs (`me`, `signIn`, `signUp`, `signOut`, `resetPassword`, and the `kiosk`
|
|
4
|
+
* profile's `switchUser`, `lock`, `setPin`, `enrollDevice`, `revokeDevice`).
|
|
5
|
+
*/
|
|
6
|
+
export type AvAccessVerbs<Question, Me, Args extends {
|
|
7
|
+
readonly signIn: unknown;
|
|
8
|
+
readonly signUp: unknown;
|
|
9
|
+
readonly resetPassword: unknown;
|
|
10
|
+
readonly switchUser: unknown;
|
|
11
|
+
readonly setPin: unknown;
|
|
12
|
+
readonly enrollDevice: unknown;
|
|
13
|
+
readonly revokeDevice: unknown;
|
|
14
|
+
}, Options> = {
|
|
15
|
+
/**
|
|
16
|
+
* Asks the policy every question at once, in one request, and answers one
|
|
17
|
+
* boolean each, in order: what each call would do before any data is sent.
|
|
18
|
+
* It only shapes the UI; the real call is still checked.
|
|
19
|
+
*/
|
|
20
|
+
can<const Q extends readonly Question[]>(questions: Q, options?: Options): Promise<{
|
|
21
|
+
readonly [K in keyof Q]: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
/** Who is signed in: the token identity, or `null` when no one is. */
|
|
24
|
+
me(options?: Options): Promise<Me | null>;
|
|
25
|
+
/** Signs in through Aventara Access; resolves what Access answers. */
|
|
26
|
+
signIn(args: Args["signIn"], options?: Options): Promise<unknown>;
|
|
27
|
+
/** Signs up through Aventara Access; resolves what Access answers. */
|
|
28
|
+
signUp(args: Args["signUp"], options?: Options): Promise<unknown>;
|
|
29
|
+
/** Signs the caller out through Aventara Access. */
|
|
30
|
+
signOut(options?: Options): Promise<void>;
|
|
31
|
+
/** Resets a password through Aventara Access. */
|
|
32
|
+
resetPassword(args: Args["resetPassword"], options?: Options): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Switches this enrolled device to another staff member by their PIN
|
|
35
|
+
* (Aventara Access, `kiosk` profile); resolves what Access answers.
|
|
36
|
+
*/
|
|
37
|
+
switchUser(args: Args["switchUser"], options?: Options): Promise<unknown>;
|
|
38
|
+
/** Locks this enrolled device: ends its session, keeps it enrolled (`kiosk` profile). */
|
|
39
|
+
lock(options?: Options): Promise<void>;
|
|
40
|
+
/** Sets the signed-in staff member's PIN (`kiosk` profile). */
|
|
41
|
+
setPin(args: Args["setPin"], options?: Options): Promise<void>;
|
|
42
|
+
/** Enrolls this device for PIN switching (`kiosk` profile); resolves what Access answers. */
|
|
43
|
+
enrollDevice(args: Args["enrollDevice"], options?: Options): Promise<unknown>;
|
|
44
|
+
/** Revokes an enrolled device (`kiosk` profile). */
|
|
45
|
+
revokeDevice(args: Args["revokeDevice"], options?: Options): Promise<void>;
|
|
46
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AvContract, AvContractCore } from "../contracts/contract.js";
|
|
2
|
+
import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
3
|
+
import type { AvOperationFailureResponse } from "../runtime/operation-response.js";
|
|
4
|
+
import { type PolicySession } from "./policy-session.js";
|
|
5
|
+
/** The refusal every policy decision answers: `A4002`. */
|
|
6
|
+
export declare function policyRefusal(message: string): AvOperationFailureResponse;
|
|
7
|
+
/**
|
|
8
|
+
* Policy admission for one request (see the module comment): the refusal, or
|
|
9
|
+
* `undefined` when the request may go on to its guards.
|
|
10
|
+
*/
|
|
11
|
+
export declare function admitByPolicy(session: PolicySession, core: AvContractCore, active: AvContract, request: AvOperationIdentity & {
|
|
12
|
+
readonly resource: string;
|
|
13
|
+
}, args: unknown): Promise<AvOperationFailureResponse | undefined>;
|
|
14
|
+
/**
|
|
15
|
+
* The write half of policy admission: every field the write sends against
|
|
16
|
+
* `fieldsOf(write)`, nested records included, the refusal or `undefined`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function admitWriteByPolicy(session: PolicySession, core: AvContractCore, request: AvOperationIdentity & {
|
|
19
|
+
readonly resource: string;
|
|
20
|
+
}, args: unknown): Promise<AvOperationFailureResponse | undefined>;
|