@aventara/cli 0.1.0-pilot.4 → 1.0.0-rc.1

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 (46) hide show
  1. package/CHANGELOG.md +345 -0
  2. package/README.md +55 -42
  3. package/dist/apply/conflict.confirmer.js +4 -4
  4. package/dist/cli.js +18 -14
  5. package/dist/command/command.parser.js +17 -10
  6. package/dist/plan/project.planner.js +2 -4
  7. package/dist/project/project.inspector.js +8 -8
  8. package/dist/run/command.runner.js +2 -0
  9. package/dist/run/init.orchestrator.js +40 -20
  10. package/dist/run/new.orchestrator.js +32 -14
  11. package/dist/run/step.reporter.js +87 -0
  12. package/dist/templates/docs.links.js +2 -1
  13. package/dist/templates/prisma7/prisma7.templates.js +26 -5
  14. package/dist/templates/template.registry.js +1 -1
  15. package/dist/wizard/answer.resolver.js +5 -5
  16. package/dist/wizard/readline.prompter.js +3 -3
  17. package/dist/wizard/wizard.questions.js +9 -9
  18. package/package.json +4 -3
  19. package/dist/apply/app-module.anchor.d.ts +0 -24
  20. package/dist/apply/conflict.confirmer.d.ts +0 -15
  21. package/dist/apply/e2e-spec.anchor.d.ts +0 -18
  22. package/dist/apply/main-cors.anchor.d.ts +0 -50
  23. package/dist/apply/manifest.merger.d.ts +0 -51
  24. package/dist/aventara.bin.d.ts +0 -2
  25. package/dist/catalog/adapter.catalog.generated.d.ts +0 -20
  26. package/dist/catalog/catalog-entry.interface.d.ts +0 -54
  27. package/dist/catalog/catalog.matcher.d.ts +0 -40
  28. package/dist/catalog/range.reader.d.ts +0 -11
  29. package/dist/cli.d.ts +0 -29
  30. package/dist/command/command.parser.d.ts +0 -38
  31. package/dist/node-version.guard.d.ts +0 -8
  32. package/dist/plan/project.planner.d.ts +0 -53
  33. package/dist/project/package-manager.detector.d.ts +0 -5
  34. package/dist/project/project.inspector.d.ts +0 -32
  35. package/dist/project/service.detector.d.ts +0 -40
  36. package/dist/project/source.scanner.d.ts +0 -16
  37. package/dist/run/command.runner.d.ts +0 -15
  38. package/dist/run/init.orchestrator.d.ts +0 -27
  39. package/dist/run/new.orchestrator.d.ts +0 -20
  40. package/dist/run/scaffold.committer.d.ts +0 -28
  41. package/dist/templates/docs.links.d.ts +0 -8
  42. package/dist/templates/prisma7/prisma7.templates.d.ts +0 -34
  43. package/dist/templates/template.registry.d.ts +0 -152
  44. package/dist/wizard/answer.resolver.d.ts +0 -47
  45. package/dist/wizard/readline.prompter.d.ts +0 -22
  46. package/dist/wizard/wizard.questions.d.ts +0 -120
package/CHANGELOG.md ADDED
@@ -0,0 +1,345 @@
1
+ # @aventara/cli
2
+
3
+ ## 1.0.0-rc.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 7e3d06f: Breaking: the configuration has a new shape. Every layer (the root, `application` and `client`) now holds the
8
+ same six keys: `exposed`, `transactionsStyle`, `limits`, `pipelines`, `resources` and `exemptions`. Everything about
9
+ one Resource lives under `resources.<Resource>`: its fields, and each field's `definition` and `pipelines`. The old
10
+ keys are refused when the framework starts, with a message that names where each one moved:
11
+
12
+ | Before (rc.0) | Now (rc.1) |
13
+ | ------------------------------------------------------- | ----------------------------------------------------------------------------------- |
14
+ | `fields: { Post: { url: { type, nullable, … } } }` | `resources: { Post: { fields: { url: { definition: { type, nullable, … } } } } }` |
15
+ | `behaviors: { Post: { fields: { slug: { create } } } }` | `resources: { Post: { fields: { slug: { pipelines: { compute: { create } } } } } }` |
16
+ | `transactions: "none"` | `transactionsStyle: "none"` |
17
+ | `restrictions` | `exposed` + `exemptions` (see below) |
18
+ | `@aventara/core/json` | `@aventara/core/avz` |
19
+
20
+ Before:
21
+
22
+ ```ts
23
+ createFramework({
24
+ api: "/api",
25
+ adapter,
26
+ transactions: "interactive",
27
+ fields: {
28
+ Post: {
29
+ url: {
30
+ type: { scalar: "string" },
31
+ nullable: false,
32
+ list: false,
33
+ lifecycle: ["VIRTUAL"],
34
+ },
35
+ },
36
+ },
37
+ behaviors: {
38
+ Post: {
39
+ fields: {
40
+ url: {
41
+ read: {
42
+ dependsOn: ["slug"],
43
+ compute: ({ record }) => `/p/${record.slug}`,
44
+ },
45
+ },
46
+ },
47
+ },
48
+ },
49
+ });
50
+ ```
51
+
52
+ After:
53
+
54
+ ```ts
55
+ createFramework({
56
+ api: "/api",
57
+ adapter,
58
+ transactionsStyle: "interactive",
59
+ resources: {
60
+ Post: {
61
+ fields: {
62
+ url: {
63
+ definition: {
64
+ type: { scalar: "string" },
65
+ nullable: false,
66
+ list: false,
67
+ lifecycle: ["VIRTUAL"],
68
+ format: "url",
69
+ },
70
+ pipelines: {
71
+ compute: {
72
+ read: {
73
+ dependsOn: ["slug"],
74
+ compute: ({ record }) => `/p/${record.slug}`,
75
+ },
76
+ },
77
+ },
78
+ },
79
+ },
80
+ },
81
+ },
82
+ });
83
+ ```
84
+
85
+ What else changed:
86
+
87
+ - A field is defined at the root only. A `definition` in `application` or `client` is refused
88
+ (`CONFIG_FORBIDDEN_IN_OVERLAY`). Define the field
89
+ at the root; `application` and `client` can still add compute stages to it.
90
+ - Computed values chain. When the root and an overlay both compute a field, the root's stage runs first and the
91
+ overlay's receives its result as `value`. A stage can no longer be turned off with `false`. Returning `undefined`
92
+ keeps the current value. An upsert computes its create branch with `compute.create` and its update branch with
93
+ `compute.update`.
94
+ - A discovered field keeps the adapter's facts. On a field the adapter discovered you may restate its own `type`,
95
+ `nullable` and `list`, and give a Json field its shape (`definition.json`). Setting a different type, any `format`
96
+ or any `capabilities` on it is refused. `format` is for fields you add, and it must be one of zod's named string
97
+ formats (`"email"`, `"url"`, `"uuid"`, …); any other name is a type error and refused at startup.
98
+ - A misplaced key is a type error. In a configuration written inline in `createFramework({ ... })` or
99
+ `AventaraModule.forRoot`, a key that has no place there (a typo, an old key, `compute` on a relation field, a field
100
+ name neither your schema nor the root has) is now a type error at that key, and still refused at startup.
101
+ - A Resource whose name starts with `$` is refused at startup (`$` names are the framework's).
102
+ - The Json shape builder moved from `@aventara/core/json` to `@aventara/core/avz`. Change the import; `AvZ` is
103
+ the same.
104
+
105
+ `exposed` and `exemptions`, which replace `restrictions`, have their own entry.
106
+
107
+ - 6317811: Breaking: `exposed` and `exemptions` replace `restrictions`. Every layer (the root, `application` and `client`)
108
+ says what it exposes with two keys: `exposed`, the layer's default, and `exemptions`, the entries that are the
109
+ opposite of it.
110
+
111
+ - `exposed: true` (the root's default) exposes everything the layer above offers, and `exemptions` lists what to
112
+ hide. `exposed: false` exposes nothing, and `exemptions` lists the only things to expose.
113
+ - In `exemptions`, `true` exempts an entry whole, `false` and `[]` exempt nothing, a list exempts the listed
114
+ entries one level down, and an object goes one level deeper. A Resource takes `true`, `false` or
115
+ `{ operations, fields }`. Operations are nested: `operations: { find: ["many"], update: { unique: true } }`.
116
+ A field takes a list of capability names, or an object per capability whose token lists name filter operators,
117
+ directives, reducers or pagination kinds.
118
+ - A list now always means "exempt these". rc.0's `filter: ["equals"]` meant "keep only `equals`"; under
119
+ `exposed: true` the same intent is the list of the operators to remove.
120
+ - Overlays only narrow. `application` and `client` start from the root's view. An overlay can no longer bring
121
+ back what the root hid (rc.0's `hidden: false`); that is now refused at startup, and the message names the other
122
+ overlay to hide it in instead. Expose an entry at the root and hide it in the overlay that must not see it.
123
+ - An overlay that sets `exemptions` must also set its own `exposed`.
124
+ - Relation positions are the adapter's: an exemption can no longer narrow where a relation is projected or written.
125
+ - A unique operation (`find.unique`, `update.unique`, `delete.unique`, `upsert.unique`) needs an identifier. Picking
126
+ one without the identifier's fields, or hiding every identifier while one stays exposed, is refused at startup
127
+ with `COMPILER_MISSING_IDENTIFIER` instead of the operation silently disappearing.
128
+
129
+ Every name in `exemptions` must exist, in both styles: a Resource, field, family, variant, capability or token the
130
+ adapter does not offer is refused at startup with its path (`COMPILER_UNKNOWN_RESOURCE`, `COMPILER_UNKNOWN_FIELD`,
131
+ `COMPILER_UNAVAILABLE_OPERATION`, `COMPILER_UNAVAILABLE_CAPABILITY`), and in a configuration written inline in
132
+ `createFramework({ ... })` it is a type error first. Under `exposed: true`, hiding in an overlay what the root
133
+ already hid does nothing.
134
+
135
+ Before (rc.0):
136
+
137
+ ```ts
138
+ createFramework({
139
+ api: "/api",
140
+ adapter,
141
+ restrictions: {
142
+ User: {
143
+ fields: {
144
+ passwordHash: { hidden: true },
145
+ email: { capabilities: { filter: ["equals"] } },
146
+ },
147
+ },
148
+ },
149
+ client: {
150
+ restrictions: {
151
+ AuditLog: { hidden: true },
152
+ Post: { operations: { delete: { unique: false } } },
153
+ },
154
+ },
155
+ });
156
+ ```
157
+
158
+ After (rc.1):
159
+
160
+ ```ts
161
+ createFramework({
162
+ api: "/api",
163
+ adapter,
164
+ // The root: `exposed` defaults to true, so these are hidden from every origin.
165
+ exemptions: {
166
+ resources: {
167
+ User: {
168
+ fields: {
169
+ passwordHash: true,
170
+ email: { filter: ["contains", "startsWith"] }, // remove every operator but `equals`
171
+ },
172
+ },
173
+ },
174
+ },
175
+ client: {
176
+ exposed: true,
177
+ exemptions: {
178
+ resources: {
179
+ AuditLog: true,
180
+ Post: { operations: { delete: ["unique"] } },
181
+ },
182
+ },
183
+ },
184
+ });
185
+ ```
186
+
187
+ Or expose only what a frontend calls:
188
+
189
+ ```ts
190
+ client: {
191
+ exposed: false,
192
+ exemptions: {
193
+ resources: {
194
+ Post: {
195
+ operations: { find: ["many", "unique"], create: ["one"] },
196
+ fields: { id: ["select"], title: ["select", "create"], body: ["select", "create"] },
197
+ },
198
+ },
199
+ },
200
+ },
201
+ ```
202
+
203
+ `aventara init` and `aventara new` now write `exposed: true` into `src/aventara.config.ts`, with a comment that
204
+ links the exposure documentation.
205
+
206
+ - 9c52482: A `$connect` to a row that does not exist now answers `404 A2003` (not found), the same as reading a missing row.
207
+ Before, it answered `422 A2004`. This covers a to-one `$connect` in `create`, `update` and `upsert`, a to-many
208
+ `$connect`, and the same writes inside a transaction plan, where `cause.operation` names the step. The message is
209
+ unchanged: "The operation's arguments referenced a record that does not exist." On `update.first`, the same mistake
210
+ answered `A2014` before, as if the row had changed underneath; it now answers `A2003` too, and a duplicate unique value
211
+ written through `update.first` answers `409 A2008` instead of `A3001`.
212
+
213
+ Clearer top-level messages for an unknown Resource or operation. `A2001` now says "The requested Resource is not
214
+ available." and `A2002` says "The requested operation is not available on this Resource.", instead of "Operation
215
+ arguments failed framework validation.", which stays the message of `A2004`, `A2007` and `A2009`. A transaction step
216
+ whose operation is outside the standard grammar now carries the same issue message as a single call, naming the
217
+ operation and the Resource (for example `Operation "dance.one" is not available on Resource "posts".`), instead of
218
+ "Operation is not part of the standard operation grammar."
219
+
220
+ A `$ref` with no `fingerprint` is `V1000` (required value missing) and answers `422 A2004`. Before, it was `V1017`
221
+ (fingerprint mismatch) under `A2007`. A fingerprint that is present but wrong is still `V1017`.
222
+
223
+ `aventara init` and `aventara new` link to the documentation at https://aventara-framework.vercel.app. The old
224
+ address redirects, so links already written into projects keep working.
225
+
226
+ - 8db76e7: `aventara new` and `aventara init` write a `diagnostics` sink into `src/aventara.config.ts`. When something fails
227
+ inside the server, the caller gets a plain 500 and the Nest log said only which request failed; the raw error went to
228
+ a sink the scaffold did not set. Now the sink logs the raw error with its stack through Nest's `Logger` (context
229
+ `Aventara`), at error level, right after that line. Replace it with your own reporter when you have one.
230
+
231
+ - `aventara new` and `aventara init` write `api: '/api'` into `src/aventara.config.ts` (the root key was renamed from
232
+ `entrypoint`).
233
+
234
+ ## 1.0.0-rc.0
235
+
236
+ ### Major Changes
237
+
238
+ - First release candidate of Aventara 1.0. The public API is now considered stable; changes before 1.0.0 are possible
239
+ based on feedback.
240
+
241
+ ### Minor Changes
242
+
243
+ - 24ffbab: `aventara new`, `aventara init`, `avclient init` and `avclient generate` show their steps while they work, so a long
244
+ install never looks hung: on a terminal, `[3/4] Installing dependencies (npm install)` with a spinner and the seconds so
245
+ far, then `✓` or `✗` and its time; in a pipe, in CI or with `NO_COLOR`, one plain line per step (`… done (12.4s)`),
246
+ with no control sequence. A closing line gives the total time. The steps go to stderr; stdout keeps the results and the
247
+ next steps. The output of `nest new` and of the install is shown only when it fails, as before, or as it runs with the
248
+ new `--verbose`.
249
+
250
+ ### Patch Changes
251
+
252
+ - 24ffbab: Each package ships its `CHANGELOG.md`, so the release notes are in the installed package beside the README.
253
+ - 24ffbab: `aventara new` prints its next steps last — after the initial commit and the closing line — so they are what is on
254
+ screen when it ends, in a terminal and in a pipe alike.
255
+
256
+ ## 0.1.0-pilot.4
257
+
258
+ ### Patch Changes
259
+
260
+ - f37dcd6: `@aventara/cli` ships no type declarations: it is a command, run with `npx` or installed globally, and has no API to
261
+ import.
262
+ - f37dcd6: `aventara new` and `aventara init` add `prebuild`, `prestart`, `prestart:dev` and `prestart:debug` scripts that run
263
+ `aventara:prepare`, so after a change to `schema.prisma` the next `npm run start:dev` (or `build`, `start`,
264
+ `start:debug`) regenerates the Prisma client and the discovery artifact before the server compiles — no reinstall
265
+ needed. npm and pnpm both run these hooks. On an existing project, `aventara init` treats a `prebuild` or `prestart*`
266
+ script you already have as a conflict, like any other script: kept unless you confirm, replaced with `--yes`.
267
+
268
+ The scaffold's rate-limiting note in `src/main.ts` links to the docs:
269
+ `https://aventara-docs.vercel.app/docs/limits-and-safety#rate-limiting`.
270
+
271
+ ## 0.1.0-pilot.3
272
+
273
+ ### Patch Changes
274
+
275
+ - d8c128b: `aventara new` and `aventara init` turn CORS on in `src/main.ts`, so a browser frontend on another port can call the
276
+ API — 0.1.0-pilot.2's scaffold had none, and a browser's preflight got the protocol's answer instead. Right after
277
+ `const app = await NestFactory.create(AppModule);` they add `app.enableCors({ origin: … })` with the comma-separated
278
+ origins in `CORS_ORIGINS`, and write `CORS_ORIGINS="http://localhost:5173,http://localhost:3001"` into the `.env` they
279
+ write. Unset or empty, CORS is **off** (`origin: false`), never open to every origin. A `main.ts` that already
280
+ configures CORS is left as it is, with a warning; one without that line is not edited, and the lines are printed. Over an
281
+ existing Prisma setup, whose `.env` init never writes, adding `CORS_ORIGINS` is printed as a next step. Nest's
282
+ `enableCors` reaches Aventara's routes on Express and Fastify alike: preflights naming the `Aventara-*` headers are
283
+ allowed, and the calls answered with the origin.
284
+ - 05d39e8: `aventara new` ends with the project's first git commit, `Initial Aventara Scaffold`: every scaffolded file and the
285
+ install's lockfile, never `.env` (it is in `.gitignore`). 0.1.0-pilot.2 left a repository with nothing committed. Where
286
+ a commit cannot or should not be made the run still succeeds, saying why in one line: git is not installed, git has no
287
+ `user.name`/`user.email`, or the directory `new` ran in is already inside a git repository (a monorepo), where no
288
+ commit is made in either repository. `--skip-git` creates no repository and makes no commit; `aventara init` never
289
+ commits.
290
+ - 6755a1f: `aventara --help`, `aventara new --help` and `aventara init --help` list the values `--orm`, `--db` and
291
+ `--package-manager` take, read from the adapter catalog: `--orm <prisma7>`, `--db <sqlite|postgresql>`,
292
+ `--package-manager <npm|pnpm>`. A refused `--orm` now names the values it takes — "`--orm takes prisma7 (Prisma 7,
293
+ @aventara/prisma7-adapter)`" — where 0.1.0-pilot.2 said "available: Prisma 7", which is not a value the flag accepts.
294
+ - 2afc651: The `main.ts` lines `aventara new` and `aventara init` add now end with a commented-out, platform-level rate limiter
295
+ and a short note on why: `@nestjs/throttler` is a Nest guard and does not run on Aventara's routes, while Express
296
+ middleware does. Uncommented (after `npm i express-rate-limit` and its import), it limits the protocol's routes and
297
+ answers `429` past the limit. Nothing is installed or enabled by default.
298
+ - `CORS_ORIGINS="http://localhost:5173,http://localhost:3001"` is appended to the project's existing `.env` too — over an existing Prisma setup as well — every other line kept, and never when a line already sets `CORS_ORIGINS`; only a reused setup with no `.env` gets it as a printed next step.
299
+ - `--orm` takes an adapter's alias, `prisma7` (Prisma 7, `@aventara/prisma7-adapter`), declared in the adapter's manifest and listed by `--help`; `prisma@7` and `prisma` are no longer accepted.
300
+
301
+ ## 0.1.0-pilot.2
302
+
303
+ ### Patch Changes
304
+
305
+ - aa65a0c: `aventara new` and `aventara init` add `.env` to the project's `.gitignore` whenever they write the `DATABASE_URL`
306
+ entry into `.env`. The file is only appended to: existing lines are kept, and nothing is added when `.env` is already
307
+ listed.
308
+ - e69e88d: The published packages are written for the people who use them. The JavaScript ships without comments; the type
309
+ declarations keep their documentation, and it, the error messages, the protocol fixtures' labels and the comments in a
310
+ generated client no longer carry the project's internal development notes.
311
+ - 0ec37d4: `avclient --version` (and `-v`) prints the generator's version and exits 0, and `aventara` now accepts `-v` beside
312
+ `--version`, so both bins answer the same two flags.
313
+
314
+ ## 0.1.0-pilot.1
315
+
316
+ ### Patch Changes
317
+
318
+ - 7714ef3: The scaffold's e2e test now proves Aventara is mounted. `aventara new` and `aventara init` add a `GET /api/_contract`
319
+ → 200 test to Nest's `test/app.e2e-spec.ts`, right after its `GET /` test (ESM and CommonJS), when AventaraModule was
320
+ added and the spec is Nest's own; a spec of the developer's own is left untouched.
321
+ - 7f2b5d4: The frontend next step is now a command that runs as printed: `pnpm dlx` under pnpm (not `npx`), and, while the CLI is a
322
+ prerelease, the client's dist-tag read from the CLI's own version — `npx @aventara/client@pilot init` for
323
+ 0.1.0-pilot.N — so a frontend gets the client from the same release instead of nothing (`@aventara/client` has no
324
+ `latest`).
325
+ - 799346e: The package READMEs (each package's npm page) are rewritten for the people who use the packages. The Prisma 7
326
+ adapter's README now states the actual behaviour of a to-many relation or `$count` projected on
327
+ `update.many`/`create.many`: a validation refusal, `A2004` with `V1008`, before any statement runs (it said `A3001`).
328
+ Every install or run command names the `@pilot` dist-tag.
329
+ - e58aebf: The READMEs show how to call the API by hand: a copy-pasteable `curl` that fetches `/api/_contract` and sends a
330
+ `find.many` with both identity headers, and runs as printed against a scaffolded server. They also say that
331
+ Resource keys are the model names as written (`/_resources/User/…`, `avClient.User.find.many`), and that list results are
332
+ `readonly` arrays (`readonly User[]`).
333
+ - 88408be: `--help` (and `-h`) works after a command: `aventara new --help`, `aventara init --help`, `avclient init --help` and
334
+ `avclient generate --help` print that command's usage and exit 0, instead of refusing "unknown flag --help". Nothing
335
+ else on the line is read or run.
336
+
337
+ ## 0.1.0-pilot.0
338
+
339
+ ### Minor Changes
340
+
341
+ - b65a4f8: New package: `@aventara/cli`, bin `aventara`. `aventara new <name>` runs the pinned `nest new` and adds Aventara;
342
+ `aventara init` adds Aventara to an existing NestJS 12 project — the Prisma 7 schema, config and service when there is
343
+ no ORM yet, or the developer's own Prisma setup reused and never written. Every question has a flag; `--yes` accepts the
344
+ defaults; a non-interactive run without the answers refuses before writing anything. The ORMs and databases on offer
345
+ come from the adapter packages' own manifests.
package/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  The `aventara` command: it scaffolds an Aventara server on NestJS 12.
4
4
 
5
5
  ```bash
6
- npm i -g @aventara/cli@pilot # or run it once: npx @aventara/cli@pilot <command>
6
+ npm i -g @aventara/cli@rc # or run it once: npx @aventara/cli@rc <command>
7
7
  aventara new my-api # a new NestJS project with Aventara
8
8
  aventara init # Aventara added to the NestJS 12 project in this directory
9
9
  ```
10
10
 
11
- It is run once, globally or through `npx`; it is not a dependency of the projects it writes. The frontend's side —
12
- `framework.client.ts` and the generated client — is `@aventara/client`'s (`npx @aventara/client@pilot init`).
11
+ It is run once, globally or through `npx`; it is not a dependency of the projects it writes. The frontend's side
12
+ (`framework.client.ts` and the generated client) belongs to `@aventara/client` (`npx @aventara/client@rc init`).
13
13
 
14
14
  ## `aventara new <name>`
15
15
 
@@ -17,22 +17,24 @@ Runs the pinned `nest new` (`npx -y @nestjs/cli@12.0.8 new …`, or `pnpm dlx
17
17
  `src/app.module.ts` is what that version writes, then runs exactly `aventara init`'s pipeline over the new project and
18
18
  installs it. A directory that exists and is not empty is refused before anything runs.
19
19
 
20
- Once installed, the project gets its first git commit, `Initial Aventara Scaffold` — the lockfile in it, `.env` not
21
- (it is in `.gitignore`). No commit is made, and one line says why, when git is not installed, when git has no
20
+ Once installed, the project gets its first git commit, `Initial Aventara Scaffold`, with the lockfile in it and
21
+ without `.env` (it is in `.gitignore`). No commit is made, and one line says why, when git is not installed, when git has no
22
22
  `user.name`/`user.email`, or when the directory is already inside a git repository (a monorepo: commit it there).
23
23
  `--skip-git` makes no repository and no commit.
24
24
 
25
25
  ## `aventara init`
26
26
 
27
- Runs inside an existing **NestJS 12** project (refused: no `package.json`, another Nest major, TypeScript 7, a yarn-only
28
- lockfile, a project already initialized).
27
+ Runs inside an existing NestJS 12 project. It refuses a directory with no `package.json`, another Nest major,
28
+ TypeScript 7, a yarn-only lockfile, or a project already initialized.
29
29
 
30
- - **No ORM yet:** the ORM and the database are asked (or taken from the flags), and everything below is written.
31
- - **Prisma already there:** the installed Prisma must be one an Aventara adapter supports — today Prisma 7, `^7.10.0`,
32
- SQLite or PostgreSQL, a driver adapter, the `prisma-client` generator — or the run is refused in one sentence, with
33
- nothing written. Your schema, Prisma config and service are **reused and never written**, and your `.env` only gains
34
- a `CORS_ORIGINS` line at its end when it has none; init finds the class extending `PrismaClient` and the module
35
- exporting it, or asks.
30
+ In a project with no ORM yet, the ORM and the database are asked (or taken from the flags), and everything below is
31
+ written.
32
+
33
+ In a project that already uses Prisma, the installed Prisma must be one an Aventara adapter supports, or the run is
34
+ refused in one sentence with nothing written. Today that is Prisma 7 (`^7.10.0`) on SQLite or PostgreSQL, with a driver
35
+ adapter and the `prisma-client` generator. Your schema, Prisma config and service are reused and never written, and
36
+ your `.env` only gains a `CORS_ORIGINS` line at its end when it has none. Init finds the class extending `PrismaClient`
37
+ and the module exporting it, or asks.
36
38
 
37
39
  ### Questions and flags
38
40
 
@@ -42,15 +44,20 @@ possible answer is shown, not asked.
42
44
 
43
45
  | Flag | Question | Default |
44
46
  |---|---|---|
45
- | `<name>` (`new` only) | The project directory. | — (required) |
47
+ | `<name>` (`new` only) | The project directory. | required |
46
48
  | `--orm <alias>` | The ORM, as an adapter's alias: `prisma7` (Prisma 7, `@aventara/prisma7-adapter`). `--help` lists the aliases that exist. | the only one there is |
47
49
  | `--db <provider>` | The database: the adapter's providers (`sqlite`, `postgresql`). | `sqlite` |
48
- | `--package-manager <npm\|pnpm>` | — | the lockfile's, else the one that launched the CLI, else npm |
50
+ | `--package-manager <npm\|pnpm>` | The package manager. | the lockfile's, else the one that launched the CLI, else npm |
49
51
  | `--prisma-service <path#Export>` (`init`) | Your Prisma service, when more than one, or none, is found. | the one found; none → write `src/prisma.service.ts` |
50
52
  | `--prisma-module <path#Export>` (`init`) | The Nest module that provides and exports it. | the one found |
51
53
  | `--skip-install` | Write the files; print the install instead of running it. | |
52
54
  | `--skip-git` (`new`) | Passed to `nest new`. | |
53
- | `-y`, `--yes` | Accept every unanswered default **and** replace existing content that differs. | |
55
+ | `-y`, `--yes` | Accept every unanswered default, and replace existing content that differs. | |
56
+ | `--verbose` | Show the output of `nest new` and the install as they run. | |
57
+
58
+ While it works, each step is shown on stderr, such as `[3/4] Installing dependencies (npm install)`. On a terminal it
59
+ has a spinner and the seconds so far; in a pipe, in CI (`CI`) or with `NO_COLOR` it is one plain line per step
60
+ (`… done (12.4s)`). The output of `nest new` and the install is shown only if it fails, or with `--verbose`.
54
61
 
55
62
  Existing content that differs from what would be written (a `.env` key, a script, a file) is listed, and replaced only
56
63
  when you confirm, or with `--yes`; where nobody can be asked, the run stops and touches nothing.
@@ -59,28 +66,28 @@ when you confirm, or with `--yes`; where nobody can be asked, the run stops and
59
66
 
60
67
  | Path | Owner afterwards |
61
68
  |---|---|
62
- | `prisma/schema.prisma` — `prisma-client` generating into `src/generated/prisma`, a `User` model | you |
63
- | `prisma.config.ts` — loads `.env` itself (Prisma does not) | you |
64
- | `src/prisma.service.ts` — `PrismaService` extending the client with the driver adapter, refusing a missing `DATABASE_URL` before the server listens; `PrismaModule` | you |
65
- | `src/aventara.config.ts` — `aventaraConfig(prisma)`: the entrypoint (`/api`), and the restrictions and pipelines you add | you |
66
- | `src/app.module.ts` — one edit: the imports, `PrismaModule` and `AventaraModule.forRootAsync({ … })`; printed instead when the file is not the shape expected | you |
67
- | `test/app.e2e-spec.ts` — one edit: a `GET /api/_contract` → 200 test after Nest's `GET /` test; left alone when the file is not Nest's | you |
68
- | `src/main.ts` — one edit after `NestFactory.create`: `app.enableCors(…)` for the comma-separated origins in `CORS_ORIGINS`, and CORS off when it is unset or empty, then a commented-out platform-level rate limiter (`express-rate-limit`; Nest's `@nestjs/throttler` is a guard, which does not run on Aventara's routes); left alone when the file already configures CORS, printed when it has no such line | you |
69
+ | `prisma/schema.prisma`: `prisma-client` generating into `src/generated/prisma`, a `User` model | you |
70
+ | `prisma.config.ts`: loads `.env` itself (Prisma does not) | you |
71
+ | `src/prisma.service.ts`: `PrismaService` extending the client with the driver adapter, refusing a missing `DATABASE_URL` before the server listens; `PrismaModule` | you |
72
+ | `src/aventara.config.ts`: `aventaraConfig(prisma)`: the `api` mount path (`/api`), a `diagnostics` sink that logs the raw error of a server failure, with its stack, through Nest's `Logger`, and the `exposed`/`exemptions`, `pipelines` and `resources` you add | you |
73
+ | `src/app.module.ts`: one edit that adds the imports, `PrismaModule` and `AventaraModule.forRootAsync({ … })`; printed instead when the file is not the shape expected | you |
74
+ | `test/app.e2e-spec.ts`: one edit that adds a `GET /api/_contract` → 200 test after Nest's `GET /` test; left alone when the file is not Nest's | you |
75
+ | `src/main.ts`: one edit after `NestFactory.create`: `app.enableCors(…)` for the comma-separated origins in `CORS_ORIGINS`, and CORS off when it is unset or empty, then a commented-out platform-level rate limiter (`express-rate-limit`; Nest's `@nestjs/throttler` is a guard, which does not run on Aventara's routes); left alone when the file already configures CORS, printed when it has no such line | you |
69
76
  | `.env` (`DATABASE_URL`, and `CORS_ORIGINS="http://localhost:5173,http://localhost:3001"` appended unless a line sets it), `.gitignore` (`/src/generated/`, `/dev.db*`, `.env`) | you |
70
- | `package.json` — `@aventara/*` at this CLI's version, `prisma`, `@prisma/client` and the driver at `7.10.0`; `aventara:prepare`, run by `postinstall` and by `prebuild`, `prestart`, `prestart:dev` and `prestart:debug`, and the `.env` on the start scripts and `test:e2e` (`--env-file`, `--env-file-if-exists`) | you |
71
- | `pnpm-workspace.yaml` (pnpm only) — `allowBuilds` for Prisma's and SQLite's install scripts | you |
72
- | `src/generated/prisma/**`, `src/generated/aventara/discovery.artifact.ts` | **generated** by `aventara:prepare` (run on every install, build and start, so a schema change needs only a restart); never edit |
77
+ | `package.json`: `@aventara/*` at this CLI's version, `prisma`, `@prisma/client` and the driver at `7.10.0`; `aventara:prepare`, run by `postinstall` and by `prebuild`, `prestart`, `prestart:dev` and `prestart:debug`, and the `.env` on the start scripts and `test:e2e` (`--env-file`, `--env-file-if-exists`) | you |
78
+ | `pnpm-workspace.yaml` (pnpm only): `allowBuilds` for Prisma's and SQLite's install scripts | you |
79
+ | `src/generated/prisma/**`, `src/generated/aventara/discovery.artifact.ts` | generated by `aventara:prepare` (run on every install, build and start, so a schema change needs only a restart); never edit |
73
80
 
74
81
  ### Next steps it prints
75
82
 
76
83
  ```bash
77
84
  npx prisma db push # create the tables (init never touches a database); pnpm: pnpm exec prisma db push
78
85
  npm run start:dev # GET http://localhost:3000/api/_contract
79
- npx @aventara/client@pilot init # in your frontend; pnpm: pnpm dlx @aventara/client@pilot init
86
+ npx @aventara/client@rc init # in your frontend; pnpm: pnpm dlx @aventara/client@rc init
80
87
  ```
81
88
 
82
89
  The frontend command is the package manager's own runner (`npx`, or `pnpm dlx` under pnpm) and, while the CLI is a
83
- prerelease, carries its dist-tag (`@pilot`), so the client comes from the same release.
90
+ prerelease, carries its dist-tag (`@rc`), so the client comes from the same release.
84
91
 
85
92
  With PostgreSQL, set `DATABASE_URL` in `.env` first (init writes Prisma's placeholder, and never asks for a secret).
86
93
 
@@ -106,23 +113,29 @@ curl -s -X POST http://localhost:3000/api/_resources/User/find/many \
106
113
  Leave out an identity header and the answer is `400 A2000`, naming the header that is missing. The hash changes
107
114
  whenever the schema or the configuration does: fetch it again, and regenerate the client.
108
115
 
109
- - **Resource keys are the model names, as written.** `model User` is `User` everywhere: on the wire
110
- (`/_resources/User/find/many`) and in the generated client (`avClient.User.find.many({})`). Nothing is renamed,
111
- lower-cased or pluralized.
112
- - **Results are read-only.** A list result is a `readonly` array: type it `readonly User[]`, not `User[]` —
113
- `const users: readonly User[] = await avClient.User.find.many({});`.
116
+ Resource keys are the model names, as written. `model User` is `User` everywhere: on the wire
117
+ (`/_resources/User/find/many`) and in the generated client (`avClient.User.find.many({})`). Nothing is renamed,
118
+ lower-cased or pluralized.
119
+
120
+ Results are read-only. A list result is a `readonly` array, so type it `readonly User[]`:
121
+ `const users: readonly User[] = await avClient.User.find.many({});`.
114
122
 
115
123
  ## Supported
116
124
 
117
- NestJS 12; Node `^22.18.0 || >=24.2.0` (on any other Node the bin refuses in one sentence naming that range;
118
- on Node 22 use npm ≥ 11 — Node 22's bundled npm 10 cannot install Nest 12's own scaffold; a CommonJS project's jest
119
- e2e needs Node ≥ 24.9, Nest's and Jest's limit); npm and pnpm (yarn is not supported); ESM and
120
- CommonJS projects; Prisma 7 (`^7.10.0`) on SQLite and PostgreSQL. The ORMs, majors, databases and drivers on offer are
121
- **generated** from the Aventara adapter packages that exist (`src/catalog/adapter.catalog.generated.ts`), never listed
122
- by hand: a future
123
- `@aventara/prisma8-adapter` appears by existing.
125
+ - NestJS 12.
126
+ - Node `^22.18.0 || >=24.2.0`. On any other Node the bin refuses in one sentence naming that range. On Node 22 use
127
+ npm ≥ 11, because Node 22's bundled npm 10 cannot install Nest 12's own scaffold. A CommonJS project's jest e2e needs
128
+ Node ≥ 24.9, which is Nest's and Jest's limit.
129
+ - npm and pnpm. Yarn is not supported.
130
+ - ESM and CommonJS projects.
131
+ - Prisma 7 (`^7.10.0`) on SQLite and PostgreSQL.
132
+
133
+ The ORMs, majors, databases and drivers on offer are generated from the Aventara adapter packages that exist
134
+ (`src/catalog/adapter.catalog.generated.ts`), never listed by hand, so a future `@aventara/prisma8-adapter` appears
135
+ once it exists.
124
136
 
125
137
  ## License
126
138
 
127
- PolyForm Shield 1.0.0 with an additional permission — free to use, including in commercial applications; you may not
128
- use it to build a product that competes with Aventara itself. See `LICENSE` and `LICENSE-ADDITIONAL-PERMISSION.md`.
139
+ PolyForm Shield 1.0.0 with an additional permission. It is free to use, including in commercial applications, but you
140
+ may not use it to build a product that competes with Aventara itself. See `LICENSE` and
141
+ `LICENSE-ADDITIONAL-PERMISSION.md`.
@@ -1,5 +1,5 @@
1
- export class ConflictsNotConfirmedError extends Error {
2
- name = "ConflictsNotConfirmedError";
1
+ export class AvConflictsNotConfirmedError extends Error {
2
+ name = "AvConflictsNotConfirmedError";
3
3
  }
4
4
  export function conflictWarning(conflicts) {
5
5
  return `${conflicts.join(", ")} already ${conflicts.length === 1 ? "has" : "have"} other content, and initializing will replace ${conflicts.length === 1 ? "it" : "them"}`;
@@ -10,7 +10,7 @@ export async function confirmConflicts(conflicts, consent) {
10
10
  }
11
11
  const them = conflicts.length === 1 ? "it" : "them";
12
12
  if (!consent.prompter.interactive) {
13
- throw new ConflictsNotConfirmedError(`not initializing, and nothing was touched: ${conflicts.join(", ")} already ${conflicts.length === 1 ? "has" : "have"} other content and nobody can be asked (stdin is not a terminal); run \`aventara init --yes\` to replace ${them}`);
13
+ throw new AvConflictsNotConfirmedError(`not initializing, and nothing was touched: ${conflicts.join(", ")} already ${conflicts.length === 1 ? "has" : "have"} other content and nobody can be asked (stdin is not a terminal); run \`aventara init --yes\` to replace ${them}`);
14
14
  }
15
15
  consent.prompter.say(`aventara: warning: ${conflictWarning(conflicts)}.`);
16
16
  const answer = await consent.prompter.ask({
@@ -19,6 +19,6 @@ export async function confirmConflicts(conflicts, consent) {
19
19
  defaultValue: "N",
20
20
  });
21
21
  if (!/^y(?:es)?$/i.test(answer.trim())) {
22
- throw new ConflictsNotConfirmedError(`cancelled, and nothing was touched; run again and answer yes to replace ${them}`);
22
+ throw new AvConflictsNotConfirmedError(`cancelled, and nothing was touched; run again and answer yes to replace ${them}`);
23
23
  }
24
24
  }
package/dist/cli.js CHANGED
@@ -1,22 +1,23 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { ConflictsNotConfirmedError } from "./apply/conflict.confirmer.js";
2
+ import { AvConflictsNotConfirmedError } from "./apply/conflict.confirmer.js";
3
3
  import { ADAPTER_CATALOG } from "./catalog/adapter.catalog.generated.js";
4
- import { CliCommandError, commandUsage, parseCliCommand, usage, } from "./command/command.parser.js";
5
- import { ProjectRefusedError } from "./project/project.inspector.js";
4
+ import { AvCliCommandError, commandUsage, parseCliCommand, usage, } from "./command/command.parser.js";
5
+ import { AvProjectRefusedError } from "./project/project.inspector.js";
6
6
  import { runCommand } from "./run/command.runner.js";
7
- import { InstallFailedError, runInit } from "./run/init.orchestrator.js";
7
+ import { AvInstallFailedError, runInit } from "./run/init.orchestrator.js";
8
8
  import { runNew } from "./run/new.orchestrator.js";
9
- import { UnansweredQuestionsError, } from "./wizard/answer.resolver.js";
10
- import { createReadlinePrompter, WizardCancelledError, } from "./wizard/readline.prompter.js";
11
- import { WizardAnswerError } from "./wizard/wizard.questions.js";
9
+ import { progressModeOf } from "./run/step.reporter.js";
10
+ import { AvUnansweredQuestionsError, } from "./wizard/answer.resolver.js";
11
+ import { AvWizardCancelledError, createReadlinePrompter, } from "./wizard/readline.prompter.js";
12
+ import { AvWizardAnswerError } from "./wizard/wizard.questions.js";
12
13
  const REFUSALS = [
13
- CliCommandError,
14
- WizardAnswerError,
15
- UnansweredQuestionsError,
16
- WizardCancelledError,
17
- ProjectRefusedError,
18
- ConflictsNotConfirmedError,
19
- InstallFailedError,
14
+ AvCliCommandError,
15
+ AvWizardAnswerError,
16
+ AvUnansweredQuestionsError,
17
+ AvWizardCancelledError,
18
+ AvProjectRefusedError,
19
+ AvConflictsNotConfirmedError,
20
+ AvInstallFailedError,
20
21
  ];
21
22
  const MANIFEST = new URL("../package.json", import.meta.url);
22
23
  function ownVersion() {
@@ -47,6 +48,7 @@ export async function runCli(argv, io) {
47
48
  runner: io.runner ?? runCommand,
48
49
  catalog: io.catalog ?? ADAPTER_CATALOG,
49
50
  aventaraVersion: ownVersion(),
51
+ progressMode: io.progress ?? "off",
50
52
  });
51
53
  }
52
54
  return await runNew(command, {
@@ -58,6 +60,7 @@ export async function runCli(argv, io) {
58
60
  runner: io.runner ?? runCommand,
59
61
  catalog: io.catalog ?? ADAPTER_CATALOG,
60
62
  aventaraVersion: ownVersion(),
63
+ progressMode: io.progress ?? "off",
61
64
  });
62
65
  }
63
66
  catch (error) {
@@ -85,6 +88,7 @@ export async function runFromProcess() {
85
88
  process.stderr.write(text);
86
89
  },
87
90
  prompter,
91
+ progress: progressModeOf(process.stderr.isTTY, process.env),
88
92
  });
89
93
  }
90
94
  finally {