@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
|
@@ -2,9 +2,24 @@ import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
|
2
2
|
import type { SemanticOperationArguments } from "../operations/operation-validator.js";
|
|
3
3
|
import type { AvAdapterModel } from "./adapter-model.js";
|
|
4
4
|
/**
|
|
5
|
-
* Provider execution request after framework semantic validation.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Provider execution request after framework semantic validation. Operation
|
|
6
|
+
* identity and arguments remain provider-neutral; adapters receive only validated
|
|
7
|
+
* semantic argument objects, never raw transport input.
|
|
8
|
+
*
|
|
9
|
+
* Three shapes exist here only, each an `AND`: a list of conditions in the general
|
|
10
|
+
* `where` grammar the addressed row must also meet.
|
|
11
|
+
*
|
|
12
|
+
* - The flat unique selector of an `update.unique` or a `delete.unique` may carry
|
|
13
|
+
* it. A row the selector names that misses them is a miss (the same `null` as a
|
|
14
|
+
* row that is not there).
|
|
15
|
+
* - A `cursor` may carry it, at the root of a `find.many` and in a to-many
|
|
16
|
+
* relation's arguments. A row the cursor names that misses them is a cursor that
|
|
17
|
+
* names no row: the same answer as a cursor on a row that is not there.
|
|
18
|
+
* - A row the selector names that misses them, or no row, is refused: the adapter
|
|
19
|
+
* fails the operation with `A4002`.
|
|
20
|
+
*
|
|
21
|
+
* An adapter must honour it or refuse the operation, never drop it: dropping it
|
|
22
|
+
* would write a row the conditions exclude, or position a page at one.
|
|
8
23
|
*/
|
|
9
24
|
export type AvAdapterOperation<M extends AvAdapterModel = AvAdapterModel> = AvOperationIdentity & {
|
|
10
25
|
readonly resource: Extract<keyof M["resources"], string>;
|
|
@@ -26,4 +26,9 @@ export type AvAdapterResource<M extends AvAdapterModel, TFields extends AvAdapte
|
|
|
26
26
|
* cannot say; nothing is then checked or typed before the store.
|
|
27
27
|
*/
|
|
28
28
|
readonly createRequirements?: AvCreateRequirements;
|
|
29
|
+
/**
|
|
30
|
+
* The database schema the store keeps this Resource in (a PostgreSQL schema,
|
|
31
|
+
* say), when the store has schemas and the model names one. Absent otherwise.
|
|
32
|
+
*/
|
|
33
|
+
readonly schema?: string;
|
|
29
34
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AvConfigComputedFields } from "../config/computed-fields.js";
|
|
1
2
|
import type { ReferentialActionTable } from "../runtime/referential-action.js";
|
|
2
3
|
import type { AvAdapterModel } from "./adapter-model.js";
|
|
3
4
|
import type { AvAdapterOperationExecutor } from "./adapter-operation-executor.interface.js";
|
|
@@ -30,6 +31,15 @@ export interface AvAdapter<M extends AvAdapterModel = AvAdapterModel> extends Av
|
|
|
30
31
|
* or `$set` runs the target's `update` guards.
|
|
31
32
|
*/
|
|
32
33
|
readonly referentialActions?: ReferentialActionTable;
|
|
34
|
+
/**
|
|
35
|
+
* Optional: which fields the configuration's write compute fills, as the
|
|
36
|
+
* Adapter's generate step read them when it wrote the model's type (the same
|
|
37
|
+
* statement as the type's `"~computedFields"`). When the Framework is
|
|
38
|
+
* constructed it is compared with the configuration, and a difference is a
|
|
39
|
+
* warning that the generated types are stale (`aventara:prepare` regenerates
|
|
40
|
+
* them); it changes no behaviour. Never part of a Contract or its hash.
|
|
41
|
+
*/
|
|
42
|
+
readonly computedFields?: AvConfigComputedFields;
|
|
33
43
|
/**
|
|
34
44
|
* Optional: `true` when the Adapter runs developer SQL statements: standalone
|
|
35
45
|
* through its own {@link executeSql}, and, when it has `transaction`, inside a
|
package/dist/avz/avz.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ export interface AvZOptional<Inner extends AvZShape = AvZShape> extends AvZShape
|
|
|
49
49
|
/** A shape that also admits `null`. */
|
|
50
50
|
export type AvZNullable<Inner extends AvZShape = AvZShape> = AvZShape<JsonShapeValue<Inner> | null, "nullable"> & (Inner extends AvZOptionalKey ? AvZOptionalKey : unknown);
|
|
51
51
|
/** A value a literal shape may hold. */
|
|
52
|
-
|
|
52
|
+
type AvZLiteralValue = JsonSchemaPrimitive;
|
|
53
53
|
/** What keys a record shape: any string, an enum's values or one literal. */
|
|
54
54
|
type AvZRecordKey = AvZShape<string, "string"> | AvZShape<string, "enum"> | AvZShape<string, "literal">;
|
|
55
55
|
/** An option of a discriminated union: an object whose discriminator is a literal or an enum. */
|
|
@@ -3,7 +3,7 @@ import type { AvScalarField } from "../contracts/field.js";
|
|
|
3
3
|
import type { JsonSchema } from "../contracts/json-shape.js";
|
|
4
4
|
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
5
5
|
/** What core may do with a Json Shape: read its Contract form, check a value. */
|
|
6
|
-
|
|
6
|
+
type JsonShapeRuntime = {
|
|
7
7
|
/** The shape's Contract form. */
|
|
8
8
|
readonly schema: JsonSchema;
|
|
9
9
|
/**
|
|
@@ -20,3 +20,4 @@ export declare function jsonShapeOf(value: unknown): JsonShapeRuntime | undefine
|
|
|
20
20
|
export declare function bindShapedField(field: AvScalarField<AvContract>, shape: JsonShapeRuntime): void;
|
|
21
21
|
/** The shape a compiled Contract field enforces, or `undefined`. */
|
|
22
22
|
export declare function shapeOfField(field: AvScalarField<AvContract>): JsonShapeRuntime | undefined;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ErrorCodeDescription } from "../runtime/error-guidance.js";
|
|
2
|
+
import type { AvContractCompilerDiagnosticCode } from "./contract-compiler-diagnostic.js";
|
|
3
|
+
/** Meaning, cause and fix of every contract-compilation diagnostic code. */
|
|
4
|
+
export declare const CONTRACT_COMPILER_DIAGNOSTIC_GUIDANCE: {
|
|
5
|
+
readonly [C in AvContractCompilerDiagnosticCode]: ErrorCodeDescription;
|
|
6
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export const CONTRACT_COMPILER_DIAGNOSTIC_GUIDANCE = {
|
|
2
|
+
COMPILER_UNKNOWN_RESOURCE: {
|
|
3
|
+
message: "Unknown Resource.",
|
|
4
|
+
cause: "A Resource name the adapter's model does not have, in resources or in exemptions; or a client or agent entry for a Resource managed elsewhere, which those layers never have.",
|
|
5
|
+
fix: "Use the model's exact name. After a schema change run `npm run aventara:prepare`. Configure a Resource managed elsewhere at the root or in application only.",
|
|
6
|
+
},
|
|
7
|
+
COMPILER_UNKNOWN_FIELD: {
|
|
8
|
+
message: "Unknown field.",
|
|
9
|
+
cause: "A field that is neither in the schema nor defined at the root.",
|
|
10
|
+
fix: "Fix the name, run aventara:prepare after a schema change, or add the field with a root definition.",
|
|
11
|
+
},
|
|
12
|
+
COMPILER_RELATION_FIELD_CONFIG_UNSUPPORTED: {
|
|
13
|
+
message: "A relation field takes write guards only.",
|
|
14
|
+
cause: "Field pipes or compute on a relation field.",
|
|
15
|
+
fix: "Put the stage on the relation's reference field, or use an operation pipe.",
|
|
16
|
+
},
|
|
17
|
+
COMPILER_INCOMPLETE_FIELD: {
|
|
18
|
+
message: "An added field is incomplete.",
|
|
19
|
+
cause: "A definition that adds a field leaves out type, nullable or list.",
|
|
20
|
+
fix: 'Spell out type, nullable and list, with lifecycle: ["VIRTUAL"] for a field that has no column.',
|
|
21
|
+
},
|
|
22
|
+
COMPILER_STRUCTURAL_FIELD_OVERRIDE: {
|
|
23
|
+
message: "A discovered field's structure was redefined.",
|
|
24
|
+
cause: "A definition on a field the adapter discovered changes its type, format or capabilities.",
|
|
25
|
+
fix: "Restate only its type, nullable and list. Change capabilities through exemptions and the column through the schema.",
|
|
26
|
+
},
|
|
27
|
+
COMPILER_MISSING_SCALAR: {
|
|
28
|
+
message: "Unknown scalar type.",
|
|
29
|
+
cause: "A definition names a scalar type that does not exist.",
|
|
30
|
+
fix: "Use a built-in scalar: string, boolean, int, float, bigint, decimal, datetime, bytes or json.",
|
|
31
|
+
},
|
|
32
|
+
COMPILER_MISSING_ENUM: {
|
|
33
|
+
message: "Unknown enum.",
|
|
34
|
+
cause: "A definition names an enum the model does not have.",
|
|
35
|
+
fix: "Use an enum of the schema, and run aventara:prepare after adding one.",
|
|
36
|
+
},
|
|
37
|
+
COMPILER_DANGLING_RELATION: {
|
|
38
|
+
message: "A visible relation points at a hidden Resource.",
|
|
39
|
+
cause: "A layer hides a Resource but still exposes a relation field that targets it.",
|
|
40
|
+
fix: "Hide the relation field too (`exemptions.resources.<R>.fields.<relation>: true`), or expose the target.",
|
|
41
|
+
},
|
|
42
|
+
COMPILER_UNAVAILABLE_OPERATION: {
|
|
43
|
+
message: "Operation not available.",
|
|
44
|
+
cause: "An operation the adapter does not offer (such as delete.many), or an overlay granting one that its parent hid.",
|
|
45
|
+
fix: "Remove it. To reach an operation from one overlay only, expose it at the root and hide it in the other overlay.",
|
|
46
|
+
},
|
|
47
|
+
COMPILER_UNAVAILABLE_CAPABILITY: {
|
|
48
|
+
message: "Capability not available.",
|
|
49
|
+
cause: "A capability or token the field does not offer, or an overlay (or the agent layer) granting one its parent hid. Overlays only narrow.",
|
|
50
|
+
fix: "Remove it, or expose it in the parent layer and hide it in the layer it must not reach.",
|
|
51
|
+
},
|
|
52
|
+
COMPILER_INVALID_LIFECYCLE: {
|
|
53
|
+
message: "Invalid field lifecycle.",
|
|
54
|
+
cause: "An added field declares a lifecycle other than VIRTUAL, a VIRTUAL field claims a database-generated lifecycle or a provider-side capability, or a definition redefines a discovered field's lifecycle.",
|
|
55
|
+
fix: 'Give an added field lifecycle: ["VIRTUAL"] and only the capabilities it can serve; computed lifecycles come from compute stages.',
|
|
56
|
+
},
|
|
57
|
+
COMPILER_MISSING_READ_COMPUTE: {
|
|
58
|
+
message: "A selectable virtual field has no compute.read.",
|
|
59
|
+
cause: "A VIRTUAL field that can be selected has no pipelines.compute.read stage.",
|
|
60
|
+
fix: "Add a compute.read stage, or make the field write-only with capabilities.select: false.",
|
|
61
|
+
},
|
|
62
|
+
COMPILER_INVALID_COMPUTE_DEPENDENCY: {
|
|
63
|
+
message: "Invalid compute.read dependency.",
|
|
64
|
+
cause: "A dependsOn entry that is not a stored scalar field of the same Resource.",
|
|
65
|
+
fix: "List only stored scalar fields of the Resource in dependsOn.",
|
|
66
|
+
},
|
|
67
|
+
COMPILER_RESERVED_RESOURCE_NAME: {
|
|
68
|
+
message: "Reserved Resource name.",
|
|
69
|
+
cause: "A model name starts with $, which is reserved for the framework's own names (ctx.$sql, $ref), or, on a host that adds members beside the Resources, is one of those members' names (on Next.js: tx and transaction on avClient, appTx and transaction on avApp).",
|
|
70
|
+
fix: "Rename the model; the table it maps to can keep its name. A host member's name is also left free when the layer it belongs to hides the Resource.",
|
|
71
|
+
},
|
|
72
|
+
COMPILER_MISSING_IDENTIFIER: {
|
|
73
|
+
message: "A unique operation has no identifier.",
|
|
74
|
+
cause: "A layer exposes a unique variant (find.unique, update.unique, delete.unique, upsert.unique) and no complete identifier of the Resource: a Pick that did not pick one, or an Omit that hid every one.",
|
|
75
|
+
fix: "Expose an identifier field (id, or every field of one unique), or exempt the unique variants.",
|
|
76
|
+
},
|
|
77
|
+
COMPILER_HIDDEN_REQUIRED_FIELD: {
|
|
78
|
+
message: "A layer that creates a Resource hides a required field.",
|
|
79
|
+
cause: "A layer still creates the Resource (a create or upsert variant, or a nested create) while a required field, or a required relation's reference field, is hidden or has its create capability exempted, and no compute.create fills it.",
|
|
80
|
+
fix: "Expose the field, give it a compute.create stage, or exempt the layer's create operations.",
|
|
81
|
+
},
|
|
82
|
+
COMPILER_INVALID_VALIDATOR: {
|
|
83
|
+
message: "A field validator cannot apply.",
|
|
84
|
+
cause: "A validator that is not built with AvZ, does not fit the field's type (AvZ.maxLength on an int, AvZ.maxItems on a field that is not a list), or sits on a relation or Json field.",
|
|
85
|
+
fix: "Use an AvZ check that fits the field's type; a Json field's checks go in its json shape.",
|
|
86
|
+
},
|
|
87
|
+
COMPILER_INVALID_JSON_SHAPE: {
|
|
88
|
+
message: "A Json shape cannot apply.",
|
|
89
|
+
cause: "A json shape on a field that is not a discovered Json field, a shape not built with AvZ, or one that admits null or absence at its top level.",
|
|
90
|
+
fix: "Put the shape on a Json field, build it with AvZ, and keep its top level non-null (the column's nullability decides null).",
|
|
91
|
+
},
|
|
92
|
+
COMPILER_INVALID_CLIENT_CONTRACT: {
|
|
93
|
+
message: "The compiled client contract is invalid.",
|
|
94
|
+
cause: "The finished client contract failed its own structural check: a framework defect.",
|
|
95
|
+
fix: "Report it with the diagnostic's path and message.",
|
|
96
|
+
},
|
|
97
|
+
};
|
|
@@ -30,3 +30,9 @@ export type ContractCompilationResult = {
|
|
|
30
30
|
* Agent Contract from the view of the layer it extends.
|
|
31
31
|
*/
|
|
32
32
|
export declare function compileContracts<M extends AvAdapterModel>(model: M, config: ResolvedFrameworkConfig<M>): Promise<ContractCompilationResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Binds Contracts loaded from a prebuilt file to the runtime pieces
|
|
35
|
+
* {@link compileContracts} binds to the ones it compiles, from the live
|
|
36
|
+
* `config` and `model` they were compiled from.
|
|
37
|
+
*/
|
|
38
|
+
export declare function bindPrebuiltContracts<M extends AvAdapterModel>(model: M, config: ResolvedFrameworkConfig<M>, contracts: AvContracts): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { bindShapedField, jsonShapeOf } from "../avz/json-shape.registry.js";
|
|
2
|
-
import { PROJECTION_SCOPES, WRITE_SCOPES } from "../contracts/capability.js";
|
|
2
|
+
import { FILTER_MODES, PROJECTION_SCOPES, WRITE_SCOPES, } from "../contracts/capability.js";
|
|
3
3
|
import { validateClientContractStructure } from "../contracts/client-contract-structure.validator.js";
|
|
4
4
|
import { canonicalizeContract, canonicalizeContractMembers, canonicalizeJson, joinCanonicalContractMembers, recordCanonicalContractText, } from "../contracts/contract-canonicalizer.js";
|
|
5
5
|
import { hashCanonicalContractText, } from "../contracts/contract-hash.js";
|
|
@@ -9,6 +9,7 @@ import { advertisedDirectives, advertisedReducers, holdsInAnyScope, } from "../c
|
|
|
9
9
|
import { isOperationVariantAvailable, } from "../contracts/resource-operations.js";
|
|
10
10
|
import { checkCreateRequirements, checkHiddenRequirements, projectCreateRequirements, } from "./create-requirements.projector.js";
|
|
11
11
|
import { applyValidators, bindFieldValidators, checkLayerValidators, compileValidatorTable, } from "./field-validator.compiler.js";
|
|
12
|
+
import { explainManagedRefusals, hideManagedElsewhere, managedElsewhereOf, managedWriteReason, markCoreResources, pruneManagedEnums, withholdManagedWrites, } from "./managed-elsewhere.projector.js";
|
|
12
13
|
const UNIQUE_VARIANTS = [
|
|
13
14
|
["find", "unique"],
|
|
14
15
|
["update", "unique"],
|
|
@@ -41,6 +42,12 @@ function normalizeAdapterScalarCapabilities(capabilities) {
|
|
|
41
42
|
...(capabilities.filter !== undefined
|
|
42
43
|
? { filter: [...capabilities.filter] }
|
|
43
44
|
: {}),
|
|
45
|
+
...(capabilities.filterModes !== undefined
|
|
46
|
+
? { filterModes: [...capabilities.filterModes] }
|
|
47
|
+
: {}),
|
|
48
|
+
...(capabilities.pathFilterModes !== undefined
|
|
49
|
+
? { pathFilterModes: [...capabilities.pathFilterModes] }
|
|
50
|
+
: {}),
|
|
44
51
|
...(capabilities.order !== undefined ? { order: capabilities.order } : {}),
|
|
45
52
|
...(capabilities.orderNulls !== undefined
|
|
46
53
|
? { orderNulls: capabilities.orderNulls }
|
|
@@ -71,8 +78,65 @@ function cloneAdapterField(field) {
|
|
|
71
78
|
cardinality: field.cardinality,
|
|
72
79
|
nullable: field.nullable,
|
|
73
80
|
capabilities: cloneValue(field.capabilities),
|
|
81
|
+
...(typeof field.inverse === "string" ? { inverse: field.inverse } : {}),
|
|
82
|
+
...(Array.isArray(field.referenceFields) && field.referenceFields.length > 0
|
|
83
|
+
? { referenceFields: [...field.referenceFields] }
|
|
84
|
+
: {}),
|
|
85
|
+
...(Array.isArray(field.referenceFields) &&
|
|
86
|
+
Array.isArray(field.references) &&
|
|
87
|
+
field.references.length > 0 &&
|
|
88
|
+
field.references.length === field.referenceFields.length
|
|
89
|
+
? { references: [...field.references] }
|
|
90
|
+
: {}),
|
|
74
91
|
};
|
|
75
92
|
}
|
|
93
|
+
function pruneHiddenPairings(projection, references) {
|
|
94
|
+
const resources = projection.resources;
|
|
95
|
+
for (const [name, resource] of Object.entries(resources)) {
|
|
96
|
+
for (const field of Object.values(resource.fields)) {
|
|
97
|
+
if (field.kind !== "relation") {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (Array.isArray(field.references) &&
|
|
101
|
+
(references === "none" ||
|
|
102
|
+
!wholePairing(resource.fields, Object.hasOwn(resources, String(field.target))
|
|
103
|
+
? resources[String(field.target)]?.fields
|
|
104
|
+
: undefined, field.referenceFields, field.references))) {
|
|
105
|
+
delete field.references;
|
|
106
|
+
}
|
|
107
|
+
if (Array.isArray(field.referenceFields)) {
|
|
108
|
+
const shown = field.referenceFields.filter((reference) => typeof reference === "string" &&
|
|
109
|
+
Object.hasOwn(resource.fields, reference) &&
|
|
110
|
+
resource.fields[reference]?.kind === "scalar");
|
|
111
|
+
if (shown.length > 0) {
|
|
112
|
+
field.referenceFields = shown;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
delete field.referenceFields;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (typeof field.inverse !== "string") {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const other = Object.hasOwn(resources, String(field.target))
|
|
122
|
+
? resources[String(field.target)]?.fields[field.inverse]
|
|
123
|
+
: undefined;
|
|
124
|
+
if (other?.kind !== "relation" || other.target !== name) {
|
|
125
|
+
delete field.inverse;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function wholePairing(fields, targetFields, referenceFields, references) {
|
|
131
|
+
const shownIn = (within, name) => typeof name === "string" &&
|
|
132
|
+
within !== undefined &&
|
|
133
|
+
Object.hasOwn(within, name) &&
|
|
134
|
+
within[name]?.kind === "scalar";
|
|
135
|
+
return (Array.isArray(referenceFields) &&
|
|
136
|
+
referenceFields.length === references.length &&
|
|
137
|
+
referenceFields.every((name) => shownIn(fields, name)) &&
|
|
138
|
+
references.every((name) => shownIn(targetFields, name)));
|
|
139
|
+
}
|
|
76
140
|
function cloneOperations(operations) {
|
|
77
141
|
return cloneValue(operations);
|
|
78
142
|
}
|
|
@@ -86,8 +150,40 @@ function cloneAdapterResource(resource) {
|
|
|
86
150
|
operations: cloneOperations(resource.operations),
|
|
87
151
|
};
|
|
88
152
|
}
|
|
153
|
+
function canonicalModes(modes) {
|
|
154
|
+
const stated = Array.isArray(modes) ? modes : [];
|
|
155
|
+
const known = FILTER_MODES.filter((mode) => mode === "default" || stated.includes(mode));
|
|
156
|
+
const unknown = stated.filter((mode) => !FILTER_MODES.includes(mode));
|
|
157
|
+
return [...known, ...unknown];
|
|
158
|
+
}
|
|
159
|
+
function qualifyFilterModes(projection) {
|
|
160
|
+
for (const resource of Object.values(projection.resources)) {
|
|
161
|
+
for (const field of Object.values(resource.fields)) {
|
|
162
|
+
if (field.kind !== "scalar") {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const capabilities = field.capabilities;
|
|
166
|
+
const filter = Array.isArray(capabilities.filter)
|
|
167
|
+
? capabilities.filter
|
|
168
|
+
: [];
|
|
169
|
+
if (!filter.includes("mode")) {
|
|
170
|
+
delete capabilities.filterModes;
|
|
171
|
+
delete capabilities.pathFilterModes;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const stated = capabilities.filterModes;
|
|
175
|
+
capabilities.filterModes = canonicalModes(stated);
|
|
176
|
+
if (filter.includes("path")) {
|
|
177
|
+
capabilities.pathFilterModes = canonicalModes(capabilities.pathFilterModes ?? stated);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
delete capabilities.pathFilterModes;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
89
185
|
function createBaseline(model) {
|
|
90
|
-
|
|
186
|
+
const baseline = {
|
|
91
187
|
scalars: Object.fromEntries(Object.entries(model.scalars).map(([key, value]) => [
|
|
92
188
|
key,
|
|
93
189
|
cloneValue(value),
|
|
@@ -106,6 +202,8 @@ function createBaseline(model) {
|
|
|
106
202
|
? {}
|
|
107
203
|
: { referenceWrites: model.referenceWrites }),
|
|
108
204
|
};
|
|
205
|
+
qualifyFilterModes(baseline);
|
|
206
|
+
return baseline;
|
|
109
207
|
}
|
|
110
208
|
function definitionPath(resource, field) {
|
|
111
209
|
return `root.resources.${resource}.fields.${field}.definition`;
|
|
@@ -285,7 +383,7 @@ function checkFieldCompute(model, resourceName, fieldName, field, compute, path,
|
|
|
285
383
|
}
|
|
286
384
|
}
|
|
287
385
|
}
|
|
288
|
-
function checkResourceTree(model, baseline, scope, tree, definitions, diagnostics) {
|
|
386
|
+
function checkResourceTree(model, baseline, scope, tree, definitions, managed, diagnostics) {
|
|
289
387
|
if (!isRecord(tree)) {
|
|
290
388
|
return;
|
|
291
389
|
}
|
|
@@ -296,12 +394,22 @@ function checkResourceTree(model, baseline, scope, tree, definitions, diagnostic
|
|
|
296
394
|
diagnostics.push(diagnostic("COMPILER_UNKNOWN_RESOURCE", resourcePath, `resource "${resourceName}" is not present in the canonical adapter model`));
|
|
297
395
|
continue;
|
|
298
396
|
}
|
|
397
|
+
if ((scope === "client" || scope === "agent") &&
|
|
398
|
+
managed.has(resourceName)) {
|
|
399
|
+
diagnostics.push(diagnostic("COMPILER_UNKNOWN_RESOURCE", resourcePath, `resource "${resourceName}" is managed elsewhere (resources.${resourceName}.managedElsewhere), so the ${scope} layer never has it: nothing configured for it here runs`));
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
299
402
|
if (!isRecord(entry)) {
|
|
300
403
|
continue;
|
|
301
404
|
}
|
|
302
405
|
if (isRecord(entry.operations)) {
|
|
303
406
|
for (const [family, level] of Object.entries(entry.operations)) {
|
|
304
407
|
const familyPath = `${resourcePath}.operations.${family}`;
|
|
408
|
+
const managedReason = managedWriteReason(managed, resourceName, family);
|
|
409
|
+
if (managedReason !== undefined) {
|
|
410
|
+
diagnostics.push(diagnostic("COMPILER_UNAVAILABLE_OPERATION", familyPath, managedReason));
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
305
413
|
const variants = resource.operations[family];
|
|
306
414
|
if (!isRecord(variants)) {
|
|
307
415
|
diagnostics.push(diagnostic("COMPILER_UNAVAILABLE_OPERATION", familyPath, `operation family "${family}" is not available for resource "${resourceName}"`));
|
|
@@ -349,9 +457,14 @@ function checkReservedResourceNames(model, diagnostics) {
|
|
|
349
457
|
}
|
|
350
458
|
}
|
|
351
459
|
}
|
|
460
|
+
function isAdapterStated(axis) {
|
|
461
|
+
return axis?.kind === "limit" || axis?.kind === "adapterTokens";
|
|
462
|
+
}
|
|
352
463
|
const SCALAR_CAPABILITY_AXES = {
|
|
353
464
|
select: { kind: "flag" },
|
|
354
465
|
filter: { kind: "tokens" },
|
|
466
|
+
filterModes: { kind: "adapterTokens", values: FILTER_MODES },
|
|
467
|
+
pathFilterModes: { kind: "adapterTokens", values: FILTER_MODES },
|
|
355
468
|
order: { kind: "flag" },
|
|
356
469
|
orderNulls: { kind: "flag" },
|
|
357
470
|
create: { kind: "tokens" },
|
|
@@ -445,11 +558,11 @@ function fieldName(resource, field) {
|
|
|
445
558
|
}
|
|
446
559
|
function exemptableAxis(walk, universeField, capability, label, path) {
|
|
447
560
|
const axis = capabilityAxisFor(universeField.kind, capability);
|
|
448
|
-
if (axis === undefined || axis
|
|
561
|
+
if (axis === undefined || isAdapterStated(axis)) {
|
|
449
562
|
const names = Object.entries(universeField.kind === "scalar"
|
|
450
563
|
? SCALAR_CAPABILITY_AXES
|
|
451
564
|
: RELATION_CAPABILITY_AXES)
|
|
452
|
-
.filter(([, entry]) => entry
|
|
565
|
+
.filter(([, entry]) => !isAdapterStated(entry))
|
|
453
566
|
.map(([name]) => name);
|
|
454
567
|
unavailableCapability(path, `"${capability}" is not a capability a ${universeField.kind} field's exemption can name; it takes ${names.join(", ")}`, walk.diagnostics);
|
|
455
568
|
return undefined;
|
|
@@ -533,7 +646,7 @@ function exemptField(walk, universeField, parentField, entry, label, path) {
|
|
|
533
646
|
const result = walk.style === "omit" ? cloneValue(parentCapabilities) : {};
|
|
534
647
|
if (walk.style === "pick") {
|
|
535
648
|
for (const [key, value] of Object.entries(parentCapabilities)) {
|
|
536
|
-
if (capabilityAxisFor(universeField.kind, key)
|
|
649
|
+
if (isAdapterStated(capabilityAxisFor(universeField.kind, key))) {
|
|
537
650
|
result[key] = cloneValue(value);
|
|
538
651
|
}
|
|
539
652
|
}
|
|
@@ -552,7 +665,7 @@ function exemptField(walk, universeField, parentField, entry, label, path) {
|
|
|
552
665
|
return undefined;
|
|
553
666
|
}
|
|
554
667
|
if (walk.style === "pick" &&
|
|
555
|
-
!Object.keys(result).some((key) => capabilityAxisFor(universeField.kind, key)
|
|
668
|
+
!Object.keys(result).some((key) => !isAdapterStated(capabilityAxisFor(universeField.kind, key)))) {
|
|
556
669
|
return undefined;
|
|
557
670
|
}
|
|
558
671
|
return { ...cloneValue(parentField), capabilities: result };
|
|
@@ -839,6 +952,11 @@ function representationFault(axis, value) {
|
|
|
839
952
|
return typeof value === "string" && axis.values.includes(value)
|
|
840
953
|
? undefined
|
|
841
954
|
: `one of ${axis.values.join(", ")} is expected`;
|
|
955
|
+
case "adapterTokens":
|
|
956
|
+
return isTokenList(value) &&
|
|
957
|
+
value.every((token) => axis.values.includes(token))
|
|
958
|
+
? undefined
|
|
959
|
+
: `a list of ${axis.values.join(", ")} is expected`;
|
|
842
960
|
case "flag":
|
|
843
961
|
return typeof value === "boolean" ? undefined : "a boolean is expected";
|
|
844
962
|
case "tokens":
|
|
@@ -912,35 +1030,71 @@ function exposureStyle(layer) {
|
|
|
912
1030
|
}
|
|
913
1031
|
function projectCore(model, config, diagnostics) {
|
|
914
1032
|
const scope = config.root;
|
|
1033
|
+
const managed = managedElsewhereOf(config.trees.root);
|
|
915
1034
|
const providerBaseline = createBaseline(model);
|
|
916
1035
|
const baseline = cloneValue(providerBaseline);
|
|
917
1036
|
baseline.limits = resolveLimits(scope);
|
|
918
1037
|
baseline.transactions = resolveTransactions(model, "root", scope, diagnostics);
|
|
919
|
-
checkResourceTree(model, baseline, "root", config.trees.root, config.definitions, diagnostics);
|
|
1038
|
+
checkResourceTree(model, baseline, "root", config.trees.root, config.definitions, managed, diagnostics);
|
|
920
1039
|
applyFieldDefinitions(model, baseline, config.definitions, diagnostics);
|
|
1040
|
+
const unwithheld = managed.size === 0 ? baseline : cloneValue(baseline);
|
|
1041
|
+
withholdManagedWrites(baseline, managed);
|
|
1042
|
+
markGovernedFields(baseline, config.policy?.governed);
|
|
921
1043
|
applyCompute(baseline, scope.compute);
|
|
922
1044
|
checkLayerValidators(baseline.resources, "root", config.trees.root, diagnostics);
|
|
923
1045
|
const validators = compileValidatorTable(baseline.resources, scope.pipelines);
|
|
924
1046
|
const projection = projectExposure({ layer: "root", style: exposureStyle(scope), diagnostics }, baseline, baseline, scope.exemptions);
|
|
1047
|
+
qualifyFilterModes(projection);
|
|
1048
|
+
pruneHiddenPairings(projection, "shown");
|
|
925
1049
|
projectCreateRequirements(model, projection.resources);
|
|
926
|
-
|
|
1050
|
+
const rootChecked = diagnostics.length;
|
|
1051
|
+
checkHiddenRequirements(model, "root", baseline.resources, unwithheld.resources, projection.resources, diagnostics);
|
|
1052
|
+
explainManagedRefusals(diagnostics, rootChecked, "root", baseline, managed);
|
|
927
1053
|
applyValidators(projection.resources, validators);
|
|
928
1054
|
validateProjection(projection, "root", diagnostics);
|
|
929
1055
|
return { baseline, projection, validators };
|
|
930
1056
|
}
|
|
1057
|
+
function markGovernedFields(baseline, governed) {
|
|
1058
|
+
if (governed === undefined) {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
for (const [resourceName, names] of Object.entries(governed)) {
|
|
1062
|
+
const resource = Object.hasOwn(baseline.resources, resourceName)
|
|
1063
|
+
? baseline.resources[resourceName]
|
|
1064
|
+
: undefined;
|
|
1065
|
+
if (resource === undefined) {
|
|
1066
|
+
continue;
|
|
1067
|
+
}
|
|
1068
|
+
for (const name of names) {
|
|
1069
|
+
const field = Object.hasOwn(resource.fields, name)
|
|
1070
|
+
? resource.fields[name]
|
|
1071
|
+
: undefined;
|
|
1072
|
+
if (field !== undefined) {
|
|
1073
|
+
field.governed = true;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
931
1078
|
function projectDerivedScope(model, scopeName, core, parentView, config, diagnostics) {
|
|
932
1079
|
const scope = config[scopeName];
|
|
1080
|
+
const managed = managedElsewhereOf(config.trees.root);
|
|
933
1081
|
const baseline = cloneValue(core.baseline);
|
|
934
1082
|
baseline.limits = resolveLimits(scope);
|
|
935
1083
|
baseline.transactions = resolveTransactions(model, scopeName, scope, scopeName === "agent" &&
|
|
936
1084
|
scope.transactionsStyle === config[config.agent.parent].transactionsStyle
|
|
937
1085
|
? []
|
|
938
1086
|
: diagnostics);
|
|
939
|
-
checkResourceTree(model, baseline, scopeName, config.trees[scopeName], config.definitions, diagnostics);
|
|
1087
|
+
checkResourceTree(model, baseline, scopeName, config.trees[scopeName], config.definitions, managed, diagnostics);
|
|
940
1088
|
applyCompute(baseline, scope.compute);
|
|
941
1089
|
checkLayerValidators(baseline.resources, scopeName, config.trees[scopeName], diagnostics);
|
|
942
1090
|
const validators = compileValidatorTable(baseline.resources, scope.pipelines);
|
|
943
1091
|
const parent = cloneValue(parentView);
|
|
1092
|
+
const unhidden = (scopeName === "client" || scopeName === "agent") && managed.size > 0
|
|
1093
|
+
? cloneValue(parent)
|
|
1094
|
+
: parent;
|
|
1095
|
+
if (unhidden !== parent) {
|
|
1096
|
+
hideManagedElsewhere(parent, managed);
|
|
1097
|
+
}
|
|
944
1098
|
parent.limits = resolveLimits(scope);
|
|
945
1099
|
parent.transactions = baseline.transactions;
|
|
946
1100
|
applyCompute(parent, scope.compute);
|
|
@@ -950,8 +1104,15 @@ function projectDerivedScope(model, scopeName, core, parentView, config, diagnos
|
|
|
950
1104
|
diagnostics,
|
|
951
1105
|
...(scopeName === "agent" ? { parent: config.agent.parent } : {}),
|
|
952
1106
|
}, baseline, parent, scope.exemptions);
|
|
1107
|
+
qualifyFilterModes(projection);
|
|
1108
|
+
pruneHiddenPairings(projection, "none");
|
|
1109
|
+
if (unhidden !== parent) {
|
|
1110
|
+
pruneManagedEnums(projection, unhidden, managed);
|
|
1111
|
+
}
|
|
953
1112
|
projectCreateRequirements(model, projection.resources);
|
|
954
|
-
|
|
1113
|
+
const layerChecked = diagnostics.length;
|
|
1114
|
+
checkHiddenRequirements(model, scopeName, baseline.resources, unhidden.resources, projection.resources, diagnostics);
|
|
1115
|
+
explainManagedRefusals(diagnostics, layerChecked, scopeName, baseline, managed);
|
|
955
1116
|
applyValidators(projection.resources, validators);
|
|
956
1117
|
validateProjection(projection, scopeName, diagnostics);
|
|
957
1118
|
return { projection, validators };
|
|
@@ -984,12 +1145,15 @@ export async function compileContracts(model, config) {
|
|
|
984
1145
|
: agentParent === "application"
|
|
985
1146
|
? applicationProjection.projection
|
|
986
1147
|
: clientProjection.projection, compilerConfig, diagnostics);
|
|
1148
|
+
markCoreResources(coreCompilation.projection, model, managedElsewhereOf(compilerConfig.trees.root));
|
|
987
1149
|
if (diagnostics.length > 0) {
|
|
988
1150
|
return { ok: false, diagnostics };
|
|
989
1151
|
}
|
|
990
1152
|
const core = semanticObject(coreCompilation.projection);
|
|
991
1153
|
const application = semanticObject(applicationProjection.projection);
|
|
992
|
-
const client = await identifiedContract(
|
|
1154
|
+
const client = await identifiedContract(compilerConfig.access === undefined
|
|
1155
|
+
? clientProjection.projection
|
|
1156
|
+
: { ...clientProjection.projection, access: compilerConfig.access });
|
|
993
1157
|
const agent = await identifiedContract(agentProjection.projection);
|
|
994
1158
|
for (const [layer, contract] of [
|
|
995
1159
|
["client", client],
|
|
@@ -1007,18 +1171,57 @@ export async function compileContracts(model, config) {
|
|
|
1007
1171
|
};
|
|
1008
1172
|
}
|
|
1009
1173
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1174
|
+
const contracts = { core, application, client, agent };
|
|
1175
|
+
bindRuntimePieces(contracts, compilerConfig.definitions, {
|
|
1176
|
+
core: coreCompilation.validators,
|
|
1177
|
+
application: applicationProjection.validators,
|
|
1178
|
+
client: clientProjection.validators,
|
|
1179
|
+
agent: agentProjection.validators,
|
|
1180
|
+
});
|
|
1181
|
+
return { ok: true, contracts };
|
|
1182
|
+
}
|
|
1183
|
+
function bindRuntimePieces(contracts, definitions, validators) {
|
|
1184
|
+
for (const origin of ["core", "application", "client", "agent"]) {
|
|
1185
|
+
bindShapedFields(contracts[origin], definitions);
|
|
1186
|
+
bindFieldValidators(contracts[origin], validators[origin]);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
export function bindPrebuiltContracts(model, config, contracts) {
|
|
1190
|
+
const compilerConfig = config;
|
|
1191
|
+
const fields = validatedFieldsView(model, compilerConfig.definitions);
|
|
1192
|
+
bindRuntimePieces(contracts, compilerConfig.definitions, {
|
|
1193
|
+
core: compileValidatorTable(fields, compilerConfig.root.pipelines),
|
|
1194
|
+
application: compileValidatorTable(fields, compilerConfig.application.pipelines),
|
|
1195
|
+
client: compileValidatorTable(fields, compilerConfig.client.pipelines),
|
|
1196
|
+
agent: compileValidatorTable(fields, compilerConfig.agent.pipelines),
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
function validatedFieldsView(model, definitions) {
|
|
1200
|
+
const resources = { ...model.resources };
|
|
1201
|
+
for (const [resourceName, resourceDefinitions] of Object.entries(definitions)) {
|
|
1202
|
+
const resource = Object.hasOwn(model.resources, resourceName)
|
|
1203
|
+
? model.resources[resourceName]
|
|
1204
|
+
: undefined;
|
|
1205
|
+
if (resource === undefined) {
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
1208
|
+
let added;
|
|
1209
|
+
for (const [fieldName, definition] of Object.entries(resourceDefinitions)) {
|
|
1210
|
+
if (Object.hasOwn(resource.fields, fieldName)) {
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
added ??= {};
|
|
1214
|
+
added[fieldName] = {
|
|
1215
|
+
kind: "scalar",
|
|
1216
|
+
type: definition.type,
|
|
1217
|
+
list: definition.list,
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
if (added !== undefined) {
|
|
1221
|
+
resources[resourceName] = { fields: { ...resource.fields, ...added } };
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return resources;
|
|
1022
1225
|
}
|
|
1023
1226
|
async function identifiedContract(projection) {
|
|
1024
1227
|
const members = canonicalizeContractMembers({
|