@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.
- package/README.md +44 -9
- package/dist/avclient.bin.js +0 -10
- package/dist/cli/command.parser.d.ts +15 -10
- package/dist/cli/command.parser.js +13 -19
- package/dist/cli/generate.command.js +0 -6
- package/dist/cli/generation-failure.renderer.js +0 -14
- package/dist/cli/generation-success.renderer.d.ts +4 -1
- package/dist/cli/generation-success.renderer.js +0 -13
- package/dist/cli/terminal.prompter.d.ts +1 -2
- package/dist/cli/warning.renderer.d.ts +2 -2
- package/dist/cli/warning.renderer.js +0 -8
- package/dist/cli.d.ts +8 -16
- package/dist/cli.js +5 -25
- package/dist/config/client-config.interface.d.ts +18 -16
- package/dist/config/client-config.interface.js +0 -13
- package/dist/config/config.loader.d.ts +34 -22
- package/dist/config/config.loader.js +49 -52
- package/dist/config/config.resolver.d.ts +13 -19
- package/dist/config/config.resolver.js +9 -48
- package/dist/config/env.cascade.d.ts +12 -14
- package/dist/config/env.cascade.js +0 -19
- package/dist/config/module-style.resolver.d.ts +52 -0
- package/dist/config/module-style.resolver.js +75 -0
- package/dist/config/tsconfig.locator.d.ts +45 -0
- package/dist/config/tsconfig.locator.js +52 -0
- package/dist/contract/contract.acceptance.d.ts +12 -26
- package/dist/contract/contract.acceptance.js +0 -54
- package/dist/contract/contract.fetcher.d.ts +12 -17
- package/dist/contract/contract.fetcher.js +0 -24
- package/dist/contract/contract.loader.d.ts +4 -5
- package/dist/contract/contract.loader.js +0 -10
- package/dist/emit/banner.emitter.d.ts +11 -12
- package/dist/emit/banner.emitter.js +0 -26
- package/dist/emit/client-surface.emitter.d.ts +17 -21
- package/dist/emit/client-surface.emitter.js +29 -55
- package/dist/emit/client-tree.emitter.d.ts +11 -20
- package/dist/emit/client-tree.emitter.js +12 -54
- package/dist/emit/contract-carrier.emitter.d.ts +5 -6
- package/dist/emit/contract-carrier.emitter.js +0 -28
- package/dist/emit/derivation.emitter.d.ts +7 -7
- package/dist/emit/derivation.emitter.js +2 -161
- package/dist/emit/descriptor.emitter.js +2 -28
- package/dist/emit/emitted-tree.interface.d.ts +40 -17
- package/dist/emit/emitted-tree.interface.js +6 -16
- package/dist/emit/enum.emitter.d.ts +4 -4
- package/dist/emit/enum.emitter.js +0 -24
- package/dist/emit/module-specifier.scanner.d.ts +25 -0
- package/dist/emit/module-specifier.scanner.js +160 -0
- package/dist/emit/module-style.interface.d.ts +58 -0
- package/dist/emit/module-style.interface.js +8 -0
- package/dist/emit/name.deriver.d.ts +33 -61
- package/dist/emit/name.deriver.js +0 -134
- package/dist/emit/named-type.emitter.d.ts +14 -21
- package/dist/emit/named-type.emitter.js +3 -30
- package/dist/emit/runtime.emitter.d.ts +23 -50
- package/dist/emit/runtime.emitter.js +68 -159
- package/dist/emit/scalar.codec.d.ts +20 -33
- package/dist/emit/scalar.codec.js +13 -69
- package/dist/emit/transaction.emitter.d.ts +6 -14
- package/dist/emit/transaction.emitter.js +24 -33
- package/dist/generate.d.ts +20 -34
- package/dist/generate.js +14 -22
- package/dist/index.js +0 -5
- package/dist/init/client-config.template.d.ts +6 -4
- package/dist/init/client-config.template.js +10 -13
- package/dist/init/client-init.errors.js +0 -3
- package/dist/init/client-init.orchestrator.js +8 -9
- package/dist/init/client-init.planner.d.ts +1 -9
- package/dist/init/client-init.planner.js +16 -24
- package/dist/init/client-init.questions.d.ts +8 -12
- package/dist/init/client-init.questions.js +0 -11
- package/dist/init/client-project.inspector.d.ts +6 -0
- package/dist/init/client-project.inspector.js +2 -2
- package/dist/node-version.guard.js +0 -12
- package/dist/output/output.validator.d.ts +49 -27
- package/dist/output/output.validator.js +113 -74
- package/dist/output/output.writer.d.ts +59 -52
- package/dist/output/output.writer.js +72 -134
- 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.
|
|
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.
|
|
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
|
-
**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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)
|
|
76
|
-
|
|
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
|
package/dist/avclient.bin.js
CHANGED
|
@@ -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
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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.
|
|
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.
|
|
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.
|
|
13
|
-
/** `avclient init`'s command line
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
13
|
-
current directory, fetch
|
|
14
|
-
write AvClient.ts and
|
|
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
|
|
49
|
-
<entrypoint>/_contract, and write AvClient.ts and generated/ into its
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
5
|
-
*
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
27
|
-
*
|
|
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
|
-
*
|
|
38
|
-
*
|
|
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
|
|
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 {};
|