@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
|
@@ -1,44 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The wire prefix of every framework-owned header (§12.4: "the working wire
|
|
3
|
-
* prefix for v1", to be frozen before the first externally published release).
|
|
4
|
-
* One place, so that freeze is a one-line change, and every name below is
|
|
5
|
-
* spelled from it rather than restating it.
|
|
6
|
-
*/
|
|
7
1
|
const WIRE_PREFIX = "Aventara";
|
|
8
|
-
/**
|
|
9
|
-
* `AvProtocol.headers` — the header names the protocol owns, as passive data.
|
|
10
|
-
*
|
|
11
|
-
* - `protocolVersion`, `contractHash`: the two identity headers every
|
|
12
|
-
* generated-client resource and transaction request sends (§12.4); the
|
|
13
|
-
* `_contract` request needs neither.
|
|
14
|
-
* - `requestId`: the correlation header (Q13). A valid one is adopted as the
|
|
15
|
-
* request's id, an invalid one ignored, and every framework-produced
|
|
16
|
-
* response echoes it.
|
|
17
|
-
*
|
|
18
|
-
* Spelled as the canonical wire text. HTTP header names are case-insensitive
|
|
19
|
-
* (§12.4), so a reader matches them without regard to case; these spellings are
|
|
20
|
-
* what the framework and the generated client SEND.
|
|
21
|
-
*
|
|
22
|
-
* Passive data (P5): strings only, frozen, so a consumer — the client generator
|
|
23
|
-
* emits it by value into generated source — can neither mutate it nor receive
|
|
24
|
-
* anything `JSON.stringify` would drop or reshape.
|
|
25
|
-
*/
|
|
26
2
|
export const headers = Object.freeze({
|
|
27
3
|
protocolVersion: `${WIRE_PREFIX}-Protocol-Version`,
|
|
28
4
|
contractHash: `${WIRE_PREFIX}-Contract-Hash`,
|
|
29
5
|
requestId: `${WIRE_PREFIX}-Request-Id`,
|
|
30
6
|
});
|
|
31
|
-
/**
|
|
32
|
-
* The request's headers as one spelling (Q7, accepted 2026-10-04): names
|
|
33
|
-
* lower-cased (they are case-insensitive, §12.4), a repeated header's values —
|
|
34
|
-
* a list, or one name received in several casings — joined with `", "` in the
|
|
35
|
-
* order received (RFC 9110 §5.3), and an `undefined` entry or an empty list
|
|
36
|
-
* dropped as absent. Values are otherwise as received. This is what a client
|
|
37
|
-
* request's `transport.headers` carries to the developer's pipelines, and what
|
|
38
|
-
* every header read below reads.
|
|
39
|
-
*
|
|
40
|
-
* Built with `Object.fromEntries`, so a header named `__proto__` stays data.
|
|
41
|
-
*/
|
|
42
7
|
export function normalizeHeaders(received) {
|
|
43
8
|
const merged = new Map();
|
|
44
9
|
for (const [name, value] of Object.entries(received)) {
|
|
@@ -51,32 +16,13 @@ export function normalizeHeaders(received) {
|
|
|
51
16
|
}
|
|
52
17
|
return Object.fromEntries(Array.from(merged, ([name, values]) => [name, values.join(", ")]));
|
|
53
18
|
}
|
|
54
|
-
/**
|
|
55
|
-
* One header's value as the framework reads it, from {@link normalizeHeaders}'
|
|
56
|
-
* output: surrounding spaces and tabs are not part of a field value (RFC 9110
|
|
57
|
-
* §5.5), so they are removed. `undefined` when the header is absent.
|
|
58
|
-
*/
|
|
59
19
|
export function headerValue(normalized, name) {
|
|
60
20
|
const key = name.toLowerCase();
|
|
61
21
|
return Object.hasOwn(normalized, key)
|
|
62
22
|
? normalized[key]?.replace(/^[ \t]+|[ \t]+$/g, "")
|
|
63
23
|
: undefined;
|
|
64
24
|
}
|
|
65
|
-
/** A protocol version as the header spells it: a decimal integer, no sign, no leading zero. */
|
|
66
25
|
const PROTOCOL_VERSION_TEXT = /^(?:0|[1-9]\d*)$/;
|
|
67
|
-
/**
|
|
68
|
-
* The identity headers (§12.4) as the `ClientProtocolIdentity` core checks, or
|
|
69
|
-
* `undefined` when either is ABSENT — a request without them is malformed
|
|
70
|
-
* (`A2000`; the architect, 2026-10-05): it does not say which protocol and
|
|
71
|
-
* ClientContract it speaks, so there is nothing to compare.
|
|
72
|
-
*
|
|
73
|
-
* Present values are read, never judged: whether they match is the Framework
|
|
74
|
-
* Validation Layer's call (cross-phase invariant 13), made by core's one
|
|
75
|
-
* stale-client check. A present version that is not a decimal integer (no
|
|
76
|
-
* sign, no leading zero) reads as `NaN`, so it cannot match (`A2006`); a
|
|
77
|
-
* present hash is passed as received (`A2005` unless it is the current one).
|
|
78
|
-
* Present includes empty: a header sent with no value was still sent.
|
|
79
|
-
*/
|
|
80
26
|
export function protocolIdentityOf(normalized) {
|
|
81
27
|
const version = headerValue(normalized, headers.protocolVersion);
|
|
82
28
|
const hash = headerValue(normalized, headers.contractHash);
|
|
@@ -88,14 +34,10 @@ export function protocolIdentityOf(normalized) {
|
|
|
88
34
|
hash,
|
|
89
35
|
};
|
|
90
36
|
}
|
|
91
|
-
|
|
37
|
+
export function missingIdentityHeaders(normalized) {
|
|
38
|
+
return [headers.protocolVersion, headers.contractHash].filter((name) => headerValue(normalized, name) === undefined);
|
|
39
|
+
}
|
|
92
40
|
const ADOPTABLE_REQUEST_ID = /^[\x21-\x7e]{1,128}$/;
|
|
93
|
-
/**
|
|
94
|
-
* Q13 (the architect's, 2026-10-04): the request's `Aventara-Request-Id` when
|
|
95
|
-
* it is 1–128 characters of visible ASCII; otherwise `undefined` — the header
|
|
96
|
-
* is ignored, never refused, and core mints an id instead. A repeated header
|
|
97
|
-
* joins with `", "`, which holds a space, so it is never adopted.
|
|
98
|
-
*/
|
|
99
41
|
export function adoptedRequestId(normalized) {
|
|
100
42
|
const value = headerValue(normalized, headers.requestId);
|
|
101
43
|
return value !== undefined && ADOPTABLE_REQUEST_ID.test(value)
|
|
@@ -2,20 +2,17 @@ import type { ClientContract } from "../contracts/contract.js";
|
|
|
2
2
|
import { type OperationIdentity } from "../operations/operation-identity.js";
|
|
3
3
|
/**
|
|
4
4
|
* One route of the protocol surface: a route a host mounts for the bound
|
|
5
|
-
* ClientContract, tagged by `kind
|
|
6
|
-
* `path` is RELATIVE to the configured entrypoint, in the same space as
|
|
7
|
-
* `AvProtocolRequest.path`; the canonical `framework.entrypoint` (`""` or
|
|
8
|
-
* `/seg(/seg)*`, R4) joins it without a doubled slash.
|
|
5
|
+
* ClientContract, tagged by `kind`.
|
|
9
6
|
*
|
|
10
|
-
* - `operation`: a `(resource, family, variant)` the ClientContract
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - `contract`: `GET /_contract`
|
|
17
|
-
* - `transactions`: `POST /_transactions`
|
|
18
|
-
*
|
|
7
|
+
* - `operation`: a `(resource, family, variant)` the ClientContract advertises.
|
|
8
|
+
* `method` is always `POST` — every Resource operation is, reads included.
|
|
9
|
+
* `path` is `/_resources/<resource>/<family>/<variant>`, each segment
|
|
10
|
+
* percent-encoded exactly as the generated client sends it, so it decodes back
|
|
11
|
+
* to the exact registry key. Family and variant are one standard operation
|
|
12
|
+
* identity.
|
|
13
|
+
* - `contract`: `GET /_contract` — always present.
|
|
14
|
+
* - `transactions`: `POST /_transactions` — present exactly when the
|
|
15
|
+
* ClientContract's `transactions` is `"interactive"`.
|
|
19
16
|
*/
|
|
20
17
|
export type SurfaceRoute = ({
|
|
21
18
|
readonly kind: "operation";
|
|
@@ -32,22 +29,21 @@ export type SurfaceRoute = ({
|
|
|
32
29
|
readonly path: "/_transactions";
|
|
33
30
|
};
|
|
34
31
|
/**
|
|
35
|
-
* The route list of one ClientContract
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* `
|
|
32
|
+
* The route list of one ClientContract: every route a host mounts, from one list,
|
|
33
|
+
* deep-frozen — exactly the advertised operation triples in the Contract's own key
|
|
34
|
+
* order, then `GET /_contract`, then `POST /_transactions` when, and only when,
|
|
35
|
+
* `transactions === "interactive"`.
|
|
39
36
|
*
|
|
40
|
-
* Derived from the ClientContract alone — never configuration, the adapter
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* nothing.
|
|
37
|
+
* Derived from the ClientContract alone — never configuration, the adapter model,
|
|
38
|
+
* or another layer's Contract — so a client-hidden resource has no route, and a
|
|
39
|
+
* resource whose every operation was restricted away keeps its `operations: {}`
|
|
40
|
+
* and contributes nothing. Availability is read ONLY through
|
|
41
|
+
* `isOperationVariantAvailable`, so a scope-qualified leaf is a route exactly as
|
|
42
|
+
* `true` is, and the next widening of `OperationAvailability` reaches this reader
|
|
43
|
+
* with every other. A family or variant key outside the standard operation set is
|
|
44
|
+
* not a route: segments go through `parseOperationIdentity`, the same decoder that
|
|
45
|
+
* reads a request's. The transaction route is tested against `"interactive"`
|
|
46
|
+
* itself, never as "not `none`", so a capability value this reader does not know
|
|
47
|
+
* mounts nothing.
|
|
52
48
|
*/
|
|
53
49
|
export declare function surfaceOf(client: ClientContract): readonly SurfaceRoute[];
|
|
@@ -2,25 +2,6 @@ import { lookupOwn, lookupResource } from "../contracts/contract-lookup.js";
|
|
|
2
2
|
import { isOperationVariantAvailable } from "../contracts/resource-operations.js";
|
|
3
3
|
import { parseOperationIdentity, } from "../operations/operation-identity.js";
|
|
4
4
|
const ownKeys = (record) => record === undefined ? [] : Object.keys(record);
|
|
5
|
-
/**
|
|
6
|
-
* The route list of one ClientContract (ADR 0007 DA-13): every route a host
|
|
7
|
-
* mounts, from one list, deep-frozen — exactly the advertised operation
|
|
8
|
-
* triples in the Contract's own key order, then `GET /_contract`, then
|
|
9
|
-
* `POST /_transactions` when, and only when, `transactions === "interactive"`.
|
|
10
|
-
*
|
|
11
|
-
* Derived from the ClientContract alone — never configuration, the adapter
|
|
12
|
-
* model, or another layer's Contract — so a client-hidden resource has no
|
|
13
|
-
* route (M7), and a resource whose every operation was restricted away keeps
|
|
14
|
-
* its `operations: {}` and contributes nothing (M6). Availability is read
|
|
15
|
-
* ONLY through `isOperationVariantAvailable` (§4), so a scope-qualified leaf
|
|
16
|
-
* is a route exactly as `true` is, and the next widening of
|
|
17
|
-
* `OperationAvailability` reaches this reader with every other. A family or
|
|
18
|
-
* variant key outside the standard operation set is not a route: segments go
|
|
19
|
-
* through `parseOperationIdentity`, the same decoder that reads a request's.
|
|
20
|
-
* The transaction route is tested against `"interactive"` itself, never as
|
|
21
|
-
* "not `none`", so a capability value this reader does not know mounts
|
|
22
|
-
* nothing.
|
|
23
|
-
*/
|
|
24
5
|
export function surfaceOf(client) {
|
|
25
6
|
const routes = [];
|
|
26
7
|
for (const resourceName of ownKeys(client.resources)) {
|
|
@@ -6,38 +6,32 @@ import { type AvProtocolResponse } from "./http-response.encoder.js";
|
|
|
6
6
|
import { transportFailure } from "./protocol-failure.js";
|
|
7
7
|
import { type SurfaceRoute } from "./protocol-surface.js";
|
|
8
8
|
/**
|
|
9
|
-
* The protocol bound to ONE Framework instance — what `AvProtocol.bind`
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* entrypoint or a limit, because the binding already read them.
|
|
13
|
-
*
|
|
14
|
-
* Grows one member per slice (§7); the exact set is pinned in
|
|
15
|
-
* `index.test-d.ts`.
|
|
9
|
+
* The protocol bound to ONE Framework instance — what `AvProtocol.bind` returns. A
|
|
10
|
+
* host binds once, at startup, and calls these members per request; none takes a
|
|
11
|
+
* Contract, an entrypoint or a limit, because the binding already read them.
|
|
16
12
|
*/
|
|
17
13
|
export type AvProtocolBinding = {
|
|
18
14
|
/**
|
|
19
|
-
* Every route a host mounts for the bound ClientContract, from one list,
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* `
|
|
24
|
-
* `
|
|
25
|
-
*
|
|
26
|
-
* every call answers the same deep-frozen list, which is passive data a
|
|
27
|
-
* host may serialize.
|
|
15
|
+
* Every route a host mounts for the bound ClientContract, from one list, each
|
|
16
|
+
* tagged by `kind`: one `POST` `operation` route per `(resource, family, variant)`
|
|
17
|
+
* it advertises — nothing it does not — then the `contract` route `GET /_contract`
|
|
18
|
+
* (always), then the `transactions` route `POST /_transactions` exactly when its
|
|
19
|
+
* `transactions` is `"interactive"`. Each path is relative to
|
|
20
|
+
* `framework.entrypoint`. Read once at bind time: every call answers the same
|
|
21
|
+
* deep-frozen list, which is passive data a host may serialize.
|
|
28
22
|
*
|
|
29
|
-
* A host that mounts one route per entry still needs a fallback for the
|
|
30
|
-
*
|
|
31
|
-
*
|
|
23
|
+
* A host that mounts one route per entry still needs a fallback for the paths it
|
|
24
|
+
* did not mount: that is the absence responder's, not a catch-all into framework
|
|
25
|
+
* handling.
|
|
32
26
|
*/
|
|
33
27
|
readonly surface: () => readonly SurfaceRoute[];
|
|
34
28
|
/**
|
|
35
29
|
* An operation route's HTTP request → the client-origin request
|
|
36
|
-
* `framework.execute` takes, or the framework response that answers it
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
30
|
+
* `framework.execute` takes, or the framework response that answers it instead,
|
|
31
|
+
* with the request id either way. Answers absence for an unadvertised triple
|
|
32
|
+
* without executing it, so a catch-all host is safe. Raw body: size, content type,
|
|
33
|
+
* JSON and shape enforced; parsed body: shape only — the rest was the host's
|
|
34
|
+
* parser's.
|
|
41
35
|
*/
|
|
42
36
|
readonly decodeOperation: (request: AvProtocolRequest) => DecodedOperation;
|
|
43
37
|
/**
|
|
@@ -47,77 +41,70 @@ export type AvProtocolBinding = {
|
|
|
47
41
|
*/
|
|
48
42
|
readonly decodeTransaction: (request: AvProtocolRequest) => DecodedTransaction;
|
|
49
43
|
/**
|
|
50
|
-
* One operation's framework response — what `framework.execute` answered —
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* it the answer is the same and nothing is reported.
|
|
44
|
+
* One operation's framework response — what `framework.execute` answered — as the
|
|
45
|
+
* HTTP response a host writes: the code's status, `data` in wire forms,
|
|
46
|
+
* `Aventara-Request-Id` echoed. A result with no wire form answers `A3003` → 500.
|
|
47
|
+
* A diagnostic of one operation names it (`resource`, `family`, `variant`), so the
|
|
48
|
+
* `A3003` reaches the diagnostics sink only when the host passes `decoded` —
|
|
49
|
+
* `decodeOperation`'s success value — as `handleOperation` does; without it the
|
|
50
|
+
* answer is the same and nothing is reported.
|
|
58
51
|
*/
|
|
59
52
|
readonly encodeOperation: (response: OperationResponse, requestId: string, decoded?: DecodedOperationRequest) => AvProtocolResponse;
|
|
60
53
|
/**
|
|
61
|
-
* The same for `/_transactions` — what `framework.executeTransaction`
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* the
|
|
65
|
-
* scope, this `requestId`, the step it blames as `operation` — with the
|
|
66
|
-
* value that had no wire form (or what its getter threw) as `error`.
|
|
54
|
+
* The same for `/_transactions` — what `framework.executeTransaction` answered. An
|
|
55
|
+
* `A3003` is reported to the Framework's diagnostics sink as a `"transaction"`
|
|
56
|
+
* diagnostic — client scope, this `requestId`, the step it blames as `operation` —
|
|
57
|
+
* with the value that had no wire form (or what its getter threw) as `error`.
|
|
67
58
|
*/
|
|
68
59
|
readonly encodeTransaction: (response: TransactionResponse, requestId: string) => AvProtocolResponse;
|
|
69
60
|
/**
|
|
70
61
|
* A transport code — `A2000`, `A2010`, `A2011` or `A2012` — as the complete
|
|
71
|
-
* framework response, with framework-authored text (ruled 2026-10-05). For a
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* `Allow` (the director, 2026-10-05).
|
|
62
|
+
* framework response, with framework-authored text (ruled 2026-10-05). For a host
|
|
63
|
+
* that parses the body itself and must answer its parser's failure. `A2012`
|
|
64
|
+
* requires the methods its route allows, so every 405 carries `Allow`.
|
|
75
65
|
*/
|
|
76
66
|
readonly failure: typeof transportFailure;
|
|
77
67
|
/**
|
|
78
|
-
* The shortcut
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* rejects.
|
|
68
|
+
* The shortcut: `decodeOperation` → `framework.execute` → `encodeOperation`,
|
|
69
|
+
* resolving the response the host writes for an operation route. A decode failure
|
|
70
|
+
* is answered without executing; an `A3003` is reported to the diagnostics sink
|
|
71
|
+
* with the operation's identity and request id. Total over any value an untyped
|
|
72
|
+
* host hands it: one that is not an `AvProtocolRequest` answers `400 A2000`; it
|
|
73
|
+
* never rejects.
|
|
85
74
|
*/
|
|
86
75
|
readonly handleOperation: (request: AvProtocolRequest) => Promise<AvProtocolResponse>;
|
|
87
76
|
/**
|
|
88
77
|
* The same for `/_transactions`: `decodeTransaction` →
|
|
89
|
-
* `framework.executeTransaction` → `encodeTransaction`. Every step runs
|
|
90
|
-
*
|
|
91
|
-
*
|
|
78
|
+
* `framework.executeTransaction` → `encodeTransaction`. Every step runs under
|
|
79
|
+
* ClientContract rules; a committed plan is `200 A1009`, a rolled-back one its
|
|
80
|
+
* failing step's own status.
|
|
92
81
|
*/
|
|
93
82
|
readonly handleTransaction: (request: AvProtocolRequest) => Promise<AvProtocolResponse>;
|
|
94
83
|
/**
|
|
95
|
-
* The `GET /_contract` responder
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
84
|
+
* The `GET /_contract` responder: the bound ClientContract's JCS-canonical bytes,
|
|
85
|
+
* `ETag` its quoted hash, `Cache-Control: no-cache`, and `304` with no body when
|
|
86
|
+
* `If-None-Match` matches (weak comparison, a list, `*`). Requires no identity
|
|
87
|
+
* header; any other method is `405 A2012` with `Allow: GET`. The bytes are written
|
|
88
|
+
* once, at bind time.
|
|
100
89
|
*/
|
|
101
90
|
readonly encodeContract: (request: AvProtocolRequest) => AvProtocolResponse;
|
|
102
91
|
/**
|
|
103
|
-
* The absence responder
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* that
|
|
109
|
-
*
|
|
110
|
-
* protocol's namespace, which the host answers itself (the architect,
|
|
111
|
-
* 2026-10-05).
|
|
92
|
+
* The absence responder: the fallback a host mounts for every path it did not
|
|
93
|
+
* mount from `surface()` — never a catch-all into framework handling (it reads no
|
|
94
|
+
* body, runs no pipeline, calls no Adapter). Answers what the catch-all decoder
|
|
95
|
+
* answers before a body — `A2000`, `A2006`, `A2005`, `A2001`, `A2002`, `A2012`
|
|
96
|
+
* with `Allow` — byte for byte; a route that exists reached with its own method as
|
|
97
|
+
* `500 A3000` (a host that mounted only part of the surface); and `undefined` for
|
|
98
|
+
* a path outside the protocol's namespace, which the host answers itself.
|
|
112
99
|
*/
|
|
113
100
|
readonly answerAbsent: (request: AvProtocolRequest) => AvProtocolResponse | undefined;
|
|
114
101
|
};
|
|
115
102
|
/**
|
|
116
|
-
* `AvProtocol.bind(framework)`: reads the instance's compiled ClientContract
|
|
117
|
-
*
|
|
103
|
+
* `AvProtocol.bind(framework)`: reads the instance's compiled ClientContract once
|
|
104
|
+
* and returns the bound members, frozen.
|
|
118
105
|
*
|
|
119
|
-
* It validates nothing construction did not: `createFramework` already refused
|
|
120
|
-
*
|
|
121
|
-
*
|
|
106
|
+
* It validates nothing construction did not: `createFramework` already refused a
|
|
107
|
+
* bad entrypoint and compiled the ClientContract this reads, so binding cannot
|
|
108
|
+
* fail.
|
|
122
109
|
*/
|
|
123
110
|
export declare function bind(framework: Framework): AvProtocolBinding;
|
|
@@ -6,14 +6,6 @@ import { encodeOperationResponse, encodeTransactionResponse, } from "./http-resp
|
|
|
6
6
|
import { handleOperationRequest, handleTransactionRequest, operationUnencodableReport, planUnencodableReport, } from "./protocol.handler.js";
|
|
7
7
|
import { transportFailure } from "./protocol-failure.js";
|
|
8
8
|
import { surfaceOf } from "./protocol-surface.js";
|
|
9
|
-
/**
|
|
10
|
-
* `AvProtocol.bind(framework)`: reads the instance's compiled ClientContract
|
|
11
|
-
* once and returns the bound members, frozen.
|
|
12
|
-
*
|
|
13
|
-
* It validates nothing construction did not: `createFramework` already refused
|
|
14
|
-
* a bad entrypoint (R4) and compiled the ClientContract this reads, so binding
|
|
15
|
-
* cannot fail.
|
|
16
|
-
*/
|
|
17
9
|
export function bind(framework) {
|
|
18
10
|
const { contracts } = framework;
|
|
19
11
|
const surface = surfaceOf(contracts.client);
|
|
@@ -16,48 +16,44 @@ export type HandlerContext = {
|
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
18
|
* Where a plan's `A3003` goes: the Framework's diagnostics sink, as a
|
|
19
|
-
* `"transaction"` diagnostic — client scope
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* `protocol.encodeTransaction` and `protocol.handleTransaction`.
|
|
19
|
+
* `"transaction"` diagnostic — client scope, the request id the plan ran under,
|
|
20
|
+
* and the step the encoder blames as `operation` when it blames one. One spelling
|
|
21
|
+
* for both `protocol.encodeTransaction` and `protocol.handleTransaction`.
|
|
23
22
|
*/
|
|
24
23
|
export declare function planUnencodableReport(sink: FrameworkDiagnosticsSink | undefined, requestId: string): UnencodableReport;
|
|
25
24
|
/**
|
|
26
25
|
* Where one operation's `A3003` goes: the Framework's diagnostics sink, as an
|
|
27
|
-
* `"operation"` diagnostic carrying the decoded request's identity and id —
|
|
28
|
-
*
|
|
29
|
-
* `protocol.handleOperation` and for `protocol.encodeOperation` given the
|
|
30
|
-
*
|
|
26
|
+
* `"operation"` diagnostic carrying the decoded request's identity and id — the
|
|
27
|
+
* shape the public `OperationDiagnostic` already has. One spelling for
|
|
28
|
+
* `protocol.handleOperation` and for `protocol.encodeOperation` given the decoded
|
|
29
|
+
* request.
|
|
31
30
|
*/
|
|
32
31
|
export declare function operationUnencodableReport(sink: FrameworkDiagnosticsSink | undefined, request: ClientOperationRequest): UnencodableReport;
|
|
33
32
|
/**
|
|
34
|
-
* `protocol.handleOperation(request)
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
33
|
+
* `protocol.handleOperation(request)`: the three steps a host would otherwise
|
|
34
|
+
* spell out — `decodeOperation` → `framework.execute` → `encodeOperation` — in one
|
|
35
|
+
* call, resolving the `AvProtocolResponse` the host writes. A request the decoder
|
|
36
|
+
* answers itself (a transport failure, an identity mismatch, an unadvertised
|
|
37
|
+
* route) is answered without executing.
|
|
39
38
|
*
|
|
40
|
-
* Total over ANY value, never rejecting: the decoder answers every value
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* which only this shortcut holds: the bare `encodeOperation` is given the
|
|
48
|
-
* response and the request id alone.
|
|
39
|
+
* Total over ANY value, never rejecting: the decoder answers every value,
|
|
40
|
+
* `execute` resolves for every request it is handed, and the encoder answers every
|
|
41
|
+
* response — a result with no wire form as `A3003` →
|
|
42
|
+
* 500. That `A3003` reaches the Framework's diagnostics sink as an `"operation"`
|
|
43
|
+
* diagnostic carrying the decoded request's identity and id, which only this
|
|
44
|
+
* shortcut holds: the bare `encodeOperation` is given the response and the
|
|
45
|
+
* request id alone.
|
|
49
46
|
*/
|
|
50
47
|
export declare function handleOperationRequest(context: HandlerContext, request: AvProtocolRequest): Promise<AvProtocolResponse>;
|
|
51
48
|
/**
|
|
52
|
-
* `protocol.handleTransaction(request)
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* client-hidden
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* reported through {@link planUnencodableReport}.
|
|
49
|
+
* `protocol.handleTransaction(request)`: the same shortcut for `/_transactions` —
|
|
50
|
+
* `decodeTransaction` → `framework.executeTransaction` → `encodeTransaction`. The
|
|
51
|
+
* decoded plan is client origin and cannot say otherwise, so every step runs under
|
|
52
|
+
* ClientContract rules: a client-hidden field, a client-restricted variant or a
|
|
53
|
+
* client-hidden Resource is refused as through its single-operation route, plus
|
|
54
|
+
* `cause.operation`. A committed plan is `200 A1009`; a rolled-back one answers
|
|
55
|
+
* its failing step's code at that code's status. Total over any value, as {@link
|
|
56
|
+
* handleOperationRequest} is; an `A3003` is reported through {@link
|
|
57
|
+
* planUnencodableReport}.
|
|
62
58
|
*/
|
|
63
59
|
export declare function handleTransactionRequest(context: HandlerContext, request: AvProtocolRequest): Promise<AvProtocolResponse>;
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { createDiagnosticsReporter, createReporter, } from "../runtime/diagnostics-reporter.js";
|
|
2
2
|
import { decodeOperationRequest, decodeTransactionRequest, } from "./http-request.decoder.js";
|
|
3
3
|
import { encodeOperationResponse, encodeTransactionResponse, } from "./http-response.encoder.js";
|
|
4
|
-
/**
|
|
5
|
-
* Where a plan's `A3003` goes: the Framework's diagnostics sink, as a
|
|
6
|
-
* `"transaction"` diagnostic — client scope (the protocol has no other
|
|
7
|
-
* origin, P4), the request id the plan ran under, and the step the encoder
|
|
8
|
-
* blames as `operation` when it blames one. One spelling for both
|
|
9
|
-
* `protocol.encodeTransaction` and `protocol.handleTransaction`.
|
|
10
|
-
*/
|
|
11
4
|
export function planUnencodableReport(sink, requestId) {
|
|
12
5
|
return (error, operation) => createReporter(sink, {
|
|
13
6
|
kind: "transaction",
|
|
@@ -16,33 +9,9 @@ export function planUnencodableReport(sink, requestId) {
|
|
|
16
9
|
...(operation === undefined ? {} : { operation }),
|
|
17
10
|
})(error, "A3003");
|
|
18
11
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Where one operation's `A3003` goes: the Framework's diagnostics sink, as an
|
|
21
|
-
* `"operation"` diagnostic carrying the decoded request's identity and id —
|
|
22
|
-
* the shape the public `OperationDiagnostic` already has. One spelling for
|
|
23
|
-
* `protocol.handleOperation` and for `protocol.encodeOperation` given the
|
|
24
|
-
* decoded request (the architect, 2026-10-05).
|
|
25
|
-
*/
|
|
26
12
|
export function operationUnencodableReport(sink, request) {
|
|
27
13
|
return (error) => createDiagnosticsReporter(sink, request)(error, "A3003");
|
|
28
14
|
}
|
|
29
|
-
/**
|
|
30
|
-
* `protocol.handleOperation(request)` (§5.9, R2; S8): the three steps a host
|
|
31
|
-
* would otherwise spell out — `decodeOperation` → `framework.execute` →
|
|
32
|
-
* `encodeOperation` — in one call, resolving the `AvProtocolResponse` the host
|
|
33
|
-
* writes. A request the decoder answers itself (a transport failure, an
|
|
34
|
-
* identity mismatch, an unadvertised route) is answered without executing.
|
|
35
|
-
*
|
|
36
|
-
* Total over ANY value, never rejecting: the decoder answers every value (one
|
|
37
|
-
* that is not an `AvProtocolRequest` as `400 A2000`; the director,
|
|
38
|
-
* 2026-10-05), `execute` resolves for every request it is handed, and the
|
|
39
|
-
* encoder answers every response — a result with no wire form as `A3003` →
|
|
40
|
-
* 500. That `A3003`
|
|
41
|
-
* reaches the Framework's diagnostics sink as an `"operation"` diagnostic
|
|
42
|
-
* carrying the decoded request's identity and id (the director, 2026-10-05),
|
|
43
|
-
* which only this shortcut holds: the bare `encodeOperation` is given the
|
|
44
|
-
* response and the request id alone.
|
|
45
|
-
*/
|
|
46
15
|
export async function handleOperationRequest(context, request) {
|
|
47
16
|
const decoded = decodeOperationRequest(context.contracts, request);
|
|
48
17
|
if (!decoded.ok) {
|
|
@@ -51,18 +20,6 @@ export async function handleOperationRequest(context, request) {
|
|
|
51
20
|
const response = await context.execute(decoded.request);
|
|
52
21
|
return encodeOperationResponse(response, decoded.requestId, operationUnencodableReport(context.sink, decoded.request));
|
|
53
22
|
}
|
|
54
|
-
/**
|
|
55
|
-
* `protocol.handleTransaction(request)` (§5.9, R2; S9): the same shortcut for
|
|
56
|
-
* `/_transactions` — `decodeTransaction` → `framework.executeTransaction` →
|
|
57
|
-
* `encodeTransaction`. The decoded plan is client origin and cannot say
|
|
58
|
-
* otherwise, so every step runs under ClientContract rules (R1): a
|
|
59
|
-
* client-hidden field, a client-restricted variant or a client-hidden
|
|
60
|
-
* Resource is refused as through its single-operation route, plus
|
|
61
|
-
* `cause.operation`. A committed plan is `200 A1009` (P3); a rolled-back one
|
|
62
|
-
* answers its failing step's code at that code's status (Q4). Total over any
|
|
63
|
-
* value, as {@link handleOperationRequest} is; an `A3003` is
|
|
64
|
-
* reported through {@link planUnencodableReport}.
|
|
65
|
-
*/
|
|
66
23
|
export async function handleTransactionRequest(context, request) {
|
|
67
24
|
const decoded = decodeTransactionRequest(context.contracts, request);
|
|
68
25
|
if (!decoded.ok) {
|
|
@@ -35,17 +35,6 @@ function supportsProjection(request) {
|
|
|
35
35
|
}
|
|
36
36
|
return request.variant !== "count";
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Plan one scalar of the read. Two Contracts answer two different questions:
|
|
40
|
-
* the **active** Contract decides what the read RETURNS, and the **Core**
|
|
41
|
-
* Contract decides what the Adapter is ASKED for — only a field it stores.
|
|
42
|
-
*
|
|
43
|
-
* A field added at a scope (`application.fields`) exists in that scope's
|
|
44
|
-
* Contract and not in Core, and is VIRTUAL by construction
|
|
45
|
-
* (`contract.compiler.ts`), so it is returned and computed, never requested.
|
|
46
|
-
* Resolving the returned field against Core instead dropped it from the default
|
|
47
|
-
* read and sent an explicit `select` of it to the Adapter as a column (D2).
|
|
48
|
-
*/
|
|
49
38
|
function addScalarProjection(core, active, behaviors, resourceName, fieldName, adapterSelect, requested, computed) {
|
|
50
39
|
const activeField = lookupField(lookupResource(active, resourceName), fieldName);
|
|
51
40
|
if (activeField?.kind !== "scalar") {
|
|
@@ -253,13 +242,6 @@ function replaceWithInternalSelect(args, select) {
|
|
|
253
242
|
internal.select = select;
|
|
254
243
|
return internal;
|
|
255
244
|
}
|
|
256
|
-
/**
|
|
257
|
-
* Clone the caller projection into the internal Adapter projection: the read
|
|
258
|
-
* set the Adapter is asked for, always explicit for a projecting variant, plus
|
|
259
|
-
* whatever computed scalar fields need to materialize. Caller-visible arguments
|
|
260
|
-
* are never mutated and hidden dependencies are resolved through the Core
|
|
261
|
-
* Contract.
|
|
262
|
-
*/
|
|
263
245
|
export function planReadOperation(core, active, behaviors, request, args) {
|
|
264
246
|
if (!isRecord(args) || !supportsProjection(request)) {
|
|
265
247
|
return { arguments: args, projection: undefined, materialize: false };
|
|
@@ -285,11 +267,6 @@ export function planReadOperation(core, active, behaviors, request, args) {
|
|
|
285
267
|
materialize: true,
|
|
286
268
|
};
|
|
287
269
|
}
|
|
288
|
-
// No caller projection: the read set is the default projection, issued
|
|
289
|
-
// explicitly and unconditionally. Leaving it unspecified would mean "whatever
|
|
290
|
-
// the Adapter's provider reads by default", which is every stored column —
|
|
291
|
-
// including one the active scope has removed from reads, fetched into server
|
|
292
|
-
// memory before the output validator could refuse it (D1).
|
|
293
270
|
const defaults = defaultProjectionLevel(core, active, behaviors, request.resource);
|
|
294
271
|
return {
|
|
295
272
|
arguments: { ...args, select: defaults.select },
|
|
@@ -319,8 +296,6 @@ async function materializeRecord(active, behaviors, request, plan, value, contex
|
|
|
319
296
|
if (!isRecord(value)) {
|
|
320
297
|
return value;
|
|
321
298
|
}
|
|
322
|
-
// The active Contract planned this read, so it is the one that knows every
|
|
323
|
-
// computed field in it — a field added at its scope included (D2).
|
|
324
299
|
const resource = lookupResource(active, plan.resource);
|
|
325
300
|
if (resource === undefined) {
|
|
326
301
|
return value;
|
|
@@ -359,10 +334,6 @@ async function materializeRecord(active, behaviors, request, plan, value, contex
|
|
|
359
334
|
.filter((fieldName) => Object.hasOwn(record, fieldName))
|
|
360
335
|
.map((fieldName) => [fieldName, record[fieldName]]));
|
|
361
336
|
}
|
|
362
|
-
/**
|
|
363
|
-
* Materialize computed scalar reads and remove internal dependency fields,
|
|
364
|
-
* against `active` — the Contract `planReadOperation` was given as `active`.
|
|
365
|
-
*/
|
|
366
337
|
export async function materializeReadOperation(active, behaviors, request, plan, value, contextFactory) {
|
|
367
338
|
const projection = plan.projection;
|
|
368
339
|
if (!plan.materialize || projection === undefined) {
|