@nodefony/devkit 10.0.0-beta.3 → 10.0.0-beta.5

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.
Files changed (55) hide show
  1. package/README.md +146 -4
  2. package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorate.js +1 -2
  3. package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorateParam.js +1 -2
  4. package/dist/index.js +24 -11
  5. package/dist/nodefony/config/config.js +16 -137
  6. package/dist/nodefony/config/defineModuleConfig.js +1 -2
  7. package/dist/nodefony/controllers/DevkitController.js +7 -14
  8. package/dist/nodefony/controllers/McpController.js +25 -226
  9. package/dist/nodefony/controllers/ProfileSessionController.js +47 -0
  10. package/dist/nodefony/mcp/observe.js +235 -0
  11. package/dist/nodefony/mcp/profileReport.js +242 -0
  12. package/dist/nodefony/mcp/profileRoute.js +521 -0
  13. package/dist/nodefony/mcp/shotClient.js +84 -0
  14. package/dist/nodefony/mcp/shutdown.js +44 -0
  15. package/dist/nodefony/mcp/tools.js +696 -0
  16. package/dist/nodefony/service/DevkitService.js +93 -29
  17. package/dist/nodefony/src/errors/DevkitError.js +1 -2
  18. package/dist/nodefony/src/profileSession.js +14 -0
  19. package/dist/types/index.d.ts +15 -1
  20. package/dist/types/nodefony/config/config.d.ts +1 -1
  21. package/dist/types/nodefony/controllers/McpController.d.ts +11 -26
  22. package/dist/types/nodefony/controllers/ProfileSessionController.d.ts +31 -0
  23. package/dist/types/nodefony/interfaces/IDevkitService.d.ts +22 -1
  24. package/dist/types/nodefony/mcp/observe.d.ts +83 -0
  25. package/dist/types/nodefony/mcp/profileReport.d.ts +138 -0
  26. package/dist/types/nodefony/mcp/profileRoute.d.ts +87 -0
  27. package/dist/types/nodefony/mcp/shotClient.d.ts +53 -0
  28. package/dist/types/nodefony/mcp/shutdown.d.ts +25 -0
  29. package/dist/types/nodefony/mcp/tools.d.ts +109 -0
  30. package/dist/types/nodefony/service/DevkitService.d.ts +41 -4
  31. package/dist/types/nodefony/src/profileSession.d.ts +12 -0
  32. package/docs/index.md +160 -11
  33. package/package.json +16 -11
  34. package/skills/nodefony-add-crud/SKILL.md +10 -1
  35. package/skills/nodefony-add-service/SKILL.md +3 -3
  36. package/skills/nodefony-authentication/SKILL.md +5 -5
  37. package/skills/nodefony-browser/SKILL.md +20 -0
  38. package/skills/nodefony-browser/references/socket.md +13 -4
  39. package/skills/nodefony-browser/references/sondes.md +13 -1
  40. package/skills/nodefony-browser/scripts/inspect.mjs +55 -8
  41. package/skills/nodefony-browser/scripts/lib/probes.mjs +53 -0
  42. package/skills/nodefony-browser/scripts/socket.mjs +70 -4
  43. package/skills/nodefony-browser/scripts/watch.mjs +101 -0
  44. package/skills/nodefony-dev/SKILL.md +31 -1
  45. package/skills/nodefony-dev/scripts/docs.mjs +3 -3
  46. package/skills/nodefony-devops/SKILL.md +85 -64
  47. package/skills/nodefony-devops/references/dimensionnement.md +122 -0
  48. package/skills/nodefony-devops/references/frontal.md +277 -47
  49. package/skills/nodefony-devops/references/kubernetes.md +41 -14
  50. package/skills/nodefony-devops/references/secrets.md +13 -2
  51. package/skills/nodefony-devops/references/variables.md +14 -12
  52. package/skills/nodefony-protect-route/SKILL.md +6 -4
  53. package/skills/nodefony-security-review/scripts/review-diff.mjs +4 -4
  54. package/skills/nodefony-troubleshoot/SKILL.md +86 -12
  55. package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js +0 -6
@@ -515,7 +515,7 @@ export function readZones(src) {
515
515
  const authenticators = auth
516
516
  ? [...auth[1].matchAll(/["']([^"']+)["']/gu)].map((a) => a[1])
517
517
  : [];
518
- let regex = null;
518
+ let regex;
519
519
  try {
520
520
  regex = new RegExp(m[2].replace(/\\\\/gu, "\\"), "u");
521
521
  } catch {
@@ -544,7 +544,7 @@ export function readZones(src) {
544
544
  export function appZones(root) {
545
545
  const files = [];
546
546
  const walk = (dir) => {
547
- let entries = [];
547
+ let entries;
548
548
  try {
549
549
  entries = readdirSync(dir, { withFileTypes: true });
550
550
  } catch {
@@ -673,8 +673,8 @@ export function controllerRoutes(lines) {
673
673
  const group = decoratorGroup(lines, i);
674
674
  if (seen.has(group.to)) continue;
675
675
  seen.add(group.to);
676
- let routePath = "";
677
- let methods = [];
676
+ let routePath;
677
+ let methods;
678
678
  if (verbDeco) {
679
679
  routePath =
680
680
  new RegExp(
@@ -1,19 +1,20 @@
1
1
  ---
2
2
  name: nodefony-troubleshoot
3
3
  description: >
4
- Dépanne une application Nodefony en partant du SYMPTÔME constaté — démarrage qui échoue,
5
- route en 404, refus 401 ou 403 inattendu, erreur au journal, colonne absente, tests rouges
6
- d'un coup — et donne pour chacun le premier geste, la commande qui le constate et le skill
7
- qui porte le détail. Extrait les erreurs du journal par un script (regroupées, datées, avec
8
- leur piste) au lieu de le lire en entier. À charger DÈS qu'une chose qui marchait ne marche
9
- plus, AVANT de lire les sources ou de contourner la panne. Coder une fonctionnalité →
10
- `nodefony-dev`.
4
+ Dépanne une application Nodefony en partant du SYMPTÔME constaté — démarrage qui échoue, route
5
+ en 404, refus 401 ou 403 inattendu, erreur au journal, colonne absente, tests rouges d'un coup,
6
+ page lente — et donne pour chacun le premier geste, la commande qui le constate et le skill qui
7
+ porte le détail. Extrait les erreurs du journal par un script ; mesure une route par l'outil MCP
8
+ `nodefony_profile_route` (il tire lui-même les requêtes), le trafic qu'on génère par
9
+ `nodefony_observe`. À charger DÈS qu'une chose qui marchait ne marche plus, AVANT de lire les
10
+ sources ou de contourner la panne. Coder une fonctionnalité → `nodefony-dev`.
11
11
  Déclencheurs : "l'application ne démarre plus", "le serveur plante au démarrage", "ma route
12
- répond 404", "ça marchait hier", "j'ai une erreur dans le journal", "erreur dans les logs",
13
- "plus rien ne répond", "tous mes tests sont rouges", "pourquoi ça plante", "dépanner",
14
- "diagnostiquer une panne", "stack trace", "EADDRINUSE", "ECONNREFUSED".
12
+ répond 404", "ça marchait hier", "dépanner", "erreur dans les logs", "tous mes tests sont
13
+ rouges", "cette page est lente", "trop de requêtes SQL", "problème de N+1", "mesure cette route",
14
+ "est-ce plus rapide après ma modification", "erreur 500 intermittente", "EADDRINUSE",
15
+ "ECONNREFUSED".
15
16
  metadata:
16
- version: 1.0.0
17
+ version: 1.1.0
17
18
  ---
18
19
 
19
20
  # nodefony-troubleshoot — du symptôme au geste, sans contourner
@@ -60,6 +61,7 @@ cause t'échappe, dis-le, avec ce que tu as constaté.
60
61
  | Une erreur dans le journal | le script du §3 | la piste qu'il donne, sinon le message lui-même |
61
62
  | « colonne inexistante », « no such table », migrations à appliquer | `npx nodefony doctor --live` | `nodefony-migrate-schema` |
62
63
  | Des dizaines de tests d'intégration rouges d'un coup (`ECONNREFUSED`) | `npx nodefony status` | ils FRAPPENT un serveur, ils ne le lancent pas : il est éteint. En e2e, laisse la commande gérer le cycle |
64
+ | Une page est lente, trop de requêtes SQL, des `500` par intermittence | l'outil MCP `nodefony_profile_route { "path": "/la/page" }` | §5 : le rapport nomme la route, la cause et le geste |
63
65
  | `nodefony <commande>` échoue là où `npm run dev` réussit | `npm ls nodefony` | deux copies du framework dans le processus (§4) |
64
66
 
65
67
  **Lis toute la réponse d'une commande de diagnostic.** Ne la tronque jamais (`| head`, une
@@ -141,7 +143,79 @@ Chacune a déjà coûté au moins une heure à quelqu'un.
141
143
  anonyme et une route authentifiée AVANT d'accuser TLS ou le pare-feu ; passe le stockage sur
142
144
  redis pour la charge.
143
145
 
144
- ## 5. Avant de dire « réparé »
146
+ ## 5. Mesurer l'application qui tourne — `nodefony_profile_route` et `nodefony_observe`
147
+
148
+ Le profileur de développement mesure chaque requête : temps de chaque phase, chaque requête SQL,
149
+ décision du pare-feu. Deux outils MCP te rendent ces mesures. C'est la seule façon de SAVOIR
150
+ qu'une page est lente ou qu'elle interroge la base dans une boucle — ni le code ni les tests ne le
151
+ montrent. **Mesure avant d'écrire un script de banc** : l'outil le fait déjà, et mieux.
152
+
153
+ | Tu veux… | L'outil | Qui envoie les requêtes |
154
+ | ---------------------------------------------------------------- | ------------------------ | --------------------------------------- |
155
+ | mesurer UNE page, avant/après une modification | `nodefony_profile_route` | l'outil lui-même, N fois, sur un chemin |
156
+ | voir ce que fait le trafic que TU génères (tests, navigation, …) | `nodefony_observe` | toi, pendant une fenêtre de secondes |
157
+
158
+ **Le protocole — mesurer, corriger, re-mesurer :**
159
+
160
+ 1. **Une page** : `nodefony_profile_route { "path": "/orders?page=2" }` — un CHEMIN de
161
+ l'application, jamais une URL. `count` (défaut 50, max 200), `concurrency` (défaut 4, max 8),
162
+ `warmup` (défaut 3 : requêtes tirées AVANT et hors mesures — la première compile la route et
163
+ ouvre la connexion à la base). GET (défaut) ou HEAD seulement.
164
+ **Un trafic** : `nodefony_observe { "durationSec": 10 }` (1 à 50 s), et PENDANT la fenêtre,
165
+ sollicite le code — l'outil n'envoie RIEN ; sans trafic, son verdict est « rien à juger ».
166
+ `"route"` restreint à une route, par son NOM (`nodefony_inspect` sujet `routes`).
167
+ 2. Lis le rapport (ci-dessous), corrige la cause nommée.
168
+ 3. **Rappelle l'outil avec les MÊMES arguments** et compare le bloc `Données (JSON…)` des deux
169
+ appels : un correctif qu'on n'a pas vu changer le chiffre est une hypothèse. Exemple réel, un
170
+ N+1 corrigé par `$in` : 18 requêtes SQL par page → 3, p50 1,2 ms → 0,7 ms.
171
+
172
+ **Au nom de qui — une page protégée vue sans compte ne mesure que des refus.**
173
+ `nodefony_profile_route` joue par défaut le **propriétaire du jeton MCP** si ce jeton porte le
174
+ scope `admin:write` : il ouvre une vraie session à son nom (tous ses rôles), tire avec, puis la
175
+ détruit — l'audit l'écrit (`login.success`, raison `devkit`). `"as": "<identifiant>"` joue un autre
176
+ compte, dont les rôles doivent être inclus dans ceux du propriétaire (jamais de montée en droits).
177
+ `"anonymous": true` force l'anonyme. Sans `admin:write`, l'outil joue l'anonyme et le rapport dit
178
+ la commande : `npx nodefony security:mcp:token --scope "admin:read admin:write" --write` — puis
179
+ relance l'agent, qui lit son jeton au démarrage.
180
+
181
+ **Lire le rapport, dans l'ordre où il s'écrit :**
182
+
183
+ | Ligne | Ce qu'elle dit | Le geste |
184
+ | -------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
185
+ | `Verdict : … INCOMPLÈTE` + `⚠️` | les chiffres ne portent pas sur tout — la cause suit, AVANT tout chiffre | lever la cause nommée, rappeler l'outil |
186
+ | `⚠️ … REFUSÉE(S) (401×…, 403×…)` | la page est protégée : ces requêtes ne mesurent rien (verdict « rien à juger ») | anonyme → le jeton `admin:write` ; compte → un compte qui a le rôle (`as`), ou la zone n'accepte pas la session |
187
+ | `⚠️ … REDIRIGÉE(S) vers /login` | la page renvoie vers la connexion : on mesure la redirection, pas la page | jouer un compte, comme ci-dessus |
188
+ | `Tir :` · `Joué en tant que :` | ce qui a été envoyé, la chauffe, l'identité réellement jouée | vérifier que c'est bien la mesure voulue |
189
+ | `N+1 — route … ×N dans une requête` | la même requête SQL répétée N fois dans UNE requête HTTP : une boucle sur la base | charger d'un coup : `relations` du dépôt, ou `$in` sur les identifiants |
190
+ | `Erreurs — route …` + `Journal …` | les `5xx` et les lignes WARNING/ERROR de leur journal, par `requestId` | corriger d'après le message ; `nodefony_admin_call` syslog `logs` pour la suite du journal |
191
+ | `Lente — route … p95 …` | p95 ≥ 500 ms, avec ce qui coûte par requête | `action.self` domine → le code de l'action ou d'un service ; `SQL (cumul)` → les requêtes ; `render` → la vue |
192
+ | `Boucle d'événements bloquée` | un traitement SYNCHRONE a gelé le process ≥ 100 ms : toutes les routes ont attendu | chercher la boucle lourde, l'API `*Sync`, le gros `JSON.parse` ; juste après un démarrage, rappeler plus tard |
193
+ | `Refus (hors percentiles)` (`observe`) | des `401`/`403` dans le trafic observé : ces requêtes ne mesurent rien | appeler avec une session ou un jeton, pas conclure sur ces durées |
194
+
195
+ **Pièges :**
196
+
197
+ - **Ne modifie AUCUN fichier pendant la mesure** : le serveur de développement redémarre, l'outil
198
+ rend un rapport partiel marqué « interrompu ». Rappelle-le une fois le serveur relancé.
199
+ - **Les requêtes de `nodefony_profile_route` sont de VRAIES requêtes** : une page qui écrit en GET
200
+ (compteur, session créée pour chaque visiteur anonyme) écrit N fois. Le rapport le montre — c'est
201
+ souvent une découverte en soi.
202
+ - **Les zones à jeton (`jwt`, `external-jwt`) ne sont pas jouées** : seule la session l'est ; leurs
203
+ requêtes rendent `401`, et le rapport le dit.
204
+ - **Le journal d'une `5xx` n'est lu que par un appelant authentifié** (scope `admin:read`). Sans
205
+ jeton, le rapport le dit et nomme le geste.
206
+ - **`nodefony_observe` écarte l'outillage (`/nodefony/…`)** — console, API d'administration, porte
207
+ MCP ; `"includeTooling": true` le compte. `nodefony_profile_route` mesure le chemin qu'on lui
208
+ donne, quel qu'il soit.
209
+ - **Les valeurs SQL sont masquées** (`?`) : le rapport montre la FORME d'une requête, jamais une
210
+ donnée.
211
+ - **« boucle d'événements : non mesurée »** : le tir a duré moins de cinq périodes de la sonde ;
212
+ augmente `count` pour la lire.
213
+ - **Abandonner l'appel** n'arrête pas toujours l'outil côté serveur : selon le client, il va au bout
214
+ de son tir (45 s au plus) ou de sa fenêtre.
215
+ - Les deux outils n'existent qu'en **développement** (`@nodefony/devkit`) ; ailleurs, ils répondent
216
+ qu'il n'y a aucun profileur.
217
+
218
+ ## 6. Avant de dire « réparé »
145
219
 
146
220
  1. **Rejoue le symptôme d'origine** — la même requête, la même commande — et constate qu'il a
147
221
  disparu. Un correctif qu'on n'a pas vu agir sur le symptôme est une hypothèse.
@@ -1,6 +0,0 @@
1
- //#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorateMetadata.js
2
- function __decorateMetadata(k, v) {
3
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4
- }
5
- //#endregion
6
- export { __decorateMetadata as default };