@aventara/core 0.1.0-pilot.3 → 0.1.0-pilot.4
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/dist/adapters/adapter-discovery-diagnostic.d.ts +2 -0
- package/dist/adapters/adapter-field.d.ts +3 -26
- package/dist/adapters/adapter-identifier.d.ts +1 -11
- package/dist/adapters/adapter-model.d.ts +4 -0
- package/dist/adapters/adapter-operation-executor.interface.d.ts +5 -1
- package/dist/adapters/adapter-resource.d.ts +7 -28
- package/dist/adapters/adapter.interface.d.ts +21 -26
- package/dist/compiler/contract-compiler-diagnostic.d.ts +2 -0
- package/dist/compiler/contract.compiler.d.ts +11 -22
- package/dist/config/any-framework-config.d.ts +5 -26
- package/dist/config/config-diagnostic.d.ts +2 -0
- package/dist/config/config-layer.d.ts +6 -19
- package/dist/config/config.resolver.d.ts +6 -14
- package/dist/config/config.validator.d.ts +6 -3
- package/dist/config/define-fields.d.ts +6 -46
- package/dist/config/effective-fields.d.ts +6 -29
- package/dist/config/entrypoint.normalizer.d.ts +6 -18
- package/dist/config/framework-behaviors-config.d.ts +11 -10
- package/dist/config/framework-config.d.ts +15 -15
- package/dist/config/framework-fields-config.d.ts +14 -7
- package/dist/config/framework-restrictions-config.d.ts +41 -61
- package/dist/config/pipeline-config.d.ts +7 -17
- package/dist/contracts/capability.d.ts +13 -49
- package/dist/contracts/client-contract-structure.validator.d.ts +7 -53
- package/dist/contracts/contract-canonicalizer.d.ts +4 -6
- package/dist/contracts/contract-hash.d.ts +3 -2
- package/dist/contracts/contract-limits.d.ts +7 -1
- package/dist/contracts/contract-protocol.d.ts +7 -8
- package/dist/contracts/contract.d.ts +13 -4
- package/dist/contracts/enum-definition.d.ts +2 -0
- package/dist/contracts/field.d.ts +30 -167
- package/dist/contracts/identifier.d.ts +1 -16
- package/dist/contracts/lifecycle-trait.d.ts +4 -3
- package/dist/contracts/resource-operations.d.ts +2 -62
- package/dist/contracts/resource.d.ts +2 -0
- package/dist/contracts/scalar-value-type.d.ts +16 -47
- package/dist/contracts/scalar.d.ts +4 -3
- package/dist/contracts/transaction-capability.d.ts +2 -0
- package/dist/contracts/wire-scalar-format.d.ts +6 -21
- package/dist/framework/contract-view.d.ts +30 -113
- package/dist/framework/framework-construction.error.d.ts +6 -1
- package/dist/framework/framework.d.ts +31 -46
- package/dist/framework/framework.factory.d.ts +3 -17
- package/dist/framework/operation-facade.d.ts +3 -7
- package/dist/operations/operation-arguments.d.ts +52 -207
- package/dist/operations/operation-call.d.ts +13 -15
- package/dist/operations/operation-identity.d.ts +4 -2
- package/dist/operations/operation-result.d.ts +15 -61
- package/dist/operations/operation-validator-core.d.ts +5 -4
- package/dist/operations/operation-validator.d.ts +5 -7
- package/dist/operations/projection-scope.resolver.d.ts +0 -10
- package/dist/operations/validation-code.d.ts +5 -17
- package/dist/operations/write-scope.resolver.d.ts +3 -28
- package/dist/protocol/absent-route.responder.d.ts +23 -38
- package/dist/protocol/av-protocol.d.ts +2 -8
- package/dist/protocol/contract-document.responder.d.ts +5 -18
- package/dist/protocol/http-request.decoder.d.ts +12 -59
- package/dist/protocol/http-request.reader.d.ts +5 -5
- package/dist/protocol/http-response.encoder.d.ts +14 -20
- package/dist/protocol/http-status.table.d.ts +0 -8
- package/dist/protocol/index.d.ts +2 -7
- package/dist/protocol/operation-response.guard.d.ts +0 -15
- package/dist/protocol/protocol-failure.d.ts +8 -27
- package/dist/protocol/protocol-headers.d.ts +15 -42
- package/dist/protocol/protocol-surface.d.ts +0 -22
- package/dist/protocol/protocol.binder.d.ts +16 -26
- package/dist/protocol/protocol.handler.d.ts +15 -23
- package/dist/runtime/decimal.d.ts +5 -3
- package/dist/runtime/diagnostics-reporter.d.ts +14 -34
- package/dist/runtime/error-boundary.d.ts +6 -10
- package/dist/runtime/execution-options.d.ts +3 -7
- package/dist/runtime/field-behavior.d.ts +12 -19
- package/dist/runtime/framework-error.d.ts +2 -2
- package/dist/runtime/json-value.d.ts +7 -15
- package/dist/runtime/mutation-planner.d.ts +6 -12
- package/dist/runtime/operation-request.d.ts +7 -0
- package/dist/runtime/operation-response.d.ts +18 -23
- package/dist/runtime/operation-runtime.d.ts +12 -27
- package/dist/runtime/pipeline.d.ts +14 -29
- package/dist/runtime/referential-action.d.ts +1 -26
- package/dist/runtime/request-id.d.ts +3 -10
- package/dist/runtime/scalar-runtime.d.ts +12 -12
- package/dist/transactions/deferred-operation.d.ts +10 -21
- package/dist/transactions/operation-arguments-encoder.d.ts +1 -0
- package/dist/transactions/operation-fingerprint.d.ts +3 -1
- package/dist/transactions/transaction-envelope.d.ts +2 -4
- package/dist/transactions/transaction-integrity-error.d.ts +4 -15
- package/dist/transactions/transaction-plan-assembler.d.ts +1 -0
- package/dist/transactions/transaction-plan-validator.d.ts +3 -17
- package/dist/transactions/transaction-reference-resolver.d.ts +9 -12
- package/dist/transactions/transaction-reference.d.ts +23 -28
- package/dist/transactions/transaction-request.d.ts +3 -5
- package/dist/transactions/transaction-response.d.ts +5 -7
- package/dist/transactions/transaction-runtime.d.ts +3 -3
- package/dist/transactions/transaction-slot-path-error.d.ts +5 -15
- package/dist/transactions/transaction-slot-writer.d.ts +3 -13
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Contract } from "../contracts/contract.js";
|
|
2
2
|
import type { OperationIdentity } from "./operation-identity.js";
|
|
3
3
|
import type { ValidationIssue } from "./validation-code.js";
|
|
4
|
+
/** An operation's arguments as an object, before validation. */
|
|
4
5
|
export type SemanticOperationArguments = Readonly<Record<string, unknown>>;
|
|
5
6
|
type OperationValidationSuccess = {
|
|
6
7
|
readonly ok: true;
|
|
@@ -10,15 +11,15 @@ type OperationValidationFailure = {
|
|
|
10
11
|
readonly ok: false;
|
|
11
12
|
readonly issues: readonly ValidationIssue[];
|
|
12
13
|
};
|
|
14
|
+
/** The answer of {@link validateOperationArguments}: success, or the issues found. */
|
|
13
15
|
export type OperationValidationResult = OperationValidationSuccess | OperationValidationFailure;
|
|
14
16
|
export type OperationValidationOptions = {
|
|
15
17
|
readonly transactionReferences?: boolean;
|
|
16
18
|
};
|
|
17
19
|
/**
|
|
18
|
-
* The Framework Validation Layer's issue for a request naming a Resource the
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* it.
|
|
20
|
+
* The Framework Validation Layer's issue for a request naming a Resource the active
|
|
21
|
+
* Contract does not have (`V1005` at `["resource"]`, rolling up to `A2001`). The one
|
|
22
|
+
* spelling — the protocol's absence answers build theirs with it.
|
|
22
23
|
*/
|
|
23
24
|
export declare function resourceUnavailableIssue(resource: string): ValidationIssue;
|
|
24
25
|
export declare function validateOperationArguments(contract: Contract, request: OperationIdentity & {
|
|
@@ -5,10 +5,9 @@ import type { ValidationIssue } from "./validation-code.js";
|
|
|
5
5
|
export type { OperationValidationOptions, OperationValidationResult, SemanticOperationArguments, } from "./operation-validator-core.js";
|
|
6
6
|
/**
|
|
7
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
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* answered.
|
|
8
|
+
* active Contract does not advertise on a Resource it has (`V1006` at `["operation"]`,
|
|
9
|
+
* rolling up to `A2002`). The one spelling — the protocol's absence answers build
|
|
10
|
+
* theirs with it, so a caller cannot tell which layer answered.
|
|
12
11
|
*/
|
|
13
12
|
export declare function operationUnavailableIssue(request: {
|
|
14
13
|
readonly resource: string;
|
|
@@ -16,9 +15,8 @@ export declare function operationUnavailableIssue(request: {
|
|
|
16
15
|
readonly variant: string;
|
|
17
16
|
}): ValidationIssue;
|
|
18
17
|
/**
|
|
19
|
-
* Validates one standard operation's
|
|
20
|
-
*
|
|
21
|
-
* enforced before deeper grammar validation.
|
|
18
|
+
* Validates one standard operation's arguments against a Contract. Operation
|
|
19
|
+
* availability and request limits are checked before the arguments' grammar.
|
|
22
20
|
*/
|
|
23
21
|
export declare function validateOperationArguments(contract: Contract, request: OperationIdentity & {
|
|
24
22
|
readonly resource: string;
|
|
@@ -25,15 +25,5 @@ export declare function resolveProjectionScope(resource: Resource<Contract> | un
|
|
|
25
25
|
/**
|
|
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
|
-
*
|
|
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.
|
|
36
|
-
*
|
|
37
|
-
* Naming it is the point.
|
|
38
28
|
*/
|
|
39
29
|
export declare const NESTED_PROJECTION_SCOPE: ProjectionScope;
|
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
/**
|
|
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.
|
|
5
|
-
*/
|
|
1
|
+
/** The set of allocated Validation codes, as a runtime array. */
|
|
6
2
|
export declare const VALIDATION_CODES: readonly ["V1000", "V1001", "V1002", "V1003", "V1004", "V1005", "V1006", "V1007", "V1008", "V1009", "V1010", "V1011", "V1012", "V1013", "V1014", "V1015", "V1016", "V1017", "V1018", "V1019"];
|
|
3
|
+
/** A validation code (`V1000` and up), one per kind of argument problem. */
|
|
7
4
|
export type ValidationCode = (typeof VALIDATION_CODES)[number];
|
|
8
|
-
/**
|
|
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`.
|
|
12
|
-
*
|
|
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.
|
|
18
|
-
*/
|
|
5
|
+
/** The framework's message for each validation code. */
|
|
19
6
|
export declare const VALIDATION_CODE_MESSAGES: Readonly<Record<ValidationCode, string>>;
|
|
7
|
+
/** One validation problem: its code, message and the argument path it is at. */
|
|
20
8
|
export type ValidationIssue = {
|
|
21
9
|
readonly path?: readonly (string | number)[];
|
|
22
10
|
readonly code: ValidationCode;
|
|
23
11
|
readonly message: string;
|
|
24
12
|
};
|
|
25
|
-
/** Builds one
|
|
13
|
+
/** Builds one validation issue at its path. */
|
|
26
14
|
export declare function validationIssue(code: ValidationCode, path: readonly (string | number)[], message: string): ValidationIssue;
|
|
@@ -3,38 +3,13 @@ import type { Contract } from "../contracts/contract.js";
|
|
|
3
3
|
import type { Resource } from "../contracts/resource.js";
|
|
4
4
|
import type { OperationIdentity } from "./operation-identity.js";
|
|
5
5
|
/**
|
|
6
|
-
* Which write position one request's
|
|
7
|
-
* argument sits in, read off the variant the Resource advertises.
|
|
8
|
-
*
|
|
9
|
-
* The write mirror of `resolveProjectionScope`, and a separate function for the
|
|
10
|
-
* reason `resource-operations.ts` gives for `projectionScopeOf`/`writeScopeOf`
|
|
11
|
-
* being two: the axes are measured and consulted independently — the flat-bulk
|
|
12
|
-
* write scope covers four variants where the bulk-returning projection scope
|
|
13
|
-
* covers two — and a caller that needs one position should not be handed the other
|
|
14
|
-
* to discard.
|
|
15
|
-
*
|
|
16
|
-
* `"nested"` is the answer wherever nothing narrower is stated — an absent
|
|
17
|
-
* Resource, an unadvertised variant, `true`, or a descriptor that qualifies only
|
|
18
|
-
* its projection argument. Availability is **not** decided here: an unadvertised
|
|
19
|
-
* operation is refused by `operation-validator.ts` before the mutation walk runs,
|
|
20
|
-
* and answering `"nested"` for one keeps this function a write question rather than
|
|
21
|
-
* a second, weaker copy of the availability gate.
|
|
6
|
+
* Which write position one request's top-level `data` (or `create`/`update`)
|
|
7
|
+
* argument sits in, read off the variant the Resource advertises. `"nested"`
|
|
8
|
+
* wherever nothing narrower is stated.
|
|
22
9
|
*/
|
|
23
10
|
export declare function resolveWriteScope(resource: Resource<Contract> | undefined, request: OperationIdentity): WriteScope;
|
|
24
11
|
/**
|
|
25
12
|
* The position a write NESTED beneath an admitted relation directive sits in: the
|
|
26
13
|
* unrestricted one, at every depth, under every top-level scope.
|
|
27
|
-
*
|
|
28
|
-
* It is a constant and not a parameter the recursion threads, because there is no
|
|
29
|
-
* depth at which the answer differs. A relation write reached through `$create`,
|
|
30
|
-
* `$connectOrCreate.create`, `$update.data` or `$upsert`'s two branches lands in
|
|
31
|
-
* the unrestricted write input on both pilot engines, whatever the top-level
|
|
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
|
-
* *through* a relation the top-level scope already admitted — and past that point
|
|
35
|
-
* the full write surface returns.
|
|
36
|
-
*
|
|
37
|
-
* Naming it is the point, exactly as `NESTED_PROJECTION_SCOPE` names the same
|
|
38
|
-
* decision on the read axis.
|
|
39
14
|
*/
|
|
40
15
|
export declare const NESTED_WRITE_SCOPE: WriteScope;
|
|
@@ -6,11 +6,12 @@ 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
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* The absence answers: the checks a framework route makes before it reads a body, runs
|
|
10
|
+
* a pipeline or reaches an Adapter — the protocol version (`A2006`), the
|
|
11
|
+
* ClientContract hash (`A2005`), then whether the ClientContract advertises the route
|
|
12
|
+
* at all (`A2001`, `A2002`). Every envelope is the one the Framework Validation Layer
|
|
13
|
+
* answers for the same request, so a caller cannot tell which layer answered. Reads
|
|
14
|
+
* the compiled Contracts only.
|
|
14
15
|
*/
|
|
15
16
|
/** A route's three decoded segments, still untrusted strings. */
|
|
16
17
|
export type OperationRouteSegments = {
|
|
@@ -28,18 +29,18 @@ export type OperationRouteResolution = {
|
|
|
28
29
|
};
|
|
29
30
|
/**
|
|
30
31
|
* An operation route `/_resources/<resource>/<family>/<variant>` under one client
|
|
31
|
-
* protocol identity: version → hash → Resource → operation. A Resource key is
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* protocol identity: version → hash → Resource → operation. A Resource key is matched
|
|
33
|
+
* exactly and only as the ClientContract's own key; a family/variant pair only when it
|
|
34
|
+
* is a standard operation the Resource advertises, read through
|
|
34
35
|
* `isOperationVariantAvailable` alone.
|
|
35
36
|
*/
|
|
36
37
|
export declare function resolveOperationRoute(contracts: FrameworkContracts, protocol: ClientProtocolIdentity, route: OperationRouteSegments): OperationRouteResolution;
|
|
37
38
|
/**
|
|
38
|
-
* The `/_transactions` route under one client protocol identity: version → hash →
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* The `/_transactions` route under one client protocol identity: version → hash → the
|
|
40
|
+
* ClientContract's transaction capability. The route exists only when that capability
|
|
41
|
+
* is `"interactive"` — tested against the value itself, as `protocol.surface()` tests
|
|
42
|
+
* it — and is otherwise absent with core's own refusal of a plan. `undefined` when the
|
|
43
|
+
* route is there.
|
|
43
44
|
*/
|
|
44
45
|
export declare function transactionsRouteFailure(contracts: FrameworkContracts, protocol: ClientProtocolIdentity): OperationFailureResponse | undefined;
|
|
45
46
|
/**
|
|
@@ -54,12 +55,12 @@ type RouteCheck<Route> = ({
|
|
|
54
55
|
readonly response: AvProtocolResponse;
|
|
55
56
|
};
|
|
56
57
|
/**
|
|
57
|
-
* An operation route's checks before its body (decoder steps 2–4): the path
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
58
|
+
* An operation route's checks before its body (decoder steps 2–4): the path (`A2000`
|
|
59
|
+
* unless `/_resources/<r>/<f>/<v>`, each segment decodable and none empty), the
|
|
60
|
+
* identity headers' presence (`A2000`), then {@link resolveOperationRoute} — version,
|
|
61
|
+
* hash, Resource, operation — and the method (`A2012`, `Allow: POST`). One sequence
|
|
62
|
+
* for both route styles: `decodeOperation` reads the body only after it passes,
|
|
63
|
+
* `answerAbsent` never.
|
|
63
64
|
*/
|
|
64
65
|
export declare function checkOperationRoute(contracts: FrameworkContracts, read: ReadRequest): RouteCheck<{
|
|
65
66
|
readonly resource: string;
|
|
@@ -74,25 +75,9 @@ export declare function checkOperationRoute(contracts: FrameworkContracts, read:
|
|
|
74
75
|
export declare function checkTransactionsRoute(contracts: FrameworkContracts, read: ReadRequest): RouteCheck<object>;
|
|
75
76
|
/**
|
|
76
77
|
* `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
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* 1. a value that is not an `AvProtocolRequest` → `400 A2000`, minted id;
|
|
82
|
-
* 2. a path outside the protocol's underscore namespace → `undefined`: the host
|
|
83
|
-
* answers it itself — `/favicon.ico` is not the framework's;
|
|
84
|
-
* 3. `/_contract`: any method but `GET` → `405 A2012` with `Allow: GET`; no
|
|
85
|
-
* identity header is read;
|
|
86
|
-
* 4. `/_transactions`, or else an operation route: exactly what the catch-all
|
|
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.
|
|
94
|
-
*
|
|
95
|
-
* Every framework answer echoes `Aventara-Request-Id`.
|
|
78
|
+
* `protocol.surface()` entry mounts for every path it did not. Never a catch-all into
|
|
79
|
+
* framework handling: it reads no body, runs no pipeline, calls no Adapter, and takes
|
|
80
|
+
* only the compiled Contracts. In order:
|
|
96
81
|
*/
|
|
97
82
|
export declare function answerAbsentRequest(contracts: FrameworkContracts, received: AvProtocolRequest): AvProtocolResponse | undefined;
|
|
98
83
|
export {};
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
*
|
|
4
|
-
* language freezes a module namespace, and a bundler drops the members a consumer
|
|
5
|
-
* does not read.
|
|
6
|
-
*
|
|
7
|
-
* Re-exports only — no logic lives here. Every member is pinned, by name and by
|
|
8
|
-
* type, in `./index.test-d.ts`, whose exact `keyof` set fails when a member is
|
|
9
|
-
* added or removed without a row.
|
|
2
|
+
* The HTTP protocol: pure functions and data a host uses to serve a Framework.
|
|
3
|
+
* Start with `AvProtocol.bind(framework)`.
|
|
10
4
|
*/
|
|
11
5
|
export { normalizeEntrypoint } from "../config/entrypoint.normalizer.js";
|
|
12
6
|
export { scalarFormats } from "../contracts/wire-scalar-format.js";
|
|
@@ -2,9 +2,9 @@ import type { ClientContract } from "../contracts/contract.js";
|
|
|
2
2
|
import type { AvProtocolRequest } from "./http-request.decoder.js";
|
|
3
3
|
import type { AvProtocolResponse } from "./http-response.encoder.js";
|
|
4
4
|
/**
|
|
5
|
-
* The served ClientContract, written once per binding: its JCS-canonical bytes and
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* The served ClientContract, written once per binding: its JCS-canonical bytes and its
|
|
6
|
+
* entity tag, the quoted contract hash. The bytes include `protocol.hash`, although
|
|
7
|
+
* the hash's own input excludes it.
|
|
8
8
|
*/
|
|
9
9
|
export type ContractDocument = {
|
|
10
10
|
readonly body: string;
|
|
@@ -13,20 +13,7 @@ export type ContractDocument = {
|
|
|
13
13
|
/** The bound ClientContract as the document `_contract` serves. */
|
|
14
14
|
export declare function contractDocumentOf(client: ClientContract): ContractDocument;
|
|
15
15
|
/**
|
|
16
|
-
* `protocol.encodeContract(request)`: the `GET <entrypoint>/_contract` responder.
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* 1. a value that is not an `AvProtocolRequest` → `400 A2000` under a minted id
|
|
20
|
-
* (as the decoders answer it);
|
|
21
|
-
* 3. a path other than `/_contract` → `400 A2000` (path syntax this route cannot
|
|
22
|
-
* read, as a decoder answers one);
|
|
23
|
-
* 4. a method other than `GET` → `405 A2012` with `Allow: GET`;
|
|
24
|
-
* 5. `If-None-Match` matching the document's entity tag — RFC 9110 §13.1.2's weak
|
|
25
|
-
* comparison, over a comma-separated list, or `*` — → `304 Not Modified`, no
|
|
26
|
-
* body, still carrying `ETag` and `Cache-Control`; otherwise `200` with the
|
|
27
|
-
* canonical bytes, `ETag`, `Cache-Control: no-cache` and `Content-Type:
|
|
28
|
-
* application/json`.
|
|
29
|
-
*
|
|
30
|
-
* No identity header is required or read, and the body is never read.
|
|
16
|
+
* `protocol.encodeContract(request)`: the `GET <entrypoint>/_contract` responder. In
|
|
17
|
+
* order:
|
|
31
18
|
*/
|
|
32
19
|
export declare function encodeContractRequest(document: ContractDocument, received: AvProtocolRequest): AvProtocolResponse;
|
|
@@ -2,13 +2,7 @@ import type { FrameworkContracts } from "../compiler/contract.compiler.js";
|
|
|
2
2
|
import type { ClientOperationRequest } from "../runtime/operation-request.js";
|
|
3
3
|
import type { ClientTransactionRequest } from "../transactions/transaction-request.js";
|
|
4
4
|
import type { AvProtocolResponse } from "./http-response.encoder.js";
|
|
5
|
-
/**
|
|
6
|
-
* One HTTP request as a host hands it to the protocol: what the decoders read, and
|
|
7
|
-
* what each row of the fixture corpus carries as its `request`.
|
|
8
|
-
*
|
|
9
|
-
* Host-independent by construction: no host's request object, only the four facts
|
|
10
|
-
* every host can supply.
|
|
11
|
-
*/
|
|
5
|
+
/** One HTTP request as a host hands it to the protocol. */
|
|
12
6
|
export type AvProtocolRequest = {
|
|
13
7
|
/** The HTTP method as received. Anything but `POST` on a framework route is `A2012`. */
|
|
14
8
|
readonly method: string;
|
|
@@ -27,13 +21,6 @@ export type AvProtocolRequest = {
|
|
|
27
21
|
/**
|
|
28
22
|
* The body, in one of two explicitly named arms — the decoder never guesses which
|
|
29
23
|
* one it was given:
|
|
30
|
-
*
|
|
31
|
-
* - `raw`: the decoded body as received, bytes or text. The decoder enforces all
|
|
32
|
-
* of it: the size limit (`A2010`), the content type (`A2011`), JSON syntax and
|
|
33
|
-
* the body's shape (`A2000`). An absent body is zero bytes (`""`).
|
|
34
|
-
* - `parsed`: a value the host's own JSON parser already produced. Size, content
|
|
35
|
-
* type and JSON syntax were the host's to enforce before the decoder ran; the
|
|
36
|
-
* decoder still refuses a non-object shape (`A2000`).
|
|
37
24
|
*/
|
|
38
25
|
readonly body: {
|
|
39
26
|
readonly kind: "raw";
|
|
@@ -44,9 +31,9 @@ export type AvProtocolRequest = {
|
|
|
44
31
|
};
|
|
45
32
|
};
|
|
46
33
|
/**
|
|
47
|
-
* What a decoder answers: the request core executes, or the framework response
|
|
48
|
-
*
|
|
49
|
-
*
|
|
34
|
+
* What a decoder answers: the request core executes, or the framework response that
|
|
35
|
+
* answers the HTTP request instead — and, either way, the request id it runs or is
|
|
36
|
+
* answered under, which the host passes to the encoder:
|
|
50
37
|
* `protocol.encodeOperation(response, decoded.requestId)`.
|
|
51
38
|
*/
|
|
52
39
|
type Decoded<Request> = {
|
|
@@ -67,51 +54,17 @@ export type DecodedOperationRequest = Extract<DecodedOperation, {
|
|
|
67
54
|
/** What `protocol.decodeTransaction` answers. */
|
|
68
55
|
export type DecodedTransaction = Decoded<ClientTransactionRequest>;
|
|
69
56
|
/**
|
|
70
|
-
* `protocol.decodeOperation(request)` — one operation route's HTTP request as
|
|
71
|
-
* client-origin request `framework.execute` takes, or its answer.
|
|
72
|
-
*
|
|
73
|
-
* Total over ANY value: a value that is not an `AvProtocolRequest` at all — not an
|
|
74
|
-
* object, a missing or mistyped member, a member behind a getter or trap that
|
|
75
|
-
* throws — is malformed, `A2000` under a minted id, before anything else is read;
|
|
76
|
-
* nothing it carries is believed. Otherwise, in order, each step answering before
|
|
77
|
-
* the next runs:
|
|
78
|
-
*
|
|
79
|
-
* 1. the request id: `Aventara-Request-Id` adopted when it is 1–128 visible ASCII
|
|
80
|
-
* characters, otherwise minted by core's one helper — never a refusal;
|
|
81
|
-
* 2. the path: `/_resources/<resource>/<family>/<variant>`, each segment
|
|
82
|
-
* URL-decoded once and none empty, or `A2000`;
|
|
83
|
-
* 3. identity and absence, with no body read: a request missing either identity
|
|
84
|
-
* header is malformed; then the protocol version (`A2006`), the ClientContract
|
|
85
|
-
* hash (`A2005`), the Resource (`A2001`) and the operation (`A2002`), each
|
|
86
|
-
* core's own envelope — so an unadvertised triple never reaches `execute`, in
|
|
87
|
-
* either route style;
|
|
88
|
-
* 4. the method: anything but `POST` is `A2012`, carrying `Allow: POST` (RFC 9110
|
|
89
|
-
* §15.5.6);
|
|
90
|
-
* 5. the body. On the RAW arm the decoder enforces all of it: the content type
|
|
91
|
-
* must be `application/json` (`A2011`; parameters are not read), the decoded
|
|
92
|
-
* byte count must not exceed the ClientContract's `limits.maxRequestBytes`, and
|
|
93
|
-
* the bytes must be UTF-8 JSON (`A2000`). On the PARSED arm the host's own
|
|
94
|
-
* parser already read the bytes, so size, content type and JSON syntax were the
|
|
95
|
-
* HOST's to enforce — answering its parser's failures with `protocol.failure` —
|
|
96
|
-
* and the decoder checks none of them. Both arms then refuse a body that is not
|
|
97
|
-
* a JSON object — an array, a scalar, `null`, or none (`A2000`). One gap is the
|
|
98
|
-
* host's by construction: a parser that turns an absent body into `{}` makes
|
|
99
|
-
* absence indistinguishable from `{}`, which is valid.
|
|
100
|
-
*
|
|
101
|
-
* The request is client origin, always: nothing the caller sends spells
|
|
102
|
-
* application origin. `transport` carries `POST` and the request's headers. The
|
|
103
|
-
* body is the operation's arguments verbatim: the decoder never reads into it, so
|
|
104
|
-
* routing metadata in it is core's to refuse, and a parsed body reaches core as
|
|
105
|
-
* the same object.
|
|
57
|
+
* `protocol.decodeOperation(request)` — one operation route's HTTP request as
|
|
58
|
+
* the client-origin request `framework.execute` takes, or its answer.
|
|
106
59
|
*/
|
|
107
60
|
export declare function decodeOperationRequest(contracts: FrameworkContracts, received: AvProtocolRequest): DecodedOperation;
|
|
108
61
|
/**
|
|
109
|
-
* `protocol.decodeTransaction(request)` — the `/_transactions` request as the
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
62
|
+
* `protocol.decodeTransaction(request)` — the `/_transactions` request as the client-
|
|
63
|
+
* origin plan request `framework.executeTransaction` takes, or its answer. The same
|
|
64
|
+
* steps as {@link decodeOperationRequest}, with the path exactly `/_transactions` and
|
|
65
|
+
* its absence being a ClientContract without interactive transactions. Every step of
|
|
66
|
+
* the plan then runs under ClientContract rules: the plan is client origin and cannot
|
|
67
|
+
* say otherwise. The body is the plan verbatim.
|
|
115
68
|
*/
|
|
116
69
|
export declare function decodeTransactionRequest(contracts: FrameworkContracts, received: AvProtocolRequest): DecodedTransaction;
|
|
117
70
|
export {};
|
|
@@ -11,9 +11,9 @@ export declare const POST_ONLY: readonly string[];
|
|
|
11
11
|
/** The methods the contract route accepts: `GET`, only. */
|
|
12
12
|
export declare const GET_ONLY: readonly string[];
|
|
13
13
|
/**
|
|
14
|
-
* Whether a path lies in the protocol's namespace: underscore-prefixed paths
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Whether a path lies in the protocol's namespace: underscore-prefixed paths beneath
|
|
15
|
+
* the entrypoint are reserved for framework facilities; every other path is the
|
|
16
|
+
* host's.
|
|
17
17
|
*/
|
|
18
18
|
export declare function isProtocolPath(path: string): boolean;
|
|
19
19
|
/** A request the protocol could read, with what every route reads off it first. */
|
|
@@ -34,8 +34,8 @@ export type UnreadableRequest = {
|
|
|
34
34
|
readonly requestId: string;
|
|
35
35
|
};
|
|
36
36
|
/**
|
|
37
|
-
* The host's value read as a request, or — when it is not an `AvProtocolRequest`
|
|
38
|
-
*
|
|
37
|
+
* The host's value read as a request, or — when it is not an `AvProtocolRequest` at
|
|
38
|
+
* all — the `400 A2000` answering it, under a minted id.
|
|
39
39
|
*/
|
|
40
40
|
export declare function readRequest(received: unknown): ReadRequest | UnreadableRequest;
|
|
41
41
|
/**
|
|
@@ -10,37 +10,31 @@ export type AvProtocolResponse = {
|
|
|
10
10
|
/** `AvProtocol.httpStatus` of the envelope's code. */
|
|
11
11
|
readonly status: number;
|
|
12
12
|
/**
|
|
13
|
-
* The headers
|
|
14
|
-
*
|
|
13
|
+
* The headers to send, canonically spelled: `Content-Type: application/json`
|
|
14
|
+
* and the echoed `Aventara-Request-Id`.
|
|
15
15
|
*/
|
|
16
16
|
readonly headers: Readonly<Record<string, string>>;
|
|
17
17
|
/** The JSON text of the envelope, its data in wire forms. */
|
|
18
18
|
readonly body: string;
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
21
|
-
* Where an encoder hands the raw failure behind an `A3003` — the binding's
|
|
22
|
-
*
|
|
23
|
-
* carries it.
|
|
21
|
+
* Where an encoder hands the raw failure behind an `A3003` — the binding's diagnostics
|
|
22
|
+
* channel — with the plan step it blames, if any. The wire never carries it.
|
|
24
23
|
*/
|
|
25
24
|
export type UnencodableReport = (error: unknown, operation?: number) => void;
|
|
26
25
|
/**
|
|
27
|
-
* `protocol.encodeOperation(response, requestId)`: one operation's framework
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* Total: a result it cannot encode — and a response whose code is not allocated —
|
|
33
|
-
* answers `A3003` → 500 with the framework's own text, and none of the result
|
|
34
|
-
* reaches the body.
|
|
26
|
+
* `protocol.encodeOperation(response, requestId)`: one operation's framework response
|
|
27
|
+
* as the HTTP response a host writes. Status is the code's; `data` is wire-encoded;
|
|
28
|
+
* `requestId` is echoed as `Aventara-Request-Id` — pass the id the request ran under,
|
|
29
|
+
* which the decoder supplies.
|
|
35
30
|
*/
|
|
36
31
|
export declare function encodeOperationResponse(response: OperationResponse, requestId: string, report?: UnencodableReport): AvProtocolResponse;
|
|
37
32
|
/**
|
|
38
|
-
* `protocol.encodeTransaction(response, requestId)`: the same for a plan's
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* plan does.
|
|
33
|
+
* `protocol.encodeTransaction(response, requestId)`: the same for a plan's response. A
|
|
34
|
+
* committed plan is `200 A1009` — even when it created something — with each
|
|
35
|
+
* operation's data wire-encoded in plan order by the same walker as {@link
|
|
36
|
+
* encodeOperationResponse}; a rolled-back plan answers its failing operation's own
|
|
37
|
+
* status. A step whose result cannot be encoded answers `A3003` → 500 naming that step
|
|
38
|
+
* as `cause.operation`, as every internal failure inside a plan does.
|
|
45
39
|
*/
|
|
46
40
|
export declare function encodeTransactionResponse(response: TransactionResponse, requestId: string, report?: UnencodableReport): AvProtocolResponse;
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import type { OperationCode } from "../runtime/operation-response.js";
|
|
2
2
|
/**
|
|
3
3
|
* `AvProtocol.httpStatus` — the HTTP status each A-code carries, as passive data.
|
|
4
|
-
*
|
|
5
|
-
* So this one table serves both encoders — an operation's response and a plan's —
|
|
6
|
-
* and a rolled-back plan answers its failing operation's own status. The status is
|
|
7
|
-
* the coarse signal; the A-code is the exact one.
|
|
8
|
-
*
|
|
9
|
-
* Total by type: the literal `satisfies` the mapped type over `OperationCode`, so
|
|
10
|
-
* a code added to core does not compile until its status is written here. Passive:
|
|
11
|
-
* numbers only, frozen, emitted by value where a consumer needs it.
|
|
12
4
|
*/
|
|
13
5
|
export declare const httpStatus: {
|
|
14
6
|
readonly [C in OperationCode]: number;
|
package/dist/protocol/index.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@aventara/core/protocol` — the HTTP protocol, as passive data and pure
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* The direction is one-way: this entry may import core's internals, and no module
|
|
6
|
-
* of core's execution side imports anything under `protocol/`
|
|
7
|
-
* (`protocol-direction.spec.ts`). The main `@aventara/core` entry exports no name
|
|
8
|
-
* from here.
|
|
2
|
+
* `@aventara/core/protocol` — the HTTP protocol, as passive data and pure functions
|
|
3
|
+
* over core. It mounts nothing and imports no HTTP library.
|
|
9
4
|
*/
|
|
10
5
|
export * as AvProtocol from "./av-protocol.js";
|
|
11
6
|
export type { AvProtocolRequest } from "./http-request.decoder.js";
|
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
import { type OperationResponse } from "../runtime/operation-response.js";
|
|
2
2
|
/**
|
|
3
3
|
* The HTTP status plays no part — a code is read even at an unexpected status.
|
|
4
|
-
*
|
|
5
|
-
* `value` is the body as parsed JSON, or `undefined` when there was no body or it
|
|
6
|
-
* was not JSON (neither is an envelope). An envelope here is:
|
|
7
|
-
*
|
|
8
|
-
* - an object (not an array) with an own `data` member and an allocated `code`;
|
|
9
|
-
* - for an A1xxx code, a `cause` of exactly `null`, and `data` of `null` when the
|
|
10
|
-
* code is `A1001`;
|
|
11
|
-
* - for every other code, `data` of `null` and a cause: an object whose `message`
|
|
12
|
-
* is a string, whose `issues`, if present, is a list of objects each with an
|
|
13
|
-
* allocated V-code, a string `message` and, if present, a `path` of strings and
|
|
14
|
-
* integers, and whose `operation`, if present, is a non-negative integer.
|
|
15
|
-
*
|
|
16
|
-
* The generated client's own check (`envelopeOf` in its emitted transport) is held
|
|
17
|
-
* to agree with this one on every row of the fixture corpus's family 11, so the
|
|
18
|
-
* two cannot drift apart silently.
|
|
19
4
|
*/
|
|
20
5
|
export declare function isOperationResponse(value: unknown): value is OperationResponse;
|
|
@@ -1,40 +1,21 @@
|
|
|
1
1
|
import { type AvProtocolResponse } from "./http-response.encoder.js";
|
|
2
2
|
import type { IdentityHeaderName } from "./protocol-headers.js";
|
|
3
3
|
/**
|
|
4
|
-
* The four transport codes: failures of the HTTP request itself, which the
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The four transport codes: failures of the HTTP request itself, which the protocol
|
|
5
|
+
* answers before any operation exists, so no execution path produces them. Module type
|
|
6
|
+
* — not an entry export.
|
|
7
7
|
*/
|
|
8
8
|
export type TransportFailureCode = "A2000" | "A2010" | "A2011" | "A2012";
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* request sent — so a developer calling the API by hand learns what to add.
|
|
10
|
+
* The `400 A2000` answering a request that did not send an identity header: its
|
|
11
|
+
* message names the missing header or headers and echoes nothing the request sent.
|
|
13
12
|
*/
|
|
14
13
|
export declare function identityHeadersMissing(missing: readonly IdentityHeaderName[], requestId: string): AvProtocolResponse;
|
|
15
14
|
/**
|
|
16
15
|
* `protocol.failure(code, requestId?)` / `protocol.failure("A2012", requestId,
|
|
17
|
-
* allow)`: a transport code as the complete framework response — the envelope `{
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* The decoders produce their transport failures through it. A host that parses the
|
|
22
|
-
* body itself answers its own parser's failures with it — `A2000` for text that is
|
|
23
|
-
* not JSON, `A2010` for a body over the limit, `A2011` for another content type.
|
|
24
|
-
*
|
|
25
|
-
* `requestId` is echoed as `Aventara-Request-Id`: pass the id the decoder gave the
|
|
26
|
-
* request when there is one. When there is none — or it is empty — core mints one
|
|
27
|
-
* through its one helper, so a failure is never refused or left uncorrelated.
|
|
28
|
-
*
|
|
29
|
-
* `allow` belongs to `A2012`, and `A2012` requires it: every 405 carries the
|
|
30
|
-
* `Allow` header naming the methods its route DOES accept, joined with `", "` —
|
|
31
|
-
* `[]` is RFC 9110's "no method", still a header. `failure` knows no route, so the
|
|
32
|
-
* caller names the methods; the decoders pass `["POST"]`.
|
|
33
|
-
*
|
|
34
|
-
* A code outside the four, `A2012` without `allow`, `allow` with any other code,
|
|
35
|
-
* or a method that is not an RFC 9110 token is a programming error that the type
|
|
36
|
-
* already refuses; an untyped caller gets a `TypeError`, and no envelope or header
|
|
37
|
-
* is invented for it.
|
|
16
|
+
* allow)`: a transport code as the complete framework response — the envelope `{ data:
|
|
17
|
+
* null, code, cause: { message } }`, encoded exactly as `protocol.encodeOperation`
|
|
18
|
+
* encodes it, at the code's status.
|
|
38
19
|
*/
|
|
39
20
|
export declare function transportFailure(code: "A2012", requestId: string | undefined, allow: readonly string[]): AvProtocolResponse;
|
|
40
21
|
export declare function transportFailure(code: Exclude<TransportFailureCode, "A2012">, requestId?: string): AvProtocolResponse;
|