@decohere/http 0.0.1-dev.116
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/README.md +246 -0
- package/commonjs/src/app/app.js +166 -0
- package/commonjs/src/app/index.js +19 -0
- package/commonjs/src/app/module.js +17 -0
- package/commonjs/src/auth/ability.js +54 -0
- package/commonjs/src/auth/auth.config.js +23 -0
- package/commonjs/src/auth/auth.extensions.js +106 -0
- package/commonjs/src/auth/auth.types.js +65 -0
- package/commonjs/src/auth/casl-authorization.service.js +36 -0
- package/commonjs/src/auth/index.js +23 -0
- package/commonjs/src/auth/principal-provider.js +19 -0
- package/commonjs/src/auth/safe-outbound-url.js +102 -0
- package/commonjs/src/auth/token-service.js +151 -0
- package/commonjs/src/builder/builder.js +95 -0
- package/commonjs/src/builder/index.js +18 -0
- package/commonjs/src/const.js +87 -0
- package/commonjs/src/health/health.controller.js +75 -0
- package/commonjs/src/health/health.extensions.js +50 -0
- package/commonjs/src/health/index.js +21 -0
- package/commonjs/src/health/readiness.service.js +67 -0
- package/commonjs/src/health/readiness.types.js +7 -0
- package/commonjs/src/hosting/hosted-service-host.js +88 -0
- package/commonjs/src/hosting/hosted-service.js +11 -0
- package/commonjs/src/hosting/index.js +19 -0
- package/commonjs/src/http/http.compression.js +27 -0
- package/commonjs/src/http/http.extensions.js +269 -0
- package/commonjs/src/http/http.options.js +26 -0
- package/commonjs/src/http/http.options.store.js +20 -0
- package/commonjs/src/http/http.security.js +27 -0
- package/commonjs/src/http/http.static.js +248 -0
- package/commonjs/src/http/index.js +22 -0
- package/commonjs/src/index.js +27 -0
- package/commonjs/src/openapi/index.js +45 -0
- package/commonjs/src/openapi/openapi.generator.js +103 -0
- package/commonjs/src/openapi/openapi.types.js +4 -0
- package/commonjs/src/openapi/request-schema.js +187 -0
- package/commonjs/src/openapi/request-validator.js +85 -0
- package/commonjs/src/providers/fastify.provider.js +391 -0
- package/commonjs/src/providers/index.js +18 -0
- package/commonjs/src/routing/anvil.types.js +99 -0
- package/commonjs/src/routing/decorators/argument.decorator.js +49 -0
- package/commonjs/src/routing/decorators/auth.decorator.js +70 -0
- package/commonjs/src/routing/decorators/controller.decorator.js +16 -0
- package/commonjs/src/routing/decorators/field.decorator.js +25 -0
- package/commonjs/src/routing/decorators/index.js +24 -0
- package/commonjs/src/routing/decorators/request.decorator.js +30 -0
- package/commonjs/src/routing/decorators/response.decorator.js +34 -0
- package/commonjs/src/routing/decorators/route.decorator.js +67 -0
- package/commonjs/src/routing/filters/exception-filter-host.js +145 -0
- package/commonjs/src/routing/filters/exception-filter.js +28 -0
- package/commonjs/src/routing/index.js +25 -0
- package/commonjs/src/routing/middleware/http-access-log.middleware.js +47 -0
- package/commonjs/src/routing/middleware/middleware.js +20 -0
- package/commonjs/src/routing/middleware/request-id.js +30 -0
- package/commonjs/src/routing/path.util.js +51 -0
- package/commonjs/src/routing/pipes/index.js +18 -0
- package/commonjs/src/routing/pipes/pipes.js +145 -0
- package/commonjs/src/routing/services/index.js +18 -0
- package/commonjs/src/routing/services/route-argument-resolver.js +77 -0
- package/commonjs/src/routing/services/route-registry.js +194 -0
- package/commonjs/src/routing/services/router.js +158 -0
- package/commonjs/src/sse/index.js +26 -0
- package/commonjs/src/sse/sse.decorator.js +42 -0
- package/commonjs/src/sse/sse.encoder.js +73 -0
- package/commonjs/src/sse/sse.types.js +36 -0
- package/commonjs/src/sse/sse.wire.js +40 -0
- package/commonjs/src/testing/boot-module.js +38 -0
- package/commonjs/src/testing/index.js +20 -0
- package/commonjs/src/testing/sse-reader.js +98 -0
- package/es6/src/app/app.js +148 -0
- package/es6/src/app/index.js +2 -0
- package/es6/src/app/module.js +7 -0
- package/es6/src/auth/ability.js +45 -0
- package/es6/src/auth/auth.config.js +19 -0
- package/es6/src/auth/auth.extensions.js +83 -0
- package/es6/src/auth/auth.types.js +35 -0
- package/es6/src/auth/casl-authorization.service.js +40 -0
- package/es6/src/auth/index.js +6 -0
- package/es6/src/auth/principal-provider.js +14 -0
- package/es6/src/auth/safe-outbound-url.js +99 -0
- package/es6/src/auth/token-service.js +141 -0
- package/es6/src/builder/builder.js +85 -0
- package/es6/src/builder/index.js +1 -0
- package/es6/src/const.js +33 -0
- package/es6/src/health/health.controller.js +65 -0
- package/es6/src/health/health.extensions.js +40 -0
- package/es6/src/health/index.js +4 -0
- package/es6/src/health/readiness.service.js +57 -0
- package/es6/src/health/readiness.types.js +4 -0
- package/es6/src/hosting/hosted-service-host.js +81 -0
- package/es6/src/hosting/hosted-service.js +8 -0
- package/es6/src/hosting/index.js +2 -0
- package/es6/src/http/http.compression.js +9 -0
- package/es6/src/http/http.extensions.js +259 -0
- package/es6/src/http/http.options.js +16 -0
- package/es6/src/http/http.options.store.js +13 -0
- package/es6/src/http/http.security.js +9 -0
- package/es6/src/http/http.static.js +224 -0
- package/es6/src/http/index.js +5 -0
- package/es6/src/index.js +10 -0
- package/es6/src/openapi/index.js +3 -0
- package/es6/src/openapi/openapi.generator.js +82 -0
- package/es6/src/openapi/openapi.types.js +1 -0
- package/es6/src/openapi/request-schema.js +160 -0
- package/es6/src/openapi/request-validator.js +71 -0
- package/es6/src/providers/fastify.provider.js +376 -0
- package/es6/src/providers/index.js +1 -0
- package/es6/src/routing/anvil.types.js +57 -0
- package/es6/src/routing/decorators/argument.decorator.js +28 -0
- package/es6/src/routing/decorators/auth.decorator.js +58 -0
- package/es6/src/routing/decorators/controller.decorator.js +6 -0
- package/es6/src/routing/decorators/field.decorator.js +15 -0
- package/es6/src/routing/decorators/index.js +7 -0
- package/es6/src/routing/decorators/request.decorator.js +24 -0
- package/es6/src/routing/decorators/response.decorator.js +16 -0
- package/es6/src/routing/decorators/route.decorator.js +37 -0
- package/es6/src/routing/filters/exception-filter-host.js +127 -0
- package/es6/src/routing/filters/exception-filter.js +10 -0
- package/es6/src/routing/index.js +8 -0
- package/es6/src/routing/middleware/http-access-log.middleware.js +37 -0
- package/es6/src/routing/middleware/middleware.js +10 -0
- package/es6/src/routing/middleware/request-id.js +14 -0
- package/es6/src/routing/path.util.js +33 -0
- package/es6/src/routing/pipes/index.js +1 -0
- package/es6/src/routing/pipes/pipes.js +118 -0
- package/es6/src/routing/services/index.js +1 -0
- package/es6/src/routing/services/route-argument-resolver.js +67 -0
- package/es6/src/routing/services/route-registry.js +184 -0
- package/es6/src/routing/services/router.js +148 -0
- package/es6/src/sse/index.js +2 -0
- package/es6/src/sse/sse.decorator.js +31 -0
- package/es6/src/sse/sse.encoder.js +67 -0
- package/es6/src/sse/sse.types.js +22 -0
- package/es6/src/sse/sse.wire.js +30 -0
- package/es6/src/testing/boot-module.js +35 -0
- package/es6/src/testing/index.js +2 -0
- package/es6/src/testing/sse-reader.js +91 -0
- package/package.json +64 -0
- package/types/src/app/app.d.ts +41 -0
- package/types/src/app/index.d.ts +2 -0
- package/types/src/app/module.d.ts +15 -0
- package/types/src/auth/ability.d.ts +19 -0
- package/types/src/auth/auth.config.d.ts +28 -0
- package/types/src/auth/auth.extensions.d.ts +53 -0
- package/types/src/auth/auth.types.d.ts +73 -0
- package/types/src/auth/casl-authorization.service.d.ts +28 -0
- package/types/src/auth/index.d.ts +6 -0
- package/types/src/auth/principal-provider.d.ts +20 -0
- package/types/src/auth/safe-outbound-url.d.ts +9 -0
- package/types/src/auth/token-service.d.ts +31 -0
- package/types/src/builder/builder.d.ts +36 -0
- package/types/src/builder/index.d.ts +1 -0
- package/types/src/const.d.ts +32 -0
- package/types/src/health/health.controller.d.ts +16 -0
- package/types/src/health/health.extensions.d.ts +31 -0
- package/types/src/health/index.d.ts +4 -0
- package/types/src/health/readiness.service.d.ts +9 -0
- package/types/src/health/readiness.types.d.ts +14 -0
- package/types/src/hosting/hosted-service-host.d.ts +37 -0
- package/types/src/hosting/hosted-service.d.ts +31 -0
- package/types/src/hosting/index.d.ts +2 -0
- package/types/src/http/http.compression.d.ts +32 -0
- package/types/src/http/http.extensions.d.ts +79 -0
- package/types/src/http/http.options.d.ts +39 -0
- package/types/src/http/http.options.store.d.ts +7 -0
- package/types/src/http/http.security.d.ts +20 -0
- package/types/src/http/http.static.d.ts +160 -0
- package/types/src/http/index.d.ts +5 -0
- package/types/src/index.d.ts +10 -0
- package/types/src/openapi/index.d.ts +6 -0
- package/types/src/openapi/openapi.generator.d.ts +6 -0
- package/types/src/openapi/openapi.types.d.ts +58 -0
- package/types/src/openapi/request-schema.d.ts +21 -0
- package/types/src/openapi/request-validator.d.ts +9 -0
- package/types/src/providers/fastify.provider.d.ts +56 -0
- package/types/src/providers/index.d.ts +1 -0
- package/types/src/routing/anvil.types.d.ts +119 -0
- package/types/src/routing/decorators/argument.decorator.d.ts +11 -0
- package/types/src/routing/decorators/auth.decorator.d.ts +30 -0
- package/types/src/routing/decorators/controller.decorator.d.ts +3 -0
- package/types/src/routing/decorators/field.decorator.d.ts +2 -0
- package/types/src/routing/decorators/index.d.ts +7 -0
- package/types/src/routing/decorators/request.decorator.d.ts +8 -0
- package/types/src/routing/decorators/response.decorator.d.ts +4 -0
- package/types/src/routing/decorators/route.decorator.d.ts +7 -0
- package/types/src/routing/filters/exception-filter-host.d.ts +19 -0
- package/types/src/routing/filters/exception-filter.d.ts +16 -0
- package/types/src/routing/index.d.ts +8 -0
- package/types/src/routing/middleware/http-access-log.middleware.d.ts +8 -0
- package/types/src/routing/middleware/middleware.d.ts +10 -0
- package/types/src/routing/middleware/request-id.d.ts +6 -0
- package/types/src/routing/path.util.d.ts +9 -0
- package/types/src/routing/pipes/index.d.ts +1 -0
- package/types/src/routing/pipes/pipes.d.ts +21 -0
- package/types/src/routing/services/index.d.ts +1 -0
- package/types/src/routing/services/route-argument-resolver.d.ts +10 -0
- package/types/src/routing/services/route-registry.d.ts +20 -0
- package/types/src/routing/services/router.d.ts +22 -0
- package/types/src/sse/index.d.ts +3 -0
- package/types/src/sse/sse.decorator.d.ts +17 -0
- package/types/src/sse/sse.encoder.d.ts +16 -0
- package/types/src/sse/sse.types.d.ts +37 -0
- package/types/src/sse/sse.wire.d.ts +9 -0
- package/types/src/testing/boot-module.d.ts +34 -0
- package/types/src/testing/index.d.ts +4 -0
- package/types/src/testing/sse-reader.d.ts +29 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { IContainer } from "@decohere/crucible";
|
|
2
|
+
import type { Constructable } from "@decohere/core/reflection";
|
|
3
|
+
import type { IReadinessCheck } from "../health/readiness.types.js";
|
|
4
|
+
import type { HostedService } from "./hosted-service.js";
|
|
5
|
+
/**
|
|
6
|
+
* Starts and stops the app's {@link HostedService}s. One per app; `Builder.withHostedService`
|
|
7
|
+
* adds the types and `App` drives it.
|
|
8
|
+
*/
|
|
9
|
+
export declare class HostedServiceHost {
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly types;
|
|
12
|
+
private readonly controller;
|
|
13
|
+
/** In start order; stopped in reverse. */
|
|
14
|
+
private readonly started;
|
|
15
|
+
private starting;
|
|
16
|
+
private stopping;
|
|
17
|
+
add(...types: Constructable<HostedService>[]): void;
|
|
18
|
+
get isEmpty(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Start every service in registration order. If one throws, the ones already started are
|
|
21
|
+
* stopped and the error is rethrown. Stops launching more once {@link stop} has begun.
|
|
22
|
+
*/
|
|
23
|
+
start(container: IContainer): Promise<void>;
|
|
24
|
+
/** Abort the services' signal: background work should wind down. {@link stop} does this too. */
|
|
25
|
+
abort(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Abort the signal, wait for a start still in progress, then stop the started services in
|
|
28
|
+
* reverse order. Every `stop()` runs even if one throws; the failures are rethrown after.
|
|
29
|
+
*/
|
|
30
|
+
stop(): Promise<void>;
|
|
31
|
+
/** The started services that report readiness, for `GET /ready`. */
|
|
32
|
+
readinessChecks(): IReadinessCheck[];
|
|
33
|
+
private startAll;
|
|
34
|
+
private stopAll;
|
|
35
|
+
/** Stop what is started, newest first. Takes each service off the list, so it runs once. */
|
|
36
|
+
private stopStarted;
|
|
37
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Work that runs for the life of the app outside a request: a feed, a poller, a queue consumer.
|
|
3
|
+
* Register it with `builder.withHostedService(Type)`; it is a singleton, so other services can
|
|
4
|
+
* inject it by its class.
|
|
5
|
+
*
|
|
6
|
+
* The app starts hosted services in registration order before the HTTP server listens, and stops
|
|
7
|
+
* them in reverse order when it stops (`app.dispose()`, SIGTERM or SIGINT, a Flux reboot).
|
|
8
|
+
*/
|
|
9
|
+
export interface HostedService {
|
|
10
|
+
/**
|
|
11
|
+
* Called once when the app starts, and awaited: a throw fails `app.start()`. Do what must be
|
|
12
|
+
* ready before traffic, then start long work (a first load that takes minutes, a timer) in
|
|
13
|
+
* the background and return. Waiting for it here keeps the HTTP server dark.
|
|
14
|
+
*
|
|
15
|
+
* `signal` is aborted as soon as the app starts stopping, before `stop()` is called, also
|
|
16
|
+
* while `start()` itself is still running. Stop background work and clear timers on it.
|
|
17
|
+
*/
|
|
18
|
+
start(signal: AbortSignal): Promise<void> | void;
|
|
19
|
+
/**
|
|
20
|
+
* Called once when the app stops, after the HTTP server has drained and before the container
|
|
21
|
+
* is disposed, so the services it uses (a DataSource) are still open. Wait here for the
|
|
22
|
+
* background work to finish. Optional: a service with nothing to wait for can rely on the
|
|
23
|
+
* signal, or on `Symbol.asyncDispose`, which the container calls later.
|
|
24
|
+
*/
|
|
25
|
+
stop?(): Promise<void> | void;
|
|
26
|
+
/**
|
|
27
|
+
* Readiness while the service is started but still warming up: throw until it can serve, and
|
|
28
|
+
* `GET /ready` answers 503 (`withHealth()`). Optional.
|
|
29
|
+
*/
|
|
30
|
+
check?(): Promise<void>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response compression (`builder.withCompression`). Provider-neutral options and defaults;
|
|
3
|
+
* the HTTP provider hands them to its compression plugin and the plugin owns the policy
|
|
4
|
+
* (which responses are compressed, `Vary`, `HEAD`, streams). See ADR 0008.
|
|
5
|
+
*/
|
|
6
|
+
/** A content coding the HTTP package can offer. */
|
|
7
|
+
export type CompressionEncoding = "br" | "gzip" | "deflate";
|
|
8
|
+
/** Bodies smaller than this many bytes are sent as they are (not applied to streams, such as files). */
|
|
9
|
+
export declare const DEFAULT_COMPRESSION_THRESHOLD = 1024;
|
|
10
|
+
/** The codings offered by default, in order of preference. `deflate` is left out on purpose. */
|
|
11
|
+
export declare const DEFAULT_COMPRESSION_ENCODINGS: readonly CompressionEncoding[];
|
|
12
|
+
/** Options for {@link Builder.withCompression}. `false` turns compression off. */
|
|
13
|
+
export type CompressionOptions = false | {
|
|
14
|
+
/** Smallest body, in bytes, that is compressed. Defaults to 1024. Not applied to streamed bodies. */
|
|
15
|
+
threshold?: number;
|
|
16
|
+
/** The codings to offer, in order of preference. Defaults to `["br", "gzip"]`. */
|
|
17
|
+
encodings?: CompressionEncoding[];
|
|
18
|
+
/**
|
|
19
|
+
* Content types to compress, tested against the `Content-Type` header. Passed to the
|
|
20
|
+
* plugin as `customTypes`: it replaces the plugin's default pattern (text, JSON, XML,
|
|
21
|
+
* `octet-stream`; never `text/event-stream`) and anything the MIME database marks
|
|
22
|
+
* compressible is still compressed. Use it to add a type; do not match
|
|
23
|
+
* `text/event-stream` unless you want streams buffered.
|
|
24
|
+
*/
|
|
25
|
+
types?: RegExp | ((contentType: string) => boolean);
|
|
26
|
+
/**
|
|
27
|
+
* Fastify-specific. Any other `@fastify/compress` option (`brotliOptions`, `zlibOptions`,
|
|
28
|
+
* `onUnsupportedEncoding`, `inflateIfDeflated`, ...), merged last so it overrides the
|
|
29
|
+
* values above. Not portable to another HTTP provider.
|
|
30
|
+
*/
|
|
31
|
+
providerOptions?: Record<string, unknown>;
|
|
32
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Constructable } from "@decohere/core/reflection";
|
|
2
|
+
import { Builder } from "../builder/builder.js";
|
|
3
|
+
import type { OpenApiOptions } from "../openapi/openapi.types.js";
|
|
4
|
+
import type { CorsOptions, HttpProvider } from "../routing/anvil.types.js";
|
|
5
|
+
import type { ExceptionFilter } from "../routing/filters/exception-filter.js";
|
|
6
|
+
import type { Middleware } from "../routing/middleware/middleware.js";
|
|
7
|
+
import type { WithHttpOptions } from "./http.options.js";
|
|
8
|
+
import type { CompressionOptions } from "./http.compression.js";
|
|
9
|
+
import type { HelmetOptions, RateLimitOptions } from "./http.security.js";
|
|
10
|
+
import { type StaticOptions } from "./http.static.js";
|
|
11
|
+
declare module "@decohere/http" {
|
|
12
|
+
interface Builder {
|
|
13
|
+
withHttpProvider<Thttp extends Constructable<HttpProvider>>(type: Thttp): Builder;
|
|
14
|
+
/**
|
|
15
|
+
* HTTP provider plus scaffold defaults (request id + Scribe access log).
|
|
16
|
+
* Prefer this over {@link Builder.withHttpProvider} for application entrypoints.
|
|
17
|
+
*/
|
|
18
|
+
withHttp<Thttp extends Constructable<HttpProvider>>(type: Thttp, options?: WithHttpOptions): Builder;
|
|
19
|
+
withControllers(...controllers: Constructable[]): Builder;
|
|
20
|
+
/**
|
|
21
|
+
* Prefix every controller route (`/api` makes `/lp/portfolio` into `/api/lp/portfolio`).
|
|
22
|
+
* It covers controller routes only: not static mounts (`withStatic`), not the OpenAPI
|
|
23
|
+
* document, and not a controller declared with `@Controller({ globalPrefix: false })`,
|
|
24
|
+
* such as the `withHealth()` probes, which platforms expect at the root. With a prefix
|
|
25
|
+
* set, the static fallback treats everything under it as the API.
|
|
26
|
+
*/
|
|
27
|
+
withGlobalPrefix(prefix: string): Builder;
|
|
28
|
+
withCors(options: CorsOptions): Builder;
|
|
29
|
+
/**
|
|
30
|
+
* Override or disable default `@fastify/helmet` headers.
|
|
31
|
+
* Defaults are on with `withHttpProvider`; pass `false` to disable.
|
|
32
|
+
*/
|
|
33
|
+
withHelmet(options?: HelmetOptions): Builder;
|
|
34
|
+
/**
|
|
35
|
+
* Override or disable default `@fastify/rate-limit` (100 req / 1 minute).
|
|
36
|
+
* Pass `false` to disable.
|
|
37
|
+
*/
|
|
38
|
+
withRateLimit(options?: RateLimitOptions): Builder;
|
|
39
|
+
/**
|
|
40
|
+
* Compress responses with `br` or `gzip` when the client accepts it, using `@fastify/compress`
|
|
41
|
+
* with best-practice defaults (on by default, 1 KB threshold, no `deflate`). Pass `false` to
|
|
42
|
+
* turn it off, or `{ threshold, encodings, types, providerOptions }` to override. The plugin
|
|
43
|
+
* does not compress `text/event-stream` by default. Compressing a response that mixes a secret
|
|
44
|
+
* with input an attacker controls can leak the secret over HTTPS (BREACH); see ADR 0008.
|
|
45
|
+
*/
|
|
46
|
+
withCompression(options?: CompressionOptions): Builder;
|
|
47
|
+
/**
|
|
48
|
+
* Override the default request body size limit (1 MiB).
|
|
49
|
+
*/
|
|
50
|
+
withBodyLimit(bytes: number): Builder;
|
|
51
|
+
withMiddleware(...middlewares: Constructable<Middleware>[]): Builder;
|
|
52
|
+
withExceptionFilters(...filters: Constructable<ExceptionFilter>[]): Builder;
|
|
53
|
+
withOpenApi(options: OpenApiOptions): Builder;
|
|
54
|
+
/**
|
|
55
|
+
* Serve a built UI (a folder of static files) from this API, for example
|
|
56
|
+
* `.withStatic("/ui/", "ui")`. The directory is resolved from the process working
|
|
57
|
+
* directory, like `./config`. The files are public: they are served before auth,
|
|
58
|
+
* validation and middleware, and outside the rate limit. An unknown path under the prefix
|
|
59
|
+
* serves `index.html` to a browser (`Accept: text/html`) so client routes survive a reload. `"/"` mounts it at the root. Hashed assets are cached for a
|
|
60
|
+
* year, `index.html` is not cached. See {@link StaticOptions}.
|
|
61
|
+
*/
|
|
62
|
+
withStatic(prefix: string, directory: string, options?: StaticOptions): Builder;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export declare class BuilderExtensions {
|
|
66
|
+
static withHttpProvider<Thttp extends Constructable<HttpProvider>>(builder: Builder, type: Thttp): Builder<import("@decohere/http").App>;
|
|
67
|
+
static withHttp<Thttp extends Constructable<HttpProvider>>(builder: Builder, type: Thttp, options?: WithHttpOptions): Builder<import("@decohere/http").App>;
|
|
68
|
+
static withControllers(builder: Builder, ...controllers: Constructable[]): Builder<import("@decohere/http").App>;
|
|
69
|
+
static withGlobalPrefix(builder: Builder, prefix: string): Builder<import("@decohere/http").App>;
|
|
70
|
+
static withCors(builder: Builder, options: CorsOptions): Builder<import("@decohere/http").App>;
|
|
71
|
+
static withHelmet(builder: Builder, options?: HelmetOptions): Builder<import("@decohere/http").App>;
|
|
72
|
+
static withRateLimit(builder: Builder, options?: RateLimitOptions): Builder<import("@decohere/http").App>;
|
|
73
|
+
static withCompression(builder: Builder, options?: CompressionOptions): Builder<import("@decohere/http").App>;
|
|
74
|
+
static withBodyLimit(builder: Builder, bytes: number): Builder<import("@decohere/http").App>;
|
|
75
|
+
static withMiddleware(builder: Builder, ...middlewares: Constructable<Middleware>[]): Builder<import("@decohere/http").App>;
|
|
76
|
+
static withExceptionFilters(builder: Builder, ...filters: Constructable<ExceptionFilter>[]): Builder<import("@decohere/http").App>;
|
|
77
|
+
static withOpenApi(builder: Builder, options: OpenApiOptions): Builder<import("@decohere/http").App>;
|
|
78
|
+
static withStatic(builder: Builder, prefix: string, directory: string, options?: StaticOptions): Builder<import("@decohere/http").App>;
|
|
79
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Constructable } from "@decohere/core/reflection";
|
|
2
|
+
import type { OpenApiOptions } from "../openapi/openapi.types.js";
|
|
3
|
+
import type { CorsOptions } from "../routing/anvil.types.js";
|
|
4
|
+
import type { ExceptionFilter } from "../routing/filters/exception-filter.js";
|
|
5
|
+
import type { Middleware } from "../routing/middleware/middleware.js";
|
|
6
|
+
import type { CompressionOptions } from "./http.compression.js";
|
|
7
|
+
import type { StaticMount } from "./http.static.js";
|
|
8
|
+
import type { HelmetOptions, RateLimitOptions } from "./http.security.js";
|
|
9
|
+
/** Options for {@link Builder.withHttp} (request-id / access-log defaults, etc.). */
|
|
10
|
+
export type WithHttpOptions = {
|
|
11
|
+
/**
|
|
12
|
+
* Register {@link HttpAccessLogMiddleware} (request id echo + Scribe access log).
|
|
13
|
+
* Defaults to `true`.
|
|
14
|
+
*/
|
|
15
|
+
accessLog?: boolean;
|
|
16
|
+
};
|
|
17
|
+
/** App-level HTTP options set via builder extensions (`withCors`, `withGlobalPrefix`, …). */
|
|
18
|
+
export declare class HttpOptions {
|
|
19
|
+
globalPrefix: string;
|
|
20
|
+
/**
|
|
21
|
+
* Controllers put under the global prefix although they declare `globalPrefix: false`
|
|
22
|
+
* (`withHealth({ underGlobalPrefix: true })`).
|
|
23
|
+
*/
|
|
24
|
+
readonly underGlobalPrefix: Set<Constructable>;
|
|
25
|
+
cors?: CorsOptions;
|
|
26
|
+
openapi?: OpenApiOptions;
|
|
27
|
+
/** `undefined` = helmet on with defaults; `false` = off; object = plugin options. */
|
|
28
|
+
helmet?: HelmetOptions;
|
|
29
|
+
/** `undefined` = rate-limit on with defaults; `false` = off; object = plugin options. */
|
|
30
|
+
rateLimit?: RateLimitOptions;
|
|
31
|
+
/** `undefined` = compression on with defaults; `false` = off; object = options. See `withCompression`. */
|
|
32
|
+
compression?: CompressionOptions;
|
|
33
|
+
/** Request body size limit in bytes; `undefined` uses the 1 MiB default. */
|
|
34
|
+
bodyLimit?: number;
|
|
35
|
+
/** Built UIs served from this API, see `withStatic`. */
|
|
36
|
+
statics: StaticMount[];
|
|
37
|
+
middlewareTypes: Constructable<Middleware>[];
|
|
38
|
+
filterTypes: Constructable<ExceptionFilter>[];
|
|
39
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Builder } from "../builder/builder.js";
|
|
2
|
+
import { HttpOptions } from "./http.options.js";
|
|
3
|
+
/**
|
|
4
|
+
* The {@link HttpOptions} a builder collects through its extensions. Internal: lets extensions
|
|
5
|
+
* outside `http.extensions.ts` (`withHealth`) set an option without a public builder method.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getOrCreateHttpOptions(builder: Builder): HttpOptions;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default HTTP security settings applied by {@link FastifyProvider} when
|
|
3
|
+
* `withHttpProvider` is used. Override via `withHelmet` / `withRateLimit` /
|
|
4
|
+
* `withBodyLimit` (pass `false` to disable helmet or rate-limit).
|
|
5
|
+
*/
|
|
6
|
+
/** Fastify body size limit (bytes). Matches Fastify's built-in default, made explicit and overridable. */
|
|
7
|
+
export declare const DEFAULT_HTTP_BODY_LIMIT = 1048576;
|
|
8
|
+
/** Global request rate limit applied unless disabled or customized. */
|
|
9
|
+
export declare const DEFAULT_HTTP_RATE_LIMIT: {
|
|
10
|
+
readonly max: 100;
|
|
11
|
+
readonly timeWindow: "1 minute";
|
|
12
|
+
};
|
|
13
|
+
/** `false` disables the plugin; an object customizes `@fastify/helmet`. */
|
|
14
|
+
export type HelmetOptions = false | Record<string, unknown>;
|
|
15
|
+
/** `false` disables the plugin; an object customizes `@fastify/rate-limit`. */
|
|
16
|
+
export type RateLimitOptions = false | {
|
|
17
|
+
max?: number;
|
|
18
|
+
timeWindow?: number | string;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serving a module's built UI from its API (`builder.withStatic`). Everything here is
|
|
3
|
+
* provider-neutral: the options, the caching rules and the missing-directory policy.
|
|
4
|
+
* Only the HTTP provider knows how to put files on the wire. See ADR 0007.
|
|
5
|
+
*/
|
|
6
|
+
/** Cache header for files whose name carries a content hash. The name changes when the content does. */
|
|
7
|
+
export declare const STATIC_IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
8
|
+
/** Cache header for files that must be revalidated on every use (the entry points of a UI). */
|
|
9
|
+
export declare const STATIC_NO_CACHE_CONTROL = "no-cache";
|
|
10
|
+
/** Cache header for every other file: cacheable, but always revalidated (ETag / Last-Modified). */
|
|
11
|
+
export declare const STATIC_DEFAULT_CACHE_CONTROL = "public, max-age=0, must-revalidate";
|
|
12
|
+
/**
|
|
13
|
+
* The entry points of a UI. `index.html` names the hashed bundles, and a module-federation host
|
|
14
|
+
* loads `remoteEntry.js` by a fixed name to find the current remote, so neither can be cached.
|
|
15
|
+
*/
|
|
16
|
+
export declare const STATIC_DEFAULT_NO_CACHE: readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* A build tool's hashed file name: `index-DiwrgTda.js`, `chunk.3f9a8c1b.css`, `app-abc123de.js.map`.
|
|
19
|
+
* The hash is 8 or more letters, digits or `_` after a `-` or `.`, and holds a digit or a lowercase
|
|
20
|
+
* letter followed by an uppercase one. Plain words (`logo-background.png`) are not hashes.
|
|
21
|
+
*/
|
|
22
|
+
export declare const STATIC_DEFAULT_IMMUTABLE: RegExp;
|
|
23
|
+
export type StaticOptions = {
|
|
24
|
+
/**
|
|
25
|
+
* Serve `index.html` for an unknown path under the prefix, so a client-side route survives a
|
|
26
|
+
* reload. Only for GET and HEAD, and never for a path that looks like a file (has an
|
|
27
|
+
* extension), so a missing asset stays a 404. Defaults to `true`.
|
|
28
|
+
*/
|
|
29
|
+
spaFallback?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Path patterns this mount never answers, neither a file nor the fallback: the request gets the
|
|
32
|
+
* normal JSON 404. Globs on the full request path (not relative to the prefix), for example
|
|
33
|
+
* `["/api/**", "/docs/**"]`: `*` is any run of characters inside one segment, `**` crosses
|
|
34
|
+
* segments, `?` is one character. `/api/**` also covers `/api` itself. Rarely needed: a path
|
|
35
|
+
* that starts with the first segment of a registered controller route is already never
|
|
36
|
+
* answered with the fallback (see `staticFiles.isUnderRoute`).
|
|
37
|
+
*/
|
|
38
|
+
exclude?: string[];
|
|
39
|
+
/** The file served for the prefix itself and for the fallback. Defaults to `index.html`. */
|
|
40
|
+
index?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Files sent with `Cache-Control: no-cache`, by file name (`index.html`) or by path relative to
|
|
43
|
+
* the directory (`remote/remoteEntry.js`). Replaces the default `["index.html", "remoteEntry.js"]`,
|
|
44
|
+
* so list `index.html` again if you override it.
|
|
45
|
+
*/
|
|
46
|
+
noCache?: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Files whose name holds a content hash get `public, max-age=31536000, immutable`. Replace the
|
|
49
|
+
* pattern if your build names files differently (it is tested against the path relative to the
|
|
50
|
+
* directory), or pass `false` to give no file the immutable header.
|
|
51
|
+
*/
|
|
52
|
+
immutable?: RegExp | false;
|
|
53
|
+
/** `Cache-Control` for every other file. Defaults to `public, max-age=0, must-revalidate`. */
|
|
54
|
+
cacheControl?: string;
|
|
55
|
+
/**
|
|
56
|
+
* What to do when the directory does not exist at start. `"fail"` stops the app with an error;
|
|
57
|
+
* `"warn"` logs a warning and serves nothing, so the API still boots before the UI is built.
|
|
58
|
+
* Defaults to `"warn"` when NODE_ENV is `development` or `dev`, and to `"fail"` otherwise.
|
|
59
|
+
*/
|
|
60
|
+
onMissingDirectory?: "fail" | "warn";
|
|
61
|
+
};
|
|
62
|
+
/** A `withStatic` call, as the builder keeps it. */
|
|
63
|
+
export type StaticMount = {
|
|
64
|
+
/** Normalised: starts and ends with `/`, for example `/ui/`. */
|
|
65
|
+
prefix: string;
|
|
66
|
+
/** As given by the caller, resolved from the process working directory when the app starts. */
|
|
67
|
+
directory: string;
|
|
68
|
+
options: StaticOptions;
|
|
69
|
+
};
|
|
70
|
+
/** A mount the provider can register: the directory exists and every option has its value. */
|
|
71
|
+
export type ResolvedStaticMount = {
|
|
72
|
+
prefix: string;
|
|
73
|
+
/** Absolute path of the directory. */
|
|
74
|
+
root: string;
|
|
75
|
+
spaFallback: boolean;
|
|
76
|
+
index: string;
|
|
77
|
+
noCache: readonly string[];
|
|
78
|
+
immutable: RegExp | false;
|
|
79
|
+
cacheControl: string;
|
|
80
|
+
exclude: readonly string[];
|
|
81
|
+
};
|
|
82
|
+
declare function toMount(prefix: string, directory: string, options?: StaticOptions): StaticMount;
|
|
83
|
+
type DirectoryProbe = (absolutePath: string) => Promise<boolean>;
|
|
84
|
+
export type ResolveStaticOptions = {
|
|
85
|
+
/** Where relative directories are resolved from. Defaults to the process working directory. */
|
|
86
|
+
cwd?: string;
|
|
87
|
+
nodeEnv?: string;
|
|
88
|
+
directoryExists: DirectoryProbe;
|
|
89
|
+
warn: (message: string) => void;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Checks every mount at start. Returns the ones that can be served; a missing directory fails or
|
|
93
|
+
* warns according to the mount's `onMissingDirectory`. Two mounts on one prefix always fail.
|
|
94
|
+
*/
|
|
95
|
+
declare function resolve(mounts: readonly StaticMount[], env: ResolveStaticOptions): Promise<ResolvedStaticMount[]>;
|
|
96
|
+
/** `Cache-Control` for a file, given its path relative to the mount's directory. */
|
|
97
|
+
declare function cacheControlFor(mount: ResolvedStaticMount, relativePath: string): string;
|
|
98
|
+
/**
|
|
99
|
+
* Does this path look like a file: an extension on the last segment, or a dotfile anywhere?
|
|
100
|
+
* Then a miss is a real 404, not a client-side route.
|
|
101
|
+
*/
|
|
102
|
+
declare function looksLikeFile(pathname: string): boolean;
|
|
103
|
+
/** The request path as the mount sees it: no query, decoded, repeated slashes collapsed. */
|
|
104
|
+
declare function normalizePathname(url: string): string;
|
|
105
|
+
/** Builds the test for a mount's `exclude` patterns. Matches on the normalised path. */
|
|
106
|
+
declare function excluder(patterns: readonly string[]): (pathname: string) => boolean;
|
|
107
|
+
/**
|
|
108
|
+
* The first path segment of every registered route, for {@link isUnderRoute}. A segment that is a
|
|
109
|
+
* parameter or wildcard (`:id`, `*`) says nothing about the path and is skipped.
|
|
110
|
+
*/
|
|
111
|
+
declare function routeSegments(routePaths: Iterable<string>): Set<string>;
|
|
112
|
+
/**
|
|
113
|
+
* Is this path under one of the app's own routes? True when its first segment is the first
|
|
114
|
+
* segment of a registered route: with a controller route `/lp/portfolio`, `/lp/portfolo` and
|
|
115
|
+
* `/lp/anything/else` belong to the API and keep the JSON 404, while `/lpx` does not.
|
|
116
|
+
*/
|
|
117
|
+
declare function isUnderRoute(pathname: string, segments: ReadonlySet<string>): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* What the fallback treats as the API, as a test on the normalised path. With a global prefix it
|
|
120
|
+
* is the prefix, the OpenAPI path and every route left outside the prefix
|
|
121
|
+
* (`@Controller({ globalPrefix: false })`, such as `/health`), each with the paths below it, so a
|
|
122
|
+
* client route may share a first segment with a controller. Without a prefix it is
|
|
123
|
+
* {@link isUnderRoute} (the first segment of every registered route), the safe guess when nothing
|
|
124
|
+
* says where the API lives.
|
|
125
|
+
*/
|
|
126
|
+
declare function apiBoundary(boundary: {
|
|
127
|
+
/** Normalised global prefix (`/api`), or `""` when there is none. */
|
|
128
|
+
globalPrefix: string;
|
|
129
|
+
openApiPath?: string;
|
|
130
|
+
/** Every registered route path, global prefix included. */
|
|
131
|
+
routePaths: Iterable<string>;
|
|
132
|
+
}): (pathname: string) => boolean;
|
|
133
|
+
/** Does the `Accept` header ask for HTML (a browser navigation)? `text/html;q=0` does not. */
|
|
134
|
+
declare function acceptsHtml(accept: string | undefined): boolean;
|
|
135
|
+
export type FallbackRequest = {
|
|
136
|
+
method: string;
|
|
137
|
+
/** Normalised, see `normalizePathname`. */
|
|
138
|
+
pathname: string;
|
|
139
|
+
accept: string | undefined;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Should an unknown path get the app's `index.html`? Only a browser navigation: GET or HEAD, no
|
|
143
|
+
* file extension and no dotfile in the path, an `Accept` that includes `text/html`, and not under
|
|
144
|
+
* the API (see {@link apiBoundary}). Everything else keeps the normal JSON 404.
|
|
145
|
+
*/
|
|
146
|
+
declare function shouldFallBack(request: FallbackRequest, belongsToApi: (pathname: string) => boolean): boolean;
|
|
147
|
+
export declare const staticFiles: {
|
|
148
|
+
toMount: typeof toMount;
|
|
149
|
+
resolve: typeof resolve;
|
|
150
|
+
cacheControlFor: typeof cacheControlFor;
|
|
151
|
+
looksLikeFile: typeof looksLikeFile;
|
|
152
|
+
normalizePathname: typeof normalizePathname;
|
|
153
|
+
excluder: typeof excluder;
|
|
154
|
+
routeSegments: typeof routeSegments;
|
|
155
|
+
isUnderRoute: typeof isUnderRoute;
|
|
156
|
+
apiBoundary: typeof apiBoundary;
|
|
157
|
+
acceptsHtml: typeof acceptsHtml;
|
|
158
|
+
shouldFallBack: typeof shouldFallBack;
|
|
159
|
+
};
|
|
160
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type { StartOptions } from "./app/index.js";
|
|
2
|
+
export * from "./app/index.js";
|
|
3
|
+
export * from "./auth/index.js";
|
|
4
|
+
export * from "./builder/index.js";
|
|
5
|
+
export * from "./const.js";
|
|
6
|
+
export * from "./health/index.js";
|
|
7
|
+
export * from "./hosting/index.js";
|
|
8
|
+
export * from "./openapi/index.js";
|
|
9
|
+
export * from "./routing/index.js";
|
|
10
|
+
export * from "./sse/index.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { ValidationIssue } from "../routing/anvil.types.js";
|
|
2
|
+
export { generateOpenApiDocument, resolveOpenApiPath, toOpenApiPath, } from "./openapi.generator.js";
|
|
3
|
+
export type { JsonSchema, OpenApiDocument, OpenApiOperation, OpenApiOptions, OpenApiParameter, } from "./openapi.types.js";
|
|
4
|
+
export type { RouteRequestSchemas } from "./request-schema.js";
|
|
5
|
+
export { buildRouteRequestSchemas, mergeObjectSchemas, objectArgToParts, pathParamsToSchema, typeToSchema, } from "./request-schema.js";
|
|
6
|
+
export { ValidationError, validateRequest } from "./request-validator.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RouteRegistry } from "../routing/services/route-registry.js";
|
|
2
|
+
import type { OpenApiDocument, OpenApiOptions } from "./openapi.types.js";
|
|
3
|
+
export declare function resolveOpenApiPath(options: OpenApiOptions): string;
|
|
4
|
+
/** Convert Fastify-style `:id` path params to OpenAPI `{id}`. */
|
|
5
|
+
export declare function toOpenApiPath(fastifyPath: string): string;
|
|
6
|
+
export declare function generateOpenApiDocument(registry: RouteRegistry, options: OpenApiOptions): OpenApiDocument;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type OpenApiInfo = {
|
|
2
|
+
title: string;
|
|
3
|
+
version: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
};
|
|
6
|
+
export type OpenApiServer = {
|
|
7
|
+
url: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
};
|
|
10
|
+
export type OpenApiOptions = {
|
|
11
|
+
/** Defaults to `/openapi.json`. Absolute Fastify path (not affected by globalPrefix). */
|
|
12
|
+
path?: string;
|
|
13
|
+
info: OpenApiInfo;
|
|
14
|
+
servers?: OpenApiServer[];
|
|
15
|
+
/** When true (default), validate request params/query/body before the handler. */
|
|
16
|
+
validateRequests?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export type JsonSchema = {
|
|
19
|
+
type?: string;
|
|
20
|
+
properties?: Record<string, JsonSchema>;
|
|
21
|
+
required?: string[];
|
|
22
|
+
items?: JsonSchema;
|
|
23
|
+
additionalProperties?: boolean | JsonSchema;
|
|
24
|
+
format?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
minLength?: number;
|
|
27
|
+
maxLength?: number;
|
|
28
|
+
};
|
|
29
|
+
export type OpenApiParameter = {
|
|
30
|
+
name: string;
|
|
31
|
+
in: "query" | "path" | "header" | "cookie";
|
|
32
|
+
required?: boolean;
|
|
33
|
+
schema?: JsonSchema;
|
|
34
|
+
};
|
|
35
|
+
export type OpenApiOperation = {
|
|
36
|
+
operationId?: string;
|
|
37
|
+
summary?: string;
|
|
38
|
+
tags?: string[];
|
|
39
|
+
parameters?: OpenApiParameter[];
|
|
40
|
+
requestBody?: {
|
|
41
|
+
required?: boolean;
|
|
42
|
+
content: Record<string, {
|
|
43
|
+
schema: JsonSchema;
|
|
44
|
+
}>;
|
|
45
|
+
};
|
|
46
|
+
responses: Record<string, {
|
|
47
|
+
description: string;
|
|
48
|
+
content?: Record<string, {
|
|
49
|
+
schema: JsonSchema;
|
|
50
|
+
}>;
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
53
|
+
export type OpenApiDocument = {
|
|
54
|
+
openapi: "3.0.3";
|
|
55
|
+
info: OpenApiInfo;
|
|
56
|
+
servers?: OpenApiServer[];
|
|
57
|
+
paths: Record<string, Partial<Record<string, OpenApiOperation>>>;
|
|
58
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type MappedRoute, type RouteArg } from "../routing/anvil.types.js";
|
|
2
|
+
import type { JsonSchema, OpenApiParameter } from "./openapi.types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Request shapes derived from route / `@Field` metadata (same source as OpenAPI).
|
|
5
|
+
* Used by the document generator and the AJV request validator.
|
|
6
|
+
*/
|
|
7
|
+
export type RouteRequestSchemas = {
|
|
8
|
+
queryParams: OpenApiParameter[];
|
|
9
|
+
pathParams: OpenApiParameter[];
|
|
10
|
+
body?: JsonSchema;
|
|
11
|
+
};
|
|
12
|
+
export declare function buildRouteRequestSchemas(route: MappedRoute): RouteRequestSchemas;
|
|
13
|
+
export declare function objectArgToParts(routeArg: RouteArg): {
|
|
14
|
+
queryParams: OpenApiParameter[];
|
|
15
|
+
pathParams: OpenApiParameter[];
|
|
16
|
+
body?: JsonSchema;
|
|
17
|
+
};
|
|
18
|
+
export declare function mergeObjectSchemas(a: JsonSchema | undefined, b: JsonSchema): JsonSchema;
|
|
19
|
+
export declare function typeToSchema(typeName?: string): JsonSchema;
|
|
20
|
+
/** JSON Schema object for required path params (HTTP path values are always strings). */
|
|
21
|
+
export declare function pathParamsToSchema(params: OpenApiParameter[]): JsonSchema | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HttpRequest, MappedRoute, ValidationIssue } from "../routing/anvil.types.js";
|
|
2
|
+
import { ValidationError } from "../routing/anvil.types.js";
|
|
3
|
+
export type { ValidationIssue };
|
|
4
|
+
export { ValidationError };
|
|
5
|
+
/**
|
|
6
|
+
* Fail-closed request validation from route / OpenAPI / `@Field` metadata.
|
|
7
|
+
* Uses AJV against the same schemas as the OpenAPI generator (no type coercion).
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateRequest(route: MappedRoute, request: HttpRequest): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type FastifyInstance } from "fastify";
|
|
2
|
+
import type { HttpOptions } from "../http/http.options.js";
|
|
3
|
+
import { type HttpProvider, type StartOptions, type StartResponse, type StopResponse } from "../routing/anvil.types.js";
|
|
4
|
+
import { type ExceptionFilterHost } from "../routing/filters/exception-filter-host.js";
|
|
5
|
+
import type { RouteRegistry } from "../routing/services/route-registry.js";
|
|
6
|
+
import type { Router } from "../routing/services/router.js";
|
|
7
|
+
export declare class FastifyProvider implements HttpProvider {
|
|
8
|
+
readonly provider: FastifyInstance;
|
|
9
|
+
readonly router: Router;
|
|
10
|
+
private readonly routeRegistry;
|
|
11
|
+
private readonly httpOptions?;
|
|
12
|
+
private readonly exceptionFilterHost?;
|
|
13
|
+
private closing;
|
|
14
|
+
private readonly logger;
|
|
15
|
+
/** One per live `@Sse()` request, so stopping the app can end the streams. */
|
|
16
|
+
private readonly openStreams;
|
|
17
|
+
constructor(routeRegistry?: RouteRegistry, router?: Router, httpOptions?: HttpOptions, exceptionFilterHost?: ExceptionFilterHost);
|
|
18
|
+
start<T extends StartOptions>(options?: T): Promise<StartResponse>;
|
|
19
|
+
stop(): Promise<StopResponse>;
|
|
20
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Once stopping, tell clients to drop the connection after their response. Otherwise
|
|
23
|
+
* a request that was in flight leaves a kept-alive socket that holds `close()` open
|
|
24
|
+
* until Node's keep-alive timeout (5s).
|
|
25
|
+
*/
|
|
26
|
+
private closeConnectionsWhileStopping;
|
|
27
|
+
get addresses(): string[];
|
|
28
|
+
private registerHelmet;
|
|
29
|
+
private registerRateLimit;
|
|
30
|
+
private resolveStatics;
|
|
31
|
+
/**
|
|
32
|
+
* One encapsulated context per mount: its not-found handler (the SPA fallback) applies to
|
|
33
|
+
* paths under the prefix and nowhere else, so an API 404 is never answered with the UI.
|
|
34
|
+
*/
|
|
35
|
+
private registerStatic;
|
|
36
|
+
/** What the static fallback leaves to the API: the global prefix, else the registered routes. ADR 0007. */
|
|
37
|
+
private apiBoundary;
|
|
38
|
+
/**
|
|
39
|
+
* `@fastify/compress` with best-practice defaults; the plugin owns the policy. Registered
|
|
40
|
+
* before any route so every response goes through it, errors and static files included.
|
|
41
|
+
* `providerOptions` is merged last, so a user can override any plugin option.
|
|
42
|
+
*/
|
|
43
|
+
private registerCompression;
|
|
44
|
+
private registerCors;
|
|
45
|
+
private registerOpenApi;
|
|
46
|
+
private registerAllRoutes;
|
|
47
|
+
private routeRequest;
|
|
48
|
+
/**
|
|
49
|
+
* Gives the handler a signal that aborts when the client goes away before the response
|
|
50
|
+
* finished. Streams are also tracked so that stopping the app can abort them.
|
|
51
|
+
*/
|
|
52
|
+
private abortOnDisconnect;
|
|
53
|
+
private sendEventStream;
|
|
54
|
+
private applyResponseHeaders;
|
|
55
|
+
private fastifyToRequest;
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./fastify.provider.js";
|