@aventara/core 0.1.0-pilot.1 → 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/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 +0 -55
- 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 +21 -26
- package/dist/protocol/protocol-failure.js +0 -12
- package/dist/protocol/protocol-headers.d.ts +25 -30
- package/dist/protocol/protocol-headers.js +0 -66
- 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
package/dist/protocol/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@aventara/core/protocol` — the HTTP protocol, as passive data and pure
|
|
3
|
-
* functions over core
|
|
3
|
+
* functions over core. It mounts nothing and imports no HTTP library.
|
|
4
4
|
*
|
|
5
|
-
* The direction is one-way: this entry may import core's internals, and no
|
|
6
|
-
*
|
|
7
|
-
* (`protocol-direction.spec.ts`). The main `@aventara/core` entry exports no
|
|
8
|
-
*
|
|
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.
|
|
9
9
|
*/
|
|
10
10
|
export * as AvProtocol from "./av-protocol.js";
|
|
11
11
|
export type { AvProtocolRequest } from "./http-request.decoder.js";
|
package/dist/protocol/index.js
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@aventara/core/protocol` — the HTTP protocol, as passive data and pure
|
|
3
|
-
* functions over core (§Q1). It mounts nothing and imports no HTTP library.
|
|
4
|
-
*
|
|
5
|
-
* The direction is one-way: this entry may import core's internals, and no
|
|
6
|
-
* module of core's execution side imports anything under `protocol/`
|
|
7
|
-
* (`protocol-direction.spec.ts`). The main `@aventara/core` entry exports no
|
|
8
|
-
* name from here.
|
|
9
|
-
*/
|
|
10
1
|
export * as AvProtocol from "./av-protocol.js";
|
|
@@ -1,27 +1,20 @@
|
|
|
1
1
|
import { type OperationResponse } from "../runtime/operation-response.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* framework envelope (§13.1), the boundary §13.5 draws: an envelope's A1xxx
|
|
5
|
-
* resolves and its every other code is a `FrameworkError`; anything else means
|
|
6
|
-
* no envelope arrived, which a client raises as `TransportError`. The HTTP
|
|
7
|
-
* status plays no part — a code is read even at an unexpected status.
|
|
3
|
+
* The HTTP status plays no part — a code is read even at an unexpected status.
|
|
8
4
|
*
|
|
9
|
-
* `value` is the body as parsed JSON, or `undefined` when there was no body or
|
|
10
|
-
*
|
|
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:
|
|
11
7
|
*
|
|
12
8
|
* - an object (not an array) with an own `data` member and an allocated `code`;
|
|
13
|
-
* - for an A1xxx code, a `cause` of exactly `null`, and `data` of `null` when
|
|
14
|
-
*
|
|
15
|
-
* - for every other code, `data` of `null` and a cause: an object whose
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* integer.
|
|
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.
|
|
20
15
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* held to agree with this one on every row of the fixture corpus's family 11
|
|
25
|
-
* (R5, `packages/client`), so the two cannot drift apart silently.
|
|
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.
|
|
26
19
|
*/
|
|
27
20
|
export declare function isOperationResponse(value: unknown): value is OperationResponse;
|
|
@@ -1,30 +1,5 @@
|
|
|
1
1
|
import { VALIDATION_CODES } from "../operations/validation-code.js";
|
|
2
2
|
import { OPERATION_CODES, } from "../runtime/operation-response.js";
|
|
3
|
-
/**
|
|
4
|
-
* `AvProtocol.isOperationResponse` — whether a parsed response body is a
|
|
5
|
-
* framework envelope (§13.1), the boundary §13.5 draws: an envelope's A1xxx
|
|
6
|
-
* resolves and its every other code is a `FrameworkError`; anything else means
|
|
7
|
-
* no envelope arrived, which a client raises as `TransportError`. The HTTP
|
|
8
|
-
* status plays no part — a code is read even at an unexpected status.
|
|
9
|
-
*
|
|
10
|
-
* `value` is the body as parsed JSON, or `undefined` when there was no body or
|
|
11
|
-
* it was not JSON (neither is an envelope). An envelope here is:
|
|
12
|
-
*
|
|
13
|
-
* - an object (not an array) with an own `data` member and an allocated `code`;
|
|
14
|
-
* - for an A1xxx code, a `cause` of exactly `null`, and `data` of `null` when
|
|
15
|
-
* the code is `A1001`;
|
|
16
|
-
* - for every other code, `data` of `null` and a cause: an object whose
|
|
17
|
-
* `message` is a string, whose `issues`, if present, is a list of objects each
|
|
18
|
-
* with an allocated V-code, a string `message` and, if present, a `path` of
|
|
19
|
-
* strings and integers, and whose `operation`, if present, is a non-negative
|
|
20
|
-
* integer.
|
|
21
|
-
*
|
|
22
|
-
* Members §13.1 does not define are no reason to refuse; a reader drops them.
|
|
23
|
-
*
|
|
24
|
-
* The generated client's own check (`envelopeOf` in its emitted transport) is
|
|
25
|
-
* held to agree with this one on every row of the fixture corpus's family 11
|
|
26
|
-
* (R5, `packages/client`), so the two cannot drift apart silently.
|
|
27
|
-
*/
|
|
28
3
|
export function isOperationResponse(value) {
|
|
29
4
|
if (!isRecord(value) || !Object.hasOwn(value, "data")) {
|
|
30
5
|
return false;
|
|
@@ -72,10 +47,6 @@ function isValidationIssue(value) {
|
|
|
72
47
|
(Array.isArray(path) &&
|
|
73
48
|
everyElement(path, (segment) => typeof segment === "string" || Number.isInteger(segment))));
|
|
74
49
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Every element, holes included (a hole reads as `undefined`, which no member
|
|
77
|
-
* test accepts) — unlike `Array.prototype.every`, which skips them.
|
|
78
|
-
*/
|
|
79
50
|
function everyElement(list, test) {
|
|
80
51
|
for (const element of list) {
|
|
81
52
|
if (!test(element)) {
|
|
@@ -1,45 +1,40 @@
|
|
|
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
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The four transport codes: failures of the HTTP request itself, which the
|
|
5
|
+
* protocol answers before any operation exists, so no execution path produces
|
|
6
|
+
* them. Module type — not an entry export.
|
|
7
7
|
*/
|
|
8
8
|
export type TransportFailureCode = "A2000" | "A2010" | "A2011" | "A2012";
|
|
9
9
|
/**
|
|
10
10
|
* pilot.1 — the `400 A2000` answering a request that did not send an identity
|
|
11
|
-
* header
|
|
12
|
-
*
|
|
13
|
-
* developer calling the API by hand learns what to add.
|
|
11
|
+
* header: its message names the missing header or headers, and echoes nothing the
|
|
12
|
+
* request sent — so a developer calling the API by hand learns what to add.
|
|
14
13
|
*/
|
|
15
14
|
export declare function identityHeadersMissing(missing: readonly IdentityHeaderName[], requestId: string): AvProtocolResponse;
|
|
16
15
|
/**
|
|
17
16
|
* `protocol.failure(code, requestId?)` / `protocol.failure("A2012", requestId,
|
|
18
|
-
* allow)
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* the code's status.
|
|
17
|
+
* allow)`: a transport code as the complete framework response — the envelope `{
|
|
18
|
+
* data: null, code, cause: { message } }`, encoded exactly as
|
|
19
|
+
* `protocol.encodeOperation` encodes it, at the code's status.
|
|
22
20
|
*
|
|
23
|
-
* The decoders produce their transport failures through it. A host that
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* limit, `A2011` for another content type.
|
|
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.
|
|
27
24
|
*
|
|
28
|
-
* `requestId` is echoed as `Aventara-Request-Id
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* refused or left uncorrelated.
|
|
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.
|
|
32
28
|
*
|
|
33
29
|
* `allow` belongs to `A2012`, and `A2012` requires it: every 405 carries the
|
|
34
|
-
* `Allow` header naming the methods its route DOES accept
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* methods; the decoders pass `["POST"]`.
|
|
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"]`.
|
|
38
33
|
*
|
|
39
|
-
* A code outside the four, `A2012` without `allow`, `allow` with any other
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
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.
|
|
43
38
|
*/
|
|
44
39
|
export declare function transportFailure(code: "A2012", requestId: string | undefined, allow: readonly string[]): AvProtocolResponse;
|
|
45
40
|
export declare function transportFailure(code: Exclude<TransportFailureCode, "A2012">, requestId?: string): AvProtocolResponse;
|
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
import { operationFailure } from "../runtime/operation-response.js";
|
|
2
2
|
import { requestIdOf } from "../runtime/request-id.js";
|
|
3
3
|
import { encodeOperationResponse, } from "./http-response.encoder.js";
|
|
4
|
-
/**
|
|
5
|
-
* The framework's own text for each transport code. It names the defect and
|
|
6
|
-
* never echoes the request (§13.5): no body, no content type, no method, no
|
|
7
|
-
* configured limit.
|
|
8
|
-
*/
|
|
9
4
|
const TRANSPORT_FAILURE_MESSAGES = Object.freeze({
|
|
10
5
|
A2000: "The request is malformed and cannot be interpreted.",
|
|
11
6
|
A2010: "The request body exceeds the maximum request size.",
|
|
12
7
|
A2011: "The request content type is not supported; send application/json.",
|
|
13
8
|
A2012: "The HTTP method is not allowed on this framework route.",
|
|
14
9
|
});
|
|
15
|
-
/**
|
|
16
|
-
* pilot.1 — the `400 A2000` answering a request that did not send an identity
|
|
17
|
-
* header (§12.4; the architect, 2026-10-05): its message names the missing
|
|
18
|
-
* header or headers, and echoes nothing the request sent (§13.5) — so a
|
|
19
|
-
* developer calling the API by hand learns what to add.
|
|
20
|
-
*/
|
|
21
10
|
export function identityHeadersMissing(missing, requestId) {
|
|
22
11
|
const named = missing.length === 1
|
|
23
12
|
? `The ${missing[0]} header is`
|
|
24
13
|
: `The ${missing.join(" and ")} headers are`;
|
|
25
14
|
return encodeOperationResponse(operationFailure("A2000", { message: `${named} missing.` }), requestIdOf({ requestId }));
|
|
26
15
|
}
|
|
27
|
-
/** An HTTP method as RFC 9110 §9.1 spells one: a `token` (§5.6.2). */
|
|
28
16
|
const METHOD_TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
29
17
|
export function transportFailure(code, requestId, allow) {
|
|
30
18
|
if (!Object.hasOwn(TRANSPORT_FAILURE_MESSAGES, code)) {
|
|
@@ -3,19 +3,18 @@ import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
|
|
|
3
3
|
* `AvProtocol.headers` — the header names the protocol owns, as passive data.
|
|
4
4
|
*
|
|
5
5
|
* - `protocolVersion`, `contractHash`: the two identity headers every
|
|
6
|
-
* generated-client resource and transaction request sends
|
|
7
|
-
*
|
|
8
|
-
* - `requestId`: the correlation header
|
|
9
|
-
*
|
|
10
|
-
* response echoes it.
|
|
6
|
+
* generated-client resource and transaction request sends; the `_contract`
|
|
7
|
+
* request needs neither.
|
|
8
|
+
* - `requestId`: the correlation header. A valid one is adopted as the request's
|
|
9
|
+
* id, an invalid one ignored, and every framework-produced response echoes it.
|
|
11
10
|
*
|
|
12
|
-
* Spelled as the canonical wire text. HTTP header names are case-insensitive
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* Spelled as the canonical wire text. HTTP header names are case-insensitive, so a
|
|
12
|
+
* reader matches them without regard to case; these spellings are what the
|
|
13
|
+
* framework and the generated client SEND.
|
|
15
14
|
*
|
|
16
|
-
* Passive data
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* Passive data: strings only, frozen, so a consumer — the client generator emits
|
|
16
|
+
* it by value into generated source — can neither mutate it nor receive anything
|
|
17
|
+
* `JSON.stringify` would drop or reshape.
|
|
19
18
|
*/
|
|
20
19
|
export declare const headers: Readonly<{
|
|
21
20
|
readonly protocolVersion: "Aventara-Protocol-Version";
|
|
@@ -25,10 +24,9 @@ export declare const headers: Readonly<{
|
|
|
25
24
|
/** A request's headers as a host hands them over (`AvProtocolRequest.headers`). */
|
|
26
25
|
type ReceivedHeaders = Readonly<Record<string, string | readonly string[] | undefined>>;
|
|
27
26
|
/**
|
|
28
|
-
* The request's headers as one spelling
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* order received (RFC 9110 §5.3), and an `undefined` entry or an empty list
|
|
27
|
+
* The request's headers as one spelling: names lower-cased, a repeated header's
|
|
28
|
+
* values — a list, or one name received in several casings — joined with `", "` in
|
|
29
|
+
* the order received (RFC 9110 §5.3), and an `undefined` entry or an empty list
|
|
32
30
|
* dropped as absent. Values are otherwise as received. This is what a client
|
|
33
31
|
* request's `transport.headers` carries to the developer's pipelines, and what
|
|
34
32
|
* every header read below reads.
|
|
@@ -43,32 +41,29 @@ export declare function normalizeHeaders(received: ReceivedHeaders): Readonly<Re
|
|
|
43
41
|
*/
|
|
44
42
|
export declare function headerValue(normalized: Readonly<Record<string, string>>, name: string): string | undefined;
|
|
45
43
|
/**
|
|
46
|
-
* The identity headers
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* ClientContract it speaks, so there is nothing to compare.
|
|
44
|
+
* The identity headers as the `ClientProtocolIdentity` core checks, or `undefined`
|
|
45
|
+
* when either is ABSENT — a request without them is malformed: it does not say
|
|
46
|
+
* which protocol and ClientContract it speaks, so there is nothing to compare.
|
|
50
47
|
*
|
|
51
48
|
* Present values are read, never judged: whether they match is the Framework
|
|
52
49
|
* Validation Layer's call (cross-phase invariant 13), made by core's one
|
|
53
|
-
* stale-client check. A present version that is not a decimal integer (no
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
50
|
+
* stale-client check. A present version that is not a decimal integer (no sign, no
|
|
51
|
+
* leading zero) reads as `NaN`, so it cannot match (`A2006`); a present hash is
|
|
52
|
+
* passed as received (`A2005` unless it is the current one). Present includes
|
|
53
|
+
* empty: a header sent with no value was still sent.
|
|
57
54
|
*/
|
|
58
55
|
export declare function protocolIdentityOf(normalized: Readonly<Record<string, string>>): ClientProtocolIdentity | undefined;
|
|
59
56
|
/**
|
|
60
|
-
* The identity headers
|
|
61
|
-
*
|
|
62
|
-
*
|
|
57
|
+
* The identity headers a request did not send, in the order the framework sends
|
|
58
|
+
* them — what the `A2000` answering it names (pilot.1). Empty exactly when {@link
|
|
59
|
+
* protocolIdentityOf} reads an identity.
|
|
63
60
|
*/
|
|
64
61
|
export declare function missingIdentityHeaders(normalized: Readonly<Record<string, string>>): readonly IdentityHeaderName[];
|
|
65
62
|
/** The two identity headers' names, as the framework spells them. */
|
|
66
63
|
export type IdentityHeaderName = (typeof headers)["protocolVersion"] | (typeof headers)["contractHash"];
|
|
67
64
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* is ignored, never refused, and core mints an id instead. A repeated header
|
|
71
|
-
* joins with `", "`, which holds a space, so it is never adopted.
|
|
65
|
+
* A repeated header joins with `", "`, which holds a space, so it is never
|
|
66
|
+
* adopted.
|
|
72
67
|
*/
|
|
73
68
|
export declare function adoptedRequestId(normalized: Readonly<Record<string, string>>): string | undefined;
|
|
74
69
|
export {};
|
|
@@ -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,22 +34,10 @@ export function protocolIdentityOf(normalized) {
|
|
|
88
34
|
hash,
|
|
89
35
|
};
|
|
90
36
|
}
|
|
91
|
-
/**
|
|
92
|
-
* The identity headers (§12.4) a request did not send, in the order the
|
|
93
|
-
* framework sends them — what the `A2000` answering it names (pilot.1).
|
|
94
|
-
* Empty exactly when {@link protocolIdentityOf} reads an identity.
|
|
95
|
-
*/
|
|
96
37
|
export function missingIdentityHeaders(normalized) {
|
|
97
38
|
return [headers.protocolVersion, headers.contractHash].filter((name) => headerValue(normalized, name) === undefined);
|
|
98
39
|
}
|
|
99
|
-
/** Q13's adoptable correlation id: 1–128 characters of visible ASCII (`0x21`–`0x7E`). */
|
|
100
40
|
const ADOPTABLE_REQUEST_ID = /^[\x21-\x7e]{1,128}$/;
|
|
101
|
-
/**
|
|
102
|
-
* Q13 (the architect's, 2026-10-04): the request's `Aventara-Request-Id` when
|
|
103
|
-
* it is 1–128 characters of visible ASCII; otherwise `undefined` — the header
|
|
104
|
-
* is ignored, never refused, and core mints an id instead. A repeated header
|
|
105
|
-
* joins with `", "`, which holds a space, so it is never adopted.
|
|
106
|
-
*/
|
|
107
41
|
export function adoptedRequestId(normalized) {
|
|
108
42
|
const value = headerValue(normalized, headers.requestId);
|
|
109
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)) {
|