@aventara/core 0.1.0-pilot.3 → 1.0.0-rc.0

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.
Files changed (167) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/README.md +100 -3
  3. package/dist/adapters/adapter-discovery-diagnostic.d.ts +2 -0
  4. package/dist/adapters/adapter-field.d.ts +3 -26
  5. package/dist/adapters/adapter-identifier.d.ts +1 -11
  6. package/dist/adapters/adapter-model.d.ts +12 -0
  7. package/dist/adapters/adapter-operation-executor.interface.d.ts +5 -1
  8. package/dist/adapters/adapter-resource.d.ts +7 -28
  9. package/dist/adapters/adapter.interface.d.ts +25 -26
  10. package/dist/compiler/contract-compiler-diagnostic.d.ts +8 -0
  11. package/dist/compiler/contract.compiler.d.ts +11 -22
  12. package/dist/compiler/contract.compiler.js +67 -0
  13. package/dist/config/any-framework-config.d.ts +5 -26
  14. package/dist/config/config-diagnostic.d.ts +2 -0
  15. package/dist/config/config-layer.d.ts +6 -19
  16. package/dist/config/config.resolver.d.ts +9 -14
  17. package/dist/config/config.resolver.js +1 -0
  18. package/dist/config/config.validator.d.ts +6 -3
  19. package/dist/config/config.validator.js +6 -0
  20. package/dist/config/define-fields.d.ts +15 -48
  21. package/dist/config/effective-fields.d.ts +6 -29
  22. package/dist/config/entrypoint.normalizer.d.ts +6 -18
  23. package/dist/config/framework-behaviors-config.d.ts +11 -10
  24. package/dist/config/framework-config.d.ts +19 -16
  25. package/dist/config/framework-fields-config.d.ts +20 -7
  26. package/dist/config/framework-restrictions-config.d.ts +41 -61
  27. package/dist/config/pipeline-config.d.ts +7 -17
  28. package/dist/contracts/capability.d.ts +13 -49
  29. package/dist/contracts/client-contract-structure.validator.d.ts +28 -54
  30. package/dist/contracts/client-contract-structure.validator.js +99 -2
  31. package/dist/contracts/contract-canonicalizer.d.ts +4 -6
  32. package/dist/contracts/contract-canonicalizer.js +32 -0
  33. package/dist/contracts/contract-hash.d.ts +3 -2
  34. package/dist/contracts/contract-limits.d.ts +7 -1
  35. package/dist/contracts/contract-protocol.d.ts +7 -8
  36. package/dist/contracts/contract.d.ts +20 -4
  37. package/dist/contracts/enum-definition.d.ts +2 -0
  38. package/dist/contracts/field.d.ts +40 -167
  39. package/dist/contracts/identifier.d.ts +1 -16
  40. package/dist/contracts/json-shape.d.ts +65 -0
  41. package/dist/contracts/json-shape.js +1 -0
  42. package/dist/contracts/lifecycle-trait.d.ts +4 -3
  43. package/dist/contracts/reference-write-limit.d.ts +7 -0
  44. package/dist/contracts/reference-write-limit.js +1 -0
  45. package/dist/contracts/resource-operations.d.ts +2 -62
  46. package/dist/contracts/resource.d.ts +2 -0
  47. package/dist/contracts/scalar-value-type.d.ts +28 -48
  48. package/dist/contracts/scalar.d.ts +4 -3
  49. package/dist/contracts/transaction-capability.d.ts +2 -0
  50. package/dist/contracts/wire-scalar-format.d.ts +6 -21
  51. package/dist/framework/contract-view.d.ts +152 -130
  52. package/dist/framework/framework-construction.error.d.ts +6 -1
  53. package/dist/framework/framework.d.ts +33 -46
  54. package/dist/framework/framework.factory.d.ts +3 -17
  55. package/dist/framework/framework.factory.js +56 -13
  56. package/dist/framework/operation-facade.d.ts +3 -7
  57. package/dist/index.d.ts +8 -40
  58. package/dist/index.js +0 -20
  59. package/dist/internal.d.ts +35 -0
  60. package/dist/internal.js +16 -0
  61. package/dist/json/avz.d.ts +96 -0
  62. package/dist/json/avz.js +212 -0
  63. package/dist/json/index.d.ts +6 -0
  64. package/dist/json/index.js +1 -0
  65. package/dist/json/json-shape.registry.d.ts +22 -0
  66. package/dist/json/json-shape.registry.js +16 -0
  67. package/dist/json/zod-issue.translator.d.ts +51 -0
  68. package/dist/json/zod-issue.translator.js +142 -0
  69. package/dist/operations/operation-arguments.d.ts +198 -303
  70. package/dist/operations/operation-call.d.ts +13 -15
  71. package/dist/operations/operation-identity.d.ts +6 -2
  72. package/dist/operations/operation-identity.js +3 -0
  73. package/dist/operations/operation-result.d.ts +15 -61
  74. package/dist/operations/operation-validator-core.d.ts +6 -5
  75. package/dist/operations/operation-validator-core.js +28 -10
  76. package/dist/operations/operation-validator.d.ts +22 -9
  77. package/dist/operations/operation-validator.js +26 -10
  78. package/dist/operations/projection-scope.resolver.d.ts +1 -11
  79. package/dist/operations/structural-limits.walker.d.ts +19 -0
  80. package/dist/operations/structural-limits.walker.js +344 -0
  81. package/dist/operations/validation-code.d.ts +5 -17
  82. package/dist/operations/write-scope.resolver.d.ts +3 -28
  83. package/dist/protocol/absent-route.responder.d.ts +25 -39
  84. package/dist/protocol/absent-route.responder.js +32 -6
  85. package/dist/protocol/av-protocol.d.ts +2 -8
  86. package/dist/protocol/contract-document.responder.d.ts +5 -18
  87. package/dist/protocol/http-request.decoder.d.ts +18 -59
  88. package/dist/protocol/http-request.decoder.js +11 -3
  89. package/dist/protocol/http-request.reader.d.ts +5 -5
  90. package/dist/protocol/http-response.encoder.d.ts +14 -20
  91. package/dist/protocol/http-status.table.d.ts +0 -8
  92. package/dist/protocol/index.d.ts +2 -7
  93. package/dist/protocol/operation-response.guard.d.ts +0 -15
  94. package/dist/protocol/protocol-failure.d.ts +8 -27
  95. package/dist/protocol/protocol-headers.d.ts +15 -42
  96. package/dist/protocol/protocol-surface.d.ts +0 -22
  97. package/dist/protocol/protocol.binder.d.ts +19 -27
  98. package/dist/protocol/protocol.binder.js +3 -1
  99. package/dist/protocol/protocol.handler.d.ts +19 -23
  100. package/dist/protocol/protocol.handler.js +14 -4
  101. package/dist/protocol/unmounted-route.error.d.ts +19 -0
  102. package/dist/protocol/unmounted-route.error.js +10 -0
  103. package/dist/runtime/caller-data.copier.d.ts +59 -0
  104. package/dist/runtime/caller-data.copier.js +470 -0
  105. package/dist/runtime/caller-data.door.d.ts +56 -0
  106. package/dist/runtime/caller-data.door.js +65 -0
  107. package/dist/runtime/computed-read-runtime.js +3 -10
  108. package/dist/runtime/computed-value.error.d.ts +13 -0
  109. package/dist/runtime/computed-value.error.js +9 -0
  110. package/dist/runtime/create-requirement.d.ts +43 -7
  111. package/dist/runtime/create-requirement.js +89 -9
  112. package/dist/runtime/decimal.d.ts +5 -3
  113. package/dist/runtime/diagnostics-reporter.d.ts +33 -37
  114. package/dist/runtime/diagnostics-reporter.js +11 -4
  115. package/dist/runtime/error-boundary.d.ts +14 -10
  116. package/dist/runtime/error-boundary.js +65 -35
  117. package/dist/runtime/execution-options.d.ts +3 -7
  118. package/dist/runtime/field-behavior.d.ts +14 -21
  119. package/dist/runtime/framework-error.d.ts +14 -2
  120. package/dist/runtime/json-value.d.ts +7 -15
  121. package/dist/runtime/misuse-reporter.d.ts +32 -0
  122. package/dist/runtime/misuse-reporter.js +19 -0
  123. package/dist/runtime/mutation-planner.d.ts +6 -12
  124. package/dist/runtime/mutation-planner.js +13 -11
  125. package/dist/runtime/operation-request.d.ts +11 -11
  126. package/dist/runtime/operation-response.d.ts +18 -23
  127. package/dist/runtime/operation-runtime.d.ts +25 -33
  128. package/dist/runtime/operation-runtime.js +37 -18
  129. package/dist/runtime/outcome-mapper.js +12 -2
  130. package/dist/runtime/output-validator.d.ts +10 -0
  131. package/dist/runtime/output-validator.js +11 -0
  132. package/dist/runtime/owned-execution.registry.d.ts +13 -0
  133. package/dist/runtime/owned-execution.registry.js +7 -0
  134. package/dist/runtime/pipeline.d.ts +33 -36
  135. package/dist/runtime/referential-action.d.ts +8 -26
  136. package/dist/runtime/request-envelope.validator.d.ts +5 -0
  137. package/dist/runtime/request-envelope.validator.js +118 -0
  138. package/dist/runtime/request-id.d.ts +3 -10
  139. package/dist/runtime/scalar-runtime.d.ts +42 -14
  140. package/dist/runtime/scalar-runtime.js +162 -79
  141. package/dist/transactions/deferred-operation.d.ts +10 -21
  142. package/dist/transactions/operation-arguments-encoder.d.ts +1 -0
  143. package/dist/transactions/operation-fingerprint.d.ts +3 -1
  144. package/dist/transactions/transaction-envelope.d.ts +2 -4
  145. package/dist/transactions/transaction-integrity-error.d.ts +4 -15
  146. package/dist/transactions/transaction-plan-assembler.d.ts +6 -1
  147. package/dist/transactions/transaction-plan-assembler.js +74 -75
  148. package/dist/transactions/transaction-plan-validator.d.ts +33 -24
  149. package/dist/transactions/transaction-plan-validator.js +204 -153
  150. package/dist/transactions/transaction-reference-collector.d.ts +30 -0
  151. package/dist/transactions/transaction-reference-collector.js +204 -0
  152. package/dist/transactions/transaction-reference-resolver.d.ts +9 -12
  153. package/dist/transactions/transaction-reference-resolver.js +10 -5
  154. package/dist/transactions/transaction-reference-validator.js +24 -17
  155. package/dist/transactions/transaction-reference.d.ts +31 -64
  156. package/dist/transactions/transaction-request.d.ts +6 -8
  157. package/dist/transactions/transaction-response.d.ts +10 -7
  158. package/dist/transactions/transaction-response.js +24 -1
  159. package/dist/transactions/transaction-runtime.d.ts +7 -5
  160. package/dist/transactions/transaction-runtime.js +4 -3
  161. package/dist/transactions/transaction-slot-path-error.d.ts +5 -15
  162. package/dist/transactions/transaction-slot-writer.d.ts +3 -13
  163. package/package.json +17 -3
  164. package/dist/operations/operation-boolean-nodes.d.ts +0 -11
  165. package/dist/operations/operation-boolean-nodes.js +0 -283
  166. package/dist/operations/operation-nesting.d.ts +0 -8
  167. package/dist/operations/operation-nesting.js +0 -307
@@ -2,13 +2,7 @@ import type { FrameworkContracts } from "../compiler/contract.compiler.js";
2
2
  import type { ClientOperationRequest } from "../runtime/operation-request.js";
3
3
  import type { ClientTransactionRequest } from "../transactions/transaction-request.js";
4
4
  import type { AvProtocolResponse } from "./http-response.encoder.js";
5
- /**
6
- * One HTTP request as a host hands it to the protocol: what the decoders read, and
7
- * what each row of the fixture corpus carries as its `request`.
8
- *
9
- * Host-independent by construction: no host's request object, only the four facts
10
- * every host can supply.
11
- */
5
+ /** One HTTP request as a host hands it to the protocol. */
12
6
  export type AvProtocolRequest = {
13
7
  /** The HTTP method as received. Anything but `POST` on a framework route is `A2012`. */
14
8
  readonly method: string;
@@ -27,13 +21,6 @@ export type AvProtocolRequest = {
27
21
  /**
28
22
  * The body, in one of two explicitly named arms — the decoder never guesses which
29
23
  * one it was given:
30
- *
31
- * - `raw`: the decoded body as received, bytes or text. The decoder enforces all
32
- * of it: the size limit (`A2010`), the content type (`A2011`), JSON syntax and
33
- * the body's shape (`A2000`). An absent body is zero bytes (`""`).
34
- * - `parsed`: a value the host's own JSON parser already produced. Size, content
35
- * type and JSON syntax were the host's to enforce before the decoder ran; the
36
- * decoder still refuses a non-object shape (`A2000`).
37
24
  */
38
25
  readonly body: {
39
26
  readonly kind: "raw";
@@ -44,9 +31,9 @@ export type AvProtocolRequest = {
44
31
  };
45
32
  };
46
33
  /**
47
- * What a decoder answers: the request core executes, or the framework response
48
- * that answers the HTTP request instead — and, either way, the request id it runs
49
- * or is answered under, which the host passes to the encoder:
34
+ * What a decoder answers: the request core executes, or the framework response that
35
+ * answers the HTTP request instead — and, either way, the request id it runs or is
36
+ * answered under, which the host passes to the encoder:
50
37
  * `protocol.encodeOperation(response, decoded.requestId)`.
51
38
  */
52
39
  type Decoded<Request> = {
@@ -67,51 +54,23 @@ export type DecodedOperationRequest = Extract<DecodedOperation, {
67
54
  /** What `protocol.decodeTransaction` answers. */
68
55
  export type DecodedTransaction = Decoded<ClientTransactionRequest>;
69
56
  /**
70
- * `protocol.decodeOperation(request)` — one operation route's HTTP request as the
71
- * client-origin request `framework.execute` takes, or its answer.
72
- *
73
- * Total over ANY value: a value that is not an `AvProtocolRequest` at all — not an
74
- * object, a missing or mistyped member, a member behind a getter or trap that
75
- * throws — is malformed, `A2000` under a minted id, before anything else is read;
76
- * nothing it carries is believed. Otherwise, in order, each step answering before
77
- * the next runs:
78
- *
79
- * 1. the request id: `Aventara-Request-Id` adopted when it is 1–128 visible ASCII
80
- * characters, otherwise minted by core's one helper — never a refusal;
81
- * 2. the path: `/_resources/<resource>/<family>/<variant>`, each segment
82
- * URL-decoded once and none empty, or `A2000`;
83
- * 3. identity and absence, with no body read: a request missing either identity
84
- * header is malformed; then the protocol version (`A2006`), the ClientContract
85
- * hash (`A2005`), the Resource (`A2001`) and the operation (`A2002`), each
86
- * core's own envelope — so an unadvertised triple never reaches `execute`, in
87
- * either route style;
88
- * 4. the method: anything but `POST` is `A2012`, carrying `Allow: POST` (RFC 9110
89
- * §15.5.6);
90
- * 5. the body. On the RAW arm the decoder enforces all of it: the content type
91
- * must be `application/json` (`A2011`; parameters are not read), the decoded
92
- * byte count must not exceed the ClientContract's `limits.maxRequestBytes`, and
93
- * the bytes must be UTF-8 JSON (`A2000`). On the PARSED arm the host's own
94
- * parser already read the bytes, so size, content type and JSON syntax were the
95
- * HOST's to enforce — answering its parser's failures with `protocol.failure` —
96
- * and the decoder checks none of them. Both arms then refuse a body that is not
97
- * a JSON object — an array, a scalar, `null`, or none (`A2000`). One gap is the
98
- * host's by construction: a parser that turns an absent body into `{}` makes
99
- * absence indistinguishable from `{}`, which is valid.
100
- *
101
- * The request is client origin, always: nothing the caller sends spells
102
- * application origin. `transport` carries `POST` and the request's headers. The
103
- * body is the operation's arguments verbatim: the decoder never reads into it, so
104
- * routing metadata in it is core's to refuse, and a parsed body reaches core as
105
- * the same object.
57
+ * `protocol.decodeOperation(request)` — one operation route's HTTP request as
58
+ * the client-origin request `framework.execute` takes, or its answer.
106
59
  */
107
60
  export declare function decodeOperationRequest(contracts: FrameworkContracts, received: AvProtocolRequest): DecodedOperation;
108
61
  /**
109
- * `protocol.decodeTransaction(request)` — the `/_transactions` request as the
110
- * client-origin plan request `framework.executeTransaction` takes, or its answer.
111
- * The same steps as {@link decodeOperationRequest}, with the path exactly
112
- * `/_transactions` and its absence being a ClientContract without interactive
113
- * transactions. Every step of the plan then runs under ClientContract rules: the
114
- * plan is client origin and cannot say otherwise. The body is the plan verbatim.
62
+ * `protocol.decodeTransaction(request)` — the `/_transactions` request as the client-
63
+ * origin plan request `framework.executeTransaction` takes, or its answer. The same
64
+ * steps as {@link decodeOperationRequest}, with the path exactly `/_transactions` and
65
+ * its absence being a ClientContract without interactive transactions. Every step of
66
+ * the plan then runs under ClientContract rules: the plan is client origin and cannot
67
+ * say otherwise. The body is the plan verbatim.
115
68
  */
116
69
  export declare function decodeTransactionRequest(contracts: FrameworkContracts, received: AvProtocolRequest): DecodedTransaction;
70
+ /**
71
+ * Whether `value` is a body this decoder parsed from raw content. Only the protocol's
72
+ * own shortcuts ask, about a request they have just decoded, before any host code
73
+ * could hold it; it is exported from no entry point.
74
+ */
75
+ export declare function isParsedByDecoder(value: unknown): boolean;
117
76
  export {};
@@ -16,7 +16,7 @@ export function decodeOperationRequest(contracts, received) {
16
16
  ? {
17
17
  ok: true,
18
18
  request: {
19
- scope: "client",
19
+ origin: "client",
20
20
  requestId: read.requestId,
21
21
  resource: route.resource,
22
22
  ...route.operation,
@@ -42,7 +42,7 @@ export function decodeTransactionRequest(contracts, received) {
42
42
  ? {
43
43
  ok: true,
44
44
  request: {
45
- scope: "client",
45
+ origin: "client",
46
46
  requestId: read.requestId,
47
47
  protocol: route.protocol,
48
48
  transport: transportOf(read),
@@ -85,7 +85,15 @@ function bodyValue(body, contentType, maxRequestBytes) {
85
85
  catch {
86
86
  return "A2000";
87
87
  }
88
- return isJsonObject(value) ? { value } : "A2000";
88
+ if (!isJsonObject(value)) {
89
+ return "A2000";
90
+ }
91
+ PARSED_HERE.add(value);
92
+ return { value };
93
+ }
94
+ const PARSED_HERE = new WeakSet();
95
+ export function isParsedByDecoder(value) {
96
+ return typeof value === "object" && value !== null && PARSED_HERE.has(value);
89
97
  }
90
98
  function isJsonMediaType(contentType) {
91
99
  return (contentType
@@ -11,9 +11,9 @@ export declare const POST_ONLY: readonly string[];
11
11
  /** The methods the contract route accepts: `GET`, only. */
12
12
  export declare const GET_ONLY: readonly string[];
13
13
  /**
14
- * Whether a path lies in the protocol's namespace: underscore-prefixed paths
15
- * beneath the entrypoint are reserved for framework facilities; every other path
16
- * is the host's.
14
+ * Whether a path lies in the protocol's namespace: underscore-prefixed paths beneath
15
+ * the entrypoint are reserved for framework facilities; every other path is the
16
+ * host's.
17
17
  */
18
18
  export declare function isProtocolPath(path: string): boolean;
19
19
  /** A request the protocol could read, with what every route reads off it first. */
@@ -34,8 +34,8 @@ export type UnreadableRequest = {
34
34
  readonly requestId: string;
35
35
  };
36
36
  /**
37
- * The host's value read as a request, or — when it is not an `AvProtocolRequest`
38
- * at all — the `400 A2000` answering it, under a minted id.
37
+ * The host's value read as a request, or — when it is not an `AvProtocolRequest` at
38
+ * all — the `400 A2000` answering it, under a minted id.
39
39
  */
40
40
  export declare function readRequest(received: unknown): ReadRequest | UnreadableRequest;
41
41
  /**
@@ -10,37 +10,31 @@ export type AvProtocolResponse = {
10
10
  /** `AvProtocol.httpStatus` of the envelope's code. */
11
11
  readonly status: number;
12
12
  /**
13
- * The headers the framework owns on this response, canonically spelled:
14
- * `Content-Type: application/json` and the `Aventara-Request-Id` it echoes.
13
+ * The headers to send, canonically spelled: `Content-Type: application/json`
14
+ * and the echoed `Aventara-Request-Id`.
15
15
  */
16
16
  readonly headers: Readonly<Record<string, string>>;
17
17
  /** The JSON text of the envelope, its data in wire forms. */
18
18
  readonly body: string;
19
19
  };
20
20
  /**
21
- * Where an encoder hands the raw failure behind an `A3003` — the binding's
22
- * diagnostics channel — with the plan step it blames, if any. The wire never
23
- * carries it.
21
+ * Where an encoder hands the raw failure behind an `A3003` — the binding's diagnostics
22
+ * channel — with the plan step it blames, if any. The wire never carries it.
24
23
  */
25
24
  export type UnencodableReport = (error: unknown, operation?: number) => void;
26
25
  /**
27
- * `protocol.encodeOperation(response, requestId)`: one operation's framework
28
- * 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.
31
- *
32
- * Total: a result it cannot encode — and a response whose code is not allocated —
33
- * answers `A3003` → 500 with the framework's own text, and none of the result
34
- * reaches the body.
26
+ * `protocol.encodeOperation(response, requestId)`: one operation's framework response
27
+ * as the HTTP response a host writes. Status is the code's; `data` is wire-encoded;
28
+ * `requestId` is echoed as `Aventara-Request-Id` — pass the id the request ran under,
29
+ * which the decoder supplies.
35
30
  */
36
31
  export declare function encodeOperationResponse(response: OperationResponse, requestId: string, report?: UnencodableReport): AvProtocolResponse;
37
32
  /**
38
- * `protocol.encodeTransaction(response, requestId)`: the same for a plan's
39
- * 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.
33
+ * `protocol.encodeTransaction(response, requestId)`: the same for a plan's response. A
34
+ * committed plan is `200 A1009` — even when it created something — with each
35
+ * operation's data wire-encoded in plan order by the same walker as {@link
36
+ * encodeOperationResponse}; a rolled-back plan answers its failing operation's own
37
+ * status. A step whose result cannot be encoded answers `A3003` → 500 naming that step
38
+ * as `cause.operation`, as every internal failure inside a plan does.
45
39
  */
46
40
  export declare function encodeTransactionResponse(response: TransactionResponse, requestId: string, report?: UnencodableReport): AvProtocolResponse;
@@ -1,14 +1,6 @@
1
1
  import type { OperationCode } from "../runtime/operation-response.js";
2
2
  /**
3
3
  * `AvProtocol.httpStatus` — the HTTP status each A-code carries, as passive data.
4
- *
5
- * So this one table serves both encoders — an operation's response and a plan's —
6
- * and a rolled-back plan answers its failing operation's own status. The status is
7
- * the coarse signal; the A-code is the exact one.
8
- *
9
- * Total by type: the literal `satisfies` the mapped type over `OperationCode`, so
10
- * a code added to core does not compile until its status is written here. Passive:
11
- * numbers only, frozen, emitted by value where a consumer needs it.
12
4
  */
13
5
  export declare const httpStatus: {
14
6
  readonly [C in OperationCode]: number;
@@ -1,11 +1,6 @@
1
1
  /**
2
- * `@aventara/core/protocol` — the HTTP protocol, as passive data and pure
3
- * functions over core. It mounts nothing and imports no HTTP library.
4
- *
5
- * The direction is one-way: this entry may import core's internals, and no module
6
- * of core's execution side imports anything under `protocol/`
7
- * (`protocol-direction.spec.ts`). The main `@aventara/core` entry exports no name
8
- * from here.
2
+ * `@aventara/core/protocol` — the HTTP protocol, as passive data and pure functions
3
+ * over core. It mounts nothing and imports no HTTP library.
9
4
  */
10
5
  export * as AvProtocol from "./av-protocol.js";
11
6
  export type { AvProtocolRequest } from "./http-request.decoder.js";
@@ -1,20 +1,5 @@
1
1
  import { type OperationResponse } from "../runtime/operation-response.js";
2
2
  /**
3
3
  * The HTTP status plays no part — a code is read even at an unexpected status.
4
- *
5
- * `value` is the body as parsed JSON, or `undefined` when there was no body or it
6
- * was not JSON (neither is an envelope). An envelope here is:
7
- *
8
- * - an object (not an array) with an own `data` member and an allocated `code`;
9
- * - for an A1xxx code, a `cause` of exactly `null`, and `data` of `null` when the
10
- * code is `A1001`;
11
- * - for every other code, `data` of `null` and a cause: an object whose `message`
12
- * is a string, whose `issues`, if present, is a list of objects each with an
13
- * allocated V-code, a string `message` and, if present, a `path` of strings and
14
- * integers, and whose `operation`, if present, is a non-negative integer.
15
- *
16
- * The generated client's own check (`envelopeOf` in its emitted transport) is held
17
- * to agree with this one on every row of the fixture corpus's family 11, so the
18
- * two cannot drift apart silently.
19
4
  */
20
5
  export declare function isOperationResponse(value: unknown): value is OperationResponse;
@@ -1,40 +1,21 @@
1
1
  import { type AvProtocolResponse } from "./http-response.encoder.js";
2
2
  import type { IdentityHeaderName } from "./protocol-headers.js";
3
3
  /**
4
- * The four transport codes: failures of the HTTP request itself, which the
5
- * protocol answers before any operation exists, so no execution path produces
6
- * them. Module type — not an entry export.
4
+ * The four transport codes: failures of the HTTP request itself, which the protocol
5
+ * answers before any operation exists, so no execution path produces them. Module type
6
+ * — not an entry export.
7
7
  */
8
8
  export type TransportFailureCode = "A2000" | "A2010" | "A2011" | "A2012";
9
9
  /**
10
- * 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.
10
+ * The `400 A2000` answering a request that did not send an identity header: its
11
+ * message names the missing header or headers and echoes nothing the request sent.
13
12
  */
14
13
  export declare function identityHeadersMissing(missing: readonly IdentityHeaderName[], requestId: string): AvProtocolResponse;
15
14
  /**
16
15
  * `protocol.failure(code, requestId?)` / `protocol.failure("A2012", requestId,
17
- * allow)`: a transport code as the complete framework response — the envelope `{
18
- * data: null, code, cause: { message } }`, encoded exactly as
19
- * `protocol.encodeOperation` encodes it, at the code's status.
20
- *
21
- * The decoders produce their transport failures through it. A host that parses the
22
- * body itself answers its own parser's failures with it — `A2000` for text that is
23
- * not JSON, `A2010` for a body over the limit, `A2011` for another content type.
24
- *
25
- * `requestId` is echoed as `Aventara-Request-Id`: pass the id the decoder gave the
26
- * request when there is one. When there is none — or it is empty — core mints one
27
- * through its one helper, so a failure is never refused or left uncorrelated.
28
- *
29
- * `allow` belongs to `A2012`, and `A2012` requires it: every 405 carries the
30
- * `Allow` header naming the methods its route DOES accept, joined with `", "` —
31
- * `[]` is RFC 9110's "no method", still a header. `failure` knows no route, so the
32
- * caller names the methods; the decoders pass `["POST"]`.
33
- *
34
- * A code outside the four, `A2012` without `allow`, `allow` with any other code,
35
- * or a method that is not an RFC 9110 token is a programming error that the type
36
- * already refuses; an untyped caller gets a `TypeError`, and no envelope or header
37
- * is invented for it.
16
+ * allow)`: a transport code as the complete framework response — the envelope `{ data:
17
+ * null, code, cause: { message } }`, encoded exactly as `protocol.encodeOperation`
18
+ * encodes it, at the code's status.
38
19
  */
39
20
  export declare function transportFailure(code: "A2012", requestId: string | undefined, allow: readonly string[]): AvProtocolResponse;
40
21
  export declare function transportFailure(code: Exclude<TransportFailureCode, "A2012">, requestId?: string): AvProtocolResponse;
@@ -1,21 +1,5 @@
1
1
  import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
2
- /**
3
- * `AvProtocol.headers` — the header names the protocol owns, as passive data.
4
- *
5
- * - `protocolVersion`, `contractHash`: the two identity headers every
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.
10
- *
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.
14
- *
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.
18
- */
2
+ /** `AvProtocol.headers` — the header names the protocol owns, as passive data. */
19
3
  export declare const headers: Readonly<{
20
4
  readonly protocolVersion: "Aventara-Protocol-Version";
21
5
  readonly contractHash: "Aventara-Contract-Hash";
@@ -24,46 +8,35 @@ export declare const headers: Readonly<{
24
8
  /** A request's headers as a host hands them over (`AvProtocolRequest.headers`). */
25
9
  type ReceivedHeaders = Readonly<Record<string, string | readonly string[] | undefined>>;
26
10
  /**
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
30
- * dropped as absent. Values are otherwise as received. This is what a client
31
- * request's `transport.headers` carries to the developer's pipelines, and what
32
- * every header read below reads.
33
- *
34
- * Built with `Object.fromEntries`, so a header named `__proto__` stays data.
11
+ * The request's headers as one spelling: names lower-cased, a repeated header's values
12
+ * — a list, or one name received in several casings — joined with `", "` in the order
13
+ * received, and an `undefined` entry or an empty list dropped as absent. Values are
14
+ * otherwise as received. This is what a client request's `transport.headers` carries
15
+ * to the developer's pipelines, and what every header read below reads.
35
16
  */
36
17
  export declare function normalizeHeaders(received: ReceivedHeaders): Readonly<Record<string, string>>;
37
18
  /**
38
- * One header's value as the framework reads it, from {@link normalizeHeaders}'
39
- * output: surrounding spaces and tabs are not part of a field value (RFC 9110
40
- * §5.5), so they are removed. `undefined` when the header is absent.
19
+ * One header's value as the framework reads it, from {@link normalizeHeaders}' output:
20
+ * surrounding spaces and tabs are not part of a field value, so they are removed.
21
+ * `undefined` when the header is absent.
41
22
  */
42
23
  export declare function headerValue(normalized: Readonly<Record<string, string>>, name: string): string | undefined;
43
24
  /**
44
25
  * 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.
47
- *
48
- * Present values are read, never judged: whether they match is the Framework
49
- * Validation Layer's call (cross-phase invariant 13), made by core's one
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.
26
+ * when either is ABSENT — a request without them is malformed: it does not say which
27
+ * protocol and ClientContract it speaks, so there is nothing to compare.
54
28
  */
55
29
  export declare function protocolIdentityOf(normalized: Readonly<Record<string, string>>): ClientProtocolIdentity | undefined;
56
30
  /**
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.
31
+ * The identity headers a request did not send, in the order the framework sends them —
32
+ * what the `A2000` answering it names. Empty exactly when {@link protocolIdentityOf}
33
+ * reads an identity.
60
34
  */
61
35
  export declare function missingIdentityHeaders(normalized: Readonly<Record<string, string>>): readonly IdentityHeaderName[];
62
36
  /** The two identity headers' names, as the framework spells them. */
63
37
  export type IdentityHeaderName = (typeof headers)["protocolVersion"] | (typeof headers)["contractHash"];
64
38
  /**
65
- * A repeated header joins with `", "`, which holds a space, so it is never
66
- * adopted.
39
+ * A repeated header joins with `", "`, which holds a space, so it is never adopted.
67
40
  */
68
41
  export declare function adoptedRequestId(normalized: Readonly<Record<string, string>>): string | undefined;
69
42
  export {};
@@ -3,16 +3,6 @@ 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
5
  * ClientContract, tagged by `kind`.
6
- *
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"`.
16
6
  */
17
7
  export type SurfaceRoute = ({
18
8
  readonly kind: "operation";
@@ -33,17 +23,5 @@ export type SurfaceRoute = ({
33
23
  * deep-frozen — exactly the advertised operation triples in the Contract's own key
34
24
  * order, then `GET /_contract`, then `POST /_transactions` when, and only when,
35
25
  * `transactions === "interactive"`.
36
- *
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.
48
26
  */
49
27
  export declare function surfaceOf(client: ClientContract): readonly SurfaceRoute[];
@@ -6,9 +6,8 @@ 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` 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.
9
+ * The protocol bound to one Framework instance, as `AvProtocol.bind` returns
10
+ * it. Bind once at startup and call these members per request.
12
11
  */
13
12
  export type AvProtocolBinding = {
14
13
  /**
@@ -19,10 +18,6 @@ export type AvProtocolBinding = {
19
18
  * `transactions` is `"interactive"`. Each path is relative to
20
19
  * `framework.entrypoint`. Read once at bind time: every call answers the same
21
20
  * deep-frozen list, which is passive data a host may serialize.
22
- *
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.
26
21
  */
27
22
  readonly surface: () => readonly SurfaceRoute[];
28
23
  /**
@@ -42,9 +37,9 @@ export type AvProtocolBinding = {
42
37
  readonly decodeTransaction: (request: AvProtocolRequest) => DecodedTransaction;
43
38
  /**
44
39
  * 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
40
+ * HTTP response a host writes: the code's status, `data` in wire forms, `Aventara-
41
+ * Request-Id` echoed. A result with no wire form answers `A3003` → 500. A
42
+ * diagnostic of one operation names it (`resource`, `family`, `variant`), so the
48
43
  * `A3003` reaches the diagnostics sink only when the host passes `decoded` —
49
44
  * `decodeOperation`'s success value — as `handleOperation` does; without it the
50
45
  * answer is the same and nothing is reported.
@@ -53,15 +48,15 @@ export type AvProtocolBinding = {
53
48
  /**
54
49
  * The same for `/_transactions` — what `framework.executeTransaction` answered. An
55
50
  * `A3003` is reported to the Framework's diagnostics sink as a `"transaction"`
56
- * diagnostic — client scope, this `requestId`, the step it blames as `operation` —
51
+ * diagnostic — client origin, this `requestId`, the step it blames as `operation` —
57
52
  * with the value that had no wire form (or what its getter threw) as `error`.
58
53
  */
59
54
  readonly encodeTransaction: (response: TransactionResponse, requestId: string) => AvProtocolResponse;
60
55
  /**
61
56
  * A transport code — `A2000`, `A2010`, `A2011` or `A2012` — as the complete
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`.
57
+ * framework response. For a host that parses the body itself and must answer
58
+ * its parser's failure. `A2012` requires the methods its route allows, so
59
+ * every 405 carries `Allow`.
65
60
  */
66
61
  readonly failure: typeof transportFailure;
67
62
  /**
@@ -89,22 +84,19 @@ export type AvProtocolBinding = {
89
84
  */
90
85
  readonly encodeContract: (request: AvProtocolRequest) => AvProtocolResponse;
91
86
  /**
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.
87
+ * The fallback for every path a host did not mount from `surface()`. It reads
88
+ * no body, runs no pipeline and calls no Adapter. It answers `A2000`, `A2006`,
89
+ * `A2005`, `A2001`, `A2002` or `A2012` (with `Allow`) as the operation routes
90
+ * would, `500 A3000` for a mounted route reached with its own method, and
91
+ * `undefined` for a path outside the protocol's namespace, which the host
92
+ * answers itself. An operation or `/_transactions` route answered `500 A3000`
93
+ * is also reported once to the Framework's diagnostics sink, as an
94
+ * `UnmountedRouteError` naming the route the host did not mount.
99
95
  */
100
96
  readonly answerAbsent: (request: AvProtocolRequest) => AvProtocolResponse | undefined;
101
97
  };
102
98
  /**
103
- * `AvProtocol.bind(framework)`: reads the instance's compiled ClientContract once
104
- * and returns the bound members, frozen.
105
- *
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.
99
+ * `AvProtocol.bind(framework)`: reads the instance's compiled ClientContract
100
+ * once and returns the bound members, frozen.
109
101
  */
110
102
  export declare function bind(framework: Framework): AvProtocolBinding;
@@ -1,4 +1,5 @@
1
1
  import { diagnosticsSinkOf } from "../runtime/diagnostics-reporter.js";
2
+ import { ownedExecutionOf } from "../runtime/owned-execution.registry.js";
2
3
  import { answerAbsentRequest } from "./absent-route.responder.js";
3
4
  import { contractDocumentOf, encodeContractRequest, } from "./contract-document.responder.js";
4
5
  import { decodeOperationRequest, decodeTransactionRequest, } from "./http-request.decoder.js";
@@ -15,6 +16,7 @@ export function bind(framework) {
15
16
  contracts,
16
17
  execute: (request) => framework.execute(request),
17
18
  executeTransaction: (request) => framework.executeTransaction(request),
19
+ owned: ownedExecutionOf(framework),
18
20
  sink,
19
21
  };
20
22
  return Object.freeze({
@@ -29,6 +31,6 @@ export function bind(framework) {
29
31
  handleOperation: (request) => handleOperationRequest(handler, request),
30
32
  handleTransaction: (request) => handleTransactionRequest(handler, request),
31
33
  encodeContract: (request) => encodeContractRequest(document, request),
32
- answerAbsent: (request) => answerAbsentRequest(contracts, request),
34
+ answerAbsent: (request) => answerAbsentRequest(contracts, request, sink),
33
35
  });
34
36
  }
@@ -2,47 +2,43 @@ import type { FrameworkContracts } from "../compiler/contract.compiler.js";
2
2
  import type { Framework } from "../framework/framework.js";
3
3
  import { type FrameworkDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
4
4
  import type { ClientOperationRequest } from "../runtime/operation-request.js";
5
+ import type { OwnedExecution } from "../runtime/owned-execution.registry.js";
5
6
  import { type AvProtocolRequest } from "./http-request.decoder.js";
6
7
  import { type AvProtocolResponse, type UnencodableReport } from "./http-response.encoder.js";
7
8
  /**
8
- * What the shortcuts read off the bound Framework: its compiled Contracts, the
9
- * execution seam, and its configured diagnostics sink.
9
+ * What the shortcuts read off the bound Framework: its compiled Contracts, its
10
+ * execution entry points — the public ones, and the owned ones that run a body this
11
+ * decoder parsed without copying it again (absent for anything but a
12
+ * constructed Framework) — and its configured diagnostics sink.
10
13
  */
11
14
  export type HandlerContext = {
12
15
  readonly contracts: FrameworkContracts;
13
16
  readonly execute: Framework["execute"];
14
17
  readonly executeTransaction: Framework["executeTransaction"];
18
+ readonly owned: OwnedExecution | undefined;
15
19
  readonly sink: FrameworkDiagnosticsSink | undefined;
16
20
  };
17
21
  /**
18
- * Where a plan's `A3003` goes: the Framework's diagnostics sink, as a
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`.
22
+ * Where a plan's `A3003` goes: the Framework's diagnostics sink, as a `"transaction"`
23
+ * diagnostic — client origin, the request id the plan ran under, and the step the
24
+ * encoder blames as `operation` when it blames one. One spelling for both
25
+ * `protocol.encodeTransaction` and `protocol.handleTransaction`.
22
26
  */
23
27
  export declare function planUnencodableReport(sink: FrameworkDiagnosticsSink | undefined, requestId: string): UnencodableReport;
24
28
  /**
25
29
  * Where one operation's `A3003` goes: the Framework's diagnostics sink, as an
26
- * `"operation"` diagnostic carrying the decoded request's identity and id — the
27
- * shape the public `OperationDiagnostic` already has. One spelling for
30
+ * `"operation"` diagnostic carrying the decoded request's identity and id — the shape
31
+ * the public `OperationDiagnostic` already has. One spelling for
28
32
  * `protocol.handleOperation` and for `protocol.encodeOperation` given the decoded
29
33
  * request.
30
34
  */
31
35
  export declare function operationUnencodableReport(sink: FrameworkDiagnosticsSink | undefined, request: ClientOperationRequest): UnencodableReport;
32
36
  /**
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.
38
- *
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.
37
+ * `protocol.handleOperation(request)`: the three steps a host would otherwise spell
38
+ * out — `decodeOperation` → `framework.execute` → `encodeOperation` — in one call,
39
+ * resolving the `AvProtocolResponse` the host writes. A request the decoder answers
40
+ * itself (a transport failure, an identity mismatch, an unadvertised route) is
41
+ * answered without executing.
46
42
  */
47
43
  export declare function handleOperationRequest(context: HandlerContext, request: AvProtocolRequest): Promise<AvProtocolResponse>;
48
44
  /**
@@ -51,8 +47,8 @@ export declare function handleOperationRequest(context: HandlerContext, request:
51
47
  * decoded plan is client origin and cannot say otherwise, so every step runs under
52
48
  * ClientContract rules: a client-hidden field, a client-restricted variant or a
53
49
  * 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
50
+ * `cause.operation`. A committed plan is `200 A1009`; a rolled-back one answers its
51
+ * failing step's code at that code's status. Total over any value, as {@link
56
52
  * handleOperationRequest} is; an `A3003` is reported through {@link
57
53
  * planUnencodableReport}.
58
54
  */