@authuser/nest 0.1.1 → 0.2.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 +39 -0
- package/README.md +33 -15
- package/dist/configure-http-app.d.ts.map +1 -1
- package/dist/configure-http-app.js +5 -4
- package/dist/configure-http-app.js.map +1 -1
- package/dist/create-app.d.ts +4 -0
- package/dist/create-app.d.ts.map +1 -0
- package/dist/{create-http-app.js → create-app.js} +28 -6
- package/dist/create-app.js.map +1 -0
- package/dist/http-exception.filter.js +15 -6
- package/dist/http-exception.filter.js.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +4 -1
- package/dist/openapi.js.map +1 -1
- package/dist/options.d.ts +2 -2
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +41 -2
- package/dist/options.js.map +1 -1
- package/dist/types.d.ts +12 -9
- package/dist/types.d.ts.map +1 -1
- package/docs/configuration.md +19 -6
- package/docs/migration.md +10 -7
- package/docs/performance.md +15 -1
- package/docs/security.md +5 -0
- package/package.json +23 -7
- package/dist/authuser.module.d.ts +0 -12
- package/dist/authuser.module.d.ts.map +0 -1
- package/dist/authuser.module.js +0 -32
- package/dist/authuser.module.js.map +0 -1
- package/dist/create-http-app.d.ts +0 -6
- package/dist/create-http-app.d.ts.map +0 -1
- package/dist/create-http-app.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,45 @@ This project uses [Semantic Versioning](https://semver.org/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2026-09-03
|
|
9
|
+
|
|
10
|
+
### Security
|
|
11
|
+
|
|
12
|
+
- Require maintained Node.js 22 or newer.
|
|
13
|
+
- Add finite connection, request, handler and header timeouts.
|
|
14
|
+
- Redact sensitive authentication and cookie log fields by default.
|
|
15
|
+
- Validate unsafe CORS, invalid rate limits, route collisions and network limits.
|
|
16
|
+
- Preserve native Fastify HTTP errors such as rate-limit responses.
|
|
17
|
+
- Allow OpenAPI and health routes to be protected with pre-handler hooks.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Load optional Fastify integrations dynamically.
|
|
22
|
+
- Expose the complete distributed `@fastify/rate-limit` configuration surface.
|
|
23
|
+
- Move Nest and Fastify to peer dependencies to prevent duplicate framework copies.
|
|
24
|
+
- Remove the disconnected `AuthuserModule` configuration API.
|
|
25
|
+
|
|
26
|
+
### Development
|
|
27
|
+
|
|
28
|
+
- Add Node 22/24/26 CI, CodeQL, Dependabot and a dependency-free benchmark harness.
|
|
29
|
+
- Raise automated coverage and enforce coverage thresholds.
|
|
30
|
+
|
|
31
|
+
## [0.1.2] - 2026-09-03
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- `createApp` as the concise primary application factory.
|
|
36
|
+
|
|
37
|
+
### Removed
|
|
38
|
+
|
|
39
|
+
- `createNestApp`, `createHttpApp`, and the legacy `CreateHttpAppOptions` type.
|
|
40
|
+
|
|
41
|
+
## [0.1.1] - 2026-09-03
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- Point npm documentation links to the public GitHub repository.
|
|
46
|
+
|
|
8
47
|
## [0.1.0] - 2026-09-03
|
|
9
48
|
|
|
10
49
|
### Added
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<p align="center">
|
|
7
7
|
<a href="https://www.npmjs.com/package/@authuser/nest"><img alt="npm" src="https://img.shields.io/npm/v/%40authuser%2Fnest?style=flat-square"></a>
|
|
8
8
|
<a href="https://www.npmjs.com/package/@authuser/nest"><img alt="downloads" src="https://img.shields.io/npm/dm/%40authuser%2Fnest?style=flat-square"></a>
|
|
9
|
-
<img alt="Node
|
|
9
|
+
<img alt="Node 22+" src="https://img.shields.io/badge/node-%3E%3D22-339933?style=flat-square&logo=node.js&logoColor=white">
|
|
10
10
|
<img alt="NestJS 12" src="https://img.shields.io/badge/NestJS-12-E0234E?style=flat-square&logo=nestjs&logoColor=white">
|
|
11
11
|
<img alt="Fastify 5" src="https://img.shields.io/badge/Fastify-5-black?style=flat-square&logo=fastify">
|
|
12
12
|
<a href="https://github.com/authuser-org/nest/blob/main/LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-green?style=flat-square"></a>
|
|
@@ -28,6 +28,8 @@ intact while removing repetitive bootstrap code.
|
|
|
28
28
|
- Fast path: request logs, compression and Swagger UI are off unless requested.
|
|
29
29
|
- Secure defaults: Helmet, strict DTO validation, bounded bodies, strict CORS and
|
|
30
30
|
rate limiting.
|
|
31
|
+
- Finite request, handler, header and connection timeouts.
|
|
32
|
+
- Sensitive authorization, cookie and set-cookie log fields are redacted by default.
|
|
31
33
|
- OpenAPI is optional at runtime. Its code is dynamically imported only when enabled.
|
|
32
34
|
- HTTP QUERY (RFC 10008) passes through Nest 12/Fastify 5 and is included in CORS defaults.
|
|
33
35
|
- Native ESM, strict declarations and a TypeScript 7 toolchain.
|
|
@@ -35,7 +37,7 @@ intact while removing repetitive bootstrap code.
|
|
|
35
37
|
|
|
36
38
|
## Requirements
|
|
37
39
|
|
|
38
|
-
- Node.js
|
|
40
|
+
- Node.js 22 or newer (Node.js 24 LTS recommended for production)
|
|
39
41
|
- An ESM project is recommended (`"type": "module"`)
|
|
40
42
|
|
|
41
43
|
## Install
|
|
@@ -44,18 +46,19 @@ intact while removing repetitive bootstrap code.
|
|
|
44
46
|
npm install @authuser/nest
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
Nest and Fastify are peer dependencies so an application never loads duplicate
|
|
50
|
+
framework instances. npm 7+ installs them when missing and reuses compatible copies
|
|
51
|
+
already present in a Nest project. Runtime integrations such as `@nestjs/swagger`,
|
|
52
|
+
validation and the Fastify plugins remain included.
|
|
50
53
|
|
|
51
54
|
## Quick start
|
|
52
55
|
|
|
53
56
|
```ts
|
|
54
57
|
// src/main.ts
|
|
55
|
-
import {
|
|
58
|
+
import { createApp } from '@authuser/nest';
|
|
56
59
|
import { AppModule } from './app.module.js';
|
|
57
60
|
|
|
58
|
-
const app = await
|
|
61
|
+
const app = await createApp({
|
|
59
62
|
rootModule: AppModule,
|
|
60
63
|
appName: 'users-api',
|
|
61
64
|
preset: 'secure',
|
|
@@ -69,8 +72,8 @@ await app.listen({ port: 3000, host: '0.0.0.0' });
|
|
|
69
72
|
```
|
|
70
73
|
|
|
71
74
|
That application has Helmet, rate limiting, safe request IDs, strict validation,
|
|
72
|
-
a 1 MiB body limit and graceful shutdown hooks. Cross-origin
|
|
73
|
-
enabled implicitly.
|
|
75
|
+
a 1 MiB body limit, finite timeouts and graceful shutdown hooks. Cross-origin
|
|
76
|
+
requests are not enabled implicitly.
|
|
74
77
|
|
|
75
78
|
## Presets
|
|
76
79
|
|
|
@@ -88,7 +91,7 @@ OpenAPI is installed but disabled with `minimal` and `secure`. Enable only the
|
|
|
88
91
|
machine-readable document:
|
|
89
92
|
|
|
90
93
|
```ts
|
|
91
|
-
const app = await
|
|
94
|
+
const app = await createApp({
|
|
92
95
|
rootModule: AppModule,
|
|
93
96
|
openApi: {
|
|
94
97
|
enabled: true,
|
|
@@ -113,6 +116,19 @@ openApi: {
|
|
|
113
116
|
For an internet-facing production service, prefer exporting the JSON during CI or
|
|
114
117
|
protecting documentation routes at the gateway.
|
|
115
118
|
|
|
119
|
+
Documentation and health routes can also be protected directly:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const protectInternalRoute = async (request, reply) => {
|
|
123
|
+
if (request.headers.authorization !== `Bearer ${process.env.INTERNAL_TOKEN}`) {
|
|
124
|
+
return reply.code(401).send({ error: 'Unauthorized' });
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
openApi: { enabled: true, preHandler: protectInternalRoute },
|
|
129
|
+
health: { enabled: true, preHandler: protectInternalRoute },
|
|
130
|
+
```
|
|
131
|
+
|
|
116
132
|
## Configuration examples
|
|
117
133
|
|
|
118
134
|
### CORS allowlist
|
|
@@ -139,6 +155,9 @@ security: {
|
|
|
139
155
|
Never enable `trustProxy: true` unless every direct connection comes through a
|
|
140
156
|
trusted proxy; client IPs are used as rate-limit keys.
|
|
141
157
|
|
|
158
|
+
For multiple replicas, pass the plugin's `redis` client or a custom `store`; the
|
|
159
|
+
in-memory default only coordinates requests inside one Node process.
|
|
160
|
+
|
|
142
161
|
### Existing Nest + Fastify application
|
|
143
162
|
|
|
144
163
|
```ts
|
|
@@ -155,10 +174,8 @@ its plugins and routes.
|
|
|
155
174
|
|
|
156
175
|
## Public API
|
|
157
176
|
|
|
158
|
-
- `
|
|
177
|
+
- `createApp(options)` — create and configure an application.
|
|
159
178
|
- `configureHttpApp(app, options)` — configure an existing Fastify-based Nest app.
|
|
160
|
-
- `AuthuserModule.forRoot(options)` — expose immutable options through Nest DI.
|
|
161
|
-
- `AUTHUSER_OPTIONS` — injection token for those options.
|
|
162
179
|
- `Public()` and `Roles(...roles)` — metadata helpers for your own guards.
|
|
163
180
|
- `HttpExceptionFilter` — the default safe JSON exception filter.
|
|
164
181
|
|
|
@@ -179,13 +196,14 @@ application before trading away Nest maintainability.
|
|
|
179
196
|
|
|
180
197
|
For the hottest path, use `preset: 'minimal'`, leave request logging and compression
|
|
181
198
|
off, declare response schemas in Fastify-compatible routes, and benchmark with your
|
|
182
|
-
actual payloads.
|
|
199
|
+
actual payloads. Run `npm run benchmark` to compare raw Fastify with both package
|
|
200
|
+
presets. See the [performance guide](https://github.com/authuser-org/nest/blob/main/docs/performance.md).
|
|
183
201
|
|
|
184
202
|
## Migration from `@authuser/nest-fastify-kit`
|
|
185
203
|
|
|
186
204
|
```diff
|
|
187
205
|
- import { createHttpApp } from '@authuser/nest-fastify-kit';
|
|
188
|
-
+ import {
|
|
206
|
+
+ import { createApp } from '@authuser/nest';
|
|
189
207
|
```
|
|
190
208
|
|
|
191
209
|
The new package targets Nest 12, uses ESM, calls Swagger configuration `openApi`, and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure-http-app.d.ts","sourceRoot":"","sources":["../src/configure-http-app.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"configure-http-app.d.ts","sourceRoot":"","sources":["../src/configure-http-app.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAKvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,sBAAsB,EAC3B,KAAK,GAAE,uBAA4B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAgEjC"}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import compress from '@fastify/compress';
|
|
2
|
-
import cors from '@fastify/cors';
|
|
3
|
-
import helmet from '@fastify/helmet';
|
|
4
|
-
import rateLimit from '@fastify/rate-limit';
|
|
5
1
|
import { ValidationPipe, VersioningType } from '@nestjs/common';
|
|
6
2
|
import { HttpExceptionFilter } from './http-exception.filter.js';
|
|
7
3
|
import { registerOpenApi } from './openapi.js';
|
|
@@ -10,19 +6,23 @@ export async function configureHttpApp(app, input = {}) {
|
|
|
10
6
|
const options = resolveOptions(input);
|
|
11
7
|
const fastify = app.getHttpAdapter().getInstance();
|
|
12
8
|
if (options.security.helmet) {
|
|
9
|
+
const { default: helmet } = await import('@fastify/helmet');
|
|
13
10
|
await fastify.register(helmet, {
|
|
14
11
|
global: true,
|
|
15
12
|
contentSecurityPolicy: options.security.contentSecurityPolicy,
|
|
16
13
|
});
|
|
17
14
|
}
|
|
18
15
|
if (options.security.cors !== false) {
|
|
16
|
+
const { default: cors } = await import('@fastify/cors');
|
|
19
17
|
await fastify.register(cors, options.security.cors);
|
|
20
18
|
}
|
|
21
19
|
if (options.security.rateLimit !== false && options.security.rateLimit.enabled) {
|
|
20
|
+
const { default: rateLimit } = await import('@fastify/rate-limit');
|
|
22
21
|
const { enabled: _enabled, ...rateLimitOptions } = options.security.rateLimit;
|
|
23
22
|
await fastify.register(rateLimit, rateLimitOptions);
|
|
24
23
|
}
|
|
25
24
|
if (options.compression.enabled) {
|
|
25
|
+
const { default: compress } = await import('@fastify/compress');
|
|
26
26
|
await fastify.register(compress, {
|
|
27
27
|
threshold: options.compression.threshold,
|
|
28
28
|
encodings: options.compression.encodings,
|
|
@@ -56,6 +56,7 @@ export async function configureHttpApp(app, input = {}) {
|
|
|
56
56
|
if (options.health.enabled) {
|
|
57
57
|
fastify.get(options.health.path, {
|
|
58
58
|
config: { rateLimit: false },
|
|
59
|
+
...(options.health.preHandler ? { preHandler: options.health.preHandler } : {}),
|
|
59
60
|
}, async (_request, reply) => reply.send(options.health.response));
|
|
60
61
|
}
|
|
61
62
|
await registerOpenApi(app, fastify, options.openApi);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure-http-app.js","sourceRoot":"","sources":["../src/configure-http-app.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"configure-http-app.js","sourceRoot":"","sources":["../src/configure-http-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-app.d.ts","sourceRoot":"","sources":["../src/create-app.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAmC1F"}
|
|
@@ -5,9 +5,10 @@ import { FastifyAdapter, } from '@nestjs/platform-fastify';
|
|
|
5
5
|
import { configureHttpApp } from './configure-http-app.js';
|
|
6
6
|
import { resolveOptions } from './options.js';
|
|
7
7
|
const SAFE_REQUEST_ID = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
8
|
-
export async function
|
|
8
|
+
export async function createApp(options) {
|
|
9
9
|
const resolved = resolveOptions(options);
|
|
10
10
|
const network = options.network ?? {};
|
|
11
|
+
validateNetworkOptions(network);
|
|
11
12
|
const adapter = new FastifyAdapter({
|
|
12
13
|
logger: resolved.observability.logger,
|
|
13
14
|
logController: new LogController({
|
|
@@ -16,22 +17,43 @@ export async function createHttpApp(options) {
|
|
|
16
17
|
trustProxy: network.trustProxy ?? false,
|
|
17
18
|
bodyLimit: network.bodyLimit ?? 1_048_576,
|
|
18
19
|
routerOptions: { maxParamLength: network.maxParamLength ?? 100 },
|
|
19
|
-
connectionTimeout: network.connectionTimeout ??
|
|
20
|
-
requestTimeout: network.requestTimeout ??
|
|
20
|
+
connectionTimeout: network.connectionTimeout ?? 10_000,
|
|
21
|
+
requestTimeout: network.requestTimeout ?? 30_000,
|
|
22
|
+
handlerTimeout: network.handlerTimeout ?? 30_000,
|
|
21
23
|
keepAliveTimeout: network.keepAliveTimeout ?? 72_000,
|
|
24
|
+
maxRequestsPerSocket: network.maxRequestsPerSocket ?? 1_000,
|
|
25
|
+
return503OnClosing: true,
|
|
26
|
+
onProtoPoisoning: 'error',
|
|
27
|
+
onConstructorPoisoning: 'error',
|
|
22
28
|
requestIdHeader: 'x-request-id',
|
|
23
29
|
genReqId: safeRequestId,
|
|
24
30
|
});
|
|
31
|
+
adapter.getInstance().server.headersTimeout = network.headersTimeout ?? 30_000;
|
|
25
32
|
const nestOptions = resolved.observability.logger === false
|
|
26
33
|
? { ...options.nest, logger: false }
|
|
27
34
|
: { ...options.nest };
|
|
28
35
|
const app = await NestFactory.create(options.rootModule, adapter, nestOptions);
|
|
29
36
|
return configureHttpApp(app, options);
|
|
30
37
|
}
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
function validateNetworkOptions(network) {
|
|
39
|
+
const values = {
|
|
40
|
+
bodyLimit: network.bodyLimit,
|
|
41
|
+
maxParamLength: network.maxParamLength,
|
|
42
|
+
connectionTimeout: network.connectionTimeout,
|
|
43
|
+
requestTimeout: network.requestTimeout,
|
|
44
|
+
handlerTimeout: network.handlerTimeout,
|
|
45
|
+
headersTimeout: network.headersTimeout,
|
|
46
|
+
keepAliveTimeout: network.keepAliveTimeout,
|
|
47
|
+
maxRequestsPerSocket: network.maxRequestsPerSocket,
|
|
48
|
+
};
|
|
49
|
+
for (const [name, value] of Object.entries(values)) {
|
|
50
|
+
if (value !== undefined && (!Number.isSafeInteger(value) || value <= 0)) {
|
|
51
|
+
throw new TypeError(`Network option ${name} must be a positive safe integer`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
33
55
|
function safeRequestId(request) {
|
|
34
56
|
const incoming = request.headers['x-request-id'];
|
|
35
57
|
return typeof incoming === 'string' && SAFE_REQUEST_ID.test(incoming) ? incoming : randomUUID();
|
|
36
58
|
}
|
|
37
|
-
//# sourceMappingURL=create-
|
|
59
|
+
//# sourceMappingURL=create-app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-app.js","sourceRoot":"","sources":["../src/create-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,12 +32,21 @@ function getHttpException(exception) {
|
|
|
32
32
|
if (typeof exception !== 'object' || exception === null)
|
|
33
33
|
return undefined;
|
|
34
34
|
const candidate = exception;
|
|
35
|
-
if (typeof candidate.getStatus
|
|
36
|
-
|
|
35
|
+
if (typeof candidate.getStatus === 'function' && typeof candidate.getResponse === 'function') {
|
|
36
|
+
const status = candidate.getStatus.call(exception);
|
|
37
|
+
return isHttpErrorStatus(status) ? candidate : undefined;
|
|
38
|
+
}
|
|
39
|
+
if (isHttpErrorStatus(candidate.statusCode)) {
|
|
40
|
+
const status = candidate.statusCode;
|
|
41
|
+
const message = typeof candidate.message === 'string' ? candidate.message : 'Request failed';
|
|
42
|
+
return {
|
|
43
|
+
getStatus: () => status,
|
|
44
|
+
getResponse: () => ({ message }),
|
|
45
|
+
};
|
|
37
46
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
function isHttpErrorStatus(value) {
|
|
50
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= 400 && value <= 599;
|
|
42
51
|
}
|
|
43
52
|
//# sourceMappingURL=http-exception.filter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-exception.filter.js","sourceRoot":"","sources":["../src/http-exception.filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,EACL,aAAa,EACb,UAAU,GAEX,MAAM,gBAAgB,CAAC;AAGxB,MAAM,OAAO,mBAAmB;IAC9B,KAAK,CAAC,SAAkB,EAAE,IAAmB;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAgB,CAAC;QAClD,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,EAAkB,CAAC;QACrD,MAAM,aAAa,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,aAAa,EAAE,SAAS,EAAE,IAAI,UAAU,CAAC,qBAAqB,CAAC;QAC9E,MAAM,QAAQ,GAAG,aAAa,EAAE,WAAW,EAAE,CAAC;QAC9C,MAAM,OAAO,GAAG,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,MAAM,OAAO,GAAG,OAAO,QAAQ,KAAK,QAAQ;YAC1C,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;QAEzF,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,yBAAyB,CAAC,CAAC;QAErF,KAAK,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;YAC7B,UAAU,EAAE,MAAM;YAClB,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,OAAO;YACpC,OAAO;YACP,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,IAAI,EAAE,OAAO,CAAC,GAAG;SAClB,CAAC,CAAC;IACL,CAAC;CACF;AAED,KAAK,EAAE,CAAC,mBAAmB,CAAC,CAAC;AAE7B,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AAOD,SAAS,gBAAgB,CAAC,SAAkB;IAC1C,IAAI,SAAS,YAAY,aAAa;QAAE,OAAO,SAAS,CAAC;IACzD,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAE1E,MAAM,SAAS,GAAG,
|
|
1
|
+
{"version":3,"file":"http-exception.filter.js","sourceRoot":"","sources":["../src/http-exception.filter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
export { AuthuserModule, AUTHUSER_OPTIONS } from './authuser.module.js';
|
|
3
|
-
export type { AuthuserModuleAsyncOptions } from './authuser.module.js';
|
|
4
2
|
export { configureHttpApp } from './configure-http-app.js';
|
|
5
|
-
export {
|
|
3
|
+
export { createApp } from './create-app.js';
|
|
6
4
|
export { Public, Roles, IS_PUBLIC_KEY, ROLES_KEY } from './decorators.js';
|
|
7
5
|
export { HttpExceptionFilter } from './http-exception.filter.js';
|
|
8
|
-
export type { CompressionOptions, ConfigureHttpAppOptions, CorsOptions,
|
|
6
|
+
export type { CompressionOptions, ConfigureHttpAppOptions, CorsOptions, CreateAppOptions, HealthOptions, NetworkOptions, ObservabilityOptions, OpenApiOptions, RateLimitOptions, SecurityOptions, SecurityPreset, } from './types.js';
|
|
9
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
export { AuthuserModule, AUTHUSER_OPTIONS } from './authuser.module.js';
|
|
3
2
|
export { configureHttpApp } from './configure-http-app.js';
|
|
4
|
-
export {
|
|
3
|
+
export { createApp } from './create-app.js';
|
|
5
4
|
export { Public, Roles, IS_PUBLIC_KEY, ROLES_KEY } from './decorators.js';
|
|
6
5
|
export { HttpExceptionFilter } from './http-exception.filter.js';
|
|
7
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/openapi.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAsB,eAAe,CACnC,GAAG,EAAE,sBAAsB,EAC3B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAsB,eAAe,CACnC,GAAG,EAAE,sBAAsB,EAC3B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAkCf"}
|
package/dist/openapi.js
CHANGED
|
@@ -10,7 +10,9 @@ export async function registerOpenApi(app, fastify, options) {
|
|
|
10
10
|
builder = builder.addBearerAuth();
|
|
11
11
|
const document = SwaggerModule.createDocument(app, builder.build());
|
|
12
12
|
if (options.json) {
|
|
13
|
-
fastify.get(options.jsonPath,
|
|
13
|
+
fastify.get(options.jsonPath, {
|
|
14
|
+
...(options.preHandler ? { preHandler: options.preHandler } : {}),
|
|
15
|
+
}, async (_request, reply) => reply.send(document));
|
|
14
16
|
}
|
|
15
17
|
if (options.ui) {
|
|
16
18
|
const { default: swagger } = await import('@fastify/swagger');
|
|
@@ -25,6 +27,7 @@ export async function registerOpenApi(app, fastify, options) {
|
|
|
25
27
|
uiConfig: { docExpansion: 'list', deepLinking: true, spec: document },
|
|
26
28
|
staticCSP: true,
|
|
27
29
|
transformStaticCSP: (header) => header,
|
|
30
|
+
...(options.preHandler ? { uiHooks: { preHandler: options.preHandler } } : {}),
|
|
28
31
|
});
|
|
29
32
|
}
|
|
30
33
|
}
|
package/dist/openapi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAA2B,EAC3B,OAAwB,EACxB,OAAmC;IAEnC,IAAI,CAAC,OAAO,CAAC,OAAO;QAAE,OAAO;IAE7B,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAC3E,IAAI,OAAO,GAAG,IAAI,eAAe,EAAE;SAChC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;SACvB,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC;SACnC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,OAAO,CAAC,UAAU;QAAE,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAE1D,MAAM,QAAQ,GAAG,aAAa,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAEpE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAA2B,EAC3B,OAAwB,EACxB,OAAmC;IAEnC,IAAI,CAAC,OAAO,CAAC,OAAO;QAAE,OAAO;IAE7B,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAC3E,IAAI,OAAO,GAAG,IAAI,eAAe,EAAE;SAChC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;SACvB,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC;SACnC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,OAAO,CAAC,UAAU;QAAE,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAE1D,MAAM,QAAQ,GAAG,aAAa,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAEpE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE;YAC5B,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClE,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC9D,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACnE,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE;YAC9B,IAAI,EAAE,QAAQ;YACd,+EAA+E;YAC/E,aAAa,EAAE,EAAE,QAAQ,EAAE,QAAiB,EAAE;SAC/C,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE;YAChC,WAAW,EAAE,OAAO,CAAC,MAAM;YAC3B,QAAQ,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;YACrE,SAAS,EAAE,IAAI;YACf,kBAAkB,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;YACtC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/E,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
package/dist/options.d.ts
CHANGED
|
@@ -12,8 +12,8 @@ export interface ResolvedOptions {
|
|
|
12
12
|
rateLimit: false | (Required<Pick<RateLimitOptions, 'enabled' | 'max' | 'timeWindow' | 'ban'>> & RateLimitOptions);
|
|
13
13
|
};
|
|
14
14
|
compression: Required<CompressionOptions>;
|
|
15
|
-
openApi: Required<OpenApiOptions>;
|
|
16
|
-
health: Required<HealthOptions>;
|
|
15
|
+
openApi: Required<Omit<OpenApiOptions, 'preHandler'>> & Pick<OpenApiOptions, 'preHandler'>;
|
|
16
|
+
health: Required<Omit<HealthOptions, 'preHandler'>> & Pick<HealthOptions, 'preHandler'>;
|
|
17
17
|
observability: Required<NonNullable<ConfigureHttpAppOptions['observability']>>;
|
|
18
18
|
shutdownHooks: boolean;
|
|
19
19
|
}
|
package/dist/options.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,uBAAuB,CAAC,YAAY,CAAC,CAAC;IAClD,UAAU,EAAE,uBAAuB,CAAC,YAAY,CAAC,CAAC;IAClD,QAAQ,EAAE;QACR,MAAM,EAAE,OAAO,CAAC;QAChB,qBAAqB,EAAE,OAAO,CAAC;QAC/B,IAAI,EAAE,KAAK,GAAG,WAAW,CAAC;QAC1B,SAAS,EAAE,KAAK,IAAG,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,KAAK,GAAG,YAAY,GAAG,KAAK,CAAC,CAAC,GAAG,gBAAgB,CAAA,CAAC;KAClH,CAAC;IACF,WAAW,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC1C,OAAO,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,uBAAuB,CAAC,YAAY,CAAC,CAAC;IAClD,UAAU,EAAE,uBAAuB,CAAC,YAAY,CAAC,CAAC;IAClD,QAAQ,EAAE;QACR,MAAM,EAAE,OAAO,CAAC;QAChB,qBAAqB,EAAE,OAAO,CAAC;QAC/B,IAAI,EAAE,KAAK,GAAG,WAAW,CAAC;QAC1B,SAAS,EAAE,KAAK,IAAG,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,KAAK,GAAG,YAAY,GAAG,KAAK,CAAC,CAAC,GAAG,gBAAgB,CAAA,CAAC;KAClH,CAAC;IACF,WAAW,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC1C,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAC3F,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACxF,aAAa,EAAE,QAAQ,CAAC,WAAW,CAAC,uBAAuB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC/E,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,uBAAuB,GAAG,eAAe,CAqFhF"}
|
package/dist/options.js
CHANGED
|
@@ -7,6 +7,9 @@ export function resolveOptions(options) {
|
|
|
7
7
|
const compressionInput = typeof options.compression === 'object' ? options.compression : {};
|
|
8
8
|
const openApiInput = typeof options.openApi === 'object' ? options.openApi : {};
|
|
9
9
|
const healthInput = typeof options.health === 'object' ? options.health : {};
|
|
10
|
+
const openApiEnabled = typeof options.openApi === 'boolean'
|
|
11
|
+
? options.openApi
|
|
12
|
+
: openApiInput.enabled ?? openApiInput.ui ?? isFull;
|
|
10
13
|
const resolved = {
|
|
11
14
|
appName: options.appName ?? 'nest-api',
|
|
12
15
|
preset,
|
|
@@ -51,7 +54,7 @@ export function resolveOptions(options) {
|
|
|
51
54
|
encodings: compressionInput.encodings ?? ['br', 'gzip', 'deflate'],
|
|
52
55
|
},
|
|
53
56
|
openApi: {
|
|
54
|
-
enabled:
|
|
57
|
+
enabled: openApiEnabled,
|
|
55
58
|
title: openApiInput.title ?? options.appName ?? 'Nest API',
|
|
56
59
|
description: openApiInput.description ?? '',
|
|
57
60
|
version: openApiInput.version ?? '1.0.0',
|
|
@@ -60,14 +63,16 @@ export function resolveOptions(options) {
|
|
|
60
63
|
ui: openApiInput.ui ?? false,
|
|
61
64
|
uiPath: normalizePath(openApiInput.uiPath ?? '/docs'),
|
|
62
65
|
bearerAuth: openApiInput.bearerAuth ?? false,
|
|
66
|
+
...(openApiInput.preHandler ? { preHandler: openApiInput.preHandler } : {}),
|
|
63
67
|
},
|
|
64
68
|
health: {
|
|
65
69
|
enabled: typeof options.health === 'boolean' ? options.health : healthInput.enabled ?? isFull,
|
|
66
70
|
path: normalizePath(healthInput.path ?? '/health'),
|
|
67
71
|
response: healthInput.response ?? { status: 'ok' },
|
|
72
|
+
...(healthInput.preHandler ? { preHandler: healthInput.preHandler } : {}),
|
|
68
73
|
},
|
|
69
74
|
observability: {
|
|
70
|
-
logger: options.observability?.logger ?? true,
|
|
75
|
+
logger: resolveLogger(options.observability?.logger ?? true),
|
|
71
76
|
requestLogging: options.observability?.requestLogging ?? false,
|
|
72
77
|
responseTimeHeader: options.observability?.responseTimeHeader ?? false,
|
|
73
78
|
},
|
|
@@ -75,10 +80,44 @@ export function resolveOptions(options) {
|
|
|
75
80
|
};
|
|
76
81
|
if (options.apiPrefix !== undefined)
|
|
77
82
|
resolved.apiPrefix = options.apiPrefix.replace(/^\/+|\/+$/g, '');
|
|
83
|
+
validateResolvedOptions(resolved);
|
|
78
84
|
return resolved;
|
|
79
85
|
}
|
|
80
86
|
function normalizePath(path) {
|
|
81
87
|
const normalized = `/${path}`.replace(/\/+/g, '/').replace(/\/$/, '');
|
|
82
88
|
return normalized || '/';
|
|
83
89
|
}
|
|
90
|
+
const SENSITIVE_LOG_PATHS = [
|
|
91
|
+
'req.headers.authorization',
|
|
92
|
+
'req.headers.cookie',
|
|
93
|
+
'res.headers["set-cookie"]',
|
|
94
|
+
];
|
|
95
|
+
function resolveLogger(logger) {
|
|
96
|
+
if (logger === false)
|
|
97
|
+
return false;
|
|
98
|
+
if (logger === true) {
|
|
99
|
+
return { redact: { paths: SENSITIVE_LOG_PATHS, censor: '[REDACTED]' } };
|
|
100
|
+
}
|
|
101
|
+
return logger.redact === undefined
|
|
102
|
+
? { ...logger, redact: { paths: SENSITIVE_LOG_PATHS, censor: '[REDACTED]' } }
|
|
103
|
+
: logger;
|
|
104
|
+
}
|
|
105
|
+
function validateResolvedOptions(options) {
|
|
106
|
+
const cors = options.security.cors;
|
|
107
|
+
if (cors !== false && cors.credentials === true && cors.origin === true) {
|
|
108
|
+
throw new TypeError('CORS credentials cannot be combined with an unrestricted origin');
|
|
109
|
+
}
|
|
110
|
+
const paths = [
|
|
111
|
+
options.health.enabled ? options.health.path : undefined,
|
|
112
|
+
options.openApi.enabled && options.openApi.json ? options.openApi.jsonPath : undefined,
|
|
113
|
+
options.openApi.enabled && options.openApi.ui ? options.openApi.uiPath : undefined,
|
|
114
|
+
].filter((path) => path !== undefined);
|
|
115
|
+
if (new Set(paths).size !== paths.length) {
|
|
116
|
+
throw new TypeError('Health, OpenAPI JSON and Swagger UI paths must be unique');
|
|
117
|
+
}
|
|
118
|
+
const rateLimit = options.security.rateLimit;
|
|
119
|
+
if (rateLimit !== false && typeof rateLimit.max === 'number' && (!Number.isFinite(rateLimit.max) || rateLimit.max <= 0)) {
|
|
120
|
+
throw new TypeError('Rate limit max must be a positive number');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
84
123
|
//# sourceMappingURL=options.js.map
|
package/dist/options.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AA6BA,MAAM,UAAU,cAAc,CAAC,OAAgC;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,QAAQ,CAAC;IAC1C,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IACxC,MAAM,cAAc,GAAG,QAAQ,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC;IACvF,MAAM,gBAAgB,GAAG,OAAO,OAAO,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5F,MAAM,YAAY,GAAG,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,MAAM,WAAW,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAE7E,MAAM,QAAQ,GAAoB;QAChC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,UAAU;QACtC,MAAM;QACN,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK;QACvC,UAAU,EAAE,OAAO,CAAC,UAAU,KAAK,SAAS;YAC1C,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;YACnE,CAAC,CAAC,OAAO,CAAC,UAAU;QACtB,QAAQ,EAAE;YACR,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,QAAQ;YACnC,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB,IAAI,IAAI;YAC7D,IAAI,EAAE,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,KAAK;gBAC1D,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC;oBACE,GAAG,QAAQ,CAAC,IAAI;oBAChB,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK;oBACrC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,IAAI;wBAChC,KAAK;wBACL,MAAM;wBACN,MAAM;wBACN,KAAK;wBACL,OAAO;wBACP,QAAQ;wBACR,SAAS;wBACT,OAAO;qBACR;oBACD,oBAAoB,EAAE,QAAQ,CAAC,IAAI,CAAC,oBAAoB,IAAI,GAAG;oBAC/D,eAAe,EAAE,QAAQ,CAAC,IAAI,CAAC,eAAe,IAAI,IAAI;iBACvD;YACL,SAAS,EAAE,cAAc,KAAK,KAAK;gBACjC,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC;oBACE,GAAG,cAAc;oBACjB,OAAO,EAAE,cAAc,CAAC,OAAO,IAAI,QAAQ;oBAC3C,GAAG,EAAE,cAAc,CAAC,GAAG,IAAI,GAAG;oBAC9B,UAAU,EAAE,cAAc,CAAC,UAAU,IAAI,UAAU;oBACnD,GAAG,EAAE,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC;iBAC9B;SACN;QACD,WAAW,EAAE;YACX,OAAO,EAAE,OAAO,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,IAAI,MAAM;YAC5G,SAAS,EAAE,gBAAgB,CAAC,SAAS,IAAI,IAAI;YAC7C,SAAS,EAAE,gBAAgB,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC;SACnE;QACD,OAAO,EAAE;YACP,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { LoggerOptions } from 'pino';
|
|
2
|
+
import type rateLimit from '@fastify/rate-limit';
|
|
2
3
|
import type { Type, ValidationPipeOptions, VersioningOptions } from '@nestjs/common';
|
|
3
4
|
import type { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
|
|
4
|
-
import type {
|
|
5
|
+
import type { preHandlerHookHandler } from 'fastify';
|
|
5
6
|
export type SecurityPreset = 'minimal' | 'secure' | 'full';
|
|
6
7
|
export interface CorsOptions {
|
|
7
8
|
/** No cross-origin requests are allowed by default. */
|
|
@@ -15,14 +16,9 @@ export interface CorsOptions {
|
|
|
15
16
|
optionsSuccessStatus?: number;
|
|
16
17
|
strictPreflight?: boolean;
|
|
17
18
|
}
|
|
18
|
-
export
|
|
19
|
+
export type RateLimitOptions = Omit<rateLimit.RateLimitPluginOptions, 'global'> & {
|
|
19
20
|
enabled?: boolean;
|
|
20
|
-
|
|
21
|
-
timeWindow?: number | string;
|
|
22
|
-
ban?: number;
|
|
23
|
-
allowList?: string[];
|
|
24
|
-
keyGenerator?: (request: FastifyRequest) => string;
|
|
25
|
-
}
|
|
21
|
+
};
|
|
26
22
|
export interface SecurityOptions {
|
|
27
23
|
helmet?: boolean;
|
|
28
24
|
/** Helmet Content-Security-Policy. Enabled by default. */
|
|
@@ -47,11 +43,15 @@ export interface OpenApiOptions {
|
|
|
47
43
|
ui?: boolean;
|
|
48
44
|
uiPath?: string;
|
|
49
45
|
bearerAuth?: boolean;
|
|
46
|
+
/** Fastify hook for authenticating or restricting the JSON and UI routes. */
|
|
47
|
+
preHandler?: preHandlerHookHandler;
|
|
50
48
|
}
|
|
51
49
|
export interface HealthOptions {
|
|
52
50
|
enabled?: boolean;
|
|
53
51
|
path?: string;
|
|
54
52
|
response?: Readonly<Record<string, unknown>>;
|
|
53
|
+
/** Fastify hook for restricting the health route. */
|
|
54
|
+
preHandler?: preHandlerHookHandler;
|
|
55
55
|
}
|
|
56
56
|
export interface ObservabilityOptions {
|
|
57
57
|
/** Fastify/Pino logging. False removes request logging overhead. */
|
|
@@ -65,7 +65,10 @@ export interface NetworkOptions {
|
|
|
65
65
|
maxParamLength?: number;
|
|
66
66
|
connectionTimeout?: number;
|
|
67
67
|
requestTimeout?: number;
|
|
68
|
+
handlerTimeout?: number;
|
|
69
|
+
headersTimeout?: number;
|
|
68
70
|
keepAliveTimeout?: number;
|
|
71
|
+
maxRequestsPerSocket?: number;
|
|
69
72
|
}
|
|
70
73
|
export interface ConfigureHttpAppOptions {
|
|
71
74
|
appName?: string;
|
|
@@ -80,7 +83,7 @@ export interface ConfigureHttpAppOptions {
|
|
|
80
83
|
observability?: ObservabilityOptions;
|
|
81
84
|
shutdownHooks?: boolean;
|
|
82
85
|
}
|
|
83
|
-
export interface
|
|
86
|
+
export interface CreateAppOptions extends ConfigureHttpAppOptions {
|
|
84
87
|
rootModule: Type<unknown>;
|
|
85
88
|
network?: NetworkOptions;
|
|
86
89
|
nest?: Omit<NestApplicationOptions, 'logger'>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAC;AAC3G,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/docs/configuration.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configuration reference
|
|
2
2
|
|
|
3
|
-
All settings are optional except `rootModule` when using `
|
|
3
|
+
All settings are optional except `rootModule` when using `createApp`.
|
|
4
4
|
|
|
5
5
|
## Application
|
|
6
6
|
|
|
@@ -27,8 +27,14 @@ can hide unexpected input. Enable it explicitly when DTO conversion is required.
|
|
|
27
27
|
| `network.maxParamLength` | `100` | Maximum route parameter length. |
|
|
28
28
|
| `network.trustProxy` | `false` | Fastify trusted-proxy policy. |
|
|
29
29
|
| `network.keepAliveTimeout` | `72000` | Keep-alive timeout in milliseconds. |
|
|
30
|
-
| `network.connectionTimeout` | `
|
|
31
|
-
| `network.requestTimeout` | `
|
|
30
|
+
| `network.connectionTimeout` | `10000` | Socket inactivity timeout. |
|
|
31
|
+
| `network.requestTimeout` | `30000` | Incoming request timeout. |
|
|
32
|
+
| `network.handlerTimeout` | `30000` | Maximum route-handler execution time. |
|
|
33
|
+
| `network.headersTimeout` | `30000` | Maximum time for receiving request headers. |
|
|
34
|
+
| `network.maxRequestsPerSocket` | `1000` | Requests accepted on one keep-alive socket. |
|
|
35
|
+
|
|
36
|
+
Network limits must be positive safe integers. Fastify returns 503 while the server
|
|
37
|
+
is closing and rejects prototype/constructor poisoning in parsed JSON.
|
|
32
38
|
|
|
33
39
|
## Security
|
|
34
40
|
|
|
@@ -39,7 +45,10 @@ DELETE, OPTIONS and QUERY. Successful browser preflights return HTTP 204 by defa
|
|
|
39
45
|
`optionsSuccessStatus` can change this for a legacy client that requires 200.
|
|
40
46
|
|
|
41
47
|
Rate-limit defaults are 100 requests per minute per client IP. Available settings
|
|
42
|
-
include
|
|
48
|
+
include the complete `@fastify/rate-limit` plugin surface: `max`, `timeWindow`,
|
|
49
|
+
`ban`, `allowList`, `keyGenerator`, `redis`, `store`, `ipv6Subnet`, standard draft
|
|
50
|
+
headers and lifecycle callbacks. Configure Redis or a custom store for multiple
|
|
51
|
+
application replicas.
|
|
43
52
|
|
|
44
53
|
## Compression
|
|
45
54
|
|
|
@@ -58,6 +67,7 @@ known payloads rather than automatically for every API.
|
|
|
58
67
|
| `ui` | `false` | Serve Swagger UI. |
|
|
59
68
|
| `uiPath` | `/docs` | UI route prefix. |
|
|
60
69
|
| `bearerAuth` | `false` | Add a bearer security scheme. |
|
|
70
|
+
| `preHandler` | none | Fastify hook used to protect JSON and UI routes. |
|
|
61
71
|
|
|
62
72
|
Set `openApi: false` to guarantee the documentation integration is never loaded.
|
|
63
73
|
|
|
@@ -65,8 +75,11 @@ Set `openApi: false` to guarantee the documentation integration is never loaded.
|
|
|
65
75
|
|
|
66
76
|
The full preset serves `{ "status": "ok" }` at `/health`. This is a liveness probe,
|
|
67
77
|
not a dependency-readiness check. Supply a custom response or implement a Nest
|
|
68
|
-
controller for deeper readiness logic.
|
|
78
|
+
controller for deeper readiness logic. Use `health.preHandler` when the endpoint
|
|
79
|
+
must not be public.
|
|
69
80
|
|
|
70
81
|
Fastify's Pino logger is enabled, while per-request logging is disabled to reduce
|
|
71
82
|
noise and overhead. Enable it with `observability.requestLogging`. The optional
|
|
72
|
-
`responseTimeHeader` emits a standards-compatible `Server-Timing` value.
|
|
83
|
+
`responseTimeHeader` emits a standards-compatible `Server-Timing` value. Default
|
|
84
|
+
logging redacts authorization, cookie and set-cookie fields. A custom Pino `redact`
|
|
85
|
+
configuration overrides those defaults.
|
package/docs/migration.md
CHANGED
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## Requirements
|
|
4
4
|
|
|
5
|
-
- Upgrade the service to Node
|
|
5
|
+
- Upgrade the service to Node 22 or newer; Node 24 LTS is recommended.
|
|
6
6
|
- Upgrade Nest packages to version 12.
|
|
7
7
|
- Use ESM-compatible imports and include `.js` on relative imports in NodeNext output.
|
|
8
8
|
|
|
9
9
|
## API changes
|
|
10
10
|
|
|
11
|
-
The application factory
|
|
12
|
-
`createNestApp
|
|
13
|
-
using the typed option reference.
|
|
11
|
+
The application factory is now `createApp`. The previous `createHttpApp` and
|
|
12
|
+
`createNestApp` names are not exported. Replace `docs` with `openApi`; replace
|
|
13
|
+
`network` and security values using the typed option reference.
|
|
14
14
|
|
|
15
15
|
The package no longer supplies an authentication guard with implied behavior.
|
|
16
16
|
`Public` and `Roles` remain metadata decorators and must be consumed by an explicit
|
|
17
17
|
application guard.
|
|
18
18
|
|
|
19
19
|
Swagger, validation packages and Nest/Fastify runtime packages are installed as
|
|
20
|
-
dependencies.
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
dependencies or automatically resolved peers. Nest and Fastify are peers so the
|
|
21
|
+
application and this package share one framework instance.
|
|
22
|
+
|
|
23
|
+
`AuthuserModule` and `AUTHUSER_OPTIONS` were removed because their configuration was
|
|
24
|
+
not connected to adapter creation. Configure the application exclusively through
|
|
25
|
+
`createApp` or `configureHttpApp`.
|
package/docs/performance.md
CHANGED
|
@@ -14,7 +14,21 @@ logging, validation, database latency, TLS and hardware dominate realistic resul
|
|
|
14
14
|
|
|
15
15
|
Request logging is disabled by default. Compression is full-preset only because it
|
|
16
16
|
trades bandwidth for CPU. OpenAPI generation happens at startup, and its modules are
|
|
17
|
-
not imported when disabled.
|
|
17
|
+
not imported when disabled. Helmet, CORS, rate limiting and compression are also
|
|
18
|
+
dynamically imported only when their configuration enables them.
|
|
19
|
+
|
|
20
|
+
## Reproducible baseline
|
|
21
|
+
|
|
22
|
+
Run the dependency-free local regression benchmark:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run benchmark
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Change duration and concurrency with `BENCHMARK_DURATION_MS` and
|
|
29
|
+
`BENCHMARK_CONNECTIONS`. Results compare an identical route on raw Fastify, the
|
|
30
|
+
minimal preset and the secure preset. Treat them as a regression signal rather than
|
|
31
|
+
a production capacity promise.
|
|
18
32
|
|
|
19
33
|
## Choosing a lower-level stack
|
|
20
34
|
|
package/docs/security.md
CHANGED
|
@@ -7,10 +7,13 @@ The secure preset establishes a baseline, not a complete application security mo
|
|
|
7
7
|
- Helmet security headers with Content Security Policy.
|
|
8
8
|
- Strict DTO property allowlisting.
|
|
9
9
|
- A one MiB default request-body limit.
|
|
10
|
+
- Finite connection, request, handler and header timeouts.
|
|
10
11
|
- Rate limiting by client IP.
|
|
11
12
|
- Request IDs restricted to 128 safe characters before log propagation.
|
|
12
13
|
- Generic internal errors; unexpected exceptions are logged server-side only.
|
|
13
14
|
- CORS disabled until an allowlist is configured.
|
|
15
|
+
- Sensitive authentication and cookie log fields redacted by default.
|
|
16
|
+
- Optional pre-handler protection for documentation and health routes.
|
|
14
17
|
|
|
15
18
|
## Application responsibilities
|
|
16
19
|
|
|
@@ -19,9 +22,11 @@ The secure preset establishes a baseline, not a complete application security mo
|
|
|
19
22
|
- Configure trusted proxies exactly; a wrong value allows IP spoofing.
|
|
20
23
|
- Store secrets outside source control and rotate them.
|
|
21
24
|
- Apply endpoint-specific rate limits for login and recovery flows.
|
|
25
|
+
- Use Redis or a custom rate-limit store whenever more than one replica runs.
|
|
22
26
|
- Use TLS at the load balancer or application edge.
|
|
23
27
|
- Keep Node and dependencies patched and review `npm audit` output.
|
|
24
28
|
- Avoid exposing Swagger UI and detailed readiness data publicly.
|
|
29
|
+
- Add CSRF protection when authentication relies on ambient cookies or sessions.
|
|
25
30
|
|
|
26
31
|
`Public()` and `Roles()` only attach metadata. They do nothing until an application
|
|
27
32
|
guard reads that metadata and enforces the intended policy.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authuser/nest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Secure, high-performance NestJS foundation powered by Fastify",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nestjs",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
],
|
|
32
32
|
"sideEffects": false,
|
|
33
33
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
34
|
+
"node": ">=22"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
44
44
|
"test": "vitest run",
|
|
45
45
|
"test:coverage": "vitest run --coverage",
|
|
46
|
+
"benchmark": "npm run build && node benchmark/run.mjs",
|
|
46
47
|
"prepack": "npm run clean && npm run build",
|
|
47
48
|
"check": "npm run typecheck && npm test && npm run build && npm pack --dry-run"
|
|
48
49
|
},
|
|
@@ -53,26 +54,41 @@
|
|
|
53
54
|
"@fastify/rate-limit": "^11.2.0",
|
|
54
55
|
"@fastify/swagger": "^9.8.1",
|
|
55
56
|
"@fastify/swagger-ui": "^6.1.1",
|
|
56
|
-
"@nestjs/common": "^12.0.1",
|
|
57
|
-
"@nestjs/core": "^12.0.1",
|
|
58
|
-
"@nestjs/platform-fastify": "^12.0.1",
|
|
59
57
|
"@nestjs/swagger": "^12.0.1",
|
|
60
58
|
"class-transformer": "^0.5.1",
|
|
61
59
|
"class-validator": "^0.15.1",
|
|
62
|
-
"fastify": "^5.12.1",
|
|
63
60
|
"pino": "^10.3.1",
|
|
64
61
|
"reflect-metadata": "^0.2.2",
|
|
65
62
|
"rxjs": "^7.8.2"
|
|
66
63
|
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@nestjs/common": "^12.0.0",
|
|
66
|
+
"@nestjs/core": "^12.0.0",
|
|
67
|
+
"@nestjs/platform-fastify": "^12.0.0",
|
|
68
|
+
"fastify": "^5.12.0"
|
|
69
|
+
},
|
|
67
70
|
"devDependencies": {
|
|
71
|
+
"@nestjs/common": "^12.0.1",
|
|
72
|
+
"@nestjs/core": "^12.0.1",
|
|
73
|
+
"@nestjs/platform-fastify": "^12.0.1",
|
|
68
74
|
"@types/node": "^24.0.0",
|
|
69
75
|
"@vitest/coverage-v8": "^4.0.0",
|
|
76
|
+
"fastify": "^5.12.1",
|
|
70
77
|
"rimraf": "^6.0.0",
|
|
71
78
|
"typescript": "^7.0.2",
|
|
72
79
|
"vitest": "^4.0.0"
|
|
73
80
|
},
|
|
74
81
|
"directories": {
|
|
75
82
|
"doc": "docs",
|
|
83
|
+
"example": "example",
|
|
76
84
|
"test": "test"
|
|
77
|
-
}
|
|
85
|
+
},
|
|
86
|
+
"repository": {
|
|
87
|
+
"type": "git",
|
|
88
|
+
"url": "git+https://github.com/authuser-org/nest.git"
|
|
89
|
+
},
|
|
90
|
+
"bugs": {
|
|
91
|
+
"url": "https://github.com/authuser-org/nest/issues"
|
|
92
|
+
},
|
|
93
|
+
"homepage": "https://github.com/authuser-org/nest#readme"
|
|
78
94
|
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type DynamicModule } from '@nestjs/common';
|
|
2
|
-
import type { ConfigureHttpAppOptions } from './types.js';
|
|
3
|
-
export declare const AUTHUSER_OPTIONS: unique symbol;
|
|
4
|
-
export interface AuthuserModuleAsyncOptions {
|
|
5
|
-
inject?: Array<string | symbol | Function>;
|
|
6
|
-
useFactory: (...dependencies: never[]) => ConfigureHttpAppOptions | Promise<ConfigureHttpAppOptions>;
|
|
7
|
-
}
|
|
8
|
-
export declare class AuthuserModule {
|
|
9
|
-
static forRoot(options?: ConfigureHttpAppOptions): DynamicModule;
|
|
10
|
-
static forRootAsync(options: AuthuserModuleAsyncOptions): DynamicModule;
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=authuser.module.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authuser.module.d.ts","sourceRoot":"","sources":["../src/authuser.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,aAAa,EAAiB,MAAM,gBAAgB,CAAC;AACnF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,eAAO,MAAM,gBAAgB,eAAuC,CAAC;AAErE,MAAM,WAAW,0BAA0B;IACzC,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;IAC3C,UAAU,EAAE,CAAC,GAAG,YAAY,EAAE,KAAK,EAAE,KAAK,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACtG;AAED,qBAEa,cAAc;IACzB,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,uBAA4B,GAAG,aAAa,CAMnE;IAED,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,0BAA0B,GAAG,aAAa,CAOtE;CACF"}
|
package/dist/authuser.module.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var AuthuserModule_1;
|
|
8
|
-
import { Global, Module } from '@nestjs/common';
|
|
9
|
-
export const AUTHUSER_OPTIONS = Symbol.for('@authuser/nest/options');
|
|
10
|
-
let AuthuserModule = AuthuserModule_1 = class AuthuserModule {
|
|
11
|
-
static forRoot(options = {}) {
|
|
12
|
-
return {
|
|
13
|
-
module: AuthuserModule_1,
|
|
14
|
-
providers: [{ provide: AUTHUSER_OPTIONS, useValue: Object.freeze({ ...options }) }],
|
|
15
|
-
exports: [AUTHUSER_OPTIONS],
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
static forRootAsync(options) {
|
|
19
|
-
const provider = {
|
|
20
|
-
provide: AUTHUSER_OPTIONS,
|
|
21
|
-
inject: options.inject ?? [],
|
|
22
|
-
useFactory: options.useFactory,
|
|
23
|
-
};
|
|
24
|
-
return { module: AuthuserModule_1, providers: [provider], exports: [provider] };
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
AuthuserModule = AuthuserModule_1 = __decorate([
|
|
28
|
-
Global(),
|
|
29
|
-
Module({})
|
|
30
|
-
], AuthuserModule);
|
|
31
|
-
export { AuthuserModule };
|
|
32
|
-
//# sourceMappingURL=authuser.module.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authuser.module.js","sourceRoot":"","sources":["../src/authuser.module.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAqC,MAAM,gBAAgB,CAAC;AAGnF,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;AAS9D,IAAM,cAAc,sBAApB,MAAM,cAAc;IAClB,AAAP,MAAM,CAAC,OAAO,CAAC,OAAO,GAA4B,EAAE;QAClD,OAAO;YACL,MAAM,kBAAgB;YACtB,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,CAAC;YACnF,OAAO,EAAE,CAAC,gBAAgB,CAAC;SAC5B,CAAC;IACJ,CAAC;IAEM,AAAP,MAAM,CAAC,YAAY,CAAC,OAAmC;QACrD,MAAM,QAAQ,GAAa;YACzB,OAAO,EAAE,gBAAgB;YACzB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;YAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC;QACF,OAAO,EAAE,MAAM,kBAAgB,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IAChF,CAAC;CACF,CAAA;AAjBY,cAAc;IAF1B,MAAM,EAAE;IACR,MAAM,CAAC,EAAE,CAAC;GACE,cAAc,CAiB1B"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type NestFastifyApplication } from '@nestjs/platform-fastify';
|
|
2
|
-
import type { CreateHttpAppOptions } from './types.js';
|
|
3
|
-
export declare function createHttpApp(options: CreateHttpAppOptions): Promise<NestFastifyApplication>;
|
|
4
|
-
/** A descriptive alias for new projects. */
|
|
5
|
-
export declare const createNestApp: typeof createHttpApp;
|
|
6
|
-
//# sourceMappingURL=create-http-app.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-http-app.d.ts","sourceRoot":"","sources":["../src/create-http-app.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIvD,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA4BlG;AAED,4CAA4C;AAC5C,eAAO,MAAM,aAAa,sBAAgB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-http-app.js","sourceRoot":"","sources":["../src/create-http-app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,cAAc,GAEf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA6B;IAC/D,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC;QACjC,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,MAAM;QACrC,aAAa,EAAE,IAAI,aAAa,CAAC;YAC/B,qBAAqB,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,cAAc;SAC9D,CAAC;QACF,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK;QACvC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS;QACzC,aAAa,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,GAAG,EAAE;QAChE,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,CAAC;QACjD,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,CAAC;QAC3C,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,MAAM;QACpD,eAAe,EAAE,cAAc;QAC/B,QAAQ,EAAE,aAAa;KACxB,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,KAAK,KAAK;QACzD,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAc,EAAE;QAC7C,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IACxB,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,MAAM,CAClC,OAAO,CAAC,UAAU,EAClB,OAAO,EACP,WAAW,CACZ,CAAC;IAEF,OAAO,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,4CAA4C;AAC5C,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC;AAE3C,SAAS,aAAa,CAAC,OAAwB;IAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACjD,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;AAClG,CAAC"}
|