@aventara/nest 1.0.0-rc.4 → 1.0.0-rc.9

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,63 @@
1
1
  # @aventara/nest
2
2
 
3
+ ## 1.0.0-rc.9
4
+
5
+ ### Patch Changes
6
+
7
+ - 8c40b81: `@aventara/nest` declares a NestJS project's layout in its manifest (`"aventara": { "host": … }`).
8
+ `aventara new` and `aventara init`, which now also scaffold Next.js apps, and `aventara-build` read a NestJS project's
9
+ paths from it, so the three always agree. A NestJS project is scaffolded exactly as before.
10
+ - 205a379: `AventaraModule` hosts a Framework built with `access` (an access provider, from `@aventara/core`): each protocol
11
+ request's `ctx.$state` is seeded by the provider's `state`, called with `{ headers, request }`, the platform
12
+ request's headers as `Headers` and Express's `req` or Fastify's `request`. It works the same through `config`
13
+ (`forRoot({ config: { ...config, access } })`) and `framework`. The module's own `state` option beside `access` is
14
+ refused while Nest builds the application, and is a type error on a `config` that states `access`.
15
+ - Updated dependencies [205a379]
16
+ - Updated dependencies [a0bb05e]
17
+ - Updated dependencies [86ab319]
18
+ - Updated dependencies [fdf52e6]
19
+ - @aventara/core@1.0.0-rc.9
20
+ - @aventara/mcp@1.0.0-rc.9
21
+
22
+ ## 1.0.0-rc.8
23
+
24
+ 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.
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies [1c8e4ee]
29
+ - @aventara/core@1.0.0-rc.8
30
+ - @aventara/mcp@1.0.0-rc.8
31
+
32
+ ## 1.0.0-rc.7
33
+
34
+ 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.
35
+
36
+ ### Patch Changes
37
+
38
+ - Updated dependencies [f917c1c]
39
+ - @aventara/core@1.0.0-rc.7
40
+ - @aventara/mcp@1.0.0-rc.7
41
+
42
+ ## 1.0.0-rc.6
43
+
44
+ 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.
45
+
46
+ ### Patch Changes
47
+
48
+ - Updated dependencies [1cf72e0]
49
+ - @aventara/core@1.0.0-rc.6
50
+ - @aventara/mcp@1.0.0-rc.6
51
+
52
+ ## 1.0.0-rc.5
53
+
54
+ ### Patch Changes
55
+
56
+ - Updated dependencies [4795ff1]
57
+ - Updated dependencies [9e178ca]
58
+ - @aventara/core@1.0.0-rc.5
59
+ - @aventara/mcp@1.0.0-rc.5
60
+
3
61
  ## 1.0.0-rc.4
4
62
 
5
63
  ### Patch Changes
package/README.md CHANGED
@@ -203,6 +203,11 @@ const signedIn: AvGuard = (ctx) => ctx.$state.user !== undefined;
203
203
  runs before it (`app.use` middleware, an earlier `onRequest` hook) has run.
204
204
  - Use `app.use(...)` for the middleware that finds the user (a Passport `authenticate` call, a session or JWT check).
205
205
  Nest guards never run on protocol routes, and `MiddlewareConsumer` middleware does not on Express (the table above).
206
+ - A Framework built with `access` (an access provider, see `@aventara/core`) seeds the state itself: the module calls
207
+ the provider's `state` with `{ headers, request }`, the platform request's headers and the request. Pass no `state`
208
+ beside it; the module refuses the pair while Nest builds the application, and as a type error on a `config` that
209
+ states `access`. It works the same through `config` and `framework`:
210
+ `AventaraModule.forRoot({ config: { ...config, access } })`.
206
211
  - Throw `new AvError("A4001", "…")` from `state` to refuse the request (`403`); any other throw is `500 A3000`, with the
207
212
  error in your `diagnostics` sink.
208
213
  - A plan sent to `/_transactions` gets one state for all its steps and transaction stages. A ctx call a stage makes
@@ -240,7 +245,7 @@ It is an optional peer dependency: an application without `mcp` does not need it
240
245
  package refuses to start, naming it and the command, with the version filled in:
241
246
 
242
247
  ```text
243
- AventaraModule: the configuration has `mcp`, and the package that serves it, @aventara/mcp, is not installed. Install it at @aventara/core's exact version (npm install --save-exact @aventara/mcp@1.0.0-rc.4), or remove `mcp` from the configuration.
248
+ AventaraModule: the configuration has `mcp`, and the package that serves it, @aventara/mcp, is not installed. Install it at @aventara/core's exact version (npm install --save-exact @aventara/mcp@1.0.0-rc.9), or remove `mcp` from the configuration.
244
249
  ```
245
250
  As for the protocol's routes, the module only mounts: the endpoint's body is read
246
251
  raw, the request's URL comes from the platform's `protocol` and `host` (set `trust proxy` on Express or `trustProxy` on
@@ -0,0 +1,7 @@
1
+ import type { AvFramework } from "@aventara/core";
2
+ import type { HostState } from "./protocol-host.factory.js";
3
+ /**
4
+ * The state seed of `framework`'s access provider, over a platform request;
5
+ * `undefined` for a Framework built without `access`.
6
+ */
7
+ export declare function accessStateSeed(framework: AvFramework): HostState | undefined;
@@ -0,0 +1,20 @@
1
+ import { accessStateOf } from "@aventara/core/internal";
2
+ function headersOf(request) {
3
+ const headers = new Headers();
4
+ const given = request?.headers;
5
+ for (const [name, value] of Object.entries(given ?? {})) {
6
+ if (value === undefined || name.startsWith(":")) {
7
+ continue;
8
+ }
9
+ for (const one of typeof value === "string" ? [value] : value) {
10
+ headers.append(name, one);
11
+ }
12
+ }
13
+ return headers;
14
+ }
15
+ export function accessStateSeed(framework) {
16
+ const state = accessStateOf(framework);
17
+ return state === undefined
18
+ ? undefined
19
+ : (request) => state({ headers: headersOf(request), request });
20
+ }
@@ -5,7 +5,8 @@ import { type PendingProtocolHost } from "./protocol-host.factory.js";
5
5
  * How the application's Framework enters Nest: your own instance
6
6
  * (`{ framework }`, from `createFramework`) or a configuration the module
7
7
  * passes to `createFramework` itself (`{ config }`). Pass exactly one. Either
8
- * arm may add `state`, which seeds each protocol request's `ctx.$state`.
8
+ * arm may add `state`, which seeds each protocol request's `ctx.$state`,
9
+ * unless the Framework is built with `access`, whose `state` seeds it.
9
10
  */
10
11
  export type AventaraModuleOptions<M extends AvAdapterModel = AvAdapterModel, Cfg = AvConfigAny> = ({
11
12
  readonly framework: AvFramework;
@@ -13,17 +14,26 @@ export type AventaraModuleOptions<M extends AvAdapterModel = AvAdapterModel, Cfg
13
14
  } | {
14
15
  readonly config: Cfg & AvConfigExact<M, Cfg> & AvConfig<M, Cfg>;
15
16
  readonly framework?: never;
16
- }) & {
17
+ }) & StateBesideAccess<Cfg> & {
17
18
  /**
18
19
  * Seeds a protocol request's `ctx.$state`, once per request, with the
19
20
  * platform's own request: Express's `req`, or Fastify's `request` (its Node
20
21
  * request is `request.raw`). What middleware already set there, such as
21
22
  * Passport's `req.user`, flows into every stage of the request. A throw is
22
23
  * answered like any developer failure: a thrown `AvError` as its own
23
- * outcome, anything else `500 A3000`. Omitted, the state is `{}`.
24
+ * outcome, anything else `500 A3000`. Omitted, the state is `{}`, or what
25
+ * the Framework's `access` provider seeds; not together with `access`.
24
26
  */
25
27
  state?(request: unknown): AvState | Promise<AvState>;
26
28
  };
29
+ /** `state` refused beside a configuration that states `access`, by the sentence that says why. */
30
+ type StateBesideAccess<Cfg> = [Cfg] extends [never] ? unknown : Cfg extends {
31
+ readonly access: object;
32
+ } ? {
33
+ readonly state?: readonly [
34
+ "Error: `access` seeds each request's state; remove `state`"
35
+ ];
36
+ } : unknown;
27
37
  /**
28
38
  * `forRootAsync`'s options: the Nest idiom when what builds the Framework
29
39
  * (a Prisma client, a configuration service) is itself a provider. The
@@ -62,3 +72,4 @@ export declare class AventaraModule implements NestModule, OnModuleInit {
62
72
  static forRootAsync<M extends AvAdapterModel, const Cfg = AvConfigAny>(options: AventaraModuleAsyncOptions<M, Cfg>): DynamicModule;
63
73
  private static mount;
64
74
  }
75
+ export {};
@@ -1,6 +1,7 @@
1
1
  import { createFramework, } from "@aventara/core";
2
2
  import { Inject, Module, } from "@nestjs/common";
3
3
  import { HttpAdapterHost } from "@nestjs/core";
4
+ import { accessStateSeed } from "./access-state.translator.js";
4
5
  import { AVENTARA_FRAMEWORK } from "./framework.token.js";
5
6
  import { checkedOptions, recordMount } from "./host-bootstrap.validator.js";
6
7
  import { withInternalFailureLog } from "./internal-failure.logger.js";
@@ -66,7 +67,7 @@ export class AventaraModule {
66
67
  {
67
68
  provide: PROTOCOL_HOST,
68
69
  inject: [HttpAdapterHost, AVENTARA_FRAMEWORK, OPTIONS, MCP_BINDING],
69
- useFactory: (application, framework, options, mcp) => createPendingProtocolHost(application, framework, options.state?.bind(options), mcp ?? undefined),
70
+ useFactory: (application, framework, options, mcp) => createPendingProtocolHost(application, framework, options.state?.bind(options) ?? accessStateSeed(framework), mcp ?? undefined),
70
71
  },
71
72
  ],
72
73
  exports: [AVENTARA_FRAMEWORK],
@@ -1,7 +1,9 @@
1
+ import { accessStateOf } from "@aventara/core/internal";
1
2
  const NEITHER_ARM = "AventaraModule: the options carry neither `framework` nor `config`; pass exactly one.";
2
3
  const BOTH_ARMS = "AventaraModule: the options carry both `framework` and `config`; pass exactly one.";
3
4
  const NOT_A_FRAMEWORK = "AventaraModule: `framework` is not an Aventara Framework (it has no string `api` and no `contracts.client`); pass what `createFramework` resolved to.";
4
5
  const STATE_NOT_A_FUNCTION = "AventaraModule: `state` is not a function; pass `(request) => ({ … })`, called once per protocol request.";
6
+ const STATE_BESIDE_ACCESS = "AventaraModule: the Framework is built with `access`, whose `state` seeds each request's state; remove the module's `state` option.";
5
7
  const MOUNTED_TWICE = "AventaraModule is mounted twice in one application; import AventaraModule.forRoot or forRootAsync once.";
6
8
  export function checkedOptions(options) {
7
9
  const record = typeof options === "object" && options !== null
@@ -22,6 +24,13 @@ export function checkedOptions(options) {
22
24
  if (state !== undefined && typeof state !== "function") {
23
25
  throw new Error(STATE_NOT_A_FUNCTION);
24
26
  }
27
+ if (state !== undefined &&
28
+ (hasFramework
29
+ ? accessStateOf(record.framework) !== undefined
30
+ : record.config?.access !==
31
+ undefined)) {
32
+ throw new Error(STATE_BESIDE_ACCESS);
33
+ }
25
34
  return record;
26
35
  }
27
36
  function isFramework(value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aventara/nest",
3
- "version": "1.0.0-rc.4",
3
+ "version": "1.0.0-rc.9",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "NestJS host integration for Aventara.",
6
6
  "type": "module",
@@ -22,10 +22,10 @@
22
22
  "CHANGELOG.md"
23
23
  ],
24
24
  "dependencies": {
25
- "@aventara/core": "1.0.0-rc.4"
25
+ "@aventara/core": "1.0.0-rc.9"
26
26
  },
27
27
  "peerDependencies": {
28
- "@aventara/mcp": "1.0.0-rc.4",
28
+ "@aventara/mcp": "1.0.0-rc.9",
29
29
  "@nestjs/common": "^12.0.0",
30
30
  "@nestjs/core": "^12.0.0"
31
31
  },
@@ -34,13 +34,25 @@
34
34
  "optional": true
35
35
  }
36
36
  },
37
+ "aventara": {
38
+ "host": {
39
+ "alias": "nest",
40
+ "label": "NestJS",
41
+ "framework": "@nestjs/core",
42
+ "layout": {
43
+ "config": "src/aventara.config",
44
+ "adapter": "src/aventara.adapter",
45
+ "generated": "src/generated/aventara"
46
+ }
47
+ }
48
+ },
37
49
  "publishConfig": {
38
50
  "access": "public"
39
51
  },
40
52
  "devDependencies": {
41
- "@aventara/mcp": "1.0.0-rc.4",
42
- "@aventara/prisma7-adapter": "1.0.0-rc.4",
43
- "@aventara/testing": "1.0.0-rc.4",
53
+ "@aventara/mcp": "1.0.0-rc.9",
54
+ "@aventara/prisma7-adapter": "1.0.0-rc.9",
55
+ "@aventara/testing": "1.0.0-rc.9",
44
56
  "@modelcontextprotocol/sdk": "1.30.1",
45
57
  "@nestjs/common": "^12.1.2",
46
58
  "@nestjs/core": "^12.1.2",