@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
|
@@ -28,6 +28,109 @@ function nestingExceeded(state) {
|
|
|
28
28
|
message: `Request nesting exceeds maxNestingDepth (${state.nestingLimit}).`,
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
+
function jsonDepthExceeded(state, fieldPath) {
|
|
32
|
+
state.nestingAtField = true;
|
|
33
|
+
state.nesting = {
|
|
34
|
+
path: state.tracking ? fieldPath : ["arguments", state.rootKey],
|
|
35
|
+
code: "V1021",
|
|
36
|
+
message: `Json value depth exceeds maxJsonDepth (${state.jsonDepthLimit}).`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function isJsonField(field) {
|
|
40
|
+
return "scalar" in field.type && field.type.scalar === "json";
|
|
41
|
+
}
|
|
42
|
+
function jsonValueExceeds(state, value) {
|
|
43
|
+
const deepest = new Map();
|
|
44
|
+
const ancestors = new Set();
|
|
45
|
+
const stack = [{ leave: false, value, level: 0 }];
|
|
46
|
+
while (stack.length > 0) {
|
|
47
|
+
const task = stack.pop();
|
|
48
|
+
if (task.leave) {
|
|
49
|
+
ancestors.delete(task.container);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const current = task.value;
|
|
53
|
+
if (typeof current !== "object" ||
|
|
54
|
+
current === null ||
|
|
55
|
+
ancestors.has(current)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const inner = task.level + 1;
|
|
59
|
+
if (inner > state.jsonDepthLimit) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
const seen = deepest.get(current);
|
|
63
|
+
if (seen !== undefined && seen >= inner) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
deepest.set(current, inner);
|
|
67
|
+
ancestors.add(current);
|
|
68
|
+
stack.push({ leave: true, container: current });
|
|
69
|
+
const entries = Array.isArray(current)
|
|
70
|
+
? current
|
|
71
|
+
: Object.values(current);
|
|
72
|
+
for (const entry of entries) {
|
|
73
|
+
stack.push({ leave: false, value: entry, level: inner });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
function walkJsonWrite(state, field, value, path) {
|
|
79
|
+
const operands = isRecord(value) && Object.keys(value).some((key) => key.startsWith("$"))
|
|
80
|
+
? Object.entries(value)
|
|
81
|
+
.filter(([key]) => key !== "$unset" && key !== "$ref")
|
|
82
|
+
.map(([, operand]) => operand)
|
|
83
|
+
: [value];
|
|
84
|
+
for (const operand of operands) {
|
|
85
|
+
const values = field.list && Array.isArray(operand) ? operand : [operand];
|
|
86
|
+
for (const entry of values) {
|
|
87
|
+
if (jsonValueExceeds(state, entry)) {
|
|
88
|
+
jsonDepthExceeded(state, path);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const JSON_LIST_OPERATORS = new Set(["in", "notIn", "hasEvery", "hasSome"]);
|
|
95
|
+
const JSON_VALUELESS_OPERATORS = new Set(["mode", "isEmpty", "path"]);
|
|
96
|
+
function walkJsonFilter(state, filter, depth, path) {
|
|
97
|
+
let level = depth;
|
|
98
|
+
let current = filter;
|
|
99
|
+
while (isRecord(current)) {
|
|
100
|
+
let next;
|
|
101
|
+
for (const operator of Object.keys(current)) {
|
|
102
|
+
const operand = current[operator];
|
|
103
|
+
if (operator === "not" && isRecord(operand)) {
|
|
104
|
+
next = operand;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (JSON_VALUELESS_OPERATORS.has(operator)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const values = JSON_LIST_OPERATORS.has(operator) && Array.isArray(operand)
|
|
111
|
+
? operand
|
|
112
|
+
: [operand];
|
|
113
|
+
for (const entry of values) {
|
|
114
|
+
if (jsonValueExceeds(state, entry)) {
|
|
115
|
+
jsonDepthExceeded(state, path);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (next === undefined) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
level += 1;
|
|
124
|
+
if (level > state.nestingLimit) {
|
|
125
|
+
nestingExceeded(state);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
current = next;
|
|
129
|
+
}
|
|
130
|
+
if (jsonValueExceeds(state, current)) {
|
|
131
|
+
jsonDepthExceeded(state, path);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
31
134
|
function countBooleanNode(state, path, key) {
|
|
32
135
|
if (state.booleanExceeded) {
|
|
33
136
|
return;
|
|
@@ -74,7 +177,18 @@ function walkWhere(state, resourceName, value, depth, path, counting) {
|
|
|
74
177
|
}
|
|
75
178
|
else {
|
|
76
179
|
const field = lookupField(resource, key);
|
|
180
|
+
if (field?.kind === "scalar") {
|
|
181
|
+
if (isJsonField(field)) {
|
|
182
|
+
walkJsonFilter(state, child, depth, extend(state, path, key));
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
walkScalarNot(state, child, depth);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
77
188
|
if (field?.kind !== "relation") {
|
|
189
|
+
if (state.nesting !== undefined) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
78
192
|
continue;
|
|
79
193
|
}
|
|
80
194
|
if (field.cardinality === "one") {
|
|
@@ -97,6 +211,22 @@ function walkWhere(state, resourceName, value, depth, path, counting) {
|
|
|
97
211
|
}
|
|
98
212
|
}
|
|
99
213
|
}
|
|
214
|
+
function walkScalarNot(state, filter, depth) {
|
|
215
|
+
let level = depth;
|
|
216
|
+
let current = filter;
|
|
217
|
+
while (isRecord(current) && Object.hasOwn(current, "not")) {
|
|
218
|
+
const operand = current.not;
|
|
219
|
+
if (!isRecord(operand)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
level += 1;
|
|
223
|
+
if (level > state.nestingLimit) {
|
|
224
|
+
nestingExceeded(state);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
current = operand;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
100
230
|
function walkOrderBy(state, resourceName, value, depth) {
|
|
101
231
|
const resource = lookupResource(state.contract, resourceName);
|
|
102
232
|
if (resource === undefined) {
|
|
@@ -194,6 +324,13 @@ function walkMutationData(state, resourceName, value, depth, path, stage, counti
|
|
|
194
324
|
for (const fieldName of Object.keys(value)) {
|
|
195
325
|
const edge = lookupField(resource, fieldName);
|
|
196
326
|
const directives = value[fieldName];
|
|
327
|
+
if (edge?.kind === "scalar" && isJsonField(edge)) {
|
|
328
|
+
walkJsonWrite(state, edge, directives, extend(state, path, fieldName));
|
|
329
|
+
if (state.nesting !== undefined) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
197
334
|
if (edge?.kind !== "relation" || !isRecord(directives)) {
|
|
198
335
|
continue;
|
|
199
336
|
}
|
|
@@ -321,11 +458,13 @@ function walk(contract, request, args, tracking) {
|
|
|
321
458
|
const state = {
|
|
322
459
|
contract,
|
|
323
460
|
nestingLimit: contract.limits.maxNestingDepth,
|
|
461
|
+
jsonDepthLimit: contract.limits.maxJsonDepth,
|
|
324
462
|
booleanLimit: contract.limits.maxBooleanNodes,
|
|
325
463
|
tracking,
|
|
326
464
|
rootKey: "",
|
|
327
465
|
booleanCount: 0,
|
|
328
466
|
nesting: undefined,
|
|
467
|
+
nestingAtField: false,
|
|
329
468
|
booleanNodes: undefined,
|
|
330
469
|
booleanExceeded: false,
|
|
331
470
|
};
|
|
@@ -334,6 +473,12 @@ function walk(contract, request, args, tracking) {
|
|
|
334
473
|
}
|
|
335
474
|
export function findStructuralLimitIssues(contract, request, args) {
|
|
336
475
|
const untracked = walk(contract, request, args, false);
|
|
476
|
+
if (untracked.nestingAtField) {
|
|
477
|
+
return {
|
|
478
|
+
nesting: walk(contract, request, args, true).nesting,
|
|
479
|
+
booleanNodes: undefined,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
337
482
|
if (untracked.nesting !== undefined || !untracked.booleanExceeded) {
|
|
338
483
|
return { nesting: untracked.nesting, booleanNodes: undefined };
|
|
339
484
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import type { AvFieldCheck } from "../contracts/field-check.js";
|
|
1
2
|
/** The set of allocated Validation codes, as a runtime array. */
|
|
2
|
-
export declare const VALIDATION_CODES: readonly ["V1000", "V1001", "V1002", "V1003", "V1004", "V1005", "V1006", "V1007", "V1008", "V1009", "V1010", "V1011", "V1012", "V1013", "V1014", "V1015", "V1016", "V1017", "V1018", "V1019"];
|
|
3
|
+
export declare const VALIDATION_CODES: readonly ["V1000", "V1001", "V1002", "V1003", "V1004", "V1005", "V1006", "V1007", "V1008", "V1009", "V1010", "V1011", "V1012", "V1013", "V1014", "V1015", "V1016", "V1017", "V1018", "V1019", "V1020", "V1021"];
|
|
3
4
|
/** A validation code (`V1000` and up), one per kind of argument problem. */
|
|
4
|
-
export type
|
|
5
|
+
export type AvValidationCode = (typeof VALIDATION_CODES)[number];
|
|
5
6
|
/** The framework's message for each validation code. */
|
|
6
|
-
export declare const VALIDATION_CODE_MESSAGES: Readonly<Record<
|
|
7
|
+
export declare const VALIDATION_CODE_MESSAGES: Readonly<Record<AvValidationCode, string>>;
|
|
7
8
|
/** One validation problem: its code, message and the argument path it is at. */
|
|
8
|
-
export type
|
|
9
|
+
export type AvValidationIssue = {
|
|
9
10
|
readonly path?: readonly (string | number)[];
|
|
10
|
-
readonly code:
|
|
11
|
+
readonly code: AvValidationCode;
|
|
11
12
|
readonly message: string;
|
|
13
|
+
/** The failed field validator's check name (`max_length`, `string_format`, …). */
|
|
14
|
+
readonly check?: AvFieldCheck["check"];
|
|
15
|
+
/** That check's parameters, as the Contract stores them (`{ maximum: 80 }`). */
|
|
16
|
+
readonly params?: Readonly<Record<string, unknown>>;
|
|
12
17
|
};
|
|
13
18
|
/** Builds one validation issue at its path. */
|
|
14
|
-
export declare function validationIssue(code:
|
|
19
|
+
export declare function validationIssue(code: AvValidationCode, path: readonly (string | number)[], message: string): AvValidationIssue;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ErrorCodeGuidance } from "../runtime/error-guidance.js";
|
|
2
|
+
import type { AvValidationCode } from "./validation-code.js";
|
|
3
|
+
/** Cause and fix of every validation code. */
|
|
4
|
+
export declare const VALIDATION_CODE_GUIDANCE: {
|
|
5
|
+
readonly [C in AvValidationCode]: ErrorCodeGuidance;
|
|
6
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export const VALIDATION_CODE_GUIDANCE = {
|
|
2
|
+
V1000: {
|
|
3
|
+
cause: "A required value is absent: a create leaves out a required field that has no database default and no compute.create (the path names the field), a required relation and its reference field are both missing, a typed Json field lacks a required key, or a $ref has no fingerprint.",
|
|
4
|
+
fix: "Send the value at the issue's path. When the server must fill it, give the field a compute.create stage or a database default; a pipe cannot fill it.",
|
|
5
|
+
},
|
|
6
|
+
V1001: {
|
|
7
|
+
cause: "A value of the wrong type: a string where a number is expected, a negative limit, a non-integer id, null given to an operator with no null meaning (gt, contains, in), two directives in one scalar action object (`{ $increment: 1, $decrement: 2 }`), or a server-side value that is not plain data. Also a value that would make the call reach more rows: `undefined` in a filter, a unique selector or a cursor, an empty boolean node (`NOT: {}`, `AND: []`, `OR: []`) in the where of a write (update or delete many, count or first, a to-many $update or $delete).",
|
|
8
|
+
fix: "Send the type the contract states at that path (the generated client's types say it).",
|
|
9
|
+
},
|
|
10
|
+
V1002: {
|
|
11
|
+
cause: "A value that is not a member of the enum, or outside a typed Json field's AvZ.enum or AvZ.literal.",
|
|
12
|
+
fix: "Send one of the enum's members.",
|
|
13
|
+
},
|
|
14
|
+
V1003: {
|
|
15
|
+
cause: 'A malformed datetime, decimal, base64 or UUID string, or a failed pattern or format validator (`check: "string_format"`).',
|
|
16
|
+
fix: "Send the canonical encoding (ISO-8601 UTC datetime, decimal string, base64 bytes) and satisfy the validator that check and params name.",
|
|
17
|
+
},
|
|
18
|
+
V1004: {
|
|
19
|
+
cause: "A number, length or size outside its range: a failed bound, length or size validator, a BigInt outside signed 64 bits, an AvZ.int() outside the safe integer range, or a transaction with no operations. Under A2004 it is also a value the database refused as too long or out of its range, a BigInt beyond what the data source's driver can bind among them (some bind at most ±(2^53 − 1)).",
|
|
20
|
+
fix: "Send a value inside the range; check and params name the validator that failed.",
|
|
21
|
+
},
|
|
22
|
+
V1005: {
|
|
23
|
+
cause: "A field that does not exist or is hidden in the caller's layer, an unknown Resource (under A2001), or a key a typed Json field's shape does not declare.",
|
|
24
|
+
fix: "Use a field the caller's contract exposes, expose it through exemptions, or make the call from server code.",
|
|
25
|
+
},
|
|
26
|
+
V1006: {
|
|
27
|
+
cause: "An operator, directive or nested write the field does not offer (at any depth, inside not too; a to-many $update's data takes only what a bulk write takes), a mode it does not offer, or an operation that is not available (under A2002).",
|
|
28
|
+
fix: "Use what the contract lists for that field or Resource, or expose it through exemptions.",
|
|
29
|
+
},
|
|
30
|
+
V1007: {
|
|
31
|
+
cause: "The where of a unique operation is not exactly one complete identifier.",
|
|
32
|
+
fix: "Pass exactly one identifier: the id, or every field of one @unique or @@unique.",
|
|
33
|
+
},
|
|
34
|
+
V1008: {
|
|
35
|
+
cause: "Both select and include, a write-only field selected, or a relation that is not selectable there.",
|
|
36
|
+
fix: "Use select or include, not both, and select only readable fields.",
|
|
37
|
+
},
|
|
38
|
+
V1009: {
|
|
39
|
+
cause: "A cursor without an explicit orderBy, or cursor keys that do not match the ordered fields.",
|
|
40
|
+
fix: "Give an orderBy and a cursor holding exactly its ordered fields.",
|
|
41
|
+
},
|
|
42
|
+
V1010: {
|
|
43
|
+
cause: "A $ref path the earlier step does not return, a $ref to a step that is not in the transaction, or to a step with no single row (a many or count step).",
|
|
44
|
+
fix: "Select the referenced field in the earlier step, and reference a single-row step.",
|
|
45
|
+
},
|
|
46
|
+
V1011: {
|
|
47
|
+
cause: "The referenced value's type does not fit its target, a nullable source where only a non-null value is accepted included.",
|
|
48
|
+
fix: "Reference a field of the target's type, non-null where the target needs it.",
|
|
49
|
+
},
|
|
50
|
+
V1012: {
|
|
51
|
+
cause: "A nested write that does not fit the relation (a list where one record is expected), a reference field set together with its own relation, one record mixing reference fields and relation writes where the adapter cannot run both, or a record written through a relation that writes that relation (or a field holding its reference) back, where the adapter admits no such write. Also a to-one $update or $upsert beside $connect, $connectOrCreate, $create, $set or $disconnect on the same relation: the row it would update is the newly linked one.",
|
|
52
|
+
fix: "Write either the relation or its reference field, in the relation's cardinality. Relink a to-one relation in one write and update the linked row in another.",
|
|
53
|
+
},
|
|
54
|
+
V1013: {
|
|
55
|
+
cause: "Nested projections, filters or writes deeper than maxNestingDepth.",
|
|
56
|
+
fix: "Nest less, or raise limits.maxNestingDepth.",
|
|
57
|
+
},
|
|
58
|
+
V1014: {
|
|
59
|
+
cause: "A limit above maxListLimit, or more steps than maxTransactionOperations.",
|
|
60
|
+
fix: "Paginate or split the plan, or raise the limit.",
|
|
61
|
+
},
|
|
62
|
+
V1015: {
|
|
63
|
+
cause: "A where tree with more nodes than maxBooleanNodes.",
|
|
64
|
+
fix: "Simplify the filter (in instead of many OR clauses), or raise limits.maxBooleanNodes.",
|
|
65
|
+
},
|
|
66
|
+
V1016: {
|
|
67
|
+
cause: "A $ref to the referencing step itself or a later one, or to an index no step has.",
|
|
68
|
+
fix: "Reference an earlier step only.",
|
|
69
|
+
},
|
|
70
|
+
V1017: {
|
|
71
|
+
cause: "A hand-written plan whose fingerprint does not match its step.",
|
|
72
|
+
fix: "Let the generated client, framework.appTx or framework.clientTx build the plan.",
|
|
73
|
+
},
|
|
74
|
+
V1018: {
|
|
75
|
+
cause: "The referenced step returned no value at that path, such as a first step that matched no row.",
|
|
76
|
+
fix: "Make sure the earlier step returns a row, or use a unique step, which fails with A2003.",
|
|
77
|
+
},
|
|
78
|
+
V1019: {
|
|
79
|
+
cause: "A later step uses a row that an earlier step's delete removed through a database cascade.",
|
|
80
|
+
fix: "Reorder or drop the dependent step.",
|
|
81
|
+
},
|
|
82
|
+
V1020: {
|
|
83
|
+
cause: "One framework.transaction([...]) list mixes appTx and clientTx steps.",
|
|
84
|
+
fix: "Build every step of a plan from one origin.",
|
|
85
|
+
},
|
|
86
|
+
V1021: {
|
|
87
|
+
cause: "A Json field's value nests deeper than maxJsonDepth.",
|
|
88
|
+
fix: "Flatten the value, or raise limits.maxJsonDepth.",
|
|
89
|
+
},
|
|
90
|
+
};
|
|
@@ -19,6 +19,8 @@ export const VALIDATION_CODES = [
|
|
|
19
19
|
"V1017",
|
|
20
20
|
"V1018",
|
|
21
21
|
"V1019",
|
|
22
|
+
"V1020",
|
|
23
|
+
"V1021",
|
|
22
24
|
];
|
|
23
25
|
export const VALIDATION_CODE_MESSAGES = {
|
|
24
26
|
V1000: "Required value missing.",
|
|
@@ -41,6 +43,8 @@ export const VALIDATION_CODE_MESSAGES = {
|
|
|
41
43
|
V1017: "Transaction fingerprint mismatch.",
|
|
42
44
|
V1018: "Transaction reference resolved to no value.",
|
|
43
45
|
V1019: "Transaction step depends on a row removed by an earlier step's cascade",
|
|
46
|
+
V1020: "Transaction mixes application and client steps.",
|
|
47
|
+
V1021: "Json value depth limit exceeded.",
|
|
44
48
|
};
|
|
45
49
|
export function validationIssue(code, path, message) {
|
|
46
50
|
return { code, path, message };
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
1
|
+
import type { AvWriteScope } 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 write position one request's top-level `data` (or `create`/`update`)
|
|
7
7
|
* argument sits in, read off the variant the Resource advertises. `"nested"`
|
|
8
8
|
* wherever nothing narrower is stated.
|
|
9
9
|
*/
|
|
10
|
-
export declare function resolveWriteScope(resource:
|
|
10
|
+
export declare function resolveWriteScope(resource: AvResource<AvContract> | undefined, request: AvOperationIdentity): AvWriteScope;
|
|
11
11
|
/**
|
|
12
12
|
* The position a write NESTED beneath an admitted relation directive sits in: the
|
|
13
13
|
* unrestricted one, at every depth, under every top-level scope.
|
|
14
14
|
*/
|
|
15
|
-
export declare const NESTED_WRITE_SCOPE:
|
|
15
|
+
export declare const NESTED_WRITE_SCOPE: AvWriteScope;
|
|
16
|
+
/** The position a to-many `$update`'s `data` sits in: the flat-bulk write position. */
|
|
17
|
+
export declare const TO_MANY_UPDATE_WRITE_SCOPE: AvWriteScope;
|
|
18
|
+
/** The position of a relation's other end inside a record written through it. */
|
|
19
|
+
export declare const LOOPBACK_WRITE_SCOPE: AvWriteScope;
|
|
@@ -5,3 +5,5 @@ export function resolveWriteScope(resource, request) {
|
|
|
5
5
|
return writeScopeOf(lookupOwn(advertised, request.variant));
|
|
6
6
|
}
|
|
7
7
|
export const NESTED_WRITE_SCOPE = "nested";
|
|
8
|
+
export const TO_MANY_UPDATE_WRITE_SCOPE = "bulkWrite";
|
|
9
|
+
export const LOOPBACK_WRITE_SCOPE = "loopback";
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { AvState } from "../runtime/request-state.js";
|
|
2
|
+
import type { AvPolicyEngine } from "./policy-engine.js";
|
|
3
|
+
/**
|
|
4
|
+
* What the framework's `access` option takes: the policy engine every client
|
|
5
|
+
* and agent request is checked against, and how a request's state is seeded.
|
|
6
|
+
* Aventara Access provides one; one written by hand works the same way.
|
|
7
|
+
*
|
|
8
|
+
* The request's principal is `ctx.$state.me` (`null` when it is absent), so
|
|
9
|
+
* `state` names it as `me`. With `access`, the configuration states no
|
|
10
|
+
* `policy`, and the host no `state` of its own.
|
|
11
|
+
*/
|
|
12
|
+
export interface AvAccessProvider {
|
|
13
|
+
/** The policy engine (`AvPolicyEngine`), asked about every client and agent request. */
|
|
14
|
+
readonly policy: AvPolicyEngine;
|
|
15
|
+
/**
|
|
16
|
+
* Seeds a request's `ctx.$state` from its headers (a Web `Headers`): `me`, the principal the
|
|
17
|
+
* policy is asked about (`null` for an anonymous caller), and anything else
|
|
18
|
+
* the stages read. Called once per request by the host. `request` is the
|
|
19
|
+
* host's own request when it has one: Express's `req`, Fastify's
|
|
20
|
+
* `request`, or the Next.js route handler's `Request`. A throw is answered
|
|
21
|
+
* like any developer failure: a thrown `AvError` as its own outcome,
|
|
22
|
+
* anything else as an internal failure.
|
|
23
|
+
*/
|
|
24
|
+
state(input: {
|
|
25
|
+
readonly headers: {
|
|
26
|
+
get(name: string): string | null;
|
|
27
|
+
has(name: string): boolean;
|
|
28
|
+
forEach(callback: (value: string, name: string) => void): void;
|
|
29
|
+
};
|
|
30
|
+
readonly request?: unknown;
|
|
31
|
+
}): (AvState & {
|
|
32
|
+
readonly me: unknown;
|
|
33
|
+
}) | Promise<AvState & {
|
|
34
|
+
readonly me: unknown;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* What the clients' `$access` needs beyond `can`: where the app mounted
|
|
38
|
+
* Aventara Access (`url`), and each verb's route under it, the JSON Schema
|
|
39
|
+
* of its arguments and result, and its server-side `call`. Compiled into
|
|
40
|
+
* the ClientContract's `access` section (its `call`s dropped). Left out,
|
|
41
|
+
* `$access` offers `can` only.
|
|
42
|
+
*/
|
|
43
|
+
readonly client?: {
|
|
44
|
+
/** Where the app mounted Access: an absolute `http(s)` URL, or root-relative (`"/api/auth"`). */
|
|
45
|
+
readonly url: string;
|
|
46
|
+
/**
|
|
47
|
+
* The verbs Access offers, each its route, its schemas and its
|
|
48
|
+
* server-side call. A verb left out is no verb of `$access`: a
|
|
49
|
+
* `service` profile, with no cookie sign-in, offers no `signIn` or
|
|
50
|
+
* `signUp`, and only the `kiosk` profile offers `switchUser`, `lock`,
|
|
51
|
+
* `setPin`, `enrollDevice` and `revokeDevice`. Any other name is
|
|
52
|
+
* refused.
|
|
53
|
+
*/
|
|
54
|
+
readonly verbs: {
|
|
55
|
+
readonly [Verb in "signIn" | "signUp" | "signOut" | "resetPassword" | "me" | "switchUser" | "lock" | "setPin" | "enrollDevice" | "revokeDevice"]?: {
|
|
56
|
+
/** The route's method. */
|
|
57
|
+
readonly method: "GET" | "POST";
|
|
58
|
+
/** Under `url`: `"/sign-in/email"`. */
|
|
59
|
+
readonly path: string;
|
|
60
|
+
/**
|
|
61
|
+
* The arguments' JSON Schema, in the subset a `json` field's shape
|
|
62
|
+
* uses (absent: the verb takes none).
|
|
63
|
+
*/
|
|
64
|
+
readonly args?: {
|
|
65
|
+
readonly [key: string]: unknown;
|
|
66
|
+
};
|
|
67
|
+
/** The result's JSON Schema, in the same subset (`me`: the value when someone is signed in). */
|
|
68
|
+
readonly result: {
|
|
69
|
+
readonly [key: string]: unknown;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* The verb run in process, for a server-side client
|
|
73
|
+
* (`framework.serverClient.$access`, Next's `avClient.$access`):
|
|
74
|
+
* Access runs it with the request's headers, and the host's own
|
|
75
|
+
* request and response when the caller hands them (Express's
|
|
76
|
+
* `req`/`res`, Fastify's `request`/`reply`), so a sign-in (or a
|
|
77
|
+
* kiosk's switch, lock or enrollment) sets its cookies as Access
|
|
78
|
+
* sets them: on the response it is handed, or, in a Server Action,
|
|
79
|
+
* through Next's `cookies()`. `me` resolves the token identity, or
|
|
80
|
+
* `null` when no one is signed in.
|
|
81
|
+
*/
|
|
82
|
+
call(input: {
|
|
83
|
+
readonly args: unknown;
|
|
84
|
+
readonly headers: Parameters<AvAccessProvider["state"]>[0]["headers"];
|
|
85
|
+
readonly request?: unknown;
|
|
86
|
+
readonly response?: unknown;
|
|
87
|
+
}): Promise<unknown>;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AvAccessProvider } from "./access-provider.interface.js";
|
|
2
|
+
/** Records the provider `framework` was configured with; called once, at construction. */
|
|
3
|
+
export declare function recordAccessProvider(framework: object, access: AvAccessProvider | undefined): void;
|
|
4
|
+
/** What a host reads of the provider a Framework was configured with. */
|
|
5
|
+
type AccessProviderView = {
|
|
6
|
+
/** The provider's `state`, called on the provider. */
|
|
7
|
+
readonly state: AvAccessProvider["state"];
|
|
8
|
+
/** The provider's `client`, when it has one. */
|
|
9
|
+
readonly client: AvAccessProvider["client"];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* The provider `framework` was configured with (`access`), as a view;
|
|
13
|
+
* `undefined` for a Framework without `access`, or a value that is no
|
|
14
|
+
* constructed Framework.
|
|
15
|
+
*/
|
|
16
|
+
export declare function accessProviderOf(framework: object): AccessProviderView | undefined;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const ACCESS_PROVIDERS = new WeakMap();
|
|
2
|
+
export function recordAccessProvider(framework, access) {
|
|
3
|
+
if (access !== undefined) {
|
|
4
|
+
ACCESS_PROVIDERS.set(framework, access);
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export function accessProviderOf(framework) {
|
|
8
|
+
const access = ACCESS_PROVIDERS.get(framework);
|
|
9
|
+
return access === undefined
|
|
10
|
+
? undefined
|
|
11
|
+
: Object.freeze({
|
|
12
|
+
state: (input) => access.state(input),
|
|
13
|
+
client: access.client,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AvPolicyWhere } from "./policy-engine.js";
|
|
2
|
+
/**
|
|
3
|
+
* One question to the policy, as a client asks it: may the signed-in principal
|
|
4
|
+
* run `action` on `resource`, or on the one row `where` names. The answer is
|
|
5
|
+
* what the real call would do before any data is sent, decided by the same
|
|
6
|
+
* engine on the server; a row the principal cannot reach answers `false`
|
|
7
|
+
* exactly as a missing one does. It only shapes the UI, and the real call is
|
|
8
|
+
* still checked.
|
|
9
|
+
*
|
|
10
|
+
* The answer is about the row and the action, not about what a page reads of
|
|
11
|
+
* the row: it is the call selecting the Resource's identifier only. A field the
|
|
12
|
+
* principal reads on some rows only is checked by the page's own call that
|
|
13
|
+
* selects it, so `true` here and a refusal of that call can both hold.
|
|
14
|
+
*/
|
|
15
|
+
export type AvAccessQuestion<R extends string = string, UniqueWhere = AvPolicyWhere> = {
|
|
16
|
+
readonly resource: R;
|
|
17
|
+
readonly action: "read" | "create" | "update" | "delete";
|
|
18
|
+
/** One row, by its unique where. Omitted: may the principal run `action` on `resource` at all. */
|
|
19
|
+
readonly where?: UniqueWhere;
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AccessQuestionsAnswerer } from "./access-question.runtime.js";
|
|
2
|
+
/** Records `framework`'s `can` answerer; called once, at construction. */
|
|
3
|
+
export declare function recordAccessQuestions(framework: object, answer: AccessQuestionsAnswerer): void;
|
|
4
|
+
/** `framework`'s `can` answerer, or `undefined` for anything `createFramework` did not return. */
|
|
5
|
+
export declare function accessQuestionsOf(framework: object): AccessQuestionsAnswerer | undefined;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { coreBrandOf } from "../runtime/core-class.brand.js";
|
|
2
|
+
const ANSWERERS = sharedAnswererRegistry();
|
|
3
|
+
function sharedAnswererRegistry() {
|
|
4
|
+
const key = coreBrandOf("access-questions");
|
|
5
|
+
const holder = globalThis;
|
|
6
|
+
const existing = holder[key];
|
|
7
|
+
if (existing instanceof WeakMap) {
|
|
8
|
+
return existing;
|
|
9
|
+
}
|
|
10
|
+
const registry = new WeakMap();
|
|
11
|
+
Object.defineProperty(holder, key, { value: registry });
|
|
12
|
+
return registry;
|
|
13
|
+
}
|
|
14
|
+
export function recordAccessQuestions(framework, answer) {
|
|
15
|
+
ANSWERERS.set(framework, answer);
|
|
16
|
+
}
|
|
17
|
+
export function accessQuestionsOf(framework) {
|
|
18
|
+
return ANSWERERS.get(framework);
|
|
19
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
|
+
import type { AvAdapterOperationExecutor } from "../adapters/adapter-operation-executor.interface.js";
|
|
3
|
+
import type { AvContracts } from "../compiler/contract.compiler.js";
|
|
4
|
+
import type { ResolvedPolicyConfig } from "../config/config.resolver.js";
|
|
5
|
+
import type { RemoteRequestOrigin } from "../config/config-layer.js";
|
|
6
|
+
import { type AvDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
|
|
7
|
+
import type { MisuseReporter } from "../runtime/misuse-reporter.js";
|
|
8
|
+
import { type AvOperationResponse } from "../runtime/operation-response.js";
|
|
9
|
+
import type { AvState } from "../runtime/request-state.js";
|
|
10
|
+
/** A `can` request as core answers it: the body the protocol read, under the request's origin, id and state. */
|
|
11
|
+
export type AccessQuestionsRequest = {
|
|
12
|
+
readonly origin: RemoteRequestOrigin;
|
|
13
|
+
readonly requestId: string;
|
|
14
|
+
/** The request's `ctx.$state` as its host seeded it; absent, `{}`. */
|
|
15
|
+
readonly state?: AvState;
|
|
16
|
+
/** The JSON object the request carried: `{ questions }`. */
|
|
17
|
+
readonly body: unknown;
|
|
18
|
+
};
|
|
19
|
+
/** Answers one `can` request: `A1000` with one boolean per question, or the refusal. */
|
|
20
|
+
export type AccessQuestionsAnswerer = (request: AccessQuestionsRequest) => Promise<AvOperationResponse<readonly boolean[]>>;
|
|
21
|
+
/** What answering reads off the Framework. */
|
|
22
|
+
type AccessQuestionsDependencies = {
|
|
23
|
+
readonly contracts: AvContracts;
|
|
24
|
+
readonly policy: ResolvedPolicyConfig | undefined;
|
|
25
|
+
readonly adapter: AvAdapterOperationExecutor & {
|
|
26
|
+
readonly model: AvAdapterModel;
|
|
27
|
+
};
|
|
28
|
+
readonly diagnostics: AvDiagnosticsSink | undefined;
|
|
29
|
+
readonly misuse: MisuseReporter;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Builds the `can` answerer of one Framework. Total: every request resolves to
|
|
33
|
+
* an answer, and no throw of the engine or the adapter escapes it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createAccessQuestionAnswerer(dependencies: AccessQuestionsDependencies): AccessQuestionsAnswerer;
|
|
36
|
+
export {};
|