@aventara/cli 1.0.0-rc.0 → 1.0.0-rc.10

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/CHANGELOG.md CHANGED
@@ -1,5 +1,466 @@
1
1
  # @aventara/cli
2
2
 
3
+ ## 1.0.0-rc.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 82afc5e: The scaffolded configuration's `diagnostics` sink logs `String(error)` when an error's `stack` is empty or missing,
8
+ instead of an empty `raw error` line.
9
+
10
+ `aventara` prints a defect as `String(error)` when its `stack` is empty or missing, instead of a blank or `undefined`
11
+ line.
12
+
13
+ - 09585dd: The agent skill's configuration reference covers `managedElsewhere`: a model whose table another service owns, and
14
+ the Prisma 7 external-tables setup that keeps `prisma migrate` off it.
15
+ - 04bb39a: `engines.node` is now `^22.23.4 || >=24.22.1`, the Node security releases of 2026-10-20 (CVE-2026-105481,
16
+ CVE-2026-105482, CVE-2026-105483, CVE-2026-106069, CVE-2026-106072, CVE-2026-106073, CVE-2026-106074,
17
+ CVE-2026-111497). The bins refuse an older Node in one sentence naming that range.
18
+ - 4f0fd29: The Prisma 7 adapter's peer floor is now `^7.10.1` (`prisma`, `@prisma/client`, `@prisma/adapter-pg`,
19
+ `@prisma/adapter-better-sqlite3`). `prisma` 7.10.0 pins `mysql2` 3.15.3 (GHSA-3f6p-5ww8-9rcr, GHSA-rgwj-5xj2-c3m3)
20
+ and, through `@prisma/config`, `deepmerge-ts` 7.1.5 (GHSA-ggr8-5vv4-36mx); 7.10.1 pins `mysql2` 3.24.4 and
21
+ `deepmerge-ts` 8.0.2. `aventara new` and `aventara init` install Prisma at the floor, so new projects get 7.10.1, and
22
+ `aventara init` refuses a project whose Prisma is below it.
23
+ - 10341d5: The Next.js scaffold's `src/prisma.ts` keeps one PrismaClient per generated schema: after `aventara:prepare` regenerates
24
+ the client, the next call makes a new one and disconnects the old one, so `next dev` needs no restart.
25
+ - 88263a1: Startup checks, tightened:
26
+
27
+ - An `mcp.authorization.servers` entry with a query or a fragment is refused for https URLs too, not only for loopback
28
+ http ones: an authorization server's issuer has neither (RFC 8414).
29
+ - A `client.resources` or `agent.resources` entry for a Resource managed elsewhere is refused (`COMPILER_UNKNOWN_RESOURCE`):
30
+ those layers never have the Resource, so nothing configured there would run. Configure it at the root or in
31
+ `application`.
32
+
33
+ - 88263a1: Documentation: `$access.can([])` answers `[]`, not a refusal; the MCP README states the query and fragment rule for
34
+ every authorization server.
35
+
36
+ ## 1.0.0-rc.9
37
+
38
+ ### Patch Changes
39
+
40
+ - a0bb05e: The agent skill that `aventara new`, `aventara init` and `aventara skill` write has a new section, "Calling the API over
41
+ HTTP", with a working curl example: the operation path uses the model's name as written in the Prisma schema
42
+ (`/api/_resources/User/create/one`), every request sends the `Aventara-Protocol-Version: 1` and
43
+ `Aventara-Contract-Hash` headers (the hash comes from `GET /api/_contract`), and a create's body is `{ "data": … }`. It
44
+ lists the answers each mistake gets. The printed next steps point to it. To refresh the skill in an existing
45
+ project, run `aventara skill`.
46
+ - 8c40b81: `aventara new` and `aventara init` now scaffold Next.js apps.
47
+
48
+ - `aventara new <name> --host next` runs `create-next-app@latest` (TypeScript, the App Router under `src/`, the `@/*`
49
+ alias, no install of its own), then the same `init` steps, then the install. create-next-app asks its own questions
50
+ on your terminal; with `--yes` it takes its defaults. Its own flags go after `--`, as they are:
51
+ `aventara new my-app --host next --yes -- --tailwind`. `--skip-git` becomes its `--disable-git`. Without a terminal,
52
+ `--yes` is required. `--host` defaults to `nest`: a NestJS project is scaffolded exactly as before.
53
+ - `aventara init` tells the host by `package.json`: `@nestjs/core` is NestJS 12, `next` is Next.js 16, and a project
54
+ that depends on both or neither is refused in one sentence, with nothing written. A Next.js app needs `src/app/`
55
+ and the `@/*` → `./src/*` path in `tsconfig.json`, and no ORM yet.
56
+ - In a Next.js app, init writes `src/aventara/config.ts`, `src/aventara/adapter.ts`, `src/aventara/server.ts`
57
+ (`Aventara()`, exporting `handlers`, `avClient`, `avApp` and `ready`), `src/app/api/[...aventara]/route.ts`,
58
+ `src/instrumentation.ts` (awaiting `ready()` on the Node.js runtime) and `src/prisma.ts`, with Prisma's schema and
59
+ config. `aventara:prepare` ends with `aventara-build --client` and runs on `postinstall` and `prebuild`; the files it
60
+ generates (`src/aventara/generated/`, `src/aventara/client.ts`, `src/aventara/universal.ts`) are added to
61
+ `.gitignore`. An instrumentation file of your own is never replaced: the lines to add are printed.
62
+ - Each host package now declares its project layout in its manifest (`"aventara": { "host": … }`). The CLI scaffolds
63
+ from it and `aventara-build` reads its paths from it, so the two always agree.
64
+
65
+ - 501b832: `aventara new --host next` and `aventara init` in a Next.js app add `serverExternalPackages: ["@aventara/core",
66
+ "@aventara/prisma7-adapter"]` to `next.config.ts`, so Node.js loads them once per server process: every route and
67
+ page shares one core, one Framework and one Prisma client. The line goes into create-next-app's config, or any config
68
+ whose `const nextConfig = {` object has no `serverExternalPackages`; an app with no config gets a `next.config.ts`. A
69
+ config that already names `serverExternalPackages`, or is written another way, is never changed, even with `--yes`:
70
+ the line to add is printed, with a warning. The agent skill's Next.js section says to keep it.
71
+ - The agent skill's Next.js section says what a page that calls `avClient` or `avApp` needs under Cache Components
72
+ (create-next-app's default): the calling component inside `<Suspense>` (or a `loading.tsx`), `"use cache"` on the
73
+ function that makes the call, or `export const instant = false`.
74
+
75
+ ## 1.0.0-rc.8
76
+
77
+ 1.0.0-rc.5, rc.6 and rc.7 were tagged but never published; 1.0.0-rc.8 contains everything listed under them and the changes below.
78
+
79
+ ## 1.0.0-rc.7
80
+
81
+ 1.0.0-rc.5 and 1.0.0-rc.6 were tagged but never published; 1.0.0-rc.7 contains everything listed under them and the changes below.
82
+
83
+ ## 1.0.0-rc.6
84
+
85
+ 1.0.0-rc.5 was tagged but never published. 1.0.0-rc.6 contains everything listed under 1.0.0-rc.5 and the fix below.
86
+
87
+ ## 1.0.0-rc.5
88
+
89
+ ## 1.0.0-rc.4
90
+
91
+ ### Patch Changes
92
+
93
+ - 7c3b65f: Build-time Contracts for serverless and edge cold starts.
94
+
95
+ - New package `@aventara/build`, bin `aventara-build`, a development dependency. It runs `src/aventara.config.ts` and
96
+ `src/aventara.adapter.ts` without a database client, compiles the Contracts with the project's `@aventara/core` and
97
+ writes `src/generated/aventara/contracts.generated.ts` (`aventaraContracts`), which a serverless or edge entry passes
98
+ to `createFramework` as `prebuilt`. A configuration that startup would refuse fails the build with the same
99
+ `CONFIG_…`/`COMPILER_…` diagnostics. `aventara-build --check` writes nothing and exits 1 when the file is missing or
100
+ stale, naming the Resources that changed.
101
+ - `@aventara/prisma7-adapter`: `describePrismaAdapter({ discovery, provider, driver })` states the adapter's passive
102
+ facts (the model, the driver's transaction capability, the referential actions, the computed fields) with no client.
103
+ `createPrismaAdapter({ ...description, client })` builds the adapter from the same facts, and still checks the client
104
+ against the discovery artifact.
105
+ - `@aventara/cli`: the scaffold's `src/aventara.config.ts` exports the configuration as a plain value
106
+ (`export const aventaraConfig = { … } as const`) with no `adapter`. A new `src/aventara.adapter.ts` default-exports
107
+ `describePrismaAdapter(…)`, and `app.module.ts` joins the two:
108
+ `config: { ...aventaraConfig, adapter: await createPrismaAdapter({ ...adapter, client: prisma }) }`. The Nest server
109
+ still compiles its Contracts at startup and passes no `prebuilt`. `aventara:prepare` ends with `&& aventara-build`,
110
+ and `@aventara/build` is an exact development dependency.
111
+
112
+ - 2b1b17e: `aventara-build`'s files no longer land inside a Prisma client generated into `src/generated`.
113
+
114
+ When `aventara init` reuses a project whose Prisma client is generated into `src/generated`, it already puts the
115
+ discovery artifact in `src/aventara/`, because `prisma generate` deletes every file in its output directory that it did
116
+ not write. `aventara-build` still wrote its three files to `src/generated/aventara/`, so each `prisma generate` deleted
117
+ them and the project stopped compiling until the next `aventara:prepare`. Now all of Aventara's generated files are
118
+ in one place.
119
+
120
+ - `@aventara/build`: `aventara-build` writes `resources.generated.ts`, `computed-fields.generated.ts` and
121
+ `contracts.generated.ts` to the directory the configuration imports `aventaraResources` from, so the tree is always
122
+ written where the configuration reads it. A configuration that imports no tree keeps `src/generated/aventara/`.
123
+ The files of a project whose client is generated anywhere else are the same bytes, in the same place.
124
+ - `@aventara/prisma7-adapter`: with `--config`, the artifact imports the computed fields from its sibling,
125
+ `./computed-fields.generated`, wherever `--out` puts it. `--config` is still required for that import and the step
126
+ still checks that the file exists, but the step no longer uses its location. A scaffold's artifact is unchanged.
127
+ - `@aventara/cli`: in that project, `src/aventara.config.ts` imports the tree from `./aventara/resources.generated`,
128
+ and `.gitignore` gets the one `/src/aventara/` line that covers all four files (no separate
129
+ `/src/generated/aventara/contracts.generated.ts` line). The agent skill says where the generated files are in
130
+ both cases.
131
+
132
+ - 99169d2: Policy engines, reads first. `createFramework` takes an optional root `policy: { engine, principal }`: an engine that
133
+ answers three questions (`can`, `scopeOf`, `fieldsOf`, each now or as a promise), and a function that derives a
134
+ request's principal from its `ctx.$state`. Core never imports an engine; one satisfies `AvPolicyEngine` by its shape,
135
+ and a scope or grant is a fragment of Aventara's own `where` (`AvPolicyWhere`).
136
+
137
+ - Client and agent requests are checked (an MCP tool call is an agent request). An application call is checked only
138
+ when it names a principal: `framework.application.Note.find.many(args, { as: user })`. A call a stage makes through
139
+ `ctx` never is.
140
+ - Before any guard, `can` and the fields the request names or receives (`fieldsOf`); a refusal is `403 A4002`. At the
141
+ adapter call, after every developer stage, the read scope is ANDed into the root `where`, every to-many include and
142
+ its `$count`, and every relation filter, at every level. A to-one include of a row out of scope refuses the request;
143
+ it is never nulled.
144
+ - Governed fields (the engine's `governed` list) are left out of every default projection and carry `governed: true`
145
+ in the Contracts. Name one to get it: `select: ["$defaults", "email"]`, where `$defaults` is the level's default
146
+ projection. It is refused where a returned row does not grant it, and a filter or sort by it is checked before the
147
+ query runs, so it cannot reveal values the caller may not read.
148
+ - The engine's `governed` and `paths` lists are checked against the Core Contract at startup. A rule's paths are lists
149
+ of segments, as other paths in core are: `["Note", "campaign", "members", "some", "userId", "equals"]`.
150
+ - Writes are checked as well; see the policy writes entry.
151
+
152
+ Without `policy`, nothing changes: the Contracts and their hashes are the same bytes.
153
+
154
+ - 154e440: Policy engines check writes. Every create, update, delete and upsert a client or agent makes (or an application call
155
+ made `{ as }` a principal) is now checked by the configuration's `policy`, where before it was refused.
156
+
157
+ - The fields a write sends are held to `fieldsOf({ access: "write" })` before any guard; a field outside it answers
158
+ `403 A4002`. A field writable on some rows only is checked against every row an update reaches, and against the
159
+ row a create inserts, after the insert and inside its transaction.
160
+ - A create asks `can({ action: "create", row })` about each new row on its final data. Its rules can look rows up
161
+ through `exists`, which runs inside the write's transaction, so a plan that creates a campaign and then its first
162
+ note sees the campaign.
163
+ - An update or delete acts only on rows the caller may both change (`scopeOf` for the action) and read. A single-row
164
+ one that matches nothing answers `A4002` when the caller can read the row, and `A2003` when it cannot, so the
165
+ answer does not reveal that the row exists. A `many` or `count` one answers for the caller's rows only.
166
+ - An update that moves a row out of what the caller reads is rolled back with `A4002`. So is one that fails an `after`
167
+ condition: inside the transaction core asks `can({ action: "update", row })` about each changed row of every
168
+ checked update. The engine's new `afterChecks` member (`{ Note: ["update"] }`) names the updates whose grants carry
169
+ such a condition, which are the ones refused where there is no interactive transaction.
170
+ - Where the operation's `transactionsStyle` is `"interactive"`, a checked write runs in a transaction of its own. Where
171
+ it is `"none"` (Cloudflare D1), a write that can only be checked after it runs is refused before it runs; every other
172
+ write runs, a create looking up before it inserts, and an unlisted update without the after check.
173
+ - Nested writes (a relation directive in a write's data) are refused under a policy for now.
174
+
175
+ `afterChecks` is checked against the Core Contract at startup and changes no Contract and no prebuilt fingerprint.
176
+
177
+ - 3813207: The Resource tree and the computed fields come from `aventara-build`.
178
+
179
+ - `@aventara/build`: before it compiles the Contracts, `aventara-build` writes two more files under
180
+ `src/generated/aventara/`. `resources.generated.ts` exports `aventaraResources`: every `defineResource(…)` result
181
+ that the files `src/resources/**/*.resource.ts` export, found by its type (never run), one `resources` tree per
182
+ layer, written as the plain spreads you wrote by hand (`root` always, `application`, `client` and `agent` when some
183
+ Resource has a block for them). Two definitions of one Resource stop the build, naming both. Imports are spelled as
184
+ the project spells its own. `computed-fields.generated.ts` exports `computedFields` and its type `AvComputedFields`:
185
+ which fields the configuration's write compute fills, read off its type after the tree exists, so a fresh install is
186
+ typed right on its first `aventara:prepare`. `--check` covers all three files. `typescript` (`>=5.7.0 <7`) is now a
187
+ peer dependency.
188
+ - `@aventara/prisma7-adapter`: the generate step no longer reads the configuration. With `--config`, the discovery
189
+ artifact imports `computedFields` and `AvComputedFields` from the file `aventara-build` writes beside the
190
+ configuration (`generated/aventara/computed-fields.generated.ts`); a `--config` file that does not exist is still
191
+ refused. `readConfigComputedFields`, `AvPrismaConfigReaderError` and `ConfigComputedFieldsReading` are removed from
192
+ `@aventara/prisma7-adapter/generate`, as are `PrismaGenerateToolchain.readComputedFields` and
193
+ `PrismaGenerateResult.computedFields`.
194
+ - `@aventara/cli`: the scaffold's `src/aventara.config.ts` takes its Resources from the tree,
195
+ `resources: aventaraResources.root`, so a new Resource file needs no configuration edit; the agent skill says so.
196
+
197
+ ## 1.0.0-rc.3
198
+
199
+ ### Patch Changes
200
+
201
+ - b38034d: A refusal that quotes a failed child's output (`npm install`, `nest new`) ends with that output as the child wrote it.
202
+ It printed a period of its own after the child's last line (`npm ERR! the registry said no.`).
203
+
204
+ ## 1.0.0-rc.2
205
+
206
+ ### Patch Changes
207
+
208
+ - `aventara init`'s refusal of a TypeScript 7 project names the supported range: "use TypeScript 5.7 to 6" (it said
209
+ "use TypeScript 6 or 5"). The Prisma adapter's `typescript` peer range starts at 5.7.0 now.
210
+ - An agent skill for your AI coding agent. `aventara new` and `aventara init` write `.claude/skills/aventara/`:
211
+ `SKILL.md` (the Agent Skills format Claude Code reads: when to use it, and one rule per task) and
212
+ `reference/config.md`, `reference/stages.md`, `reference/recipes.md` and `reference/errors.md` (`@aventara/core`'s
213
+ `ERRORS.md`), for the Aventara version they install. They also add a short Aventara section to `AGENTS.md`, between
214
+ `<!-- aventara:start -->` and `<!-- aventara:end -->`, for agents that read `AGENTS.md`: an existing `AGENTS.md`
215
+ keeps everything else, and `CLAUDE.md` is never written.
216
+ - `aventara skill` refreshes those files for the `@aventara/core` installed in the project (its version and its
217
+ `ERRORS.md`; it runs none of the project's packages). It rewrites the skill files it wrote, keeps one you changed
218
+ and says so (`--force` replaces it), and replaces only the marked section of `AGENTS.md`.
219
+ - `aventara new` and `aventara init` write an `aventara:prepare` script that also passes
220
+ `--config src/aventara.config.ts`, so the generated types know which fields your configuration computes: a
221
+ variant's guards, pipes and filters may leave exactly those out of a create. A project set up before keeps working;
222
+ add the flag to its script to get the precise types.
223
+ - The agent skill says that a `Date` or bytes value a stage is told is that stage's own copy, so changing it in place
224
+ changes nothing another stage sees, what is written or what the caller receives; and that a `compute.read` stage with
225
+ no `dependsOn` computes from the same inputs for every row, so its value usually belongs in response metadata or
226
+ `ctx.$state`. In rc.1 it said neither.
227
+ - The agent skill says that a `compute.read` stage is told the row frozen: it returns its field's value, and writing
228
+ into `record` answers `A3000`. Its error reference lists a nested write that writes its relation back (`A2004`,
229
+ `V1012`).
230
+ - The agent skill says that a computed value its field's `format` refuses (a relative path for `format: "url"`)
231
+ answers `A3000`, as a value of the wrong type does.
232
+ - Released with the other Aventara packages, and `aventara new` and `aventara init` install them at 1.0.0-rc.2.
233
+
234
+ ## 1.0.0-rc.1
235
+
236
+ ### Patch Changes
237
+
238
+ - 7e3d06f: Breaking: the configuration has a new shape. Every layer (the root, `application` and `client`) now holds the
239
+ same six keys: `exposed`, `transactionsStyle`, `limits`, `pipelines`, `resources` and `exemptions`. Everything about
240
+ one Resource lives under `resources.<Resource>`: its fields, and each field's `definition` and `pipelines`. The old
241
+ keys are refused when the framework starts, with a message that names where each one moved:
242
+
243
+ | Before (rc.0) | Now (rc.1) |
244
+ | ------------------------------------------------------- | ----------------------------------------------------------------------------------- |
245
+ | `fields: { Post: { url: { type, nullable, … } } }` | `resources: { Post: { fields: { url: { definition: { type, nullable, … } } } } }` |
246
+ | `behaviors: { Post: { fields: { slug: { create } } } }` | `resources: { Post: { fields: { slug: { pipelines: { compute: { create } } } } } }` |
247
+ | `transactions: "none"` | `transactionsStyle: "none"` |
248
+ | `restrictions` | `exposed` + `exemptions` (see below) |
249
+ | `@aventara/core/json` | `@aventara/core/avz` |
250
+
251
+ Before:
252
+
253
+ ```ts
254
+ createFramework({
255
+ api: "/api",
256
+ adapter,
257
+ transactions: "interactive",
258
+ fields: {
259
+ Post: {
260
+ url: {
261
+ type: { scalar: "string" },
262
+ nullable: false,
263
+ list: false,
264
+ lifecycle: ["VIRTUAL"],
265
+ },
266
+ },
267
+ },
268
+ behaviors: {
269
+ Post: {
270
+ fields: {
271
+ url: {
272
+ read: {
273
+ dependsOn: ["slug"],
274
+ compute: ({ record }) => `/p/${record.slug}`,
275
+ },
276
+ },
277
+ },
278
+ },
279
+ },
280
+ });
281
+ ```
282
+
283
+ After:
284
+
285
+ ```ts
286
+ createFramework({
287
+ api: "/api",
288
+ adapter,
289
+ transactionsStyle: "interactive",
290
+ resources: {
291
+ Post: {
292
+ fields: {
293
+ url: {
294
+ definition: {
295
+ type: { scalar: "string" },
296
+ nullable: false,
297
+ list: false,
298
+ lifecycle: ["VIRTUAL"],
299
+ },
300
+ pipelines: {
301
+ compute: {
302
+ read: {
303
+ dependsOn: ["slug"],
304
+ compute: ({ record }) => `/p/${record.slug}`,
305
+ },
306
+ },
307
+ },
308
+ },
309
+ },
310
+ },
311
+ },
312
+ });
313
+ ```
314
+
315
+ What else changed:
316
+
317
+ - A field is defined at the root only. A `definition` in `application` or `client` is refused
318
+ (`CONFIG_FORBIDDEN_IN_OVERLAY`). Define the field
319
+ at the root; `application` and `client` can still add compute stages to it.
320
+ - Computed values chain. When the root and an overlay both compute a field, the root's stage runs first and the
321
+ overlay's receives its result as `value`. A stage can no longer be turned off with `false`. Returning `undefined`
322
+ keeps the current value. An upsert computes its create branch with `compute.create` and its update branch with
323
+ `compute.update`.
324
+ - A discovered field keeps the adapter's facts. On a field the adapter discovered you may restate its own `type`,
325
+ `nullable` and `list`, and give a Json field its shape (`definition.json`). Setting a different type, any `format`
326
+ or any `capabilities` on it is refused. `format` is for fields you add, and it must be one of zod's named string
327
+ formats (`"email"`, `"url"`, `"uuid"`, …); any other name is a type error and refused at startup.
328
+ - A misplaced key is a type error. In a configuration written inline in `createFramework({ ... })` or
329
+ `AventaraModule.forRoot`, a key that has no place there (a typo, an old key, `compute` on a relation field, a field
330
+ name neither your schema nor the root has) is now a type error at that key, and still refused at startup.
331
+ - A Resource whose name starts with `$` is refused at startup (`$` names are the framework's).
332
+ - The Json shape builder moved from `@aventara/core/json` to `@aventara/core/avz`. Change the import; `AvZ` is
333
+ the same.
334
+
335
+ `exposed` and `exemptions`, which replace `restrictions`, have their own entry.
336
+
337
+ - 6317811: Breaking: `exposed` and `exemptions` replace `restrictions`. Every layer (the root, `application` and `client`)
338
+ says what it exposes with two keys: `exposed`, the layer's default, and `exemptions`, the entries that are the
339
+ opposite of it.
340
+
341
+ - `exposed: true` (the root's default) exposes everything the layer above offers, and `exemptions` lists what to
342
+ hide. `exposed: false` exposes nothing, and `exemptions` lists the only things to expose.
343
+ - In `exemptions`, `true` exempts an entry whole, `false` and `[]` exempt nothing, a list exempts the listed
344
+ entries one level down, and an object goes one level deeper. A Resource takes `true`, `false` or
345
+ `{ operations, fields }`. Operations are nested: `operations: { find: ["many"], update: { unique: true } }`.
346
+ A field takes a list of capability names, or an object per capability whose token lists name filter operators,
347
+ directives, reducers or pagination kinds.
348
+ - A list now always means "exempt these". rc.0's `filter: ["equals"]` meant "keep only `equals`"; under
349
+ `exposed: true` the same intent is the list of the operators to remove.
350
+ - Overlays only narrow. `application` and `client` start from the root's view. An overlay can no longer bring
351
+ back what the root hid (rc.0's `hidden: false`); that is now refused at startup, and the message names the other
352
+ overlay to hide it in instead. Expose an entry at the root and hide it in the overlay that must not see it.
353
+ - An overlay that sets `exemptions` must also set its own `exposed`.
354
+ - Relation positions are the adapter's: an exemption can no longer narrow where a relation is projected or written.
355
+ - A unique operation (`find.unique`, `update.unique`, `delete.unique`, `upsert.unique`) needs an identifier. Picking
356
+ one without the identifier's fields, or hiding every identifier while one stays exposed, is refused at startup
357
+ with `COMPILER_MISSING_IDENTIFIER` instead of the operation silently disappearing.
358
+
359
+ Every name in `exemptions` must exist, in both styles: a Resource, field, family, variant, capability or token the
360
+ adapter does not offer is refused at startup with its path (`COMPILER_UNKNOWN_RESOURCE`, `COMPILER_UNKNOWN_FIELD`,
361
+ `COMPILER_UNAVAILABLE_OPERATION`, `COMPILER_UNAVAILABLE_CAPABILITY`), and in a configuration written inline in
362
+ `createFramework({ ... })` it is a type error first. Under `exposed: true`, hiding in an overlay what the root
363
+ already hid does nothing.
364
+
365
+ Before (rc.0):
366
+
367
+ ```ts
368
+ createFramework({
369
+ api: "/api",
370
+ adapter,
371
+ restrictions: {
372
+ User: {
373
+ fields: {
374
+ passwordHash: { hidden: true },
375
+ email: { capabilities: { filter: ["equals"] } },
376
+ },
377
+ },
378
+ },
379
+ client: {
380
+ restrictions: {
381
+ AuditLog: { hidden: true },
382
+ Post: { operations: { delete: { unique: false } } },
383
+ },
384
+ },
385
+ });
386
+ ```
387
+
388
+ After (rc.1):
389
+
390
+ ```ts
391
+ createFramework({
392
+ api: "/api",
393
+ adapter,
394
+ // The root: `exposed` defaults to true, so these are hidden from every origin.
395
+ exemptions: {
396
+ resources: {
397
+ User: {
398
+ fields: {
399
+ passwordHash: true,
400
+ email: { filter: ["contains", "startsWith"] }, // remove every operator but `equals`
401
+ },
402
+ },
403
+ },
404
+ },
405
+ client: {
406
+ exposed: true,
407
+ exemptions: {
408
+ resources: {
409
+ AuditLog: true,
410
+ Post: { operations: { delete: ["unique"] } },
411
+ },
412
+ },
413
+ },
414
+ });
415
+ ```
416
+
417
+ Or expose only what a frontend calls:
418
+
419
+ ```ts
420
+ client: {
421
+ exposed: false,
422
+ exemptions: {
423
+ resources: {
424
+ Post: {
425
+ operations: { find: ["many", "unique"], create: ["one"] },
426
+ fields: { id: ["select"], title: ["select", "create"], body: ["select", "create"] },
427
+ },
428
+ },
429
+ },
430
+ },
431
+ ```
432
+
433
+ `aventara init` and `aventara new` now write `exposed: true` into `src/aventara.config.ts`, with a comment that
434
+ links the exposure documentation.
435
+
436
+ - 9c52482: A `$connect` to a row that does not exist now answers `404 A2003` (not found), the same as reading a missing row.
437
+ Before, it answered `422 A2004`. This covers a to-one `$connect` in `create`, `update` and `upsert`, a to-many
438
+ `$connect`, and the same writes inside a transaction plan, where `cause.operation` names the step. The message is
439
+ unchanged: "The operation's arguments referenced a record that does not exist." On `update.first`, the same mistake
440
+ answered `A2014` before, as if the row had changed underneath; it now answers `A2003` too, and a duplicate unique value
441
+ written through `update.first` answers `409 A2008` instead of `A3001`.
442
+
443
+ Clearer top-level messages for an unknown Resource or operation. `A2001` now says "The requested Resource is not
444
+ available." and `A2002` says "The requested operation is not available on this Resource.", instead of "Operation
445
+ arguments failed framework validation.", which stays the message of `A2004`, `A2007` and `A2009`. A transaction step
446
+ whose operation is outside the standard grammar now carries the same issue message as a single call, naming the
447
+ operation and the Resource (for example `Operation "dance.one" is not available on Resource "posts".`), instead of
448
+ "Operation is not part of the standard operation grammar."
449
+
450
+ A `$ref` with no `fingerprint` is `V1000` (required value missing) and answers `422 A2004`. Before, it was `V1017`
451
+ (fingerprint mismatch) under `A2007`. A fingerprint that is present but wrong is still `V1017`.
452
+
453
+ `aventara init` and `aventara new` link to the documentation at https://aventara-framework.vercel.app. The old
454
+ address redirects, so links already written into projects keep working.
455
+
456
+ - 8db76e7: `aventara new` and `aventara init` write a `diagnostics` sink into `src/aventara.config.ts`. When something fails
457
+ inside the server, the caller gets a plain 500 and the Nest log said only which request failed; the raw error went to
458
+ a sink the scaffold did not set. Now the sink logs the raw error with its stack through Nest's `Logger` (context
459
+ `Aventara`), at error level, right after that line. Replace it with your own reporter when you have one.
460
+
461
+ - `aventara new` and `aventara init` write `api: '/api'` into `src/aventara.config.ts` (the root key was renamed from
462
+ `entrypoint`).
463
+
3
464
  ## 1.0.0-rc.0
4
465
 
5
466
  ### Major Changes