@nodefony/http 10.0.0-beta.6 → 10.0.0-beta.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/dist/_virtual/{_@oxc-project_runtime@0.157.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.157.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorateParam.js +1 -1
- package/dist/index.js +3 -2
- package/dist/nodefony/config/config.js +25 -2
- package/dist/nodefony/grpc/GrpcCall.js +298 -0
- package/dist/nodefony/grpc/GrpcEndpoint.js +528 -0
- package/dist/nodefony/grpc/index.js +4 -0
- package/dist/nodefony/interfaces/IRpcCall.js +1 -0
- package/dist/nodefony/service/audit-logger.js +52 -6
- package/dist/nodefony/service/error-renderer.js +41 -9
- package/dist/nodefony/service/http-kernel.js +198 -19
- package/dist/nodefony/service/pretty-request-logger.js +5 -3
- package/dist/nodefony/service/request-logger.js +21 -6
- package/dist/nodefony/service/reverse-proxy.js +1 -1
- package/dist/nodefony/service/servers/clientError.js +26 -1
- package/dist/nodefony/service/servers/server-h2c.js +3 -3
- package/dist/nodefony/service/servers/server-http.js +3 -3
- package/dist/nodefony/service/servers/server-https.js +4 -4
- package/dist/nodefony/service/servers/server-websocket-secure.js +3 -3
- package/dist/nodefony/service/servers/server-websocket.js +3 -3
- package/dist/nodefony/service/servers/serverShutdown.js +14 -36
- package/dist/nodefony/service/sessions/sessions-service.js +6 -6
- package/dist/nodefony/service/upload/upload-service.js +2 -2
- package/dist/nodefony/src/context/Context.js +12 -1
- package/dist/nodefony/src/context/http/ByteStream.js +9 -4
- package/dist/nodefony/src/context/http/HttpContext.js +86 -8
- package/dist/nodefony/src/context/http/Request.js +96 -16
- package/dist/nodefony/src/context/http/Response.js +120 -17
- package/dist/nodefony/src/context/http/SseStream.js +4 -4
- package/dist/nodefony/src/context/http/StreamLifecycle.js +328 -19
- package/dist/nodefony/src/context/http/parser.js +29 -11
- package/dist/nodefony/src/context/http/webResponse.js +56 -0
- package/dist/nodefony/src/context/http2/Response.js +47 -8
- package/dist/nodefony/src/context/requestTrace.js +6 -2
- package/dist/nodefony/src/context/rpcOutcome.js +20 -0
- package/dist/nodefony/src/context/websocket/Response.js +11 -1
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +15 -4
- package/dist/nodefony/src/cookies/cookie.js +3 -1
- package/dist/nodefony/src/errors/httpError.js +58 -25
- package/dist/nodefony/src/grpc/cors.js +59 -0
- package/dist/nodefony/src/grpc/limits.js +16 -0
- package/dist/nodefony/src/grpc/refusal.js +271 -0
- package/dist/nodefony/src/profiler/aggregate.js +2 -2
- package/dist/nodefony/src/proxy/forward.js +1 -1
- package/dist/nodefony/src/proxy/generateProxyConfig.js +91 -15
- package/dist/nodefony/src/servers/http2Goaway.js +76 -0
- package/dist/nodefony/src/servers/http2Limits.js +41 -15
- package/dist/nodefony/src/servers/http2StreamGrace.js +100 -0
- package/dist/nodefony/src/servers/receiveDeadline.js +177 -0
- package/dist/types/index.d.ts +5 -2
- package/dist/types/nodefony/config/config.d.ts +10 -0
- package/dist/types/nodefony/grpc/GrpcCall.d.ts +142 -0
- package/dist/types/nodefony/grpc/GrpcEndpoint.d.ts +98 -0
- package/dist/types/nodefony/grpc/index.d.ts +15 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +9 -0
- package/dist/types/nodefony/interfaces/IErrorRenderer.d.ts +14 -0
- package/dist/types/nodefony/interfaces/IRequest.d.ts +2 -1
- package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +10 -0
- package/dist/types/nodefony/interfaces/IRouting.d.ts +19 -0
- package/dist/types/nodefony/interfaces/IRpcCall.d.ts +83 -0
- package/dist/types/nodefony/interfaces/IUpload.d.ts +51 -4
- package/dist/types/nodefony/interfaces/index.d.ts +2 -1
- package/dist/types/nodefony/service/audit-logger.d.ts +33 -3
- package/dist/types/nodefony/service/error-renderer.d.ts +22 -1
- package/dist/types/nodefony/service/http-kernel.d.ts +21 -1
- package/dist/types/nodefony/service/request-logger.d.ts +10 -0
- package/dist/types/nodefony/service/servers/serverShutdown.d.ts +2 -2
- package/dist/types/nodefony/src/context/Context.d.ts +9 -1
- package/dist/types/nodefony/src/context/http/ByteStream.d.ts +1 -1
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +56 -2
- package/dist/types/nodefony/src/context/http/Request.d.ts +38 -8
- package/dist/types/nodefony/src/context/http/Response.d.ts +61 -7
- package/dist/types/nodefony/src/context/http/SseStream.d.ts +1 -1
- package/dist/types/nodefony/src/context/http/StreamLifecycle.d.ts +53 -0
- package/dist/types/nodefony/src/context/http/parser.d.ts +17 -3
- package/dist/types/nodefony/src/context/http/webResponse.d.ts +31 -0
- package/dist/types/nodefony/src/context/http2/Response.d.ts +35 -2
- package/dist/types/nodefony/src/context/requestTrace.d.ts +3 -1
- package/dist/types/nodefony/src/context/rpcOutcome.d.ts +11 -0
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +6 -1
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +8 -0
- package/dist/types/nodefony/src/errors/httpError.d.ts +29 -4
- package/dist/types/nodefony/src/grpc/cors.d.ts +32 -0
- package/dist/types/nodefony/src/grpc/limits.d.ts +14 -0
- package/dist/types/nodefony/src/grpc/refusal.d.ts +136 -0
- package/dist/types/nodefony/src/proxy/forward.d.ts +7 -0
- package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +15 -2
- package/dist/types/nodefony/src/servers/http2Goaway.d.ts +41 -0
- package/dist/types/nodefony/src/servers/http2Limits.d.ts +27 -14
- package/dist/types/nodefony/src/servers/http2StreamGrace.d.ts +34 -0
- package/dist/types/nodefony/src/servers/receiveDeadline.d.ts +77 -0
- package/docs/byte-stream.md +52 -17
- package/docs/diagnostics-channel.md +45 -1
- package/docs/servers.md +57 -44
- package/docs/upload.md +43 -17
- package/package.json +26 -6
package/docs/upload.md
CHANGED
|
@@ -297,6 +297,30 @@ du calque de configuration — une application peut les changer pour une requêt
|
|
|
297
297
|
sont lus au moment de lire le corps (`Request.readBodyLimits()`), donc un calque posé après ce moment
|
|
298
298
|
(au pare-feu, dans un contrôleur) n'agit pas. Détail : [configuration](../../../../../docs/guides/configuration.md).
|
|
299
299
|
|
|
300
|
+
### Par route — l'option `upload`
|
|
301
|
+
|
|
302
|
+
Une route règle ses propres bornes d'envoi, sans toucher à celles des autres : un dépôt de vidéos
|
|
303
|
+
relève `maxFileSize`, un avatar l'abaisse. Chaque clé déclarée remplace celle de la configuration,
|
|
304
|
+
**dans les deux sens** ; une clé absente garde la valeur de la configuration
|
|
305
|
+
(`framework/nodefony/src/Route.ts#RouteOptions.upload`).
|
|
306
|
+
|
|
307
|
+
```ts ignore
|
|
308
|
+
// un avatar : 256 Kio au plus, un seul fichier, son empreinte calculée pendant le flux
|
|
309
|
+
@Post("/avatar", { upload: { maxFileSize: 262_144, maxFiles: 1, hashAlgorithm: "sha256" } })
|
|
310
|
+
async avatar(@UploadedFile() file: IUploadedFile | undefined) {
|
|
311
|
+
return { size: file?.size ?? 0, sha256: file?.hash ?? null };
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- **Le fichier trop gros est coupé PENDANT son flux** (413) : la route est résolue avant la lecture
|
|
316
|
+
du corps, ses bornes s'appliquent donc à busboy comme celles de la configuration — jamais un
|
|
317
|
+
fichier écrit en entier puis refusé (`context/http/Request.ts#HttpRequest.readBodyLimits`).
|
|
318
|
+
- **Une route sans l'option ne paie rien** : aucune fusion, aucune allocation.
|
|
319
|
+
- **Validée à la déclaration** (`framework/nodefony/decorators/routerDecorators.ts#checkedUpload`) :
|
|
320
|
+
entiers ≥ 1, empreinte connue, aucune clé inconnue — une faute de frappe (`maxFilesize`) laisserait
|
|
321
|
+
sinon la route sur la borne de l'application. `uploadDir` et `encoding` restent ceux de la
|
|
322
|
+
configuration. Exclue avec `bodyStream: true`, dont le corps n'est jamais lu par le pipeline.
|
|
323
|
+
|
|
300
324
|
### Fichiers multipart — `upload.*`
|
|
301
325
|
|
|
302
326
|
Table dérivée de `uploadSchema` (`config/config.ts#uploadSchema`). Toutes les bornes sont `runtimeMutable`.
|
|
@@ -342,15 +366,15 @@ Les décorateurs `@UploadedFile` / `@UploadedFiles` sont des fabriques de param
|
|
|
342
366
|
Chaque entrée de `files` est un `UploadedFile` (`service/upload/upload-service.ts#UploadedFile`), déjà écrit
|
|
343
367
|
sur disque. Ses membres utiles :
|
|
344
368
|
|
|
345
|
-
| Membre | Ce qu'il donne
|
|
346
|
-
| ------------------------ |
|
|
347
|
-
| `filename` | Nom **d'origine** déclaré par le client (métadonnée, jamais le chemin).
|
|
348
|
-
| `size` | Taille réellement écrite (octets).
|
|
349
|
-
| `prettySize` | Taille lisible (`« 1.2 MB »`).
|
|
350
|
-
| `mimeType` | Type MIME déclaré (`image/png`…), sinon deviné de l'extension.
|
|
351
|
-
| `hash` / `hashAlgorithm` | Empreinte d'intégrité si `upload.hashAlgorithm` est réglé.
|
|
352
|
-
| `moveAsync(target)` | Déplace le temp — **non bloquant, recommandé** dans le pipeline.
|
|
353
|
-
| `move(target)` | Variante **synchrone** (compat) — bloque l'event-loop.
|
|
369
|
+
| Membre | Ce qu'il donne | Ancrage |
|
|
370
|
+
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
371
|
+
| `filename` | Nom **d'origine** déclaré par le client (métadonnée, jamais le chemin). | `realName()` (`service/upload/upload-service.ts#UploadedFile.realName`) |
|
|
372
|
+
| `size` | Taille réellement écrite (octets). | `getSize()` (`service/upload/upload-service.ts#UploadedFile.getSize`) |
|
|
373
|
+
| `prettySize` | Taille lisible (`« 1.2 MB »`). | `getPrettySize()` (`service/upload/upload-service.ts#UploadedFile.getPrettySize`) |
|
|
374
|
+
| `mimeType` | Type MIME déclaré (`image/png`…), sinon deviné de l'extension ; `false` si ni l'un ni l'autre. Déclaratif : jamais une preuve du contenu. | `getMimeType()` (`service/upload/upload-service.ts#UploadedFile.getMimeType`) |
|
|
375
|
+
| `hash` / `hashAlgorithm` | Empreinte d'intégrité si `upload.hashAlgorithm` est réglé. | `interfaces/IUpload.ts#IUploadedFile.hashAlgorithm` |
|
|
376
|
+
| `moveAsync(target)` | Déplace le temp — **non bloquant, recommandé** dans le pipeline. Rend le `FileClass` de la destination (sans nom d'origine ni empreinte : ils restent sur le fichier reçu). | `moveAsync()` (`service/upload/upload-service.ts#UploadedFile.moveAsync`) |
|
|
377
|
+
| `move(target)` | Variante **synchrone** (compat) — bloque l'event-loop. | `move()` (`service/upload/upload-service.ts#UploadedFile.move`) |
|
|
354
378
|
|
|
355
379
|
`move`/`moveAsync` acceptent un **fichier cible** ou un **dossier existant** : sur un dossier, la
|
|
356
380
|
destination est bâtie avec `filename` — d'où l'avertissement de sécurité ci-dessous.
|
|
@@ -429,6 +453,7 @@ pipeline : `npm run test:memory` (skill `nodefony-check-memory-health`).
|
|
|
429
453
|
| `@Body()` est vide sur un upload de fichier | Les fichiers vont dans `files`, **pas** dans `body` | Lire les fichiers avec `@UploadedFiles()` / `this.files` ; `@Body()` = champs texte |
|
|
430
454
|
| Un `POST` JSON de 1,5 Mo est refusé en `413` | `maxBodySize` vaut **1 MiB** par défaut | Augmenter `maxBodySize` (pas `upload.maxFileSize`) |
|
|
431
455
|
| Un gros fichier passe alors que `maxBodySize` est petit | Le multipart **n'écoute pas** `maxBodySize` | Régler `upload.maxFileSize` / `maxTotalFileSize` |
|
|
456
|
+
| Un avatar de 2 Go remplit le disque avant d'être refusé | La borne de l'application (500 Mo) vaut pour toutes les routes | Option de route `upload: { maxFileSize }` — coupé pendant le flux |
|
|
432
457
|
| `413` sur upload sans message clair | Une borne busboy atteinte en streaming (fichier, cumul, nombre) | Vérifier les bornes `upload.*` — 413 émis sur `stream.on("limit")` (`context/http/Request.ts#HttpRequest.enforceBodyLimit`) |
|
|
433
458
|
| Un fichier écrit `../../etc/…` après un `move` | `move(dossier)` utilise le nom **client** (`upload-service.ts#UploadedFile.move`) | Passer une cible complète, ou `path.basename(file.filename)` |
|
|
434
459
|
| Des fichiers temporaires s'accumulent dans `uploadDir` | Le contrôleur ne déplace jamais le temp | Appeler `moveAsync()` (ou purger l'ancien temp par TTL) |
|
|
@@ -441,14 +466,15 @@ pipeline : `npm run test:memory` (skill `nodefony-check-memory-health`).
|
|
|
441
466
|
Les chiffres exacts vivent dans la carte de tests de cette page (régénérée depuis vitest, jamais figés
|
|
442
467
|
dans le Markdown).
|
|
443
468
|
|
|
444
|
-
| Type | Où
|
|
445
|
-
| --------------------------- |
|
|
446
|
-
| Unitaires — `UploadedFile` | `unit/UploadedFile.test.ts` — `create()` async, `move`/`moveAsync`, `mimeType`, `realName`
|
|
447
|
-
| Unitaires — `@Body` stream | `framework` `unit/BodyStream.test.ts` — `@Body({ stream })`, `resolveParamArg`, `routeExpectsBodyStream`
|
|
448
|
-
| Intégration — multipart | `http/upload.test.ts` — upload simple, multi-fichiers, mime non-octet, champ + fichier, `413` par fichier et cumulé |
|
|
449
|
-
|
|
|
450
|
-
| Intégration —
|
|
451
|
-
| Intégration —
|
|
469
|
+
| Type | Où |
|
|
470
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
471
|
+
| Unitaires — `UploadedFile` | `unit/UploadedFile.test.ts` — `create()` async, `move`/`moveAsync`, `mimeType`, `realName` |
|
|
472
|
+
| Unitaires — `@Body` stream | `framework` `unit/BodyStream.test.ts` — `@Body({ stream })`, `resolveParamArg`, `routeExpectsBodyStream` |
|
|
473
|
+
| Intégration — multipart | `http/upload.test.ts` — upload simple, multi-fichiers, mime non-octet, champ + fichier, `413` par fichier et cumulé ; bornes et empreinte PAR ROUTE (abaissée, relevée), aucun temporaire laissé par un refus |
|
|
474
|
+
| Unitaires — option `upload` | `framework` `unit/httpMethodDecorators.test.ts` — portée jusqu'à la route, figée ; refus à la déclaration |
|
|
475
|
+
| Intégration — content-types | `http/body-content-types.test.ts` — JSON, urlencoded, `@Body("champ")`, XML → `body` |
|
|
476
|
+
| Intégration — bornes | `http/body-limit.test.ts` — sous la limite `200`, `Content-Length` > 1 MiB → `413`, chunked > 1 MiB refusé |
|
|
477
|
+
| Intégration — flux brut | `integration/bodyStream.test.ts` — `@Body({ stream })` bout-en-bout (TLS + clair), non-régression `@Body()` |
|
|
452
478
|
|
|
453
479
|
Ce qui **manque** aujourd'hui : pas de banc de **charge** dédié à l'upload (le streaming multipart n'est
|
|
454
480
|
exercé que fonctionnellement), pas de test **d'attaque** (`*.attack.test.ts`) sur le path traversal de
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodefony/http",
|
|
3
|
-
"version": "10.0.0-beta.
|
|
3
|
+
"version": "10.0.0-beta.7",
|
|
4
4
|
"description": "Serveurs HTTP, HTTPS, HTTP/2 et WebSocket natifs pour Nodefony : sessions, contextes de requête, certificats TLS",
|
|
5
5
|
"author": "Christophe CAMENSULI <ccamensuli@gmail.com>",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
"types": "./dist/types/index.d.ts",
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./grpc": {
|
|
17
|
+
"nodefony-source": "./nodefony/grpc/index.ts",
|
|
18
|
+
"types": "./dist/types/nodefony/grpc/index.d.ts",
|
|
19
|
+
"import": "./dist/nodefony/grpc/index.js",
|
|
20
|
+
"default": "./dist/nodefony/grpc/index.js"
|
|
15
21
|
}
|
|
16
22
|
},
|
|
17
23
|
"scripts": {
|
|
@@ -27,7 +33,7 @@
|
|
|
27
33
|
},
|
|
28
34
|
"private": false,
|
|
29
35
|
"engines": {
|
|
30
|
-
"node": "
|
|
36
|
+
"node": "^24.16.0 || >=26.0.0"
|
|
31
37
|
},
|
|
32
38
|
"keywords": [
|
|
33
39
|
"nodefony",
|
|
@@ -63,7 +69,7 @@
|
|
|
63
69
|
"qs": "^6.17.1",
|
|
64
70
|
"serve-static": "2.2.1",
|
|
65
71
|
"tslib": "2.9.1",
|
|
66
|
-
"ws": "8.
|
|
72
|
+
"ws": "8.23.0",
|
|
67
73
|
"xml2js": "0.6.2"
|
|
68
74
|
},
|
|
69
75
|
"devDependencies": {
|
|
@@ -72,7 +78,7 @@
|
|
|
72
78
|
"@types/node": "26.6.6",
|
|
73
79
|
"@types/websocket": "1.0.10",
|
|
74
80
|
"@vitest/coverage-v8": "5.1.0",
|
|
75
|
-
"nodefony": "^10.0.0-beta.
|
|
81
|
+
"nodefony": "^10.0.0-beta.7",
|
|
76
82
|
"tsx": "4.23.15",
|
|
77
83
|
"vitest": "5.1.0"
|
|
78
84
|
},
|
|
@@ -80,9 +86,23 @@
|
|
|
80
86
|
"readmeFilename": "README.md",
|
|
81
87
|
"contributors": [],
|
|
82
88
|
"peerDependencies": {
|
|
83
|
-
"
|
|
89
|
+
"@bufbuild/protobuf": "^2.7.0",
|
|
90
|
+
"@connectrpc/connect": "^2.3.0",
|
|
91
|
+
"@connectrpc/connect-node": "^2.3.0",
|
|
92
|
+
"nodefony": "^10.0.0-beta.7",
|
|
84
93
|
"zod": "^4.6.7"
|
|
85
94
|
},
|
|
95
|
+
"peerDependenciesMeta": {
|
|
96
|
+
"@bufbuild/protobuf": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"@connectrpc/connect": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"@connectrpc/connect-node": {
|
|
103
|
+
"optional": true
|
|
104
|
+
}
|
|
105
|
+
},
|
|
86
106
|
"files": [
|
|
87
107
|
"dist",
|
|
88
108
|
"docs"
|
|
@@ -90,7 +110,7 @@
|
|
|
90
110
|
"publishConfig": {
|
|
91
111
|
"access": "public"
|
|
92
112
|
},
|
|
93
|
-
"homepage": "https://nodefony.
|
|
113
|
+
"homepage": "https://nodefony.net/",
|
|
94
114
|
"bugs": {
|
|
95
115
|
"url": "https://github.com/nodefony/nodefony-core/issues"
|
|
96
116
|
}
|