@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,36 +1,14 @@
|
|
|
1
1
|
import { requestIdOf } from "../runtime/request-id.js";
|
|
2
2
|
import { transportFailure } from "./protocol-failure.js";
|
|
3
3
|
import { adoptedRequestId, normalizeHeaders, protocolIdentityOf, } from "./protocol-headers.js";
|
|
4
|
-
/**
|
|
5
|
-
* Reading a host's request before any route answers it: the request as a
|
|
6
|
-
* value of its declared type, read once; the request id it is answered under
|
|
7
|
-
* (Q13); its headers as one spelling (Q7); its identity headers; and the
|
|
8
|
-
* route paths the protocol owns (§12.1). Shared by the decoders, the absence
|
|
9
|
-
* responder and the contract responder, so each reads a request one way.
|
|
10
|
-
*/
|
|
11
|
-
/** `<entrypoint>/_resources/:resource/:family/:variant` (§12.1). */
|
|
12
4
|
const OPERATION_ROUTE = /^\/_resources\/([^/]*)\/([^/]*)\/([^/]*)$/;
|
|
13
|
-
/** `POST <entrypoint>/_transactions` (§12.1). */
|
|
14
5
|
export const TRANSACTIONS_ROUTE = "/_transactions";
|
|
15
|
-
/** `GET <entrypoint>/_contract` (§12.1, §12.5). */
|
|
16
6
|
export const CONTRACT_ROUTE = "/_contract";
|
|
17
|
-
/** The methods an operation or `/_transactions` route accepts: `POST`, only (§12.2). */
|
|
18
7
|
export const POST_ONLY = Object.freeze(["POST"]);
|
|
19
|
-
/** The methods the contract route accepts: `GET`, only (§12.2). */
|
|
20
8
|
export const GET_ONLY = Object.freeze(["GET"]);
|
|
21
|
-
/**
|
|
22
|
-
* Whether a path lies in the protocol's namespace: underscore-prefixed paths
|
|
23
|
-
* beneath the entrypoint are reserved for framework facilities; every other
|
|
24
|
-
* path is the host's (§12.1).
|
|
25
|
-
*/
|
|
26
9
|
export function isProtocolPath(path) {
|
|
27
10
|
return path.startsWith("/_");
|
|
28
11
|
}
|
|
29
|
-
/**
|
|
30
|
-
* The host's value read as a request, or — when it is not an
|
|
31
|
-
* `AvProtocolRequest` at all — the `400 A2000` answering it, under a minted
|
|
32
|
-
* id (the director, 2026-10-05).
|
|
33
|
-
*/
|
|
34
12
|
export function readRequest(received) {
|
|
35
13
|
const request = wellFormedRequest(received);
|
|
36
14
|
if (request === undefined) {
|
|
@@ -45,10 +23,6 @@ export function readRequest(received) {
|
|
|
45
23
|
protocol: protocolIdentityOf(headers),
|
|
46
24
|
};
|
|
47
25
|
}
|
|
48
|
-
/**
|
|
49
|
-
* The three segments of an operation route, each URL-decoded and none empty
|
|
50
|
-
* (§12.6 refuses an empty-resource route); `undefined` when it is not one.
|
|
51
|
-
*/
|
|
52
26
|
export function operationRouteSegments(path) {
|
|
53
27
|
const match = OPERATION_ROUTE.exec(path);
|
|
54
28
|
if (match === null) {
|
|
@@ -61,7 +35,6 @@ export function operationRouteSegments(path) {
|
|
|
61
35
|
? { resource, family, variant }
|
|
62
36
|
: undefined;
|
|
63
37
|
}
|
|
64
|
-
/** One path segment, URL-decoded once; `undefined` when it is not decodable. */
|
|
65
38
|
function decodeSegment(segment) {
|
|
66
39
|
try {
|
|
67
40
|
return decodeURIComponent(segment);
|
|
@@ -70,11 +43,6 @@ function decodeSegment(segment) {
|
|
|
70
43
|
return undefined;
|
|
71
44
|
}
|
|
72
45
|
}
|
|
73
|
-
/**
|
|
74
|
-
* The answer to a value that is not an `AvProtocolRequest`: `A2000` under a
|
|
75
|
-
* freshly minted id — the value's own headers are not believed, so no id is
|
|
76
|
-
* adopted from them.
|
|
77
|
-
*/
|
|
78
46
|
function malformedRequest() {
|
|
79
47
|
const requestId = requestIdOf(undefined);
|
|
80
48
|
return {
|
|
@@ -83,20 +51,8 @@ function malformedRequest() {
|
|
|
83
51
|
requestId,
|
|
84
52
|
};
|
|
85
53
|
}
|
|
86
|
-
/**
|
|
87
|
-
* The host's request, read ONCE into a value of its declared type, or
|
|
88
|
-
* `undefined` when it is not one: not an object, a `method` or `path` that is
|
|
89
|
-
* not text, `headers` that are not a record of text or lists of text, or a
|
|
90
|
-
* `body` of neither arm (Q11) — raw content that is neither text nor bytes
|
|
91
|
-
* has no byte count to measure. Each member is read once, so a getter cannot
|
|
92
|
-
* answer one check and lie to the next, and one that throws — like any trap —
|
|
93
|
-
* makes the request malformed rather than the decoder throw. A parsed body's
|
|
94
|
-
* value is kept as the same object, never read into (§12.3).
|
|
95
|
-
*/
|
|
96
54
|
function wellFormedRequest(received) {
|
|
97
55
|
try {
|
|
98
|
-
// `null` and `undefined` throw here; any other non-object has no
|
|
99
|
-
// members, so its `method` is not text.
|
|
100
56
|
const { method, path, headers, body } = received;
|
|
101
57
|
const copied = headerRecord(headers);
|
|
102
58
|
const armed = armedBody(body);
|
|
@@ -130,7 +86,6 @@ function headerRecord(headers) {
|
|
|
130
86
|
return undefined;
|
|
131
87
|
}
|
|
132
88
|
}
|
|
133
|
-
// `fromEntries` defines each member, so a header named `__proto__` stays data.
|
|
134
89
|
return Object.fromEntries(copied);
|
|
135
90
|
}
|
|
136
91
|
function armedBody(body) {
|
|
@@ -7,41 +7,40 @@ import type { TransactionResponse } from "../transactions/transaction-response.j
|
|
|
7
7
|
* text, and adds nothing of the framework's.
|
|
8
8
|
*/
|
|
9
9
|
export type AvProtocolResponse = {
|
|
10
|
-
/** `AvProtocol.httpStatus` of the envelope's code
|
|
10
|
+
/** `AvProtocol.httpStatus` of the envelope's code. */
|
|
11
11
|
readonly status: number;
|
|
12
12
|
/**
|
|
13
13
|
* The headers the framework owns on this response, canonically spelled:
|
|
14
|
-
* `Content-Type: application/json` and the `Aventara-Request-Id` it echoes
|
|
15
|
-
* (Q13).
|
|
14
|
+
* `Content-Type: application/json` and the `Aventara-Request-Id` it echoes.
|
|
16
15
|
*/
|
|
17
16
|
readonly headers: Readonly<Record<string, string>>;
|
|
18
|
-
/** The JSON text of the envelope
|
|
17
|
+
/** The JSON text of the envelope, its data in wire forms. */
|
|
19
18
|
readonly body: string;
|
|
20
19
|
};
|
|
21
20
|
/**
|
|
22
21
|
* Where an encoder hands the raw failure behind an `A3003` — the binding's
|
|
23
|
-
* diagnostics channel
|
|
24
|
-
*
|
|
22
|
+
* diagnostics channel — with the plan step it blames, if any. The wire never
|
|
23
|
+
* carries it.
|
|
25
24
|
*/
|
|
26
25
|
export type UnencodableReport = (error: unknown, operation?: number) => void;
|
|
27
26
|
/**
|
|
28
27
|
* `protocol.encodeOperation(response, requestId)`: one operation's framework
|
|
29
|
-
* response as the HTTP response a host writes. Status is the code's
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* response as the HTTP response a host writes. Status is the code's; `data` is
|
|
29
|
+
* wire-encoded; `requestId` is echoed as `Aventara-Request-Id` — pass the id the
|
|
30
|
+
* request ran under, which the decoder supplies.
|
|
32
31
|
*
|
|
33
|
-
* Total: a result it cannot encode — and a response whose code is not
|
|
34
|
-
*
|
|
35
|
-
*
|
|
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.
|
|
36
35
|
*/
|
|
37
36
|
export declare function encodeOperationResponse(response: OperationResponse, requestId: string, report?: UnencodableReport): AvProtocolResponse;
|
|
38
37
|
/**
|
|
39
38
|
* `protocol.encodeTransaction(response, requestId)`: the same for a plan's
|
|
40
|
-
* response
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
39
|
+
* response. A committed plan is `200 A1009` — even when it created something —
|
|
40
|
+
* with each operation's data wire-encoded in plan order by the same walker as
|
|
41
|
+
* {@link encodeOperationResponse}; a rolled-back plan answers its failing
|
|
42
|
+
* operation's own status. A step whose result cannot be encoded answers `A3003` →
|
|
43
|
+
* 500 naming that step as `cause.operation`, as every internal failure inside a
|
|
44
|
+
* plan does.
|
|
46
45
|
*/
|
|
47
46
|
export declare function encodeTransactionResponse(response: TransactionResponse, requestId: string, report?: UnencodableReport): AvProtocolResponse;
|
|
@@ -4,16 +4,6 @@ import { SERIALIZATION_FAILURE_MESSAGE } from "../runtime/error-boundary.js";
|
|
|
4
4
|
import { operationFailure, } from "../runtime/operation-response.js";
|
|
5
5
|
import { httpStatus } from "./http-status.table.js";
|
|
6
6
|
import { headers } from "./protocol-headers.js";
|
|
7
|
-
/**
|
|
8
|
-
* `protocol.encodeOperation(response, requestId)`: one operation's framework
|
|
9
|
-
* response as the HTTP response a host writes. Status is the code's (§13.2);
|
|
10
|
-
* `data` is wire-encoded (P1); `requestId` is echoed as `Aventara-Request-Id`
|
|
11
|
-
* (Q13) — pass the id the request ran under, which the decoder supplies.
|
|
12
|
-
*
|
|
13
|
-
* Total: a result it cannot encode — and a response whose code is not
|
|
14
|
-
* allocated — answers `A3003` → 500 with the framework's own text, and none of
|
|
15
|
-
* the result reaches the body.
|
|
16
|
-
*/
|
|
17
7
|
export function encodeOperationResponse(response, requestId, report) {
|
|
18
8
|
try {
|
|
19
9
|
return written(response, toWire(response.data, new Set()), requestId);
|
|
@@ -23,15 +13,6 @@ export function encodeOperationResponse(response, requestId, report) {
|
|
|
23
13
|
return written(serializationFailure(), null, requestId);
|
|
24
14
|
}
|
|
25
15
|
}
|
|
26
|
-
/**
|
|
27
|
-
* `protocol.encodeTransaction(response, requestId)`: the same for a plan's
|
|
28
|
-
* response (§14). A committed plan is `200 A1009` — even when it created
|
|
29
|
-
* something (P3) — with each operation's data wire-encoded in plan order by
|
|
30
|
-
* the same walker as {@link encodeOperationResponse}; a rolled-back plan
|
|
31
|
-
* answers its failing operation's own status (Q4). A step whose result cannot
|
|
32
|
-
* be encoded answers `A3003` → 500 naming that step as `cause.operation`, as
|
|
33
|
-
* every internal failure inside a plan does (Q5).
|
|
34
|
-
*/
|
|
35
16
|
export function encodeTransactionResponse(response, requestId, report) {
|
|
36
17
|
if (response.code !== "A1009") {
|
|
37
18
|
return encodeOperationResponse(response, requestId, report);
|
|
@@ -53,18 +34,12 @@ export function encodeTransactionResponse(response, requestId, report) {
|
|
|
53
34
|
return written(serializationFailure(step), null, requestId);
|
|
54
35
|
}
|
|
55
36
|
}
|
|
56
|
-
/** The one A3003 envelope: the framework's text, plus the step in a plan. */
|
|
57
37
|
function serializationFailure(operation) {
|
|
58
38
|
return operationFailure("A3003", {
|
|
59
39
|
message: SERIALIZATION_FAILURE_MESSAGE,
|
|
60
40
|
...(operation === undefined ? {} : { operation }),
|
|
61
41
|
});
|
|
62
42
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Writes an envelope whose data is already in wire form. Throws for a code
|
|
65
|
-
* with no status (only an untyped caller can supply one), which every caller
|
|
66
|
-
* turns into `A3003`.
|
|
67
|
-
*/
|
|
68
43
|
function written(response, wireData, requestId) {
|
|
69
44
|
const { code, cause } = response;
|
|
70
45
|
if (!Object.hasOwn(httpStatus, code)) {
|
|
@@ -79,37 +54,9 @@ function written(response, wireData, requestId) {
|
|
|
79
54
|
body: JSON.stringify({ data: wireData, code, cause }),
|
|
80
55
|
};
|
|
81
56
|
}
|
|
82
|
-
/**
|
|
83
|
-
* What the walker throws for a value with no wire form — never past an
|
|
84
|
-
* encoder, which answers `A3003` and hands it to the diagnostics channel, so
|
|
85
|
-
* it names the offending value as its `cause` for the developer.
|
|
86
|
-
*/
|
|
87
57
|
function unencodable(value) {
|
|
88
58
|
return new TypeError("A result value has no wire form.", { cause: value });
|
|
89
59
|
}
|
|
90
|
-
/**
|
|
91
|
-
* The P1 wire walker: a result's runtime value as the JSON value the wire
|
|
92
|
-
* carries. Value-directed, with no Contract read: exactly four runtime classes
|
|
93
|
-
* are scalars whose wire form differs from their runtime form (A6), and a
|
|
94
|
-
* `json` value is a `JsonValue`, which contains none of them —
|
|
95
|
-
*
|
|
96
|
-
* - `bigint` → its base-10 string;
|
|
97
|
-
* - `Decimal` (core's) → its decimal string (not through `toJSON`, Q16);
|
|
98
|
-
* - `Date` → `toISOString()`, which must match the datetime wire grammar — an
|
|
99
|
-
* invalid Date, or a year the grammar's four digits cannot spell, has none;
|
|
100
|
-
* - `Uint8Array` → canonical base64.
|
|
101
|
-
*
|
|
102
|
-
* Everything else must already be JSON: `null`, a boolean, a string, a finite
|
|
103
|
-
* number, a list, or a plain record (prototype `Object.prototype` or `null`).
|
|
104
|
-
* A record member whose value is `undefined` is omitted, as JSON omits it; any
|
|
105
|
-
* other value — `undefined` in a list or a hole, a non-finite number, a
|
|
106
|
-
* function, a symbol, any other object, a cycle — has no wire form, and the
|
|
107
|
-
* walk throws. So does a getter or a proxy that throws; the encoders catch all
|
|
108
|
-
* of it.
|
|
109
|
-
*
|
|
110
|
-
* `ancestors` holds the containers on the current path only, so a shared
|
|
111
|
-
* reference is encoded twice, as JSON writes it, while a cycle is refused.
|
|
112
|
-
*/
|
|
113
60
|
function toWire(value, ancestors) {
|
|
114
61
|
switch (typeof value) {
|
|
115
62
|
case "string":
|
|
@@ -163,11 +110,6 @@ function toWireList(list, ancestors) {
|
|
|
163
110
|
}
|
|
164
111
|
return wire;
|
|
165
112
|
}
|
|
166
|
-
/**
|
|
167
|
-
* One list element. A hole has no wire form (JSON would write `null`), and is
|
|
168
|
-
* never filled from the prototype chain; an `undefined` element has none
|
|
169
|
-
* either ({@link toWire}).
|
|
170
|
-
*/
|
|
171
113
|
function toWireElement(list, index, ancestors) {
|
|
172
114
|
if (!Object.hasOwn(list, index)) {
|
|
173
115
|
throw unencodable(list);
|
|
@@ -186,6 +128,5 @@ function toWireRecord(record, ancestors) {
|
|
|
186
128
|
members.push([key, toWire(member, ancestors)]);
|
|
187
129
|
}
|
|
188
130
|
}
|
|
189
|
-
// `fromEntries` defines each member, so an own `__proto__` key stays data.
|
|
190
131
|
return Object.fromEntries(members);
|
|
191
132
|
}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import type { OperationCode } from "../runtime/operation-response.js";
|
|
2
2
|
/**
|
|
3
|
-
* `AvProtocol.httpStatus` — the HTTP status each A-code carries
|
|
4
|
-
* "default HTTP" column), as passive data.
|
|
3
|
+
* `AvProtocol.httpStatus` — the HTTP status each A-code carries, as passive data.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* plan's — and a rolled-back plan answers its failing operation's own status
|
|
10
|
-
* (Q4). The status is the coarse signal; the A-code is the exact one.
|
|
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.
|
|
11
8
|
*
|
|
12
|
-
* Total by type: the literal `satisfies` the mapped type over `OperationCode`,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* it.
|
|
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.
|
|
16
12
|
*/
|
|
17
13
|
export declare const httpStatus: {
|
|
18
14
|
readonly [C in OperationCode]: number;
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `AvProtocol.httpStatus` — the HTTP status each A-code carries (§13.2's
|
|
3
|
-
* "default HTTP" column), as passive data.
|
|
4
|
-
*
|
|
5
|
-
* Status is a function of the code alone (N14): §13.2 gives every code exactly
|
|
6
|
-
* one status, and its success table's two 201s are exactly `A1002` and `A1003`.
|
|
7
|
-
* So this one table serves both encoders — an operation's response and a
|
|
8
|
-
* plan's — and a rolled-back plan answers its failing operation's own status
|
|
9
|
-
* (Q4). The status is the coarse signal; the A-code is the exact one.
|
|
10
|
-
*
|
|
11
|
-
* Total by type: the literal `satisfies` the mapped type over `OperationCode`,
|
|
12
|
-
* so a code added to core does not compile until its status is written here.
|
|
13
|
-
* Passive (P5): numbers only, frozen, emitted by value where a consumer needs
|
|
14
|
-
* it.
|
|
15
|
-
*/
|
|
16
1
|
export const httpStatus = Object.freeze({
|
|
17
2
|
A1000: 200,
|
|
18
3
|
A1001: 200,
|
|
@@ -43,6 +28,7 @@ export const httpStatus = Object.freeze({
|
|
|
43
28
|
A3001: 500,
|
|
44
29
|
A3002: 500,
|
|
45
30
|
A3003: 500,
|
|
31
|
+
A3004: 500,
|
|
46
32
|
A4000: 401,
|
|
47
33
|
A4001: 403,
|
|
48
34
|
A4002: 403,
|
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,37 +1,40 @@
|
|
|
1
1
|
import { type AvProtocolResponse } from "./http-response.encoder.js";
|
|
2
|
+
import type { IdentityHeaderName } from "./protocol-headers.js";
|
|
2
3
|
/**
|
|
3
|
-
* The four transport codes
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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.
|
|
6
7
|
*/
|
|
7
8
|
export type TransportFailureCode = "A2000" | "A2010" | "A2011" | "A2012";
|
|
9
|
+
/**
|
|
10
|
+
* pilot.1 — the `400 A2000` answering a request that did not send an identity
|
|
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.
|
|
13
|
+
*/
|
|
14
|
+
export declare function identityHeadersMissing(missing: readonly IdentityHeaderName[], requestId: string): AvProtocolResponse;
|
|
8
15
|
/**
|
|
9
16
|
* `protocol.failure(code, requestId?)` / `protocol.failure("A2012", requestId,
|
|
10
|
-
* allow)
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* 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.
|
|
14
20
|
*
|
|
15
|
-
* The decoders produce their transport failures through it. A host that
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* 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.
|
|
19
24
|
*
|
|
20
|
-
* `requestId` is echoed as `Aventara-Request-Id
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* 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.
|
|
24
28
|
*
|
|
25
29
|
* `allow` belongs to `A2012`, and `A2012` requires it: every 405 carries the
|
|
26
|
-
* `Allow` header naming the methods its route DOES accept
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* 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"]`.
|
|
30
33
|
*
|
|
31
|
-
* A code outside the four, `A2012` without `allow`, `allow` with any other
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
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.
|
|
35
38
|
*/
|
|
36
39
|
export declare function transportFailure(code: "A2012", requestId: string | undefined, allow: readonly string[]): AvProtocolResponse;
|
|
37
40
|
export declare function transportFailure(code: Exclude<TransportFailureCode, "A2012">, requestId?: string): AvProtocolResponse;
|
|
@@ -1,18 +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
|
-
|
|
10
|
+
export function identityHeadersMissing(missing, requestId) {
|
|
11
|
+
const named = missing.length === 1
|
|
12
|
+
? `The ${missing[0]} header is`
|
|
13
|
+
: `The ${missing.join(" and ")} headers are`;
|
|
14
|
+
return encodeOperationResponse(operationFailure("A2000", { message: `${named} missing.` }), requestIdOf({ requestId }));
|
|
15
|
+
}
|
|
16
16
|
const METHOD_TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
17
17
|
export function transportFailure(code, requestId, allow) {
|
|
18
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,24 +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
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
|
|
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.
|
|
60
|
+
*/
|
|
61
|
+
export declare function missingIdentityHeaders(normalized: Readonly<Record<string, string>>): readonly IdentityHeaderName[];
|
|
62
|
+
/** The two identity headers' names, as the framework spells them. */
|
|
63
|
+
export type IdentityHeaderName = (typeof headers)["protocolVersion"] | (typeof headers)["contractHash"];
|
|
64
|
+
/**
|
|
65
|
+
* A repeated header joins with `", "`, which holds a space, so it is never
|
|
66
|
+
* adopted.
|
|
64
67
|
*/
|
|
65
68
|
export declare function adoptedRequestId(normalized: Readonly<Record<string, string>>): string | undefined;
|
|
66
69
|
export {};
|