@aventara/core 1.0.0-rc.1 → 1.0.0-rc.11
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 +1022 -16
- package/ERRORS.md +142 -0
- package/README.md +330 -16
- 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 +22 -0
- package/dist/adapters/adapter-identifier.d.ts +9 -0
- package/dist/adapters/adapter-identifier.js +6 -1
- package/dist/adapters/adapter-model.d.ts +9 -0
- package/dist/adapters/adapter-operation.d.ts +18 -3
- package/dist/adapters/adapter-resource.d.ts +5 -0
- package/dist/adapters/adapter.interface.d.ts +10 -0
- package/dist/avz/avz.d.ts +1 -1
- package/dist/avz/json-shape.registry.d.ts +2 -1
- 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 +6 -0
- package/dist/compiler/contract.compiler.js +281 -31
- package/dist/compiler/create-requirements.projector.js +1 -3
- package/dist/compiler/field-validator.compiler.js +1 -3
- 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/cache-stage.factory.d.ts +24 -0
- package/dist/config/cache-stage.factory.js +3 -0
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +73 -0
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/config.resolver.d.ts +24 -0
- package/dist/config/config.resolver.js +66 -7
- package/dist/config/config.validator.js +283 -21
- package/dist/config/define-resource.d.ts +1 -5
- package/dist/config/entrypoint.normalizer.d.ts +3 -2
- package/dist/config/exact-framework-config.d.ts +73 -22
- package/dist/config/field-compute.resolver.d.ts +2 -0
- package/dist/config/field-compute.resolver.js +9 -3
- package/dist/config/framework-config.d.ts +53 -15
- package/dist/config/framework-resources-config.d.ts +25 -14
- package/dist/config/pipeline-config.d.ts +20 -4
- package/dist/config/pipeline-tree.resolver.d.ts +2 -2
- package/dist/config/pipeline-tree.resolver.js +2 -3
- package/dist/contracts/access-route.rules.d.ts +10 -0
- package/dist/contracts/access-route.rules.js +45 -0
- package/dist/contracts/canonical-json.writer.d.ts +7 -0
- package/dist/contracts/canonical-json.writer.js +55 -0
- package/dist/contracts/capability.d.ts +26 -1
- package/dist/contracts/capability.js +20 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +365 -89
- package/dist/contracts/client-contract-structure.validator.js +49 -2
- package/dist/contracts/contract-access.d.ts +29 -0
- package/dist/contracts/contract-access.js +1 -0
- package/dist/contracts/contract-canonicalizer.d.ts +9 -1
- package/dist/contracts/contract-canonicalizer.js +35 -4
- package/dist/contracts/contract-hash.d.ts +0 -1
- package/dist/contracts/contract-hash.js +1 -1
- package/dist/contracts/contract-limits.d.ts +6 -0
- package/dist/contracts/contract-limits.js +2 -0
- package/dist/contracts/contract.d.ts +42 -1
- package/dist/contracts/field.d.ts +58 -1
- package/dist/contracts/json-schema.projector.d.ts +11 -0
- package/dist/contracts/json-schema.projector.js +76 -0
- package/dist/contracts/scalar-value-type.d.ts +3 -1
- package/dist/framework/access-facade.d.ts +116 -0
- package/dist/framework/access-facade.js +118 -0
- package/dist/framework/contract-view.d.ts +120 -16
- package/dist/framework/framework-construction.error.d.ts +14 -4
- package/dist/framework/framework-construction.error.js +18 -2
- package/dist/framework/framework.d.ts +26 -5
- package/dist/framework/framework.factory.d.ts +1 -1
- package/dist/framework/framework.factory.js +145 -24
- package/dist/framework/operation-facade.d.ts +141 -13
- package/dist/framework/operation-facade.js +9 -1
- package/dist/framework/operation-set.runner.d.ts +47 -0
- package/dist/framework/operation-set.runner.js +168 -0
- package/dist/index.d.ts +19 -5
- package/dist/index.js +3 -0
- package/dist/internal.d.ts +9 -2
- package/dist/internal.js +8 -0
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +148 -60
- package/dist/operations/operation-call.d.ts +9 -5
- package/dist/operations/operation-result.d.ts +6 -4
- package/dist/operations/operation-validator-core.js +160 -39
- package/dist/operations/operation-validator.d.ts +1 -1
- package/dist/operations/structural-limits.walker.d.ts +1 -1
- package/dist/operations/structural-limits.walker.js +1 -3
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/write-scope.resolver.d.ts +4 -0
- 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 +295 -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 +407 -0
- package/dist/policy/policy-after-update.runtime.d.ts +79 -0
- package/dist/policy/policy-after-update.runtime.js +206 -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 +536 -0
- package/dist/policy/policy-read.runtime.d.ts +81 -0
- package/dist/policy/policy-read.runtime.js +501 -0
- package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
- package/dist/policy/policy-reference-write.runtime.js +336 -0
- package/dist/policy/policy-request.d.ts +72 -0
- package/dist/policy/policy-request.js +115 -0
- package/dist/policy/policy-session.d.ts +106 -0
- package/dist/policy/policy-session.js +293 -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 +530 -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 +63 -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 +75 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +227 -0
- package/dist/protocol/absent-route.responder.d.ts +49 -14
- package/dist/protocol/absent-route.responder.js +92 -15
- package/dist/protocol/contract-document.responder.d.ts +9 -1
- package/dist/protocol/contract-document.responder.js +3 -2
- package/dist/protocol/http-request.decoder.d.ts +52 -3
- package/dist/protocol/http-request.decoder.js +45 -6
- package/dist/protocol/http-request.reader.d.ts +10 -3
- package/dist/protocol/http-request.reader.js +12 -2
- package/dist/protocol/http-response.encoder.d.ts +12 -0
- package/dist/protocol/http-response.encoder.js +17 -3
- package/dist/protocol/operation-response.guard.js +1 -3
- package/dist/protocol/operation-set.decoder.d.ts +48 -0
- package/dist/protocol/operation-set.decoder.js +185 -0
- package/dist/protocol/operation-set.handler.d.ts +27 -0
- package/dist/protocol/operation-set.handler.js +179 -0
- package/dist/protocol/protocol-headers.d.ts +12 -3
- package/dist/protocol/protocol-headers.js +12 -5
- package/dist/protocol/protocol-surface.d.ts +16 -3
- package/dist/protocol/protocol-surface.js +41 -1
- package/dist/protocol/protocol.binder.d.ts +52 -1
- package/dist/protocol/protocol.binder.js +6 -1
- package/dist/protocol/protocol.handler.d.ts +45 -1
- package/dist/protocol/protocol.handler.js +164 -19
- package/dist/protocol/read-cache.responder.d.ts +26 -0
- package/dist/protocol/read-cache.responder.js +47 -0
- package/dist/protocol/read-query.codec.d.ts +34 -0
- package/dist/protocol/read-query.codec.js +125 -0
- package/dist/runtime/caller-data.copier.d.ts +18 -3
- package/dist/runtime/caller-data.copier.js +21 -8
- package/dist/runtime/caller-data.door.d.ts +13 -6
- package/dist/runtime/computed-read-runtime.d.ts +6 -1
- package/dist/runtime/computed-read-runtime.js +229 -48
- package/dist/runtime/computed-value.error.d.ts +3 -2
- package/dist/runtime/computed-value.error.js +3 -2
- package/dist/runtime/context-executor.runtime.d.ts +4 -3
- package/dist/runtime/context-executor.runtime.js +4 -2
- 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 +31 -5
- package/dist/runtime/create-requirement.js +130 -24
- package/dist/runtime/decimal.d.ts +14 -0
- package/dist/runtime/decimal.js +21 -0
- package/dist/runtime/diagnostics-reporter.d.ts +49 -9
- package/dist/runtime/diagnostics-reporter.js +16 -9
- package/dist/runtime/error-boundary.d.ts +9 -2
- package/dist/runtime/error-boundary.js +12 -0
- 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 +8 -0
- package/dist/runtime/field-check.evaluator.d.ts +0 -2
- package/dist/runtime/field-check.evaluator.js +1 -1
- package/dist/runtime/field-compute.d.ts +11 -10
- package/dist/runtime/field-stage.runtime.d.ts +3 -3
- package/dist/runtime/field-stage.runtime.js +9 -11
- package/dist/runtime/field-validator.runtime.d.ts +19 -1
- package/dist/runtime/field-validator.runtime.js +49 -9
- package/dist/runtime/framework-error.js +9 -0
- package/dist/runtime/framework-warning.emitter.d.ts +6 -0
- package/dist/runtime/framework-warning.emitter.js +8 -0
- package/dist/runtime/json-value.d.ts +10 -5
- package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
- package/dist/runtime/level-lifecycle.runtime.js +3 -5
- package/dist/runtime/mutation-planner.d.ts +1 -6
- package/dist/runtime/mutation-planner.js +4 -17
- package/dist/runtime/nested-write.walker.js +2 -1
- 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 +16 -9
- package/dist/runtime/operation-runtime.d.ts +35 -17
- package/dist/runtime/operation-runtime.js +220 -49
- package/dist/runtime/outcome-mapper.d.ts +2 -1
- package/dist/runtime/output-validator.d.ts +1 -1
- package/dist/runtime/output-validator.js +1 -3
- package/dist/runtime/owned-execution.registry.d.ts +34 -4
- package/dist/runtime/pipe-output.validator.d.ts +10 -0
- package/dist/runtime/pipe-output.validator.js +4 -2
- package/dist/runtime/pipeline.d.ts +52 -23
- package/dist/runtime/readonly-value.d.ts +20 -5
- package/dist/runtime/readonly-value.js +74 -26
- package/dist/runtime/record.guard.d.ts +14 -0
- package/dist/runtime/record.guard.js +10 -0
- package/dist/runtime/referential-action.d.ts +1 -1
- package/dist/runtime/request-envelope.validator.js +13 -10
- package/dist/runtime/scalar-runtime.d.ts +4 -21
- package/dist/runtime/scalar-runtime.js +91 -31
- package/dist/runtime/thenable.guard.d.ts +7 -0
- package/dist/runtime/thenable.guard.js +5 -0
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +129 -0
- package/dist/transactions/operation-arguments-encoder.js +9 -10
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +10 -2
- package/dist/transactions/sql-statement.validator.d.ts +2 -2
- package/dist/transactions/sql-statement.validator.js +40 -6
- package/dist/transactions/transaction-envelope.d.ts +5 -4
- package/dist/transactions/transaction-integrity-error.js +2 -0
- package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
- package/dist/transactions/transaction-plan-assembler.js +49 -17
- package/dist/transactions/transaction-plan-validator.d.ts +23 -7
- package/dist/transactions/transaction-plan-validator.js +31 -7
- package/dist/transactions/transaction-reference-collector.js +8 -10
- package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
- package/dist/transactions/transaction-reference-resolver.js +1 -3
- package/dist/transactions/transaction-reference-validator.d.ts +43 -3
- package/dist/transactions/transaction-reference-validator.js +83 -57
- package/dist/transactions/transaction-reference.d.ts +1 -1
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +8 -8
- package/dist/transactions/transaction-runtime.d.ts +5 -2
- package/dist/transactions/transaction-runtime.js +108 -27
- package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
- package/dist/transactions/transaction-slot-path-error.js +2 -0
- package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
- package/dist/transactions/transaction-stage.runtime.js +8 -7
- package/package.json +6 -5
- package/src/runtime/field-check.evaluator.ts +1 -1
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import { isAccessPath, isAccessUrl } from "../contracts/access-route.rules.js";
|
|
1
2
|
import { TRANSACTION_CAPABILITIES } from "../contracts/transaction-capability.js";
|
|
3
|
+
import { ACCESS_VERB_NAMES, isAccessVerbName, providerVerb, } from "../policy/access-verb.table.js";
|
|
4
|
+
import { isPlainRecord } from "../runtime/record.guard.js";
|
|
2
5
|
import { normalizeEntrypoint } from "./entrypoint.normalizer.js";
|
|
3
6
|
import { AVZ_FORMATS } from "./framework-field-definition.js";
|
|
4
7
|
const ROOT_ONLY_PROPERTIES = new Set([
|
|
5
8
|
"api",
|
|
6
9
|
"mcp",
|
|
7
10
|
"adapter",
|
|
11
|
+
"prebuilt",
|
|
12
|
+
"policy",
|
|
13
|
+
"access",
|
|
8
14
|
"diagnostics",
|
|
9
15
|
"misuse",
|
|
10
16
|
"application",
|
|
@@ -36,6 +42,7 @@ const RESOURCE_PROPERTIES = new Set([
|
|
|
36
42
|
"operations",
|
|
37
43
|
"transactions",
|
|
38
44
|
"fields",
|
|
45
|
+
"managedElsewhere",
|
|
39
46
|
]);
|
|
40
47
|
const FIELD_PROPERTIES = new Set(["definition", "pipelines"]);
|
|
41
48
|
const DEFINITION_PROPERTIES = new Set([
|
|
@@ -71,6 +78,8 @@ const LIMIT_PROPERTIES = new Set([
|
|
|
71
78
|
"maxTransactionOperations",
|
|
72
79
|
"maxBooleanNodes",
|
|
73
80
|
"maxJsonDepth",
|
|
81
|
+
"maxAll",
|
|
82
|
+
"maxAllConcurrency",
|
|
74
83
|
]);
|
|
75
84
|
const PIPELINE_PROPERTIES = new Set([
|
|
76
85
|
"guards",
|
|
@@ -80,13 +89,6 @@ const PIPELINE_PROPERTIES = new Set([
|
|
|
80
89
|
"filters",
|
|
81
90
|
]);
|
|
82
91
|
const PIPELINE_HOOK_PROPERTIES = new Set(["before", "after"]);
|
|
83
|
-
function isPlainRecord(value) {
|
|
84
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
const prototype = Object.getPrototypeOf(value);
|
|
88
|
-
return prototype === Object.prototype || prototype === null;
|
|
89
|
-
}
|
|
90
92
|
function diagnostic(code, path, message) {
|
|
91
93
|
return { code, path, message };
|
|
92
94
|
}
|
|
@@ -113,6 +115,14 @@ function validateLimits(value, path, diagnostics) {
|
|
|
113
115
|
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", limitPath, `unknown limit property: ${key}`));
|
|
114
116
|
continue;
|
|
115
117
|
}
|
|
118
|
+
if (key === "maxAllConcurrency") {
|
|
119
|
+
if (typeof limit !== "number" ||
|
|
120
|
+
!Number.isSafeInteger(limit) ||
|
|
121
|
+
limit < 1) {
|
|
122
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", limitPath, `${limitPath} must be a whole number of at least 1`));
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
116
126
|
if (typeof limit !== "number" ||
|
|
117
127
|
!Number.isFinite(limit) ||
|
|
118
128
|
!Number.isInteger(limit) ||
|
|
@@ -121,6 +131,33 @@ function validateLimits(value, path, diagnostics) {
|
|
|
121
131
|
}
|
|
122
132
|
}
|
|
123
133
|
}
|
|
134
|
+
const CACHE_PROPERTIES = new Set(["for", "maxAge"]);
|
|
135
|
+
const CACHE_AUDIENCES = new Set(["user", "anonymous", "everyone"]);
|
|
136
|
+
function validateCache(value, path, diagnostics) {
|
|
137
|
+
if (!requireRecord(value, path, diagnostics)) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
for (const key of Object.keys(value)) {
|
|
141
|
+
if (!CACHE_PROPERTIES.has(key)) {
|
|
142
|
+
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `${path}.${key}`, `unknown cache property: ${key}; cache takes for and maxAge`));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const maxAgePath = `${path}.maxAge`;
|
|
146
|
+
if (!Object.hasOwn(value, "maxAge")) {
|
|
147
|
+
diagnostics.push(diagnostic("CONFIG_REQUIRED", maxAgePath, `${maxAgePath} is required`));
|
|
148
|
+
}
|
|
149
|
+
else if (typeof value.maxAge !== "number" ||
|
|
150
|
+
!Number.isInteger(value.maxAge) ||
|
|
151
|
+
value.maxAge < 0 ||
|
|
152
|
+
value.maxAge > MAX_CACHE_AGE) {
|
|
153
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", maxAgePath, `${maxAgePath} must be a whole number of seconds from 0 to ${MAX_CACHE_AGE}`));
|
|
154
|
+
}
|
|
155
|
+
if (Object.hasOwn(value, "for") && !CACHE_AUDIENCES.has(value.for)) {
|
|
156
|
+
const forPath = `${path}.for`;
|
|
157
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", forPath, `${forPath} must be "user", "anonymous" or "everyone"`));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const MAX_CACHE_AGE = 2_147_483_647;
|
|
124
161
|
function validateArray(value, key, path, diagnostics) {
|
|
125
162
|
if (!Object.hasOwn(value, key)) {
|
|
126
163
|
return;
|
|
@@ -142,7 +179,7 @@ function validatePipelineHooks(value, path, diagnostics) {
|
|
|
142
179
|
validateArray(value, "before", path, diagnostics);
|
|
143
180
|
validateArray(value, "after", path, diagnostics);
|
|
144
181
|
}
|
|
145
|
-
function validatePipelines(value, path, diagnostics) {
|
|
182
|
+
function validatePipelines(value, path, diagnostics, cacheRefusal) {
|
|
146
183
|
if (!requireRecord(value, path, diagnostics)) {
|
|
147
184
|
return;
|
|
148
185
|
}
|
|
@@ -151,6 +188,16 @@ function validatePipelines(value, path, diagnostics) {
|
|
|
151
188
|
diagnostics.push(diagnostic("CONFIG_MOVED_PROPERTY", `${path}.${key}`, `${path}.${key} moved in rc.1: hooks are ${path}.hooks.${key}`));
|
|
152
189
|
continue;
|
|
153
190
|
}
|
|
191
|
+
if (key === "cache") {
|
|
192
|
+
const refusal = cacheRefusal ?? layerCacheRefusal(path);
|
|
193
|
+
if (refusal !== undefined) {
|
|
194
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.cache`, `${path}.cache: ${refusal}`));
|
|
195
|
+
}
|
|
196
|
+
else if (value.cache !== undefined) {
|
|
197
|
+
validateCache(value.cache, `${path}.cache`, diagnostics);
|
|
198
|
+
}
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
154
201
|
if (!PIPELINE_PROPERTIES.has(key)) {
|
|
155
202
|
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `${path}.${key}`, `unknown pipeline property: ${key}`));
|
|
156
203
|
}
|
|
@@ -162,6 +209,13 @@ function validatePipelines(value, path, diagnostics) {
|
|
|
162
209
|
validatePipelineHooks(value.hooks, `${path}.hooks`, diagnostics);
|
|
163
210
|
}
|
|
164
211
|
}
|
|
212
|
+
function layerCacheRefusal(path) {
|
|
213
|
+
const layer = path.split(".")[0];
|
|
214
|
+
return layer === "application" || layer === "agent"
|
|
215
|
+
? `cache applies to a client's reads; the ${layer} layer is never served a GET (state it at the root or in client)`
|
|
216
|
+
: undefined;
|
|
217
|
+
}
|
|
218
|
+
const WRITE_CACHE_REFUSAL = "cache applies to reads (the find family) only; a write is never a GET";
|
|
165
219
|
function validateForceTransaction(value, path, diagnostics) {
|
|
166
220
|
if (!Object.hasOwn(value, "forceTransaction")) {
|
|
167
221
|
return;
|
|
@@ -171,21 +225,21 @@ function validateForceTransaction(value, path, diagnostics) {
|
|
|
171
225
|
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", propertyPath, `${propertyPath} must be a boolean`));
|
|
172
226
|
}
|
|
173
227
|
}
|
|
174
|
-
function validateOperationLevel(value, path, isFamily, diagnostics) {
|
|
228
|
+
function validateOperationLevel(value, path, isFamily, diagnostics, isRead) {
|
|
175
229
|
if (!requireRecord(value, path, diagnostics)) {
|
|
176
230
|
return;
|
|
177
231
|
}
|
|
178
232
|
for (const [key, child] of Object.entries(value)) {
|
|
179
233
|
const keyPath = `${path}.${key}`;
|
|
180
234
|
if (key === "pipelines") {
|
|
181
|
-
validatePipelines(child, keyPath, diagnostics);
|
|
235
|
+
validatePipelines(child, keyPath, diagnostics, isRead ? undefined : WRITE_CACHE_REFUSAL);
|
|
182
236
|
continue;
|
|
183
237
|
}
|
|
184
238
|
if (key === "forceTransaction") {
|
|
185
239
|
continue;
|
|
186
240
|
}
|
|
187
241
|
if (isFamily && OPERATION_VARIANTS.has(key)) {
|
|
188
|
-
validateOperationLevel(child, keyPath, false, diagnostics);
|
|
242
|
+
validateOperationLevel(child, keyPath, false, diagnostics, isRead);
|
|
189
243
|
continue;
|
|
190
244
|
}
|
|
191
245
|
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, isFamily
|
|
@@ -204,7 +258,7 @@ function validateOperations(value, path, diagnostics) {
|
|
|
204
258
|
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", familyPath, `unknown operation family: ${family}`));
|
|
205
259
|
continue;
|
|
206
260
|
}
|
|
207
|
-
validateOperationLevel(level, familyPath, true, diagnostics);
|
|
261
|
+
validateOperationLevel(level, familyPath, true, diagnostics, family === "find");
|
|
208
262
|
}
|
|
209
263
|
}
|
|
210
264
|
function validateResourceTransactions(value, path, diagnostics) {
|
|
@@ -217,7 +271,7 @@ function validateResourceTransactions(value, path, diagnostics) {
|
|
|
217
271
|
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown Resource transactions property: ${key}`));
|
|
218
272
|
continue;
|
|
219
273
|
}
|
|
220
|
-
validatePipelines(child, keyPath, diagnostics);
|
|
274
|
+
validatePipelines(child, keyPath, diagnostics, "cache applies to reads; a transaction is never a GET");
|
|
221
275
|
}
|
|
222
276
|
}
|
|
223
277
|
function validateDefinition(value, path, diagnostics) {
|
|
@@ -339,7 +393,16 @@ function validateResource(value, path, resource, isRoot, diagnostics) {
|
|
|
339
393
|
continue;
|
|
340
394
|
}
|
|
341
395
|
if (!RESOURCE_PROPERTIES.has(key)) {
|
|
342
|
-
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown Resource property: ${key}; a Resource takes pipelines, operations, transactions and fields`));
|
|
396
|
+
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown Resource property: ${key}; a Resource takes pipelines, operations, transactions and fields (and managedElsewhere at the root)`));
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
if (key === "managedElsewhere") {
|
|
400
|
+
if (!isRoot) {
|
|
401
|
+
diagnostics.push(diagnostic("CONFIG_FORBIDDEN_IN_OVERLAY", keyPath, `${keyPath}: managedElsewhere is only allowed at root; it states who owns the table, which no layer changes (state it at resources.${resource}.managedElsewhere)`));
|
|
402
|
+
}
|
|
403
|
+
else if (typeof child !== "boolean") {
|
|
404
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", keyPath, `${keyPath} must be a boolean`));
|
|
405
|
+
}
|
|
343
406
|
continue;
|
|
344
407
|
}
|
|
345
408
|
if (key === "pipelines") {
|
|
@@ -618,6 +681,20 @@ export function validateFrameworkConfig(value) {
|
|
|
618
681
|
else {
|
|
619
682
|
validateAdapter(value.adapter, diagnostics);
|
|
620
683
|
}
|
|
684
|
+
if (Object.hasOwn(value, "prebuilt") &&
|
|
685
|
+
value.prebuilt !== undefined &&
|
|
686
|
+
(value.prebuilt === null || typeof value.prebuilt !== "object")) {
|
|
687
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "prebuilt", "prebuilt must be the generated prebuilt Contracts object when provided"));
|
|
688
|
+
}
|
|
689
|
+
if (Object.hasOwn(value, "policy") && value.policy !== undefined) {
|
|
690
|
+
validatePolicy(value.policy, diagnostics);
|
|
691
|
+
}
|
|
692
|
+
if (Object.hasOwn(value, "access") && value.access !== undefined) {
|
|
693
|
+
validateAccess(value.access, diagnostics);
|
|
694
|
+
if (Object.hasOwn(value, "policy") && value.policy !== undefined) {
|
|
695
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", "policy", "policy cannot be configured with access: access.policy is the policy engine, and ctx.$state.me the principal; remove policy"));
|
|
696
|
+
}
|
|
697
|
+
}
|
|
621
698
|
if (Object.hasOwn(value, "diagnostics") &&
|
|
622
699
|
value.diagnostics !== undefined &&
|
|
623
700
|
typeof value.diagnostics !== "function") {
|
|
@@ -639,6 +716,155 @@ export function validateFrameworkConfig(value) {
|
|
|
639
716
|
}
|
|
640
717
|
return diagnostics;
|
|
641
718
|
}
|
|
719
|
+
const POLICY_PROPERTIES = new Set(["engine", "principal"]);
|
|
720
|
+
function validatePolicy(value, diagnostics) {
|
|
721
|
+
if (!isPlainRecord(value)) {
|
|
722
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "policy", "policy must be { engine, principal }"));
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
for (const key of Object.keys(value)) {
|
|
726
|
+
if (!POLICY_PROPERTIES.has(key)) {
|
|
727
|
+
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `policy.${key}`, `unknown policy property: ${key}`));
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
if (!Object.hasOwn(value, "principal")) {
|
|
731
|
+
diagnostics.push(diagnostic("CONFIG_REQUIRED", "policy.principal", "policy.principal is required"));
|
|
732
|
+
}
|
|
733
|
+
else if (typeof value.principal !== "function") {
|
|
734
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "policy.principal", "policy.principal must be a function"));
|
|
735
|
+
}
|
|
736
|
+
if (!Object.hasOwn(value, "engine")) {
|
|
737
|
+
diagnostics.push(diagnostic("CONFIG_REQUIRED", "policy.engine", "policy.engine is required"));
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
validatePolicyEngine(value.engine, "policy.engine", diagnostics);
|
|
741
|
+
}
|
|
742
|
+
function validateAccess(value, diagnostics) {
|
|
743
|
+
if (value === null || typeof value !== "object") {
|
|
744
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access", "access must be an access provider, { policy, state }"));
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
const provider = value;
|
|
748
|
+
if (typeof provider.state !== "function") {
|
|
749
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.state", "access.state must be a function"));
|
|
750
|
+
}
|
|
751
|
+
if (provider.client !== undefined) {
|
|
752
|
+
validateAccessClient(provider.client, diagnostics);
|
|
753
|
+
}
|
|
754
|
+
if (provider.policy === undefined) {
|
|
755
|
+
diagnostics.push(diagnostic("CONFIG_REQUIRED", "access.policy", "access.policy is required"));
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
validatePolicyEngine(provider.policy, "access.policy", diagnostics);
|
|
759
|
+
}
|
|
760
|
+
function validateAccessClient(value, diagnostics) {
|
|
761
|
+
if (value === null || typeof value !== "object") {
|
|
762
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.client", "access.client must be an object, { url, verbs }"));
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const client = value;
|
|
766
|
+
if (!isAccessUrl(client.url)) {
|
|
767
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", "access.client.url", 'access.client.url must be an absolute http(s) URL or a root-relative path ("/api/auth")'));
|
|
768
|
+
}
|
|
769
|
+
const verbs = client.verbs;
|
|
770
|
+
if (verbs === null || typeof verbs !== "object") {
|
|
771
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.client.verbs", `access.client.verbs must be an object of $access verbs (${ACCESS_VERB_NAMES.join(", ")})`));
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
for (const name of ACCESS_VERB_NAMES) {
|
|
775
|
+
const verb = providerVerb(verbs, name);
|
|
776
|
+
if (verb !== undefined) {
|
|
777
|
+
validateAccessVerb(verb, `access.client.verbs.${name}`, diagnostics);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
for (const name of Object.keys(verbs)) {
|
|
781
|
+
if (!isAccessVerbName(name)) {
|
|
782
|
+
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `access.client.verbs.${name}`, `access.client.verbs.${name} is not a $access verb`));
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
function validateAccessVerb(value, path, diagnostics) {
|
|
787
|
+
if (value === null || typeof value !== "object") {
|
|
788
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object, { method, path, args?, result, call }`));
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
const verb = value;
|
|
792
|
+
if (verb.method !== "GET" && verb.method !== "POST") {
|
|
793
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.method`, `${path}.method must be "GET" or "POST"`));
|
|
794
|
+
}
|
|
795
|
+
if (!isAccessPath(verb.path)) {
|
|
796
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.path`, `${path}.path must be a path under access.client.url, starting with one "/"`));
|
|
797
|
+
}
|
|
798
|
+
for (const schema of ["args", "result"]) {
|
|
799
|
+
const given = verb[schema];
|
|
800
|
+
if ((schema === "result" || given !== undefined) && !isPlainRecord(given)) {
|
|
801
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${path}.${schema}`, `${path}.${schema} must be a JSON Schema object`));
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
if (typeof verb.call !== "function") {
|
|
805
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${path}.call`, `${path}.call must be a function`));
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
function validatePolicyEngine(engine, at, diagnostics) {
|
|
809
|
+
if (engine === null || typeof engine !== "object") {
|
|
810
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", at, `${at} must be an object`));
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
const members = engine;
|
|
814
|
+
for (const question of ["can", "scopeOf", "fieldsOf"]) {
|
|
815
|
+
if (typeof members[question] !== "function") {
|
|
816
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${question}`, `${at}.${question} must be a function`));
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
for (const optional of ["grantsOf", "hosted"]) {
|
|
820
|
+
if (members[optional] !== undefined &&
|
|
821
|
+
typeof members[optional] !== "function") {
|
|
822
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${optional}`, `${at}.${optional} must be a function when present`));
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
validatePolicyLists(members.governed, at, "governed", { all: "string lists", one: "a list of strings" }, isStringList, diagnostics);
|
|
826
|
+
validatePolicyLists(members.paths, at, "paths", {
|
|
827
|
+
all: "path lists",
|
|
828
|
+
one: "a list of paths, each a list of strings",
|
|
829
|
+
}, (paths) => Array.isArray(paths) && paths.every(isStringList), diagnostics);
|
|
830
|
+
validatePolicyLists(members.afterChecks, at, "afterChecks", { all: "action lists", one: "a list of actions" }, isStringList, diagnostics);
|
|
831
|
+
validateAfterCheckActions(members.afterChecks, at, diagnostics);
|
|
832
|
+
if (members.unheld !== undefined && !isStringList(members.unheld)) {
|
|
833
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.unheld`, `${at}.unheld must be a list of Resource names when provided`));
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function validateAfterCheckActions(lists, at, diagnostics) {
|
|
837
|
+
if (!isPlainRecord(lists)) {
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
for (const [resource, actions] of Object.entries(lists)) {
|
|
841
|
+
if (!isStringList(actions)) {
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
for (const action of actions) {
|
|
845
|
+
if (action !== "update") {
|
|
846
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${at}.afterChecks.${resource}`, `${at}.afterChecks.${resource}: "${action}" is no action an after check runs on; only "update" is`));
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
function isStringList(value) {
|
|
852
|
+
return (Array.isArray(value) && value.every((name) => typeof name === "string"));
|
|
853
|
+
}
|
|
854
|
+
function validatePolicyLists(lists, at, list, entry, isEntry, diagnostics) {
|
|
855
|
+
if (lists === undefined) {
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
if (!isPlainRecord(lists)) {
|
|
859
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${list}`, `${at}.${list} must be an object of ${entry.all} when provided`));
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
for (const [key, value] of Object.entries(lists)) {
|
|
863
|
+
if (!isEntry(value)) {
|
|
864
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${list}.${key}`, `${at}.${list}.${key} must be ${entry.one}`));
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
642
868
|
function validateMcp(value, api, diagnostics) {
|
|
643
869
|
if (typeof value === "string") {
|
|
644
870
|
validateMcpPath(value, "mcp", api, diagnostics);
|
|
@@ -704,9 +930,10 @@ function validateMcpAuthorization(value, diagnostics) {
|
|
|
704
930
|
}
|
|
705
931
|
else {
|
|
706
932
|
value.servers.forEach((server, index) => {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
933
|
+
const serverPath = `${serversPath}[${index}]`;
|
|
934
|
+
const refusal = authorizationServerRefusal(server, serverPath);
|
|
935
|
+
if (refusal !== undefined) {
|
|
936
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", serverPath, refusal));
|
|
710
937
|
}
|
|
711
938
|
});
|
|
712
939
|
}
|
|
@@ -718,14 +945,49 @@ function validateMcpAuthorization(value, diagnostics) {
|
|
|
718
945
|
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", verifyPath, `${verifyPath} must be a function: token in, the caller or null out`));
|
|
719
946
|
}
|
|
720
947
|
}
|
|
721
|
-
|
|
948
|
+
const LOOPBACK_HOSTNAMES = new Set(["127.0.0.1", "[::1]"]);
|
|
949
|
+
const LOOPBACK_NAME = "localhost";
|
|
950
|
+
function authorizationServerRefusal(value, path) {
|
|
951
|
+
const notHttps = `${path} must be an absolute https URL`;
|
|
722
952
|
if (typeof value !== "string") {
|
|
723
|
-
return
|
|
953
|
+
return notHttps;
|
|
724
954
|
}
|
|
955
|
+
let url;
|
|
725
956
|
try {
|
|
726
|
-
|
|
957
|
+
url = new URL(value);
|
|
727
958
|
}
|
|
728
959
|
catch {
|
|
729
|
-
return
|
|
960
|
+
return notHttps;
|
|
961
|
+
}
|
|
962
|
+
const http = url.protocol === "http:";
|
|
963
|
+
if (!http && url.protocol !== "https:") {
|
|
964
|
+
return notHttps;
|
|
965
|
+
}
|
|
966
|
+
if (http &&
|
|
967
|
+
((!LOOPBACK_HOSTNAMES.has(url.hostname) &&
|
|
968
|
+
url.hostname !== LOOPBACK_NAME) ||
|
|
969
|
+
url.username !== "" ||
|
|
970
|
+
url.password !== "")) {
|
|
971
|
+
return notHttps;
|
|
972
|
+
}
|
|
973
|
+
if (url.pathname.includes("//")) {
|
|
974
|
+
return `${path} has an empty path segment ("//"); a client can read what follows it as another host`;
|
|
975
|
+
}
|
|
976
|
+
if (url.port === "0") {
|
|
977
|
+
return `${path} names port 0, which no server listens on`;
|
|
978
|
+
}
|
|
979
|
+
if (url.href.includes("?") || url.href.includes("#")) {
|
|
980
|
+
return `${path} has a query or fragment; an authorization server's URL (its issuer) takes neither`;
|
|
981
|
+
}
|
|
982
|
+
if (!http) {
|
|
983
|
+
return undefined;
|
|
984
|
+
}
|
|
985
|
+
if (url.hostname === LOOPBACK_NAME) {
|
|
986
|
+
url.hostname = "127.0.0.1";
|
|
730
987
|
}
|
|
988
|
+
const canonical = url.href;
|
|
989
|
+
const short = canonical === `${url.origin}/` ? url.origin : canonical;
|
|
990
|
+
return value === canonical || value === short
|
|
991
|
+
? undefined
|
|
992
|
+
: `${path} is an http loopback URL; write it as ${short}, the spelling every client reads as this machine`;
|
|
731
993
|
}
|
|
@@ -16,10 +16,6 @@ type OverlayLayer = "application" | "client" | "agent";
|
|
|
16
16
|
type ResourceOverlays = {
|
|
17
17
|
readonly [L in OverlayLayer]?: unknown;
|
|
18
18
|
};
|
|
19
|
-
/** The overlay blocks `Overlays`, each checked against the root `Block`. */
|
|
20
|
-
type CheckedOverlays<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, Block, Overlays> = {
|
|
21
|
-
readonly [L in keyof Overlays]: L extends OverlayLayer ? NoInfer<AvConfigResource<M, ResourceBlockConfig<R, Block>, R, "overlay"> & ExactOverlayResource<M, ResourceBlockConfig<R, Block>, R, Overlays[L]>> : never;
|
|
22
|
-
};
|
|
23
19
|
/**
|
|
24
20
|
* What {@link defineResource} returns: `root`, and `application`, `client` and
|
|
25
21
|
* `agent` exactly when they were given, each `{ [R]: block }` to spread into that
|
|
@@ -53,5 +49,5 @@ export type AvDefinedResource<R extends string, Block, Overlays> = {
|
|
|
53
49
|
* client: { resources: { ...post.client } },
|
|
54
50
|
* ```
|
|
55
51
|
*/
|
|
56
|
-
export declare function defineResource<M extends AvAdapterModel>(): <const R extends AvConfigResourceKey<M>, const Block = AvConfigResource<M, AvConfigAny, R, "root">, const Overlays extends ResourceOverlays = Record<never, never>>(resource: R, block: Block & NoInfer<AvConfigResource<M, ResourceBlockConfig<R, Block>, R, "root"> & ExactRootResource<M, R, Block>>, overlays?: Overlays &
|
|
52
|
+
export declare function defineResource<M extends AvAdapterModel>(): <const R extends AvConfigResourceKey<M>, const Block = AvConfigResource<M, AvConfigAny, R, "root">, const Overlays extends ResourceOverlays = Record<never, never>>(resource: R, block: Block & NoInfer<AvConfigResource<M, ResourceBlockConfig<R, Block>, R, "root"> & ExactRootResource<M, R, Block>>, overlays?: Overlays & { readonly [L in keyof Overlays]: L extends OverlayLayer ? NoInfer<AvConfigResource<M, ResourceBlockConfig<R, Block>, R, "overlay", L> & ExactOverlayResource<M, ResourceBlockConfig<R, Block>, R, Overlays[L]>> : never; }) => AvDefinedResource<R, ErasedResourceBlock<Block>, ErasedOverlayBlocks<Overlays>>;
|
|
57
53
|
export {};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Root is the empty string, not `"/"`, so a route joins onto it by concatenation with
|
|
5
5
|
* no special case.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
type EntrypointPath = "" | `/${string}`;
|
|
8
8
|
/**
|
|
9
9
|
* Why a mount path is refused. Only the slash spelling is ever coerced
|
|
10
10
|
* (`api`, `/api/` and `//api//` are one intent, `/api`); everything else that is
|
|
@@ -17,7 +17,7 @@ export type EntrypointRefusalReason = "whitespace" | "scheme" | "query" | "fragm
|
|
|
17
17
|
* and the rule, and never echoes the value: an entrypoint may carry
|
|
18
18
|
* credentials (the client's rule, shared by the server).
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
type EntrypointNormalization = {
|
|
21
21
|
readonly ok: true;
|
|
22
22
|
readonly path: EntrypointPath;
|
|
23
23
|
} | {
|
|
@@ -30,3 +30,4 @@ export type EntrypointNormalization = {
|
|
|
30
30
|
* or a refusal.
|
|
31
31
|
*/
|
|
32
32
|
export declare function normalizeEntrypoint(value: string): EntrypointNormalization;
|
|
33
|
+
export {};
|
|
@@ -16,6 +16,10 @@ type PipelinesSchema = {
|
|
|
16
16
|
};
|
|
17
17
|
readonly interceptors: Leaf;
|
|
18
18
|
readonly filters: Leaf;
|
|
19
|
+
readonly cache: {
|
|
20
|
+
readonly for: Leaf;
|
|
21
|
+
readonly maxAge: Leaf;
|
|
22
|
+
};
|
|
19
23
|
};
|
|
20
24
|
type LimitsSchema = {
|
|
21
25
|
readonly maxRequestBytes: Leaf;
|
|
@@ -24,6 +28,8 @@ type LimitsSchema = {
|
|
|
24
28
|
readonly maxTransactionOperations: Leaf;
|
|
25
29
|
readonly maxBooleanNodes: Leaf;
|
|
26
30
|
readonly maxJsonDepth: Leaf;
|
|
31
|
+
readonly maxAll: Leaf;
|
|
32
|
+
readonly maxAllConcurrency: Leaf;
|
|
27
33
|
};
|
|
28
34
|
type LevelSchema = {
|
|
29
35
|
readonly pipelines: PipelinesSchema;
|
|
@@ -103,9 +109,11 @@ type TokenOf<Member> = Member extends {
|
|
|
103
109
|
} ? {
|
|
104
110
|
[K in keyof Member]: K extends "scopes" ? never : Member[K] extends readonly (infer Token)[] ? Token : never;
|
|
105
111
|
}[keyof Member] : Member extends readonly (infer Token)[] ? Token : never;
|
|
112
|
+
/** The capability members an exemption never names. */
|
|
113
|
+
type AdapterStatedMember = "nestedWriteFilter" | "filterModes" | "pathFilterModes";
|
|
106
114
|
/** A field's exemption against its capabilities: their names, and each one's tokens. */
|
|
107
|
-
type CapabilityExemptionSchema<Caps> = ListOf<Exclude<keyof Caps,
|
|
108
|
-
readonly [K in Exclude<keyof Caps,
|
|
115
|
+
type CapabilityExemptionSchema<Caps> = ListOf<Exclude<keyof Caps, AdapterStatedMember>> & {
|
|
116
|
+
readonly [K in Exclude<keyof Caps, AdapterStatedMember>]-?: ListOf<TokenOf<NonNullable<Caps[K]>>>;
|
|
109
117
|
};
|
|
110
118
|
type FieldExemptionSchema<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, F> = F extends AvAdapterFieldKey<M, R> ? M["resources"][R]["fields"][F] extends {
|
|
111
119
|
readonly kind: "relation";
|
|
@@ -131,33 +139,58 @@ type ExemptionsSchema<M extends AvAdapterModel, Cfg> = {
|
|
|
131
139
|
};
|
|
132
140
|
};
|
|
133
141
|
};
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
declare const refusal: unique symbol;
|
|
143
|
+
/** What a level refuses an unknown key for: `layer` cannot expose it, `parent` hid it, under `at`. */
|
|
144
|
+
type Refusal<Layer extends string, Parent extends string, At extends string> = {
|
|
145
|
+
readonly [refusal]: {
|
|
146
|
+
readonly layer: Layer;
|
|
147
|
+
readonly parent: Parent;
|
|
148
|
+
readonly at: At;
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
/** The sentence a refused key `K` holding `Value` is typed as; `never` for an entry written `false`. */
|
|
152
|
+
type RefusalOf<Info, K, Value> = [Value] extends [false] ? never : Info extends {
|
|
153
|
+
readonly layer: infer Layer extends string;
|
|
154
|
+
readonly parent: infer Parent extends string;
|
|
155
|
+
readonly at: infer At extends string;
|
|
156
|
+
} ? Value extends readonly unknown[] ? {
|
|
157
|
+
readonly [S in `Error: ${Layer} cannot expose '${At}${K & string}': hidden by ${Parent}`]: true;
|
|
158
|
+
} : readonly [
|
|
159
|
+
`Error: ${Layer} cannot expose '${At}${K & string}': hidden by ${Parent}`
|
|
160
|
+
] : never;
|
|
161
|
+
/** A Pick layer's operations exemption, a family or variant its parent hid refused by name. */
|
|
162
|
+
type PickOperationsSchema<Ops, Layer extends string, Parent extends string, R extends string> = ListOf<keyof Ops> & {
|
|
163
|
+
readonly [F in keyof Ops]-?: ListOf<keyof NonNullable<Ops[F]>> & {
|
|
164
|
+
readonly [V in keyof NonNullable<Ops[F]>]: Leaf;
|
|
165
|
+
} & Refusal<Layer, Parent, `${R}.${F & string}.`>;
|
|
166
|
+
} & Refusal<Layer, Parent, `${R}.`>;
|
|
167
|
+
/** The fields of one Resource of a view. */
|
|
168
|
+
type ViewFields<Resource> = Resource extends {
|
|
169
|
+
readonly fields: infer Fields;
|
|
170
|
+
} ? Fields : never;
|
|
171
|
+
/** A Pick layer's exemptions, against its parent's view. */
|
|
172
|
+
type PickExemptionsSchema<Resources, Layer extends string, Parent extends string> = {
|
|
136
173
|
readonly resources: {
|
|
137
174
|
readonly [R in keyof Resources]: {
|
|
138
|
-
readonly operations:
|
|
175
|
+
readonly operations: PickOperationsSchema<Resources[R] extends {
|
|
139
176
|
readonly operations: infer Ops;
|
|
140
|
-
} ? Ops : never>;
|
|
177
|
+
} ? Ops : never, Layer, Parent, R & string>;
|
|
141
178
|
readonly fields: {
|
|
142
|
-
readonly [F in keyof
|
|
143
|
-
readonly fields: infer Fields;
|
|
144
|
-
} ? Fields : never)]: CapabilityExemptionSchema<(Resources[R] extends {
|
|
145
|
-
readonly fields: infer Fields;
|
|
146
|
-
} ? Fields : never)[F] extends {
|
|
179
|
+
readonly [F in keyof ViewFields<Resources[R]>]: CapabilityExemptionSchema<ViewFields<Resources[R]>[F] extends {
|
|
147
180
|
readonly capabilities: infer Caps;
|
|
148
|
-
} ? Caps : never
|
|
149
|
-
}
|
|
181
|
+
} ? Caps : never> & Refusal<Layer, Parent, `${R & string}.${F & string}.`>;
|
|
182
|
+
} & Refusal<Layer, Parent, `${R & string}.`>;
|
|
150
183
|
};
|
|
151
|
-
}
|
|
184
|
+
} & Refusal<Layer, Parent, "">;
|
|
152
185
|
};
|
|
153
186
|
/** A layer's own configuration: `application`, `client` or `agent`. */
|
|
154
187
|
type OverlayOf<Cfg, Layer extends "application" | "client" | "agent"> = (Cfg & {
|
|
155
188
|
readonly [L in Layer]?: unknown;
|
|
156
189
|
})[Layer];
|
|
157
190
|
/** An overlay's exemptions schema, by the overlay's own `exposed`. */
|
|
158
|
-
type OverlayExemptionsSchema<M extends AvAdapterModel, Cfg, Overlay> = Overlay extends {
|
|
191
|
+
type OverlayExemptionsSchema<M extends AvAdapterModel, Cfg, Overlay, Layer extends "application" | "client"> = Overlay extends {
|
|
159
192
|
readonly exposed: false;
|
|
160
|
-
} ? PickExemptionsSchema<RootViewResources<M, Cfg
|
|
193
|
+
} ? PickExemptionsSchema<RootViewResources<M, Cfg>, Layer, "root"> : ExemptionsSchema<M, Cfg>;
|
|
161
194
|
type LayerKeysSchema = {
|
|
162
195
|
readonly exposed: Leaf;
|
|
163
196
|
readonly transactionsStyle: Leaf;
|
|
@@ -167,7 +200,9 @@ type LayerKeysSchema = {
|
|
|
167
200
|
type RootResourcesSchema<M extends AvAdapterModel> = {
|
|
168
201
|
readonly [R in AvConfigResourceKey<M>]: ResourceSchema<M, R, FieldsSchema<M, R, "root", AvAdapterFieldKey<M, R>> & {
|
|
169
202
|
readonly [otherKeys]: RootScalarFieldSchema;
|
|
170
|
-
}
|
|
203
|
+
}> & {
|
|
204
|
+
readonly managedElsewhere: Leaf;
|
|
205
|
+
};
|
|
171
206
|
};
|
|
172
207
|
/**
|
|
173
208
|
* One root `resources.<R>` block, checked key by key as
|
|
@@ -183,7 +218,7 @@ type OverlaySchema<M extends AvAdapterModel, Cfg, Layer extends "application" |
|
|
|
183
218
|
readonly resources: {
|
|
184
219
|
readonly [R in AvConfigResourceKey<M>]: ResourceSchema<M, R, FieldsSchema<M, R, "overlay", AvEffectiveFieldKey<M, Cfg, R>>>;
|
|
185
220
|
};
|
|
186
|
-
readonly exemptions: OverlayExemptionsSchema<M, Cfg, OverlayOf<Cfg, Layer
|
|
221
|
+
readonly exemptions: OverlayExemptionsSchema<M, Cfg, OverlayOf<Cfg, Layer>, Layer>;
|
|
187
222
|
};
|
|
188
223
|
type McpSchema = {
|
|
189
224
|
readonly path: Leaf;
|
|
@@ -197,7 +232,7 @@ type AgentParentOf<Cfg> = OverlayOf<Cfg, "agent"> extends {
|
|
|
197
232
|
readonly extends: infer Parent;
|
|
198
233
|
} ? Parent : "client";
|
|
199
234
|
/** A Pick agent's exemptions, against the view of the layer it extends. */
|
|
200
|
-
type AgentPickExemptionsSchema<M extends AvAdapterModel, Cfg, Parent> = Parent extends "application" | "client" ? [Parent] extends ["application"] | ["client"] ? PickExemptionsSchema<OverlayViewResources<M, Cfg, Parent
|
|
235
|
+
type AgentPickExemptionsSchema<M extends AvAdapterModel, Cfg, Parent> = Parent extends "application" | "client" ? [Parent] extends ["application"] | ["client"] ? PickExemptionsSchema<OverlayViewResources<M, Cfg, Parent>, "agent", Parent> : PickExemptionsSchema<RootViewResources<M, Cfg>, "agent", "root"> : PickExemptionsSchema<RootViewResources<M, Cfg>, "agent", "root">;
|
|
201
236
|
type AgentSchema<M extends AvAdapterModel, Cfg> = LayerKeysSchema & {
|
|
202
237
|
readonly extends: Leaf;
|
|
203
238
|
readonly resources: {
|
|
@@ -211,6 +246,12 @@ type RootSchema<M extends AvAdapterModel, Cfg> = LayerKeysSchema & {
|
|
|
211
246
|
readonly api: Leaf;
|
|
212
247
|
readonly mcp: McpSchema;
|
|
213
248
|
readonly adapter: Leaf;
|
|
249
|
+
readonly prebuilt: Leaf;
|
|
250
|
+
readonly policy: {
|
|
251
|
+
readonly engine: Leaf;
|
|
252
|
+
readonly principal: Leaf;
|
|
253
|
+
};
|
|
254
|
+
readonly access: Leaf;
|
|
214
255
|
readonly diagnostics: Leaf;
|
|
215
256
|
readonly misuse: Leaf;
|
|
216
257
|
readonly resources: RootResourcesSchema<M>;
|
|
@@ -219,9 +260,12 @@ type RootSchema<M extends AvAdapterModel, Cfg> = LayerKeysSchema & {
|
|
|
219
260
|
readonly client: OverlaySchema<M, Cfg, "client">;
|
|
220
261
|
readonly agent: AgentSchema<M, Cfg>;
|
|
221
262
|
};
|
|
222
|
-
/**
|
|
263
|
+
/**
|
|
264
|
+
* `V` with every key schema `S` lacks mapped to `never`, or to the sentence a
|
|
265
|
+
* refusing level states; every leaf `unknown`.
|
|
266
|
+
*/
|
|
223
267
|
type Exact<S, V> = [S] extends [Leaf] ? unknown : V extends readonly unknown[] ? S extends ListOf<infer Names> ? readonly Names[] : unknown : V extends (...args: any) => any ? unknown : V extends object ? string extends keyof V ? unknown : {
|
|
224
|
-
readonly [K in keyof V]: K extends keyof S ? Exact<S[K], V[K]> : typeof otherKeys extends keyof S ? Exact<S[typeof otherKeys], V[K]> : never;
|
|
268
|
+
readonly [K in keyof V]: K extends keyof S ? Exact<S[K], V[K]> : typeof otherKeys extends keyof S ? Exact<S[typeof otherKeys], V[K]> : typeof refusal extends keyof S ? RefusalOf<S[typeof refusal], K, V[K]> : never;
|
|
225
269
|
} : unknown;
|
|
226
270
|
/**
|
|
227
271
|
* The authored configuration `Cfg`, checked key by key: a key no level of the
|
|
@@ -229,7 +273,14 @@ type Exact<S, V> = [S] extends [Leaf] ? unknown : V extends readonly unknown[] ?
|
|
|
229
273
|
* rc.0 key, a `definition` in an overlay, a stage a relation field does not take,
|
|
230
274
|
* or a name the model and the root do not have.
|
|
231
275
|
*/
|
|
232
|
-
export type AvConfigExact<M extends AvAdapterModel, Cfg> = Exact<RootSchema<M, Cfg>, Cfg> & ExposedWithExemptions<Cfg, "application"> & ExposedWithExemptions<Cfg, "client"> & ExposedWithExemptions<Cfg, "agent"> & ForceNeedsTransactions<M, Cfg
|
|
276
|
+
export type AvConfigExact<M extends AvAdapterModel, Cfg> = Exact<RootSchema<M, Cfg>, Cfg> & ExposedWithExemptions<Cfg, "application"> & ExposedWithExemptions<Cfg, "client"> & ExposedWithExemptions<Cfg, "agent"> & ForceNeedsTransactions<M, Cfg> & (Cfg extends {
|
|
277
|
+
readonly access: object;
|
|
278
|
+
readonly policy: object;
|
|
279
|
+
} ? {
|
|
280
|
+
readonly policy: readonly [
|
|
281
|
+
"Error: `access` brings the policy engine; remove `policy`"
|
|
282
|
+
];
|
|
283
|
+
} : unknown);
|
|
233
284
|
/** A layer's own literal `transactionsStyle`, `undefined` when it states none. */
|
|
234
285
|
type StyleOf<Layer> = Layer extends {
|
|
235
286
|
readonly transactionsStyle: infer Style;
|
|
@@ -17,3 +17,5 @@ export declare function computeOfLayer(resources: unknown): ResolvedComputeConfi
|
|
|
17
17
|
* chained phase by phase. Nothing is disabled from below.
|
|
18
18
|
*/
|
|
19
19
|
export declare function chainCompute(root: ResolvedComputeConfig, overlay: ResolvedComputeConfig): ResolvedComputeConfig;
|
|
20
|
+
/** The fields of `resource` with a `compute.create` stage in `compute`. */
|
|
21
|
+
export declare function createComputedFields(compute: ResolvedComputeConfig, resource: string): ReadonlySet<string>;
|