@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 +58 -0
- package/README.md +6 -1
- package/dist/access-state.translator.d.ts +7 -0
- package/dist/access-state.translator.js +20 -0
- package/dist/aventara.module.d.ts +14 -3
- package/dist/aventara.module.js +2 -1
- package/dist/host-bootstrap.validator.js +9 -0
- package/package.json +18 -6
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.
|
|
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 {};
|
package/dist/aventara.module.js
CHANGED
|
@@ -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.
|
|
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.
|
|
25
|
+
"@aventara/core": "1.0.0-rc.9"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@aventara/mcp": "1.0.0-rc.
|
|
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.
|
|
42
|
-
"@aventara/prisma7-adapter": "1.0.0-rc.
|
|
43
|
-
"@aventara/testing": "1.0.0-rc.
|
|
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",
|