@aventara/client 0.1.0-pilot.1 → 0.1.0-pilot.3

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 (79) hide show
  1. package/README.md +44 -9
  2. package/dist/avclient.bin.js +0 -10
  3. package/dist/cli/command.parser.d.ts +15 -10
  4. package/dist/cli/command.parser.js +13 -19
  5. package/dist/cli/generate.command.js +0 -6
  6. package/dist/cli/generation-failure.renderer.js +0 -14
  7. package/dist/cli/generation-success.renderer.d.ts +4 -1
  8. package/dist/cli/generation-success.renderer.js +0 -13
  9. package/dist/cli/terminal.prompter.d.ts +1 -2
  10. package/dist/cli/warning.renderer.d.ts +2 -2
  11. package/dist/cli/warning.renderer.js +0 -8
  12. package/dist/cli.d.ts +8 -16
  13. package/dist/cli.js +5 -25
  14. package/dist/config/client-config.interface.d.ts +18 -16
  15. package/dist/config/client-config.interface.js +0 -13
  16. package/dist/config/config.loader.d.ts +34 -22
  17. package/dist/config/config.loader.js +49 -52
  18. package/dist/config/config.resolver.d.ts +13 -19
  19. package/dist/config/config.resolver.js +9 -48
  20. package/dist/config/env.cascade.d.ts +12 -14
  21. package/dist/config/env.cascade.js +0 -19
  22. package/dist/config/module-style.resolver.d.ts +52 -0
  23. package/dist/config/module-style.resolver.js +75 -0
  24. package/dist/config/tsconfig.locator.d.ts +45 -0
  25. package/dist/config/tsconfig.locator.js +52 -0
  26. package/dist/contract/contract.acceptance.d.ts +12 -26
  27. package/dist/contract/contract.acceptance.js +0 -54
  28. package/dist/contract/contract.fetcher.d.ts +12 -17
  29. package/dist/contract/contract.fetcher.js +0 -24
  30. package/dist/contract/contract.loader.d.ts +4 -5
  31. package/dist/contract/contract.loader.js +0 -10
  32. package/dist/emit/banner.emitter.d.ts +11 -12
  33. package/dist/emit/banner.emitter.js +0 -26
  34. package/dist/emit/client-surface.emitter.d.ts +17 -21
  35. package/dist/emit/client-surface.emitter.js +29 -55
  36. package/dist/emit/client-tree.emitter.d.ts +11 -20
  37. package/dist/emit/client-tree.emitter.js +12 -54
  38. package/dist/emit/contract-carrier.emitter.d.ts +5 -6
  39. package/dist/emit/contract-carrier.emitter.js +0 -28
  40. package/dist/emit/derivation.emitter.d.ts +7 -7
  41. package/dist/emit/derivation.emitter.js +2 -161
  42. package/dist/emit/descriptor.emitter.js +2 -28
  43. package/dist/emit/emitted-tree.interface.d.ts +40 -17
  44. package/dist/emit/emitted-tree.interface.js +6 -16
  45. package/dist/emit/enum.emitter.d.ts +4 -4
  46. package/dist/emit/enum.emitter.js +0 -24
  47. package/dist/emit/module-specifier.scanner.d.ts +25 -0
  48. package/dist/emit/module-specifier.scanner.js +160 -0
  49. package/dist/emit/module-style.interface.d.ts +58 -0
  50. package/dist/emit/module-style.interface.js +8 -0
  51. package/dist/emit/name.deriver.d.ts +33 -61
  52. package/dist/emit/name.deriver.js +0 -134
  53. package/dist/emit/named-type.emitter.d.ts +14 -21
  54. package/dist/emit/named-type.emitter.js +3 -30
  55. package/dist/emit/runtime.emitter.d.ts +23 -50
  56. package/dist/emit/runtime.emitter.js +68 -159
  57. package/dist/emit/scalar.codec.d.ts +20 -33
  58. package/dist/emit/scalar.codec.js +13 -69
  59. package/dist/emit/transaction.emitter.d.ts +6 -14
  60. package/dist/emit/transaction.emitter.js +24 -33
  61. package/dist/generate.d.ts +20 -34
  62. package/dist/generate.js +14 -22
  63. package/dist/index.js +0 -5
  64. package/dist/init/client-config.template.d.ts +6 -4
  65. package/dist/init/client-config.template.js +10 -13
  66. package/dist/init/client-init.errors.js +0 -3
  67. package/dist/init/client-init.orchestrator.js +8 -9
  68. package/dist/init/client-init.planner.d.ts +1 -9
  69. package/dist/init/client-init.planner.js +16 -24
  70. package/dist/init/client-init.questions.d.ts +8 -12
  71. package/dist/init/client-init.questions.js +0 -11
  72. package/dist/init/client-project.inspector.d.ts +6 -0
  73. package/dist/init/client-project.inspector.js +2 -2
  74. package/dist/node-version.guard.js +0 -12
  75. package/dist/output/output.validator.d.ts +49 -27
  76. package/dist/output/output.validator.js +113 -74
  77. package/dist/output/output.writer.d.ts +59 -52
  78. package/dist/output/output.writer.js +72 -134
  79. package/package.json +6 -4
@@ -1,41 +1,15 @@
1
1
  import { OPERATION_CODES, VALIDATION_CODES, } from "@aventara/core";
2
2
  import { AvProtocol } from "@aventara/core/protocol";
3
3
  import { entrypointHref } from "../config/config.resolver.js";
4
+ import { moduleSpecifierWriter, } from "./module-style.interface.js";
4
5
  import { wireGrammarLiteral } from "./scalar.codec.js";
5
- /**
6
- * The runtime modules the generated client carries: `metadata.ts`, the
7
- * framework `Decimal`, the outcome codes and error classes, and the transport
8
- * here; the scalar codec in `scalar.codec.ts`.
9
- */
10
- /**
11
- * `runtime/decimal.ts` — the framework-owned `Decimal` of §6.2, the generated
12
- * runtime value of the `decimal` scalar. Bundled with the client and imported
13
- * from nothing: its public type is its own, never an ORM's (§6.2, C-801).
14
- *
15
- * It holds the decimal string it was made from, digit for digit, and does no
16
- * arithmetic — the surface is core's `Decimal` (a string constructor and
17
- * `toString`) plus `toJSON`, so a value means the same on both sides of the wire.
18
- * A proven decimal library may later sit behind it (§6.2); none is needed to
19
- * carry digits.
20
- *
21
- * `toJSON` is the architect's (2026-10-04, S6 answers): it returns the decimal
22
- * string, so a Decimal in a consumer's own JSON — a log line, a cache entry — is
23
- * its digits rather than `{}`. No `equals`, no arithmetic. The request body never
24
- * relies on it: `serializeWireBody` refuses an unencoded Decimal regardless, so a
25
- * value the codec did not encode cannot slip onto the wire through `toJSON`.
26
- *
27
- * The grammar is core's `Decimal` grammar, read from `AvProtocol.scalarFormats`
28
- * and emitted by value (C2, R7; `protocol-parity.spec.ts`). Unlike
29
- * core's, the constructor refuses a non-string outright: a pattern test coerces
30
- * its argument, so `5` would otherwise pass as `"5"` and be kept as a number.
31
- */
32
6
  export function emitDecimalModule() {
33
7
  return {
34
8
  path: "runtime/decimal.ts",
35
9
  source: `const DECIMAL_STRING = ${wireGrammarLiteral("decimal")};
36
10
 
37
11
  /**
38
- * An exact decimal: the runtime value of the "decimal" scalar (§6.2).
12
+ * An exact decimal: the runtime value of the "decimal" scalar.
39
13
  *
40
14
  * It holds the decimal string it was made from, digit for digit, and is sent as
41
15
  * that string. It does no arithmetic.
@@ -64,55 +38,28 @@ export class Decimal {
64
38
  `,
65
39
  };
66
40
  }
67
- /**
68
- * `metadata.ts` — what this client was generated against: the ClientContract
69
- * hash and the protocol version (Phase 12-partial Q4 = A), and the resolved
70
- * entrypoint as the client's default (§15.2; Phase 12-rest Q5 = A). Nothing else:
71
- * no driver, no timestamp, no generator version, no host path — anything a re-run
72
- * over the same inputs could change breaks byte-equality (§19.3's spirit). The
73
- * entrypoint is an input like the contract: changing it regenerates different
74
- * bytes and leaves the hash alone (§15.2), and it never carries credentials
75
- * (refused at resolution, Q5).
76
- *
77
- * The hash and the version are what every operation request sends (§12.4), from
78
- * `runtime/transport.ts`; all three are internal — `AvClient.ts` exports none.
79
- */
80
41
  export function emitMetadataModule(protocol, entrypoint) {
81
42
  return {
82
43
  path: "metadata.ts",
83
- source: "/** The hash of the ClientContract this client was generated against (§19.2). */\n" +
44
+ source: "/** The hash of the ClientContract this client was generated against. */\n" +
84
45
  `export const CLIENT_CONTRACT_HASH = ${JSON.stringify(protocol.hash)};\n` +
85
46
  "\n" +
86
- "/** The Aventara protocol version that ClientContract speaks (§19.1). */\n" +
47
+ "/** The Aventara protocol version that ClientContract speaks. */\n" +
87
48
  `export const PROTOCOL_VERSION = ${JSON.stringify(protocol.version)};\n` +
88
49
  "\n" +
89
- "/** The entrypoint the client was generated from: its default deployment (§15.2). */\n" +
50
+ "/** The entrypoint the client was generated from: its default deployment. */\n" +
90
51
  `export const DEFAULT_ENTRYPOINT = ${JSON.stringify(entrypointHref(entrypoint))};\n`,
91
52
  };
92
53
  }
93
- /**
94
- * # The FrameworkError subclass set (Q2 = B)
95
- *
96
- * One subclass per code CLASS, plus the two the specification names by
97
- * behaviour: `NotFoundError` (§13.4, A2003) and the contract-mismatch error
98
- * (invariant 15, A2005). Each class's doc line is emitted above it.
99
- *
100
- * The keys are the emitted class names, in UTF-16 code-unit order.
101
- */
102
54
  const FRAMEWORK_ERROR_CLASSES = {
103
55
  AuthError: "The caller is not authenticated, or is not permitted to run the operation.",
104
- ConflictError: "The operation conflicted with stored state, and nothing was written. A2008 fails the same way if sent again; A2013 and A2014 may succeed if sent again, and no retry is automatic (§13.5).",
56
+ ConflictError: "The operation conflicted with stored state, and nothing was written. A2008 fails the same way if sent again; A2013 and A2014 may succeed if sent again, and no retry is automatic.",
105
57
  ContractMismatchError: "This client was generated against a ClientContract other than the one the server serves (invariant 15). Regenerate it with `avclient generate`.",
106
- InternalError: "The server failed. Nothing in its cause is actionable; the diagnostics are in the server's logs (§13.5).",
107
- NotFoundError: "A strict unique target does not exist (§13.4).",
58
+ InternalError: "The server failed. Nothing in its cause is actionable; the diagnostics are in the server's logs.",
59
+ NotFoundError: "A strict unique target does not exist.",
108
60
  ProtocolError: "The request was not one the server could route or interpret: an unknown Resource or operation, a protocol version it does not speak, or a body, media type, size or method it refuses.",
109
61
  ValidationError: "The request broke a Contract rule: a field, type, capability, projection, reference or limit. The cause's issues say which, by code and path.",
110
62
  };
111
- /**
112
- * The class every error code throws. A mapped type over core's
113
- * `OperationErrorCode`, so a code core adds is a compile error here until it is
114
- * classified — the classification is total by construction, never by care.
115
- */
116
63
  const FRAMEWORK_ERROR_CLASS_OF = {
117
64
  A2000: "ProtocolError",
118
65
  A2001: "ProtocolError",
@@ -133,23 +80,13 @@ const FRAMEWORK_ERROR_CLASS_OF = {
133
80
  A3001: "InternalError",
134
81
  A3002: "InternalError",
135
82
  A3003: "InternalError",
83
+ A3004: "InternalError",
136
84
  A4000: "AuthError",
137
85
  A4001: "AuthError",
138
86
  A4002: "AuthError",
139
87
  };
140
- /**
141
- * The `FrameworkError` subclasses the generated runtime declares, in UTF-16
142
- * code-unit order — names the root namespace reserves (`name.deriver.ts`).
143
- */
144
88
  export const FRAMEWORK_ERROR_CLASS_NAMES = Object.keys(FRAMEWORK_ERROR_CLASSES);
145
- /** The error codes, in core's allocation order. */
146
89
  const ERROR_CODES = OPERATION_CODES.filter((code) => !code.startsWith("A1"));
147
- /**
148
- * The names `AvClient.ts` re-exports from `generated/runtime/errors.ts`: the classes and the
149
- * two code unions §15.4 requires, and `Cause` and `ValidationIssue` — the types a
150
- * thrown FrameworkError carries, public by the architect's decision of
151
- * 2026-10-04 — in UTF-16 code-unit order.
152
- */
153
90
  export function errorsModuleExports() {
154
91
  return [
155
92
  ...FRAMEWORK_ERROR_CLASS_NAMES,
@@ -165,20 +102,19 @@ export function errorsModuleExports() {
165
102
  return a < b ? -1 : a > b ? 1 : 0;
166
103
  });
167
104
  }
168
- /** One code array as emitted source: a `const` tuple, one code per line. */
169
105
  function codeArray(codes) {
170
106
  return `[\n${codes.map((code) => `\t${JSON.stringify(code)},\n`).join("")}] as const`;
171
107
  }
172
108
  const ERRORS_MODULE_HEAD = `/**
173
- * The outcome codes and error classes of Aventara protocol version 1 (§13).
109
+ * The outcome codes and error classes of Aventara protocol version 1.
174
110
  *
175
111
  * A1xxx resolves; every other code throws the FrameworkError subclass of its
176
- * class (§13.5); a response that is not a framework envelope throws
112
+ * class; a response that is not a framework envelope throws
177
113
  * TransportError. Branch on the class or on \`code\`, never on the message.
178
114
  */
179
115
  `;
180
116
  const ERRORS_MODULE_TYPES = `
181
- /** One actionable validation issue (§13.1); \`path\` locates it in the request. */
117
+ /** One actionable validation issue; \`path\` locates it in the request. */
182
118
  export interface ValidationIssue {
183
119
  readonly path?: readonly (string | number)[];
184
120
  readonly code: ValidationCode;
@@ -186,9 +122,9 @@ export interface ValidationIssue {
186
122
  }
187
123
 
188
124
  /**
189
- * Why an operation failed (§13.1). Rebuilt member by member from the envelope:
125
+ * Why an operation failed. Rebuilt member by member from the envelope:
190
126
  * a member the protocol does not define is never carried, so no stack, SQL or
191
- * server path the server should not have sent reaches it (§13.5).
127
+ * server path the server should not have sent reaches it.
192
128
  */
193
129
  export interface Cause {
194
130
  readonly message: string;
@@ -198,7 +134,7 @@ export interface Cause {
198
134
  }
199
135
 
200
136
  /**
201
- * A framework outcome that throws (§13.5): every code outside A1xxx. It is
137
+ * A framework outcome that throws: every code outside A1xxx. It is
202
138
  * always thrown as the subclass of its code's class; catch FrameworkError to
203
139
  * catch them all.
204
140
  */
@@ -218,7 +154,7 @@ export class FrameworkError<C extends OperationErrorCode = OperationErrorCode> e
218
154
  `;
219
155
  const ERRORS_MODULE_TAIL = `
220
156
  /**
221
- * A failure that never produced a framework envelope (§13.5): no response
157
+ * A failure that never produced a framework envelope: no response
222
158
  * arrived, or the one that did is not an Aventara response envelope — a proxy's
223
159
  * HTML error page, a truncated body, JSON of another shape. It carries no
224
160
  * cause: nothing in such a response is the framework's to report.
@@ -234,16 +170,6 @@ export class TransportError extends Error {
234
170
  }
235
171
  }
236
172
  `;
237
- /**
238
- * `runtime/errors.ts` — §13's vocabulary as the generated client carries it.
239
- *
240
- * Both code unions are emitted from core's exported arrays (Q3), so the emitted
241
- * tree states each code exactly once and core stays their one source; the
242
- * subclass set and the code each one throws are Q2's (above), accepted as-is by
243
- * the architect on 2026-10-04. Exported beyond what `AvClient.ts` re-exports: the
244
- * two arrays, `OperationErrorCode` and `frameworkErrorOf`, which
245
- * `runtime/transport.ts` reads.
246
- */
247
173
  export function emitErrorsModule() {
248
174
  const classes = Object.entries(FRAMEWORK_ERROR_CLASSES).map(([name, summary]) => {
249
175
  const codes = ERROR_CODES.filter((code) => FRAMEWORK_ERROR_CLASS_OF[code] === name);
@@ -255,15 +181,15 @@ export function emitErrorsModule() {
255
181
  return {
256
182
  path: "runtime/errors.ts",
257
183
  source: ERRORS_MODULE_HEAD +
258
- "\n/** The outcome codes of the protocol, in allocation order (§13.2). */\n" +
184
+ "\n/** The outcome codes of the protocol, in allocation order. */\n" +
259
185
  `export const OPERATION_CODES = ${codeArray(OPERATION_CODES)};\n` +
260
- "\n/** An outcome code (§13.2). */\n" +
186
+ "\n/** An outcome code. */\n" +
261
187
  "export type OperationCode = (typeof OPERATION_CODES)[number];\n" +
262
- "\n/** An outcome code that throws: every code outside A1xxx (§13.5). */\n" +
188
+ "\n/** An outcome code that throws: every code outside A1xxx. */\n" +
263
189
  `export type OperationErrorCode = Exclude<OperationCode, \`A1\${string}\`>;\n` +
264
- "\n/** The validation codes of the protocol, in allocation order (§13.3). */\n" +
190
+ "\n/** The validation codes of the protocol, in allocation order. */\n" +
265
191
  `export const VALIDATION_CODES = ${codeArray(VALIDATION_CODES)};\n` +
266
- "\n/** A validation code (§13.3): what one issue in a cause is about. */\n" +
192
+ "\n/** A validation code: what one issue in a cause is about. */\n" +
267
193
  "export type ValidationCode = (typeof VALIDATION_CODES)[number];\n" +
268
194
  ERRORS_MODULE_TYPES +
269
195
  classes.join("") +
@@ -278,36 +204,12 @@ export function emitErrorsModule() {
278
204
  "}\n",
279
205
  };
280
206
  }
281
- /**
282
- * `runtime/transport.ts` — the happy path of §12 and §13.5, above Phase
283
- * 12-partial's boundary: one POST per operation to
284
- * `<entrypoint>/_resources/<resource>/<family>/<variant>` (§12.1–§12.3), the
285
- * identity headers on every request (§12.4), per-request options that are never
286
- * serialized (§15.7), and the envelope read back by §13.5's rule.
287
- *
288
- * `execute` is Q1 = B's primitive: exported from this module for the
289
- * per-variant methods to wrap, and re-exported from nowhere — it is not public
290
- * surface. It reads no capability and no operation descriptor; the caller names
291
- * the operation.
292
- *
293
- * Fetch and AbortSignal are the platform's, reached through the structural types
294
- * below so the module compiles with neither DOM nor Node types (§15.7, U5).
295
- *
296
- * Stale-route recovery is not here: it is F-716, Phase 10's, and the emitted
297
- * module documents it as a hole in its own doc comment (S9).
298
- */
299
- export function emitTransportModule() {
300
- return { path: "runtime/transport.ts", source: TRANSPORT_MODULE };
207
+ export function emitTransportModule(style) {
208
+ return {
209
+ path: "runtime/transport.ts",
210
+ source: transportModuleSource(moduleSpecifierWriter(style)),
211
+ };
301
212
  }
302
- /**
303
- * Core's identity header names (`AvProtocol.headers`, §12.4), split back into
304
- * the one wire prefix and each header's own part, so the emitted transport
305
- * spells both from one constant — its freeze stays a one-line change in the
306
- * generated code — and from core's values rather than restated text.
307
- *
308
- * @throws Error at load when core's names stop sharing one `<prefix>-` head:
309
- * the emitted spelling could no longer be the names core sends.
310
- */
311
213
  const IDENTITY_HEADERS = (() => {
312
214
  const { protocolVersion, contractHash, requestId } = AvProtocol.headers;
313
215
  const prefix = protocolVersion.slice(0, protocolVersion.indexOf("-"));
@@ -323,9 +225,10 @@ const IDENTITY_HEADERS = (() => {
323
225
  requestId: requestId.slice(prefix.length),
324
226
  };
325
227
  })();
326
- const TRANSPORT_MODULE = `import { CLIENT_CONTRACT_HASH, PROTOCOL_VERSION } from "../metadata.js";
327
- import { decodeResult, encodeArguments, serializeWireBody } from "./codec.js";
328
- import { DECODE_TABLE } from "./descriptor.js";
228
+ function transportModuleSource(from) {
229
+ return `import { CLIENT_CONTRACT_HASH, PROTOCOL_VERSION } from ${from("../metadata")};
230
+ import { decodeResult, encodeArguments, serializeWireBody } from ${from("./codec")};
231
+ import { DECODE_TABLE } from ${from("./descriptor")};
329
232
  import {
330
233
  type Cause,
331
234
  frameworkErrorOf,
@@ -336,20 +239,20 @@ import {
336
239
  VALIDATION_CODES,
337
240
  type ValidationCode,
338
241
  type ValidationIssue,
339
- } from "./errors.js";
242
+ } from ${from("./errors")};
340
243
 
341
244
  /**
342
- * The transport of Aventara protocol version 1: one POST per operation (§12.2),
343
- * sent with the protocol version and ClientContract hash (§12.4), its response
344
- * read by §13.5's rule — A1xxx resolves with the envelope's data, every other
245
+ * The transport of Aventara protocol version 1: one POST per operation,
246
+ * sent with the protocol version and ClientContract hash, its response
247
+ * read by the protocol's rule — A1xxx resolves with the envelope's data, every other
345
248
  * code throws its FrameworkError subclass, and anything that is not a framework
346
- * envelope throws TransportError. No request is ever retried (§13.5).
249
+ * envelope throws TransportError. No request is ever retried.
347
250
  *
348
- * # A stale client (F-716)
251
+ * # A stale client
349
252
  *
350
253
  * A client generated against an older ClientContract must fail hard and say to
351
254
  * regenerate (cross-phase invariant 15). The server is what knows: it checks the
352
- * identity this transport sends BEFORE it routes (Phase 10, Q3), so a request
255
+ * identity this transport sends BEFORE it routes, so a request
353
256
  * under a stale hash — to an operation the deployment still advertises, or to
354
257
  * one it no longer does — is answered 409 A2005, which throws
355
258
  * ContractMismatchError naming the remedy. Nothing here guesses: a response that
@@ -358,17 +261,17 @@ import {
358
261
  * client is stale.
359
262
  */
360
263
 
361
- /** The wire prefix of the identity headers, in one place: its freeze (§12.4) is a one-line change. */
264
+ /** The wire prefix of the identity headers, in one place: its freeze is a one-line change. */
362
265
  const WIRE_PREFIX = ${JSON.stringify(IDENTITY_HEADERS.prefix)};
363
266
 
364
- /** The headers the framework owns on every operation request (§12.3, §12.4). */
267
+ /** The headers the framework owns on every operation request. */
365
268
  const FRAMEWORK_HEADERS: Readonly<Record<string, string>> = {
366
269
  "Content-Type": "application/json",
367
270
  [WIRE_PREFIX + ${JSON.stringify(IDENTITY_HEADERS.protocolVersion)}]: String(PROTOCOL_VERSION),
368
271
  [WIRE_PREFIX + ${JSON.stringify(IDENTITY_HEADERS.contractHash)}]: CLIENT_CONTRACT_HASH,
369
272
  };
370
273
 
371
- /** The request id header (§12.4, Phase 10 Q13): CallOptions.requestId sends it. */
274
+ /** The request id header: CallOptions.requestId sends it. */
372
275
  const REQUEST_ID_HEADER = WIRE_PREFIX + ${JSON.stringify(IDENTITY_HEADERS.requestId)};
373
276
 
374
277
  /** What the transport reads of an AbortSignal, where the consumer's lib declares none. */
@@ -394,7 +297,7 @@ export interface FetchResponse {
394
297
  export type StructuralFetch = (url: string, init: FetchInit) => Promise<FetchResponse>;
395
298
 
396
299
  /**
397
- * The fetch this client calls (§15.7): the consumer's own platform fetch type when
300
+ * The fetch this client calls: the consumer's own platform fetch type when
398
301
  * their lib declares one — DOM's, Node's — so the platform fetch is accepted
399
302
  * without a cast, and the structural fetch above where it declares none. Read
400
303
  * through typeof globalThis, so this module names neither lib.
@@ -410,12 +313,12 @@ export type PlatformSignal = typeof globalThis extends {
410
313
 
411
314
  /** Where operations go: the framework entrypoint, and the fetch that reaches it. */
412
315
  export interface TransportConnection {
413
- /** The framework entrypoint, an absolute URL without a trailing slash (§12.1). */
316
+ /** The framework entrypoint, an absolute URL without a trailing slash. */
414
317
  readonly entrypoint: string;
415
318
  readonly fetch: Fetch;
416
319
  }
417
320
 
418
- /** Per-call options (§15.7). Never serialized into the operation body. */
321
+ /** Per-call options. Never serialized into the operation body. */
419
322
  export interface CallOptions {
420
323
  /** Aborts the request; the call rejects with what fetch rejected with. */
421
324
  readonly signal?: PlatformSignal;
@@ -430,10 +333,15 @@ export interface CallOptions {
430
333
 
431
334
  type SuccessCode = Exclude<OperationCode, OperationErrorCode>;
432
335
 
433
- /** A framework envelope (§13.1), read and checked. */
336
+ /**
337
+ * A framework envelope, read and checked — told apart by \`outcome\`, a string
338
+ * discriminant, rather than by \`cause\` being null: without \`strictNullChecks\`
339
+ * (\`strict: false\`, which Next.js writes into a tsconfig it creates) null
340
+ * narrows nothing, and the client must type-check under the consumer's settings.
341
+ */
434
342
  type Envelope =
435
- | { readonly code: SuccessCode; readonly data: unknown; readonly cause: null }
436
- | { readonly code: OperationErrorCode; readonly data: null; readonly cause: Cause };
343
+ | { readonly outcome: "data"; readonly code: SuccessCode; readonly data: unknown }
344
+ | { readonly outcome: "failure"; readonly code: OperationErrorCode; readonly cause: Cause };
437
345
 
438
346
  /**
439
347
  * Runs one operation: POSTs its arguments and settles its envelope.
@@ -461,7 +369,7 @@ export async function execute(
461
369
  }
462
370
 
463
371
  /**
464
- * Runs one transaction plan (§14.2): POSTs it to \`/_transactions\` and settles
372
+ * Runs one transaction plan: POSTs it to \`/_transactions\` and settles
465
373
  * its envelope; a committed plan's data is one result per operation, each decoded
466
374
  * by its own operation's Resource (\`resources\`, in plan order).
467
375
  *
@@ -529,7 +437,7 @@ async function post(
529
437
 
530
438
  /**
531
439
  * The decoded data, or — a scalar in \`data\` that does not decode, inside an
532
- * otherwise valid envelope — a TransportError (architect, 2026-10-04).
440
+ * otherwise valid envelope — a TransportError.
533
441
  */
534
442
  function decoded<T>(operation: string, status: number, decode: () => T): T {
535
443
  try {
@@ -544,9 +452,9 @@ function decoded<T>(operation: string, status: number, decode: () => T): T {
544
452
  }
545
453
 
546
454
  /**
547
- * Settles one response by §13.5's rule: the envelope's data, still in wire form,
548
- * which the caller decodes by the decode table (P1). A decode failure's mode is
549
- * decided (architect, 2026-10-04):
455
+ * Settles one response by the protocol's rule: the envelope's data, still in wire form,
456
+ * which the caller decodes by the decode table. A decode failure's mode is
457
+ * decided:
550
458
  * A scalar in \`data\` that fails to decode, inside an otherwise valid envelope, throws TransportError
551
459
  * — not a FrameworkError, because the server reported no failure; the response is
552
460
  * one this client cannot read, which is what TransportError means.
@@ -559,10 +467,10 @@ function settle(operation: string, status: number, text: string): unknown {
559
467
  status,
560
468
  );
561
469
  }
562
- if (envelope.cause === null) {
563
- return envelope.data;
470
+ if (envelope.outcome === "failure") {
471
+ throw frameworkErrorOf(envelope.code, envelope.cause);
564
472
  }
565
- throw frameworkErrorOf(envelope.code, envelope.cause);
473
+ return envelope.data;
566
474
  }
567
475
 
568
476
  /** The parsed body, or undefined — which no envelope is — when it is not JSON. */
@@ -590,7 +498,7 @@ function isSuccessCode(code: OperationCode): code is SuccessCode {
590
498
  return code.startsWith("A1");
591
499
  }
592
500
 
593
- /** The envelope in a parsed body, or undefined when the body is not one (§13.1). */
501
+ /** The envelope in a parsed body, or undefined when the body is not one. */
594
502
  function envelopeOf(body: unknown): Envelope | undefined {
595
503
  if (!isRecord(body) || !Object.hasOwn(body, "data")) {
596
504
  return undefined;
@@ -601,14 +509,14 @@ function envelopeOf(body: unknown): Envelope | undefined {
601
509
  return undefined;
602
510
  }
603
511
  if (isSuccessCode(code)) {
604
- return body["cause"] === null && (code !== "A1001" || data === null) ? { code, data, cause: null } : undefined;
512
+ return body["cause"] === null && (code !== "A1001" || data === null) ? { outcome: "data", code, data } : undefined;
605
513
  }
606
514
  const cause = causeOf(body["cause"]);
607
- return data === null && cause !== undefined ? { code, data, cause } : undefined;
515
+ return data === null && cause !== undefined ? { outcome: "failure", code, cause } : undefined;
608
516
  }
609
517
 
610
518
  /**
611
- * The cause rebuilt from the members §13.1 defines, or undefined when one of them
519
+ * The cause rebuilt from the members the protocol defines, or undefined when one of them
612
520
  * is malformed. Every other member is dropped, so whatever else a server put in
613
521
  * its cause — a stack, SQL, a file path — is never carried into a thrown error.
614
522
  */
@@ -672,10 +580,10 @@ function issueOf(value: unknown): ValidationIssue | undefined {
672
580
  return Object.freeze({ path: Object.freeze(segments), code, message });
673
581
  }
674
582
 
675
- /** The arguments, refused unless they are an object: the body is always one (§12.6). */
583
+ /** The arguments, refused unless they are an object: the body is always one. */
676
584
  function argumentObject(args: unknown): unknown {
677
585
  if (!isRecord(args)) {
678
- throw new TypeError("An operation's arguments must be an object; send {} when there are none (§12.3).");
586
+ throw new TypeError("An operation's arguments must be an object; send {} when there are none.");
679
587
  }
680
588
  return args;
681
589
  }
@@ -683,14 +591,14 @@ function argumentObject(args: unknown): unknown {
683
591
  /**
684
592
  * The framework's headers plus the caller's, refusing a caller's that names one of
685
593
  * the framework's; then requestId, which overwrites any request id header the
686
- * caller set (architect, 2026-10-05).
594
+ * caller set.
687
595
  */
688
596
  function requestHeaders(options: CallOptions): Record<string, string> {
689
597
  const headers: Record<string, string> = { ...FRAMEWORK_HEADERS };
690
598
  const owned = new Set(Object.keys(FRAMEWORK_HEADERS).map((name) => name.toLowerCase()));
691
599
  for (const [name, value] of Object.entries(options.headers ?? {})) {
692
600
  if (owned.has(name.toLowerCase())) {
693
- throw new TypeError('The "' + name + '" header is the framework\\'s own; a request cannot set it (§12.4).');
601
+ throw new TypeError('The "' + name + '" header is the framework\\'s own; a request cannot set it.');
694
602
  }
695
603
  headers[name] = value;
696
604
  }
@@ -705,3 +613,4 @@ function requestHeaders(options: CallOptions): Record<string, string> {
705
613
  return headers;
706
614
  }
707
615
  `;
616
+ }
@@ -1,51 +1,38 @@
1
1
  import { AvProtocol } from "@aventara/core/protocol";
2
2
  import type { EmittedModule } from "./emitted-tree.interface.js";
3
+ import { type ClientModuleStyle } from "./module-style.interface.js";
3
4
  /**
4
- * The scalar codecs of §6.2, as the generated client carries them in
5
- * `runtime/codec.ts`.
6
- *
7
5
  * # Keyed on `BuiltInScalar` alone
8
6
  *
9
- * §6.2's table is fixed by PROTOCOL VERSION, not carried in the Contract: the
10
- * scalar registry is a key registry (`{ builtin: true }`) and scalars carry no
11
- * position qualifier [M10]. So the codec reads no field, no capability and no
12
- * operation descriptor — the caller names the scalar, and the codec converts one
13
- * value. Walking a Resource's fields to find which scalar a value is belongs to
14
- * the method surface, below Phase 12-partial's boundary.
7
+ * So the codec reads no field, no capability and no operation descriptor — the
8
+ * caller names the scalar, and the codec converts one value.
15
9
  *
16
- * One source for the scalar set: the emitted `BuiltInScalar` union and the
17
- * emitted table both come from core's `BUILT_IN_SCALARS`, in its order, and
18
- * {@link SCALAR_CODEC_SOURCES} is a mapped type over core's `BuiltInScalar` — a
19
- * scalar the protocol adds is a compile error here until its codec is written.
10
+ * One source for the scalar set: the emitted `BuiltInScalar` union and the emitted
11
+ * table both come from core's `BUILT_IN_SCALARS`, in its order, and {@link
12
+ * SCALAR_CODEC_SOURCES} is a mapped type over core's `BuiltInScalar` — a scalar
13
+ * the protocol adds is a compile error here until its codec is written.
20
14
  *
21
15
  * # Untyped on purpose
22
16
  *
23
- * Every codec is `unknown → unknown`, checked at runtime. The TYPE of a scalar's
24
- * application form and wire form is Phase 9's `ScalarValueType` and its `Forms`
25
- * maps (architect decision Q3 = 3a); declaring a second scalar→type map here
26
- * would be a parallel source of that fact. When the boundary lifts, the methods
27
- * that call these codecs carry the types.
17
+ * Every codec is `unknown → unknown`, checked at runtime. When the boundary lifts,
18
+ * the methods that call these codecs carry the types.
28
19
  *
29
20
  * # What the emitted codec promises
30
21
  *
31
- * - `encodeScalar`/`decodeScalar` convert between the generated runtime value
32
- * and the JSON wire value of §6.2, and `decodeScalar(s, encodeScalar(s, v))`
33
- * equals `v` for every scalar.
34
22
  * - `null` passes through both: it is explicit, and whether a field admits it is
35
- * the field's nullability, which the server validates (§6.2).
23
+ * the field's nullability, which the server validates.
36
24
  * - `undefined` is never a value: an optional property is omitted, and
37
25
  * `serializeWireBody` strips every `undefined` property before transport.
38
- * - A value outside a scalar's runtime or wire form is refused with a
39
- * `TypeError` naming the scalar — never coerced. A `json` value carrying a
40
- * `BigInt`, `Date`, `Uint8Array`, `Decimal`, function, symbol or `undefined`
41
- * is refused (§6.2), with the path to the offending member.
42
- * - Wire grammars are the server's, read from core — `AvProtocol.scalarFormats`
43
- * (C2, R7) — and emitted by value as regular-expression literals
44
- * ({@link wireGrammarLiteral}): bigint `-?(0|[1-9]\d*)`, datetime exactly
26
+ * - A value outside a scalar's runtime or wire form is refused with a `TypeError`
27
+ * naming the scalar — never coerced. A `json` value carrying a `BigInt`, `Date`,
28
+ * `Uint8Array`, `Decimal`, function, symbol or `undefined` is refused, with the
29
+ * path to the offending member.
30
+ * - Wire grammars are the server's, read from core — `AvProtocol.scalarFormats` —
31
+ * and emitted by value as regular-expression literals ({@link
32
+ * wireGrammarLiteral}): bigint `-?(0|[1-9]\d*)`, datetime exactly
45
33
  * `toISOString()`'s form, bytes RFC 4648 base64 with the standard alphabet and
46
- * padding, canonical (zero pad bits, like the server's — C1). Base64 is written
47
- * out rather than delegated to `atob`/`btoa`, so the module needs neither a DOM
48
- * nor a Node global (§15.7, U5).
34
+ * padding, canonical. Base64 is written out rather than delegated to
35
+ * `atob`/`btoa`, so the module needs neither a DOM nor a Node global.
49
36
  */
50
37
  /**
51
38
  * The regular-expression literal of one of core's wire grammars, as emitted
@@ -60,4 +47,4 @@ export declare function wireGrammarLiteral(scalar: keyof typeof AvProtocol.scala
60
47
  * functions the generated transport calls. Nothing here is re-exported from the
61
48
  * tree's `AvClient.ts`: the codec is the runtime's, not the consumer's.
62
49
  */
63
- export declare function emitScalarCodecModule(): EmittedModule;
50
+ export declare function emitScalarCodecModule(style: ClientModuleStyle): EmittedModule;