@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
package/README.md CHANGED
@@ -23,7 +23,7 @@ It asks — or takes from flags, or with `--yes` takes every default — four th
23
23
  | `--generate-at <dir>` | Where the client goes | `./src/api` |
24
24
  | `--package-manager <npm\|pnpm>` | | the lockfile's, else the launching one, else npm |
25
25
 
26
- It writes `framework.client.mts`, the variable into `.env` (only with a variable), `"avclient:generate": "avclient
26
+ It writes `framework.client.ts` (or reuses the config the project already has), the variable into `.env` (only with a variable), `"avclient:generate": "avclient
27
27
  generate"` into the scripts and `@aventara/client` as an **exact** devDependency at its own version; runs the install
28
28
  (`--skip-install` prints it instead); and generates the client right away (`--skip-generate` to skip; a server that does
29
29
  not answer leaves the files and names `avclient generate`). Existing content that differs is listed and replaced only
@@ -32,7 +32,7 @@ committed: regenerating it needs a running server.
32
32
 
33
33
  ## Generating a client
34
34
 
35
- Install it as a dev dependency (or let `avclient init` do it), then add `framework.client.mts` to the directory you run
35
+ Install it as a dev dependency (or let `avclient init` do it), then add `framework.client.ts` to the directory you run
36
36
  the generator from:
37
37
 
38
38
  ```ts
@@ -50,15 +50,34 @@ and run:
50
50
  npx avclient generate [--yes]
51
51
  ```
52
52
 
53
- **Why `.mts`.** `npm init -y` writes `"type": "commonjs"`, and under it Node reads a `.ts` file as CommonJS — the
54
- config's `import` would stop the run. A `.mts` file is an ES module in every project. A `framework.client.ts` written
55
- before 0.1.0-pilot.1 is still read; with both files present the generator refuses, and `avclient init` moves the old one
56
- to `framework.client.mts` (asking first if you edited it).
53
+ **The config file** is loaded the way Prisma 7 loads `prisma.config.ts`: `framework.client.ts` — or `.mts`, `.cts`,
54
+ `.js`, `.mjs`, `.cjs` — in ES module or CommonJS syntax, whatever your `package.json`'s `"type"`. A
55
+ `framework.client.mts` written by 0.1.0-pilot.1 keeps working, and `avclient init` reuses it. Two config files in one
56
+ directory are refused, naming both.
57
57
 
58
58
  - **`entrypoint`** is the deployment's framework entrypoint: origin plus mount path, one absolute `http(s)` URL. It
59
59
  may not carry credentials — the platform's `fetch` refuses such a URL, and the entrypoint ships inside the client.
60
60
  - **`generateAt`** is a directory you may share with your own files. The generator owns exactly two entries in it —
61
61
  `AvClient.ts` and `generated/` — and never reads, moves or removes anything else there.
62
+
63
+ ### Your tsconfig decides how the client is written
64
+
65
+ The client is TypeScript source that **your own toolchain compiles**, like your own files — `tsc`, Next.js (Turbopack or
66
+ webpack), Vite, `tsx`, Node's type stripping. Its modules import each other the way your project imports its files,
67
+ read from your `tsconfig.json` (the nearest one above `generateAt`, `extends` included) by Prisma 7's rules:
68
+
69
+ | Your tsconfig | The client's own imports | You import it as |
70
+ |---|---|---|
71
+ | `allowImportingTsExtensions` or `rewriteRelativeImportExtensions` (Vite's react-ts template, Node's type stripping) | `./generated/client.ts` | `./api/AvClient.ts` |
72
+ | `moduleResolution: "bundler"` (Next.js) or `module: "commonjs"` | `./generated/client` | `./api/AvClient` |
73
+ | anything else — `module: "nodenext"`/`"node16"` (NestJS 12) | `./generated/client.js` | `./api/AvClient.js` (ES module) or `./api/AvClient` (CommonJS) |
74
+
75
+ Under `nodenext`, the nearest `package.json`'s `"type"` decides whether the client is checked as an ES module or as
76
+ CommonJS. Vite's `tsconfig.json`, which only lists `references`, defers to the referenced project that includes the
77
+ client (`tsconfig.app.json`). The validate step type-checks the client in your project's resolution and module format.
78
+
79
+ A project with no `tsconfig.json` is refused: the generated client is TypeScript, and JavaScript projects are not
80
+ supported yet.
62
81
  - **The `.env` cascade** is read from the current directory before the config is evaluated, highest precedence first:
63
82
  the process environment, `.env.<mode>.local`, `.env.<mode>`, `.env.local`, `.env`; `mode` is `NODE_ENV`, or
64
83
  `development`. The config reads it through `env("NAME")`; `process.env` is never written.
@@ -72,8 +91,9 @@ to `framework.client.mts` (asking first if you edited it).
72
91
  - **A failed run leaves the previous output exactly as it was.** The whole tree is written to a staging directory inside
73
92
  `generateAt`, validated there as one program, and only then moved into place. A run killed part-way is repaired by the
74
93
  next run that writes, before it writes anything. A first run that fails removes the directories it created.
75
- - **The validate step is a real type check** when the optional peer `typescript` (5.5 to 6) is installed, under a
76
- consumer's strictest plausible settings and with nothing outside the tree resolvable. Without it — or under
94
+ - **The validate step is a real type check** when your project has the optional peer `typescript` (5.5 to 6) — it is
95
+ resolved from your project, so `npx @aventara/client@pilot init` type-checks too — under a consumer's strictest plausible
96
+ settings and with nothing outside the tree resolvable. Without it — or under
77
97
  TypeScript 7, which has no classic compiler API to check with — the check degrades to a parse with Node's own
78
98
  TypeScript parser, and says so loudly in one warning; it is never skipped, and the client is still written. The peer
79
99
  range has no upper bound, so a frontend on TypeScript 7 installs it; your own `tsc` checks the tree when it compiles.
@@ -85,7 +105,7 @@ to `framework.client.mts` (asking first if you edited it).
85
105
  ## Calling the API
86
106
 
87
107
  ```ts
88
- import avClient, { AvClient, type User, type UserWhere } from "./api/AvClient";
108
+ import avClient, { AvClient, type User, type UserWhere } from "./api/AvClient"; // as you import your own files
89
109
 
90
110
  const where: UserWhere = { email: { equals: "ada@example.com" } };
91
111
  const users = await avClient.User.find.many({ where, select: ["id", "email", { posts: { select: ["$count"] } }] });
@@ -229,6 +249,21 @@ program, the 500,000 line near 150 Resources.
229
249
  `Aventara-Request-Id`) may still change before the first stable release. It is one constant in the generated
230
250
  `generated/runtime/transport.ts`; regenerating picks up a change.
231
251
 
252
+ ## Known issues
253
+
254
+ - **The generator read the wrong `tsconfig.json`.** In a monorepo or a non-standard layout, the nearest
255
+ `tsconfig.json` above `generateAt` may not be the one your project compiles the client with, and the client's
256
+ imports or module format then do not match your compiler (`Cannot find module './generated/client.js'`, an
257
+ extension your bundler will not resolve). Name the right one in `framework.client.ts`, relative to the config file:
258
+
259
+ ```ts
260
+ export default defineClientConfig({
261
+ entrypoint: env("AVENTARA_API_URL"),
262
+ generateAt: "./src/api",
263
+ tsconfigFile: "./tsconfig.app.json",
264
+ });
265
+ ```
266
+
232
267
  ## License
233
268
 
234
269
  PolyForm Shield 1.0.0 with an additional permission — free to use, including in commercial applications; you may not
@@ -1,15 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import { refuseUnsupportedNode } from "./node-version.guard.js";
3
- /**
4
- * `avclient`'s entry, what the manifest's `bin` names (F-855). It always runs — no
5
- * `import.meta.main` — and checks this Node against the package's
6
- * `engines.node` before it loads anything else: the program is imported only
7
- * once the guard admits this Node, so an older Node meets one sentence and exit
8
- * 1, never a silent exit 0 or a parse error from a module it cannot run.
9
- *
10
- * A promise chain rather than a top-level `await`, which Node 12 cannot parse:
11
- * this file is read by the Nodes the package does not support.
12
- */
13
3
  if (!refuseUnsupportedNode("avclient", new URL("../package.json", import.meta.url))) {
14
4
  void import("./cli.js").then((program) => program.runFromProcess());
15
5
  }
@@ -1,16 +1,16 @@
1
1
  /**
2
- * The `avclient` command line: one command, its one flag, and help. Everything
3
- * the generator needs is in `framework.client.ts` and the `.env` cascade (§15.2),
4
- * so `generate` takes no flag that would duplicate a config member — a second
5
- * source of the same fact. `--yes` is not one: it answers the one question the
6
- * generator asks (architect, 2026-10-04).
2
+ * The `avclient` command line: one command, its one flag, and help. Everything the
3
+ * generator needs is in `framework.client.ts` and the `.env` cascade, so
4
+ * `generate` takes no flag that would duplicate a config member — a second source
5
+ * of the same fact. `--yes` is not one: it answers the one question the generator
6
+ * asks.
7
7
  */
8
- export declare const USAGE = "avclient \u2014 generate a typed Aventara client from a deployed ClientContract.\n\nUsage:\n avclient generate [--yes] Read framework.client.mts (or framework.client.ts) in the\n current directory, fetch <entrypoint>/_contract, and\n write AvClient.ts and generated/ into its generateAt\n directory.\n avclient init [options] Set up this frontend: write framework.client.mts, the\n .env entry, the avclient:generate script and the\n @aventara/client devDependency; install; generate.\n --entrypoint <url> The server's entrypoint [http://localhost:3000/api].\n --env-var <NAME> Read it from this variable [AVENTARA_API_URL].\n --no-env-var Write it into framework.client.mts as a literal.\n --generate-at <dir> Where the client goes [./src/api].\n --package-manager <npm|pnpm> [the lockfile's, else the launching one, else npm]\n --skip-install Print the install instead of running it.\n --skip-generate Do not generate now.\n -y, --yes Accept every default, and replace differing content.\n avclient --help Print this and exit 0.\n avclient <command> --help Print that command's usage and exit 0.\n\nOptions:\n -y, --yes Overwrite or remove content in AvClient.ts and generated/ that the\n generator did not produce, without asking. Without it, such content\n is listed and you are asked; where nobody can answer (stdin is not a\n terminal, as in CI), the run is refused and nothing is touched.\n\nThe generator owns AvClient.ts and generated/ in generateAt, and nothing else\nthere: your own files beside them are never read, moved or removed. Generated\nfiles are replaced on every run; do not edit them.\n\nBefore framework.client.mts is evaluated, the .env cascade is read from the\ncurrent directory, highest precedence first: the process environment,\n.env.<mode>.local, .env.<mode>, .env.local, .env \u2014 where mode is NODE_ENV, or\n\"development\".\n";
8
+ export declare const USAGE = "avclient \u2014 generate a typed Aventara client from a deployed ClientContract.\n\nUsage:\n avclient generate [--yes] Read framework.client.ts (or .js, .mjs, .cjs, .mts,\n .cts) in the current directory, fetch\n <entrypoint>/_contract, and write AvClient.ts and\n generated/ into its generateAt directory, its imports\n spelled as the project's tsconfig.json says.\n avclient init [options] Set up this frontend: write framework.client.ts, the\n .env entry, the avclient:generate script and the\n @aventara/client devDependency; install; generate.\n --entrypoint <url> The server's entrypoint [http://localhost:3000/api].\n --env-var <NAME> Read it from this variable [AVENTARA_API_URL].\n --no-env-var Write it into framework.client.ts as a literal.\n --generate-at <dir> Where the client goes [./src/api].\n --package-manager <npm|pnpm> [the lockfile's, else the launching one, else npm]\n --skip-install Print the install instead of running it.\n --skip-generate Do not generate now.\n -y, --yes Accept every default, and replace differing content.\n avclient --help Print this and exit 0.\n avclient <command> --help Print that command's usage and exit 0.\n avclient --version, -v Print this generator's version and exit 0.\n\nOptions:\n -y, --yes Overwrite or remove content in AvClient.ts and generated/ that the\n generator did not produce, without asking. Without it, such content\n is listed and you are asked; where nobody can answer (stdin is not a\n terminal, as in CI), the run is refused and nothing is touched.\n\nThe generator owns AvClient.ts and generated/ in generateAt, and nothing else\nthere: your own files beside them are never read, moved or removed. Generated\nfiles are replaced on every run; do not edit them.\n\nBefore framework.client.ts is evaluated, the .env cascade is read from the\ncurrent directory, highest precedence first: the process environment,\n.env.<mode>.local, .env.<mode>, .env.local, .env \u2014 where mode is NODE_ENV, or\n\"development\".\n";
9
9
  /** `avclient generate --help` (pilot.1): that command's usage alone. */
10
- export declare const GENERATE_USAGE = "Usage: avclient generate [--yes]\n\nRead framework.client.mts (or framework.client.ts) in the current directory, fetch\n<entrypoint>/_contract, and write AvClient.ts and generated/ into its generateAt\ndirectory.\n\nOptions:\n -y, --yes Overwrite or remove content in AvClient.ts and generated/ that the\n generator did not produce, without asking. Without it, such content\n is listed and you are asked; where nobody can answer (stdin is not a\n terminal, as in CI), the run is refused and nothing is touched.\n\nThe generator owns AvClient.ts and generated/ in generateAt, and nothing else\nthere: your own files beside them are never read, moved or removed.\n\nBefore the config is evaluated, the .env cascade is read from the current\ndirectory, highest precedence first: the process environment, .env.<mode>.local,\n.env.<mode>, .env.local, .env \u2014 where mode is NODE_ENV, or \"development\".\n";
10
+ export declare const GENERATE_USAGE = "Usage: avclient generate [--yes]\n\nRead framework.client.ts (or .js, .mjs, .cjs, .mts, .cts) in the current directory,\nfetch <entrypoint>/_contract, and write AvClient.ts and generated/ into its\ngenerateAt directory, its imports spelled as the project's tsconfig.json says.\n\nOptions:\n -y, --yes Overwrite or remove content in AvClient.ts and generated/ that the\n generator did not produce, without asking. Without it, such content\n is listed and you are asked; where nobody can answer (stdin is not a\n terminal, as in CI), the run is refused and nothing is touched.\n\nThe generator owns AvClient.ts and generated/ in generateAt, and nothing else\nthere: your own files beside them are never read, moved or removed.\n\nBefore the config is evaluated, the .env cascade is read from the current\ndirectory, highest precedence first: the process environment, .env.<mode>.local,\n.env.<mode>, .env.local, .env \u2014 where mode is NODE_ENV, or \"development\".\n";
11
11
  /** `avclient init --help` (pilot.1): that command's usage alone. */
12
- export declare const INIT_USAGE = "Usage: avclient init [options]\n\nSet up this frontend: write framework.client.mts, the .env entry, the avclient:generate\nscript and the @aventara/client devDependency; install; generate.\n\nOptions:\n --entrypoint <url> The server's entrypoint [http://localhost:3000/api].\n --env-var <NAME> Read it from this variable [AVENTARA_API_URL].\n --no-env-var Write it into framework.client.mts as a literal.\n --generate-at <dir> Where the client goes [./src/api].\n --package-manager <npm|pnpm> [the lockfile's, else the launching one, else npm]\n --skip-install Print the install instead of running it.\n --skip-generate Do not generate now.\n -y, --yes Accept every default, and replace differing content.\n\nOn a terminal every unanswered question is asked; anywhere else, pass its flag\nor --yes, or the run stops before writing anything.\n";
13
- /** `avclient init`'s command line (R4, Q16 rows 12–15). */
12
+ export declare const INIT_USAGE = "Usage: avclient init [options]\n\nSet up this frontend: write framework.client.ts, the .env entry, the avclient:generate\nscript and the @aventara/client devDependency; install; generate.\n\nOptions:\n --entrypoint <url> The server's entrypoint [http://localhost:3000/api].\n --env-var <NAME> Read it from this variable [AVENTARA_API_URL].\n --no-env-var Write it into framework.client.ts as a literal.\n --generate-at <dir> Where the client goes [./src/api].\n --package-manager <npm|pnpm> [the lockfile's, else the launching one, else npm]\n --skip-install Print the install instead of running it.\n --skip-generate Do not generate now.\n -y, --yes Accept every default, and replace differing content.\n\nOn a terminal every unanswered question is asked; anywhere else, pass its flag\nor --yes, or the run stops before writing anything.\n";
13
+ /** `avclient init`'s command line. */
14
14
  export type ClientInitCommand = {
15
15
  readonly command: "init";
16
16
  readonly given: Readonly<Partial<Record<"entrypoint" | "envVar" | "generateAt" | "packageManager", string>>>;
@@ -25,6 +25,8 @@ export type CliCommand =
25
25
  {
26
26
  readonly command: "help";
27
27
  readonly topic?: "generate" | "init";
28
+ } | {
29
+ readonly command: "version";
28
30
  } | {
29
31
  readonly command: "generate";
30
32
  readonly yes: boolean;
@@ -33,5 +35,8 @@ export type CliCommand =
33
35
  export declare class CliCommandError extends Error {
34
36
  readonly name = "CliCommandError";
35
37
  }
36
- /** @throws CliCommandError when `argv` is not `generate [--yes|-y]`, `--help` or `-h`. */
38
+ /**
39
+ * @throws CliCommandError when `argv` is not `generate [--yes|-y]`, `init …`,
40
+ * `--help`/`-h` or `--version`/`-v`.
41
+ */
37
42
  export declare function parseCliCommand(argv: readonly string[]): CliCommand;
@@ -1,18 +1,12 @@
1
- import { CLIENT_CONFIG_FILE, LEGACY_CLIENT_CONFIG_FILE, } from "../config/config.loader.js";
2
- /**
3
- * The `avclient` command line: one command, its one flag, and help. Everything
4
- * the generator needs is in `framework.client.ts` and the `.env` cascade (§15.2),
5
- * so `generate` takes no flag that would duplicate a config member — a second
6
- * source of the same fact. `--yes` is not one: it answers the one question the
7
- * generator asks (architect, 2026-10-04).
8
- */
1
+ import { CLIENT_CONFIG_FILE } from "../config/config.loader.js";
9
2
  export const USAGE = `avclient — generate a typed Aventara client from a deployed ClientContract.
10
3
 
11
4
  Usage:
12
- avclient generate [--yes] Read ${CLIENT_CONFIG_FILE} (or ${LEGACY_CLIENT_CONFIG_FILE}) in the
13
- current directory, fetch <entrypoint>/_contract, and
14
- write AvClient.ts and generated/ into its generateAt
15
- directory.
5
+ avclient generate [--yes] Read ${CLIENT_CONFIG_FILE} (or .js, .mjs, .cjs, .mts,
6
+ .cts) in the current directory, fetch
7
+ <entrypoint>/_contract, and write AvClient.ts and
8
+ generated/ into its generateAt directory, its imports
9
+ spelled as the project's tsconfig.json says.
16
10
  avclient init [options] Set up this frontend: write ${CLIENT_CONFIG_FILE}, the
17
11
  .env entry, the avclient:generate script and the
18
12
  @aventara/client devDependency; install; generate.
@@ -26,6 +20,7 @@ Usage:
26
20
  -y, --yes Accept every default, and replace differing content.
27
21
  avclient --help Print this and exit 0.
28
22
  avclient <command> --help Print that command's usage and exit 0.
23
+ avclient --version, -v Print this generator's version and exit 0.
29
24
 
30
25
  Options:
31
26
  -y, --yes Overwrite or remove content in AvClient.ts and generated/ that the
@@ -42,12 +37,11 @@ current directory, highest precedence first: the process environment,
42
37
  .env.<mode>.local, .env.<mode>, .env.local, .env — where mode is NODE_ENV, or
43
38
  "development".
44
39
  `;
45
- /** `avclient generate --help` (pilot.1): that command's usage alone. */
46
40
  export const GENERATE_USAGE = `Usage: avclient generate [--yes]
47
41
 
48
- Read ${CLIENT_CONFIG_FILE} (or ${LEGACY_CLIENT_CONFIG_FILE}) in the current directory, fetch
49
- <entrypoint>/_contract, and write AvClient.ts and generated/ into its generateAt
50
- directory.
42
+ Read ${CLIENT_CONFIG_FILE} (or .js, .mjs, .cjs, .mts, .cts) in the current directory,
43
+ fetch <entrypoint>/_contract, and write AvClient.ts and generated/ into its
44
+ generateAt directory, its imports spelled as the project's tsconfig.json says.
51
45
 
52
46
  Options:
53
47
  -y, --yes Overwrite or remove content in AvClient.ts and generated/ that the
@@ -62,7 +56,6 @@ Before the config is evaluated, the .env cascade is read from the current
62
56
  directory, highest precedence first: the process environment, .env.<mode>.local,
63
57
  .env.<mode>, .env.local, .env — where mode is NODE_ENV, or "development".
64
58
  `;
65
- /** `avclient init --help` (pilot.1): that command's usage alone. */
66
59
  export const INIT_USAGE = `Usage: avclient init [options]
67
60
 
68
61
  Set up this frontend: write ${CLIENT_CONFIG_FILE}, the .env entry, the avclient:generate
@@ -81,11 +74,9 @@ Options:
81
74
  On a terminal every unanswered question is asked; anywhere else, pass its flag
82
75
  or --yes, or the run stops before writing anything.
83
76
  `;
84
- /** The command line cannot be understood. A refusal: one sentence, exit 1. */
85
77
  export class CliCommandError extends Error {
86
78
  name = "CliCommandError";
87
79
  }
88
- /** @throws CliCommandError when `argv` is not `generate [--yes|-y]`, `--help` or `-h`. */
89
80
  export function parseCliCommand(argv) {
90
81
  const [command, ...rest] = argv;
91
82
  const help = "run `avclient --help` for usage.";
@@ -95,6 +86,9 @@ export function parseCliCommand(argv) {
95
86
  if (command === "--help" || command === "-h") {
96
87
  return { command: "help" };
97
88
  }
89
+ if (command === "--version" || command === "-v") {
90
+ return { command: "version" };
91
+ }
98
92
  if ((command === "init" || command === "generate") &&
99
93
  (rest.includes("--help") || rest.includes("-h"))) {
100
94
  return { command: "help", topic: command };
@@ -1,11 +1,5 @@
1
1
  import { generateClient } from "../generate.js";
2
2
  import { FOREIGN_CONTENT_QUESTION, renderForeignContentCancellation, renderForeignContentWarning, renderGenerationSuccess, renderUpToDate, } from "./generation-success.renderer.js";
3
- /**
4
- * `avclient generate` — the generation, the generateAt rule's question, and the
5
- * report. Shared by `init`, which generates once the project is set up.
6
- *
7
- * @throws whatever the generation raises; the caller renders it.
8
- */
9
3
  export async function runGenerate(io, yes) {
10
4
  const outcome = await generateClient({
11
5
  directory: io.cwd,
@@ -9,18 +9,6 @@ import { ClientProjectRefusedError } from "../init/client-project.inspector.js";
9
9
  import { OutputWriteError, warningsRaisedBeforeDefect, } from "../output/output.writer.js";
10
10
  import { CliCommandError } from "./command.parser.js";
11
11
  import { renderWarningLines } from "./warning.renderer.js";
12
- /**
13
- * How a failed generation reaches the person running it (M3, the adapter CLI's
14
- * precedent): a refusal is a sentence and a non-zero exit code, never a stack — a
15
- * stack printed over it buries the sentence that says what to do. Anything else is
16
- * a defect and keeps its stack.
17
- *
18
- * A refusal that stopped a run part-way carries what the run said before it —
19
- * a crash recovered, a name renamed — and those lines come first, in the order a
20
- * success prints them, so nothing the run did goes unreported because it failed.
21
- * A defect's come first too, then its stack, whole.
22
- */
23
- /** Every error the generator raises on purpose. One list, read by `instanceof`. */
24
12
  const REFUSALS = [
25
13
  CliCommandError,
26
14
  ClientConfigError,
@@ -39,8 +27,6 @@ export function renderGenerationFailure(error) {
39
27
  if (REFUSALS.some((refusal) => error instanceof refusal)) {
40
28
  const carried = error instanceof OutputWriteError ? error.warnings : [];
41
29
  return {
42
- // A refused contract carries its own (plan §7); the other refusals are 1,
43
- // the adapter CLI's precedent (M3).
44
30
  exitCode: error instanceof ContractProtocolError ? error.exitCode : 1,
45
31
  text: `${renderWarningLines(carried)}avclient: ${error.message}\n`,
46
32
  };
@@ -13,7 +13,10 @@ export interface GenerationSuccessReport {
13
13
  readonly stderr: string;
14
14
  }
15
15
  export declare function renderGenerationSuccess(result: ClientGenerated): GenerationSuccessReport;
16
- /** Nothing written (Phase 12-rest Q6): the deployment's ClientContract and these bytes are what is there. */
16
+ /**
17
+ * Nothing written: the deployment's ClientContract and these bytes are what is
18
+ * there.
19
+ */
17
20
  export declare function renderUpToDate(result: ClientUpToDate): GenerationSuccessReport;
18
21
  /**
19
22
  * What the person running the generator is told before being asked: every path
@@ -10,32 +10,19 @@ export function renderGenerationSuccess(result) {
10
10
  stderr: renderWarningLines(result.warnings),
11
11
  };
12
12
  }
13
- /** Nothing written (Phase 12-rest Q6): the deployment's ClientContract and these bytes are what is there. */
14
13
  export function renderUpToDate(result) {
15
14
  return {
16
15
  stdout: `avclient: up to date: ${result.generateAt} already holds this deployment's client; nothing was written.\n`,
17
16
  stderr: renderWarningLines(result.warnings),
18
17
  };
19
18
  }
20
- /**
21
- * What the person running the generator is told before being asked: every path
22
- * in `AvClient.ts` and `generated/` that the generator did not produce, which
23
- * proceeding overwrites or removes.
24
- */
25
19
  export function renderForeignContentWarning(found) {
26
20
  return (`${WARNING_LINE_PREFIX}${found.foreign.join(", ")} in ${found.generateAt} ` +
27
21
  `${found.foreign.length === 1 ? "was" : "were"} not generated by @aventara/client, ` +
28
22
  "and generating will overwrite or remove " +
29
23
  `${found.foreign.length === 1 ? "it" : "them"}.\n`);
30
24
  }
31
- /** The question; answered yes, generation proceeds. */
32
25
  export const FOREIGN_CONTENT_QUESTION = "avclient: overwrite them and generate? [y/N] ";
33
- /**
34
- * Nobody confirmed: nothing was touched. One sentence naming what to sort out —
35
- * and, where nobody could have been asked, the flag that answers yes — after
36
- * every warning the run raised before it stopped, so a cancelled run's renames
37
- * are reported as a refused one's are.
38
- */
39
26
  export function renderForeignContentCancellation(found, asked) {
40
27
  const them = found.foreign.length === 1 ? "it" : "them";
41
28
  return `${renderWarningLines(found.warnings)}${asked
@@ -2,8 +2,7 @@
2
2
  * The terminal's questions — `generate`'s yes/no and `init`'s wizard — over one
3
3
  * `node:readline` interface whose lines are **queued**: a line typed (or piped
4
4
  * into a pseudo-terminal) before its question is kept for it, where a fresh
5
- * interface per question, or `readline/promises`' `question`, drops it (measured
6
- * in `@aventara/cli`'s S5; the same rule there, P7).
5
+ * interface per question, or `readline/promises`' `question`, drops it.
7
6
  */
8
7
  export type TerminalPrompter = {
9
8
  readonly ask: (prompt: string) => Promise<string>;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * How one warning reaches the person running the generator: its own stderr line,
3
3
  * under the CLI's one prefix. Warnings carry no prefix of their own, so the line
4
- * says "warning" once (S7b's report: the degraded check used to say it twice).
5
- * Shared by a success and a refusal, so a warning reads the same either way.
4
+ * says "warning" once. Shared by a success and a refusal, so a warning reads the
5
+ * same either way.
6
6
  */
7
7
  /** The prefix every warning line opens with. */
8
8
  export declare const WARNING_LINE_PREFIX = "avclient: warning: ";
@@ -1,12 +1,4 @@
1
- /**
2
- * How one warning reaches the person running the generator: its own stderr line,
3
- * under the CLI's one prefix. Warnings carry no prefix of their own, so the line
4
- * says "warning" once (S7b's report: the degraded check used to say it twice).
5
- * Shared by a success and a refusal, so a warning reads the same either way.
6
- */
7
- /** The prefix every warning line opens with. */
8
1
  export const WARNING_LINE_PREFIX = "avclient: warning: ";
9
- /** One newline-terminated line per warning, in the order given; empty for none. */
10
2
  export function renderWarningLines(warnings) {
11
3
  return warnings
12
4
  .map((warning) => `${WARNING_LINE_PREFIX}${warning}\n`)
package/dist/cli.d.ts CHANGED
@@ -1,22 +1,14 @@
1
1
  import { type CliIo } from "./cli/generate.command.js";
2
2
  export type { CliIo } from "./cli/generate.command.js";
3
3
  /**
4
- * `avclient` — the generator's bin (`avclient generate`), S7b.
5
- *
6
- * It parses the command line, runs §15.3's pipeline (`generate.ts`) in the
7
- * current directory, and owns the terminal: the success line goes to stdout,
8
- * every warning the run returned to stderr in the run's order, and a failure
9
- * through the refusal renderer — a refusal is one sentence and exit 1 with no
10
- * stack (M3), anything else is a defect and keeps its stack.
11
- *
12
- * It is also the one place that ASKS (architect, 2026-10-04): when content the
13
- * generator did not produce stands in `AvClient.ts` or `generated/`, the paths
14
- * are listed and the person is asked whether to overwrite them. `--yes` answers
15
- * for them. Where nobody can answer — stdin is not a terminal — it never asks
16
- * and never overrides: it refuses, naming `--yes`. Cancelled or refused, nothing
17
- * was touched, the run's warnings are printed before the sentence, and the exit
18
- * code is 1. A killed run's leftovers are looked at before the question, so the
19
- * answer — and `--yes` — covers what it hid as well.
4
+ * It is also the one place that ASKS: when content the generator did not produce
5
+ * stands in `AvClient.ts` or `generated/`, the paths are listed and the person is
6
+ * asked whether to overwrite them. `--yes` answers for them. Where nobody can
7
+ * answer — stdin is not a terminal — it never asks and never overrides: it
8
+ * refuses, naming `--yes`. Cancelled or refused, nothing was touched, the run's
9
+ * warnings are printed before the sentence, and the exit code is 1. A killed run's
10
+ * leftovers are looked at before the question, so the answer — and `--yes` —
11
+ * covers what it hid as well.
20
12
  */
21
13
  /** Runs one command line; resolves to the exit code. Never throws. */
22
14
  export declare function runCli(argv: readonly string[], io: CliIo): Promise<number>;
package/dist/cli.js CHANGED
@@ -2,27 +2,9 @@ import { GENERATE_USAGE, INIT_USAGE, parseCliCommand, USAGE, } from "./cli/comma
2
2
  import { runGenerate } from "./cli/generate.command.js";
3
3
  import { renderGenerationFailure } from "./cli/generation-failure.renderer.js";
4
4
  import { createTerminalPrompter } from "./cli/terminal.prompter.js";
5
+ import { AVENTARA_CLIENT_GENERATOR_VERSION } from "./index.js";
5
6
  import { runClientInit } from "./init/client-init.orchestrator.js";
6
7
  import { runCommand } from "./init/command.runner.js";
7
- /**
8
- * `avclient` — the generator's bin (`avclient generate`), S7b.
9
- *
10
- * It parses the command line, runs §15.3's pipeline (`generate.ts`) in the
11
- * current directory, and owns the terminal: the success line goes to stdout,
12
- * every warning the run returned to stderr in the run's order, and a failure
13
- * through the refusal renderer — a refusal is one sentence and exit 1 with no
14
- * stack (M3), anything else is a defect and keeps its stack.
15
- *
16
- * It is also the one place that ASKS (architect, 2026-10-04): when content the
17
- * generator did not produce stands in `AvClient.ts` or `generated/`, the paths
18
- * are listed and the person is asked whether to overwrite them. `--yes` answers
19
- * for them. Where nobody can answer — stdin is not a terminal — it never asks
20
- * and never overrides: it refuses, naming `--yes`. Cancelled or refused, nothing
21
- * was touched, the run's warnings are printed before the sentence, and the exit
22
- * code is 1. A killed run's leftovers are looked at before the question, so the
23
- * answer — and `--yes` — covers what it hid as well.
24
- */
25
- /** Runs one command line; resolves to the exit code. Never throws. */
26
8
  export async function runCli(argv, io) {
27
9
  try {
28
10
  const command = parseCliCommand(argv);
@@ -34,6 +16,10 @@ export async function runCli(argv, io) {
34
16
  : GENERATE_USAGE);
35
17
  return 0;
36
18
  }
19
+ if (command.command === "version") {
20
+ io.stdout(`${AVENTARA_CLIENT_GENERATOR_VERSION}\n`);
21
+ return 0;
22
+ }
37
23
  if (command.command === "init") {
38
24
  return await runClientInit(command, io);
39
25
  }
@@ -45,12 +31,6 @@ export async function runCli(argv, io) {
45
31
  return failure.exitCode;
46
32
  }
47
33
  }
48
- /**
49
- * Runs `avclient` over this process — its arguments, its terminal, its exit
50
- * code. Called by the bin's entry (`avclient.bin.ts`) once the Node guard has
51
- * admitted this Node; importing this module runs nothing, which is what lets
52
- * `runCli` be tested in process.
53
- */
54
34
  export async function runFromProcess() {
55
35
  const terminal = createTerminalPrompter();
56
36
  try {
@@ -1,15 +1,11 @@
1
1
  /**
2
- * The generator's configuration, in its two states (plan §7, group 1).
2
+ * The generator's configuration, in its two states.
3
3
  *
4
4
  * `ClientConfigInput` is what a `framework.client.ts` default-exports through
5
- * `defineClientConfig`. It is passive data: an environment variable appears as
6
- * an `EnvReference`, a NAME to look up, so the file can be evaluated without the
5
+ * `defineClientConfig`. It is passive data: an environment variable appears as an
6
+ * `EnvReference`, a NAME to look up, so the file can be evaluated without the
7
7
  * environment having been loaded into the global and resolution stays a pure
8
8
  * function of the input and an `EnvRecord`.
9
- *
10
- * `ResolvedClientConfig` is what later slices consume: the one §15.2 entrypoint
11
- * split into the deployment it addresses and its canonical mount path,
12
- * `generateAt` made absolute, and the mode the cascade resolved under.
13
9
  */
14
10
  /** A deferred read of one environment variable from the resolved cascade. */
15
11
  export interface EnvReference {
@@ -19,32 +15,36 @@ export interface EnvReference {
19
15
  /** A value written literally, or read from the resolved environment. */
20
16
  export type ConfigValue = string | EnvReference;
21
17
  export interface ClientConfigInput {
22
- /** The full deployed framework entrypoint: origin plus mount path (§15.2). */
18
+ /** The full deployed framework entrypoint: origin plus mount path. */
23
19
  readonly entrypoint: ConfigValue;
24
20
  /**
25
21
  * The directory the client is generated into, relative to the config file's
26
- * directory (architect, 2026-10-04). It is SHARED: the generator owns only
27
- * `AvClient.ts` and `generated/` in it, and never touches anything else there.
28
- * Named `generateAt`, not §15.2's `output`, by the architect's decision.
22
+ * directory. It is SHARED: the generator owns only `AvClient.ts` and `generated/`
23
+ * in it, and never touches anything else there.
29
24
  */
30
25
  readonly generateAt: ConfigValue;
26
+ /**
27
+ * The `tsconfig.json` the generated client is written for, relative to the
28
+ * config file's directory — only for a layout the discovery gets wrong (a
29
+ * monorepo, a non-standard name). Absent, the nearest `tsconfig.json` above
30
+ * `generateAt` (`tsconfig.locator.ts`).
31
+ */
32
+ readonly tsconfigFile?: string;
31
33
  }
32
34
  /** A filesystem path known to be absolute. */
33
35
  export type AbsolutePath = string & {
34
36
  readonly __absolutePath: true;
35
37
  };
36
38
  /**
37
- * A mount path in F-822's canonical form: `""` at the root, otherwise
38
- * `/seg(/seg)*` — one leading slash, no trailing slash, no empty segment. Root is
39
- * the empty string, not `"/"`, so every route is `path + "/<route>"` with no
40
- * special case. Only resolution makes one.
39
+ * Root is the empty string, not `"/"`, so every route is `path + "/<route>"` with
40
+ * no special case. Only resolution makes one.
41
41
  */
42
42
  export type EntrypointPath = ("" | `/${string}`) & {
43
43
  readonly __entrypointPath: true;
44
44
  };
45
45
  /**
46
46
  * The deployed entrypoint, normalised once at resolution so every consumer reads
47
- * one canonical form (F-822). Joining a route onto it is concatenation.
47
+ * one canonical form. Joining a route onto it is concatenation.
48
48
  */
49
49
  export interface ClientEntrypoint {
50
50
  /**
@@ -58,5 +58,7 @@ export interface ResolvedClientConfig {
58
58
  readonly entrypoint: ClientEntrypoint;
59
59
  /** `generateAt`, made absolute. */
60
60
  readonly generateAt: AbsolutePath;
61
+ /** `tsconfigFile`, made absolute; absent when the config names none. */
62
+ readonly tsconfigFile?: AbsolutePath;
61
63
  readonly mode: string;
62
64
  }
@@ -1,14 +1 @@
1
- /**
2
- * The generator's configuration, in its two states (plan §7, group 1).
3
- *
4
- * `ClientConfigInput` is what a `framework.client.ts` default-exports through
5
- * `defineClientConfig`. It is passive data: an environment variable appears as
6
- * an `EnvReference`, a NAME to look up, so the file can be evaluated without the
7
- * environment having been loaded into the global and resolution stays a pure
8
- * function of the input and an `EnvRecord`.
9
- *
10
- * `ResolvedClientConfig` is what later slices consume: the one §15.2 entrypoint
11
- * split into the deployment it addresses and its canonical mount path,
12
- * `generateAt` made absolute, and the mode the cascade resolved under.
13
- */
14
1
  export {};