@aventara/nest 0.1.0-pilot.3 → 1.0.0-rc.0
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 +150 -0
- package/README.md +2 -2
- package/dist/aventara.module.d.ts +23 -18
- package/dist/express-protocol.mounter.d.ts +4 -15
- package/dist/fastify-protocol.mounter.d.ts +7 -27
- package/dist/framework.token.d.ts +3 -5
- package/dist/internal-failure.logger.d.ts +1 -1
- package/dist/internal-failure.logger.js +1 -1
- package/dist/node-exchange.translator.d.ts +5 -8
- package/dist/protocol-host.factory.d.ts +5 -12
- package/dist/protocol-route.table.d.ts +2 -10
- package/dist/request-body.reader.d.ts +5 -18
- package/package.json +7 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @aventara/nest
|
|
2
|
+
|
|
3
|
+
## 1.0.0-rc.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- First release candidate of Aventara 1.0. The public API is now considered stable; changes before 1.0.0 are possible
|
|
8
|
+
based on feedback.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- 24ffbab: Each package ships its `CHANGELOG.md`, so the release notes are in the installed package beside the README.
|
|
13
|
+
- 24ffbab: **Behaviour changes:** Pipelines and guards read where a request came from as `request.origin` (was `request.scope`).
|
|
14
|
+
The same property is renamed everywhere it means `"application"` or `"client"`: the pipeline context
|
|
15
|
+
(`context.origin`), the request objects `framework.execute` and `framework.executeTransaction` take
|
|
16
|
+
(`{ origin: "client", … }`), the context a computed field's behaviour receives, and every diagnostic the diagnostics
|
|
17
|
+
sink receives. There is no `scope` alias: replace `scope` with `origin` in those places. Nothing sent over HTTP
|
|
18
|
+
changes.
|
|
19
|
+
|
|
20
|
+
The Nest host's log line for an internal failure now reads `(client origin, request …)` instead of
|
|
21
|
+
`(client scope, request …)`.
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [24ffbab]
|
|
24
|
+
- Updated dependencies [24ffbab]
|
|
25
|
+
- Updated dependencies [24ffbab]
|
|
26
|
+
- Updated dependencies [24ffbab]
|
|
27
|
+
- Updated dependencies [24ffbab]
|
|
28
|
+
- Updated dependencies [24ffbab]
|
|
29
|
+
- Updated dependencies [24ffbab]
|
|
30
|
+
- Updated dependencies [24ffbab]
|
|
31
|
+
- Updated dependencies [24ffbab]
|
|
32
|
+
- Updated dependencies [24ffbab]
|
|
33
|
+
- Updated dependencies [24ffbab]
|
|
34
|
+
- Updated dependencies [24ffbab]
|
|
35
|
+
- Updated dependencies [a973e89]
|
|
36
|
+
- Updated dependencies [1e65e9a]
|
|
37
|
+
- Updated dependencies
|
|
38
|
+
- Updated dependencies [a973e89]
|
|
39
|
+
- Updated dependencies [a973e89]
|
|
40
|
+
- Updated dependencies [1e65e9a]
|
|
41
|
+
- Updated dependencies [1e65e9a]
|
|
42
|
+
- Updated dependencies [24ffbab]
|
|
43
|
+
- Updated dependencies [2d00ad7]
|
|
44
|
+
- Updated dependencies [384a50c]
|
|
45
|
+
- Updated dependencies [d43d1cc]
|
|
46
|
+
- Updated dependencies [3f98749]
|
|
47
|
+
- Updated dependencies [032f792]
|
|
48
|
+
- Updated dependencies [dbe6961]
|
|
49
|
+
- @aventara/core@1.0.0-rc.0
|
|
50
|
+
|
|
51
|
+
## 0.1.0-pilot.4
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- f37dcd6: The documentation shipped with the package — the comments an editor shows on hover, and the README — now describes
|
|
56
|
+
what each export does, how to use it, what it returns and what it throws. Notes about how the package was built and
|
|
57
|
+
why are no longer part of what is published.
|
|
58
|
+
- Updated dependencies [f37dcd6]
|
|
59
|
+
- @aventara/core@0.1.0-pilot.4
|
|
60
|
+
|
|
61
|
+
## 0.1.0-pilot.3
|
|
62
|
+
|
|
63
|
+
### Patch Changes
|
|
64
|
+
|
|
65
|
+
- @aventara/core@0.1.0-pilot.3
|
|
66
|
+
|
|
67
|
+
## 0.1.0-pilot.2
|
|
68
|
+
|
|
69
|
+
### Patch Changes
|
|
70
|
+
|
|
71
|
+
- 5535994: Internal failures are visible in the host's log: when `AventaraModule` builds the framework from `config`, every
|
|
72
|
+
`A3000`–`A3003` writes one error line through Nest's `Logger` (context `Aventara`) with the code, the operation, the
|
|
73
|
+
scope, the request id and the thrown value's class name — never the error's message. A configured `diagnostics` sink
|
|
74
|
+
still receives the raw error.
|
|
75
|
+
- e69e88d: The published packages are written for the people who use them. The JavaScript ships without comments; the type
|
|
76
|
+
declarations keep their documentation, and it, the error messages, the protocol fixtures' labels and the comments in a
|
|
77
|
+
generated client no longer carry the project's internal development notes.
|
|
78
|
+
- ab58424: A pipe's output is checked against the server's own rules before it reaches the adapter. The request is validated
|
|
79
|
+
against the caller's Contract; after each pipe, the arguments are validated against the Core Contract (plus fields the
|
|
80
|
+
caller's scope adds), so a pipe may still write what the caller cannot — a field the client Contract hides, such as a
|
|
81
|
+
password hash — but not what the server cannot store. A refusal is the new internal code `A3004 PIPE_OUTPUT_INVALID` (HTTP
|
|
82
|
+
500). The caller receives only the generic `A server pipeline produced invalid arguments.`, like every internal
|
|
83
|
+
failure; the pipe (`pipes[i]` and its function name), the operation, the offending field and its V-code go to the
|
|
84
|
+
diagnostics sink as a `PipeOutputError`, and `@aventara/nest` writes them into its error log line. Nothing reaches the
|
|
85
|
+
adapter. This holds for operations and transaction steps alike (a plan answers with `cause.operation`). Generated
|
|
86
|
+
clients map `A3004` to `InternalError`; the protocol fixtures in `@aventara/testing` include an `A3004` row.
|
|
87
|
+
- Updated dependencies [c2a3b7c]
|
|
88
|
+
- Updated dependencies [e69e88d]
|
|
89
|
+
- Updated dependencies [ab58424]
|
|
90
|
+
- Updated dependencies [23937f8]
|
|
91
|
+
- @aventara/core@0.1.0-pilot.2
|
|
92
|
+
|
|
93
|
+
## 0.1.0-pilot.1
|
|
94
|
+
|
|
95
|
+
### Patch Changes
|
|
96
|
+
|
|
97
|
+
- 1c45eb7: Startup says what Aventara mounted. Its routes are platform routes, which Nest's `RouterExplorer` never lists, so a
|
|
98
|
+
started server showed no sign of them. On mount, the module now logs one line through Nest's `Logger` (context
|
|
99
|
+
`AventaraModule`), read off `protocol.surface()`: `Aventara mounted 10 operations at /api (+ GET /api/_contract, POST
|
|
100
|
+
/api/_transactions)`. The application's logger settings govern it.
|
|
101
|
+
- 799346e: The package READMEs (each package's npm page) are rewritten for the people who use the packages. The Prisma 7
|
|
102
|
+
adapter's README now states the actual behaviour of a to-many relation or `$count` projected on
|
|
103
|
+
`update.many`/`create.many`: a validation refusal, `A2004` with `V1008`, before any statement runs (it said `A3001`).
|
|
104
|
+
Every install or run command names the `@pilot` dist-tag.
|
|
105
|
+
- e58aebf: The READMEs show how to call the API by hand: a copy-pasteable `curl` that fetches `/api/_contract` and sends a
|
|
106
|
+
`find.many` with both identity headers, and runs as printed against a scaffolded server. They also say that
|
|
107
|
+
Resource keys are the model names as written (`/_resources/User/…`, `avClient.User.find.many`), and that list results are
|
|
108
|
+
`readonly` arrays (`readonly User[]`).
|
|
109
|
+
- Updated dependencies [a45f8a8]
|
|
110
|
+
- Updated dependencies [799346e]
|
|
111
|
+
- @aventara/core@0.1.0-pilot.1
|
|
112
|
+
|
|
113
|
+
## 0.1.0-pilot.0
|
|
114
|
+
|
|
115
|
+
### Minor Changes
|
|
116
|
+
|
|
117
|
+
- First pilot release of `@aventara/nest`: it hosts an Aventara Framework in a NestJS 12 application (peers
|
|
118
|
+
`@nestjs/common` and `@nestjs/core` `^12.0.0`). It exports `AventaraModule`, `AVENTARA_FRAMEWORK`, `InjectFramework`
|
|
119
|
+
and the types `AventaraModuleOptions` / `AventaraModuleAsyncOptions`.
|
|
120
|
+
|
|
121
|
+
- **Mounting.** `AventaraModule.forRoot({ framework })` uses your own instance; `forRoot({ config })` calls
|
|
122
|
+
`createFramework(config)` itself; `forRootAsync({ imports, inject, useFactory })` resolves either. Both forms are
|
|
123
|
+
generic like `createFramework`, so a configuration is checked against its adapter's model. The module is global;
|
|
124
|
+
inject the Framework with `@InjectFramework()`. A configuration error rejects `NestFactory.create` before the
|
|
125
|
+
application listens, and passing both `framework` and `config`, neither, a value that is not a Framework, or
|
|
126
|
+
mounting the module twice is refused with a fixed message.
|
|
127
|
+
- **Routes.** One platform route per route the protocol advertises — every operation, `GET /_contract`, and
|
|
128
|
+
`POST /_transactions` when transactions are interactive — at its literal path under `FrameworkConfig.entrypoint`
|
|
129
|
+
(a Nest global prefix does not move it), on Express and on Fastify. Any other path under the entrypoint's `/_`
|
|
130
|
+
namespace gets the protocol's own answer; every other path goes on to Nest.
|
|
131
|
+
- **What runs on them.** Nest's guards, interceptors and pipes do not; `app.use` middleware and `enableCors()` do.
|
|
132
|
+
`MiddlewareConsumer` middleware does not run on them on Express, and does on Fastify — exclude `<entrypoint>/_*`
|
|
133
|
+
(for example `.exclude("api/_*path")`) to keep it off. A throw while translating a request reaches your exception
|
|
134
|
+
filter.
|
|
135
|
+
- **Request bodies.** Read raw and bounded by the contract's `limits.maxRequestBytes`; `gzip`, `deflate` and `br` are
|
|
136
|
+
decoded and the limit counts decoded bytes (`413 A2010`); any other coding answers `415 A2011`, and a body that does
|
|
137
|
+
not decode in the coding it names answers `400 A2000`. Nothing is executed in either case. Your own routes keep Nest's
|
|
138
|
+
parsed `req.body`.
|
|
139
|
+
- **Platform differences.** On Fastify, Resource keys or an entrypoint holding `*` or a reserved character
|
|
140
|
+
(`: + # $ & , / ; = ? @`) are refused at startup, naming them — rename them, or host on Express. Express answers a
|
|
141
|
+
non-canonical percent-encoding of a protocol route with `500 A3000`, and matches the entrypoint in any case by
|
|
142
|
+
default.
|
|
143
|
+
- Works under Nest's testing module (`Test.createTestingModule(…).compile()` then `createNestApplication()`), and every
|
|
144
|
+
export has a `default` condition, so a CommonJS NestJS project can `require()` it. The README covers the ways to
|
|
145
|
+
mount the module, typed injection, what fails before listen, and the platform differences.
|
|
146
|
+
|
|
147
|
+
### Patch Changes
|
|
148
|
+
|
|
149
|
+
- Updated dependencies
|
|
150
|
+
- @aventara/core@0.1.0-pilot.0
|
package/README.md
CHANGED
|
@@ -127,12 +127,12 @@ own when it mounts them, through Nest's `Logger` (context `AventaraModule`; `log
|
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
An internal failure (`A3000`–`A3004`, answered as a 500) is logged as one error line through Nest's `Logger`
|
|
130
|
-
(context `Aventara`): the code, the operation, the
|
|
130
|
+
(context `Aventara`): the code, the operation, the origin and the request id, and the thrown value's class name — never
|
|
131
131
|
its message, which can hold SQL or a connection string. The raw error still goes to your `diagnostics` sink, when you
|
|
132
132
|
configure one:
|
|
133
133
|
|
|
134
134
|
```text
|
|
135
|
-
[Nest] ERROR [Aventara] A3001 on Post.create.one (client
|
|
135
|
+
[Nest] ERROR [Aventara] A3001 on Post.create.one (client origin, request 3f1c…): PrismaClientValidationError. The raw error goes to the framework's diagnostics sink.
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
For `A3004` — one of your pipes returned arguments the server contract refuses — the line also names the pipe, the
|
|
@@ -2,16 +2,9 @@ import { type AdapterModel, type AnyFrameworkConfig, type Framework, type Framew
|
|
|
2
2
|
import { type DynamicModule, type FactoryProvider, type ModuleMetadata, type NestModule, type OnModuleInit } from "@nestjs/common";
|
|
3
3
|
import { type PendingProtocolHost } from "./protocol-host.factory.js";
|
|
4
4
|
/**
|
|
5
|
-
* How the application's Framework enters Nest:
|
|
6
|
-
*
|
|
7
|
-
* `createFramework` itself
|
|
8
|
-
* type error.
|
|
9
|
-
*
|
|
10
|
-
* The `config` arm is typed exactly as `createFramework`'s parameter, so a
|
|
11
|
-
* configuration annotated `FrameworkConfig<M>`, written inline, inferred or
|
|
12
|
-
* checked with `satisfies` is accepted — and checked against its own Adapter model
|
|
13
|
-
* — wherever `createFramework` would accept it. The defaults are the untyped
|
|
14
|
-
* forms.
|
|
5
|
+
* How the application's Framework enters Nest: your own instance
|
|
6
|
+
* (`{ framework }`, from `createFramework`) or a configuration the module
|
|
7
|
+
* passes to `createFramework` itself (`{ config }`). Pass exactly one.
|
|
15
8
|
*/
|
|
16
9
|
export type AventaraModuleOptions<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig> = {
|
|
17
10
|
readonly framework: Framework;
|
|
@@ -21,28 +14,40 @@ export type AventaraModuleOptions<M extends AdapterModel = AdapterModel, Cfg = A
|
|
|
21
14
|
readonly framework?: never;
|
|
22
15
|
};
|
|
23
16
|
/**
|
|
24
|
-
* `forRootAsync`'s options: the Nest idiom when what builds the Framework
|
|
25
|
-
* Prisma client, a configuration service) is itself a provider. The
|
|
26
|
-
* resolves to either arm of {@link AventaraModuleOptions}.
|
|
17
|
+
* `forRootAsync`'s options: the Nest idiom when what builds the Framework
|
|
18
|
+
* (a Prisma client, a configuration service) is itself a provider. The
|
|
19
|
+
* factory resolves to either arm of {@link AventaraModuleOptions}.
|
|
27
20
|
*/
|
|
28
21
|
export type AventaraModuleAsyncOptions<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig> = {
|
|
22
|
+
/** Modules whose providers the factory injects. */
|
|
29
23
|
readonly imports?: ModuleMetadata["imports"];
|
|
24
|
+
/** The providers passed to `useFactory`, in order. */
|
|
30
25
|
readonly inject?: FactoryProvider["inject"];
|
|
26
|
+
/** Returns the module options: `{ framework }` or `{ config }`. */
|
|
31
27
|
readonly useFactory: (...deps: never[]) => AventaraModuleOptions<M, Cfg> | Promise<AventaraModuleOptions<M, Cfg>>;
|
|
32
28
|
};
|
|
33
29
|
/**
|
|
34
|
-
* The global module that hosts one Aventara Framework
|
|
35
|
-
* the application's platform
|
|
36
|
-
* `
|
|
37
|
-
*
|
|
30
|
+
* The global module that hosts one Aventara Framework and mounts its protocol
|
|
31
|
+
* on the application's platform: after your `app.use` / `enableCors`, before
|
|
32
|
+
* `MiddlewareConsumer` middleware and every controller, so the reserved `_`
|
|
33
|
+
* namespace cannot be shadowed.
|
|
38
34
|
*/
|
|
39
35
|
export declare class AventaraModule implements NestModule, OnModuleInit {
|
|
40
36
|
private readonly host;
|
|
41
37
|
constructor(host: PendingProtocolHost);
|
|
38
|
+
/** Mounts the protocol routes on the HTTP platform. */
|
|
42
39
|
configure(): void;
|
|
43
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Refuses to start in a Nest application context with no HTTP platform, where
|
|
42
|
+
* the protocol cannot be mounted.
|
|
43
|
+
*/
|
|
44
44
|
onModuleInit(): void;
|
|
45
|
+
/** Registers the module with a Framework instance or a configuration. */
|
|
45
46
|
static forRoot<M extends AdapterModel, const Cfg = AnyFrameworkConfig>(options: AventaraModuleOptions<M, Cfg>): DynamicModule;
|
|
47
|
+
/**
|
|
48
|
+
* Registers the module with options built by a factory, for when the
|
|
49
|
+
* Framework's inputs (a Prisma client, a config service) are providers.
|
|
50
|
+
*/
|
|
46
51
|
static forRootAsync<M extends AdapterModel, const Cfg = AnyFrameworkConfig>(options: AventaraModuleAsyncOptions<M, Cfg>): DynamicModule;
|
|
47
52
|
private static mount;
|
|
48
53
|
}
|
|
@@ -2,21 +2,10 @@ import type { AvProtocolBinding } from "@aventara/core/protocol";
|
|
|
2
2
|
import { type NodeIncoming, type NodeOutgoing } from "./node-exchange.translator.js";
|
|
3
3
|
import type { ProtocolHost } from "./protocol-host.factory.js";
|
|
4
4
|
/**
|
|
5
|
-
* The protocol on Nest's Express platform
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* raw, bounded and decoded, and kept for its route. Its stream is then finished,
|
|
10
|
-
* so Nest's parsers skip it; every other request keeps Nest's parsed body. It
|
|
11
|
-
* reads; it answers nothing.
|
|
12
|
-
* - **The routes**, mounted from the module's `configure()`: one platform route
|
|
13
|
-
* per `protocol.surface()` entry, each at its escaped literal path under the
|
|
14
|
-
* entrypoint, then one fallback — `protocol.answerAbsent`, the absence handler,
|
|
15
|
-
* not a catch-all: it executes nothing, and a path it does not own (`undefined`)
|
|
16
|
-
* goes on to Nest.
|
|
17
|
-
*
|
|
18
|
-
* Its whole job is translation: the Express request into an `AvProtocolRequest`,
|
|
19
|
-
* the `AvProtocolResponse` back onto the wire.
|
|
5
|
+
* The protocol on Nest's Express platform: one platform route per protocol
|
|
6
|
+
* route under the entrypoint, translating the Express request into the
|
|
7
|
+
* protocol's request and the protocol's response back onto the wire. A path the
|
|
8
|
+
* protocol does not own goes on to Nest.
|
|
20
9
|
*/
|
|
21
10
|
/** Express's request: Node's `IncomingMessage`, plus `originalUrl`. */
|
|
22
11
|
type ExpressRequest = NodeIncoming & {
|
|
@@ -2,33 +2,13 @@ import type { AvProtocolBinding } from "@aventara/core/protocol";
|
|
|
2
2
|
import { type NodeIncoming, type NodeOutgoing, type PlatformHeaders } from "./node-exchange.translator.js";
|
|
3
3
|
import type { ProtocolHost } from "./protocol-host.factory.js";
|
|
4
4
|
/**
|
|
5
|
-
* The protocol on Nest's Fastify platform
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* step, before its content-type check and body parsing: the body is read raw off
|
|
13
|
-
* Node's request by the bounded reader, the bound member answers, and the reply
|
|
14
|
-
* is hijacked. Fastify's parsers, `bodyLimit` and early `415` (on a
|
|
15
|
-
* `Content-Type` it cannot parse) never run on a protocol route, so every body
|
|
16
|
-
* failure is the protocol's own answer, as on Express. The route handler is
|
|
17
|
-
* never reached.
|
|
18
|
-
* - **The absence fallback** is a root `onRequest` hook acting only on a request
|
|
19
|
-
* Fastify matched to no route (`request.is404`) under `<entrypoint>/`:
|
|
20
|
-
* `protocol.answerAbsent`, and `undefined` hands the request on to Nest's own
|
|
21
|
-
* not-found handler. A not-found handler of our own could not hand back: inside
|
|
22
|
-
* one, Fastify answers its plain-text 404, not Nest's.
|
|
23
|
-
* - **Literal paths**: each route is registered `decodeURI`-ed, as find-my-way
|
|
24
|
-
* decodes a request path before matching it (`café`, `a[b]`). A path find-my-way
|
|
25
|
-
* cannot match as a literal — a `*` (its wildcard) or a reserved escape (it
|
|
26
|
-
* keeps those encoded, and never matches them against a static route) — is
|
|
27
|
-
* refused while Nest builds the application, naming the Resource keys; Express
|
|
28
|
-
* mounts them all.
|
|
29
|
-
* - **Writes** go through Node's response after `reply.hijack()`, with the headers
|
|
30
|
-
* Fastify hooks already set (CORS) beneath the protocol's own — what Node's
|
|
31
|
-
* `writeHead` does on Express.
|
|
5
|
+
* The protocol on Nest's Fastify platform: one Fastify route per protocol route
|
|
6
|
+
* under the entrypoint, answered from its own `onRequest` hook before Fastify's
|
|
7
|
+
* content-type check and body parsing, so every body failure is the protocol's
|
|
8
|
+
* own answer, as on Express. A path the protocol does not own goes on to Nest's
|
|
9
|
+
* not-found handler. A route path Fastify cannot match literally (a `*`, or a
|
|
10
|
+
* reserved escape) is refused while Nest builds the application, naming the
|
|
11
|
+
* Resource keys.
|
|
32
12
|
*/
|
|
33
13
|
/** Fastify's request: Node's own under `raw`, and whether a route matched. */
|
|
34
14
|
type FastifyRequest = {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
* `Framework`.
|
|
4
|
-
* the injected value as an empty class, not the application's own `Framework<M,
|
|
5
|
-
* Cfg>`.
|
|
2
|
+
* The injection token under which `AventaraModule` provides the application's
|
|
3
|
+
* `Framework`. Type the injected value with your own `Framework<M, Cfg>` alias.
|
|
6
4
|
*/
|
|
7
5
|
export declare const AVENTARA_FRAMEWORK: unique symbol;
|
|
8
|
-
/** `@InjectFramework()
|
|
6
|
+
/** `@InjectFramework()`: `@Inject(AVENTARA_FRAMEWORK)` in one call. */
|
|
9
7
|
export declare function InjectFramework(): ParameterDecorator;
|
|
@@ -2,7 +2,7 @@ import type { FrameworkDiagnostic, FrameworkDiagnosticsSink } from "@aventara/co
|
|
|
2
2
|
/** Wraps the application's sink (if any): log an internal failure, then forward. */
|
|
3
3
|
export declare function withInternalFailureLog(sink: FrameworkDiagnosticsSink | undefined): FrameworkDiagnosticsSink;
|
|
4
4
|
/**
|
|
5
|
-
* e.g. `A3001 on Post.create.one (client
|
|
5
|
+
* e.g. `A3001 on Post.create.one (client origin, request 7f3c…): Error. The raw
|
|
6
6
|
* error goes to the framework's diagnostics sink.`
|
|
7
7
|
*/
|
|
8
8
|
export declare function internalFailureLine(diagnostic: FrameworkDiagnostic): string;
|
|
@@ -19,7 +19,7 @@ export function internalFailureLine(diagnostic) {
|
|
|
19
19
|
const step = diagnostic.operation === undefined
|
|
20
20
|
? ""
|
|
21
21
|
: `, plan operation ${diagnostic.operation}`;
|
|
22
|
-
return `${diagnostic.code} on ${subject} (${diagnostic.
|
|
22
|
+
return `${diagnostic.code} on ${subject} (${diagnostic.origin} origin, request ${diagnostic.requestId}${step}): ${thrownKind(diagnostic.error)}${frameworkDetail(diagnostic.error)}. The raw error goes to the framework's diagnostics sink.`;
|
|
23
23
|
}
|
|
24
24
|
function frameworkDetail(error) {
|
|
25
25
|
try {
|
|
@@ -10,16 +10,13 @@ export type NodeOutgoing = {
|
|
|
10
10
|
export type PlatformHeaders = Readonly<Record<string, string | number | readonly string[] | undefined>>;
|
|
11
11
|
/** Zero bytes: the body of a request whose body the protocol does not read. */
|
|
12
12
|
export declare const NO_BYTES: Uint8Array<ArrayBuffer>;
|
|
13
|
-
/** A request URL's raw pathname
|
|
13
|
+
/** A request URL's raw pathname: the query is dropped and nothing is URL-decoded. */
|
|
14
14
|
export declare function pathnameOf(url: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* The request as the protocol reads it: path relative to the entrypoint,
|
|
17
|
-
* `headersDistinct`, the raw arm.
|
|
18
|
-
*/
|
|
15
|
+
/** The request as the protocol reads it: path relative to the entrypoint, distinct headers, raw body. */
|
|
19
16
|
export declare function protocolRequest(method: string, url: string, incoming: NodeIncoming, entrypoint: string, content: Uint8Array): AvProtocolRequest;
|
|
20
17
|
/**
|
|
21
|
-
*
|
|
22
|
-
* set (CORS, say) go beneath it; a protocol header of the same name, in any
|
|
23
|
-
* wins
|
|
18
|
+
* Writes the protocol's answer as it is. Headers the platform's hooks already
|
|
19
|
+
* set (CORS, say) go beneath it; a protocol header of the same name, in any
|
|
20
|
+
* case, wins.
|
|
24
21
|
*/
|
|
25
22
|
export declare function writeAnswer(response: NodeOutgoing, answer: AvProtocolResponse, beneath?: PlatformHeaders): void;
|
|
@@ -7,9 +7,9 @@ export type ProtocolHost = {
|
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
9
|
* Binds `framework`'s protocol for the application's platform, refusing an
|
|
10
|
-
* unsupported platform while providers are instantiated
|
|
11
|
-
* rejects before the application listens. The routes are mounted later, from
|
|
12
|
-
* module's `configure()`.
|
|
10
|
+
* unsupported platform while providers are instantiated, so `NestFactory.create`
|
|
11
|
+
* rejects before the application listens. The routes are mounted later, from
|
|
12
|
+
* the module's `configure()`.
|
|
13
13
|
*/
|
|
14
14
|
export declare function createProtocolHost(adapter: AbstractHttpAdapter | undefined, framework: Framework): ProtocolHost;
|
|
15
15
|
/**
|
|
@@ -32,14 +32,7 @@ export type AdapterHostView = {
|
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* first and receives its adapter from `createNestApplication()`, which sets it on
|
|
38
|
-
* the `HttpAdapterHost` — `init$` fires — before `app.init()` registers Nest's
|
|
39
|
-
* body parsers: the host is created at that moment, so a platform's body reader is
|
|
40
|
-
* still installed ahead of them. A refusal there is kept and raised by `mount()`
|
|
41
|
-
* or `assertReady()`, from `app.init()` — still before the application listens.
|
|
42
|
-
* With no adapter at all (`createApplicationContext`), `assertReady()` refuses
|
|
43
|
-
* from `onModuleInit`.
|
|
35
|
+
* A host for an application whose HTTP adapter may arrive after the providers
|
|
36
|
+
* are instantiated (Nest's testing module).
|
|
44
37
|
*/
|
|
45
38
|
export declare function createPendingProtocolHost(application: AdapterHostView, framework: Framework): PendingProtocolHost;
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import type { AvProtocolBinding, AvProtocolRequest, AvProtocolResponse } from "@aventara/core/protocol";
|
|
2
|
-
/**
|
|
3
|
-
* One route `protocol.surface()` lists. Core keeps `SurfaceRoute` a module
|
|
4
|
-
* type, so the host derives it from the binding — no new core export.
|
|
5
|
-
*/
|
|
2
|
+
/** One route `protocol.surface()` lists. */
|
|
6
3
|
export type SurfaceRoute = ReturnType<AvProtocolBinding["surface"]>[number];
|
|
7
4
|
/** What a mounted route answers its request with: a bound protocol member. */
|
|
8
5
|
export type RouteAnswer = (request: AvProtocolRequest) => AvProtocolResponse | Promise<AvProtocolResponse>;
|
|
9
|
-
/**
|
|
10
|
-
* The bound member each kind of surface route is answered by — total over
|
|
11
|
-
* `SurfaceRoute["kind"]`, so a route kind core adds fails to compile here
|
|
12
|
-
* rather than mounting a route nothing answers. Every platform's mounter
|
|
13
|
-
* reads this one table; none decides an answer of its own.
|
|
14
|
-
*/
|
|
6
|
+
/** The bound member each kind of surface route is answered by. */
|
|
15
7
|
export type ProtocolRouteTable = {
|
|
16
8
|
readonly [K in SurfaceRoute["kind"]]: (binding: AvProtocolBinding) => RouteAnswer;
|
|
17
9
|
};
|
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
import type { AvProtocolBinding, AvProtocolResponse } from "@aventara/core/protocol";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* one more than the limit is all the decoder needs to answer `A2010`, and counting
|
|
6
|
-
* decoded bytes is also the decompression-bomb bound. Past the bound the stream is
|
|
7
|
-
* still read to its end and discarded, so the connection stays usable; nothing
|
|
8
|
-
* more is inflated.
|
|
9
|
-
*
|
|
10
|
-
* Platform-free: it reads an async iterable of bytes, as Node's `IncomingMessage`
|
|
11
|
-
* is.
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* What the reader hands on: the stored bytes; an unsupported coding; or a body
|
|
15
|
-
* that does not decode in the coding it names — a malformed request.
|
|
3
|
+
* What the body reader hands on: the stored bytes, an unsupported coding, or a
|
|
4
|
+
* body that does not decode in the coding it names.
|
|
16
5
|
*/
|
|
17
6
|
export type RequestBodyRead = {
|
|
18
7
|
readonly kind: "read";
|
|
@@ -23,11 +12,9 @@ export type RequestBodyRead = {
|
|
|
23
12
|
readonly kind: "undecodable";
|
|
24
13
|
};
|
|
25
14
|
/**
|
|
26
|
-
* The answer to a body the reader could not hand on, through the bound
|
|
27
|
-
* member
|
|
28
|
-
*
|
|
29
|
-
* request id is minted by core: it exposes no adoption of the client's id to a
|
|
30
|
-
* host.
|
|
15
|
+
* The answer to a body the reader could not hand on, through the bound
|
|
16
|
+
* `failure` member: an unsupported coding is `415 A2011`; a body that does not
|
|
17
|
+
* decode in its coding is malformed, `400 A2000`.
|
|
31
18
|
*/
|
|
32
19
|
export declare function unreadBodyAnswer(binding: AvProtocolBinding, read: Exclude<RequestBodyRead, {
|
|
33
20
|
readonly kind: "read";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aventara/nest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0-rc.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "NestJS host integration for Aventara.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,10 +18,11 @@
|
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
|
-
"LICENSE-ADDITIONAL-PERMISSION.md"
|
|
21
|
+
"LICENSE-ADDITIONAL-PERMISSION.md",
|
|
22
|
+
"CHANGELOG.md"
|
|
22
23
|
],
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@aventara/core": "
|
|
25
|
+
"@aventara/core": "1.0.0-rc.0"
|
|
25
26
|
},
|
|
26
27
|
"peerDependencies": {
|
|
27
28
|
"@nestjs/common": "^12.0.0",
|
|
@@ -31,8 +32,8 @@
|
|
|
31
32
|
"access": "public"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
|
-
"@aventara/prisma7-adapter": "
|
|
35
|
-
"@aventara/testing": "
|
|
35
|
+
"@aventara/prisma7-adapter": "1.0.0-rc.0",
|
|
36
|
+
"@aventara/testing": "1.0.0-rc.0",
|
|
36
37
|
"@nestjs/common": "^12.1.2",
|
|
37
38
|
"@nestjs/core": "^12.1.2",
|
|
38
39
|
"@nestjs/platform-express": "^12.1.2",
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
"rxjs": "^7.8.2"
|
|
44
45
|
},
|
|
45
46
|
"scripts": {
|
|
46
|
-
"build": "tsc -p tsconfig.json --removeComments --declaration false && tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/build/declaration-comments.sanitizer.ts dist",
|
|
47
|
+
"build": "node ../../scripts/build/build-output.cleaner.ts dist && tsc -p tsconfig.json --removeComments --declaration false && tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/build/declaration-comments.sanitizer.ts dist",
|
|
47
48
|
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
|
|
48
49
|
"test": "vitest run --typecheck --config ../../vitest.config.mts --root .",
|
|
49
50
|
"lint": "biome lint src"
|