@lenne.tech/nest-server 11.42.5 → 11.42.7
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/.claude/rules/configurable-features.md +2 -1
- package/.claude/rules/testing.md +3 -3
- package/FRAMEWORK-API.md +1 -1
- package/dist/core/common/helpers/swagger.helper.d.ts +11 -0
- package/dist/core/common/helpers/swagger.helper.js +362 -0
- package/dist/core/common/helpers/swagger.helper.js.map +1 -0
- package/dist/core/common/interfaces/swagger-setup-options.interface.d.ts +33 -0
- package/dist/core/common/interfaces/swagger-setup-options.interface.js +3 -0
- package/dist/core/common/interfaces/swagger-setup-options.interface.js.map +1 -0
- package/dist/core/common/services/core-body-parser.initializer.d.ts +2 -0
- package/dist/core/common/services/core-body-parser.initializer.js +23 -3
- package/dist/core/common/services/core-body-parser.initializer.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.js +8 -14
- package/dist/main.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/REQUEST-LIFECYCLE.md +1 -1
- package/migration-guides/11.42.3-to-11.42.4.md +10 -1
- package/migration-guides/11.42.5-to-11.42.6.md +113 -0
- package/migration-guides/11.42.6-to-11.42.7.md +115 -0
- package/package.json +4 -4
- package/src/core/common/helpers/swagger.helper.ts +529 -0
- package/src/core/common/interfaces/server-options.interface.ts +5 -0
- package/src/core/common/interfaces/swagger-setup-options.interface.ts +131 -0
- package/src/core/common/services/core-body-parser.initializer.ts +47 -5
- package/src/index.ts +2 -0
- package/src/main.ts +9 -15
|
@@ -569,7 +569,7 @@ Both use body-parser's default limit of **100 kB** unless `bodyParser` says othe
|
|
|
569
569
|
bodyParser: { json: { limit: '2mb' } },
|
|
570
570
|
```
|
|
571
571
|
|
|
572
|
-
`CoreBodyParserInitializer` applies it during module init by replacing the handle of the global parser layers NestJS created — in place, because NestJS registers them before any init hook runs and a parser appended later would sit behind the routes. Running during module init is what makes the limit hold under `Test.createTestingModule()`, which never runs `main.ts`. A path-scoped parser (`server.use('/upload', json({ limit }))` in `main.ts`) runs before the global one and is left untouched — that remains the way to give one path a different limit.
|
|
572
|
+
`CoreBodyParserInitializer` applies it during module init by replacing the handle of the global parser layers NestJS created — in place, because NestJS registers them before any init hook runs and a parser appended later would sit behind the routes. Running during module init is what makes the limit hold under `Test.createTestingModule()`, which never runs `main.ts`. A path-scoped parser (`server.use('/upload', json({ limit }))` in `main.ts`) runs before the global one and is left untouched — that remains the way to give one path a different limit. Keep `server.useBodyParser('json')` (or `'urlencoded'`) in `main.ts` next to it: NestJS registers its global parser only when no layer with the same function name exists, so a path-scoped one registered before `app.init()` suppresses it, and every other path receives an empty body. Since 11.42.6 `CoreBodyParserInitializer` warns at boot in that case.
|
|
573
573
|
|
|
574
574
|
The parser runs **before authentication and routing**. Over the limit, the whole request is refused:
|
|
575
575
|
|
|
@@ -63,6 +63,14 @@ server.useBodyParser('json', { limit: '2mb' });
|
|
|
63
63
|
bodyParser: { json: { limit: '2mb' } },
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
**Exception: keep `useBodyParser()` when `main.ts` also registers a path-scoped parser** such as
|
|
67
|
+
`server.use('/upload', json({ limit: '20mb' }))`. NestJS registers its own global parser only if no
|
|
68
|
+
layer with the same function name exists yet, and a path-scoped `json()` registered before
|
|
69
|
+
`app.init()` counts as one. Removing `useBodyParser()` then leaves the app without a global JSON
|
|
70
|
+
parser: every request outside that path reaches its handler with an empty body, and a sign-in fails
|
|
71
|
+
with a validation error. Keep `server.useBodyParser('json')` (the configured limit is applied to it)
|
|
72
|
+
and set the limit in the config as above. Since 11.42.6 the server warns at boot when it finds this.
|
|
73
|
+
|
|
66
74
|
**Starter-based projects:** `config.env.ts` builds `local` / `e2e` / `ci` from `localConfig()` and the
|
|
67
75
|
deployed environments from `deployedConfig()`. Put the limit where BOTH see it — the starter ships a
|
|
68
76
|
shared `PROJECT_BODY_PARSER` constant for this since its 11.42.4 update — or set
|
|
@@ -75,7 +83,8 @@ The config is applied during module init, so it holds in every test that builds
|
|
|
75
83
|
global parser your `main.ts` registered; keeping both is harmless, but the config wins.
|
|
76
84
|
|
|
77
85
|
A **path-scoped** parser is left alone: `server.use('/upload', json({ limit: '20mb' }))` in `main.ts`
|
|
78
|
-
still gives that one path its own limit
|
|
86
|
+
still gives that one path its own limit, as long as the global parser stays registered next to it
|
|
87
|
+
(see the exception above). The parser runs before routing, so a per-route limit can only
|
|
79
88
|
key on the path — and all GraphQL operations share one.
|
|
80
89
|
|
|
81
90
|
**`rawBody: true`:** `req.rawBody` is kept for apps created with `NestFactory.create(…, { rawBody:
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Migration Guide: 11.42.5 → 11.42.6
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
7
|
+
| **Correction** | The 11.42.3 → 11.42.4 guide told every project to drop `useBodyParser()` from `main.ts`. With a path-scoped parser in `main.ts` that removes JSON parsing everywhere else (§1) |
|
|
8
|
+
| **Improvement** | The server warns at boot when NestJS skipped its global body parser because of such a path-scoped one (§1) |
|
|
9
|
+
| **Tooling** | `check:overrides` no longer reports a failed audit as clean, and its probe follows `pnpm_config_registry` (§2) |
|
|
10
|
+
| **Breaking Changes** | None |
|
|
11
|
+
| **Migration Effort** | None for most projects. Projects that removed `useBodyParser()` while registering a path-scoped parser in `main.ts` must add it back (§1) |
|
|
12
|
+
|
|
13
|
+
## Quick Migration
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm update @lenne.tech/nest-server
|
|
17
|
+
pnpm run update # starter-based projects: raises every exact pin you share with the framework
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Then check `main.ts` as described in §1. Vendor-mode projects pick up the core update and need the
|
|
21
|
+
same check.
|
|
22
|
+
|
|
23
|
+
**Exact pins below the framework's own split packages in two.** A project that pins `@nestjs/core`,
|
|
24
|
+
`@nestjs/common`, `mongoose` or another package the framework also declares, at a LOWER exact version,
|
|
25
|
+
gets two copies of it. The install only prints a peer warning. The failure appears in the tests, as a
|
|
26
|
+
dependency-injection error that does not look like a version problem (see Troubleshooting).
|
|
27
|
+
`pnpm run update` (`extras/sync-packages.mjs` in starter-based projects) raises those pins. Without
|
|
28
|
+
that script, list the deviations and raise each one:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
node -e "const f=require('@lenne.tech/nest-server/package.json'),p=require('./package.json');const want={...f.dependencies,...f.peerDependencies};for(const s of ['dependencies','devDependencies'])for(const[k,v]of Object.entries(p[s]||{}))if(want[k]&&/^\d/.test(want[k])&&want[k]!==v)console.log(s,k,v,'->',want[k])"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
An `overrides:` entry in `pnpm-workspace.yaml` must not pin such a package below the framework's
|
|
35
|
+
version either: it forces the framework onto the older version without anybody having tested it.
|
|
36
|
+
|
|
37
|
+
## 1. Keep `useBodyParser()` next to a path-scoped parser
|
|
38
|
+
|
|
39
|
+
§1 of the [11.42.3 → 11.42.4 guide](./11.42.3-to-11.42.4.md) recommended moving the body limit from
|
|
40
|
+
`main.ts` into `bodyParser.json.limit` and deleting the `useBodyParser()` call. That is right, with one
|
|
41
|
+
exception the guide did not name.
|
|
42
|
+
|
|
43
|
+
NestJS registers its own global JSON and URL-encoded parsers inside `app.init()`, but only when no
|
|
44
|
+
layer with the same function name exists yet. It compares the NAME and nothing else. A path-scoped
|
|
45
|
+
parser registered in `main.ts` before `listen()` carries that name:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// main.ts
|
|
49
|
+
server.use('/diagnostics', json({ limit: '256kb' })); // a layer named `jsonParser`
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
With `useBodyParser()` removed, NestJS treats the JSON parser as already applied and registers none.
|
|
53
|
+
Every request outside `/diagnostics` then reaches its handler with an empty body. A sign-in fails with
|
|
54
|
+
a validation error such as "Missing input", and before this release nothing was logged.
|
|
55
|
+
|
|
56
|
+
**Check `main.ts`.** If it registers `json(...)` or `urlencoded(...)` on a path, keep or restore the
|
|
57
|
+
global parser next to it:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// main.ts
|
|
61
|
+
server.use('/diagnostics', json({ limit: '256kb' }));
|
|
62
|
+
server.useBodyParser('json'); // the configured bodyParser.json.limit is applied to it
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Keep the limit itself in the config (`bodyParser.json.limit`), where it also holds under
|
|
66
|
+
`Test.createTestingModule()`. The e2e suite cannot catch the missing parser: the testing module never
|
|
67
|
+
runs `main.ts`, so it never registers the path-scoped parser either.
|
|
68
|
+
|
|
69
|
+
Since 11.42.6 the server logs a warning at boot in exactly this situation:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
No global json body parser is registered: NestJS skips its own when a layer named `jsonParser`
|
|
73
|
+
already exists, and a path-scoped `json()` parser registered before `app.init()` counts as one. …
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The framework only reports it. It does not register the missing parser itself: NestJS would have put
|
|
77
|
+
it after everything `main.ts` registered, and that position is no longer known during module init. A
|
|
78
|
+
raw-body webhook or a proxy registered after the path-scoped parser must keep receiving the unread
|
|
79
|
+
request stream.
|
|
80
|
+
|
|
81
|
+
## 2. `check:overrides`: a failed audit is no longer reported as clean
|
|
82
|
+
|
|
83
|
+
Two fixes in `scripts/check-overrides.mjs` (and the shared registry block in `scripts/check.mjs`):
|
|
84
|
+
|
|
85
|
+
- When pnpm 11 cannot reach the registry, `pnpm audit --json` prints
|
|
86
|
+
`{"error": {"message": "fetch failed"}}` instead of a report. The guard read that as "0 advisories"
|
|
87
|
+
and printed `ok — N override(s) checked … none is failing`. It now prints
|
|
88
|
+
`could not obtain an audit report` (exit 0) on a live run, and fails (exit 1) when the failed report
|
|
89
|
+
was passed in with `--audit-file`, which is the CI path. The suppression checks still run in that
|
|
90
|
+
case, because they ask the GitHub Advisory API rather than the audit: a suppressed advisory that
|
|
91
|
+
gained a fix still fails with `FIX AVAILABLE`.
|
|
92
|
+
- The clean-tree probe reads `pnpm_config_registry`, the variable pnpm 11 audits against. It used to
|
|
93
|
+
read `npm_config_registry`, which pnpm 11 ignores, and could then ask a registry the audit never used.
|
|
94
|
+
|
|
95
|
+
`scripts/` is not part of the npm package. Projects created from nest-server-starter or lt-monorepo
|
|
96
|
+
receive these fixes with their template update.
|
|
97
|
+
|
|
98
|
+
## Troubleshooting
|
|
99
|
+
|
|
100
|
+
| Symptom | Cause | Fix |
|
|
101
|
+
| ------- | ----- | --- |
|
|
102
|
+
| Boot warning "No global json body parser is registered" | `main.ts` registers a path-scoped `json()` and no global parser | Add `server.useBodyParser('json')` to `main.ts` (§1) |
|
|
103
|
+
| Requests arrive with an empty body outside one path; sign-in reports "Missing input" | Same cause, on a version before 11.42.6 | Same fix (§1) |
|
|
104
|
+
| Tests fail with `Nest can't resolve dependencies of the MongooseCoreModule (MongooseConnectionName, ?)` (often hidden behind `Cannot read properties of undefined` from a `beforeAll` that swallows it) | Two copies of `@nestjs/core`: the project pins it below the framework's version | Raise the exact pins (Quick Migration), then check that `pnpm-lock.yaml` holds one copy of each |
|
|
105
|
+
| `check:overrides` prints `could not obtain an audit report (fetch failed)` | The npm registry was not reachable during the audit | Re-run with network access, or pass a captured report with `--audit-file` |
|
|
106
|
+
| `check:overrides` fails with `records a failed audit, not a result` | The report passed with `--audit-file` is a pnpm error, not an audit | Capture the report again once the registry answers |
|
|
107
|
+
|
|
108
|
+
## Module Documentation
|
|
109
|
+
|
|
110
|
+
- [REQUEST-LIFECYCLE.md — 0d. Body parsers](../docs/REQUEST-LIFECYCLE.md)
|
|
111
|
+
- [11.42.3 → 11.42.4 guide §1](./11.42.3-to-11.42.4.md)
|
|
112
|
+
- `.claude/rules/configurable-features.md` — Body Parser Limits row
|
|
113
|
+
- `.claude/rules/package-management.md` — the `check:overrides` guard
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Migration Guide: 11.42.6 → 11.42.7
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **New Feature** | `setupSwagger()` — a Swagger document that says how each route is reached: security, API-token scopes, tenant header (§1) |
|
|
8
|
+
| **New Feature** | Optional second document with only the routes an API token may call (§2) |
|
|
9
|
+
| **Dependencies** | `nodemailer` 10.0.15, `@modelcontextprotocol/sdk` 1.32.1, dev: `oxlint` 1.87.0 (§3) |
|
|
10
|
+
| **Breaking Changes** | None |
|
|
11
|
+
| **Migration Effort** | Optional. Switching `main.ts` to the helper replaces the hand-built `DocumentBuilder` block with one call |
|
|
12
|
+
|
|
13
|
+
## Quick Migration
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm update @lenne.tech/nest-server
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Nothing changes until `main.ts` calls the new helper. Vendor-mode projects pick it up with the core
|
|
20
|
+
update.
|
|
21
|
+
|
|
22
|
+
## 1. `setupSwagger()` instead of a hand-built `DocumentBuilder`
|
|
23
|
+
|
|
24
|
+
The starters built the document like this:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
const config = new DocumentBuilder().setTitle('…').addBearerAuth().build();
|
|
28
|
+
SwaggerModule.setup('swagger', server, () => SwaggerModule.createDocument(server, config, { … }), {
|
|
29
|
+
jsonDocumentUrl: '/api-docs-json',
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`addBearerAuth()` registers a scheme but attaches it to no route. A token entered under "Authorize" is
|
|
34
|
+
therefore sent with almost no request: in one project 10 of 158 operations carried a security entry.
|
|
35
|
+
And what a caller needs to know — is the route public, which API-token scope does it release, does it
|
|
36
|
+
read the tenant header — lived only in decorators.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { setupSwagger } from '@lenne.tech/nest-server';
|
|
40
|
+
|
|
41
|
+
setupSwagger(server, {
|
|
42
|
+
description: 'API of my project',
|
|
43
|
+
documentOptions: {
|
|
44
|
+
extraModels: [CoreUserModel, CoreAuthModel, User, PersistenceModel, CorePersistenceModel, FilterArgs],
|
|
45
|
+
},
|
|
46
|
+
title: 'My Project API',
|
|
47
|
+
version: packageJson.version,
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Paths stay as before (`/swagger`, `/api-docs-json`) unless `path` / `jsonDocumentUrl` say otherwise.
|
|
52
|
+
What the document now contains, read from the same metadata the guards read:
|
|
53
|
+
|
|
54
|
+
| Feature in the config | In the document |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| always | `bearer` as a global security requirement — "Authorize" applies to every route. Public routes (no `@Roles`, or `S_EVERYONE`) carry `security: []` |
|
|
57
|
+
| `betterAuth` + `cookies` on | the session cookie (`iam.session_token`, or the name `COOKIE_PREFIX` / `basePath` produce) as a second, alternative requirement |
|
|
58
|
+
| `apiTokens` on | per operation `x-api-token-scopes` and a description line: "allowed with scope `read`" or "not allowed on this route". `@ApiTokenScopes()` on the method replaces the class declaration, exactly as in `assertApiTokenScopes()` |
|
|
59
|
+
| `multiTenancy` on | a reusable `TenantHeader` parameter (`X-Tenant-Id`, or `multiTenancy.headerName`) on every operation except public ones and `@SkipTenantCheck()`; its description says which callers need it (sessions and personal tokens) and which may omit it (company tokens) |
|
|
60
|
+
|
|
61
|
+
Optional:
|
|
62
|
+
|
|
63
|
+
- `operationTags: (operation) => string[] | undefined` regroups operations by use case instead of by
|
|
64
|
+
controller; `tags: [{ name, description }]` orders and describes them.
|
|
65
|
+
- `configureBuilder: (builder) => builder` adds servers, contact or further schemes.
|
|
66
|
+
- `customOptions` is passed to `SwaggerModule.setup()` for both documents.
|
|
67
|
+
|
|
68
|
+
Each operation is mapped to its handler through the default operation id (`<Controller>_<method>`, with
|
|
69
|
+
`[<n>]` for a handler serving several paths). An own `operationIdFactory` is therefore refused. Two different controller classes with the same name
|
|
70
|
+
cannot be told apart; their operations are left as Swagger built them, with a warning.
|
|
71
|
+
|
|
72
|
+
## 2. A document for API-token callers
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
setupSwagger(server, { …, apiTokenView: true });
|
|
76
|
+
// or: apiTokenView: { path: 'swagger-partner', title: 'Partner API' }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Serves a second document (default: UI `swagger-api-tokens`, JSON `/api-docs-api-tokens-json`) with only
|
|
80
|
+
the operations that release a scope, the bearer scheme as the only requirement and without the schemas
|
|
81
|
+
nothing refers to any more. Keep its path outside the path of the full UI, which serves its assets below
|
|
82
|
+
its own path.
|
|
83
|
+
|
|
84
|
+
The tenant header stays in this view while personal (user) tokens are enabled (`apiTokens.userTokens`,
|
|
85
|
+
the default): such a token without a company restriction chooses the company like a session does, and
|
|
86
|
+
without the header it is checked against its global roles and refused on company routes. With company
|
|
87
|
+
tokens only (`userTokens: false`) the header is dropped — a company token carries its company.
|
|
88
|
+
|
|
89
|
+
## 3. Dependency updates
|
|
90
|
+
|
|
91
|
+
Patch-level maintenance, no code changes required:
|
|
92
|
+
|
|
93
|
+
| Package | Old | New | Section |
|
|
94
|
+
| --- | --- | --- | --- |
|
|
95
|
+
| `nodemailer` | 10.0.14 | 10.0.15 | dependencies |
|
|
96
|
+
| `@modelcontextprotocol/sdk` | 1.32.0 | 1.32.1 | dependencies |
|
|
97
|
+
| `oxlint` | 1.86.0 | 1.87.0 | devDependencies |
|
|
98
|
+
|
|
99
|
+
A project that pins `oxlint` itself should raise it to 1.87.0 alongside the framework —
|
|
100
|
+
`pnpm run update` in starter-based projects does this. A project that carries a `nodemailer`
|
|
101
|
+
override matching the framework's version (the starter does) should raise it to `10.0.15`.
|
|
102
|
+
|
|
103
|
+
## Compatibility Notes
|
|
104
|
+
|
|
105
|
+
- The helper is additive. `DocumentBuilder` + `SwaggerModule.setup()` keep working unchanged.
|
|
106
|
+
- The document is built on the first request, as before.
|
|
107
|
+
- `buildSwaggerDocument()` and `buildApiTokenSwaggerDocument()` are exported for tests: a project can
|
|
108
|
+
assert in its e2e suite that a route documents the scope it enforces.
|
|
109
|
+
|
|
110
|
+
## References
|
|
111
|
+
|
|
112
|
+
- Helper: `src/core/common/helpers/swagger.helper.ts`
|
|
113
|
+
- Options: `src/core/common/interfaces/swagger-setup-options.interface.ts`
|
|
114
|
+
- Tests: `tests/unit/swagger-helper.spec.ts`
|
|
115
|
+
- [nest-server-starter](https://github.com/lenneTech/nest-server-starter) `src/main.ts`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.42.
|
|
3
|
+
"version": "11.42.7",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"@apollo/server": "5.5.1",
|
|
93
93
|
"@as-integrations/express5": "1.1.2",
|
|
94
94
|
"@getbrevo/brevo": "6.0.3",
|
|
95
|
-
"@modelcontextprotocol/sdk": "1.32.
|
|
95
|
+
"@modelcontextprotocol/sdk": "1.32.1",
|
|
96
96
|
"@nestjs/apollo": "13.4.5",
|
|
97
97
|
"@nestjs/common": "11.2.7",
|
|
98
98
|
"@nestjs/core": "11.2.7",
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
"mongoose": "9.10.4",
|
|
130
130
|
"multer": "2.4.0",
|
|
131
131
|
"node-mailjet": "6.0.11",
|
|
132
|
-
"nodemailer": "10.0.
|
|
132
|
+
"nodemailer": "10.0.15",
|
|
133
133
|
"passport": "0.7.0",
|
|
134
134
|
"passport-jwt": "4.0.1",
|
|
135
135
|
"reflect-metadata": "0.2.2",
|
|
@@ -212,7 +212,7 @@
|
|
|
212
212
|
"npm-watch": "0.13.0",
|
|
213
213
|
"otpauth": "9.5.2",
|
|
214
214
|
"oxfmt": "0.71.0",
|
|
215
|
-
"oxlint": "1.
|
|
215
|
+
"oxlint": "1.87.0",
|
|
216
216
|
"rimraf": "6.1.3",
|
|
217
217
|
"smtp-server": "3.19.17",
|
|
218
218
|
"ts-node": "10.9.2",
|