@authuser/nest 0.2.2 → 1.0.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 +31 -0
- package/README.md +34 -2
- package/SECURITY.md +17 -0
- package/SUPPORT.md +11 -0
- package/dist/configure-http-app.d.ts.map +1 -1
- package/dist/configure-http-app.js +25 -1
- package/dist/configure-http-app.js.map +1 -1
- package/dist/create-app.d.ts.map +1 -1
- package/dist/create-app.js +4 -6
- package/dist/create-app.js.map +1 -1
- package/dist/http-exception.filter.d.ts.map +1 -1
- package/dist/http-exception.filter.js +10 -7
- package/dist/http-exception.filter.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/nest-fastify.logger.d.ts +2 -1
- package/dist/nest-fastify.logger.d.ts.map +1 -1
- package/dist/nest-fastify.logger.js +9 -6
- package/dist/nest-fastify.logger.js.map +1 -1
- package/dist/options.d.ts +13 -2
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +64 -7
- package/dist/options.js.map +1 -1
- package/dist/types.d.ts +24 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/api-stability.md +26 -0
- package/docs/configuration.md +42 -6
- package/docs/migration.md +12 -0
- package/docs/performance.md +16 -0
- package/docs/production.md +45 -0
- package/docs/releasing.md +28 -0
- package/docs/security.md +8 -2
- package/docs/threat-model.md +41 -0
- package/package.json +11 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,37 @@ This project uses [Semantic Versioning](https://semver.org/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.0.0] - 2026-09-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Establish and document the stable 1.x public API contract.
|
|
13
|
+
- Add dynamic liveness and dependency-readiness checks with safe 503 failures.
|
|
14
|
+
- Return validated correlation IDs through a configurable response header.
|
|
15
|
+
- Verify the packed artifact from clean ESM and CommonJS consumers.
|
|
16
|
+
- Add cross-platform CI, release automation, contribution policies, a threat model,
|
|
17
|
+
and a production checklist.
|
|
18
|
+
|
|
19
|
+
### Security
|
|
20
|
+
|
|
21
|
+
- Hide every 5xx exception message and log the original cause server-side.
|
|
22
|
+
- Remove query strings from error paths and request logs by default.
|
|
23
|
+
- Validate incoming request IDs instead of trusting Fastify's header passthrough.
|
|
24
|
+
- Reject invalid internal paths, overlapping Swagger routes, and invalid correlation
|
|
25
|
+
header names.
|
|
26
|
+
- Add tests for JSON prototype/constructor poisoning, body limits, handler deadlines,
|
|
27
|
+
shared rate-limit stores, and sensitive-data exposure.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Make Nest and Fastify logging independently configurable. Setting
|
|
32
|
+
`observability.logger: false` no longer disables the Nest logger; use
|
|
33
|
+
`nest.logger: false` for that behavior.
|
|
34
|
+
- Add an explicit CommonJS export condition while retaining the native ESM build.
|
|
35
|
+
- Mark the entry point side effect so bundlers preserve `reflect-metadata` setup.
|
|
36
|
+
- Raise enforced coverage thresholds to 95% statements/lines/functions and 85%
|
|
37
|
+
branches.
|
|
38
|
+
|
|
8
39
|
## [0.2.2] - 2026-09-03
|
|
9
40
|
|
|
10
41
|
### Added
|
package/README.md
CHANGED
|
@@ -6,6 +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
|
+
<a href="https://github.com/authuser-org/nest/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/authuser-org/nest/actions/workflows/ci.yml/badge.svg"></a>
|
|
9
10
|
<img alt="Node 22.12+" src="https://img.shields.io/badge/node-%3E%3D22.12-339933?style=flat-square&logo=node.js&logoColor=white">
|
|
10
11
|
<img alt="NestJS 12" src="https://img.shields.io/badge/NestJS-12-E0234E?style=flat-square&logo=nestjs&logoColor=white">
|
|
11
12
|
<img alt="Fastify 5" src="https://img.shields.io/badge/Fastify-5-black?style=flat-square&logo=fastify">
|
|
@@ -30,7 +31,10 @@ intact while removing repetitive bootstrap code.
|
|
|
30
31
|
rate limiting.
|
|
31
32
|
- Finite request, handler, header and connection timeouts.
|
|
32
33
|
- Sensitive authorization, cookie and set-cookie log fields are redacted by default.
|
|
34
|
+
- Query strings are omitted from logs and error paths unless explicitly enabled.
|
|
33
35
|
- JSON logging by default, with an optional standard Nest console format.
|
|
36
|
+
- Correlated request IDs are validated and returned in `x-request-id`.
|
|
37
|
+
- Dynamic liveness and readiness checks fail closed with HTTP 503.
|
|
34
38
|
- OpenAPI is optional at runtime. Its code is dynamically imported only when enabled.
|
|
35
39
|
- HTTP QUERY (RFC 10008) passes through Nest 12/Fastify 5 and is included in CORS defaults.
|
|
36
40
|
- Native ESM, strict declarations and a TypeScript 7 toolchain.
|
|
@@ -84,6 +88,9 @@ That application has Helmet, rate limiting, safe request IDs, strict validation,
|
|
|
84
88
|
a 1 MiB body limit, finite timeouts and graceful shutdown hooks. Cross-origin
|
|
85
89
|
requests are not enabled implicitly.
|
|
86
90
|
|
|
91
|
+
`1.x` follows Semantic Versioning: documented public exports and option behavior only
|
|
92
|
+
change incompatibly in a new major version. See the [API stability policy](https://github.com/authuser-org/nest/blob/main/docs/api-stability.md).
|
|
93
|
+
|
|
87
94
|
## Presets
|
|
88
95
|
|
|
89
96
|
| Preset | Intended use | Enabled by default |
|
|
@@ -138,6 +145,25 @@ openApi: { enabled: true, preHandler: protectInternalRoute },
|
|
|
138
145
|
health: { enabled: true, preHandler: protectInternalRoute },
|
|
139
146
|
```
|
|
140
147
|
|
|
148
|
+
### Liveness and readiness
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
health: {
|
|
152
|
+
enabled: true,
|
|
153
|
+
check: () => ({ status: 'live' }),
|
|
154
|
+
readiness: {
|
|
155
|
+
path: '/ready',
|
|
156
|
+
check: async () => {
|
|
157
|
+
await database.ping();
|
|
158
|
+
return { status: 'ready' };
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
A thrown health check is logged internally and returned as a generic HTTP 503. Do
|
|
165
|
+
not include credentials, topology or personal data in successful health responses.
|
|
166
|
+
|
|
141
167
|
## Configuration examples
|
|
142
168
|
|
|
143
169
|
### CORS allowlist
|
|
@@ -179,7 +205,8 @@ await configureHttpApp(app, {
|
|
|
179
205
|
```
|
|
180
206
|
|
|
181
207
|
Call `configureHttpApp` before `app.init()` or `app.listen()` so Fastify can register
|
|
182
|
-
its plugins and routes.
|
|
208
|
+
its plugins and routes. When supplying your own adapter, request-ID generation and
|
|
209
|
+
network limits remain adapter responsibilities; `createApp` configures those safely.
|
|
183
210
|
|
|
184
211
|
## Public API
|
|
185
212
|
|
|
@@ -187,13 +214,16 @@ its plugins and routes.
|
|
|
187
214
|
- `configureHttpApp(app, options)` — configure an existing Fastify-based Nest app.
|
|
188
215
|
- `Public()` and `Roles(...roles)` — metadata helpers for your own guards.
|
|
189
216
|
- `HttpExceptionFilter` — the default safe JSON exception filter.
|
|
217
|
+
- Public TypeScript contracts for configuration, health checks and error responses.
|
|
190
218
|
|
|
191
219
|
The decorators intentionally do not provide authentication. Authentication policy
|
|
192
220
|
belongs to the consuming application; pretending otherwise would create a dangerous
|
|
193
221
|
security boundary.
|
|
194
222
|
|
|
195
223
|
See the [complete option reference](https://github.com/authuser-org/nest/blob/main/docs/configuration.md), the
|
|
196
|
-
[security model](https://github.com/authuser-org/nest/blob/main/docs/security.md),
|
|
224
|
+
[security model](https://github.com/authuser-org/nest/blob/main/docs/security.md), the
|
|
225
|
+
[production checklist](https://github.com/authuser-org/nest/blob/main/docs/production.md), and the
|
|
226
|
+
[performance guide](https://github.com/authuser-org/nest/blob/main/docs/performance.md).
|
|
197
227
|
|
|
198
228
|
## Performance notes
|
|
199
229
|
|
|
@@ -225,6 +255,8 @@ required integrations as normal dependencies. See the
|
|
|
225
255
|
```bash
|
|
226
256
|
npm install
|
|
227
257
|
npm run check
|
|
258
|
+
npm run test:coverage
|
|
259
|
+
npm run test:package
|
|
228
260
|
```
|
|
229
261
|
|
|
230
262
|
An executable API and an importable Postman collection are available in the
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes are provided for the latest minor release. Until version 1.0, a
|
|
6
|
+
security fix may include a documented breaking change when that is the safest
|
|
7
|
+
course.
|
|
8
|
+
|
|
9
|
+
Only maintained Node.js release lines accepted by `package.json` are supported.
|
|
10
|
+
|
|
11
|
+
## Report a vulnerability
|
|
12
|
+
|
|
13
|
+
Do not open a public issue. Send a private report to `security@authuser.es` with
|
|
14
|
+
the affected version, reproduction steps and expected impact. You should receive
|
|
15
|
+
an acknowledgement within three business days.
|
|
16
|
+
|
|
17
|
+
Never include production credentials or personal data in a report.
|
package/SUPPORT.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Support
|
|
2
|
+
|
|
3
|
+
The latest `1.x` minor release receives bug and security fixes. Supported Node, Nest
|
|
4
|
+
and Fastify ranges are declared in `package.json`.
|
|
5
|
+
|
|
6
|
+
Use GitHub Issues for reproducible bugs and focused feature proposals. Include the
|
|
7
|
+
package version, Node version, package manager, minimal reproduction and relevant
|
|
8
|
+
sanitized logs. General Nest or Fastify usage questions should use their respective
|
|
9
|
+
community support channels.
|
|
10
|
+
|
|
11
|
+
Report vulnerabilities privately according to [SECURITY.md](./SECURITY.md).
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAG1D,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,sBAAsB,EAC3B,KAAK,GAAE,uBAA4B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CA+EjC"}
|
|
@@ -53,13 +53,37 @@ export async function configureHttpApp(app, input = {}) {
|
|
|
53
53
|
return payload;
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
|
+
if (options.observability.requestIdResponseHeader !== false) {
|
|
57
|
+
const header = options.observability.requestIdResponseHeader;
|
|
58
|
+
fastify.addHook('onRequest', async (request, reply) => {
|
|
59
|
+
reply.header(header, request.id);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
56
62
|
if (options.health.enabled) {
|
|
57
63
|
fastify.get(options.health.path, {
|
|
58
64
|
config: { rateLimit: false },
|
|
59
65
|
...(options.health.preHandler ? { preHandler: options.health.preHandler } : {}),
|
|
60
|
-
},
|
|
66
|
+
}, healthHandler(options.health.check, options.health.response));
|
|
67
|
+
}
|
|
68
|
+
if (options.health.readiness !== false) {
|
|
69
|
+
const readiness = options.health.readiness;
|
|
70
|
+
fastify.get(readiness.path, {
|
|
71
|
+
config: { rateLimit: false },
|
|
72
|
+
...(readiness.preHandler ? { preHandler: readiness.preHandler } : {}),
|
|
73
|
+
}, healthHandler(readiness.check, { status: 'ready' }));
|
|
61
74
|
}
|
|
62
75
|
await registerOpenApi(app, fastify, options.openApi);
|
|
63
76
|
return app;
|
|
64
77
|
}
|
|
78
|
+
function healthHandler(check, fallback) {
|
|
79
|
+
return async (request, reply) => {
|
|
80
|
+
try {
|
|
81
|
+
return reply.send(check ? await check(request) : fallback);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
request.log.error({ err: error }, 'Health check failed');
|
|
85
|
+
return reply.status(503).send({ status: 'unavailable' });
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
65
89
|
//# sourceMappingURL=configure-http-app.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure-http-app.js","sourceRoot":"","sources":["../src/configure-http-app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"configure-http-app.js","sourceRoot":"","sources":["../src/configure-http-app.ts"],"names":[],"mappings":"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"}
|
package/dist/create-app.d.ts.map
CHANGED
|
@@ -1 +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;AAIlC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,sBAAsB,CAAC,
|
|
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;AAIlC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAwC1F"}
|
package/dist/create-app.js
CHANGED
|
@@ -12,7 +12,7 @@ export async function createApp(options) {
|
|
|
12
12
|
validateNetworkOptions(network);
|
|
13
13
|
const loggerOptions = resolved.observability.loggerFormat === 'nest'
|
|
14
14
|
&& resolved.observability.logger !== false
|
|
15
|
-
? { loggerInstance: new NestFastifyLogger(resolved.appName) }
|
|
15
|
+
? { loggerInstance: new NestFastifyLogger(resolved.appName, resolved.observability.includeQueryString) }
|
|
16
16
|
: { logger: resolved.observability.logger };
|
|
17
17
|
const adapter = new FastifyAdapter({
|
|
18
18
|
...loggerOptions,
|
|
@@ -30,14 +30,12 @@ export async function createApp(options) {
|
|
|
30
30
|
return503OnClosing: true,
|
|
31
31
|
onProtoPoisoning: 'error',
|
|
32
32
|
onConstructorPoisoning: 'error',
|
|
33
|
-
requestIdHeader
|
|
33
|
+
// Fastify trusts requestIdHeader verbatim; validate it ourselves in genReqId.
|
|
34
|
+
requestIdHeader: false,
|
|
34
35
|
genReqId: safeRequestId,
|
|
35
36
|
});
|
|
36
37
|
adapter.getInstance().server.headersTimeout = network.headersTimeout ?? 30_000;
|
|
37
|
-
const
|
|
38
|
-
? { ...options.nest, logger: false }
|
|
39
|
-
: { ...options.nest };
|
|
40
|
-
const app = await NestFactory.create(options.rootModule, adapter, nestOptions);
|
|
38
|
+
const app = await NestFactory.create(options.rootModule, adapter, options.nest ?? {});
|
|
41
39
|
return configureHttpApp(app, options);
|
|
42
40
|
}
|
|
43
41
|
function validateNetworkOptions(network) {
|
package/dist/create-app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-app.js","sourceRoot":"","sources":["../src/create-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,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAyB;IACvD,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,YAAY,KAAK,MAAM;WAC/D,QAAQ,CAAC,aAAa,CAAC,MAAM,KAAK,KAAK;QAC1C,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,iBAAiB,
|
|
1
|
+
{"version":3,"file":"create-app.js","sourceRoot":"","sources":["../src/create-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-exception.filter.d.ts","sourceRoot":"","sources":["../src/http-exception.filter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAIb,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"http-exception.filter.d.ts","sourceRoot":"","sources":["../src/http-exception.filter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAIb,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAIxB,qBAAa,mBAAoB,YAAW,eAAe;IACzD,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAwBnD;CACF"}
|
|
@@ -8,18 +8,21 @@ export class HttpExceptionFilter {
|
|
|
8
8
|
const status = httpException?.getStatus() ?? HttpStatus.INTERNAL_SERVER_ERROR;
|
|
9
9
|
const response = httpException?.getResponse();
|
|
10
10
|
const details = typeof response === 'object' && response !== null ? response : {};
|
|
11
|
-
const message =
|
|
12
|
-
?
|
|
13
|
-
:
|
|
14
|
-
|
|
11
|
+
const message = status >= 500
|
|
12
|
+
? 'Internal server error'
|
|
13
|
+
: typeof response === 'string'
|
|
14
|
+
? response
|
|
15
|
+
: getMessage(details) ?? 'Request failed';
|
|
16
|
+
if (status >= 500)
|
|
15
17
|
request.log.error({ err: exception }, 'Unhandled request error');
|
|
16
|
-
|
|
18
|
+
const body = {
|
|
17
19
|
statusCode: status,
|
|
18
20
|
error: HttpStatus[status] ?? 'Error',
|
|
19
21
|
message,
|
|
20
22
|
requestId: request.id,
|
|
21
|
-
path: request.url,
|
|
22
|
-
}
|
|
23
|
+
path: request.url.split('?', 1)[0] ?? request.url,
|
|
24
|
+
};
|
|
25
|
+
void reply.status(status).send(body);
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
Catch()(HttpExceptionFilter);
|
|
@@ -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;
|
|
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
|
@@ -3,5 +3,5 @@ export { configureHttpApp } from './configure-http-app.js';
|
|
|
3
3
|
export { createApp } from './create-app.js';
|
|
4
4
|
export { Public, Roles, IS_PUBLIC_KEY, ROLES_KEY } from './decorators.js';
|
|
5
5
|
export { HttpExceptionFilter } from './http-exception.filter.js';
|
|
6
|
-
export type { CompressionOptions, ConfigureHttpAppOptions, CorsOptions, CreateAppOptions, HealthOptions, NetworkOptions, ObservabilityOptions, OpenApiOptions, RateLimitOptions, SecurityOptions, SecurityPreset, } from './types.js';
|
|
6
|
+
export type { CompressionOptions, ConfigureHttpAppOptions, CorsOptions, CreateAppOptions, HealthCheck, HealthOptions, HttpErrorResponse, NetworkOptions, ObservabilityOptions, OpenApiOptions, RateLimitOptions, ReadinessOptions, SecurityOptions, SecurityPreset, } from './types.js';
|
|
7
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,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"}
|
|
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,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC"}
|
|
@@ -4,6 +4,7 @@ import type { Bindings } from 'pino';
|
|
|
4
4
|
/** Adapts Fastify's structured logger contract to Nest's standard console logger. */
|
|
5
5
|
export declare class NestFastifyLogger implements FastifyBaseLogger {
|
|
6
6
|
private readonly context;
|
|
7
|
+
private readonly includeQueryString;
|
|
7
8
|
private readonly bindings;
|
|
8
9
|
private readonly logger;
|
|
9
10
|
level: string;
|
|
@@ -14,7 +15,7 @@ export declare class NestFastifyLogger implements FastifyBaseLogger {
|
|
|
14
15
|
readonly warn: FastifyLogFn;
|
|
15
16
|
readonly trace: FastifyLogFn;
|
|
16
17
|
readonly silent: FastifyLogFn;
|
|
17
|
-
constructor(context: string, bindings?: Bindings, logger?: Logger);
|
|
18
|
+
constructor(context: string, includeQueryString?: boolean, bindings?: Bindings, logger?: Logger);
|
|
18
19
|
child(bindings: Bindings): FastifyBaseLogger;
|
|
19
20
|
private write;
|
|
20
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest-fastify.logger.d.ts","sourceRoot":"","sources":["../src/nest-fastify.logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAIrC,qFAAqF;AACrF,qBAAa,iBAAkB,YAAW,iBAAiB;IAYvD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"nest-fastify.logger.d.ts","sourceRoot":"","sources":["../src/nest-fastify.logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAIrC,qFAAqF;AACrF,qBAAa,iBAAkB,YAAW,iBAAiB;IAYvD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAdzB,KAAK,SAAU;IAEf,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAoD;IAC/E,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAqD;IACjF,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAqD;IACjF,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAqD;IACjF,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAoD;IAC/E,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAqD;IACjF,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAmB;IAEhD,YACmB,OAAO,EAAE,MAAM,EACf,kBAAkB,UAAQ,EAC1B,QAAQ,GAAE,QAAa,EACvB,MAAM,SAAsB,EAC3C;IAEJ,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,iBAAiB,CAO3C;IAED,OAAO,CAAC,KAAK;CAsBd"}
|
|
@@ -2,6 +2,7 @@ import { Logger } from '@nestjs/common';
|
|
|
2
2
|
/** Adapts Fastify's structured logger contract to Nest's standard console logger. */
|
|
3
3
|
export class NestFastifyLogger {
|
|
4
4
|
context;
|
|
5
|
+
includeQueryString;
|
|
5
6
|
bindings;
|
|
6
7
|
logger;
|
|
7
8
|
level = 'info';
|
|
@@ -12,16 +13,17 @@ export class NestFastifyLogger {
|
|
|
12
13
|
warn = (...args) => this.write('warn', args);
|
|
13
14
|
trace = (...args) => this.write('trace', args);
|
|
14
15
|
silent = () => undefined;
|
|
15
|
-
constructor(context, bindings = {}, logger = new Logger(context)) {
|
|
16
|
+
constructor(context, includeQueryString = false, bindings = {}, logger = new Logger(context)) {
|
|
16
17
|
this.context = context;
|
|
18
|
+
this.includeQueryString = includeQueryString;
|
|
17
19
|
this.bindings = bindings;
|
|
18
20
|
this.logger = logger;
|
|
19
21
|
}
|
|
20
22
|
child(bindings) {
|
|
21
|
-
return new NestFastifyLogger(this.context, { ...this.bindings, ...bindings }, this.logger);
|
|
23
|
+
return new NestFastifyLogger(this.context, this.includeQueryString, { ...this.bindings, ...bindings }, this.logger);
|
|
22
24
|
}
|
|
23
25
|
write(level, args) {
|
|
24
|
-
const message = formatLogMessage(args, this.bindings);
|
|
26
|
+
const message = formatLogMessage(args, this.bindings, this.includeQueryString);
|
|
25
27
|
switch (level) {
|
|
26
28
|
case 'error':
|
|
27
29
|
this.logger.error(message);
|
|
@@ -43,7 +45,7 @@ export class NestFastifyLogger {
|
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
|
-
function formatLogMessage(args, bindings) {
|
|
48
|
+
function formatLogMessage(args, bindings, includeQueryString) {
|
|
47
49
|
const data = isRecord(args[0]) ? args[0] : undefined;
|
|
48
50
|
const text = args.find((value) => typeof value === 'string') ?? 'Fastify event';
|
|
49
51
|
const details = [];
|
|
@@ -52,8 +54,9 @@ function formatLogMessage(args, bindings) {
|
|
|
52
54
|
const error = data && isRecord(data.err) ? data.err : undefined;
|
|
53
55
|
if (typeof request?.method === 'string')
|
|
54
56
|
details.push(request.method);
|
|
55
|
-
if (typeof request?.url === 'string')
|
|
56
|
-
details.push(request.url);
|
|
57
|
+
if (typeof request?.url === 'string') {
|
|
58
|
+
details.push(includeQueryString ? request.url : request.url.split('?', 1)[0] ?? '');
|
|
59
|
+
}
|
|
57
60
|
if (typeof response?.statusCode === 'number')
|
|
58
61
|
details.push(`status=${response.statusCode}`);
|
|
59
62
|
if (typeof data?.responseTime === 'number')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest-fastify.logger.js","sourceRoot":"","sources":["../src/nest-fastify.logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAMxC,qFAAqF;AACrF,MAAM,OAAO,iBAAiB;IAYT,OAAO;IACP,QAAQ;IACR,MAAM;
|
|
1
|
+
{"version":3,"file":"nest-fastify.logger.js","sourceRoot":"","sources":["../src/nest-fastify.logger.ts"],"names":[],"mappings":"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"}
|
package/dist/options.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CompressionOptions, ConfigureHttpAppOptions, CorsOptions, HealthOptions, OpenApiOptions, RateLimitOptions, SecurityPreset } from './types.js';
|
|
1
|
+
import type { CompressionOptions, ConfigureHttpAppOptions, CorsOptions, HealthOptions, HealthCheck, OpenApiOptions, RateLimitOptions, SecurityPreset } from './types.js';
|
|
2
2
|
export interface ResolvedOptions {
|
|
3
3
|
appName: string;
|
|
4
4
|
preset: SecurityPreset;
|
|
@@ -13,7 +13,18 @@ export interface ResolvedOptions {
|
|
|
13
13
|
};
|
|
14
14
|
compression: Required<CompressionOptions>;
|
|
15
15
|
openApi: Required<Omit<OpenApiOptions, 'preHandler'>> & Pick<OpenApiOptions, 'preHandler'>;
|
|
16
|
-
health:
|
|
16
|
+
health: {
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
path: string;
|
|
19
|
+
response: Readonly<Record<string, unknown>>;
|
|
20
|
+
check?: HealthCheck;
|
|
21
|
+
preHandler?: HealthOptions['preHandler'];
|
|
22
|
+
readiness: false | {
|
|
23
|
+
path: string;
|
|
24
|
+
check: HealthCheck;
|
|
25
|
+
preHandler?: HealthOptions['preHandler'];
|
|
26
|
+
};
|
|
27
|
+
};
|
|
17
28
|
observability: Required<NonNullable<ConfigureHttpAppOptions['observability']>>;
|
|
18
29
|
shutdownHooks: boolean;
|
|
19
30
|
}
|
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,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAC3F,MAAM,EAAE,
|
|
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,WAAW,EACX,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;QACN,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QAC5C,KAAK,CAAC,EAAE,WAAW,CAAC;QACpB,UAAU,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;QACzC,SAAS,EAAE,KAAK,GAAG;YACjB,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,WAAW,CAAC;YACnB,UAAU,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;SAC1C,CAAC;KACH,CAAC;IACF,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,CAoGhF"}
|
package/dist/options.js
CHANGED
|
@@ -7,6 +7,10 @@ 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 readinessInput = healthInput.readiness === false || healthInput.readiness === undefined
|
|
11
|
+
? false
|
|
12
|
+
: healthInput.readiness;
|
|
13
|
+
const includeQueryString = options.observability?.includeQueryString ?? false;
|
|
10
14
|
const openApiEnabled = typeof options.openApi === 'boolean'
|
|
11
15
|
? options.openApi
|
|
12
16
|
: openApiInput.enabled ?? openApiInput.ui ?? isFull;
|
|
@@ -69,12 +73,22 @@ export function resolveOptions(options) {
|
|
|
69
73
|
enabled: typeof options.health === 'boolean' ? options.health : healthInput.enabled ?? isFull,
|
|
70
74
|
path: normalizePath(healthInput.path ?? '/health'),
|
|
71
75
|
response: healthInput.response ?? { status: 'ok' },
|
|
76
|
+
...(healthInput.check ? { check: healthInput.check } : {}),
|
|
72
77
|
...(healthInput.preHandler ? { preHandler: healthInput.preHandler } : {}),
|
|
78
|
+
readiness: readinessInput === false
|
|
79
|
+
? false
|
|
80
|
+
: {
|
|
81
|
+
path: normalizePath(readinessInput.path ?? '/ready'),
|
|
82
|
+
check: readinessInput.check,
|
|
83
|
+
...(readinessInput.preHandler ? { preHandler: readinessInput.preHandler } : {}),
|
|
84
|
+
},
|
|
73
85
|
},
|
|
74
86
|
observability: {
|
|
75
|
-
logger: resolveLogger(options.observability?.logger ?? true),
|
|
87
|
+
logger: resolveLogger(options.observability?.logger ?? true, includeQueryString),
|
|
76
88
|
loggerFormat: options.observability?.loggerFormat ?? 'json',
|
|
77
89
|
requestLogging: options.observability?.requestLogging ?? false,
|
|
90
|
+
includeQueryString,
|
|
91
|
+
requestIdResponseHeader: options.observability?.requestIdResponseHeader ?? 'x-request-id',
|
|
78
92
|
responseTimeHeader: options.observability?.responseTimeHeader ?? false,
|
|
79
93
|
},
|
|
80
94
|
shutdownHooks: options.shutdownHooks ?? true,
|
|
@@ -93,17 +107,45 @@ const SENSITIVE_LOG_PATHS = [
|
|
|
93
107
|
'req.headers.cookie',
|
|
94
108
|
'res.headers["set-cookie"]',
|
|
95
109
|
];
|
|
96
|
-
function resolveLogger(logger) {
|
|
110
|
+
function resolveLogger(logger, includeQueryString) {
|
|
97
111
|
if (logger === false)
|
|
98
112
|
return false;
|
|
113
|
+
const requestSerializer = (request) => ({
|
|
114
|
+
method: request.method,
|
|
115
|
+
url: safePath(typeof request.url === 'string' ? request.url : '', includeQueryString),
|
|
116
|
+
host: request.host,
|
|
117
|
+
remoteAddress: request.ip,
|
|
118
|
+
});
|
|
99
119
|
if (logger === true) {
|
|
100
|
-
return {
|
|
120
|
+
return {
|
|
121
|
+
redact: { paths: SENSITIVE_LOG_PATHS, censor: '[REDACTED]' },
|
|
122
|
+
serializers: { req: requestSerializer },
|
|
123
|
+
};
|
|
101
124
|
}
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
return {
|
|
126
|
+
...logger,
|
|
127
|
+
...(logger.redact === undefined
|
|
128
|
+
? { redact: { paths: SENSITIVE_LOG_PATHS, censor: '[REDACTED]' } }
|
|
129
|
+
: {}),
|
|
130
|
+
serializers: {
|
|
131
|
+
req: requestSerializer,
|
|
132
|
+
...logger.serializers,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
105
135
|
}
|
|
106
136
|
function validateResolvedOptions(options) {
|
|
137
|
+
if (options.appName.trim().length === 0 || options.appName.length > 128) {
|
|
138
|
+
throw new TypeError('Application name must contain 1 to 128 characters');
|
|
139
|
+
}
|
|
140
|
+
if (options.apiPrefix !== undefined && (options.apiPrefix.length > 1_024
|
|
141
|
+
|| options.apiPrefix.includes('?')
|
|
142
|
+
|| options.apiPrefix.includes('#')
|
|
143
|
+
|| options.apiPrefix.includes('\0'))) {
|
|
144
|
+
throw new TypeError('API prefix must be a valid URL path prefix');
|
|
145
|
+
}
|
|
146
|
+
if (!Number.isSafeInteger(options.compression.threshold) || options.compression.threshold < 0) {
|
|
147
|
+
throw new TypeError('Compression threshold must be a non-negative safe integer');
|
|
148
|
+
}
|
|
107
149
|
const cors = options.security.cors;
|
|
108
150
|
if (cors !== false && cors.credentials === true && cors.origin === true) {
|
|
109
151
|
throw new TypeError('CORS credentials cannot be combined with an unrestricted origin');
|
|
@@ -112,13 +154,28 @@ function validateResolvedOptions(options) {
|
|
|
112
154
|
options.health.enabled ? options.health.path : undefined,
|
|
113
155
|
options.openApi.enabled && options.openApi.json ? options.openApi.jsonPath : undefined,
|
|
114
156
|
options.openApi.enabled && options.openApi.ui ? options.openApi.uiPath : undefined,
|
|
157
|
+
options.health.readiness !== false ? options.health.readiness.path : undefined,
|
|
115
158
|
].filter((path) => path !== undefined);
|
|
116
|
-
if (
|
|
159
|
+
if (paths.some((path, index) => paths.some((other, otherIndex) => (index !== otherIndex && (path === other || path.startsWith(`${other}/`) || other.startsWith(`${path}/`)))))) {
|
|
117
160
|
throw new TypeError('Health, OpenAPI JSON and Swagger UI paths must be unique');
|
|
118
161
|
}
|
|
162
|
+
for (const path of paths)
|
|
163
|
+
validateInternalPath(path);
|
|
164
|
+
const requestIdHeader = options.observability.requestIdResponseHeader;
|
|
165
|
+
if (requestIdHeader !== false && !/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(requestIdHeader)) {
|
|
166
|
+
throw new TypeError('Request ID response header must be a valid HTTP header name');
|
|
167
|
+
}
|
|
119
168
|
const rateLimit = options.security.rateLimit;
|
|
120
169
|
if (rateLimit !== false && typeof rateLimit.max === 'number' && (!Number.isFinite(rateLimit.max) || rateLimit.max <= 0)) {
|
|
121
170
|
throw new TypeError('Rate limit max must be a positive number');
|
|
122
171
|
}
|
|
123
172
|
}
|
|
173
|
+
function validateInternalPath(path) {
|
|
174
|
+
if (path.length > 2_048 || path.includes('?') || path.includes('#') || path.includes('\0')) {
|
|
175
|
+
throw new TypeError(`Invalid internal route path: ${path}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function safePath(url, includeQueryString) {
|
|
179
|
+
return includeQueryString ? url : url.split('?', 1)[0] ?? '';
|
|
180
|
+
}
|
|
124
181
|
//# 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":"
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { LoggerOptions } from 'pino';
|
|
|
2
2
|
import type rateLimit from '@fastify/rate-limit';
|
|
3
3
|
import type { Type, ValidationPipeOptions, VersioningOptions } from '@nestjs/common';
|
|
4
4
|
import type { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
|
|
5
|
-
import type { preHandlerHookHandler } from 'fastify';
|
|
5
|
+
import type { FastifyRequest, preHandlerHookHandler } from 'fastify';
|
|
6
6
|
export type SecurityPreset = 'minimal' | 'secure' | 'full';
|
|
7
7
|
export interface CorsOptions {
|
|
8
8
|
/** No cross-origin requests are allowed by default. */
|
|
@@ -50,8 +50,18 @@ export interface HealthOptions {
|
|
|
50
50
|
enabled?: boolean;
|
|
51
51
|
path?: string;
|
|
52
52
|
response?: Readonly<Record<string, unknown>>;
|
|
53
|
+
/** Dynamic liveness check. Throwing produces a safe HTTP 503 response. */
|
|
54
|
+
check?: HealthCheck;
|
|
53
55
|
/** Fastify hook for restricting the health route. */
|
|
54
56
|
preHandler?: preHandlerHookHandler;
|
|
57
|
+
/** Optional dependency-readiness endpoint. */
|
|
58
|
+
readiness?: false | ReadinessOptions;
|
|
59
|
+
}
|
|
60
|
+
export type HealthCheck = (request: FastifyRequest) => Readonly<Record<string, unknown>> | Promise<Readonly<Record<string, unknown>>>;
|
|
61
|
+
export interface ReadinessOptions {
|
|
62
|
+
path?: string;
|
|
63
|
+
check: HealthCheck;
|
|
64
|
+
preHandler?: preHandlerHookHandler;
|
|
55
65
|
}
|
|
56
66
|
export interface ObservabilityOptions {
|
|
57
67
|
/** Fastify logging. An options object configures the default Pino JSON logger. */
|
|
@@ -59,8 +69,19 @@ export interface ObservabilityOptions {
|
|
|
59
69
|
/** JSON is optimal for production ingestion; nest uses Nest's readable console format. */
|
|
60
70
|
loggerFormat?: 'json' | 'nest';
|
|
61
71
|
requestLogging?: boolean;
|
|
72
|
+
/** Query strings may contain secrets or personal data and are omitted by default. */
|
|
73
|
+
includeQueryString?: boolean;
|
|
74
|
+
/** Response correlation header. False disables it. */
|
|
75
|
+
requestIdResponseHeader?: string | false;
|
|
62
76
|
responseTimeHeader?: boolean;
|
|
63
77
|
}
|
|
78
|
+
export interface HttpErrorResponse {
|
|
79
|
+
statusCode: number;
|
|
80
|
+
error: string;
|
|
81
|
+
message: unknown;
|
|
82
|
+
requestId: string;
|
|
83
|
+
path: string;
|
|
84
|
+
}
|
|
64
85
|
export interface NetworkOptions {
|
|
65
86
|
trustProxy?: boolean | string | string[];
|
|
66
87
|
bodyLimit?: number;
|
|
@@ -88,6 +109,7 @@ export interface ConfigureHttpAppOptions {
|
|
|
88
109
|
export interface CreateAppOptions extends ConfigureHttpAppOptions {
|
|
89
110
|
rootModule: Type<unknown>;
|
|
90
111
|
network?: NetworkOptions;
|
|
91
|
-
|
|
112
|
+
/** Native Nest factory options, including an independent Nest logger. */
|
|
113
|
+
nest?: NestApplicationOptions;
|
|
92
114
|
}
|
|
93
115
|
//# sourceMappingURL=types.d.ts.map
|
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,SAAS,MAAM,qBAAqB,CAAC;AACjD,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,qBAAqB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# API stability policy
|
|
2
|
+
|
|
3
|
+
Version 1 follows Semantic Versioning. The supported public API is the root export
|
|
4
|
+
documented in `README.md` and the TypeScript declarations reachable from it.
|
|
5
|
+
|
|
6
|
+
## Compatibility guarantees
|
|
7
|
+
|
|
8
|
+
- Patch releases fix bugs and security issues without intentionally breaking valid
|
|
9
|
+
1.x configurations.
|
|
10
|
+
- Minor releases may add optional exports, options and preset capabilities. Existing
|
|
11
|
+
explicit options retain their behavior.
|
|
12
|
+
- Removed or renamed APIs require a deprecation in a minor release and removal in
|
|
13
|
+
the next major release, except when continued behavior creates a critical security
|
|
14
|
+
vulnerability.
|
|
15
|
+
- Undocumented `dist/*` paths and internal classes are not public API.
|
|
16
|
+
- Node, Nest and Fastify support ranges are declared in `package.json`. Dropping a
|
|
17
|
+
supported major runtime requires a new package major version.
|
|
18
|
+
|
|
19
|
+
The stable runtime exports are `createApp`, `configureHttpApp`, `Public`, `Roles`,
|
|
20
|
+
their metadata keys, and `HttpExceptionFilter`. Exported configuration and response
|
|
21
|
+
types are part of the TypeScript contract.
|
|
22
|
+
|
|
23
|
+
## Deprecation process
|
|
24
|
+
|
|
25
|
+
A deprecation is documented in the changelog and migration guide. When practical,
|
|
26
|
+
the previous behavior remains available throughout the current major release.
|
package/docs/configuration.md
CHANGED
|
@@ -13,7 +13,7 @@ All settings are optional except `rootModule` when using `createApp`.
|
|
|
13
13
|
| `versioning` | `false` | `true` for URI versioning, or Nest versioning options. |
|
|
14
14
|
| `shutdownHooks` | `true` | Enable Nest shutdown signal hooks. |
|
|
15
15
|
| `validation` | strict defaults | `false` or Nest `ValidationPipeOptions`. |
|
|
16
|
-
| `nest` | `{}` |
|
|
16
|
+
| `nest` | `{}` | Native `NestApplicationOptions`, including its independent logger. |
|
|
17
17
|
|
|
18
18
|
Default validation uses `whitelist: true`, `forbidNonWhitelisted: true`, and
|
|
19
19
|
`transform: false`. Transformation is off because implicit coercion costs work and
|
|
@@ -71,12 +71,27 @@ known payloads rather than automatically for every API.
|
|
|
71
71
|
|
|
72
72
|
Set `openApi: false` to guarantee the documentation integration is never loaded.
|
|
73
73
|
|
|
74
|
-
## Health
|
|
74
|
+
## Health
|
|
75
75
|
|
|
76
76
|
The full preset serves `{ "status": "ok" }` at `/health`. This is a liveness probe,
|
|
77
|
-
not a dependency-readiness check.
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
not a dependency-readiness check. `health.check` supplies a dynamic liveness result.
|
|
78
|
+
`health.readiness.check` adds a separate `/ready` endpoint for dependencies. A thrown
|
|
79
|
+
check returns only `{ "status": "unavailable" }` with HTTP 503 and logs the original
|
|
80
|
+
error internally. Health endpoints bypass the global rate limit so probes cannot
|
|
81
|
+
evict application traffic. Use `preHandler` when an endpoint must not be public.
|
|
82
|
+
|
|
83
|
+
| Option | Default | Description |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| `health.enabled` | full preset only | Enable liveness. |
|
|
86
|
+
| `health.path` | `/health` | Liveness route. |
|
|
87
|
+
| `health.response` | `{ status: 'ok' }` | Static liveness response. |
|
|
88
|
+
| `health.check` | none | Dynamic liveness callback. |
|
|
89
|
+
| `health.preHandler` | none | Access-control hook for liveness. |
|
|
90
|
+
| `health.readiness` | `false` | Object containing a required `check`. |
|
|
91
|
+
| `health.readiness.path` | `/ready` | Readiness route. |
|
|
92
|
+
| `health.readiness.preHandler` | none | Access-control hook for readiness. |
|
|
93
|
+
|
|
94
|
+
## Observability
|
|
80
95
|
|
|
81
96
|
Fastify's Pino JSON logger is enabled by default, while per-request logging is
|
|
82
97
|
disabled to reduce noise and overhead. Enable it with
|
|
@@ -87,4 +102,25 @@ metadata and never serializes headers or bodies.
|
|
|
87
102
|
|
|
88
103
|
The optional `responseTimeHeader` emits a standards-compatible `Server-Timing`
|
|
89
104
|
value. Default JSON logging redacts authorization, cookie and set-cookie fields. A
|
|
90
|
-
custom Pino `redact` configuration overrides those defaults.
|
|
105
|
+
custom Pino `redact` configuration overrides those defaults. Likewise, a custom
|
|
106
|
+
`serializers.req` replaces the safe request serializer, so redaction of URL data
|
|
107
|
+
then becomes the application's responsibility.
|
|
108
|
+
|
|
109
|
+
| Option | Default | Description |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| `observability.logger` | `true` | `false`, or Pino configuration for JSON logs. |
|
|
112
|
+
| `observability.loggerFormat` | `json` | `json` or readable `nest`. |
|
|
113
|
+
| `observability.requestLogging` | `false` | Log request start and completion. |
|
|
114
|
+
| `observability.includeQueryString` | `false` | Include potentially sensitive query strings in request logs. |
|
|
115
|
+
| `observability.requestIdResponseHeader` | `x-request-id` | Correlation response header, or `false`. |
|
|
116
|
+
| `observability.responseTimeHeader` | `false` | Emit `Server-Timing`. |
|
|
117
|
+
|
|
118
|
+
The Fastify logger and Nest logger are independent. Disable both explicitly with
|
|
119
|
+
`observability.logger: false` and `nest.logger: false`.
|
|
120
|
+
|
|
121
|
+
## Error response contract
|
|
122
|
+
|
|
123
|
+
Client-visible errors use the exported `HttpErrorResponse` shape: `statusCode`,
|
|
124
|
+
`error`, `message`, `requestId`, and `path`. Query strings never appear in `path`.
|
|
125
|
+
Every status from 500 through 599 receives the generic message `Internal server
|
|
126
|
+
error`; the original exception is available only in server logs.
|
package/docs/migration.md
CHANGED
|
@@ -24,3 +24,15 @@ application and this package share one framework instance.
|
|
|
24
24
|
`AuthuserModule` and `AUTHUSER_OPTIONS` were removed because their configuration was
|
|
25
25
|
not connected to adapter creation. Configure the application exclusively through
|
|
26
26
|
`createApp` or `configureHttpApp`.
|
|
27
|
+
|
|
28
|
+
## Migrating from 0.x to 1.x
|
|
29
|
+
|
|
30
|
+
- `observability.logger: false` disables Fastify logging only. Use
|
|
31
|
+
`nest.logger: false` when Nest logs must also be disabled.
|
|
32
|
+
- Responses include `x-request-id` by default. Set
|
|
33
|
+
`observability.requestIdResponseHeader: false` to opt out.
|
|
34
|
+
- Request logs omit query strings by default. Set
|
|
35
|
+
`observability.includeQueryString: true` only after reviewing data exposure.
|
|
36
|
+
- All 5xx response messages are generic and error paths omit query strings.
|
|
37
|
+
- Internal route paths must be unique and cannot contain query strings or fragments.
|
|
38
|
+
- `health.check` and `health.readiness` provide dynamic probe callbacks.
|
package/docs/performance.md
CHANGED
|
@@ -17,6 +17,10 @@ trades bandwidth for CPU. OpenAPI generation happens at startup, and its modules
|
|
|
17
17
|
not imported when disabled. Helmet, CORS, rate limiting and compression are also
|
|
18
18
|
dynamically imported only when their configuration enables them.
|
|
19
19
|
|
|
20
|
+
Pino JSON is the production logging default. The Nest-formatted adapter prioritizes
|
|
21
|
+
human readability and is intended primarily for local development; benchmark it
|
|
22
|
+
before enabling per-request Nest logs on a high-throughput service.
|
|
23
|
+
|
|
20
24
|
## Reproducible baseline
|
|
21
25
|
|
|
22
26
|
Run the dependency-free local regression benchmark:
|
|
@@ -30,6 +34,18 @@ Change duration and concurrency with `BENCHMARK_DURATION_MS` and
|
|
|
30
34
|
minimal preset and the secure preset. Treat them as a regression signal rather than
|
|
31
35
|
a production capacity promise.
|
|
32
36
|
|
|
37
|
+
The 1.0.0 release check on Node 22.14 with 100 local connections produced this
|
|
38
|
+
single-run baseline:
|
|
39
|
+
|
|
40
|
+
| Scenario | Requests/s | p50 | p99 | Errors |
|
|
41
|
+
| --- | ---: | ---: | ---: | ---: |
|
|
42
|
+
| Fastify raw | 30,703 | 3.23 ms | 3.73 ms | 0 |
|
|
43
|
+
| `@authuser/nest` minimal | 26,602 | 3.68 ms | 4.40 ms | 0 |
|
|
44
|
+
| `@authuser/nest` secure | 19,807 | 4.98 ms | 6.31 ms | 0 |
|
|
45
|
+
|
|
46
|
+
That run retained about 87% of raw Fastify throughput in `minimal` and 65% in
|
|
47
|
+
`secure`. It is a local regression reference, not a service capacity guarantee.
|
|
48
|
+
|
|
33
49
|
## Choosing a lower-level stack
|
|
34
50
|
|
|
35
51
|
If profiling shows Nest itself is the bottleneck, raw Fastify is the closest smaller
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Production checklist
|
|
2
|
+
|
|
3
|
+
Use this list before exposing a service to untrusted traffic.
|
|
4
|
+
|
|
5
|
+
## Application
|
|
6
|
+
|
|
7
|
+
- Start from the `secure` preset and document every disabled control.
|
|
8
|
+
- Authenticate and authorize sensitive routes with application guards.
|
|
9
|
+
- Keep `Public()` usage explicit and covered by authorization tests.
|
|
10
|
+
- Validate business rules, file uploads and data leaving persistence layers.
|
|
11
|
+
- Use `nest.logger` and `observability.logger` intentionally.
|
|
12
|
+
|
|
13
|
+
## Network and edge
|
|
14
|
+
|
|
15
|
+
- Terminate TLS at a trusted edge and redirect plaintext traffic.
|
|
16
|
+
- Configure `network.trustProxy` only for known proxy addresses or networks.
|
|
17
|
+
- Apply an infrastructure-level request/body limit no larger than the application
|
|
18
|
+
limit where possible.
|
|
19
|
+
- Tune connection, header, request and handler timeouts against production latency.
|
|
20
|
+
- Use an upstream DDoS control for an internet-facing API.
|
|
21
|
+
|
|
22
|
+
## Distributed operation
|
|
23
|
+
|
|
24
|
+
- Configure Redis or another shared `@fastify/rate-limit` store for multiple replicas.
|
|
25
|
+
- Give login, recovery and expensive routes stricter endpoint-specific limits.
|
|
26
|
+
- Keep liveness independent of downstream dependencies.
|
|
27
|
+
- Put database, queue and critical service checks in readiness.
|
|
28
|
+
- Ensure the orchestrator removes a replica when readiness returns 503.
|
|
29
|
+
|
|
30
|
+
## Exposure and data
|
|
31
|
+
|
|
32
|
+
- Disable or protect Swagger UI and OpenAPI in production.
|
|
33
|
+
- Do not return credentials or topology from health checks.
|
|
34
|
+
- Keep secrets and personal data out of URLs and logs.
|
|
35
|
+
- Keep JSON log redaction enabled and extend it for application-specific fields.
|
|
36
|
+
- Add CSRF protection when browsers authenticate with ambient cookies.
|
|
37
|
+
|
|
38
|
+
## Release
|
|
39
|
+
|
|
40
|
+
- Run `npm run check`, `npm run test:coverage`, `npm run test:package`, and
|
|
41
|
+
`npm run smoke --prefix example`.
|
|
42
|
+
- Review `npm audit --omit=dev` and dependency updates.
|
|
43
|
+
- Load-test realistic payloads through the production proxy and TLS path.
|
|
44
|
+
- Exercise shutdown while requests are active.
|
|
45
|
+
- Monitor latency percentiles, error rate, event-loop utilization and memory.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Release process
|
|
2
|
+
|
|
3
|
+
## Preparation
|
|
4
|
+
|
|
5
|
+
1. Ensure `main` is green and the worktree is clean.
|
|
6
|
+
2. Update `CHANGELOG.md` and the package version using Semantic Versioning.
|
|
7
|
+
3. Run `npm run check`, `npm run test:coverage`, `npm run test:package`, and
|
|
8
|
+
`npm run smoke --prefix example`.
|
|
9
|
+
4. Commit the release and create an annotated `vX.Y.Z` tag at that commit.
|
|
10
|
+
5. Push the commit and tag.
|
|
11
|
+
|
|
12
|
+
## Trusted publishing
|
|
13
|
+
|
|
14
|
+
Configure npm trusted publishing for:
|
|
15
|
+
|
|
16
|
+
- Organization/user: `authuser-org`
|
|
17
|
+
- Repository: `nest`
|
|
18
|
+
- Workflow: `.github/workflows/release.yml`
|
|
19
|
+
- Environment: `npm`
|
|
20
|
+
|
|
21
|
+
Create a GitHub Release from the version tag. The release workflow verifies that the
|
|
22
|
+
tag equals `package.json`, repeats all release checks, and publishes with npm
|
|
23
|
+
provenance through GitHub OIDC. No long-lived npm token should be stored in GitHub.
|
|
24
|
+
|
|
25
|
+
## Verification
|
|
26
|
+
|
|
27
|
+
Confirm the npm version and provenance, install it into a clean project, and verify
|
|
28
|
+
that the GitHub tag resolves to the same commit used by the release workflow.
|
package/docs/security.md
CHANGED
|
@@ -9,11 +9,14 @@ The secure preset establishes a baseline, not a complete application security mo
|
|
|
9
9
|
- A one MiB default request-body limit.
|
|
10
10
|
- Finite connection, request, handler and header timeouts.
|
|
11
11
|
- Rate limiting by client IP.
|
|
12
|
-
-
|
|
13
|
-
-
|
|
12
|
+
- `createApp` request IDs restricted to 128 safe characters before log propagation.
|
|
13
|
+
- Correlation IDs returned to clients in a configurable response header.
|
|
14
|
+
- Generic 5xx errors; unexpected exceptions are logged server-side only.
|
|
14
15
|
- CORS disabled until an allowlist is configured.
|
|
15
16
|
- Sensitive authentication and cookie log fields redacted by default.
|
|
17
|
+
- Query strings excluded from default request logs and error response paths.
|
|
16
18
|
- Optional pre-handler protection for documentation and health routes.
|
|
19
|
+
- Dynamic readiness checks that fail closed without exposing dependency errors.
|
|
17
20
|
|
|
18
21
|
## Application responsibilities
|
|
19
22
|
|
|
@@ -26,6 +29,9 @@ The secure preset establishes a baseline, not a complete application security mo
|
|
|
26
29
|
- Use TLS at the load balancer or application edge.
|
|
27
30
|
- Keep Node and dependencies patched and review `npm audit` output.
|
|
28
31
|
- Avoid exposing Swagger UI and detailed readiness data publicly.
|
|
32
|
+
- Keep credentials, tokens and personal data out of URL query parameters.
|
|
33
|
+
- Preserve the default request serializer, or redact equivalent data in a custom
|
|
34
|
+
Pino `serializers.req` implementation.
|
|
29
35
|
- Add CSRF protection when authentication relies on ambient cookies or sessions.
|
|
30
36
|
|
|
31
37
|
`Public()` and `Roles()` only attach metadata. They do nothing until an application
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Threat model
|
|
2
|
+
|
|
3
|
+
`@authuser/nest` hardens the HTTP process boundary for a Nest application. It does
|
|
4
|
+
not establish user identity or decide whether a caller may access a business object.
|
|
5
|
+
|
|
6
|
+
## Protected assets
|
|
7
|
+
|
|
8
|
+
- Availability of the Node process and its event loop.
|
|
9
|
+
- Confidentiality of request credentials and internal exception details.
|
|
10
|
+
- Integrity of parsed JSON objects and request correlation identifiers.
|
|
11
|
+
- Predictable application bootstrap and shutdown behavior.
|
|
12
|
+
|
|
13
|
+
## Included mitigations
|
|
14
|
+
|
|
15
|
+
- Bounded bodies, parameters, sockets and finite timeouts reduce common resource
|
|
16
|
+
exhaustion paths.
|
|
17
|
+
- Prototype and constructor poisoning are rejected during JSON parsing.
|
|
18
|
+
- Helmet establishes browser-facing security headers.
|
|
19
|
+
- Strict DTO defaults reject unexpected properties.
|
|
20
|
+
- CORS is closed until explicitly configured.
|
|
21
|
+
- Rate limiting controls abusive clients per instance or shared store.
|
|
22
|
+
- Incoming request IDs are validated by `createApp` before they reach logs.
|
|
23
|
+
- Sensitive headers and query strings are excluded from default logs.
|
|
24
|
+
- All 5xx details and health-check failures are hidden from clients.
|
|
25
|
+
|
|
26
|
+
## Explicitly out of scope
|
|
27
|
+
|
|
28
|
+
- Authentication, authorization, tenancy and object-level access control.
|
|
29
|
+
- TLS termination, WAF, network policy and volumetric DDoS protection.
|
|
30
|
+
- Database query construction, encryption, secret storage and key rotation.
|
|
31
|
+
- CSRF defenses for cookie-authenticated applications.
|
|
32
|
+
- Malware scanning, file validation and non-HTTP ingestion.
|
|
33
|
+
|
|
34
|
+
## Trust assumptions
|
|
35
|
+
|
|
36
|
+
- Nest, Fastify and direct dependencies are kept on supported patched versions.
|
|
37
|
+
- `trustProxy` contains only infrastructure controlled by the operator.
|
|
38
|
+
- A distributed deployment uses a shared rate-limit store.
|
|
39
|
+
- Application code does not deliberately log or expose sensitive data.
|
|
40
|
+
- Applications calling `configureHttpApp` directly configure equivalent request-ID
|
|
41
|
+
and network limits on their own Fastify adapter.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authuser/nest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Secure, high-performance NestJS foundation powered by Fastify",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nestjs",
|
|
@@ -19,17 +19,23 @@
|
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/index.d.ts",
|
|
21
21
|
"import": "./dist/index.js",
|
|
22
|
+
"require": "./dist/index.js",
|
|
22
23
|
"default": "./dist/index.js"
|
|
23
|
-
}
|
|
24
|
+
},
|
|
25
|
+
"./package.json": "./package.json"
|
|
24
26
|
},
|
|
25
27
|
"files": [
|
|
26
28
|
"dist",
|
|
27
29
|
"docs",
|
|
28
30
|
"README.md",
|
|
29
31
|
"CHANGELOG.md",
|
|
32
|
+
"SECURITY.md",
|
|
33
|
+
"SUPPORT.md",
|
|
30
34
|
"LICENSE"
|
|
31
35
|
],
|
|
32
|
-
"sideEffects":
|
|
36
|
+
"sideEffects": [
|
|
37
|
+
"./dist/index.js"
|
|
38
|
+
],
|
|
33
39
|
"engines": {
|
|
34
40
|
"node": ">=22.12"
|
|
35
41
|
},
|
|
@@ -43,8 +49,10 @@
|
|
|
43
49
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
44
50
|
"test": "vitest run",
|
|
45
51
|
"test:coverage": "vitest run --coverage",
|
|
52
|
+
"test:package": "npm run build && node scripts/verify-package.mjs",
|
|
46
53
|
"benchmark": "npm run build && node benchmark/run.mjs",
|
|
47
54
|
"prepack": "npm run clean && npm run build",
|
|
55
|
+
"prepublishOnly": "npm run check && npm run test:package",
|
|
48
56
|
"check": "npm run typecheck && npm test && npm run build && npm pack --dry-run"
|
|
49
57
|
},
|
|
50
58
|
"dependencies": {
|