@aventara/nest 1.0.0-rc.1 → 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,151 @@
1
1
  # @aventara/nest
2
2
 
3
+ ## 1.0.0-rc.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 04bb39a: `engines.node` is now `^22.23.4 || >=24.22.1`, the Node security releases of 2026-10-20 (CVE-2026-105481,
8
+ CVE-2026-105482, CVE-2026-105483, CVE-2026-106069, CVE-2026-106072, CVE-2026-106073, CVE-2026-106074,
9
+ CVE-2026-111497). The bins refuse an older Node in one sentence naming that range.
10
+ - 587dd01: `AventaraModule` mounts `POST {api}/_access/can` on Express and Fastify when the Framework is built with `access`,
11
+ answered by `AvProtocol.bind(framework).handleCan` with the request's state seeded as on every other protocol route. The internal-failure log line names a `can`
12
+ request's failure by its question (`A3000 on access question 2 (orders update) …`) or as `the access questions`.
13
+ - Updated dependencies [587dd01]
14
+ - Updated dependencies [d7e7369]
15
+ - Updated dependencies [7ee547b]
16
+ - Updated dependencies [f52c499]
17
+ - Updated dependencies [2907484]
18
+ - Updated dependencies [a6bbdf0]
19
+ - Updated dependencies [3e26549]
20
+ - Updated dependencies [a6bbdf0]
21
+ - Updated dependencies [6f3f6f6]
22
+ - Updated dependencies [04bb39a]
23
+ - Updated dependencies [d7e7369]
24
+ - Updated dependencies [3fb3333]
25
+ - Updated dependencies [827ccb6]
26
+ - Updated dependencies [7f5abc3]
27
+ - Updated dependencies [88263a1]
28
+ - Updated dependencies [10341d5]
29
+ - Updated dependencies [8129844]
30
+ - Updated dependencies [88263a1]
31
+ - Updated dependencies [3020b5c]
32
+ - Updated dependencies [88263a1]
33
+ - Updated dependencies [88263a1]
34
+ - @aventara/core@1.0.0-rc.10
35
+ - @aventara/mcp@1.0.0-rc.10
36
+
37
+ ## 1.0.0-rc.9
38
+
39
+ ### Patch Changes
40
+
41
+ - 8c40b81: `@aventara/nest` declares a NestJS project's layout in its manifest (`"aventara": { "host": … }`).
42
+ `aventara new` and `aventara init`, which now also scaffold Next.js apps, and `aventara-build` read a NestJS project's
43
+ paths from it, so the three always agree. A NestJS project is scaffolded exactly as before.
44
+ - 205a379: `AventaraModule` hosts a Framework built with `access` (an access provider, from `@aventara/core`): each protocol
45
+ request's `ctx.$state` is seeded by the provider's `state`, called with `{ headers, request }`, the platform
46
+ request's headers as `Headers` and Express's `req` or Fastify's `request`. It works the same through `config`
47
+ (`forRoot({ config: { ...config, access } })`) and `framework`. The module's own `state` option beside `access` is
48
+ refused while Nest builds the application, and is a type error on a `config` that states `access`.
49
+ - Updated dependencies [205a379]
50
+ - Updated dependencies [a0bb05e]
51
+ - Updated dependencies [86ab319]
52
+ - Updated dependencies [fdf52e6]
53
+ - @aventara/core@1.0.0-rc.9
54
+ - @aventara/mcp@1.0.0-rc.9
55
+
56
+ ## 1.0.0-rc.8
57
+
58
+ 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.
59
+
60
+ ### Patch Changes
61
+
62
+ - Updated dependencies [1c8e4ee]
63
+ - @aventara/core@1.0.0-rc.8
64
+ - @aventara/mcp@1.0.0-rc.8
65
+
66
+ ## 1.0.0-rc.7
67
+
68
+ 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.
69
+
70
+ ### Patch Changes
71
+
72
+ - Updated dependencies [f917c1c]
73
+ - @aventara/core@1.0.0-rc.7
74
+ - @aventara/mcp@1.0.0-rc.7
75
+
76
+ ## 1.0.0-rc.6
77
+
78
+ 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.
79
+
80
+ ### Patch Changes
81
+
82
+ - Updated dependencies [1cf72e0]
83
+ - @aventara/core@1.0.0-rc.6
84
+ - @aventara/mcp@1.0.0-rc.6
85
+
86
+ ## 1.0.0-rc.5
87
+
88
+ ### Patch Changes
89
+
90
+ - Updated dependencies [4795ff1]
91
+ - Updated dependencies [9e178ca]
92
+ - @aventara/core@1.0.0-rc.5
93
+ - @aventara/mcp@1.0.0-rc.5
94
+
95
+ ## 1.0.0-rc.4
96
+
97
+ ### Patch Changes
98
+
99
+ - Updated dependencies [e3d03a7]
100
+ - Updated dependencies [d10639a]
101
+ - Updated dependencies [f67e68c]
102
+ - Updated dependencies [708556c]
103
+ - Updated dependencies [3a0dfca]
104
+ - Updated dependencies [99169d2]
105
+ - Updated dependencies [0fd2608]
106
+ - Updated dependencies [154e440]
107
+ - Updated dependencies [2fcffdb]
108
+ - @aventara/core@1.0.0-rc.4
109
+ - @aventara/mcp@1.0.0-rc.4
110
+
111
+ ## 1.0.0-rc.3
112
+
113
+ ### Patch Changes
114
+
115
+ - Updated dependencies [b38034d]
116
+ - Updated dependencies [b38034d]
117
+ - Updated dependencies [b38034d]
118
+ - Updated dependencies [b38034d]
119
+ - Updated dependencies [b38034d]
120
+ - Updated dependencies [b38034d]
121
+ - @aventara/core@1.0.0-rc.3
122
+ - @aventara/mcp@1.0.0-rc.3
123
+
124
+ ## 1.0.0-rc.2
125
+
126
+ ### Patch Changes
127
+
128
+ - `AventaraModule.forRoot({ config })` reports a Pick layer that names what its parent hid with the sentence first, as
129
+ `createFramework` does: an inline `client: { exposed: false, exemptions: { resources: { Comment: true } } }` whose
130
+ root hid `Comment` fails at the key with
131
+ `Type 'true' is not assignable to type 'true & (readonly ["Error: client cannot expose 'Comment': hidden by root"] & …)'`.
132
+ - 9366e16: MCP endpoint polish:
133
+
134
+ - A request with no bearer credentials (no `Authorization` header, or another scheme such as `Basic`) is answered
135
+ `401` with `WWW-Authenticate: Bearer resource_metadata="…"` and no error code, as RFC 6750 §3.1 asks; its body no
136
+ longer says "Missing Authorization header". A bad bearer token keeps `error="invalid_token"`.
137
+ - A `mcp.authorization.verify` that throws is still answered `401`, and is now reported to the `diagnostics` sink as
138
+ an `AvMcpDiagnostic` holding the error.
139
+ - With `mcp` configured and `@aventara/mcp` missing, the startup error names the command that installs it at the
140
+ installed `@aventara/core`'s exact version: `npm install --save-exact @aventara/mcp@<version>`.
141
+
142
+ - Updated dependencies [9366e16]
143
+ - Updated dependencies [9366e16]
144
+ - Updated dependencies [9366e16]
145
+ - Updated dependencies [9366e16]
146
+ - @aventara/core@1.0.0-rc.2
147
+ - @aventara/mcp@1.0.0-rc.2
148
+
3
149
  ## 1.0.0-rc.1
4
150
 
5
151
  ### Patch Changes
@@ -65,7 +211,6 @@
65
211
  nullable: false,
66
212
  list: false,
67
213
  lifecycle: ["VIRTUAL"],
68
- format: "url",
69
214
  },
70
215
  pipelines: {
71
216
  compute: {
package/README.md CHANGED
@@ -51,7 +51,7 @@ export async function aventaraConfig(prisma: PrismaService) {
51
51
  const { error } = diagnostic;
52
52
  logger.error(
53
53
  `${diagnostic.code} (request ${diagnostic.requestId}): raw error`,
54
- error instanceof Error ? error.stack : String(error),
54
+ (error instanceof Error && error.stack) || String(error),
55
55
  );
56
56
  },
57
57
  adapter: await createPrismaAdapter({
@@ -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
@@ -229,15 +234,20 @@ const signedIn: AvGuard = (ctx) => ctx.$state.user !== undefined;
229
234
  ## The MCP endpoint
230
235
 
231
236
  With `mcp` in the configuration, the module also mounts the MCP server of `@aventara/mcp` at that path, on Express and
232
- Fastify alike, and logs `Aventara mounted the MCP endpoint at /mcp (…)`. Install it beside this package, at the same
233
- version:
237
+ Fastify alike, and logs `Aventara mounted the MCP endpoint at /mcp (…)`. Install it beside this package, at
238
+ `@aventara/core`'s exact version:
234
239
 
235
240
  ```bash
236
- npm install @aventara/mcp@rc
241
+ npm install --save-exact @aventara/mcp@<your @aventara/core version>
237
242
  ```
238
243
 
239
244
  It is an optional peer dependency: an application without `mcp` does not need it, and one with `mcp` and without the
240
- package refuses to start, naming it. As for the protocol's routes, the module only mounts: the endpoint's body is read
245
+ package refuses to start, naming it and the command, with the version filled in:
246
+
247
+ ```text
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.10), or remove `mcp` from the configuration.
249
+ ```
250
+ As for the protocol's routes, the module only mounts: the endpoint's body is read
241
251
  raw, the request's URL comes from the platform's `protocol` and `host` (set `trust proxy` on Express or `trustProxy` on
242
252
  Fastify behind a proxy), and every answer is `@aventara/mcp`'s. The `state` option seeds each tool call's `ctx.$state`.
243
253
  See `@aventara/mcp`'s README for the tools, the contract resource and authorization.
@@ -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 { accessProviderOf } 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 = accessProviderOf(framework)?.state;
17
+ return state === undefined
18
+ ? undefined
19
+ : (request) => state({ headers: headersOf(request), request });
20
+ }
@@ -5,25 +5,35 @@ 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;
12
13
  readonly config?: never;
13
14
  } | {
14
- readonly config: Cfg & AvConfig<M, Cfg> & AvConfigExact<M, Cfg>;
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],
@@ -25,7 +25,7 @@ type ExpressRequest = NodeIncoming & {
25
25
  type ExpressResponse = NodeOutgoing;
26
26
  /** Express passes `next`; Nest's handler type declares it as an optional `Function`. */
27
27
  type ExpressHandler = (request: ExpressRequest, response: ExpressResponse, next?: unknown) => unknown;
28
- export type ExpressPlatform = {
28
+ type ExpressPlatform = {
29
29
  get(path: string, handler: ExpressHandler): unknown;
30
30
  post(path: string, handler: ExpressHandler): unknown;
31
31
  delete(path: string, handler: ExpressHandler): unknown;
@@ -1,7 +1,9 @@
1
+ import { accessProviderOf } 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
+ ? accessProviderOf(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) {
@@ -17,7 +17,11 @@ export function internalFailureLine(diagnostic) {
17
17
  ? `${diagnostic.resource}.${diagnostic.family}.${diagnostic.variant}`
18
18
  : diagnostic.kind === "transaction"
19
19
  ? "a transaction"
20
- : "the MCP endpoint";
20
+ : diagnostic.kind === "can"
21
+ ? diagnostic.question === undefined
22
+ ? "the access questions"
23
+ : `access question ${diagnostic.question} (${diagnostic.resource} ${diagnostic.action})`
24
+ : "the MCP endpoint";
21
25
  const step = diagnostic.operation === undefined
22
26
  ? ""
23
27
  : `, plan operation ${diagnostic.operation}`;
@@ -1,5 +1,19 @@
1
1
  const MCP_PACKAGE = "@aventara/mcp";
2
- const missing = (specifier) => `AventaraModule: the configuration has \`mcp\`, and the package that serves it, ${specifier}, is not installed. Install it beside @aventara/nest, at the same version (npm install ${specifier}), or remove \`mcp\` from the configuration.`;
2
+ const missing = (specifier, coreVersion) => `AventaraModule: the configuration has \`mcp\`, and the package that serves it, ${specifier}, is not installed. Install it at @aventara/core's exact version (npm install --save-exact ${specifier}@${coreVersion ?? "<your @aventara/core version>"}), or remove \`mcp\` from the configuration.`;
3
+ async function installedCoreVersion() {
4
+ try {
5
+ const manifest = new URL("../package.json", import.meta.resolve("@aventara/core"));
6
+ const { default: read } = (await import(manifest.href, {
7
+ with: { type: "json" },
8
+ }));
9
+ return read.name === "@aventara/core" && typeof read.version === "string"
10
+ ? read.version
11
+ : undefined;
12
+ }
13
+ catch {
14
+ return undefined;
15
+ }
16
+ }
3
17
  function isMissing(error, specifier) {
4
18
  const { code, message } = (error ?? {});
5
19
  return ((code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") &&
@@ -16,7 +30,7 @@ export async function loadMcpBinding(framework, specifier = MCP_PACKAGE) {
16
30
  }
17
31
  catch (error) {
18
32
  if (isMissing(error, specifier)) {
19
- throw new Error(missing(specifier));
33
+ throw new Error(missing(specifier, await installedCoreVersion()));
20
34
  }
21
35
  throw error;
22
36
  }
@@ -1,41 +1,19 @@
1
1
  import type { AvFramework, AvState } from "@aventara/core";
2
2
  import type { AbstractHttpAdapter } from "@nestjs/core";
3
- import type { McpBinding, McpRoute } from "./mcp-binding.loader.js";
4
- import type { SurfaceRoute } from "./protocol-route.table.js";
3
+ import type { McpBinding } from "./mcp-binding.loader.js";
5
4
  /** The developer's `state` option: seeds a request's `ctx.$state` from its platform request. */
6
5
  export type HostState = (request: unknown) => AvState | Promise<AvState>;
7
6
  /** The protocol, bound once at startup, and the one call that mounts it. */
8
7
  export type ProtocolHost = {
9
8
  readonly mount: () => void;
10
9
  };
11
- /**
12
- * Binds `framework`'s protocol for the application's platform, refusing an
13
- * unsupported platform while providers are instantiated, so `NestFactory.create`
14
- * rejects before the application listens. The routes are mounted later, from
15
- * the module's `configure()`.
16
- */
17
- export declare function createProtocolHost(adapter: AbstractHttpAdapter | undefined, framework: AvFramework, state?: HostState, mcp?: McpBinding): ProtocolHost;
18
- /**
19
- * What the MCP mount registered: the endpoint, and its OAuth metadata route
20
- * or, without one, the rule an open endpoint answers by — e.g. `Aventara
21
- * mounted the MCP endpoint at /mcp (+ GET
22
- * /.well-known/oauth-protected-resource/mcp)`.
23
- */
24
- export declare function mcpMountedLine(routes: readonly McpRoute[]): string;
25
- /**
26
- * What one mount registered, read off `protocol.surface()`: the operation
27
- * count under the entrypoint, then each framework route by method and path —
28
- * e.g. `Aventara mounted 5 operations at /api (+ GET /api/_contract, POST
29
- * /api/_transactions)`.
30
- */
31
- export declare function mountedLine(routes: readonly SurfaceRoute[], entrypoint: string): string;
32
10
  /** What `AventaraModule` holds: a host, perhaps waiting for its platform, and the check that it has one. */
33
11
  export type PendingProtocolHost = ProtocolHost & {
34
12
  /** Throws when no platform arrived, or the one that did is refused. */
35
13
  readonly assertReady: () => void;
36
14
  };
37
15
  /** The parts of Nest's `HttpAdapterHost` the module reads. */
38
- export type AdapterHostView = {
16
+ type AdapterHostView = {
39
17
  readonly httpAdapter: AbstractHttpAdapter | undefined;
40
18
  readonly init$: {
41
19
  subscribe(next: () => void): unknown;
@@ -46,3 +24,4 @@ export type AdapterHostView = {
46
24
  * are instantiated (Nest's testing module).
47
25
  */
48
26
  export declare function createPendingProtocolHost(application: AdapterHostView, framework: AvFramework, state?: HostState, mcp?: McpBinding): PendingProtocolHost;
27
+ export {};
@@ -12,7 +12,7 @@ const PLATFORM_MOUNTERS = {
12
12
  }, binding, entrypoint, maxRequestBytes, state, mcp),
13
13
  fastify: (adapter, binding, entrypoint, maxRequestBytes, state, mcp) => createFastifyProtocolHost(adapter.getInstance(), binding, entrypoint, maxRequestBytes, state, mcp),
14
14
  };
15
- export function createProtocolHost(adapter, framework, state, mcp) {
15
+ function createProtocolHost(adapter, framework, state, mcp) {
16
16
  const platform = checkedPlatform(adapter?.getType());
17
17
  const binding = AvProtocol.bind(framework);
18
18
  const host = PLATFORM_MOUNTERS[platform](adapter, binding, framework.api, framework.contracts.client.limits.maxRequestBytes, state, mcp);
@@ -26,7 +26,7 @@ export function createProtocolHost(adapter, framework, state, mcp) {
26
26
  },
27
27
  };
28
28
  }
29
- export function mcpMountedLine(routes) {
29
+ function mcpMountedLine(routes) {
30
30
  const endpoint = routes.find((route) => route.kind === "endpoint");
31
31
  const metadata = routes.find((route) => route.kind === "metadata");
32
32
  return `Aventara mounted the MCP endpoint at ${endpoint?.path ?? "/"} (${metadata === undefined
@@ -34,7 +34,7 @@ export function mcpMountedLine(routes) {
34
34
  : `+ GET ${metadata.path}`})`;
35
35
  }
36
36
  const MOUNT_LOGGER = new Logger("AventaraModule");
37
- export function mountedLine(routes, entrypoint) {
37
+ function mountedLine(routes, entrypoint) {
38
38
  const operations = routes.filter((route) => route.kind === "operation");
39
39
  const framework = routes
40
40
  .filter((route) => route.kind !== "operation")
@@ -4,7 +4,7 @@ import type { McpBinding, McpRequest, McpRoute } from "./mcp-binding.loader.js";
4
4
  /** One route `protocol.surface()` lists. */
5
5
  export type SurfaceRoute = ReturnType<AvProtocolBinding["surface"]>[number];
6
6
  /** The developer's `state` option over one platform request: seeds its `ctx.$state`. */
7
- export type StateSeed = () => AvState | Promise<AvState>;
7
+ type StateSeed = () => AvState | Promise<AvState>;
8
8
  /** What a mounted route answers its request with: a bound protocol member. */
9
9
  export type RouteAnswer = (request: AvProtocolRequest, state: StateSeed | undefined) => AvProtocolResponse | Promise<AvProtocolResponse>;
10
10
  /** The bound member each kind of surface route is answered by. */
@@ -13,8 +13,9 @@ export type ProtocolRouteTable = {
13
13
  };
14
14
  export declare const PROTOCOL_ROUTES: ProtocolRouteTable;
15
15
  /** What a mounted MCP route answers its request with: a bound `@aventara/mcp` member. */
16
- export type McpRouteAnswer = (request: McpRequest, state: StateSeed | undefined) => AvProtocolResponse | Promise<AvProtocolResponse>;
16
+ type McpRouteAnswer = (request: McpRequest, state: StateSeed | undefined) => AvProtocolResponse | Promise<AvProtocolResponse>;
17
17
  /** The bound `@aventara/mcp` member each kind of MCP route is answered by. */
18
18
  export declare const MCP_ROUTES: {
19
19
  readonly [K in McpRoute["kind"]]: (binding: McpBinding) => McpRouteAnswer;
20
20
  };
21
+ export {};
@@ -2,6 +2,7 @@ export const PROTOCOL_ROUTES = {
2
2
  operation: (binding) => (request, state) => binding.handleOperation(request, state === undefined ? {} : { state }),
3
3
  contract: (binding) => (request) => binding.encodeContract(request),
4
4
  transactions: (binding) => (request, state) => binding.handleTransaction(request, state === undefined ? {} : { state }),
5
+ can: (binding) => (request, state) => binding.handleCan(request, state === undefined ? {} : { state }),
5
6
  };
6
7
  export const MCP_ROUTES = {
7
8
  endpoint: (binding) => (request, state) => binding.handleEndpoint(request, state === undefined ? {} : { state }),
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@aventara/nest",
3
- "version": "1.0.0-rc.1",
3
+ "version": "1.0.0-rc.10",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "NestJS host integration for Aventara.",
6
6
  "type": "module",
7
7
  "engines": {
8
- "node": "^22.18.0 || >=24.2.0"
8
+ "node": "^22.23.4 || >=24.22.1"
9
9
  },
10
10
  "main": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts",
@@ -22,10 +22,10 @@
22
22
  "CHANGELOG.md"
23
23
  ],
24
24
  "dependencies": {
25
- "@aventara/core": "1.0.0-rc.1"
25
+ "@aventara/core": "1.0.0-rc.10"
26
26
  },
27
27
  "peerDependencies": {
28
- "@aventara/mcp": "1.0.0-rc.1",
28
+ "@aventara/mcp": "1.0.0-rc.10",
29
29
  "@nestjs/common": "^12.0.0",
30
30
  "@nestjs/core": "^12.0.0"
31
31
  },
@@ -34,21 +34,33 @@
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.1",
42
- "@aventara/prisma7-adapter": "1.0.0-rc.1",
43
- "@aventara/testing": "1.0.0-rc.1",
44
- "@modelcontextprotocol/sdk": "1.30.1",
45
- "@nestjs/common": "^12.1.2",
46
- "@nestjs/core": "^12.1.2",
47
- "@nestjs/platform-express": "^12.1.2",
48
- "@nestjs/platform-fastify": "^12.1.2",
49
- "@nestjs/testing": "^12.1.2",
50
- "@prisma/adapter-better-sqlite3": "7.10.0",
51
- "@prisma/adapter-pg": "7.10.0",
53
+ "@aventara/mcp": "1.0.0-rc.10",
54
+ "@aventara/prisma7-adapter": "1.0.0-rc.10",
55
+ "@aventara/testing": "1.0.0-rc.10",
56
+ "@modelcontextprotocol/sdk": "1.32.2",
57
+ "@nestjs/common": "^12.2.0",
58
+ "@nestjs/core": "^12.2.0",
59
+ "@nestjs/platform-express": "^12.2.0",
60
+ "@nestjs/platform-fastify": "^12.2.0",
61
+ "@nestjs/testing": "^12.2.0",
62
+ "@prisma/adapter-better-sqlite3": "7.10.1",
63
+ "@prisma/adapter-pg": "7.10.1",
52
64
  "reflect-metadata": "^0.2.2",
53
65
  "rxjs": "^7.8.2"
54
66
  },