@nodefony/framework 10.0.0-beta.1 → 10.0.0-beta.2
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/README.md +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.152.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.152.0}/helpers/esm/decorateMetadata.js +1 -1
- package/dist/index.js +2 -2
- package/dist/nodefony/controller/ApiKeyController.js +2 -1
- package/dist/nodefony/controller/TokenAuthController.js +2 -2
- package/dist/nodefony/controller/TotpController.js +2 -1
- package/dist/nodefony/service/AdminBroker.js +2 -2
- package/dist/nodefony/service/IdempotencyStore.js +2 -2
- package/dist/nodefony/service/router.js +5 -3
- package/dist/nodefony/src/Resolver.js +2 -2
- package/dist/nodefony/src/Route.js +24 -1
- package/dist/nodefony/src/docsReader.js +27 -21
- package/dist/types/nodefony/controller/ApiKeyController.d.ts +2 -1
- package/dist/types/nodefony/controller/TokenAuthController.d.ts +2 -2
- package/dist/types/nodefony/controller/TotpController.d.ts +2 -1
- package/dist/types/nodefony/src/Resolver.d.ts +1 -1
- package/dist/types/nodefony/src/Route.d.ts +15 -1
- package/dist/types/nodefony/src/docsReader.d.ts +16 -6
- package/docs/controller.md +55 -55
- package/docs/decorateurs.md +18 -17
- package/docs/idempotence.md +11 -11
- package/docs/index.md +1 -1
- package/docs/routing.md +44 -43
- package/docs/templates.md +7 -7
- package/package.json +9 -10
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ sert **HTTP et WebSocket dans le même contexte**, nativement.
|
|
|
6
6
|
|
|
7
7
|
> Docs IA (dans le dépôt) : [`CLAUDE.md`](https://github.com/nodefony/nodefony-core/blob/main/src/packages/@nodefony/framework/CLAUDE.md) (instructions session) · [`MEMORY.md`](https://github.com/nodefony/nodefony-core/blob/main/src/packages/@nodefony/framework/MEMORY.md)
|
|
8
8
|
> (internals concis) · [`docs/`](./docs) (concepts). `@nodefony/http` ne peut PAS importer
|
|
9
|
-
> ce module (dépendance circulaire) — l'accès se fait via `
|
|
9
|
+
> ce module (dépendance circulaire) — l'accès se fait via `context.resolver`, typé par le contrat `IRouteResolver` (défini par http, implémenté par framework).
|
|
10
10
|
|
|
11
11
|
## Rôle
|
|
12
12
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.152.0/helpers/esm/decorate.js
|
|
2
2
|
function __decorate(decorators, target, key, desc) {
|
|
3
3
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
4
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.152.0/helpers/esm/decorateMetadata.js
|
|
2
2
|
function __decorateMetadata(k, v) {
|
|
3
3
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4
4
|
}
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,8 @@ import Route from "./nodefony/src/Route.js";
|
|
|
7
7
|
import Controller from "./nodefony/src/Controller.js";
|
|
8
8
|
import { All, Anonymous, Body, BypassFirewall, Cookie, Csp, CsrfExempt, CsrfProtect, CurrentUser, Delete, Domain, Get, Head, Header, Headers, HttpCode, Idempotent, IsGranted, Options, Param, Patch, Post, Put, Query, Redirect, Req, RequireScope, Res, Scope, Session, UploadedFile, UploadedFiles, UseSession, controller, controllers, route, routeExpectsBodyStream } from "./nodefony/decorators/routerDecorators.js";
|
|
9
9
|
import Resolver from "./nodefony/src/Resolver.js";
|
|
10
|
-
import __decorateMetadata from "./_virtual/_@oxc-project_runtime@0.
|
|
11
|
-
import __decorate from "./_virtual/_@oxc-project_runtime@0.
|
|
10
|
+
import __decorateMetadata from "./_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorateMetadata.js";
|
|
11
|
+
import __decorate from "./_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorate.js";
|
|
12
12
|
import router_default from "./nodefony/service/router.js";
|
|
13
13
|
import ResourceController from "./nodefony/src/ResourceController.js";
|
|
14
14
|
import AdminApiController from "./nodefony/controller/AdminApiController.js";
|
|
@@ -18,7 +18,8 @@ let mounted = false;
|
|
|
18
18
|
* zone data plane `^/nodefony/[^/]+/api(/|$)` → **session BFF requise**. Le porteur
|
|
19
19
|
* est TOUJOURS l'utilisateur courant (`authFlow.me`), jamais un paramètre — on ne
|
|
20
20
|
* crée/révoque jamais une clé pour autrui. Montés seulement si le service `apiKeys`
|
|
21
|
-
* existe (security chargé
|
|
21
|
+
* existe (security chargé) — sans security, 404 et zéro surface ; clés
|
|
22
|
+
* désactivées, les routes répondent 503.
|
|
22
23
|
*
|
|
23
24
|
* Erreurs mappées par DUCK-TYPING sur `code` (400/409/503) — framework ne peut pas
|
|
24
25
|
* importer les classes d'erreur de security.
|
|
@@ -16,8 +16,8 @@ function parseScope(scope) {
|
|
|
16
16
|
* - `POST /nodefony/security/api/token/refresh` — body `{refresh_token}` → rotation
|
|
17
17
|
*
|
|
18
18
|
* Montés par le module framework UNIQUEMENT si le service `tokenService` existe
|
|
19
|
-
* (module security chargé
|
|
20
|
-
*
|
|
19
|
+
* (module security chargé) — sans lui, les routes n'existent pas (404, zéro
|
|
20
|
+
* surface). JWT désactivé ou store indisponible : les routes répondent 503.
|
|
21
21
|
*
|
|
22
22
|
* Le JWT part en **réponse JSON** (Bearer), JAMAIS en cookie ni en URL (anti
|
|
23
23
|
* fuite / non-révocable). Erreurs mappées par DUCK-TYPING sur `code` (401/429) —
|
|
@@ -17,7 +17,8 @@ let mounted = false;
|
|
|
17
17
|
* plane `^/nodefony/[^/]+/api(/|$)` → **session BFF requise**. Le sujet est
|
|
18
18
|
* TOUJOURS l'utilisateur courant (`authFlow.me`), jamais un paramètre — on n'active
|
|
19
19
|
* /ne désactive jamais le 2FA d'autrui (anti-IDOR). Montés seulement si le service
|
|
20
|
-
* `totp` existe (security chargé
|
|
20
|
+
* `totp` existe (security chargé) — sans security, 404 et zéro surface ; 2FA
|
|
21
|
+
* désactivé, les routes répondent 503.
|
|
21
22
|
*/
|
|
22
23
|
var TotpController = class extends Controller {
|
|
23
24
|
constructor(context) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorate.js";
|
|
3
3
|
import router_default from "./router.js";
|
|
4
4
|
import AdminApiController from "../controller/AdminApiController.js";
|
|
5
5
|
import { ADMIN_DEFAULT_ROLE, Module, Service, injectable, resolveAdminRole } from "nodefony";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorate.js";
|
|
3
3
|
import { Module, Service, assertPageQuery, injectable } from "nodefony";
|
|
4
4
|
//#region nodefony/service/IdempotencyStore.ts
|
|
5
5
|
const serviceName = "idempotencyStore";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import Route from "../src/Route.js";
|
|
2
2
|
import { routeExpectsBodyStream } from "../decorators/routerDecorators.js";
|
|
3
3
|
import Resolver from "../src/Resolver.js";
|
|
4
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
5
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
4
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorateMetadata.js";
|
|
5
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorate.js";
|
|
6
6
|
import { Injector, Module, Service, injectable, isPromise } from "nodefony";
|
|
7
7
|
import { HttpError, isDomainAllowed } from "@nodefony/http";
|
|
8
8
|
//#region nodefony/service/router.ts
|
|
@@ -156,11 +156,13 @@ let Router = class Router extends Service {
|
|
|
156
156
|
let di = 0;
|
|
157
157
|
while (li < litCount || di < dynCount) {
|
|
158
158
|
let route;
|
|
159
|
+
let fromLiterals = false;
|
|
159
160
|
const literal = literals[li];
|
|
160
161
|
const candidate = dynamics[di];
|
|
161
162
|
if (literal !== void 0 && (candidate === void 0 || literal.pos < candidate.pos)) {
|
|
162
163
|
li++;
|
|
163
164
|
route = literal.route;
|
|
165
|
+
fromLiterals = true;
|
|
164
166
|
} else if (candidate === void 0) break;
|
|
165
167
|
else {
|
|
166
168
|
di++;
|
|
@@ -168,7 +170,7 @@ let Router = class Router extends Service {
|
|
|
168
170
|
route = candidate.route;
|
|
169
171
|
}
|
|
170
172
|
try {
|
|
171
|
-
if (resolver.match(route, context, cleanPath)) {
|
|
173
|
+
if (resolver.match(route, context, cleanPath, fromLiterals)) {
|
|
172
174
|
routeNoticePromoted ??= this.kernel?.environment !== "production";
|
|
173
175
|
if (routeNoticePromoted) this.log(`Match route : ${route.name}`, "NOTICE");
|
|
174
176
|
resolver.exception = void 0;
|
|
@@ -78,8 +78,8 @@ var Resolver = class {
|
|
|
78
78
|
this.context = context;
|
|
79
79
|
this.injector = context.container?.get("injector") ?? null;
|
|
80
80
|
}
|
|
81
|
-
match(route, context, cleanPath) {
|
|
82
|
-
const match = route.match(context, cleanPath, this.methodOverride ?? void 0);
|
|
81
|
+
match(route, context, cleanPath, literal) {
|
|
82
|
+
const match = route.match(context, cleanPath, this.methodOverride ?? void 0, literal);
|
|
83
83
|
if (match) {
|
|
84
84
|
this.variables = match;
|
|
85
85
|
this.route = route;
|
|
@@ -203,10 +203,29 @@ var Route = class Route {
|
|
|
203
203
|
if (!reqUrl) return;
|
|
204
204
|
return stripTrailingSlashes(reqUrl.pathname);
|
|
205
205
|
}
|
|
206
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Confronte la requête à cette route : chemin, hôte, puis exigences.
|
|
208
|
+
*
|
|
209
|
+
* @param context - contexte HTTP/WS courant.
|
|
210
|
+
* @param cleanPath - pathname déjà normalisé par l'appelant (sinon recalculé).
|
|
211
|
+
* @param methodOverride - méthode logique du pont WS-RPC (cf `Resolver`).
|
|
212
|
+
* @param literal - l'appelant GARANTIT que le chemin de la route ne porte
|
|
213
|
+
* aucune syntaxe de motif (`{}`, `*`…) — c'est le cas d'une route trouvée
|
|
214
|
+
* par l'index des littérales du `Router`. Le motif n'est alors pas exécuté
|
|
215
|
+
* quand le chemin est identique à la lettre.
|
|
216
|
+
* @returns les valeurs capturées (tableau + accès par nom), ou `null`/`undefined`
|
|
217
|
+
* quand le chemin ne correspond pas.
|
|
218
|
+
* @throws 403/405/1002 quand le chemin correspond mais pas l'hôte ou les exigences.
|
|
219
|
+
*/
|
|
220
|
+
match(context, cleanPath, methodOverride, literal) {
|
|
207
221
|
let res;
|
|
208
222
|
if (context.request && this.pattern) {
|
|
209
223
|
const url = cleanPath ?? Route.cleanPathname(context);
|
|
224
|
+
if (literal === true && url === this.path && !this.#hasPositionalDefaults()) {
|
|
225
|
+
this.matchHostname(context);
|
|
226
|
+
this.matchRequirements(context, methodOverride);
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
210
229
|
if (url !== void 0) res = url.match(this.pattern);
|
|
211
230
|
}
|
|
212
231
|
if (!res) return res;
|
|
@@ -307,6 +326,10 @@ var Route = class Route {
|
|
|
307
326
|
if (compiled) (this.varRegexp ??= Object.create(null))[k] = compiled;
|
|
308
327
|
}
|
|
309
328
|
}
|
|
329
|
+
#hasPositionalDefaults() {
|
|
330
|
+
for (const def in this.defaults) if (def !== "controller") return true;
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
310
333
|
hydrateDefaultParameters(res) {
|
|
311
334
|
if (this.variables.length) for (let i = 0; i < this.variables.length; i++) {
|
|
312
335
|
const name = this.variables[i];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basename, dirname, extname, join } from "node:path";
|
|
2
|
-
import { findProjectRoot, resolveSymbolsFile } from "nodefony";
|
|
2
|
+
import { findProjectRoot, packageManagerCommandLines, packageManagerExecArgs, portableSpawn, resolvePackageManager, resolveSymbolsFile } from "nodefony";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { readFile, readdir, stat } from "node:fs/promises";
|
|
@@ -653,50 +653,54 @@ async function listTestGroups(modulePath) {
|
|
|
653
653
|
* config du module (la liste `reporter` dupliquée par module divergeait).
|
|
654
654
|
* - sinon (cœur : monocart, pas de `vitest.config.ts`) → `npm run coverage`.
|
|
655
655
|
*
|
|
656
|
+
* Le binaire et le script passent par le gestionnaire de paquets du PROJET :
|
|
657
|
+
* `npx` n'existe pas chez bun, et sous pnpm il chercherait hors de l'arbre que
|
|
658
|
+
* le verrou décrit.
|
|
659
|
+
*
|
|
656
660
|
* @param modulePath - racine du module (où vit `vitest.config.ts`)
|
|
657
661
|
* @param file - chemin relatif d'UN fichier de test, déjà validé par l'appelant
|
|
662
|
+
* @param manager - gestionnaire du projet ; défaut : résolu depuis la racine
|
|
663
|
+
* de l'application qui contient le module
|
|
658
664
|
* @returns commande, arguments en tableau (spawn sans shell) et libellé du mode
|
|
659
665
|
*/
|
|
660
|
-
function testRunCommand(modulePath, file) {
|
|
666
|
+
function testRunCommand(modulePath, file, manager = resolvePackageManager({ dir: findProjectRoot(modulePath) ?? modulePath }).name) {
|
|
661
667
|
const hasVitest = existsSync(join(modulePath, "vitest.config.ts"));
|
|
662
668
|
if (file && hasVitest) return {
|
|
663
|
-
cmd:
|
|
664
|
-
args: [
|
|
665
|
-
"vitest",
|
|
666
|
-
"run",
|
|
667
|
-
file
|
|
668
|
-
],
|
|
669
|
+
cmd: manager,
|
|
670
|
+
args: packageManagerExecArgs(manager, "vitest", ["run", file]),
|
|
669
671
|
mode: `vitest run ${file}`
|
|
670
672
|
};
|
|
671
673
|
if (hasVitest) return {
|
|
672
|
-
cmd:
|
|
673
|
-
args: [
|
|
674
|
-
"vitest",
|
|
674
|
+
cmd: manager,
|
|
675
|
+
args: packageManagerExecArgs(manager, "vitest", [
|
|
675
676
|
"run",
|
|
676
677
|
"--coverage",
|
|
677
678
|
"--coverage.reporter=text-summary",
|
|
678
679
|
"--coverage.reporter=json-summary",
|
|
679
680
|
"--coverage.reporter=lcov",
|
|
680
681
|
"--coverage.reportsDirectory=.coverage"
|
|
681
|
-
],
|
|
682
|
+
]),
|
|
682
683
|
mode: "vitest run --coverage (reporters forcés)"
|
|
683
684
|
};
|
|
684
685
|
return {
|
|
685
|
-
cmd:
|
|
686
|
+
cmd: manager,
|
|
686
687
|
args: ["run", "coverage"],
|
|
687
|
-
mode: "
|
|
688
|
+
mode: `${packageManagerCommandLines(manager).run("coverage")} (suite complète)`
|
|
688
689
|
};
|
|
689
690
|
}
|
|
690
691
|
/**
|
|
691
692
|
* Lance les tests d'un module et renvoie un résumé (pass/fail/durée + tail).
|
|
692
693
|
*
|
|
693
|
-
* - 1 fichier (module vitest) → `
|
|
694
|
-
* - sinon →
|
|
695
|
-
* pour vitest comme pour
|
|
694
|
+
* - 1 fichier (module vitest) → `vitest run <file>` (rapide, pass/fail).
|
|
695
|
+
* - sinon → le script `coverage` (suite complète + refresh coverage ; marche
|
|
696
|
+
* pour vitest comme pour le cœur).
|
|
697
|
+
* Les deux par le gestionnaire du projet (cf {@link testRunCommand}).
|
|
696
698
|
*
|
|
697
699
|
* ⚠️ EXÉCUTE un process — appelé UNIQUEMENT derrière le garde dev-only de
|
|
698
|
-
* l'endpoint (cf KernelAdminApi).
|
|
699
|
-
* d'injection
|
|
700
|
+
* l'endpoint (cf KernelAdminApi). `portableSpawn` : jamais de `shell`, args
|
|
701
|
+
* en tableau (pas d'injection), et le `.cmd` du gestionnaire se lance sous
|
|
702
|
+
* Windows — un `spawn("npx")` nu y rendait `ENOENT`. `file` validé en amont
|
|
703
|
+
* (suffixe .test.ts, pas de `..`).
|
|
700
704
|
*/
|
|
701
705
|
function runModuleTests(modulePath, file) {
|
|
702
706
|
const { cmd, args, mode } = testRunCommand(modulePath, file);
|
|
@@ -709,9 +713,11 @@ function runModuleTests(modulePath, file) {
|
|
|
709
713
|
};
|
|
710
714
|
let child;
|
|
711
715
|
try {
|
|
712
|
-
|
|
716
|
+
const run = portableSpawn(cmd, args);
|
|
717
|
+
child = spawn(run.file, run.args, {
|
|
713
718
|
cwd: modulePath,
|
|
714
|
-
env: process.env
|
|
719
|
+
env: process.env,
|
|
720
|
+
windowsVerbatimArguments: run.windowsVerbatimArguments
|
|
715
721
|
});
|
|
716
722
|
} catch (e) {
|
|
717
723
|
return resolve({
|
|
@@ -16,7 +16,8 @@ import Controller from "../src/Controller.js";
|
|
|
16
16
|
* zone data plane `^/nodefony/[^/]+/api(/|$)` → **session BFF requise**. Le porteur
|
|
17
17
|
* est TOUJOURS l'utilisateur courant (`authFlow.me`), jamais un paramètre — on ne
|
|
18
18
|
* crée/révoque jamais une clé pour autrui. Montés seulement si le service `apiKeys`
|
|
19
|
-
* existe (security chargé
|
|
19
|
+
* existe (security chargé) — sans security, 404 et zéro surface ; clés
|
|
20
|
+
* désactivées, les routes répondent 503.
|
|
20
21
|
*
|
|
21
22
|
* Erreurs mappées par DUCK-TYPING sur `code` (400/409/503) — framework ne peut pas
|
|
22
23
|
* importer les classes d'erreur de security.
|
|
@@ -23,8 +23,8 @@ export interface ITokenIssuer {
|
|
|
23
23
|
* - `POST /nodefony/security/api/token/refresh` — body `{refresh_token}` → rotation
|
|
24
24
|
*
|
|
25
25
|
* Montés par le module framework UNIQUEMENT si le service `tokenService` existe
|
|
26
|
-
* (module security chargé
|
|
27
|
-
*
|
|
26
|
+
* (module security chargé) — sans lui, les routes n'existent pas (404, zéro
|
|
27
|
+
* surface). JWT désactivé ou store indisponible : les routes répondent 503.
|
|
28
28
|
*
|
|
29
29
|
* Le JWT part en **réponse JSON** (Bearer), JAMAIS en cookie ni en URL (anti
|
|
30
30
|
* fuite / non-révocable). Erreurs mappées par DUCK-TYPING sur `code` (401/429) —
|
|
@@ -16,7 +16,8 @@ import Controller from "../src/Controller.js";
|
|
|
16
16
|
* plane `^/nodefony/[^/]+/api(/|$)` → **session BFF requise**. Le sujet est
|
|
17
17
|
* TOUJOURS l'utilisateur courant (`authFlow.me`), jamais un paramètre — on n'active
|
|
18
18
|
* /ne désactive jamais le 2FA d'autrui (anti-IDOR). Montés seulement si le service
|
|
19
|
-
* `totp` existe (security chargé
|
|
19
|
+
* `totp` existe (security chargé) — sans security, 404 et zéro surface ; 2FA
|
|
20
|
+
* désactivé, les routes répondent 503.
|
|
20
21
|
*/
|
|
21
22
|
declare class TotpController extends Controller {
|
|
22
23
|
#private;
|
|
@@ -71,7 +71,7 @@ declare class Resolver implements IResolver {
|
|
|
71
71
|
*/
|
|
72
72
|
messageInvocation: boolean;
|
|
73
73
|
constructor(context: ContextType);
|
|
74
|
-
match(route: Route, context: ContextType, cleanPath?: string): ((string | null)[] & Record<string, unknown>) | null | undefined;
|
|
74
|
+
match(route: Route, context: ContextType, cleanPath?: string, literal?: boolean): ((string | null)[] & Record<string, unknown>) | null | undefined;
|
|
75
75
|
/**
|
|
76
76
|
* Snapshot per-requête des variables de route matchées (`{name}` → valeur,
|
|
77
77
|
* + wildcard `*` éventuel). Construit depuis les valeurs de CETTE requête
|
|
@@ -151,7 +151,21 @@ declare class Route implements IRoute {
|
|
|
151
151
|
* @returns le pathname sans slash final, ou `undefined` si la requête n'a pas d'URL.
|
|
152
152
|
*/
|
|
153
153
|
static cleanPathname(context: ContextType): string | undefined;
|
|
154
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Confronte la requête à cette route : chemin, hôte, puis exigences.
|
|
156
|
+
*
|
|
157
|
+
* @param context - contexte HTTP/WS courant.
|
|
158
|
+
* @param cleanPath - pathname déjà normalisé par l'appelant (sinon recalculé).
|
|
159
|
+
* @param methodOverride - méthode logique du pont WS-RPC (cf `Resolver`).
|
|
160
|
+
* @param literal - l'appelant GARANTIT que le chemin de la route ne porte
|
|
161
|
+
* aucune syntaxe de motif (`{}`, `*`…) — c'est le cas d'une route trouvée
|
|
162
|
+
* par l'index des littérales du `Router`. Le motif n'est alors pas exécuté
|
|
163
|
+
* quand le chemin est identique à la lettre.
|
|
164
|
+
* @returns les valeurs capturées (tableau + accès par nom), ou `null`/`undefined`
|
|
165
|
+
* quand le chemin ne correspond pas.
|
|
166
|
+
* @throws 403/405/1002 quand le chemin correspond mais pas l'hôte ou les exigences.
|
|
167
|
+
*/
|
|
168
|
+
match(context: ContextType, cleanPath?: string, methodOverride?: string, literal?: boolean): ((string | null)[] & Record<string, unknown>) | null | undefined;
|
|
155
169
|
/**
|
|
156
170
|
* Compile the route into a regular expression pattern.
|
|
157
171
|
* @returns The compiled regular expression pattern.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { IPackageManagerResolution } from "nodefony";
|
|
1
2
|
/**
|
|
2
3
|
* Frontmatter d'un fichier de doc module. Tous les champs sont optionnels —
|
|
3
4
|
* un `.md` sans frontmatter reste lisible (titre dérivé du premier `# H1`).
|
|
@@ -297,21 +298,30 @@ export interface TestRunCommand {
|
|
|
297
298
|
* config du module (la liste `reporter` dupliquée par module divergeait).
|
|
298
299
|
* - sinon (cœur : monocart, pas de `vitest.config.ts`) → `npm run coverage`.
|
|
299
300
|
*
|
|
301
|
+
* Le binaire et le script passent par le gestionnaire de paquets du PROJET :
|
|
302
|
+
* `npx` n'existe pas chez bun, et sous pnpm il chercherait hors de l'arbre que
|
|
303
|
+
* le verrou décrit.
|
|
304
|
+
*
|
|
300
305
|
* @param modulePath - racine du module (où vit `vitest.config.ts`)
|
|
301
306
|
* @param file - chemin relatif d'UN fichier de test, déjà validé par l'appelant
|
|
307
|
+
* @param manager - gestionnaire du projet ; défaut : résolu depuis la racine
|
|
308
|
+
* de l'application qui contient le module
|
|
302
309
|
* @returns commande, arguments en tableau (spawn sans shell) et libellé du mode
|
|
303
310
|
*/
|
|
304
|
-
export declare function testRunCommand(modulePath: string, file?: string): TestRunCommand;
|
|
311
|
+
export declare function testRunCommand(modulePath: string, file?: string, manager?: IPackageManagerResolution["name"]): TestRunCommand;
|
|
305
312
|
/**
|
|
306
313
|
* Lance les tests d'un module et renvoie un résumé (pass/fail/durée + tail).
|
|
307
314
|
*
|
|
308
|
-
* - 1 fichier (module vitest) → `
|
|
309
|
-
* - sinon →
|
|
310
|
-
* pour vitest comme pour
|
|
315
|
+
* - 1 fichier (module vitest) → `vitest run <file>` (rapide, pass/fail).
|
|
316
|
+
* - sinon → le script `coverage` (suite complète + refresh coverage ; marche
|
|
317
|
+
* pour vitest comme pour le cœur).
|
|
318
|
+
* Les deux par le gestionnaire du projet (cf {@link testRunCommand}).
|
|
311
319
|
*
|
|
312
320
|
* ⚠️ EXÉCUTE un process — appelé UNIQUEMENT derrière le garde dev-only de
|
|
313
|
-
* l'endpoint (cf KernelAdminApi).
|
|
314
|
-
* d'injection
|
|
321
|
+
* l'endpoint (cf KernelAdminApi). `portableSpawn` : jamais de `shell`, args
|
|
322
|
+
* en tableau (pas d'injection), et le `.cmd` du gestionnaire se lance sous
|
|
323
|
+
* Windows — un `spawn("npx")` nu y rendait `ENOENT`. `file` validé en amont
|
|
324
|
+
* (suffixe .test.ts, pas de `..`).
|
|
315
325
|
*/
|
|
316
326
|
export declare function runModuleTests(modulePath: string, file?: string): Promise<TestRunResult>;
|
|
317
327
|
/**
|