@nodefony/framework 10.0.0-beta.5 → 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.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/_@oxc-project_runtime@0.158.0/helpers/esm/decorateParam.js +7 -0
- package/dist/index.js +14 -10
- package/dist/nodefony/config/config.js +16 -2
- package/dist/nodefony/controller/AdminApiController.js +18 -5
- package/dist/nodefony/controller/BenchController.js +1 -1
- package/dist/nodefony/controller/CspReportController.js +70 -0
- package/dist/nodefony/controller/IssuerMetadataController.js +3 -3
- package/dist/nodefony/controller/LoginPageController.js +5 -7
- package/dist/nodefony/controller/ProtectedResourceMetadataController.js +75 -10
- package/dist/nodefony/controller/SessionAuthController.js +6 -7
- package/dist/nodefony/controller/TokenAuthController.js +3 -3
- package/dist/nodefony/decorators/routerDecorators.js +103 -15
- package/dist/nodefony/grpc/GrpcController.js +138 -0
- package/dist/nodefony/grpc/GrpcService.js +75 -0
- package/dist/nodefony/grpc/declarations.js +33 -0
- package/dist/nodefony/grpc/index.js +3 -0
- package/dist/nodefony/service/AdminBroker.js +1 -1
- package/dist/nodefony/service/IdempotencyStore.js +1 -1
- package/dist/nodefony/service/router.js +15 -12
- package/dist/nodefony/src/Controller.js +330 -115
- package/dist/nodefony/src/PlaygroundAdminApi.js +1 -1
- package/dist/nodefony/src/Resolver.js +85 -51
- package/dist/nodefony/src/Route.js +45 -45
- package/dist/nodefony/src/SecurityApiController.js +30 -7
- package/dist/nodefony/src/conditionalRequest.js +103 -0
- package/dist/nodefony/src/docsReader.js +1 -1
- package/dist/nodefony/src/idempotency.js +1 -1
- package/dist/nodefony/src/loginPage.js +3 -2
- package/dist/nodefony/src/scopeCatalog.js +1 -1
- package/dist/nodefony/src/viewNonce.js +58 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/nodefony/config/config.d.ts +20 -0
- package/dist/types/nodefony/controller/AdminApiController.d.ts +4 -2
- package/dist/types/nodefony/controller/CspReportController.d.ts +35 -0
- package/dist/types/nodefony/controller/LoginPageController.d.ts +3 -2
- package/dist/types/nodefony/controller/ProtectedResourceMetadataController.d.ts +21 -1
- package/dist/types/nodefony/controller/SessionAuthController.d.ts +5 -6
- package/dist/types/nodefony/controller/TokenAuthController.d.ts +3 -3
- package/dist/types/nodefony/decorators/routerDecorators.d.ts +2 -1
- package/dist/types/nodefony/grpc/GrpcController.d.ts +75 -0
- package/dist/types/nodefony/grpc/GrpcService.d.ts +51 -0
- package/dist/types/nodefony/grpc/declarations.d.ts +12 -0
- package/dist/types/nodefony/grpc/index.d.ts +13 -0
- package/dist/types/nodefony/interfaces/IController.d.ts +4 -4
- package/dist/types/nodefony/service/router.d.ts +8 -6
- package/dist/types/nodefony/src/Controller.d.ts +124 -14
- package/dist/types/nodefony/src/Resolver.d.ts +35 -8
- package/dist/types/nodefony/src/Route.d.ts +35 -0
- package/dist/types/nodefony/src/SecurityApiController.d.ts +17 -4
- package/dist/types/nodefony/src/conditionalRequest.d.ts +82 -0
- package/dist/types/nodefony/src/loginPage.d.ts +1 -1
- package/dist/types/nodefony/src/viewNonce.d.ts +33 -0
- package/docs/controller.md +234 -35
- package/docs/decorateurs.md +1 -1
- package/docs/grpc.md +690 -0
- package/docs/idempotence.md +13 -8
- package/docs/index.md +16 -10
- package/docs/routing.md +30 -2
- package/docs/templates.md +15 -0
- package/package.json +28 -11
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import Controller from "../src/Controller.js";
|
|
2
|
+
import { computeActionMeta, getReservedActionNames } from "../decorators/routerDecorators.js";
|
|
3
|
+
import { grpcDeclarationOf } from "./declarations.js";
|
|
4
|
+
import { BootConfigurationError } from "nodefony";
|
|
5
|
+
import { HttpContext } from "@nodefony/http";
|
|
6
|
+
import { GrpcEndpoint, markGrpcRoute } from "@nodefony/http/grpc";
|
|
7
|
+
// nodefony/grpc/GrpcController.ts
|
|
8
|
+
/**
|
|
9
|
+
* Nom de l'action de base, celle que toute route gRPC exécute : elle remet la
|
|
10
|
+
* requête à l'adaptateur. Les gardes, elles, se lisent sur la méthode du
|
|
11
|
+
* contrat.
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
const GRPC_ACTION = "serveGrpc";
|
|
16
|
+
/**
|
|
17
|
+
* Ce que chaque décorateur sans effet en gRPC laisse dans la méta d'action —
|
|
18
|
+
* un refus au démarrage le nomme (ADR-0026 D1, point 5 ; S-grpc-18).
|
|
19
|
+
*/
|
|
20
|
+
function inertDecorators(meta) {
|
|
21
|
+
const found = [];
|
|
22
|
+
if (meta.paramsMeta !== null) found.push("@Body/@Param/@Query… (paramètres)");
|
|
23
|
+
if (meta.schema !== null) found.push("schéma de route");
|
|
24
|
+
if (meta.sessionIntent !== null) found.push("@UseSession");
|
|
25
|
+
if (meta.cspDirectives !== null) found.push("@Csp");
|
|
26
|
+
if (meta.idempotent !== null) found.push("@Idempotent");
|
|
27
|
+
if (meta.httpCode !== null) found.push("@HttpCode");
|
|
28
|
+
if (meta.headerEntries !== null) found.push("@Header");
|
|
29
|
+
if (meta.redirectMeta !== null) found.push("@Redirect");
|
|
30
|
+
return found;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Classe de base d'un point d'entrée gRPC (ADR-0026 D1), jumelle de
|
|
34
|
+
* `RealtimeController` : marquée par `@GrpcService(Contrat)`, déclarée par
|
|
35
|
+
* `@controllers([...])`. Chaque méthode du contrat est une méthode de la
|
|
36
|
+
* classe, appelée par l'adaptateur Connect avec `(request, HandlerContext)` ;
|
|
37
|
+
* la logique métier vit dans un service injecté.
|
|
38
|
+
*
|
|
39
|
+
* Singleton par défaut : aucune instance par appel, l'adaptateur lie les
|
|
40
|
+
* méthodes une fois. `@Scope("request")` donne une instance par appel.
|
|
41
|
+
*
|
|
42
|
+
* Ce que le framework décide pour chaque méthode, sans code de ta part :
|
|
43
|
+
* - les gardes (`@IsGranted`, `@RequireAuthentication`…) posées sur la
|
|
44
|
+
* méthode ou la classe s'appliquent ; un refus part en 16
|
|
45
|
+
* `UNAUTHENTICATED` sans identité, en 7 `PERMISSION_DENIED` sinon ;
|
|
46
|
+
* - `this.user`, l'ALS et la portée `request` valent pendant tout l'appel,
|
|
47
|
+
* flux compris ;
|
|
48
|
+
* - une `ConnectError` part telle quelle ; une `HttpError` est traduite par
|
|
49
|
+
* la table de `google/rpc/code.proto` ; toute autre exception devient 13
|
|
50
|
+
* `INTERNAL`. Dans un flux, la traduction ne vaut qu'avant le premier
|
|
51
|
+
* message ;
|
|
52
|
+
* - un flux est interrompu en 14 `UNAVAILABLE` à l'arrêt du serveur et en 16
|
|
53
|
+
* à la révocation de son identité : passer `ctx.signal` à ses sources ;
|
|
54
|
+
* - messages bornés à 4 Mio (section `grpc` de la configuration http).
|
|
55
|
+
*
|
|
56
|
+
* Un décorateur sans effet en gRPC (`@Body`, `@UseSession`, `@Csp`,
|
|
57
|
+
* `@Idempotent`…) sur une méthode du contrat interrompt le démarrage.
|
|
58
|
+
* Guide complet : `docs/grpc.md` du paquet.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* \@GrpcService(GreetService)
|
|
62
|
+
* export class GreetController extends GrpcController {
|
|
63
|
+
* constructor(context: ContextType) {
|
|
64
|
+
* super("GreetController", context);
|
|
65
|
+
* }
|
|
66
|
+
* greet(request: GreetRequest) {
|
|
67
|
+
* return { greeting: `Bonjour, ${request.name} !` };
|
|
68
|
+
* }
|
|
69
|
+
* }
|
|
70
|
+
*
|
|
71
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
72
|
+
*/
|
|
73
|
+
var GrpcController = class extends Controller {
|
|
74
|
+
/**
|
|
75
|
+
* Vérifie la déclaration gRPC de la classe et fige ses routes — au
|
|
76
|
+
* démarrage (`Router.setController`), jamais à la première requête.
|
|
77
|
+
*
|
|
78
|
+
* Refuse : une classe sans `@GrpcService` ; une méthode du contrat absente
|
|
79
|
+
* de la classe ou dont le nom est réservé par le framework ; un décorateur
|
|
80
|
+
* sans effet en gRPC sur une méthode du contrat (ou sur la classe) — le
|
|
81
|
+
* refus nomme la méthode et le décorateur.
|
|
82
|
+
*
|
|
83
|
+
* Fige ensuite, sur chaque route, la méta d'action lue sur la MÉTHODE DU
|
|
84
|
+
* CONTRAT (l'action exécutée reste celle de la base) et le corps laissé en
|
|
85
|
+
* flux : les gardes valent quel que soit l'ordre des décorateurs de classe.
|
|
86
|
+
*
|
|
87
|
+
* @throws BootConfigurationError sur une déclaration refusée.
|
|
88
|
+
*/
|
|
89
|
+
static assertScope() {
|
|
90
|
+
const declaration = grpcDeclarationOf(this);
|
|
91
|
+
if (declaration === void 0) throw new BootConfigurationError(`Contrôleur gRPC « ${this.name} » sans @GrpcService(Contrat) : rien ne dit quel service il sert. Poser @GrpcService sur la classe.`);
|
|
92
|
+
const typeName = declaration.service.typeName;
|
|
93
|
+
const reserved = getReservedActionNames();
|
|
94
|
+
const metas = /* @__PURE__ */ new Map();
|
|
95
|
+
for (const method of declaration.service.methods) {
|
|
96
|
+
const name = method.localName;
|
|
97
|
+
const where = `Service gRPC ${typeName} (« ${this.name} »), méthode « ${name} »`;
|
|
98
|
+
const owner = name === "serveGrpc" || name === "grpcEndpoint" ? "GrpcController" : reserved.get(name);
|
|
99
|
+
if (owner !== void 0) throw new BootConfigurationError(`${where} : ce nom est réservé par ${owner}, dont tout contrôleur hérite. Renommer la méthode dans le contrat.`);
|
|
100
|
+
if (typeof Reflect.get(this.prototype, name) !== "function") throw new BootConfigurationError(`${where} : absente de la classe. Chaque méthode du contrat s'implémente sur son contrôleur.`);
|
|
101
|
+
const meta = computeActionMeta(this, name);
|
|
102
|
+
const inert = inertDecorators(meta);
|
|
103
|
+
if (inert.length !== 0) throw new BootConfigurationError(`${where} : ${inert.join(", ")} sans effet sur un appel gRPC (posé sur la méthode ou sur la classe). Les retirer.`);
|
|
104
|
+
metas.set(name, meta);
|
|
105
|
+
}
|
|
106
|
+
for (const { route, method } of declaration.routes) {
|
|
107
|
+
const meta = metas.get(method.localName);
|
|
108
|
+
if (meta === void 0) continue;
|
|
109
|
+
route.actionMeta = {
|
|
110
|
+
...meta,
|
|
111
|
+
bodyStream: true
|
|
112
|
+
};
|
|
113
|
+
route.bodyStream = true;
|
|
114
|
+
markGrpcRoute(route);
|
|
115
|
+
}
|
|
116
|
+
Object.defineProperty(this.prototype, "grpcEndpoint", {
|
|
117
|
+
value: new GrpcEndpoint(declaration.service, { perCall: this.scope !== "singleton" }),
|
|
118
|
+
configurable: true
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* L'action de base de toute route gRPC : remet la requête et la réponse
|
|
123
|
+
* brutes à l'adaptateur, qui appelle la méthode du contrat et écrit la
|
|
124
|
+
* réponse. Synchrone, sauf pour un flux dont la session est à sauver : la
|
|
125
|
+
* promesse de la remise est alors rendue au résolveur, qui en lit l'échec.
|
|
126
|
+
*
|
|
127
|
+
* @throws Error quand la classe n'a pas été enregistrée par le routeur, ou
|
|
128
|
+
* hors d'une requête HTTP.
|
|
129
|
+
*/
|
|
130
|
+
serveGrpc() {
|
|
131
|
+
const endpoint = this.grpcEndpoint;
|
|
132
|
+
if (endpoint === void 0) throw new Error(`Contrôleur gRPC « ${this.constructor.name} » non enregistré : le déclarer par @controllers([...]).`);
|
|
133
|
+
const context = this.context;
|
|
134
|
+
if (!(context instanceof HttpContext)) throw new Error("Un appel gRPC n'est servi que sur une requête HTTP.");
|
|
135
|
+
return endpoint.serve(context, this);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
export { GRPC_ACTION, GrpcController };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import router_default from "../service/router.js";
|
|
2
|
+
import { applyDeclaredRouteOptions } from "../decorators/routerDecorators.js";
|
|
3
|
+
import { GRPC_ACTION } from "./GrpcController.js";
|
|
4
|
+
import { claimGrpcService, declareGrpcService } from "./declarations.js";
|
|
5
|
+
import { BootConfigurationError } from "nodefony";
|
|
6
|
+
import { MethodOptions_IdempotencyLevel } from "@bufbuild/protobuf/wkt";
|
|
7
|
+
// nodefony/grpc/GrpcService.ts
|
|
8
|
+
/**
|
|
9
|
+
* Déclare un contrôleur comme le point d'entrée du service gRPC `service`
|
|
10
|
+
* (le descripteur généré par `buf`, ex. `EchoService` de `echo_pb.ts`).
|
|
11
|
+
*
|
|
12
|
+
* Monte une route littérale du Router par méthode du contrat,
|
|
13
|
+
* `POST /<paquet.Service>/<Méthode>`, plus `GET` pour une méthode déclarée
|
|
14
|
+
* `option idempotency_level = NO_SIDE_EFFECTS` (le GET de Connect). Ces
|
|
15
|
+
* routes passent par tout le pipeline — pare-feu, `@IsGranted`, hôtes
|
|
16
|
+
* virtuels, profileur, liste des routes —, et leurs gardes se lisent sur la
|
|
17
|
+
* méthode du contrat. La classe se déclare ensuite par `@controllers([...])`,
|
|
18
|
+
* comme tout point d'entrée d'un module.
|
|
19
|
+
*
|
|
20
|
+
* Les décorateurs de classe `@Domain` et `@BypassFirewall` se placent SOUS
|
|
21
|
+
* `@GrpcService` (lus au montage des routes, comme sous `@controller`).
|
|
22
|
+
*
|
|
23
|
+
* Le descripteur vient du code généré, jamais écrit à la main : contrat dans
|
|
24
|
+
* `proto/<paquet>/v1/*.proto`, `npx buf generate` vers `nodefony/gen/`, code
|
|
25
|
+
* commité. Les routes répondent sur 5152 (gRPC, gRPC-Web, Connect), 5151
|
|
26
|
+
* (gRPC-Web, Connect : HTTP/1.1, jamais le gRPC natif) et 5153 si h2c est
|
|
27
|
+
* activé. Guide complet : `docs/grpc.md` du paquet.
|
|
28
|
+
*
|
|
29
|
+
* @param service - le descripteur du service.
|
|
30
|
+
* @returns le décorateur de classe.
|
|
31
|
+
* @throws BootConfigurationError quand une autre classe sert déjà ce contrat.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* \@GrpcService(EchoService)
|
|
35
|
+
* export class EchoController extends GrpcController {
|
|
36
|
+
* constructor(context: ContextType) {
|
|
37
|
+
* super("EchoController", context);
|
|
38
|
+
* }
|
|
39
|
+
* \@IsGranted("ROLE_ECHO")
|
|
40
|
+
* say(request: SayRequest) {
|
|
41
|
+
* return { sentence: request.sentence };
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
46
|
+
*/
|
|
47
|
+
function GrpcService(service) {
|
|
48
|
+
return function(ctor) {
|
|
49
|
+
const owner = claimGrpcService(service.typeName, ctor.name);
|
|
50
|
+
if (owner !== null) throw new BootConfigurationError(`@GrpcService(${service.typeName}) sur « ${ctor.name} » : ce service est déjà servi par « ${owner} ». Un contrat n'a qu'un point d'entrée.`);
|
|
51
|
+
const routes = [];
|
|
52
|
+
for (const method of service.methods) {
|
|
53
|
+
const options = {
|
|
54
|
+
prefix: `/${service.typeName}`,
|
|
55
|
+
path: `/${method.name}`,
|
|
56
|
+
constructor: ctor,
|
|
57
|
+
className: ctor.name,
|
|
58
|
+
classMethod: GRPC_ACTION,
|
|
59
|
+
method: method.idempotency === MethodOptions_IdempotencyLevel.NO_SIDE_EFFECTS ? ["POST", "GET"] : "POST"
|
|
60
|
+
};
|
|
61
|
+
applyDeclaredRouteOptions(ctor, options, method.localName);
|
|
62
|
+
const route = router_default.createRoute(`${ctor.name}::${method.localName}`, options);
|
|
63
|
+
routes.push({
|
|
64
|
+
route,
|
|
65
|
+
method
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
declareGrpcService(ctor, {
|
|
69
|
+
service,
|
|
70
|
+
routes
|
|
71
|
+
});
|
|
72
|
+
return ctor;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export { GrpcService };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// nodefony/grpc/declarations.ts
|
|
2
|
+
/**
|
|
3
|
+
* Déclarations par classe contrôleur. Écrite à l'import (`@GrpcService`), lue
|
|
4
|
+
* une fois au démarrage (`GrpcController.assertScope`) : jamais sur le chemin
|
|
5
|
+
* d'un appel.
|
|
6
|
+
*/
|
|
7
|
+
const declarations = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
/**
|
|
9
|
+
* Contrat déjà servi, par nom complet : deux classes qui serviraient le même
|
|
10
|
+
* service monteraient deux fois les mêmes chemins.
|
|
11
|
+
*/
|
|
12
|
+
const servedBy = /* @__PURE__ */ new Map();
|
|
13
|
+
/** @internal */
|
|
14
|
+
function declareGrpcService(ctor, declaration) {
|
|
15
|
+
declarations.set(ctor, declaration);
|
|
16
|
+
}
|
|
17
|
+
/** @internal */
|
|
18
|
+
function grpcDeclarationOf(ctor) {
|
|
19
|
+
return declarations.get(ctor);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Retient quelle classe sert un contrat.
|
|
23
|
+
*
|
|
24
|
+
* @returns le nom de la classe qui le servait déjà, ou `null`.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
function claimGrpcService(typeName, className) {
|
|
28
|
+
const owner = servedBy.get(typeName);
|
|
29
|
+
if (owner !== void 0) return owner;
|
|
30
|
+
servedBy.set(typeName, className);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
export { claimGrpcService, declareGrpcService, grpcDeclarationOf };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
|
|
2
1
|
import router_default from "./router.js";
|
|
3
2
|
import AdminApiController from "../controller/AdminApiController.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.158.0/helpers/esm/decorate.js";
|
|
4
4
|
import { ADMIN_DEFAULT_ROLE, Service, injectable, resolveAdminRole } from "nodefony";
|
|
5
5
|
// nodefony/service/AdminBroker.ts
|
|
6
6
|
const serviceName = "adminBroker";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.158.0/helpers/esm/decorate.js";
|
|
2
2
|
import { Service, assertPageQuery, injectable } from "nodefony";
|
|
3
3
|
// nodefony/service/IdempotencyStore.ts
|
|
4
4
|
const serviceName = "idempotencyStore";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Route from "../src/Route.js";
|
|
2
|
-
import { assertRouteSchemaDeclaration, routeExpectsBodyStream } from "../decorators/routerDecorators.js";
|
|
3
2
|
import Resolver from "../src/Resolver.js";
|
|
4
|
-
import
|
|
3
|
+
import { assertRouteSchemaDeclaration, routeExpectsBodyStream } from "../decorators/routerDecorators.js";
|
|
4
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.158.0/helpers/esm/decorate.js";
|
|
5
5
|
import { BootConfigurationError, Injector, Module, Service, injectable, isPromise, stripTrailingSlashes } from "nodefony";
|
|
6
6
|
import { HttpError, isDomainAllowed } from "@nodefony/http";
|
|
7
7
|
// nodefony/service/router.ts
|
|
@@ -173,10 +173,11 @@ let Router = class Router extends Service {
|
|
|
173
173
|
* lieu de `context.request.url` — permet de router un path **porté par un message**
|
|
174
174
|
* (WS-RPC `invoke`) vers une action, sans muter l'URL de la connexion (état partagé).
|
|
175
175
|
* `undefined` (cas hot path normal) → comportement inchangé.
|
|
176
|
-
* @param methodOverride - méthode HTTP **logique**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* `undefined` (
|
|
176
|
+
* @param methodOverride - méthode HTTP **logique** du pont WS-RPC `api.request`,
|
|
177
|
+
* GET compris, exigée en plus du transport WEBSOCKET par la règle du cœur
|
|
178
|
+
* `bridgeServesVerb` : un GET n'atteint jamais une action POST du même
|
|
179
|
+
* chemin. `undefined` (requête HTTP, ouverture de socket) → match sur
|
|
180
|
+
* `context.method`.
|
|
180
181
|
* @returns un `Resolver` (`.resolve === true` si une route a matché) — ou,
|
|
181
182
|
* pour un chemin servi en WebSocket SEULEMENT et demandé en HTTP, un
|
|
182
183
|
* `Resolver` dont `exception` porte le `426` (en-têtes `Upgrade` posés) :
|
|
@@ -220,8 +221,9 @@ let Router = class Router extends Service {
|
|
|
220
221
|
return resolver;
|
|
221
222
|
}
|
|
222
223
|
} catch (e) {
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
routeMatchLogged ??= this.kernel?.environment !== "production";
|
|
225
|
+
if (routeMatchLogged) this.log(`Match route exception : ${route.name} ${String(e)}`, "DEBUG");
|
|
226
|
+
resolver.exception = e instanceof Error ? e : new Error(String(e));
|
|
225
227
|
continue;
|
|
226
228
|
}
|
|
227
229
|
}
|
|
@@ -239,12 +241,12 @@ let Router = class Router extends Service {
|
|
|
239
241
|
Upgrade: "websocket",
|
|
240
242
|
Connection: "Upgrade"
|
|
241
243
|
});
|
|
242
|
-
resolver.exception =
|
|
244
|
+
resolver.exception = HttpError.withoutStack("Upgrade Required: websocket", 426, context);
|
|
243
245
|
return resolver;
|
|
244
246
|
}
|
|
245
247
|
if (allowed.size > 0) {
|
|
246
248
|
const allowHeader = Array.from(allowed).join(", ");
|
|
247
|
-
const err =
|
|
249
|
+
const err = HttpError.withoutStack(`Method ${context.method} Not Allowed`, 405, context);
|
|
248
250
|
const methodErr = err;
|
|
249
251
|
methodErr.allow = allowHeader;
|
|
250
252
|
methodErr.type = "method";
|
|
@@ -349,11 +351,12 @@ Router = _Router = __decorate([injectable()], Router);
|
|
|
349
351
|
* installées du framework feraient échouer `instanceof` en silence. Une
|
|
350
352
|
* lecture de propriété.
|
|
351
353
|
*
|
|
352
|
-
* @param router - le routeur lu sur le contexte (`context.router`)
|
|
354
|
+
* @param router - le routeur lu sur le contexte (`context.router`) ou le
|
|
355
|
+
* service `router` du conteneur.
|
|
353
356
|
* @returns `true` si c'est le Router du framework.
|
|
354
357
|
*/
|
|
355
358
|
function isFrameworkRouter(router) {
|
|
356
|
-
return router
|
|
359
|
+
return typeof router === "object" && router !== null && FRAMEWORK_ROUTER in router;
|
|
357
360
|
}
|
|
358
361
|
var router_default = Router;
|
|
359
362
|
export { FRAMEWORK_ROUTER, router_default as default, isFrameworkRouter };
|