@aventara/core 1.0.0-rc.1 → 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 +943 -16
- package/ERRORS.md +142 -0
- package/README.md +274 -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 +227 -24
- 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/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 +65 -0
- package/dist/config/config.validator.js +222 -8
- 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 +67 -22
- package/dist/config/field-compute.resolver.d.ts +2 -0
- package/dist/config/field-compute.resolver.js +8 -0
- 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 +4 -4
- package/dist/config/pipeline-tree.resolver.d.ts +2 -2
- 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 +26 -1
- package/dist/contracts/capability.js +20 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +301 -89
- package/dist/contracts/client-contract-structure.validator.js +37 -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 +30 -4
- package/dist/contracts/contract-hash.d.ts +0 -1
- package/dist/contracts/contract-hash.js +1 -1
- package/dist/contracts/contract.d.ts +27 -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 +78 -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 +120 -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 +115 -23
- package/dist/framework/operation-facade.d.ts +80 -13
- package/dist/framework/operation-facade.js +2 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +1 -0
- package/dist/internal.d.ts +7 -2
- package/dist/internal.js +6 -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 +159 -36
- package/dist/operations/operation-validator.d.ts +1 -1
- package/dist/operations/structural-limits.walker.d.ts +1 -1
- 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 +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 +9 -27
- package/dist/protocol/absent-route.responder.js +36 -3
- package/dist/protocol/contract-document.responder.d.ts +2 -1
- package/dist/protocol/http-request.decoder.d.ts +19 -3
- package/dist/protocol/http-request.decoder.js +24 -1
- package/dist/protocol/http-request.reader.d.ts +6 -3
- package/dist/protocol/http-request.reader.js +1 -0
- package/dist/protocol/http-response.encoder.js +2 -2
- package/dist/protocol/protocol-headers.d.ts +3 -3
- package/dist/protocol/protocol-surface.d.ts +6 -1
- package/dist/protocol/protocol-surface.js +7 -0
- package/dist/protocol/protocol.binder.d.ts +16 -1
- package/dist/protocol/protocol.binder.js +4 -1
- package/dist/protocol/protocol.handler.d.ts +12 -1
- package/dist/protocol/protocol.handler.js +86 -17
- 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 +232 -45
- 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 +129 -21
- package/dist/runtime/decimal.d.ts +14 -0
- package/dist/runtime/decimal.js +21 -0
- package/dist/runtime/diagnostics-reporter.d.ts +44 -9
- package/dist/runtime/diagnostics-reporter.js +13 -1
- 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 -1
- package/dist/runtime/field-stage.runtime.js +8 -4
- package/dist/runtime/field-validator.runtime.d.ts +19 -1
- package/dist/runtime/field-validator.runtime.js +47 -8
- 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 +3 -14
- 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/owned-execution.registry.d.ts +13 -3
- 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 +47 -22
- package/dist/runtime/readonly-value.d.ts +20 -5
- package/dist/runtime/readonly-value.js +74 -26
- package/dist/runtime/referential-action.d.ts +1 -1
- package/dist/runtime/scalar-runtime.d.ts +4 -11
- package/dist/runtime/scalar-runtime.js +91 -22
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- package/dist/transactions/operation-arguments-encoder.js +8 -3
- 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 +38 -5
- 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 +48 -10
- package/dist/transactions/transaction-plan-validator.d.ts +23 -7
- package/dist/transactions/transaction-plan-validator.js +27 -1
- package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
- 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 +79 -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 +7 -4
- package/package.json +6 -5
- package/src/runtime/field-check.evaluator.ts +1 -1
|
@@ -1,10 +1,15 @@
|
|
|
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";
|
|
2
4
|
import { normalizeEntrypoint } from "./entrypoint.normalizer.js";
|
|
3
5
|
import { AVZ_FORMATS } from "./framework-field-definition.js";
|
|
4
6
|
const ROOT_ONLY_PROPERTIES = new Set([
|
|
5
7
|
"api",
|
|
6
8
|
"mcp",
|
|
7
9
|
"adapter",
|
|
10
|
+
"prebuilt",
|
|
11
|
+
"policy",
|
|
12
|
+
"access",
|
|
8
13
|
"diagnostics",
|
|
9
14
|
"misuse",
|
|
10
15
|
"application",
|
|
@@ -36,6 +41,7 @@ const RESOURCE_PROPERTIES = new Set([
|
|
|
36
41
|
"operations",
|
|
37
42
|
"transactions",
|
|
38
43
|
"fields",
|
|
44
|
+
"managedElsewhere",
|
|
39
45
|
]);
|
|
40
46
|
const FIELD_PROPERTIES = new Set(["definition", "pipelines"]);
|
|
41
47
|
const DEFINITION_PROPERTIES = new Set([
|
|
@@ -339,7 +345,16 @@ function validateResource(value, path, resource, isRoot, diagnostics) {
|
|
|
339
345
|
continue;
|
|
340
346
|
}
|
|
341
347
|
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`));
|
|
348
|
+
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", keyPath, `unknown Resource property: ${key}; a Resource takes pipelines, operations, transactions and fields (and managedElsewhere at the root)`));
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (key === "managedElsewhere") {
|
|
352
|
+
if (!isRoot) {
|
|
353
|
+
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)`));
|
|
354
|
+
}
|
|
355
|
+
else if (typeof child !== "boolean") {
|
|
356
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", keyPath, `${keyPath} must be a boolean`));
|
|
357
|
+
}
|
|
343
358
|
continue;
|
|
344
359
|
}
|
|
345
360
|
if (key === "pipelines") {
|
|
@@ -618,6 +633,20 @@ export function validateFrameworkConfig(value) {
|
|
|
618
633
|
else {
|
|
619
634
|
validateAdapter(value.adapter, diagnostics);
|
|
620
635
|
}
|
|
636
|
+
if (Object.hasOwn(value, "prebuilt") &&
|
|
637
|
+
value.prebuilt !== undefined &&
|
|
638
|
+
(value.prebuilt === null || typeof value.prebuilt !== "object")) {
|
|
639
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "prebuilt", "prebuilt must be the generated prebuilt Contracts object when provided"));
|
|
640
|
+
}
|
|
641
|
+
if (Object.hasOwn(value, "policy") && value.policy !== undefined) {
|
|
642
|
+
validatePolicy(value.policy, diagnostics);
|
|
643
|
+
}
|
|
644
|
+
if (Object.hasOwn(value, "access") && value.access !== undefined) {
|
|
645
|
+
validateAccess(value.access, diagnostics);
|
|
646
|
+
if (Object.hasOwn(value, "policy") && value.policy !== undefined) {
|
|
647
|
+
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"));
|
|
648
|
+
}
|
|
649
|
+
}
|
|
621
650
|
if (Object.hasOwn(value, "diagnostics") &&
|
|
622
651
|
value.diagnostics !== undefined &&
|
|
623
652
|
typeof value.diagnostics !== "function") {
|
|
@@ -639,6 +668,155 @@ export function validateFrameworkConfig(value) {
|
|
|
639
668
|
}
|
|
640
669
|
return diagnostics;
|
|
641
670
|
}
|
|
671
|
+
const POLICY_PROPERTIES = new Set(["engine", "principal"]);
|
|
672
|
+
function validatePolicy(value, diagnostics) {
|
|
673
|
+
if (!isPlainRecord(value)) {
|
|
674
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "policy", "policy must be { engine, principal }"));
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
for (const key of Object.keys(value)) {
|
|
678
|
+
if (!POLICY_PROPERTIES.has(key)) {
|
|
679
|
+
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `policy.${key}`, `unknown policy property: ${key}`));
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (!Object.hasOwn(value, "principal")) {
|
|
683
|
+
diagnostics.push(diagnostic("CONFIG_REQUIRED", "policy.principal", "policy.principal is required"));
|
|
684
|
+
}
|
|
685
|
+
else if (typeof value.principal !== "function") {
|
|
686
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "policy.principal", "policy.principal must be a function"));
|
|
687
|
+
}
|
|
688
|
+
if (!Object.hasOwn(value, "engine")) {
|
|
689
|
+
diagnostics.push(diagnostic("CONFIG_REQUIRED", "policy.engine", "policy.engine is required"));
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
validatePolicyEngine(value.engine, "policy.engine", diagnostics);
|
|
693
|
+
}
|
|
694
|
+
function validateAccess(value, diagnostics) {
|
|
695
|
+
if (value === null || typeof value !== "object") {
|
|
696
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access", "access must be an access provider, { policy, state }"));
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
const provider = value;
|
|
700
|
+
if (typeof provider.state !== "function") {
|
|
701
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.state", "access.state must be a function"));
|
|
702
|
+
}
|
|
703
|
+
if (provider.client !== undefined) {
|
|
704
|
+
validateAccessClient(provider.client, diagnostics);
|
|
705
|
+
}
|
|
706
|
+
if (provider.policy === undefined) {
|
|
707
|
+
diagnostics.push(diagnostic("CONFIG_REQUIRED", "access.policy", "access.policy is required"));
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
validatePolicyEngine(provider.policy, "access.policy", diagnostics);
|
|
711
|
+
}
|
|
712
|
+
function validateAccessClient(value, diagnostics) {
|
|
713
|
+
if (value === null || typeof value !== "object") {
|
|
714
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.client", "access.client must be an object, { url, verbs }"));
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
const client = value;
|
|
718
|
+
if (!isAccessUrl(client.url)) {
|
|
719
|
+
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")'));
|
|
720
|
+
}
|
|
721
|
+
const verbs = client.verbs;
|
|
722
|
+
if (verbs === null || typeof verbs !== "object") {
|
|
723
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", "access.client.verbs", `access.client.verbs must be an object of $access verbs (${ACCESS_VERB_NAMES.join(", ")})`));
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
for (const name of ACCESS_VERB_NAMES) {
|
|
727
|
+
const verb = providerVerb(verbs, name);
|
|
728
|
+
if (verb !== undefined) {
|
|
729
|
+
validateAccessVerb(verb, `access.client.verbs.${name}`, diagnostics);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
for (const name of Object.keys(verbs)) {
|
|
733
|
+
if (!isAccessVerbName(name)) {
|
|
734
|
+
diagnostics.push(diagnostic("CONFIG_UNKNOWN_PROPERTY", `access.client.verbs.${name}`, `access.client.verbs.${name} is not a $access verb`));
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
function validateAccessVerb(value, path, diagnostics) {
|
|
739
|
+
if (value === null || typeof value !== "object") {
|
|
740
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", path, `${path} must be an object, { method, path, args?, result, call }`));
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
const verb = value;
|
|
744
|
+
if (verb.method !== "GET" && verb.method !== "POST") {
|
|
745
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.method`, `${path}.method must be "GET" or "POST"`));
|
|
746
|
+
}
|
|
747
|
+
if (!isAccessPath(verb.path)) {
|
|
748
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${path}.path`, `${path}.path must be a path under access.client.url, starting with one "/"`));
|
|
749
|
+
}
|
|
750
|
+
for (const schema of ["args", "result"]) {
|
|
751
|
+
const given = verb[schema];
|
|
752
|
+
if ((schema === "result" || given !== undefined) && !isPlainRecord(given)) {
|
|
753
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${path}.${schema}`, `${path}.${schema} must be a JSON Schema object`));
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (typeof verb.call !== "function") {
|
|
757
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${path}.call`, `${path}.call must be a function`));
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
function validatePolicyEngine(engine, at, diagnostics) {
|
|
761
|
+
if (engine === null || typeof engine !== "object") {
|
|
762
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", at, `${at} must be an object`));
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const members = engine;
|
|
766
|
+
for (const question of ["can", "scopeOf", "fieldsOf"]) {
|
|
767
|
+
if (typeof members[question] !== "function") {
|
|
768
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${question}`, `${at}.${question} must be a function`));
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
for (const optional of ["grantsOf", "hosted"]) {
|
|
772
|
+
if (members[optional] !== undefined &&
|
|
773
|
+
typeof members[optional] !== "function") {
|
|
774
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${optional}`, `${at}.${optional} must be a function when present`));
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
validatePolicyLists(members.governed, at, "governed", { all: "string lists", one: "a list of strings" }, isStringList, diagnostics);
|
|
778
|
+
validatePolicyLists(members.paths, at, "paths", {
|
|
779
|
+
all: "path lists",
|
|
780
|
+
one: "a list of paths, each a list of strings",
|
|
781
|
+
}, (paths) => Array.isArray(paths) && paths.every(isStringList), diagnostics);
|
|
782
|
+
validatePolicyLists(members.afterChecks, at, "afterChecks", { all: "action lists", one: "a list of actions" }, isStringList, diagnostics);
|
|
783
|
+
validateAfterCheckActions(members.afterChecks, at, diagnostics);
|
|
784
|
+
if (members.unheld !== undefined && !isStringList(members.unheld)) {
|
|
785
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.unheld`, `${at}.unheld must be a list of Resource names when provided`));
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
function validateAfterCheckActions(lists, at, diagnostics) {
|
|
789
|
+
if (!isPlainRecord(lists)) {
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
for (const [resource, actions] of Object.entries(lists)) {
|
|
793
|
+
if (!isStringList(actions)) {
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
for (const action of actions) {
|
|
797
|
+
if (action !== "update") {
|
|
798
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", `${at}.afterChecks.${resource}`, `${at}.afterChecks.${resource}: "${action}" is no action an after check runs on; only "update" is`));
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
function isStringList(value) {
|
|
804
|
+
return (Array.isArray(value) && value.every((name) => typeof name === "string"));
|
|
805
|
+
}
|
|
806
|
+
function validatePolicyLists(lists, at, list, entry, isEntry, diagnostics) {
|
|
807
|
+
if (lists === undefined) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
if (!isPlainRecord(lists)) {
|
|
811
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${list}`, `${at}.${list} must be an object of ${entry.all} when provided`));
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
for (const [key, value] of Object.entries(lists)) {
|
|
815
|
+
if (!isEntry(value)) {
|
|
816
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", `${at}.${list}.${key}`, `${at}.${list}.${key} must be ${entry.one}`));
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
642
820
|
function validateMcp(value, api, diagnostics) {
|
|
643
821
|
if (typeof value === "string") {
|
|
644
822
|
validateMcpPath(value, "mcp", api, diagnostics);
|
|
@@ -704,9 +882,10 @@ function validateMcpAuthorization(value, diagnostics) {
|
|
|
704
882
|
}
|
|
705
883
|
else {
|
|
706
884
|
value.servers.forEach((server, index) => {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
885
|
+
const serverPath = `${serversPath}[${index}]`;
|
|
886
|
+
const refusal = authorizationServerRefusal(server, serverPath);
|
|
887
|
+
if (refusal !== undefined) {
|
|
888
|
+
diagnostics.push(diagnostic("CONFIG_INVALID_VALUE", serverPath, refusal));
|
|
710
889
|
}
|
|
711
890
|
});
|
|
712
891
|
}
|
|
@@ -718,14 +897,49 @@ function validateMcpAuthorization(value, diagnostics) {
|
|
|
718
897
|
diagnostics.push(diagnostic("CONFIG_INVALID_TYPE", verifyPath, `${verifyPath} must be a function: token in, the caller or null out`));
|
|
719
898
|
}
|
|
720
899
|
}
|
|
721
|
-
|
|
900
|
+
const LOOPBACK_HOSTNAMES = new Set(["127.0.0.1", "[::1]"]);
|
|
901
|
+
const LOOPBACK_NAME = "localhost";
|
|
902
|
+
function authorizationServerRefusal(value, path) {
|
|
903
|
+
const notHttps = `${path} must be an absolute https URL`;
|
|
722
904
|
if (typeof value !== "string") {
|
|
723
|
-
return
|
|
905
|
+
return notHttps;
|
|
724
906
|
}
|
|
907
|
+
let url;
|
|
725
908
|
try {
|
|
726
|
-
|
|
909
|
+
url = new URL(value);
|
|
727
910
|
}
|
|
728
911
|
catch {
|
|
729
|
-
return
|
|
912
|
+
return notHttps;
|
|
913
|
+
}
|
|
914
|
+
const http = url.protocol === "http:";
|
|
915
|
+
if (!http && url.protocol !== "https:") {
|
|
916
|
+
return notHttps;
|
|
917
|
+
}
|
|
918
|
+
if (http &&
|
|
919
|
+
((!LOOPBACK_HOSTNAMES.has(url.hostname) &&
|
|
920
|
+
url.hostname !== LOOPBACK_NAME) ||
|
|
921
|
+
url.username !== "" ||
|
|
922
|
+
url.password !== "")) {
|
|
923
|
+
return notHttps;
|
|
924
|
+
}
|
|
925
|
+
if (url.pathname.includes("//")) {
|
|
926
|
+
return `${path} has an empty path segment ("//"); a client can read what follows it as another host`;
|
|
927
|
+
}
|
|
928
|
+
if (url.port === "0") {
|
|
929
|
+
return `${path} names port 0, which no server listens on`;
|
|
930
|
+
}
|
|
931
|
+
if (url.href.includes("?") || url.href.includes("#")) {
|
|
932
|
+
return `${path} has a query or fragment; an authorization server's URL (its issuer) takes neither`;
|
|
933
|
+
}
|
|
934
|
+
if (!http) {
|
|
935
|
+
return undefined;
|
|
936
|
+
}
|
|
937
|
+
if (url.hostname === LOOPBACK_NAME) {
|
|
938
|
+
url.hostname = "127.0.0.1";
|
|
730
939
|
}
|
|
940
|
+
const canonical = url.href;
|
|
941
|
+
const short = canonical === `${url.origin}/` ? url.origin : canonical;
|
|
942
|
+
return value === canonical || value === short
|
|
943
|
+
? undefined
|
|
944
|
+
: `${path} is an http loopback URL; write it as ${short}, the spelling every client reads as this machine`;
|
|
731
945
|
}
|
|
@@ -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 {};
|
|
@@ -103,9 +103,11 @@ type TokenOf<Member> = Member extends {
|
|
|
103
103
|
} ? {
|
|
104
104
|
[K in keyof Member]: K extends "scopes" ? never : Member[K] extends readonly (infer Token)[] ? Token : never;
|
|
105
105
|
}[keyof Member] : Member extends readonly (infer Token)[] ? Token : never;
|
|
106
|
+
/** The capability members an exemption never names. */
|
|
107
|
+
type AdapterStatedMember = "nestedWriteFilter" | "filterModes" | "pathFilterModes";
|
|
106
108
|
/** 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,
|
|
109
|
+
type CapabilityExemptionSchema<Caps> = ListOf<Exclude<keyof Caps, AdapterStatedMember>> & {
|
|
110
|
+
readonly [K in Exclude<keyof Caps, AdapterStatedMember>]-?: ListOf<TokenOf<NonNullable<Caps[K]>>>;
|
|
109
111
|
};
|
|
110
112
|
type FieldExemptionSchema<M extends AvAdapterModel, R extends AvConfigResourceKey<M>, F> = F extends AvAdapterFieldKey<M, R> ? M["resources"][R]["fields"][F] extends {
|
|
111
113
|
readonly kind: "relation";
|
|
@@ -131,33 +133,58 @@ type ExemptionsSchema<M extends AvAdapterModel, Cfg> = {
|
|
|
131
133
|
};
|
|
132
134
|
};
|
|
133
135
|
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
declare const refusal: unique symbol;
|
|
137
|
+
/** What a level refuses an unknown key for: `layer` cannot expose it, `parent` hid it, under `at`. */
|
|
138
|
+
type Refusal<Layer extends string, Parent extends string, At extends string> = {
|
|
139
|
+
readonly [refusal]: {
|
|
140
|
+
readonly layer: Layer;
|
|
141
|
+
readonly parent: Parent;
|
|
142
|
+
readonly at: At;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
/** The sentence a refused key `K` holding `Value` is typed as; `never` for an entry written `false`. */
|
|
146
|
+
type RefusalOf<Info, K, Value> = [Value] extends [false] ? never : Info extends {
|
|
147
|
+
readonly layer: infer Layer extends string;
|
|
148
|
+
readonly parent: infer Parent extends string;
|
|
149
|
+
readonly at: infer At extends string;
|
|
150
|
+
} ? Value extends readonly unknown[] ? {
|
|
151
|
+
readonly [S in `Error: ${Layer} cannot expose '${At}${K & string}': hidden by ${Parent}`]: true;
|
|
152
|
+
} : readonly [
|
|
153
|
+
`Error: ${Layer} cannot expose '${At}${K & string}': hidden by ${Parent}`
|
|
154
|
+
] : never;
|
|
155
|
+
/** A Pick layer's operations exemption, a family or variant its parent hid refused by name. */
|
|
156
|
+
type PickOperationsSchema<Ops, Layer extends string, Parent extends string, R extends string> = ListOf<keyof Ops> & {
|
|
157
|
+
readonly [F in keyof Ops]-?: ListOf<keyof NonNullable<Ops[F]>> & {
|
|
158
|
+
readonly [V in keyof NonNullable<Ops[F]>]: Leaf;
|
|
159
|
+
} & Refusal<Layer, Parent, `${R}.${F & string}.`>;
|
|
160
|
+
} & Refusal<Layer, Parent, `${R}.`>;
|
|
161
|
+
/** The fields of one Resource of a view. */
|
|
162
|
+
type ViewFields<Resource> = Resource extends {
|
|
163
|
+
readonly fields: infer Fields;
|
|
164
|
+
} ? Fields : never;
|
|
165
|
+
/** A Pick layer's exemptions, against its parent's view. */
|
|
166
|
+
type PickExemptionsSchema<Resources, Layer extends string, Parent extends string> = {
|
|
136
167
|
readonly resources: {
|
|
137
168
|
readonly [R in keyof Resources]: {
|
|
138
|
-
readonly operations:
|
|
169
|
+
readonly operations: PickOperationsSchema<Resources[R] extends {
|
|
139
170
|
readonly operations: infer Ops;
|
|
140
|
-
} ? Ops : never>;
|
|
171
|
+
} ? Ops : never, Layer, Parent, R & string>;
|
|
141
172
|
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 {
|
|
173
|
+
readonly [F in keyof ViewFields<Resources[R]>]: CapabilityExemptionSchema<ViewFields<Resources[R]>[F] extends {
|
|
147
174
|
readonly capabilities: infer Caps;
|
|
148
|
-
} ? Caps : never
|
|
149
|
-
}
|
|
175
|
+
} ? Caps : never> & Refusal<Layer, Parent, `${R & string}.${F & string}.`>;
|
|
176
|
+
} & Refusal<Layer, Parent, `${R & string}.`>;
|
|
150
177
|
};
|
|
151
|
-
}
|
|
178
|
+
} & Refusal<Layer, Parent, "">;
|
|
152
179
|
};
|
|
153
180
|
/** A layer's own configuration: `application`, `client` or `agent`. */
|
|
154
181
|
type OverlayOf<Cfg, Layer extends "application" | "client" | "agent"> = (Cfg & {
|
|
155
182
|
readonly [L in Layer]?: unknown;
|
|
156
183
|
})[Layer];
|
|
157
184
|
/** An overlay's exemptions schema, by the overlay's own `exposed`. */
|
|
158
|
-
type OverlayExemptionsSchema<M extends AvAdapterModel, Cfg, Overlay> = Overlay extends {
|
|
185
|
+
type OverlayExemptionsSchema<M extends AvAdapterModel, Cfg, Overlay, Layer extends "application" | "client"> = Overlay extends {
|
|
159
186
|
readonly exposed: false;
|
|
160
|
-
} ? PickExemptionsSchema<RootViewResources<M, Cfg
|
|
187
|
+
} ? PickExemptionsSchema<RootViewResources<M, Cfg>, Layer, "root"> : ExemptionsSchema<M, Cfg>;
|
|
161
188
|
type LayerKeysSchema = {
|
|
162
189
|
readonly exposed: Leaf;
|
|
163
190
|
readonly transactionsStyle: Leaf;
|
|
@@ -167,7 +194,9 @@ type LayerKeysSchema = {
|
|
|
167
194
|
type RootResourcesSchema<M extends AvAdapterModel> = {
|
|
168
195
|
readonly [R in AvConfigResourceKey<M>]: ResourceSchema<M, R, FieldsSchema<M, R, "root", AvAdapterFieldKey<M, R>> & {
|
|
169
196
|
readonly [otherKeys]: RootScalarFieldSchema;
|
|
170
|
-
}
|
|
197
|
+
}> & {
|
|
198
|
+
readonly managedElsewhere: Leaf;
|
|
199
|
+
};
|
|
171
200
|
};
|
|
172
201
|
/**
|
|
173
202
|
* One root `resources.<R>` block, checked key by key as
|
|
@@ -183,7 +212,7 @@ type OverlaySchema<M extends AvAdapterModel, Cfg, Layer extends "application" |
|
|
|
183
212
|
readonly resources: {
|
|
184
213
|
readonly [R in AvConfigResourceKey<M>]: ResourceSchema<M, R, FieldsSchema<M, R, "overlay", AvEffectiveFieldKey<M, Cfg, R>>>;
|
|
185
214
|
};
|
|
186
|
-
readonly exemptions: OverlayExemptionsSchema<M, Cfg, OverlayOf<Cfg, Layer
|
|
215
|
+
readonly exemptions: OverlayExemptionsSchema<M, Cfg, OverlayOf<Cfg, Layer>, Layer>;
|
|
187
216
|
};
|
|
188
217
|
type McpSchema = {
|
|
189
218
|
readonly path: Leaf;
|
|
@@ -197,7 +226,7 @@ type AgentParentOf<Cfg> = OverlayOf<Cfg, "agent"> extends {
|
|
|
197
226
|
readonly extends: infer Parent;
|
|
198
227
|
} ? Parent : "client";
|
|
199
228
|
/** 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
|
|
229
|
+
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
230
|
type AgentSchema<M extends AvAdapterModel, Cfg> = LayerKeysSchema & {
|
|
202
231
|
readonly extends: Leaf;
|
|
203
232
|
readonly resources: {
|
|
@@ -211,6 +240,12 @@ type RootSchema<M extends AvAdapterModel, Cfg> = LayerKeysSchema & {
|
|
|
211
240
|
readonly api: Leaf;
|
|
212
241
|
readonly mcp: McpSchema;
|
|
213
242
|
readonly adapter: Leaf;
|
|
243
|
+
readonly prebuilt: Leaf;
|
|
244
|
+
readonly policy: {
|
|
245
|
+
readonly engine: Leaf;
|
|
246
|
+
readonly principal: Leaf;
|
|
247
|
+
};
|
|
248
|
+
readonly access: Leaf;
|
|
214
249
|
readonly diagnostics: Leaf;
|
|
215
250
|
readonly misuse: Leaf;
|
|
216
251
|
readonly resources: RootResourcesSchema<M>;
|
|
@@ -219,9 +254,12 @@ type RootSchema<M extends AvAdapterModel, Cfg> = LayerKeysSchema & {
|
|
|
219
254
|
readonly client: OverlaySchema<M, Cfg, "client">;
|
|
220
255
|
readonly agent: AgentSchema<M, Cfg>;
|
|
221
256
|
};
|
|
222
|
-
/**
|
|
257
|
+
/**
|
|
258
|
+
* `V` with every key schema `S` lacks mapped to `never`, or to the sentence a
|
|
259
|
+
* refusing level states; every leaf `unknown`.
|
|
260
|
+
*/
|
|
223
261
|
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;
|
|
262
|
+
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
263
|
} : unknown;
|
|
226
264
|
/**
|
|
227
265
|
* The authored configuration `Cfg`, checked key by key: a key no level of the
|
|
@@ -229,7 +267,14 @@ type Exact<S, V> = [S] extends [Leaf] ? unknown : V extends readonly unknown[] ?
|
|
|
229
267
|
* rc.0 key, a `definition` in an overlay, a stage a relation field does not take,
|
|
230
268
|
* or a name the model and the root do not have.
|
|
231
269
|
*/
|
|
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
|
|
270
|
+
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 {
|
|
271
|
+
readonly access: object;
|
|
272
|
+
readonly policy: object;
|
|
273
|
+
} ? {
|
|
274
|
+
readonly policy: readonly [
|
|
275
|
+
"Error: `access` brings the policy engine; remove `policy`"
|
|
276
|
+
];
|
|
277
|
+
} : unknown);
|
|
233
278
|
/** A layer's own literal `transactionsStyle`, `undefined` when it states none. */
|
|
234
279
|
type StyleOf<Layer> = Layer extends {
|
|
235
280
|
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>;
|
|
@@ -113,3 +113,11 @@ export function chainCompute(root, overlay) {
|
|
|
113
113
|
}
|
|
114
114
|
return result;
|
|
115
115
|
}
|
|
116
|
+
export function createComputedFields(compute, resource) {
|
|
117
|
+
const fields = Object.hasOwn(compute, resource)
|
|
118
|
+
? compute[resource]
|
|
119
|
+
: undefined;
|
|
120
|
+
return new Set(Object.entries(fields ?? {})
|
|
121
|
+
.filter(([, phases]) => phases.create !== undefined)
|
|
122
|
+
.map(([field]) => field));
|
|
123
|
+
}
|
|
@@ -2,19 +2,28 @@ import type { AvAdapter } from "../adapters/adapter.interface.js";
|
|
|
2
2
|
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
3
3
|
import type { AvContractLimits } from "../contracts/contract-limits.js";
|
|
4
4
|
import type { AvTransactionCapability } from "../contracts/transaction-capability.js";
|
|
5
|
+
import type { AvAccessProvider } from "../policy/access-provider.interface.js";
|
|
6
|
+
import type { AvPolicyEngine } from "../policy/policy-engine.js";
|
|
7
|
+
import type { AvPrebuiltContracts } from "../prebuilt/prebuilt-contracts.js";
|
|
5
8
|
import type { AvDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
|
|
6
9
|
import type { AvMisuseSink } from "../runtime/misuse-reporter.js";
|
|
10
|
+
import type { AvState } from "../runtime/request-state.js";
|
|
7
11
|
import type { AvConfigAny } from "./any-framework-config.js";
|
|
12
|
+
import type { AvConfigLayerName, AvRequestOrigin } from "./config-layer.js";
|
|
8
13
|
import type { AvConfigExemptions } from "./framework-exemptions-config.js";
|
|
9
|
-
import type { AvConfigLayerKind, AvConfigResources } from "./framework-resources-config.js";
|
|
14
|
+
import type { AvConfigLayerKind, AvConfigResources, LayerOfKind } from "./framework-resources-config.js";
|
|
10
15
|
import type { AvPipeline } from "./pipeline-config.js";
|
|
11
16
|
/**
|
|
12
17
|
* Request limits to override; each one left out takes its default from
|
|
13
18
|
* {@link DEFAULT_CONTRACT_LIMITS}.
|
|
14
19
|
*/
|
|
15
20
|
export type AvConfigLimits = Partial<AvContractLimits>;
|
|
16
|
-
/**
|
|
17
|
-
|
|
21
|
+
/**
|
|
22
|
+
* The six keys every layer holds: the root, `application`, `client` and
|
|
23
|
+
* `agent`. Stages are added to the root's; `transactionsStyle` and `limits`
|
|
24
|
+
* replace it where an overlay states them; exposure only narrows.
|
|
25
|
+
*/
|
|
26
|
+
export type AvConfigLayer<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny, Kind extends AvConfigLayerKind = "root", Layer extends AvConfigLayerName = LayerOfKind<Kind>> = {
|
|
18
27
|
/** Moved: `exposed` + `exemptions`. */
|
|
19
28
|
readonly restrictions?: never;
|
|
20
29
|
/** Moved: `resources.<R>.fields.<f>.pipelines.compute`. */
|
|
@@ -23,13 +32,6 @@ type MovedLayerKeys = {
|
|
|
23
32
|
readonly fields?: never;
|
|
24
33
|
/** Moved: `transactionsStyle`. */
|
|
25
34
|
readonly transactions?: never;
|
|
26
|
-
};
|
|
27
|
-
/**
|
|
28
|
-
* The six keys every layer holds: the root, `application`, `client` and
|
|
29
|
-
* `agent`. Stages are added to the root's; `transactionsStyle` and `limits`
|
|
30
|
-
* replace it where an overlay states them; exposure only narrows.
|
|
31
|
-
*/
|
|
32
|
-
export type AvConfigLayer<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny, Kind extends AvConfigLayerKind = "root"> = MovedLayerKeys & {
|
|
33
35
|
/**
|
|
34
36
|
* Whether the layer's `exemptions` hide (`true`, the root's default) or are
|
|
35
37
|
* the only entries exposed (`false`). Each layer narrows its parent: the root
|
|
@@ -43,7 +45,7 @@ export type AvConfigLayer<M extends AvAdapterModel = AvAdapterModel, Cfg = AvCon
|
|
|
43
45
|
/** Guards, pipes, hooks, interceptors and filters run around every operation of the layer. */
|
|
44
46
|
readonly pipelines?: AvPipeline<NoInfer<M>>;
|
|
45
47
|
/** The per-Resource tree: stages, operations, transactions and fields. */
|
|
46
|
-
readonly resources?: AvConfigResources<M, Cfg, Kind>;
|
|
48
|
+
readonly resources?: AvConfigResources<M, Cfg, Kind, Layer>;
|
|
47
49
|
/**
|
|
48
50
|
* The entries that are the opposite of `exposed`. An overlay that sets them
|
|
49
51
|
* states its own `exposed`.
|
|
@@ -70,11 +72,45 @@ export type AvConfig<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAn
|
|
|
70
72
|
*/
|
|
71
73
|
readonly mcp?: AvConfigMcp;
|
|
72
74
|
readonly adapter: AvAdapter<M>;
|
|
75
|
+
/**
|
|
76
|
+
* Contracts compiled ahead of time (the generated `aventaraContracts`), for a
|
|
77
|
+
* fast cold start on serverless and edge platforms. Used only when they were
|
|
78
|
+
* compiled from this configuration and the adapter's model by this core;
|
|
79
|
+
* otherwise the Contracts are compiled at startup, as without it, and a
|
|
80
|
+
* `AVENTARA_PREBUILT_STALE` warning says why.
|
|
81
|
+
*/
|
|
82
|
+
readonly prebuilt?: AvPrebuiltContracts;
|
|
83
|
+
/**
|
|
84
|
+
* The policy engine every client and agent request is checked against, and
|
|
85
|
+
* how a request's principal is derived from its `ctx.$state`. Application
|
|
86
|
+
* calls bypass it unless they name a principal (`{ as }`); calls a stage
|
|
87
|
+
* makes through `ctx` always do.
|
|
88
|
+
*/
|
|
89
|
+
readonly policy?: {
|
|
90
|
+
readonly engine: AvPolicyEngine;
|
|
91
|
+
/**
|
|
92
|
+
* The request's principal, from its `ctx.$state` and its layer; `null` for
|
|
93
|
+
* an anonymous caller. It may answer with a promise (rc.5), which is
|
|
94
|
+
* awaited; a throw or a rejection answers `A3000`.
|
|
95
|
+
*/
|
|
96
|
+
readonly principal: (facts: {
|
|
97
|
+
readonly $state: AvState;
|
|
98
|
+
readonly $origin: AvRequestOrigin;
|
|
99
|
+
}) => unknown;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* The access provider (Aventara Access, or one written by hand): its
|
|
103
|
+
* `policy` engine checks every client and agent request, with
|
|
104
|
+
* `ctx.$state.me` as the principal, and the host seeds each request's
|
|
105
|
+
* `ctx.$state` with its `state`. Not together with `policy`, nor with a
|
|
106
|
+
* host's own `state` option.
|
|
107
|
+
*/
|
|
108
|
+
readonly access?: AvAccessProvider;
|
|
73
109
|
readonly diagnostics?: AvDiagnosticsSink;
|
|
74
110
|
/** Told about every caller value refused as unreadable or not plain data. */
|
|
75
111
|
readonly misuse?: AvMisuseSink;
|
|
76
|
-
readonly application?: AvConfigLayer<M, Cfg, "overlay">;
|
|
77
|
-
readonly client?: AvConfigLayer<M, Cfg, "overlay">;
|
|
112
|
+
readonly application?: AvConfigLayer<M, Cfg, "overlay", "application">;
|
|
113
|
+
readonly client?: AvConfigLayer<M, Cfg, "overlay", "client">;
|
|
78
114
|
/**
|
|
79
115
|
* The layer an AI agent's calls run under. It narrows the view of the layer it
|
|
80
116
|
* `extends` (the client's when left out), and its stages run after that
|
|
@@ -95,7 +131,9 @@ export type AvConfigMcp = string | {
|
|
|
95
131
|
readonly authorization?: {
|
|
96
132
|
/**
|
|
97
133
|
* The authorization servers (https URLs) a caller obtains its token
|
|
98
|
-
* from, advertised in the endpoint's protected-resource metadata.
|
|
134
|
+
* from, advertised in the endpoint's protected-resource metadata. A
|
|
135
|
+
* server on this machine may be http: `http://127.0.0.1` or
|
|
136
|
+
* `http://[::1]`, with any port and path (not `localhost`).
|
|
99
137
|
*/
|
|
100
138
|
readonly servers: readonly string[];
|
|
101
139
|
/**
|
|
@@ -109,7 +147,7 @@ export type AvConfigMcp = string | {
|
|
|
109
147
|
* The `agent` layer: the six layer keys, and `extends`, the layer whose final
|
|
110
148
|
* view it narrows and whose stages run before its own.
|
|
111
149
|
*/
|
|
112
|
-
export type AvConfigAgentLayer<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny> = AvConfigLayer<M, Cfg, "overlay"> & {
|
|
150
|
+
export type AvConfigAgentLayer<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny> = AvConfigLayer<M, Cfg, "overlay", "agent"> & {
|
|
113
151
|
/**
|
|
114
152
|
* The layer the agent starts from: `"client"` (the default), `"application"`
|
|
115
153
|
* or `"root"`. The agent never widens it.
|