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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +41 -7
  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 +17 -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 +1 -9
  68. package/dist/init/client-init.planner.d.ts +1 -9
  69. package/dist/init/client-init.planner.js +6 -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 +22 -22
  76. package/dist/output/output.validator.js +46 -59
  77. package/dist/output/output.writer.d.ts +56 -52
  78. package/dist/output/output.writer.js +71 -133
  79. package/package.json +6 -4
@@ -1,17 +1,14 @@
1
1
  import type { ClientContract } from "@aventara/core";
2
2
  import type { ClientEntrypoint } from "../config/client-config.interface.js";
3
3
  import { type ClientEmission } from "./emitted-tree.interface.js";
4
+ import { type ClientModuleStyle } from "./module-style.interface.js";
4
5
  /**
5
- * §15.3's emit steps over an accepted ClientContract, as one value (plan §7).
6
- *
7
6
  * The banner, the encoding and the file order are applied HERE, once, over every
8
- * module — so no emitter can forget the banner, and byte-equality is a property
9
- * of this function rather than of each emitter's care (C-843):
7
+ * module — so no emitter can forget the banner, and byte-equality is a property of
8
+ * this function rather than of each emitter's care:
10
9
  *
11
- * - every module opens with the generated banner (M17);
10
+ * - every module opens with the generated banner;
12
11
  * - every file is UTF-8;
13
- * - the layout is the architect's (2026-10-04): `AvClient.ts` at the root of
14
- * `generateAt`, every other module under `generated/`;
15
12
  * - files come in UTF-16 code-unit order of their path, each path once.
16
13
  *
17
14
  * The name derivation's rename warnings ride on the result beside the tree; this
@@ -19,19 +16,13 @@ import { type ClientEmission } from "./emitted-tree.interface.js";
19
16
  *
20
17
  * The names and enums read the enum registry, registry NAMES and `protocol`.
21
18
  * Core's derivation is copied under `generated/derivation/` as its published
22
- * declarations (Q1 = A, `derivation.emitter.ts`): read from the installed
23
- * `@aventara/core`, never from the Contract. The contract itself reaches the
24
- * tree as three projections of the one accepted contract (plan §6): the carrier
25
- * `generated/contract.ts` (Q4), the runtime's decode table and advertised
26
- * operations `generated/runtime/descriptor.ts` (P1, P4), and `metadata.ts`'s
27
- * hash, version and default entrypoint (Q5) — the entrypoint being the run's
28
- * other input.
29
- *
30
- * The runtime (`generated/runtime/codec.ts`, `decimal.ts`, `errors.ts`,
31
- * `transport.ts`) reads nothing of the Contract at all: §6.2's codecs and
32
- * §13's codes are fixed by protocol version (M10, Q3), and the transport sends
33
- * the operation its caller names.
19
+ * declarations: read from the installed `@aventara/core`, never from the Contract.
20
+ * The contract itself reaches the tree as three projections of the one accepted
21
+ * contract: the carrier `generated/contract.ts`, the runtime's decode table and
22
+ * advertised operations `generated/runtime/descriptor.ts`, and `metadata.ts`'s
23
+ * hash, version and default entrypoint — the entrypoint being the run's other
24
+ * input.
34
25
  *
35
26
  * @throws GeneratedNameError when a name cannot be emitted, even renamed.
36
27
  */
37
- export declare function emitClientTree(contract: ClientContract, entrypoint: ClientEntrypoint): ClientEmission;
28
+ export declare function emitClientTree(contract: ClientContract, entrypoint: ClientEntrypoint, style: ClientModuleStyle): ClientEmission;
@@ -5,65 +5,32 @@ import { emitDerivationModules } from "./derivation.emitter.js";
5
5
  import { emitDescriptorModule } from "./descriptor.emitter.js";
6
6
  import { CLIENT_ENTRY_FILE, GENERATED_DIRECTORY, } from "./emitted-tree.interface.js";
7
7
  import { emitEnumsModule } from "./enum.emitter.js";
8
+ import { moduleSpecifierWriter, } from "./module-style.interface.js";
8
9
  import { deriveEmittedNames } from "./name.deriver.js";
9
10
  import { emitNamedTypesModule } from "./named-type.emitter.js";
10
11
  import { emitDecimalModule, emitErrorsModule, emitMetadataModule, emitTransportModule, errorsModuleExports, } from "./runtime.emitter.js";
11
12
  import { emitScalarCodecModule } from "./scalar.codec.js";
12
13
  import { emitTransactionModules } from "./transaction.emitter.js";
13
- /**
14
- * §15.3's emit steps over an accepted ClientContract, as one value (plan §7).
15
- *
16
- * The banner, the encoding and the file order are applied HERE, once, over every
17
- * module — so no emitter can forget the banner, and byte-equality is a property
18
- * of this function rather than of each emitter's care (C-843):
19
- *
20
- * - every module opens with the generated banner (M17);
21
- * - every file is UTF-8;
22
- * - the layout is the architect's (2026-10-04): `AvClient.ts` at the root of
23
- * `generateAt`, every other module under `generated/`;
24
- * - files come in UTF-16 code-unit order of their path, each path once.
25
- *
26
- * The name derivation's rename warnings ride on the result beside the tree; this
27
- * function prints nothing.
28
- *
29
- * The names and enums read the enum registry, registry NAMES and `protocol`.
30
- * Core's derivation is copied under `generated/derivation/` as its published
31
- * declarations (Q1 = A, `derivation.emitter.ts`): read from the installed
32
- * `@aventara/core`, never from the Contract. The contract itself reaches the
33
- * tree as three projections of the one accepted contract (plan §6): the carrier
34
- * `generated/contract.ts` (Q4), the runtime's decode table and advertised
35
- * operations `generated/runtime/descriptor.ts` (P1, P4), and `metadata.ts`'s
36
- * hash, version and default entrypoint (Q5) — the entrypoint being the run's
37
- * other input.
38
- *
39
- * The runtime (`generated/runtime/codec.ts`, `decimal.ts`, `errors.ts`,
40
- * `transport.ts`) reads nothing of the Contract at all: §6.2's codecs and
41
- * §13's codes are fixed by protocol version (M10, Q3), and the transport sends
42
- * the operation its caller names.
43
- *
44
- * @throws GeneratedNameError when a name cannot be emitted, even renamed.
45
- */
46
- export function emitClientTree(contract, entrypoint) {
14
+ export function emitClientTree(contract, entrypoint, style) {
47
15
  const names = deriveEmittedNames(contract);
48
16
  const generated = [
49
17
  ...emitDerivationModules(),
50
- emitClientSurfaceModule(contract, names),
18
+ emitClientSurfaceModule(contract, names, style),
51
19
  emitContractCarrierModule(contract),
52
20
  emitDescriptorModule(contract),
53
21
  emitEnumsModule(contract, names),
54
22
  emitMetadataModule(contract.protocol, entrypoint),
55
- emitScalarCodecModule(),
23
+ emitScalarCodecModule(style),
56
24
  emitDecimalModule(),
57
25
  emitErrorsModule(),
58
- emitTransportModule(),
59
- emitNamedTypesModule(contract, names),
60
- // P3: the builder and runner exist iff transactions are interactive.
26
+ emitTransportModule(style),
27
+ emitNamedTypesModule(contract, names, style),
61
28
  ...(contract.transactions === "interactive"
62
- ? emitTransactionModules()
29
+ ? emitTransactionModules(style)
63
30
  : []),
64
31
  ];
65
32
  const files = [
66
- { path: CLIENT_ENTRY_FILE, source: clientEntrySource() },
33
+ { path: CLIENT_ENTRY_FILE, source: clientEntrySource(style) },
67
34
  ...generated.map((module) => ({
68
35
  path: `${GENERATED_DIRECTORY}/${module.path}`,
69
36
  source: module.source,
@@ -76,20 +43,11 @@ export function emitClientTree(contract, entrypoint) {
76
43
  path: file.path,
77
44
  bytes: encoder.encode(withGeneratedBanner(file.source)),
78
45
  }));
79
- return { tree, warnings: names.warnings };
46
+ return { tree, style, warnings: names.warnings };
80
47
  }
81
- /**
82
- * `AvClient.ts`, the entry point a consumer imports (§15.4; Phase 12-rest Q7):
83
- * the ready client `avClient` as the DEFAULT export, and as named exports the
84
- * class `AvClient`, `AvClientOptions`, `CallOptions`, `Fetch`, `Operation<T>`,
85
- * the named Resource types, the enums, `Decimal`, the errors and the code unions —
86
- * re-exported from `generated/`. Never the transport's primitive (Q1 = B), never
87
- * the derived forms map (Q3: internal).
88
- *
89
- * import avClient, { AvClient, User, UserWhere } from "./AvClient";
90
- */
91
- function clientEntrySource() {
92
- const from = (module) => JSON.stringify(`./${GENERATED_DIRECTORY}/${module.replace(/\.d\.ts$|\.ts$/, ".js")}`);
48
+ function clientEntrySource(style) {
49
+ const specifier = moduleSpecifierWriter(style);
50
+ const from = (module) => specifier(`./${GENERATED_DIRECTORY}/${module.replace(/\.d\.ts$|\.ts$/, "")}`);
93
51
  return (`export { default } from ${from("client.ts")};\n` +
94
52
  `export {\n\tAvClient,\n\ttype AvClientOptions,\n\ttype CallOptions,\n} from ${from("client.ts")};\n` +
95
53
  `export type { Fetch } from ${from("runtime/transport.ts")};\n` +
@@ -3,11 +3,10 @@ import type { EmittedModule } from "./emitted-tree.interface.js";
3
3
  /** `generated/contract.ts`, before the banner. */
4
4
  export declare function emitContractCarrierModule(contract: ClientContract): EmittedModule;
5
5
  /**
6
- * The ClientContract a carrier file holds — its whole text, banner included —
7
- * or `undefined` when it is not one this generator wrote over a contract that
8
- * still verifies: a foreign prefix or suffix, bytes that are not JSON, a body
9
- * that is not a ClientContract or whose hash does not re-verify, or bytes that
10
- * are not that contract's canonical form. Never trusted otherwise (Q6: a carrier
11
- * that does not re-hash is treated as absent).
6
+ * The ClientContract a carrier file holds — its whole text, banner included — or
7
+ * `undefined` when it is not one this generator wrote over a contract that still
8
+ * verifies: a foreign prefix or suffix, bytes that are not JSON, a body that is
9
+ * not a ClientContract or whose hash does not re-verify, or bytes that are not
10
+ * that contract's canonical form. Never trusted otherwise.
12
11
  */
13
12
  export declare function parseContractCarrier(text: string): Promise<ClientContract | undefined>;
@@ -1,42 +1,14 @@
1
1
  import { canonicalizeContract } from "@aventara/core";
2
2
  import { acceptClientContract } from "../contract/contract.acceptance.js";
3
3
  import { withGeneratedBanner } from "./banner.emitter.js";
4
- /**
5
- * The carrier (Q4 = A): `generated/contract.ts` holds the ClientContract the
6
- * client was generated against, as its served canonical bytes (RFC 8785, §19.2)
7
- * verbatim — which are a valid TypeScript type literal (plan M4):
8
- *
9
- * ```ts
10
- * export type ClientContractShape = {"enums":{},…};
11
- * ```
12
- *
13
- * One artefact, three readers: the derivation's `C` (S4); the generator on a
14
- * `304` (Q6, S7), which parses it back with {@link parseContractCarrier}; and a
15
- * person auditing what the client was generated against. It costs no runtime
16
- * byte — nothing imports it as a value.
17
- *
18
- * The bytes are `canonicalizeContract`'s over the ACCEPTED contract: the body a
19
- * deployment serves is those bytes (`_contract` serves `canonicalizeContract`'s
20
- * output, and acceptance verified the hash over the same canonical form), and a
21
- * contract that arrives in another key order still emits them (C-843).
22
- */
23
4
  const CARRIER_PREFIX = "export type ClientContractShape = ";
24
5
  const CARRIER_SUFFIX = ";\n";
25
- /** `generated/contract.ts`, before the banner. */
26
6
  export function emitContractCarrierModule(contract) {
27
7
  return {
28
8
  path: "contract.ts",
29
9
  source: `${CARRIER_PREFIX}${canonicalizeContract(contract)}${CARRIER_SUFFIX}`,
30
10
  };
31
11
  }
32
- /**
33
- * The ClientContract a carrier file holds — its whole text, banner included —
34
- * or `undefined` when it is not one this generator wrote over a contract that
35
- * still verifies: a foreign prefix or suffix, bytes that are not JSON, a body
36
- * that is not a ClientContract or whose hash does not re-verify, or bytes that
37
- * are not that contract's canonical form. Never trusted otherwise (Q6: a carrier
38
- * that does not re-hash is treated as absent).
39
- */
40
12
  export async function parseContractCarrier(text) {
41
13
  const opening = withGeneratedBanner(CARRIER_PREFIX);
42
14
  if (!text.startsWith(opening) || !text.endsWith(CARRIER_SUFFIX)) {
@@ -1,14 +1,14 @@
1
1
  import type { EmittedModule } from "./emitted-tree.interface.js";
2
2
  /**
3
- * The derivation, transported (Phase 12-rest S2, Q1 = A). A generated client's
4
- * argument and result types are core's own `OperationArgumentsFor`,
5
- * `OperationResultFor` and the call grammar (`OperationCall`, …) — never a second
6
- * spelling. They reach the emitted tree as core's PUBLISHED DECLARATIONS, copied
7
- * under `generated/derivation/` at their path relative to core's `dist`:
3
+ * The derivation, transported. A generated client's argument and result types are
4
+ * core's own `OperationArgumentsFor`, `OperationResultFor` and the call grammar
5
+ * (`OperationCall`, …) — never a second spelling. They reach the emitted tree as
6
+ * core's PUBLISHED DECLARATIONS, copied under `generated/derivation/` at their
7
+ * path relative to core's `dist`:
8
8
  *
9
9
  * - declarations, not sources: the sources' closure carries value imports (the
10
- * canonicaliser, the wire grammars), the declarations' carries none (plan M1);
11
- * a `.d.ts` cannot carry runtime, so a bundler never sees one;
10
+ * canonicaliser, the wire grammars), the declarations' carries none; a `.d.ts`
11
+ * cannot carry runtime, so a bundler never sees one;
12
12
  * - under their own directory, so core's `runtime/decimal.d.ts` cannot shadow the
13
13
  * emitted `generated/runtime/decimal.ts`;
14
14
  * - byte for byte, except the trailing `//# sourceMappingURL=…` line, which names
@@ -1,34 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- /**
5
- * The derivation, transported (Phase 12-rest S2, Q1 = A). A generated client's
6
- * argument and result types are core's own `OperationArgumentsFor`,
7
- * `OperationResultFor` and the call grammar (`OperationCall`, …) — never a second
8
- * spelling. They reach the emitted tree as core's PUBLISHED DECLARATIONS, copied
9
- * under `generated/derivation/` at their path relative to core's `dist`:
10
- *
11
- * - declarations, not sources: the sources' closure carries value imports (the
12
- * canonicaliser, the wire grammars), the declarations' carries none (plan M1);
13
- * a `.d.ts` cannot carry runtime, so a bundler never sees one;
14
- * - under their own directory, so core's `runtime/decimal.d.ts` cannot shadow the
15
- * emitted `generated/runtime/decimal.ts`;
16
- * - byte for byte, except the trailing `//# sourceMappingURL=…` line, which names
17
- * a map the tree does not hold.
18
- *
19
- * The closure is walked here, at generation time, from {@link DERIVATION_ROOTS}
20
- * over whichever `@aventara/core` this package resolves — so the output is a
21
- * function of the core version the generator depends on, as the rest of it is a
22
- * function of the generator. A closure that names a package, carries a
23
- * triple-slash reference, or leaves core's declarations is refused: it cannot be
24
- * transported, and core's own gate (`emittable-closure.gate.spec.ts`) exists so
25
- * that it never is.
26
- */
27
- /**
28
- * The modules whose declarations the generated client copies — the roots of core's
29
- * `emittable-closure.gate.spec.ts`, mirrored (core cannot export a test constant,
30
- * and this package cannot read core's tests).
31
- */
4
+ import { scanModuleSpecifiers } from "./module-specifier.scanner.js";
32
5
  export const DERIVATION_ROOTS = [
33
6
  "contracts/contract",
34
7
  "contracts/scalar-value-type",
@@ -39,7 +12,6 @@ export const DERIVATION_ROOTS = [
39
12
  "transactions/deferred-operation",
40
13
  "transactions/transaction-reference",
41
14
  ];
42
- /** The published declarations of the `@aventara/core` this package resolves. */
43
15
  export function publishedCoreDeclarations() {
44
16
  const dist = path.dirname(fileURLToPath(import.meta.resolve("@aventara/core")));
45
17
  return (relative) => {
@@ -54,13 +26,6 @@ export function publishedCoreDeclarations() {
54
26
  }
55
27
  };
56
28
  }
57
- /**
58
- * Core's declaration closure from {@link DERIVATION_ROOTS}, as modules under
59
- * `derivation/`, in UTF-16 code-unit order of their path.
60
- *
61
- * @throws Error when the closure cannot be transported — a defect of the
62
- * installed `@aventara/core`, never of the consumer's input.
63
- */
64
29
  export function emitDerivationModules(read = publishedCoreDeclarations()) {
65
30
  const copied = new Map();
66
31
  const queue = DERIVATION_ROOTS.map((root) => `${root}.d.ts`);
@@ -73,7 +38,7 @@ export function emitDerivationModules(read = publishedCoreDeclarations()) {
73
38
  if (text === undefined) {
74
39
  throw new Error(`@aventara/core's declaration closure names ${file}, which it does not publish.`);
75
40
  }
76
- const scanned = scanDeclaration(text);
41
+ const scanned = scanModuleSpecifiers(text);
77
42
  if (scanned.references) {
78
43
  throw untransportable(`${file} carries a triple-slash reference, which the emitted tree cannot satisfy`);
79
44
  }
@@ -92,10 +57,6 @@ export function emitDerivationModules(read = publishedCoreDeclarations()) {
92
57
  function untransportable(reason) {
93
58
  return new Error(`@aventara/core's declarations cannot be copied into the generated client: ${reason}.`);
94
59
  }
95
- /**
96
- * The declaration file a specifier names, relative to core's `dist`: a relative
97
- * `.js` specifier inside it, as NodeNext resolves an emitted declaration's import.
98
- */
99
60
  function declarationTarget(file, specifier) {
100
61
  const leaves = () => untransportable(`${file} names ${JSON.stringify(specifier)}, which is not a declaration file beside it`);
101
62
  if (!(specifier.startsWith("./") || specifier.startsWith("../")) ||
@@ -108,126 +69,6 @@ function declarationTarget(file, specifier) {
108
69
  }
109
70
  return target.replace(/\.js$/, ".d.ts");
110
71
  }
111
- /** `text` without its final `//# sourceMappingURL=…` line, when it ends with one. */
112
72
  function withoutSourceMapTrailer(text) {
113
73
  return text.replace(/(^|\n)\/\/# sourceMappingURL=[^\n]*\n?$/, "$1");
114
74
  }
115
- /**
116
- * A word followed directly by a string literal names a module. A pattern, not two
117
- * string comparisons: the packaging gate reads shipped JavaScript lexically, and
118
- * a keyword spelled as a quoted literal would read to it as an import.
119
- */
120
- const SPECIFIER_KEYWORD = /^(?:from|import)$/;
121
- /**
122
- * The specifiers one declaration file names, read by a small lexer rather than
123
- * by `typescript` (an optional peer, absent from a consumer's install): comments,
124
- * string literals and template literals are skipped as units, so text inside them
125
- * is never mistaken for an import. Agrees with TypeScript's own pre-processor
126
- * over core's closure (`derivation.emitter.spec.ts`).
127
- */
128
- function scanDeclaration(text) {
129
- const tokens = [];
130
- let references = false;
131
- let index = 0;
132
- const readQuoted = (quote) => {
133
- let value = "";
134
- index += 1;
135
- while (index < text.length && text[index] !== quote) {
136
- if (text[index] === "\\") {
137
- value += text[index + 1] ?? "";
138
- index += 2;
139
- continue;
140
- }
141
- value += text[index];
142
- index += 1;
143
- }
144
- index += 1;
145
- return value;
146
- };
147
- /** Scans code until the end, or until the `}` closing a `${` when `inPlaceholder`. */
148
- const scanCode = (inPlaceholder) => {
149
- let depth = 0;
150
- while (index < text.length) {
151
- const character = text[index];
152
- const next = text[index + 1];
153
- if (character === "/" && next === "/") {
154
- const end = text.indexOf("\n", index);
155
- const line = text.slice(index, end === -1 ? text.length : end);
156
- if (/^\/\/\/\s*<reference\b/.test(line)) {
157
- references = true;
158
- }
159
- index = end === -1 ? text.length : end + 1;
160
- }
161
- else if (character === "/" && next === "*") {
162
- const end = text.indexOf("*/", index + 2);
163
- index = end === -1 ? text.length : end + 2;
164
- }
165
- else if (character === '"' || character === "'") {
166
- tokens.push({ kind: "string", value: readQuoted(character) });
167
- }
168
- else if (character === "`") {
169
- scanTemplate();
170
- }
171
- else if (/[A-Za-z_$]/.test(character)) {
172
- const start = index;
173
- while (index < text.length && /[\w$]/.test(text[index])) {
174
- index += 1;
175
- }
176
- tokens.push({ kind: "word", value: text.slice(start, index) });
177
- }
178
- else if (/\s/.test(character)) {
179
- index += 1;
180
- }
181
- else {
182
- if (inPlaceholder && character === "{") {
183
- depth += 1;
184
- }
185
- else if (inPlaceholder && character === "}") {
186
- if (depth === 0) {
187
- index += 1;
188
- return;
189
- }
190
- depth -= 1;
191
- }
192
- tokens.push({ kind: "punctuation", value: character });
193
- index += 1;
194
- }
195
- }
196
- };
197
- const scanTemplate = () => {
198
- index += 1;
199
- while (index < text.length && text[index] !== "`") {
200
- if (text[index] === "\\") {
201
- index += 2;
202
- }
203
- else if (text[index] === "$" && text[index + 1] === "{") {
204
- index += 2;
205
- scanCode(true);
206
- }
207
- else {
208
- index += 1;
209
- }
210
- }
211
- index += 1;
212
- // A template is one opaque token: nothing before it pairs with it.
213
- tokens.push({ kind: "punctuation", value: "`" });
214
- };
215
- scanCode(false);
216
- const specifiers = [];
217
- tokens.forEach((token, at) => {
218
- const following = tokens[at + 1];
219
- if (token.kind !== "word") {
220
- return;
221
- }
222
- if (SPECIFIER_KEYWORD.test(token.value) && following?.kind === "string") {
223
- specifiers.push(following.value);
224
- }
225
- else if (token.value === "import" &&
226
- following?.kind === "punctuation" &&
227
- following.value === "(" &&
228
- tokens[at + 2]?.kind === "string") {
229
- specifiers.push(tokens[at + 2].value);
230
- }
231
- });
232
- return { specifiers, references };
233
- }
@@ -1,36 +1,11 @@
1
1
  import { isOperationVariantAvailable, } from "@aventara/core";
2
2
  import { ownPropertyKey } from "./name.deriver.js";
3
- /**
4
- * `generated/runtime/descriptor.ts` — what the RUNTIME needs of the ClientContract,
5
- * as data (P1, P4). A projection of the same accepted contract the carrier
6
- * (`generated/contract.ts`) holds, derived in the same run, so it is not a second
7
- * source: `descriptor.emitter.spec.ts` regenerates it from the parsed carrier and
8
- * compares.
9
- *
10
- * - **The decode table (P1).** Encoding is decidable by a value's runtime class;
11
- * decoding is not — a wire `"12"` is a `string`, a `bigint` or a `decimal`
12
- * depending only on the field (M13). So per Resource the table names each
13
- * result field whose wire string is revived (`bigint`, `decimal`, `datetime`,
14
- * `bytes`, §6.2) and each relation with its target and whether it is to-many,
15
- * which the decode walk recurses into (S5 added `many`: a to-one record may
16
- * itself hold a `data` and a `count` field, so the shape alone cannot say). Every other key passes through untouched; `json` is never
17
- * revived.
18
- * - **The advertised operations (P4).** Read here through core's
19
- * `isOperationVariantAvailable`, emitted as `[resource, family, variant]`; the
20
- * type grammar reads the carrier's `operations` keys. They agree while present
21
- * ⇔ advertised (Phase 10 A3), and a gate asserts it over both pilots.
22
- *
23
- * Every registry is walked in UTF-16 code-unit order, so the key order a
24
- * contract arrives in never reaches the bytes (C-843).
25
- */
26
- /** The scalars whose wire form a decoder revives into another runtime class (§6.2). */
27
3
  const REVIVED_SCALARS = new Set([
28
4
  "bigint",
29
5
  "bytes",
30
6
  "datetime",
31
7
  "decimal",
32
8
  ]);
33
- /** `generated/runtime/descriptor.ts`, before the banner. */
34
9
  export function emitDescriptorModule(contract) {
35
10
  const resources = codeUnitOrder(Object.keys(contract.resources));
36
11
  const table = resources.map((name) => {
@@ -55,9 +30,9 @@ export function emitDescriptorModule(contract) {
55
30
  return {
56
31
  path: "runtime/descriptor.ts",
57
32
  source: "/**\n" +
58
- " * A result field the decoder revives from its wire string (§6.2), or a relation\n" +
33
+ " * A result field the decoder revives from its wire string, or a relation\n" +
59
34
  " * it recurses into, read as the relation's target Resource — `many` saying the\n" +
60
- " * value is a list, `{ data, count }` or `{ count }` rather than one record (P1).\n" +
35
+ " * value is a list, `{ data, count }` or `{ count }` rather than one record.\n" +
61
36
  " */\n" +
62
37
  "export type FieldDecoding =\n" +
63
38
  '\t| "bigint"\n' +
@@ -79,7 +54,6 @@ export function emitDescriptorModule(contract) {
79
54
  `])[] = [${advertised.length === 0 ? "" : `\n${advertised.join("")}`}];\n`,
80
55
  };
81
56
  }
82
- /** The table entry a field needs, as source, or `undefined` when it passes through. */
83
57
  function decodingOf(field) {
84
58
  if (field === undefined) {
85
59
  return undefined;
@@ -1,37 +1,58 @@
1
1
  /**
2
- * The generator's output as a VALUE before it is a filesystem effect (plan §7,
3
- * group 3). Byte-equality is therefore testable without touching disk, and
4
- * temp → validate → replace (S7) is a property of the writer alone rather than of
5
- * every emitter.
2
+ * The generator's output as a VALUE before it is a filesystem effect.
3
+ * Byte-equality is therefore testable without touching disk, and temp → validate →
4
+ * replace is a property of the writer alone rather than of every emitter.
6
5
  */
6
+ import type { ClientModuleStyle } from "./module-style.interface.js";
7
7
  /**
8
- * The output layout (architect, 2026-10-04): the consumer names a directory,
9
- * `generateAt`, which is SHARED — they may keep their own files there. The
10
- * generator owns exactly two entries in it:
8
+ * The output layout: the consumer names a directory, `generateAt`, which is SHARED
9
+ * — they may keep their own files there. The generator owns exactly two entries in
10
+ * it:
11
11
  *
12
12
  * - `AvClient.ts`, the entry point a consumer imports;
13
13
  * - `generated/`, every other module, owned and replaced whole.
14
+ *
15
+ * The tree is TypeScript source that the developer's own toolchain compiles like
16
+ * their own files — `tsc`, Next.js (Turbopack or webpack), Vite, `tsx`, Node's
17
+ * type stripping. pilot.1's tree always spelled its internal imports NodeNext's
18
+ * way (`./generated/client.js`), which a bundler that does not map `.js` back to
19
+ * `.ts` (Turbopack) and plain Node could not follow. Now those specifiers are the
20
+ * project's: extensionless, `.js` or `.ts`, as its `tsconfig.json` decides
21
+ * (`module-style.interface.ts`, Prisma 7's rules). A consumer imports the entry as
22
+ * they import their own files — `./api/AvClient`, `./api/AvClient.js` or
23
+ * `./api/AvClient.ts`.
14
24
  */
15
25
  /** The entry point, at the root of `generateAt`. */
16
26
  export declare const CLIENT_ENTRY_FILE = "AvClient.ts";
27
+ /** The files the generator owns at the root of `generateAt`. */
28
+ export declare const CLIENT_ENTRY_FILES: readonly ["AvClient.ts"];
29
+ /** One of the entry point's files. */
30
+ export type ClientEntryFile = (typeof CLIENT_ENTRY_FILES)[number];
31
+ /**
32
+ * Entry files an unreleased build of this generator wrote — JavaScript beside
33
+ * declarations, never published. Each is the generator's only while it carries
34
+ * the ownership line: a generation removes it then, so no stale `AvClient.mjs`
35
+ * is left beside the `AvClient.ts` it was replaced by. One without the line is
36
+ * the developer's file, and nothing reads, refuses on or removes it. (pilot.0's
37
+ * and pilot.1's entry is `AvClient.ts` itself, replaced in place.)
38
+ */
39
+ export declare const LEGACY_CLIENT_ENTRY_FILES: readonly string[];
17
40
  /** The directory holding every other emitted module, under `generateAt`. */
18
41
  export declare const GENERATED_DIRECTORY = "generated";
19
42
  /**
20
43
  * One of core's published declaration files, copied under `generated/derivation/`
21
- * at its path relative to core's `dist` (Q1 = A, `derivation.emitter.ts`).
44
+ * at its path relative to core's `dist`.
22
45
  */
23
46
  export type DerivationModulePath = `derivation/${string}.d.ts`;
24
47
  /**
25
- * The modules under `generated/`: the emitted sources, the carrier
26
- * (`contract.ts`, Q4), the typed surface (`client.ts`) and named types
27
- * (`types.d.ts`, S4 — a declaration file, architect 2026-10-05), and core's declarations under `derivation/`. §15.4's
28
- * `runtime/transaction.ts` and `runtime/fingerprint.ts` exist iff transactions
29
- * are interactive (S6, P3); `resources/` and `runtime/projection.ts` are not
30
- * emitted (plan §7).
31
- *
32
48
  * Relative to `generated/`, POSIX-separated.
33
49
  */
34
50
  export type GeneratedModulePath = DerivationModulePath | "client.ts" | "contract.ts" | "enums.ts" | "metadata.ts" | "runtime/codec.ts" | "runtime/decimal.ts" | "runtime/descriptor.ts" | "runtime/errors.ts" | "runtime/fingerprint.ts" | "runtime/transaction.ts" | "runtime/transport.ts" | "types.d.ts";
51
+ /**
52
+ * The carrier: the ClientContract the tree was generated against, under
53
+ * `generated/` — the module a rerun reads back to ask for a `304`.
54
+ */
55
+ export declare const CONTRACT_CARRIER_MODULE = "contract.ts";
35
56
  /** A path in the emitted tree: relative to `generateAt`, POSIX-separated. */
36
57
  export type EmittedFilePath = typeof CLIENT_ENTRY_FILE | `${typeof GENERATED_DIRECTORY}/${GeneratedModulePath}`;
37
58
  /** One module's TypeScript source under `generated/`, before the banner and before encoding. */
@@ -46,8 +67,8 @@ export interface EmittedFile {
46
67
  }
47
68
  /**
48
69
  * Every file one generation emits, in UTF-16 code-unit order of `path`, each path
49
- * once — `AvClient.ts` first, then `generated/**`. Replaced, never merged
50
- * (§15.3): `generated/` whole, `AvClient.ts` as one file.
70
+ * once — `AvClient.ts` first, then `generated/**`. Replaced, never merged:
71
+ * `generated/` whole, `AvClient.ts` as one file.
51
72
  */
52
73
  export type EmittedTree = readonly EmittedFile[];
53
74
  /**
@@ -57,5 +78,7 @@ export type EmittedTree = readonly EmittedFile[];
57
78
  */
58
79
  export interface ClientEmission {
59
80
  readonly tree: EmittedTree;
81
+ /** The project's spelling the tree was emitted in, and is validated in. */
82
+ readonly style: ClientModuleStyle;
60
83
  readonly warnings: readonly string[];
61
84
  }
@@ -1,18 +1,8 @@
1
- /**
2
- * The generator's output as a VALUE before it is a filesystem effect (plan §7,
3
- * group 3). Byte-equality is therefore testable without touching disk, and
4
- * temp → validate → replace (S7) is a property of the writer alone rather than of
5
- * every emitter.
6
- */
7
- /**
8
- * The output layout (architect, 2026-10-04): the consumer names a directory,
9
- * `generateAt`, which is SHARED — they may keep their own files there. The
10
- * generator owns exactly two entries in it:
11
- *
12
- * - `AvClient.ts`, the entry point a consumer imports;
13
- * - `generated/`, every other module, owned and replaced whole.
14
- */
15
- /** The entry point, at the root of `generateAt`. */
16
1
  export const CLIENT_ENTRY_FILE = "AvClient.ts";
17
- /** The directory holding every other emitted module, under `generateAt`. */
2
+ export const CLIENT_ENTRY_FILES = [CLIENT_ENTRY_FILE];
3
+ export const LEGACY_CLIENT_ENTRY_FILES = [
4
+ "AvClient.d.mts",
5
+ "AvClient.mjs",
6
+ ];
18
7
  export const GENERATED_DIRECTORY = "generated";
8
+ export const CONTRACT_CARRIER_MODULE = "contract.ts";
@@ -3,7 +3,7 @@ import type { EmittedModule } from "./emitted-tree.interface.js";
3
3
  import { type EmittedNames } from "./name.deriver.js";
4
4
  /**
5
5
  * `enums.ts`: per enum, a string-literal union type and a same-named `as const`
6
- * object (§15.4's "enum types"; architect decision, 2026-10-04):
6
+ * object:
7
7
  *
8
8
  * ```ts
9
9
  * export type Role = "ADMIN" | "USER";
@@ -17,8 +17,8 @@ import { type EmittedNames } from "./name.deriver.js";
17
17
  * renamed.
18
18
  *
19
19
  * Enums come in the order `names` gives them — UTF-16 code units of the contract
20
- * name — so the key order a contract arrives in never reaches the bytes (C-843).
21
- * An enum's VALUES keep their declared order, in the type and in the object: that
22
- * order is meaning, and canonical form keeps it too.
20
+ * name — so the key order a contract arrives in never reaches the bytes. An enum's
21
+ * VALUES keep their declared order, in the type and in the object: that order is
22
+ * meaning, and canonical form keeps it too.
23
23
  */
24
24
  export declare function emitEnumsModule(contract: Pick<ClientContract, "enums">, names: EmittedNames): EmittedModule;