@aventara/nest 0.1.0-pilot.3 → 0.1.0-pilot.4

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.
@@ -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: either the developer's own instance
6
- * — they called `createFramework` — or the configuration the module hands to
7
- * `createFramework` itself. Exactly one arm; the `?: never` halves make both a
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 (a
25
- * Prisma client, a configuration service) is itself a provider. The factory
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, and mounts its protocol on
35
- * the application's platform from `configure()`: after the developer's `app.use` /
36
- * `enableCors`, before `MiddlewareConsumer` middleware and every controller, so
37
- * the reserved `_` namespace cannot be shadowed.
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
- /** An application context never receives a platform: refused here, at its init. */
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
- * - **The pre-parser**, installed while Nest instantiates providers — before
8
- * Nest's own body parsers: a request under `<entrypoint>/_` has its body read
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, mounted from the module's
6
- * `configure()`.
7
- *
8
- * - **One Fastify route per `protocol.surface()` entry**, at its literal path
9
- * under the entrypoint, with Fastify's automatic `HEAD` route off, so `HEAD
10
- * /_contract` reaches the protocol's `405` as on Express.
11
- * - **Each route is answered from its own `onRequest` hook** — Fastify's first
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 DI token under which `AventaraModule` provides the application's
3
- * `Framework`. A symbol, so injection is exact: an abstract-class token would type
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()` — `@Inject(AVENTARA_FRAMEWORK)` in one call. */
6
+ /** `@InjectFramework()`: `@Inject(AVENTARA_FRAMEWORK)` in one call. */
9
7
  export declare function InjectFramework(): ParameterDecorator;
@@ -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 — query dropped, not URL-decoded. */
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
- * The protocol's answer, written as it is. Headers the platform's hooks already
22
- * set (CORS, say) go beneath it; a protocol header of the same name, in any case,
23
- * wins — what Node's `writeHead` does with `setHeader`'s on Express.
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 — so `NestFactory.create`
11
- * rejects before the application listens. The routes are mounted later, from the
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
- * `NestFactory.create` sets the adapter first: the host is created at once, and an
36
- * unsupported platform rejects then, as before. Nest's testing module compiles
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
- * The raw arm's body reader: a request body read off a Node stream, decoded per
4
- * its `Content-Encoding`, and stored up to `maxRequestBytes + 1` DECODED bytes —
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 `failure`
27
- * member — the one place the host names an A-code: an unsupported coding is `415
28
- * A2011`; a body that does not decode in its coding is malformed, `400 A2000`. The
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": "0.1.0-pilot.3",
3
+ "version": "0.1.0-pilot.4",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "NestJS host integration for Aventara.",
6
6
  "type": "module",
@@ -21,7 +21,7 @@
21
21
  "LICENSE-ADDITIONAL-PERMISSION.md"
22
22
  ],
23
23
  "dependencies": {
24
- "@aventara/core": "0.1.0-pilot.3"
24
+ "@aventara/core": "0.1.0-pilot.4"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@nestjs/common": "^12.0.0",
@@ -31,8 +31,8 @@
31
31
  "access": "public"
32
32
  },
33
33
  "devDependencies": {
34
- "@aventara/prisma7-adapter": "0.1.0-pilot.3",
35
- "@aventara/testing": "0.1.0-pilot.3",
34
+ "@aventara/prisma7-adapter": "0.1.0-pilot.4",
35
+ "@aventara/testing": "0.1.0-pilot.4",
36
36
  "@nestjs/common": "^12.1.2",
37
37
  "@nestjs/core": "^12.1.2",
38
38
  "@nestjs/platform-express": "^12.1.2",