@nodefony/security 10.0.0-beta.4 → 10.0.0-beta.6
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.155.0 → _@oxc-project_runtime@0.157.0}/helpers/esm/decorate.js +1 -1
- package/dist/index.js +60 -60
- package/dist/nodefony/config/config.js +13 -5
- package/dist/nodefony/contracts/IWebhookPayload.js +1 -0
- package/dist/nodefony/errors/index.js +4 -4
- package/dist/nodefony/keycloak/keycloakAdmin.js +3 -3
- package/dist/nodefony/keycloak/security-keycloak-realm.js +1 -1
- package/dist/nodefony/service/accessTokenVerifier.js +5 -5
- package/dist/nodefony/service/apiKeys.js +8 -4
- package/dist/nodefony/service/authFlow.js +3 -3
- package/dist/nodefony/service/authorization.js +1 -1
- package/dist/nodefony/service/firewall.js +233 -41
- package/dist/nodefony/service/keycloak.js +1 -1
- package/dist/nodefony/service/oauth2.js +8 -4
- package/dist/nodefony/service/securityHeaders.js +340 -47
- package/dist/nodefony/service/tokenService.js +8 -8
- package/dist/nodefony/service/totp.js +3 -3
- package/dist/nodefony/service/webAuthn.js +1 -1
- package/dist/nodefony/service/webhooks.js +11 -4
- package/dist/nodefony/src/admin/SecurityAdminApi.js +19 -0
- package/dist/nodefony/src/authenticator/ApiKeyAuthenticator.js +1 -1
- package/dist/nodefony/src/authenticator/ExternalSubjectResolver.js +31 -7
- package/dist/nodefony/src/authenticator/FirewallRealtimeAuthenticator.js +62 -20
- package/dist/nodefony/src/authenticator/JwtAuthenticator.js +5 -2
- package/dist/nodefony/src/authenticator/SessionAuthenticator.js +1 -1
- package/dist/nodefony/src/authenticator/authenticatorRegistry.js +1 -1
- package/dist/nodefony/src/csp.js +265 -10
- package/dist/nodefony/src/cspReports.js +307 -0
- package/dist/nodefony/src/oauth/clientCredentials.js +1 -1
- package/dist/nodefony/src/oauth/metadata.js +1 -1
- package/dist/nodefony/src/oauth/oauthProviderRegistry.js +17 -4
- package/dist/nodefony/src/oauth/providers/github.js +1 -1
- package/dist/nodefony/src/realtime/UserRealtimeToken.js +59 -2
- package/dist/nodefony/src/realtime/frameAuthorizer.js +7 -6
- package/dist/nodefony/src/token/RemoteJwtVerifier.js +8 -2
- package/dist/nodefony/src/token/tokenTimeClaims.js +34 -0
- package/dist/nodefony/src/totp/totpOperations.js +1 -1
- package/dist/nodefony/src/voter/RoleVoter.js +1 -1
- package/dist/nodefony/src/webhook/WebhookDispatcher.js +71 -17
- package/dist/nodefony/src/webhook/webhookDelivery.js +3 -3
- package/dist/nodefony/testing/index.js +98 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/nodefony/config/config.d.ts +2 -0
- package/dist/types/nodefony/contracts/IApiKey.d.ts +8 -2
- package/dist/types/nodefony/contracts/IFirewall.d.ts +15 -2
- package/dist/types/nodefony/contracts/ITokenStore.d.ts +7 -3
- package/dist/types/nodefony/contracts/IWebhookEndpoint.d.ts +13 -3
- package/dist/types/nodefony/contracts/IWebhookPayload.d.ts +24 -0
- package/dist/types/nodefony/service/apiKeys.d.ts +3 -0
- package/dist/types/nodefony/service/firewall.d.ts +28 -7
- package/dist/types/nodefony/service/securityHeaders.d.ts +82 -11
- package/dist/types/nodefony/service/webhooks.d.ts +7 -1
- package/dist/types/nodefony/src/admin/SecurityAdminApi.d.ts +3 -0
- package/dist/types/nodefony/src/authenticator/ExternalSubjectResolver.d.ts +11 -0
- package/dist/types/nodefony/src/csp.d.ts +142 -0
- package/dist/types/nodefony/src/cspReports.d.ts +73 -0
- package/dist/types/nodefony/src/oauth/oauthProviderRegistry.d.ts +15 -0
- package/dist/types/nodefony/src/realtime/UserRealtimeToken.d.ts +35 -1
- package/dist/types/nodefony/src/realtime/frameAuthorizer.d.ts +2 -2
- package/dist/types/nodefony/src/realtime/realtimeContracts.d.ts +25 -17
- package/dist/types/nodefony/src/token/tokenTimeClaims.d.ts +32 -0
- package/dist/types/nodefony/src/webhook/WebhookDispatcher.d.ts +36 -1
- package/dist/types/nodefony/testing/index.d.ts +57 -0
- package/docs/api-keys.md +3 -1
- package/docs/authenticators.md +6 -4
- package/docs/csrf.md +3 -2
- package/docs/external-jwt.md +5 -1
- package/docs/firewall.md +3 -2
- package/docs/headers.md +427 -71
- package/docs/login-page.md +4 -3
- package/docs/totp.md +2 -2
- package/docs/webauthn.md +2 -2
- package/docs/webhooks.md +57 -11
- package/package.json +20 -14
package/docs/login-page.md
CHANGED
|
@@ -118,8 +118,8 @@ redéfinissent pour les deux thèmes (voir « Pièges », plus bas) :
|
|
|
118
118
|
|
|
119
119
|
### Ce qu'on observe
|
|
120
120
|
|
|
121
|
-
- `GET /login` rend la page, avec `Cache-Control: no-store` et une CSP
|
|
122
|
-
`frame-ancestors 'none'` (`
|
|
121
|
+
- `GET /login` rend la page, avec `Cache-Control: no-store` et, par défaut, une CSP
|
|
122
|
+
`frame-ancestors 'none'` (réglée pour toute l’application par `http.securityHeaders.frameOptions`) ;
|
|
123
123
|
- le titre de la carte vaut « Espace client », le panneau affiche votre accroche à la place de la
|
|
124
124
|
vitrine Nodefony ;
|
|
125
125
|
- votre feuille arrive en second `<link rel="stylesheet">`, après `login.css` : vos variables
|
|
@@ -303,7 +303,8 @@ nommant, au lieu d'être ignorée.
|
|
|
303
303
|
|
|
304
304
|
## 🔒 Sécurité
|
|
305
305
|
|
|
306
|
-
- **Pas de cache partagé** (`no-store`)
|
|
306
|
+
- **Pas de cache partagé** (`no-store`) ; l’affichage dans un cadre suit `http.securityHeaders.frameOptions`,
|
|
307
|
+
refusé par défaut (`X-Frame-Options: DENY`, `frame-ancestors 'none'`) ;
|
|
307
308
|
le script porte le nonce CSP de la requête.
|
|
308
309
|
- **Mot de passe en clair refusé en production** : sur une requête qui n'arrive pas en HTTPS, la
|
|
309
310
|
connexion répond 403 avant toute vérification, et la page affiche « doit passer par HTTPS » au
|
package/docs/totp.md
CHANGED
|
@@ -581,7 +581,7 @@ TOTP et les passkeys (`cascadeUserRevocation`, `userRevocationCascade.ts#cascade
|
|
|
581
581
|
recréé sous le même identifiant hériterait du second facteur de l'ancien titulaire. Un compte
|
|
582
582
|
seulement désactivé ou verrouillé garde ses facteurs.
|
|
583
583
|
|
|
584
|
-
Spécification logique de la table (`
|
|
584
|
+
Spécification logique de la table (`TOTP_SECRET_TABLE`, `totpSecretEntity.ts#TOTP_SECRET_TABLE`), déclinée par
|
|
585
585
|
dialecte via le colKit :
|
|
586
586
|
|
|
587
587
|
| Colonne | Rôle | SQLite | PostgreSQL | MySQL / MariaDB |
|
|
@@ -600,7 +600,7 @@ dialecte via le colKit :
|
|
|
600
600
|
Deux pièges de lecture, signalés dans l'entité elle-même :
|
|
601
601
|
|
|
602
602
|
- `lastUsedStep` est un **numéro de tranche RFC 6238**, pas un horodatage — d'où le type `int`
|
|
603
|
-
partout, quand les vraies dates sont en `
|
|
603
|
+
partout, quand les vraies dates sont en `int64` (`totpSecretEntity.ts#TotpSecretRow.algorithm`).
|
|
604
604
|
- Un epoch en millisecondes **déborde** un `integer` 32 bits → `bigint` en PostgreSQL et MySQL
|
|
605
605
|
(SQLite, lui, a des INTEGER 64 bits).
|
|
606
606
|
|
package/docs/webauthn.md
CHANGED
|
@@ -504,8 +504,8 @@ clé privée n'existe que dans l'authenticator.
|
|
|
504
504
|
| `backupState` | BS flag — la passkey **est** sauvegardée | `bool` notNull | `Boolean` requis | `"1"`/`"0"` |
|
|
505
505
|
| `uvInitialized` | Une vérification humaine a déjà eu lieu | `bool` notNull | `Boolean` requis | `"1"`/`"0"` |
|
|
506
506
|
| `nickname` | Surnom d'appareil, optionnel | `text` nullable | `String` (null) | champ absent si vide |
|
|
507
|
-
| `createdAt` | Enrôlement (epoch ms) | `
|
|
508
|
-
| `lastUsedAt` | Dernière authentification réussie, ou `null` | `
|
|
507
|
+
| `createdAt` | Enrôlement (epoch ms) | `int64` notNull | `Number` requis | champ |
|
|
508
|
+
| `lastUsedAt` | Dernière authentification réussie, ou `null` | `int64` nullable | `Number` (null) | champ absent si null |
|
|
509
509
|
|
|
510
510
|
Spécification SQL : `webAuthnCredentialEntity.ts#webAuthnCredentialSchema`, index sur `userId`
|
|
511
511
|
(`drizzle/nodefony/entity/webAuthnCredentialEntity.ts#WebAuthnCredentialRow.userId`). Schéma documentaire :
|
package/docs/webhooks.md
CHANGED
|
@@ -89,6 +89,7 @@ part (les autres événements ne sont pas souscrits) :
|
|
|
89
89
|
```json
|
|
90
90
|
{
|
|
91
91
|
"id": "msg_7Yb1kQ2pR8sT",
|
|
92
|
+
"timestamp": "2026-10-29T09:14:03.000Z",
|
|
92
93
|
"type": "login.failure",
|
|
93
94
|
"data": {
|
|
94
95
|
"actor": "alice",
|
|
@@ -98,6 +99,13 @@ part (les autres événements ne sont pas souscrits) :
|
|
|
98
99
|
}
|
|
99
100
|
```
|
|
100
101
|
|
|
102
|
+
> [!NOTE]
|
|
103
|
+
> **`timestamp` date la TENTATIVE, pas l'événement** : un réessai deux heures plus tard porte une
|
|
104
|
+
> heure plus tardive. L'heure de l'événement vit dans `data` (`ts` pour l'audit). Et `id` est
|
|
105
|
+
> exactement l'en-tête `webhook-id`, stable d'un réessai à l'autre : c'est la clé de déduplication.
|
|
106
|
+
> Le corps se type par `IWebhookPayload` (exporté par `@nodefony/security`,
|
|
107
|
+
> `IWebhookPayload.ts#IWebhookPayload`).
|
|
108
|
+
|
|
101
109
|
> [!NOTE]
|
|
102
110
|
> Ce qui peut partir est **ce que le journal d'audit de sécurité enregistre** : connexions, refus
|
|
103
111
|
> d'accès, jetons, sessions, passkeys. Tes propres événements applicatifs — « commande payée »,
|
|
@@ -250,6 +258,7 @@ import { createHmac, timingSafeEqual } from "node:crypto";
|
|
|
250
258
|
import { Buffer } from "node:buffer";
|
|
251
259
|
// prettier-ignore
|
|
252
260
|
import { Controller, controller, Post, Body, Headers, BypassFirewall } from "@nodefony/framework";
|
|
261
|
+
import type { IWebhookPayload } from "@nodefony/security";
|
|
253
262
|
// NF_HOOK_SECRET se déclare dans env.ts (`envString`) : seul lecteur de l'environnement.
|
|
254
263
|
import { env } from "../../env";
|
|
255
264
|
|
|
@@ -276,7 +285,7 @@ class HookMiniController extends Controller {
|
|
|
276
285
|
if (got.length !== want.length || !timingSafeEqual(got, want)) {
|
|
277
286
|
return this.renderJson({ error: "bad signature" }, 401);
|
|
278
287
|
}
|
|
279
|
-
this.log(`reçu : ${(JSON.parse(raw) as
|
|
288
|
+
this.log(`reçu : ${(JSON.parse(raw) as IWebhookPayload).type}`, "INFO");
|
|
280
289
|
return this.renderJson({ ok: true });
|
|
281
290
|
}
|
|
282
291
|
}
|
|
@@ -308,6 +317,7 @@ import { createHmac, timingSafeEqual } from "node:crypto";
|
|
|
308
317
|
import { Buffer } from "node:buffer";
|
|
309
318
|
// prettier-ignore
|
|
310
319
|
import { Controller, controller, Post, Body, Headers, BypassFirewall } from "@nodefony/framework";
|
|
320
|
+
import type { IWebhookPayload } from "@nodefony/security";
|
|
311
321
|
import { env } from "../../env";
|
|
312
322
|
|
|
313
323
|
/** Secret `whsec_…` donné par l'émetteur — déclaré dans env.ts, jamais en dur. */
|
|
@@ -369,7 +379,7 @@ class HookController extends Controller {
|
|
|
369
379
|
|
|
370
380
|
// 4. Dédupliquer par `webhook-id` AVANT d'agir (un retry rejoue le MÊME id),
|
|
371
381
|
// puis répondre 2xx vite : le travail long part en tâche de fond.
|
|
372
|
-
const event = JSON.parse(raw) as
|
|
382
|
+
const event = JSON.parse(raw) as IWebhookPayload;
|
|
373
383
|
this.log(`webhook ${event.id} — ${event.type}`, "INFO");
|
|
374
384
|
return this.renderJson({ ok: true });
|
|
375
385
|
}
|
|
@@ -431,20 +441,47 @@ Les catégories d'audit disponibles (`AuditCategory`, `IAuditEvent.ts#AuditCateg
|
|
|
431
441
|
| `webhook` | Vie des webhooks eux-mêmes (`webhook.created`, `webhook.disabled`) |
|
|
432
442
|
| `config` | Mutation de config runtime depuis Studio |
|
|
433
443
|
|
|
444
|
+
> [!IMPORTANT]
|
|
445
|
+
> **Les noms de l'audit sont RÉSERVÉS.** Une émission applicative d'événements, quand elle viendra,
|
|
446
|
+
> refusera tout type qui appartient à l'audit (`login.*`, `token.*` et les autres familles
|
|
447
|
+
> ci-dessus) : sans cette réserve, un code applicatif pourrait fabriquer un `login.success` signé
|
|
448
|
+
> par le serveur, qu'un centre de sécurité abonné ne distinguerait pas d'un vrai
|
|
449
|
+
> ([ADR-0023](../../../../../docs/adr/0023-webhooks-evenements-et-abonnements.md), W3). Ne nommez
|
|
450
|
+
> pas vos futurs événements comme ceux de l'audit.
|
|
451
|
+
|
|
434
452
|
> [!NOTE]
|
|
435
453
|
> Trois catégories sont **réservées** au contrat sans émetteur à ce jour : `oauth`, `csrf`, `cors`
|
|
436
454
|
> (`IAuditEvent.ts#AuditCategory`). S'y abonner est accepté, mais ne livre jamais rien.
|
|
437
455
|
|
|
438
456
|
### La syntaxe d'abonnement
|
|
439
457
|
|
|
440
|
-
Le champ `events` d'un endpoint
|
|
441
|
-
|
|
458
|
+
Le champ `events` d'un endpoint prend des **motifs**, dans la même grammaire que les canaux de la
|
|
459
|
+
socket : `*` vaut n'importe quelle suite de caractères, tout le reste est littéral, trois `*` au
|
|
460
|
+
plus. Un motif plus large est **refusé** à l'enregistrement, avec une erreur qui le nomme. La règle
|
|
461
|
+
vit une seule fois, au cœur (`channelPattern.ts#compileChannelPattern`), et
|
|
462
|
+
`matchesSubscription()` (`WebhookDispatcher.ts#matchesSubscription`) l'appelle :
|
|
442
463
|
|
|
443
|
-
| Motif |
|
|
444
|
-
| ----------------- | ----------------------------------------------------- |
|
|
445
|
-
| `"*"` | **toutes** les actions | un SIEM qui veut tout
|
|
446
|
-
| `"login.success"` | l'action exacte, et elle seule | une alerte ciblée
|
|
447
|
-
| `"login.*"` | toute action **préfixée** `login.` (`login.failure`…) | suivre une famille d'événements
|
|
464
|
+
| Motif | Désigne | Usage typique |
|
|
465
|
+
| ----------------- | ----------------------------------------------------- | --------------------------------- |
|
|
466
|
+
| `"*"` | **toutes** les actions | un SIEM qui veut tout |
|
|
467
|
+
| `"login.success"` | l'action exacte, et elle seule | une alerte ciblée |
|
|
468
|
+
| `"login.*"` | toute action **préfixée** `login.` (`login.failure`…) | suivre une famille d'événements |
|
|
469
|
+
| `"commande:*"` | `commande:42`, `commande:créée`… | un espace de noms applicatif |
|
|
470
|
+
| `"*:créée"` | toute action qui finit par `:créée` | un même geste sur tous les objets |
|
|
471
|
+
|
|
472
|
+
> [!IMPORTANT]
|
|
473
|
+
> **`"*"` veut dire tout, y compris ce qui viendra.** Aujourd'hui, seuls les événements d'audit
|
|
474
|
+
> sont livrés ; le jour où une application pourra émettre les siens, un abonnement `"*"` les
|
|
475
|
+
> recevra aussi. Qui ne veut que la sécurité liste ses familles (`login.*`, `token.*`…). Cette
|
|
476
|
+
> grammaire ne changera pas de sens dans la série 10
|
|
477
|
+
> ([ADR-0023](../../../../../docs/adr/0023-webhooks-evenements-et-abonnements.md), W2).
|
|
478
|
+
>
|
|
479
|
+
> **Le périmètre.** Le périmètre d'un événement est le locataire — l'organisation cliente — auquel
|
|
480
|
+
> il est rattaché. Un abonnement sans périmètre — le cas de tous aujourd'hui — a le périmètre de
|
|
481
|
+
> la **plateforme** : il reçoit tout, y compris les événements qu'une version ultérieure rattachera
|
|
482
|
+
> à un locataire (ADR-0023, W2). Le multi-tenant n'existant pas encore, `WebhookService.register`
|
|
483
|
+
> **refuse** un `tenantId` rempli (`webhooks.ts#WebhookService.register`) : l'accepter le ferait
|
|
484
|
+
> passer pour un cloisonnement qu'il n'est pas.
|
|
448
485
|
|
|
449
486
|
> [!CAUTION]
|
|
450
487
|
> Les événements de catégorie `webhook` **ne déclenchent jamais de livraison**
|
|
@@ -747,7 +784,7 @@ partage entre pods. Les colonnes suivent `IWebhookEndpoint` (`IWebhookEndpoint.t
|
|
|
747
784
|
| `events` | actions souscrites | `text mode:json` · `jsonb` · `json` | `[String]` |
|
|
748
785
|
| `enabled` | actif ? | `integer mode:bool` · `boolean` · `boolean` | `Boolean` |
|
|
749
786
|
| `description` | libellé console | `text` | `String` |
|
|
750
|
-
| `tenantId` |
|
|
787
|
+
| `tenantId` | périmètre d’un locataire (réservé, toujours `null`) | `text` | `String` |
|
|
751
788
|
| `createdBy` | admin créateur (traçabilité) | `text` | `String` |
|
|
752
789
|
| `createdAt` / `updatedAt` | epoch **ms** | `integer` · `bigint` · `bigint` | `Number` |
|
|
753
790
|
| `lastDeliveryAt` | dernière tentative (epoch ms) | `integer` · `bigint` · `bigint` | `Number` |
|
|
@@ -757,7 +794,7 @@ partage entre pods. Les colonnes suivent `IWebhookEndpoint` (`IWebhookEndpoint.t
|
|
|
757
794
|
| `metadata` | extras applicatifs (jamais de secret) | `text mode:json` · `jsonb` · `json` | `Object` |
|
|
758
795
|
|
|
759
796
|
Côté SQL, la table est décrite **une seule fois** en spec logique
|
|
760
|
-
(`
|
|
797
|
+
(`WEBHOOK_ENDPOINT_TABLE`, `drizzle/nodefony/entity/webhookEndpointEntity.ts#WEBHOOK_ENDPOINT_TABLE`) puis déclinée
|
|
761
798
|
par dialecte via le `colKit`. Côté documentaire, le schéma force `_id: String` — l'identifiant
|
|
762
799
|
`wh_…` **est** la clé primaire, pas un `ObjectId` généré
|
|
763
800
|
(`webhookEndpointSchema`, `mongoose/nodefony/entity/webhookEndpointEntity.ts#webhookEndpointSchema`).
|
|
@@ -893,6 +930,15 @@ runtime, zéro cycle. Pour valider ton implémentation, importe le banc de contr
|
|
|
893
930
|
(`tests/support/webhookPaginationContract.ts`) et branche-le sur ton store : les invariants d'ordre,
|
|
894
931
|
de filtres et de bornes sont alors prouvés, pas supposés.
|
|
895
932
|
|
|
933
|
+
**Ta fabrique lève quand son backend n'est pas joignable — jamais un registre qui se tait.** Un
|
|
934
|
+
`IWebhookStore` qui, faute de connexion, rend une liste d'abonnements vide ne lève rien et ne
|
|
935
|
+
livre plus rien : les abonnés cessent d'être notifiés, sans une ligne au journal, pendant que la
|
|
936
|
+
configuration affiche ton backend. Le registre livré pour SQL fait l'inverse : sa fabrique passe
|
|
937
|
+
par `resolveConnectedOrm()` (`drizzle/nodefony/registerStores.ts#resolveConnectedOrm`), qui lève
|
|
938
|
+
en nommant la cause — module absent, ordre de démarrage, dialecte — si la connexion n'existe pas.
|
|
939
|
+
Fais de même : vérifie la connexion dans la fabrique, et laisse remonter l'erreur. Ne la rattrape
|
|
940
|
+
pas dans chaque méthode par un `if (!connected) return []`.
|
|
941
|
+
|
|
896
942
|
## 📜 Normes appliquées
|
|
897
943
|
|
|
898
944
|
| Domaine | Norme / référence | Ancrage |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodefony/security",
|
|
3
|
-
"version": "10.0.0-beta.
|
|
3
|
+
"version": "10.0.0-beta.6",
|
|
4
4
|
"description": "Pare-feu applicatif par zones pour Nodefony : authentification, autorisation par rôles, protection CSRF, journal d'audit",
|
|
5
5
|
"author": "Christophe CAMENSULI <ccamensuli@gmail.com>",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
"types": "./dist/types/index.d.ts",
|
|
17
17
|
"import": "./dist/index.js",
|
|
18
18
|
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./testing": {
|
|
21
|
+
"nodefony-source": "./nodefony/testing/index.ts",
|
|
22
|
+
"types": "./dist/types/nodefony/testing/index.d.ts",
|
|
23
|
+
"import": "./dist/nodefony/testing/index.js",
|
|
24
|
+
"default": "./dist/nodefony/testing/index.js"
|
|
19
25
|
}
|
|
20
26
|
},
|
|
21
27
|
"scripts": {
|
|
@@ -50,27 +56,27 @@
|
|
|
50
56
|
},
|
|
51
57
|
"dependencies": {
|
|
52
58
|
"@simplewebauthn/server": "14.0.3",
|
|
53
|
-
"jose": "6.2.
|
|
54
|
-
"tslib": "2.
|
|
59
|
+
"jose": "6.2.15",
|
|
60
|
+
"tslib": "2.9.1",
|
|
55
61
|
"zod": "^4.6.7"
|
|
56
62
|
},
|
|
57
63
|
"devDependencies": {
|
|
58
|
-
"@nodefony/framework": "^10.0.0-beta.
|
|
59
|
-
"@nodefony/http": "^10.0.0-beta.
|
|
60
|
-
"@nodefony/user": "^10.0.0-beta.
|
|
61
|
-
"@types/node": "26.6.
|
|
62
|
-
"@vitest/coverage-v8": "5.0
|
|
63
|
-
"nodefony": "^10.0.0-beta.
|
|
64
|
-
"vitest": "5.0
|
|
64
|
+
"@nodefony/framework": "^10.0.0-beta.6",
|
|
65
|
+
"@nodefony/http": "^10.0.0-beta.6",
|
|
66
|
+
"@nodefony/user": "^10.0.0-beta.6",
|
|
67
|
+
"@types/node": "26.6.6",
|
|
68
|
+
"@vitest/coverage-v8": "5.1.0",
|
|
69
|
+
"nodefony": "^10.0.0-beta.6",
|
|
70
|
+
"vitest": "5.1.0"
|
|
65
71
|
},
|
|
66
72
|
"license": "Apache-2.0",
|
|
67
73
|
"readmeFilename": "README.md",
|
|
68
74
|
"contributors": [],
|
|
69
75
|
"peerDependencies": {
|
|
70
|
-
"@nodefony/framework": "^10.0.0-beta.
|
|
71
|
-
"@nodefony/http": "^10.0.0-beta.
|
|
72
|
-
"@nodefony/user": "^10.0.0-beta.
|
|
73
|
-
"nodefony": "^10.0.0-beta.
|
|
76
|
+
"@nodefony/framework": "^10.0.0-beta.6",
|
|
77
|
+
"@nodefony/http": "^10.0.0-beta.6",
|
|
78
|
+
"@nodefony/user": "^10.0.0-beta.6",
|
|
79
|
+
"nodefony": "^10.0.0-beta.6"
|
|
74
80
|
},
|
|
75
81
|
"files": [
|
|
76
82
|
"dist",
|