@aventara/core 0.1.0-pilot.0 → 0.1.0-pilot.2
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/README.md +3 -3
- package/dist/adapters/adapter-field.d.ts +4 -4
- package/dist/adapters/adapter-resource.d.ts +10 -12
- package/dist/adapters/adapter.interface.d.ts +20 -10
- package/dist/compiler/contract-compiler-diagnostic.d.ts +3 -4
- package/dist/compiler/contract.compiler.d.ts +5 -4
- package/dist/compiler/contract.compiler.js +0 -132
- package/dist/config/config.resolver.d.ts +2 -2
- package/dist/config/config.resolver.js +0 -5
- package/dist/config/config.validator.d.ts +3 -3
- package/dist/config/config.validator.js +0 -8
- package/dist/config/define-fields.d.ts +2 -7
- package/dist/config/define-fields.js +0 -15
- package/dist/config/effective-fields.d.ts +4 -8
- package/dist/config/entrypoint.normalizer.d.ts +7 -7
- package/dist/config/entrypoint.normalizer.js +0 -22
- package/dist/config/framework-behaviors-config.d.ts +6 -6
- package/dist/config/framework-config.d.ts +3 -5
- package/dist/config/framework-restrictions-config.d.ts +19 -29
- package/dist/config/pipeline-config.d.ts +8 -18
- package/dist/contracts/capability.d.ts +18 -21
- package/dist/contracts/capability.js +0 -75
- package/dist/contracts/client-contract-structure.validator.d.ts +15 -22
- package/dist/contracts/client-contract-structure.validator.js +0 -27
- package/dist/contracts/contract-canonicalizer.js +0 -96
- package/dist/contracts/contract-hash.js +0 -2
- package/dist/contracts/contract-limits.js +0 -1
- package/dist/contracts/contract-lookup.js +0 -10
- package/dist/contracts/contract-protocol.js +0 -10
- package/dist/contracts/field.d.ts +23 -26
- package/dist/contracts/field.js +0 -107
- package/dist/contracts/lifecycle-trait.js +0 -5
- package/dist/contracts/resource-operations.d.ts +17 -18
- package/dist/contracts/resource-operations.js +0 -63
- package/dist/contracts/scalar-value-type.d.ts +12 -22
- package/dist/contracts/scalar.js +0 -1
- package/dist/contracts/wire-scalar-format.d.ts +20 -20
- package/dist/contracts/wire-scalar-format.js +0 -26
- package/dist/framework/contract-view.d.ts +7 -8
- package/dist/framework/framework-construction.error.js +0 -1
- package/dist/framework/framework.d.ts +26 -27
- package/dist/framework/framework.factory.js +0 -49
- package/dist/framework/operation-facade.js +0 -17
- package/dist/operations/operation-arguments.d.ts +36 -46
- package/dist/operations/operation-boolean-nodes.js +0 -16
- package/dist/operations/operation-call.d.ts +4 -9
- package/dist/operations/operation-identity.js +0 -1
- package/dist/operations/operation-nesting.js +0 -5
- package/dist/operations/operation-result.d.ts +4 -4
- package/dist/operations/operation-validator-core.d.ts +2 -2
- package/dist/operations/operation-validator-core.js +6 -71
- package/dist/operations/operation-validator.d.ts +4 -4
- package/dist/operations/operation-validator.js +0 -12
- package/dist/operations/projection-scope.resolver.d.ts +8 -10
- package/dist/operations/projection-scope.resolver.js +0 -35
- package/dist/operations/validation-code.d.ts +11 -18
- package/dist/operations/validation-code.js +0 -24
- package/dist/operations/write-scope.resolver.d.ts +4 -7
- package/dist/operations/write-scope.resolver.js +0 -37
- package/dist/protocol/absent-route.responder.d.ts +33 -48
- package/dist/protocol/absent-route.responder.js +13 -57
- package/dist/protocol/av-protocol.d.ts +6 -6
- package/dist/protocol/av-protocol.js +0 -10
- package/dist/protocol/contract-document.responder.d.ts +15 -18
- package/dist/protocol/contract-document.responder.js +0 -33
- package/dist/protocol/http-request.decoder.d.ts +55 -61
- package/dist/protocol/http-request.decoder.js +0 -62
- package/dist/protocol/http-request.reader.d.ts +12 -13
- package/dist/protocol/http-request.reader.js +0 -45
- package/dist/protocol/http-response.encoder.d.ts +17 -18
- package/dist/protocol/http-response.encoder.js +0 -59
- package/dist/protocol/http-status.table.d.ts +7 -11
- package/dist/protocol/http-status.table.js +1 -15
- package/dist/protocol/index.d.ts +5 -5
- package/dist/protocol/index.js +0 -9
- package/dist/protocol/operation-response.guard.d.ts +12 -19
- package/dist/protocol/operation-response.guard.js +0 -29
- package/dist/protocol/protocol-failure.d.ts +26 -23
- package/dist/protocol/protocol-failure.js +6 -6
- package/dist/protocol/protocol-headers.d.ts +30 -27
- package/dist/protocol/protocol-headers.js +3 -61
- package/dist/protocol/protocol-surface.d.ts +25 -29
- package/dist/protocol/protocol-surface.js +0 -19
- package/dist/protocol/protocol.binder.d.ts +58 -71
- package/dist/protocol/protocol.binder.js +0 -8
- package/dist/protocol/protocol.handler.d.ts +28 -32
- package/dist/protocol/protocol.handler.js +0 -43
- package/dist/runtime/computed-read-runtime.js +0 -29
- package/dist/runtime/create-requirement.d.ts +65 -0
- package/dist/runtime/create-requirement.js +141 -0
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +0 -8
- package/dist/runtime/diagnostics-reporter.d.ts +6 -6
- package/dist/runtime/diagnostics-reporter.js +0 -35
- package/dist/runtime/error-boundary.d.ts +3 -3
- package/dist/runtime/error-boundary.js +2 -167
- package/dist/runtime/execution-options.d.ts +4 -4
- package/dist/runtime/field-behavior.d.ts +6 -9
- package/dist/runtime/framework-error.js +0 -4
- package/dist/runtime/mutation-planner.d.ts +5 -6
- package/dist/runtime/mutation-planner.js +0 -23
- package/dist/runtime/operation-response.d.ts +1 -1
- package/dist/runtime/operation-response.js +1 -17
- package/dist/runtime/operation-runtime.d.ts +24 -22
- package/dist/runtime/operation-runtime.js +18 -52
- package/dist/runtime/outcome-mapper.js +0 -22
- package/dist/runtime/output-validator.js +0 -1
- package/dist/runtime/pipe-output.validator.d.ts +48 -0
- package/dist/runtime/pipe-output.validator.js +79 -0
- package/dist/runtime/pipeline.d.ts +20 -26
- package/dist/runtime/referential-action.d.ts +14 -19
- package/dist/runtime/referential-action.js +0 -23
- package/dist/runtime/request-id.js +0 -21
- package/dist/runtime/scalar-runtime.d.ts +14 -16
- package/dist/runtime/scalar-runtime.js +12 -57
- package/dist/transactions/deferred-operation.d.ts +9 -14
- package/dist/transactions/operation-arguments-encoder.d.ts +0 -1
- package/dist/transactions/operation-arguments-encoder.js +0 -14
- package/dist/transactions/operation-fingerprint.js +0 -1
- package/dist/transactions/transaction-envelope.js +0 -14
- package/dist/transactions/transaction-integrity-error.d.ts +10 -11
- package/dist/transactions/transaction-integrity-error.js +0 -5
- package/dist/transactions/transaction-plan-assembler.d.ts +0 -1
- package/dist/transactions/transaction-plan-assembler.js +0 -35
- package/dist/transactions/transaction-plan-validator.d.ts +5 -5
- package/dist/transactions/transaction-plan-validator.js +0 -63
- package/dist/transactions/transaction-reference-resolver.d.ts +12 -13
- package/dist/transactions/transaction-reference-resolver.js +0 -16
- package/dist/transactions/transaction-reference-validator.js +0 -8
- package/dist/transactions/transaction-reference.d.ts +19 -43
- package/dist/transactions/transaction-reference.js +0 -11
- package/dist/transactions/transaction-request.d.ts +4 -5
- package/dist/transactions/transaction-response.d.ts +1 -1
- package/dist/transactions/transaction-runtime.d.ts +2 -3
- package/dist/transactions/transaction-runtime.js +5 -44
- package/dist/transactions/transaction-slot-path-error.d.ts +10 -11
- package/dist/transactions/transaction-slot-path-error.js +0 -7
- package/dist/transactions/transaction-slot-writer.d.ts +12 -12
- package/dist/transactions/transaction-slot-writer.js +0 -34
- package/package.json +2 -2
|
@@ -168,11 +168,6 @@ function validateScalarFilter(fieldName, field, value, path, state) {
|
|
|
168
168
|
}
|
|
169
169
|
return;
|
|
170
170
|
}
|
|
171
|
-
// Equality shorthand: anything that is not a plain record is a value — a
|
|
172
|
-
// `Date`, a `Decimal` and a `Uint8Array` included — read through the scalar
|
|
173
|
-
// runtime's own discriminant, which holds it to the field's scalar after
|
|
174
|
-
// this layer (`normalizeScalarFilter`). Reading every object as operators
|
|
175
|
-
// refused the shorthand the ORM accepts (C-855, sign flipped).
|
|
176
171
|
if (!isPlainRecord(value)) {
|
|
177
172
|
if (!includes(supported, "equals")) {
|
|
178
173
|
addIssue(state.issues, "V1006", path, `Equality filtering is not available on field "${fieldName}".`);
|
|
@@ -409,14 +404,7 @@ function validateCursor(contract, resourceName, cursor, orderBy, path, issues) {
|
|
|
409
404
|
addIssue(issues, "V1009", path, "orderBy must include a complete Resource identifier as an explicit tie-breaker.");
|
|
410
405
|
}
|
|
411
406
|
}
|
|
412
|
-
function validateProjection(contract, resourceName, mode, value,
|
|
413
|
-
/**
|
|
414
|
-
* The projection position THIS projection's own field and relation entries sit
|
|
415
|
-
* in. The caller resolves it once from the advertised variant; a nested call
|
|
416
|
-
* passes {@link NESTED_PROJECTION_SCOPE}, because a scope qualifies the top level
|
|
417
|
-
* only. A `$count` entry is the exception and reads {@link ReducerOwner.scope}.
|
|
418
|
-
*/
|
|
419
|
-
scope, path, issues, reducerOwner) {
|
|
407
|
+
function validateProjection(contract, resourceName, mode, value, scope, path, issues, reducerOwner) {
|
|
420
408
|
if (!Array.isArray(value)) {
|
|
421
409
|
addIssue(issues, "V1008", path, `${mode} must be an array.`);
|
|
422
410
|
return;
|
|
@@ -431,10 +419,7 @@ scope, path, issues, reducerOwner) {
|
|
|
431
419
|
if (entry === "$count") {
|
|
432
420
|
if (mode !== "select" ||
|
|
433
421
|
reducerOwner?.edge.cardinality !== "many" ||
|
|
434
|
-
!includes(advertisedReducersAt(reducerOwner.edge.capabilities.reducers,
|
|
435
|
-
// The OWNER's position, not this projection's: see
|
|
436
|
-
// {@link ReducerOwner}.
|
|
437
|
-
reducerOwner.scope), "$count")) {
|
|
422
|
+
!includes(advertisedReducersAt(reducerOwner.edge.capabilities.reducers, reducerOwner.scope), "$count")) {
|
|
438
423
|
addIssue(issues, "V1008", entryPath, "$count is available only as an advertised to-many relation reducer.");
|
|
439
424
|
}
|
|
440
425
|
return;
|
|
@@ -477,16 +462,10 @@ scope, path, issues, reducerOwner) {
|
|
|
477
462
|
addIssue(issues, "V1008", relationPath, `Relation "${relationName}" is not available for ${mode}.`);
|
|
478
463
|
return;
|
|
479
464
|
}
|
|
480
|
-
validateRelationProjection(contract, field,
|
|
481
|
-
// The position the edge itself was admitted in. The edge's nested
|
|
482
|
-
// projection is unrestricted, but a `$count` of this edge is carried at
|
|
483
|
-
// THIS level, so the scope has to travel with the edge.
|
|
484
|
-
scope, entry[relationName], relationPath, issues);
|
|
465
|
+
validateRelationProjection(contract, field, scope, entry[relationName], relationPath, issues);
|
|
485
466
|
});
|
|
486
467
|
}
|
|
487
|
-
function validateRelationProjection(contract, edge,
|
|
488
|
-
/** The projection position `edge` itself was admitted in — see {@link ReducerOwner}. */
|
|
489
|
-
scope, value, path, issues) {
|
|
468
|
+
function validateRelationProjection(contract, edge, scope, value, path, issues) {
|
|
490
469
|
if (!isRecord(value)) {
|
|
491
470
|
addIssue(issues, "V1008", path, "Customized relation projection must be an object.");
|
|
492
471
|
return;
|
|
@@ -551,10 +530,6 @@ scope, value, path, issues) {
|
|
|
551
530
|
validateCursor(contract, edge.target, value.cursor, value.orderBy, [...path, "cursor"], issues);
|
|
552
531
|
}
|
|
553
532
|
}
|
|
554
|
-
// Past an admitted relation the unrestricted surface returns, measured on both
|
|
555
|
-
// pilot engines — see {@link NESTED_PROJECTION_SCOPE}. The edge's own scope is
|
|
556
|
-
// deliberately NOT passed down: a recursive narrowing would refuse what the ORM
|
|
557
|
-
// accepts.
|
|
558
533
|
if ("select" in value) {
|
|
559
534
|
validateProjection(contract, edge.target, "select", value.select, NESTED_PROJECTION_SCOPE, [...path, "select"], issues, { edge, scope });
|
|
560
535
|
}
|
|
@@ -595,16 +570,6 @@ function validateScalarMutation(fieldName, field, value, stage, path, issues, tr
|
|
|
595
570
|
}
|
|
596
571
|
}
|
|
597
572
|
}
|
|
598
|
-
/**
|
|
599
|
-
* One relation mutation directive's operand, past the point where the directive
|
|
600
|
-
* itself was admitted.
|
|
601
|
-
*
|
|
602
|
-
* It takes **no write scope**, and that is the rule rather than an omission: every
|
|
603
|
-
* data object it reaches is nested, and {@link NESTED_WRITE_SCOPE} is the answer at
|
|
604
|
-
* every depth. A parameter here would be a parameter this function could only
|
|
605
|
-
* ignore, and the next reader would thread the caller's scope through it and refuse
|
|
606
|
-
* what the ORM accepts.
|
|
607
|
-
*/
|
|
608
573
|
function validateRelationMutationEntry(contract, edge, directive, value, path, issues) {
|
|
609
574
|
const target = edge.target;
|
|
610
575
|
if (edge.cardinality === "one" && Array.isArray(value)) {
|
|
@@ -747,13 +712,7 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
747
712
|
}
|
|
748
713
|
}
|
|
749
714
|
}
|
|
750
|
-
function validateRelationMutation(contract, fieldName, field, value, stage,
|
|
751
|
-
/** The write position this relation member itself sits in; see {@link WriteScope}. */
|
|
752
|
-
scope, path, issues) {
|
|
753
|
-
// Scope-aware, through the shape owner's one reader. A stage that does not hold
|
|
754
|
-
// at this write position is not writable at this write position, and says so with
|
|
755
|
-
// the message an absent member already has — which is why the two answers
|
|
756
|
-
// `advertisedDirectivesAt` can give are the two this branch already handled.
|
|
715
|
+
function validateRelationMutation(contract, fieldName, field, value, stage, scope, path, issues) {
|
|
757
716
|
const directives = advertisedDirectivesAt(field.capabilities[stage], scope);
|
|
758
717
|
if (directives === undefined) {
|
|
759
718
|
addIssue(issues, "V1006", path, `Relation "${fieldName}" is not writable during ${stage}.`);
|
|
@@ -772,15 +731,7 @@ scope, path, issues) {
|
|
|
772
731
|
validateRelationMutationEntry(contract, field, directive, directiveValue, directivePath, issues);
|
|
773
732
|
}
|
|
774
733
|
}
|
|
775
|
-
function validateMutationData(contract, resourceName, data, stage,
|
|
776
|
-
/**
|
|
777
|
-
* The write position THIS data object's own relation members sit in. The caller
|
|
778
|
-
* resolves it once from the advertised variant; a nested call passes
|
|
779
|
-
* {@link NESTED_WRITE_SCOPE}, because a scope qualifies the top level only.
|
|
780
|
-
* Scalar members never read it — all six scalar capability members were measured
|
|
781
|
-
* uniform across every variant on the axis.
|
|
782
|
-
*/
|
|
783
|
-
scope, path, issues, transactionReferences = false) {
|
|
734
|
+
function validateMutationData(contract, resourceName, data, stage, scope, path, issues, transactionReferences = false) {
|
|
784
735
|
if (!isRecord(data)) {
|
|
785
736
|
addIssue(issues, "V1001", path, `${stage} data must be an object.`);
|
|
786
737
|
return;
|
|
@@ -806,14 +757,6 @@ scope, path, issues, transactionReferences = false) {
|
|
|
806
757
|
}
|
|
807
758
|
}
|
|
808
759
|
function validateMutationArguments(contract, resourceName, request, args, issues, options) {
|
|
809
|
-
// The one resolution, from the variant the Resource advertises, and the write
|
|
810
|
-
// mirror of the projection scope resolved at the top level. It qualifies the top
|
|
811
|
-
// level of the write argument only; everything beneath an admitted relation
|
|
812
|
-
// directive is nested and asks about the unrestricted position instead.
|
|
813
|
-
//
|
|
814
|
-
// Resolved here rather than passed in because `request` is what carries the
|
|
815
|
-
// variant, and an argument walk handed a scope could be handed one resolved for a
|
|
816
|
-
// different request.
|
|
817
760
|
const scope = resolveWriteScope(getResource(contract, resourceName), request);
|
|
818
761
|
if (request.family === "create") {
|
|
819
762
|
if (!("data" in args)) {
|
|
@@ -853,12 +796,6 @@ function isUniqueOperation(request) {
|
|
|
853
796
|
request.family === "delete" ||
|
|
854
797
|
request.family === "upsert"));
|
|
855
798
|
}
|
|
856
|
-
/**
|
|
857
|
-
* The Framework Validation Layer's issue for a request naming a Resource the
|
|
858
|
-
* active Contract does not have (`V1005` at `["resource"]`, rolling up to
|
|
859
|
-
* `A2001`). The one spelling — the protocol's absence answers
|
|
860
|
-
* (`@aventara/core/protocol`, Q2's O3) build theirs with it.
|
|
861
|
-
*/
|
|
862
799
|
export function resourceUnavailableIssue(resource) {
|
|
863
800
|
return {
|
|
864
801
|
code: "V1005",
|
|
@@ -911,8 +848,6 @@ export function validateOperationArguments(contract, request, options) {
|
|
|
911
848
|
if ("cursor" in request.arguments) {
|
|
912
849
|
validateCursor(contract, request.resource, request.arguments.cursor, request.arguments.orderBy, ["arguments", "cursor"], issues);
|
|
913
850
|
}
|
|
914
|
-
// The one resolution, from the variant the Resource advertises. Everything below
|
|
915
|
-
// the top level is nested and asks about the unrestricted position instead.
|
|
916
851
|
const projectionScope = resolveProjectionScope(resource, request);
|
|
917
852
|
if ("select" in request.arguments) {
|
|
918
853
|
validateProjection(contract, request.resource, "select", request.arguments.select, projectionScope, ["arguments", "select"], issues);
|
|
@@ -4,11 +4,11 @@ import { type OperationValidationOptions, type OperationValidationResult } from
|
|
|
4
4
|
import type { ValidationIssue } from "./validation-code.js";
|
|
5
5
|
export type { OperationValidationOptions, OperationValidationResult, SemanticOperationArguments, } from "./operation-validator-core.js";
|
|
6
6
|
/**
|
|
7
|
-
* The Framework Validation Layer's issue for a `(resource, family, variant)`
|
|
8
|
-
*
|
|
7
|
+
* The Framework Validation Layer's issue for a `(resource, family, variant)` the
|
|
8
|
+
* active Contract does not advertise on a Resource it has (`V1006` at
|
|
9
9
|
* `["operation"]`, rolling up to `A2002`). The one spelling — the protocol's
|
|
10
|
-
* absence answers
|
|
11
|
-
*
|
|
10
|
+
* absence answers build theirs with it, so a caller cannot tell which layer
|
|
11
|
+
* answered.
|
|
12
12
|
*/
|
|
13
13
|
export declare function operationUnavailableIssue(request: {
|
|
14
14
|
readonly resource: string;
|
|
@@ -15,13 +15,6 @@ function isOperationAvailable(contract, request) {
|
|
|
15
15
|
const family = lookupOwn(advertised, request.family);
|
|
16
16
|
return isOperationVariantAvailable(lookupOwn(family, request.variant));
|
|
17
17
|
}
|
|
18
|
-
/**
|
|
19
|
-
* The Framework Validation Layer's issue for a `(resource, family, variant)`
|
|
20
|
-
* the active Contract does not advertise on a Resource it has (`V1006` at
|
|
21
|
-
* `["operation"]`, rolling up to `A2002`). The one spelling — the protocol's
|
|
22
|
-
* absence answers (`@aventara/core/protocol`, Q2's O3) build theirs with it, so
|
|
23
|
-
* a caller cannot tell which layer answered.
|
|
24
|
-
*/
|
|
25
18
|
export function operationUnavailableIssue(request) {
|
|
26
19
|
return {
|
|
27
20
|
path: ["operation"],
|
|
@@ -39,11 +32,6 @@ function hasGeneralRootWhere(request) {
|
|
|
39
32
|
request.family === "delete" ||
|
|
40
33
|
request.family === "upsert"));
|
|
41
34
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Validates one standard operation's semantic arguments against the active
|
|
44
|
-
* Contract. Operation availability and request-wide structural limits are
|
|
45
|
-
* enforced before deeper grammar validation.
|
|
46
|
-
*/
|
|
47
35
|
export function validateOperationArguments(contract, request, options) {
|
|
48
36
|
if (!isOperationAvailable(contract, request)) {
|
|
49
37
|
return { ok: false, issues: [operationUnavailableIssue(request)] };
|
|
@@ -26,16 +26,14 @@ export declare function resolveProjectionScope(resource: Resource<Contract> | un
|
|
|
26
26
|
* The position a projection NESTED beneath an admitted relation sits in: the
|
|
27
27
|
* unrestricted one, at every depth, under every top-level scope.
|
|
28
28
|
*
|
|
29
|
-
* **Measured at runtime on both pilot engines, 2026-10-03** — not inferred from
|
|
30
|
-
* types, which permit more than they accept. A bulk-returning write accepted
|
|
31
|
-
* `include: { <owned to-one>: { include: { <to-many>: true } } }` and populated
|
|
32
|
-
* rows, while the same to-many asked for at the top level was refused
|
|
33
|
-
* generated types say why: a bulk projection types an admitted
|
|
34
|
-
* *unrestricted* projection argument, so the full surface returns
|
|
29
|
+
* **Measured at runtime on both pilot engines, 2026-10-03** — not inferred from
|
|
30
|
+
* the types, which permit more than they accept. A bulk-returning write accepted
|
|
31
|
+
* `include: { <owned to-one>: { include: { <to-many>: true } } }` and populated
|
|
32
|
+
* the rows, while the same to-many asked for at the top level was refused
|
|
33
|
+
* outright. The generated types say why: a bulk projection types an admitted
|
|
34
|
+
* relation as the *unrestricted* projection argument, so the full surface returns
|
|
35
|
+
* one level in.
|
|
35
36
|
*
|
|
36
|
-
* Naming it is the point.
|
|
37
|
-
* refuse what the ORM accepts, which is C-855 with the sign flipped and the same
|
|
38
|
-
* defect; this constant is the single place that decision is written, and S7's
|
|
39
|
-
* `bulkDoesNotNarrowRecursively` pins the identical rule at the type level.
|
|
37
|
+
* Naming it is the point.
|
|
40
38
|
*/
|
|
41
39
|
export declare const NESTED_PROJECTION_SCOPE: ProjectionScope;
|
|
@@ -1,42 +1,7 @@
|
|
|
1
1
|
import { lookupOwn } from "../contracts/contract-lookup.js";
|
|
2
2
|
import { projectionScopeOf, } from "../contracts/resource-operations.js";
|
|
3
|
-
/**
|
|
4
|
-
* Which projection position one request's **top-level** projection arguments sit
|
|
5
|
-
* in, read off the variant the Resource advertises.
|
|
6
|
-
*
|
|
7
|
-
* Two readers need the answer and they run one after the other over the same
|
|
8
|
-
* request — the `maxBooleanNodes` walk in `operation-boolean-nodes.ts`, then the
|
|
9
|
-
* grammar walk in `operation-validator-core.ts`. They must agree: a walk that
|
|
10
|
-
* resolved a wider scope than the validator would count nodes inside a projection
|
|
11
|
-
* the validator then refuses (harmless), and a walk that resolved a narrower one
|
|
12
|
-
* would stop counting inside a projection the validator admits, which is a limit
|
|
13
|
-
* silently not enforced. So the resolution has one home.
|
|
14
|
-
*
|
|
15
|
-
* `"record"` is the answer wherever nothing narrower is stated — an absent
|
|
16
|
-
* Resource, an unadvertised variant, `true`, or a descriptor that qualifies only
|
|
17
|
-
* its write argument. Availability is **not** decided here: an unadvertised
|
|
18
|
-
* operation is refused by `operation-validator.ts` before either walk runs, and
|
|
19
|
-
* answering `"record"` for one keeps this function a projection question rather
|
|
20
|
-
* than a second, weaker copy of the availability gate.
|
|
21
|
-
*/
|
|
22
3
|
export function resolveProjectionScope(resource, request) {
|
|
23
4
|
const advertised = lookupOwn(resource?.operations, request.family);
|
|
24
5
|
return projectionScopeOf(lookupOwn(advertised, request.variant));
|
|
25
6
|
}
|
|
26
|
-
/**
|
|
27
|
-
* The position a projection NESTED beneath an admitted relation sits in: the
|
|
28
|
-
* unrestricted one, at every depth, under every top-level scope.
|
|
29
|
-
*
|
|
30
|
-
* **Measured at runtime on both pilot engines, 2026-10-03** — not inferred from the
|
|
31
|
-
* types, which permit more than they accept. A bulk-returning write accepted
|
|
32
|
-
* `include: { <owned to-one>: { include: { <to-many>: true } } }` and populated the
|
|
33
|
-
* rows, while the same to-many asked for at the top level was refused outright. The
|
|
34
|
-
* generated types say why: a bulk projection types an admitted relation as the
|
|
35
|
-
* *unrestricted* projection argument, so the full surface returns one level in.
|
|
36
|
-
*
|
|
37
|
-
* Naming it is the point. A recursive walk that passed its own scope down would
|
|
38
|
-
* refuse what the ORM accepts, which is C-855 with the sign flipped and the same
|
|
39
|
-
* defect; this constant is the single place that decision is written, and S7's
|
|
40
|
-
* `bulkDoesNotNarrowRecursively` pins the identical rule at the type level.
|
|
41
|
-
*/
|
|
42
7
|
export const NESTED_PROJECTION_SCOPE = "record";
|
|
@@ -1,27 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* array for the same reason `OPERATION_CODES` is one: the union below is the
|
|
6
|
-
* compiler's view of the set, and the response boundary needs the set itself
|
|
7
|
-
* to test a thrower-supplied code by identity before emitting it (ADR 0005
|
|
8
|
-
* applied to the V axis, ADR 0008 decision 4).
|
|
2
|
+
* It is a runtime array for the same reason `OPERATION_CODES` is one: the union
|
|
3
|
+
* below is the compiler's view of the set, and the response boundary needs the set
|
|
4
|
+
* itself to test a thrower-supplied code by identity before emitting it.
|
|
9
5
|
*/
|
|
10
6
|
export declare const VALIDATION_CODES: readonly ["V1000", "V1001", "V1002", "V1003", "V1004", "V1005", "V1006", "V1007", "V1008", "V1009", "V1010", "V1011", "V1012", "V1013", "V1014", "V1015", "V1016", "V1017", "V1018", "V1019"];
|
|
11
7
|
export type ValidationCode = (typeof VALIDATION_CODES)[number];
|
|
12
8
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* thrower-supplied issue message, which is untrusted and may carry provider
|
|
17
|
-
* text that specification 13.5 forbids in `cause`.
|
|
9
|
+
* This is the text the response boundary emits in place of a thrower-supplied
|
|
10
|
+
* issue message, which is untrusted and may carry provider text that specification
|
|
11
|
+
* 13.5 forbids in `cause`.
|
|
18
12
|
*
|
|
19
|
-
* It is deliberately not the only message a `V` code may ever carry. A
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* the ones it did.
|
|
13
|
+
* It is deliberately not the only message a `V` code may ever carry. A framework
|
|
14
|
+
* producer knows the offending field, limit or reference and says so; those issues
|
|
15
|
+
* are built here and mapped straight to their envelope by `mapValidationOutcome`,
|
|
16
|
+
* never through the sanitization boundary. This table is the floor for an issue
|
|
17
|
+
* the framework did not author, not a ceiling on the ones it did.
|
|
25
18
|
*/
|
|
26
19
|
export declare const VALIDATION_CODE_MESSAGES: Readonly<Record<ValidationCode, string>>;
|
|
27
20
|
export type ValidationIssue = {
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The closed Validation-code vocabulary, allocated by specification 13.3 as
|
|
3
|
-
* `V1000`-`V1015`, amended to `V1018` by ADR 0006 DA-4 and to `V1019` by the
|
|
4
|
-
* Phase 9 cascade refusal (§13.3, ADR 0008 decision 4). It is a runtime
|
|
5
|
-
* array for the same reason `OPERATION_CODES` is one: the union below is the
|
|
6
|
-
* compiler's view of the set, and the response boundary needs the set itself
|
|
7
|
-
* to test a thrower-supplied code by identity before emitting it (ADR 0005
|
|
8
|
-
* applied to the V axis, ADR 0008 decision 4).
|
|
9
|
-
*/
|
|
10
1
|
export const VALIDATION_CODES = [
|
|
11
2
|
"V1000",
|
|
12
3
|
"V1001",
|
|
@@ -29,20 +20,6 @@ export const VALIDATION_CODES = [
|
|
|
29
20
|
"V1018",
|
|
30
21
|
"V1019",
|
|
31
22
|
];
|
|
32
|
-
/**
|
|
33
|
-
* The framework's own text for each Validation code: the published meaning
|
|
34
|
-
* from specification 13.3, and from ADR 0006 DA-4 for the three codes it
|
|
35
|
-
* amended in. `V1019` is the architect's wording, verbatim (2026-10-04). This is the text the response boundary emits in place of a
|
|
36
|
-
* thrower-supplied issue message, which is untrusted and may carry provider
|
|
37
|
-
* text that specification 13.5 forbids in `cause`.
|
|
38
|
-
*
|
|
39
|
-
* It is deliberately not the only message a `V` code may ever carry. A
|
|
40
|
-
* framework producer knows the offending field, limit or reference and says
|
|
41
|
-
* so; those issues are built here and mapped straight to their envelope by
|
|
42
|
-
* `mapValidationOutcome`, never through the sanitization boundary. This table
|
|
43
|
-
* is the floor for an issue the framework did not author, not a ceiling on
|
|
44
|
-
* the ones it did.
|
|
45
|
-
*/
|
|
46
23
|
export const VALIDATION_CODE_MESSAGES = {
|
|
47
24
|
V1000: "Required value missing.",
|
|
48
25
|
V1001: "Invalid runtime/wire type.",
|
|
@@ -65,7 +42,6 @@ export const VALIDATION_CODE_MESSAGES = {
|
|
|
65
42
|
V1018: "Transaction reference resolved to no value.",
|
|
66
43
|
V1019: "Transaction step depends on a row removed by an earlier step's cascade",
|
|
67
44
|
};
|
|
68
|
-
/** Builds one Framework Validation Layer issue at its path. */
|
|
69
45
|
export function validationIssue(code, path, message) {
|
|
70
46
|
return { code, path, message };
|
|
71
47
|
}
|
|
@@ -30,14 +30,11 @@ export declare function resolveWriteScope(resource: Resource<Contract> | undefin
|
|
|
30
30
|
* `$connectOrCreate.create`, `$update.data` or `$upsert`'s two branches lands in
|
|
31
31
|
* the unrestricted write input on both pilot engines, whatever the top-level
|
|
32
32
|
* argument was. The measurement behind that is the flat bulk write inputs carrying
|
|
33
|
-
* **no relation member at all**, so a nested write is only ever reachable
|
|
34
|
-
* a relation the top-level scope already admitted — and past that point
|
|
35
|
-
* write surface returns.
|
|
33
|
+
* **no relation member at all**, so a nested write is only ever reachable
|
|
34
|
+
* *through* a relation the top-level scope already admitted — and past that point
|
|
35
|
+
* the full write surface returns.
|
|
36
36
|
*
|
|
37
37
|
* Naming it is the point, exactly as `NESTED_PROJECTION_SCOPE` names the same
|
|
38
|
-
* decision on the read axis.
|
|
39
|
-
* refuse what the ORM accepts, which is C-855 with the sign flipped and the same
|
|
40
|
-
* defect; this constant is the single place that decision is written, and S7's
|
|
41
|
-
* non-recursion rows pin the identical rule at the type level.
|
|
38
|
+
* decision on the read axis.
|
|
42
39
|
*/
|
|
43
40
|
export declare const NESTED_WRITE_SCOPE: WriteScope;
|
|
@@ -1,44 +1,7 @@
|
|
|
1
1
|
import { lookupOwn } from "../contracts/contract-lookup.js";
|
|
2
2
|
import { writeScopeOf, } from "../contracts/resource-operations.js";
|
|
3
|
-
/**
|
|
4
|
-
* Which write position one request's **top-level** `data` (or `create`/`update`)
|
|
5
|
-
* argument sits in, read off the variant the Resource advertises.
|
|
6
|
-
*
|
|
7
|
-
* The write mirror of `resolveProjectionScope`, and a separate function for the
|
|
8
|
-
* reason `resource-operations.ts` gives for `projectionScopeOf`/`writeScopeOf`
|
|
9
|
-
* being two: the axes are measured and consulted independently — the flat-bulk
|
|
10
|
-
* write scope covers four variants where the bulk-returning projection scope
|
|
11
|
-
* covers two — and a caller that needs one position should not be handed the other
|
|
12
|
-
* to discard.
|
|
13
|
-
*
|
|
14
|
-
* `"nested"` is the answer wherever nothing narrower is stated — an absent
|
|
15
|
-
* Resource, an unadvertised variant, `true`, or a descriptor that qualifies only
|
|
16
|
-
* its projection argument. Availability is **not** decided here: an unadvertised
|
|
17
|
-
* operation is refused by `operation-validator.ts` before the mutation walk runs,
|
|
18
|
-
* and answering `"nested"` for one keeps this function a write question rather than
|
|
19
|
-
* a second, weaker copy of the availability gate.
|
|
20
|
-
*/
|
|
21
3
|
export function resolveWriteScope(resource, request) {
|
|
22
4
|
const advertised = lookupOwn(resource?.operations, request.family);
|
|
23
5
|
return writeScopeOf(lookupOwn(advertised, request.variant));
|
|
24
6
|
}
|
|
25
|
-
/**
|
|
26
|
-
* The position a write NESTED beneath an admitted relation directive sits in: the
|
|
27
|
-
* unrestricted one, at every depth, under every top-level scope.
|
|
28
|
-
*
|
|
29
|
-
* It is a constant and not a parameter the recursion threads, because there is no
|
|
30
|
-
* depth at which the answer differs. A relation write reached through `$create`,
|
|
31
|
-
* `$connectOrCreate.create`, `$update.data` or `$upsert`'s two branches lands in
|
|
32
|
-
* the unrestricted write input on both pilot engines, whatever the top-level
|
|
33
|
-
* argument was. The measurement behind that is the flat bulk write inputs carrying
|
|
34
|
-
* **no relation member at all**, so a nested write is only ever reachable *through*
|
|
35
|
-
* a relation the top-level scope already admitted — and past that point the full
|
|
36
|
-
* write surface returns.
|
|
37
|
-
*
|
|
38
|
-
* Naming it is the point, exactly as `NESTED_PROJECTION_SCOPE` names the same
|
|
39
|
-
* decision on the read axis. A recursive walk that passed its own scope down would
|
|
40
|
-
* refuse what the ORM accepts, which is C-855 with the sign flipped and the same
|
|
41
|
-
* defect; this constant is the single place that decision is written, and S7's
|
|
42
|
-
* non-recursion rows pin the identical rule at the type level.
|
|
43
|
-
*/
|
|
44
7
|
export const NESTED_WRITE_SCOPE = "nested";
|
|
@@ -6,23 +6,11 @@ import type { AvProtocolRequest } from "./http-request.decoder.js";
|
|
|
6
6
|
import { type ReadRequest } from "./http-request.reader.js";
|
|
7
7
|
import { type AvProtocolResponse } from "./http-response.encoder.js";
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* reaches an Adapter: the protocol version (`A2006`), the ClientContract hash
|
|
12
|
-
* (`A2005`), then whether the ClientContract advertises the route at all
|
|
13
|
-
* (`A2001`, `A2002`). One implementation, for both route styles Q12 permits:
|
|
14
|
-
* the decoders answer a catch-all host's unadvertised path with it, and
|
|
15
|
-
* `protocol.answerAbsent` (S10) is the fallback a per-operation host mounts.
|
|
9
|
+
* "Removed" and "never existed" are not distinguished; a stale client hears
|
|
10
|
+
* `A2005` first.
|
|
16
11
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* `resourceUnavailableIssue`, `operationUnavailableIssue`,
|
|
20
|
-
* `mapValidationOutcome`, `transactionsUnavailableFailure`) — so a caller
|
|
21
|
-
* cannot tell which layer answered [M4, M5, M17]. "Removed" and "never
|
|
22
|
-
* existed" are not distinguished; a stale client hears `A2005` first (Q3).
|
|
23
|
-
*
|
|
24
|
-
* It reads the compiled Contracts only — passive data — so nothing it depends
|
|
25
|
-
* on can execute an operation.
|
|
12
|
+
* It reads the compiled Contracts only — passive data — so nothing it depends on
|
|
13
|
+
* can execute an operation.
|
|
26
14
|
*/
|
|
27
15
|
/** A route's three decoded segments, still untrusted strings. */
|
|
28
16
|
export type OperationRouteSegments = {
|
|
@@ -39,20 +27,19 @@ export type OperationRouteResolution = {
|
|
|
39
27
|
readonly failure: OperationFailureResponse;
|
|
40
28
|
};
|
|
41
29
|
/**
|
|
42
|
-
* An operation route `/_resources/<resource>/<family>/<variant>` under one
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
30
|
+
* An operation route `/_resources/<resource>/<family>/<variant>` under one client
|
|
31
|
+
* protocol identity: version → hash → Resource → operation. A Resource key is
|
|
32
|
+
* matched exactly and only as the ClientContract's own key; a family/variant pair
|
|
33
|
+
* only when it is a standard operation the Resource advertises, read through
|
|
34
|
+
* `isOperationVariantAvailable` alone.
|
|
47
35
|
*/
|
|
48
36
|
export declare function resolveOperationRoute(contracts: FrameworkContracts, protocol: ClientProtocolIdentity, route: OperationRouteSegments): OperationRouteResolution;
|
|
49
37
|
/**
|
|
50
|
-
* The `/_transactions` route under one client protocol identity: version →
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* `undefined` when the route is there.
|
|
38
|
+
* The `/_transactions` route under one client protocol identity: version → hash →
|
|
39
|
+
* the ClientContract's transaction capability. The route exists only when that
|
|
40
|
+
* capability is `"interactive"` — tested against the value itself, as
|
|
41
|
+
* `protocol.surface()` tests it — and is otherwise absent with core's own refusal
|
|
42
|
+
* of a plan. `undefined` when the route is there.
|
|
56
43
|
*/
|
|
57
44
|
export declare function transactionsRouteFailure(contracts: FrameworkContracts, protocol: ClientProtocolIdentity): OperationFailureResponse | undefined;
|
|
58
45
|
/**
|
|
@@ -69,10 +56,10 @@ type RouteCheck<Route> = ({
|
|
|
69
56
|
/**
|
|
70
57
|
* An operation route's checks before its body (decoder steps 2–4): the path
|
|
71
58
|
* (`A2000` unless `/_resources/<r>/<f>/<v>`, each segment decodable and none
|
|
72
|
-
* empty), the identity headers' presence (`A2000`), then
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
59
|
+
* empty), the identity headers' presence (`A2000`), then {@link
|
|
60
|
+
* resolveOperationRoute} — version, hash, Resource, operation — and the method
|
|
61
|
+
* (`A2012`, `Allow: POST`). One sequence for both route styles: `decodeOperation`
|
|
62
|
+
* reads the body only after it passes, `answerAbsent` never.
|
|
76
63
|
*/
|
|
77
64
|
export declare function checkOperationRoute(contracts: FrameworkContracts, read: ReadRequest): RouteCheck<{
|
|
78
65
|
readonly resource: string;
|
|
@@ -86,28 +73,26 @@ export declare function checkOperationRoute(contracts: FrameworkContracts, read:
|
|
|
86
73
|
*/
|
|
87
74
|
export declare function checkTransactionsRoute(contracts: FrameworkContracts, read: ReadRequest): RouteCheck<object>;
|
|
88
75
|
/**
|
|
89
|
-
* `protocol.answerAbsent(request)`
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* In order:
|
|
76
|
+
* `protocol.answerAbsent(request)` — the fallback a host that mounts one route per
|
|
77
|
+
* `protocol.surface()` entry mounts for every path it did not. Never a catch-all
|
|
78
|
+
* into framework handling: it reads no body, runs no pipeline, calls no Adapter,
|
|
79
|
+
* and takes only the compiled Contracts. In order:
|
|
94
80
|
*
|
|
95
81
|
* 1. a value that is not an `AvProtocolRequest` → `400 A2000`, minted id;
|
|
96
|
-
* 2. a path outside the protocol's underscore namespace
|
|
97
|
-
*
|
|
98
|
-
* framework's (the architect, 2026-10-05);
|
|
82
|
+
* 2. a path outside the protocol's underscore namespace → `undefined`: the host
|
|
83
|
+
* answers it itself — `/favicon.ico` is not the framework's;
|
|
99
84
|
* 3. `/_contract`: any method but `GET` → `405 A2012` with `Allow: GET`; no
|
|
100
|
-
* identity header is read
|
|
85
|
+
* identity header is read;
|
|
101
86
|
* 4. `/_transactions`, or else an operation route: exactly what the catch-all
|
|
102
|
-
* host's decoder answers before its body — path syntax and identity
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* 5. a route that EXISTS, reached with its own method — the host mounted
|
|
107
|
-
*
|
|
108
|
-
*
|
|
87
|
+
* host's decoder answers before its body — path syntax and identity presence
|
|
88
|
+
* (`A2000`), version (`A2006`), hash (`A2005`), Resource (`A2001`), operation
|
|
89
|
+
* or the `"none"` capability (`A2002`), method (`A2012`, `Allow: POST`) — each
|
|
90
|
+
* core's own envelope;
|
|
91
|
+
* 5. a route that EXISTS, reached with its own method — the host mounted only part
|
|
92
|
+
* of the surface — → `500 A3000`: a host wiring bug made visible, never a
|
|
93
|
+
* silent 404.
|
|
109
94
|
*
|
|
110
|
-
* Every framework answer echoes `Aventara-Request-Id
|
|
95
|
+
* Every framework answer echoes `Aventara-Request-Id`.
|
|
111
96
|
*/
|
|
112
97
|
export declare function answerAbsentRequest(contracts: FrameworkContracts, received: AvProtocolRequest): AvProtocolResponse | undefined;
|
|
113
98
|
export {};
|