@nodefony/framework 10.0.0-alpha.1
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/LICENSE +544 -0
- package/README.md +50 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js +9 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js +6 -0
- package/dist/index.js +211 -0
- package/dist/nodefony/config/config.js +61 -0
- package/dist/nodefony/config/defineModuleConfig.js +36 -0
- package/dist/nodefony/controller/AdminApiController.js +163 -0
- package/dist/nodefony/controller/ApiKeyController.js +151 -0
- package/dist/nodefony/controller/BenchController.js +132 -0
- package/dist/nodefony/controller/IssuerMetadataController.js +148 -0
- package/dist/nodefony/controller/OAuth2Controller.js +133 -0
- package/dist/nodefony/controller/ProtectedResourceMetadataController.js +221 -0
- package/dist/nodefony/controller/SessionAuthController.js +141 -0
- package/dist/nodefony/controller/TokenAuthController.js +113 -0
- package/dist/nodefony/controller/TotpController.js +129 -0
- package/dist/nodefony/controller/WebAuthnController.js +242 -0
- package/dist/nodefony/controller/oauthAuthority.js +74 -0
- package/dist/nodefony/decorators/routerDecorators.js +967 -0
- package/dist/nodefony/interfaces/IAdminBroker.js +1 -0
- package/dist/nodefony/interfaces/IController.js +1 -0
- package/dist/nodefony/interfaces/IIdempotencyStore.js +1 -0
- package/dist/nodefony/interfaces/IResolver.js +1 -0
- package/dist/nodefony/interfaces/IRoute.js +1 -0
- package/dist/nodefony/interfaces/index.js +1 -0
- package/dist/nodefony/service/AdminBroker.js +106 -0
- package/dist/nodefony/service/Eta.js +68 -0
- package/dist/nodefony/service/IdempotencyStore.js +136 -0
- package/dist/nodefony/service/router.js +243 -0
- package/dist/nodefony/src/Controller.js +515 -0
- package/dist/nodefony/src/FrameworkAdminApi.js +268 -0
- package/dist/nodefony/src/KernelAdminApi.js +1243 -0
- package/dist/nodefony/src/PlaygroundAdminApi.js +97 -0
- package/dist/nodefony/src/RedisIdempotencyStore.js +254 -0
- package/dist/nodefony/src/Resolver.js +416 -0
- package/dist/nodefony/src/ResourceController.js +148 -0
- package/dist/nodefony/src/Route.js +476 -0
- package/dist/nodefony/src/SyslogAdminApi.js +466 -0
- package/dist/nodefony/src/Template.js +15 -0
- package/dist/nodefony/src/configMutation.js +186 -0
- package/dist/nodefony/src/docsReader.js +929 -0
- package/dist/nodefony/src/idempotency.js +137 -0
- package/dist/nodefony/src/idempotencyGc.js +32 -0
- package/dist/nodefony/src/idempotencyStoreRegistry.js +36 -0
- package/dist/nodefony/src/scopeCatalog.js +40 -0
- package/dist/nodefony/src/syslogFilters.js +51 -0
- package/dist/types/index.d.ts +96 -0
- package/dist/types/nodefony/config/config.d.ts +41 -0
- package/dist/types/nodefony/config/defineModuleConfig.d.ts +27 -0
- package/dist/types/nodefony/controller/AdminApiController.d.ts +70 -0
- package/dist/types/nodefony/controller/ApiKeyController.d.ts +49 -0
- package/dist/types/nodefony/controller/BenchController.d.ts +45 -0
- package/dist/types/nodefony/controller/IssuerMetadataController.d.ts +86 -0
- package/dist/types/nodefony/controller/OAuth2Controller.d.ts +81 -0
- package/dist/types/nodefony/controller/ProtectedResourceMetadataController.d.ts +147 -0
- package/dist/types/nodefony/controller/SessionAuthController.d.ts +74 -0
- package/dist/types/nodefony/controller/TokenAuthController.d.ts +56 -0
- package/dist/types/nodefony/controller/TotpController.d.ts +42 -0
- package/dist/types/nodefony/controller/WebAuthnController.d.ts +123 -0
- package/dist/types/nodefony/controller/oauthAuthority.d.ts +54 -0
- package/dist/types/nodefony/decorators/routerDecorators.d.ts +632 -0
- package/dist/types/nodefony/interfaces/IAdminBroker.d.ts +79 -0
- package/dist/types/nodefony/interfaces/IController.d.ts +38 -0
- package/dist/types/nodefony/interfaces/IIdempotencyStore.d.ts +1 -0
- package/dist/types/nodefony/interfaces/IResolver.d.ts +25 -0
- package/dist/types/nodefony/interfaces/IRoute.d.ts +31 -0
- package/dist/types/nodefony/interfaces/index.d.ts +5 -0
- package/dist/types/nodefony/service/AdminBroker.d.ts +37 -0
- package/dist/types/nodefony/service/Eta.d.ts +25 -0
- package/dist/types/nodefony/service/IdempotencyStore.d.ts +45 -0
- package/dist/types/nodefony/service/router.d.ts +53 -0
- package/dist/types/nodefony/src/Controller.d.ts +193 -0
- package/dist/types/nodefony/src/FrameworkAdminApi.d.ts +35 -0
- package/dist/types/nodefony/src/KernelAdminApi.d.ts +71 -0
- package/dist/types/nodefony/src/PlaygroundAdminApi.d.ts +98 -0
- package/dist/types/nodefony/src/RedisIdempotencyStore.d.ts +104 -0
- package/dist/types/nodefony/src/Resolver.d.ts +165 -0
- package/dist/types/nodefony/src/ResourceController.d.ts +171 -0
- package/dist/types/nodefony/src/Route.d.ts +192 -0
- package/dist/types/nodefony/src/SyslogAdminApi.d.ts +38 -0
- package/dist/types/nodefony/src/Template.d.ts +8 -0
- package/dist/types/nodefony/src/configMutation.d.ts +109 -0
- package/dist/types/nodefony/src/docsReader.d.ts +369 -0
- package/dist/types/nodefony/src/idempotency.d.ts +96 -0
- package/dist/types/nodefony/src/idempotencyGc.d.ts +30 -0
- package/dist/types/nodefony/src/idempotencyStoreRegistry.d.ts +59 -0
- package/dist/types/nodefony/src/scopeCatalog.d.ts +26 -0
- package/dist/types/nodefony/src/syslogFilters.d.ts +52 -0
- package/docs/admin.md +451 -0
- package/docs/controller.md +645 -0
- package/docs/decorateurs.md +845 -0
- package/docs/idempotence.md +741 -0
- package/docs/index.md +151 -0
- package/docs/routing.md +648 -0
- package/docs/templates.md +380 -0
- package/package.json +83 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { HTTPMethod, SchemeType, ContextType } from "@nodefony/http";
|
|
2
|
+
import type { IRoute } from "../interfaces/index.js";
|
|
3
|
+
import type { RouteActionMeta } from "../decorators/routerDecorators.js";
|
|
4
|
+
import Controller from "./Controller.js";
|
|
5
|
+
export interface ControllerConstructor {
|
|
6
|
+
new (...args: any[]): Controller;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Options pour la configuration d'une route.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* |@route("myroute", {
|
|
13
|
+
* path: "/add/{name}",
|
|
14
|
+
* method: ["GET", "POST"],
|
|
15
|
+
* defaults: { name: "john" },
|
|
16
|
+
* })
|
|
17
|
+
* method(name: string) {
|
|
18
|
+
* return this.renderJson({ name });
|
|
19
|
+
* }
|
|
20
|
+
*/
|
|
21
|
+
export interface RouteOptions {
|
|
22
|
+
path?: string;
|
|
23
|
+
constructor?: Controller["constructor"];
|
|
24
|
+
classMethod?: string;
|
|
25
|
+
prefix?: string;
|
|
26
|
+
method?: HTTPMethod | HTTPMethod[];
|
|
27
|
+
className?: string;
|
|
28
|
+
host?: string | string[];
|
|
29
|
+
pattern?: string;
|
|
30
|
+
defaults?: Record<string, unknown>;
|
|
31
|
+
requirements?: RouteRequirements;
|
|
32
|
+
filePath?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Court-circuite le firewall pour cette route — `handleSecurity` retourne sans
|
|
35
|
+
* exécuter la chaîne d'authenticators. Réservé aux routes qui SONT le mécanisme
|
|
36
|
+
* d'auth (login/logout/me du flux BFF) : elles ne peuvent pas être gardées par
|
|
37
|
+
* le mécanisme qu'elles servent. Défaut `false` (Zero Trust).
|
|
38
|
+
*/
|
|
39
|
+
bypassFirewall?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface RouteRequirements {
|
|
42
|
+
domain?: string | string[];
|
|
43
|
+
scheme?: SchemeType;
|
|
44
|
+
methods?: HTTPMethod[] | HTTPMethod;
|
|
45
|
+
protocol?: string;
|
|
46
|
+
}
|
|
47
|
+
declare class Route implements IRoute {
|
|
48
|
+
#private;
|
|
49
|
+
name: string;
|
|
50
|
+
path?: string;
|
|
51
|
+
controller?: ControllerConstructor;
|
|
52
|
+
classMethod?: string;
|
|
53
|
+
prefix?: string;
|
|
54
|
+
method?: HTTPMethod;
|
|
55
|
+
schemes?: SchemeType;
|
|
56
|
+
pattern?: RegExp;
|
|
57
|
+
variables: string[];
|
|
58
|
+
/**
|
|
59
|
+
* Caractères du chemin déclaré qu'une requête ne peut PAS porter — la route
|
|
60
|
+
* est donc inatteignable. `undefined` tant que rien n'a été trouvé (le cas de
|
|
61
|
+
* toutes les routes saines : aucune allocation).
|
|
62
|
+
*
|
|
63
|
+
* @see {@link UNREACHABLE_IN_PATHNAME}
|
|
64
|
+
*/
|
|
65
|
+
unreachableChars?: string[];
|
|
66
|
+
defaults: Partial<Record<string, unknown>>;
|
|
67
|
+
requirements: Partial<RouteRequirements>;
|
|
68
|
+
hash?: string;
|
|
69
|
+
host?: string | string[];
|
|
70
|
+
/**
|
|
71
|
+
* Patterns de domaine pré-compilés (host + `requirements.domain`), RegExp
|
|
72
|
+
* ancrées/wildcard. Compilé UNE fois dans {@link compile} ; testé par requête
|
|
73
|
+
* via {@link isDomainAllowed} (zéro alloc hot-path). `undefined` = route servie
|
|
74
|
+
* sur tous les vhosts.
|
|
75
|
+
*/
|
|
76
|
+
hostRegexp?: RegExp[];
|
|
77
|
+
/**
|
|
78
|
+
* P3a — requirements pré-compilés au boot (0 alloc par match) :
|
|
79
|
+
* `methodsSet` = méthodes autorisées normalisées UPPERCASE (lookup O(1)) ;
|
|
80
|
+
* `methodsAllow` = valeur du header `Allow` du 405, jointe UNE fois ;
|
|
81
|
+
* `varRegexp` = requirements de variables de route (string → RegExp).
|
|
82
|
+
* `this.requirements` reste la config BRUTE (hash de route + introspection).
|
|
83
|
+
*/
|
|
84
|
+
methodsSet?: Set<string>;
|
|
85
|
+
methodsAllow?: string;
|
|
86
|
+
varRegexp?: Record<string, RegExp>;
|
|
87
|
+
bypassFirewall: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* P2.9 — Cache mémoïsé : l'action attend-elle le **flux brut** du body
|
|
90
|
+
* (`@Body({ stream:true })`) ? `undefined` = pas encore calculé (résolu au 1er
|
|
91
|
+
* `routeExpectsBodyStream(route)` via lecture `Reflect` des `ParamMeta`, O(1)
|
|
92
|
+
* ensuite). Lu en amont par `handleHttp` pour sauter le parse.
|
|
93
|
+
*/
|
|
94
|
+
bodyStream?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* P5 — Metadata d'action figées (`@HttpCode`/`@Header`/`@Redirect`/params/
|
|
97
|
+
* session), memo au 1er hit comme {@link bodyStream} : `undefined` = pas
|
|
98
|
+
* encore résolu (via `resolveActionMeta`, 1 lecture Reflect par route, O(1)
|
|
99
|
+
* ensuite → plus aucun `Reflect.getMetadata` par requête). Objet PARTAGÉ
|
|
100
|
+
* entre requêtes — ne jamais muter. Posé après `generateId()` → hash stable.
|
|
101
|
+
*/
|
|
102
|
+
actionMeta?: RouteActionMeta;
|
|
103
|
+
filePath?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Module propriétaire de la route — set par `Router.setController()` à
|
|
106
|
+
* `onBoot`, donc PAS disponible à la création de la route (via `@controller`)
|
|
107
|
+
* qui s'évalue à l'import. Utilisé pour `toLogLine()`.
|
|
108
|
+
*/
|
|
109
|
+
module?: {
|
|
110
|
+
name: string;
|
|
111
|
+
};
|
|
112
|
+
constructor(name: string, obj?: RouteOptions);
|
|
113
|
+
/**
|
|
114
|
+
* Normalise le pathname de la requête pour le matching : retire le(s)
|
|
115
|
+
* slash(es) final(aux) via `stripTrailingSlashes`. À calculer UNE fois
|
|
116
|
+
* par requête dans `Router.resolve`, puis à passer à chaque {@link Route.match}
|
|
117
|
+
* scannée — sinon le getter `URL.pathname` + la normalisation sont refaits
|
|
118
|
+
* pour CHAQUE route du scan O(N) (hot path, ~N routes/req).
|
|
119
|
+
*
|
|
120
|
+
* @param context - contexte HTTP/WS courant.
|
|
121
|
+
* @returns le pathname sans slash final, ou `undefined` si la requête n'a pas d'URL.
|
|
122
|
+
*/
|
|
123
|
+
static cleanPathname(context: ContextType): string | undefined;
|
|
124
|
+
match(context: ContextType, cleanPath?: string, methodOverride?: string): ((string | null)[] & Record<string, unknown>) | null | undefined;
|
|
125
|
+
/**
|
|
126
|
+
* Compile the route into a regular expression pattern.
|
|
127
|
+
* @returns The compiled regular expression pattern.
|
|
128
|
+
*/
|
|
129
|
+
compile(): RegExp;
|
|
130
|
+
/**
|
|
131
|
+
* Pré-compile les requirements (P3a) — méthodes normalisées en Set UPPERCASE
|
|
132
|
+
* + RegExp des requirements de variables. Appelé par {@link compile} et
|
|
133
|
+
* {@link addRequirement} ; {@link matchRequirements} et la boucle de
|
|
134
|
+
* variables ne font plus que des lookups (0 alloc, 0 RegExp par match).
|
|
135
|
+
* Une RegExp string invalide throw ICI (création de la route, fail-fast)
|
|
136
|
+
* au lieu du 1er match.
|
|
137
|
+
*/
|
|
138
|
+
compileRequirements(): void;
|
|
139
|
+
hydrateDefaultParameters(res: RegExpMatchArray): void;
|
|
140
|
+
toString(): string;
|
|
141
|
+
/**
|
|
142
|
+
* Formatte la route en une seule ligne lisible pour le log debug — évite le
|
|
143
|
+
* JSON multi-ligne du `toString()` qui polluait ~7 lignes par route au boot.
|
|
144
|
+
*
|
|
145
|
+
* Format : `[METHODS] path → @module/Controller.action (no auth?)`
|
|
146
|
+
*
|
|
147
|
+
* Exemple :
|
|
148
|
+
* ```
|
|
149
|
+
* [GET|HEAD] /nodefony/test/index → @test/DefaultController.index
|
|
150
|
+
* [ANY] /admin/users → @app/AdminController.users (no auth)
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* Le `@module` ne s'affiche qu'après que `Router.setController()` ait set
|
|
154
|
+
* `this.module` à `onBoot` — appel via le décorateur `@controllers` du module.
|
|
155
|
+
*/
|
|
156
|
+
toLogLine(): string;
|
|
157
|
+
toObject(): object;
|
|
158
|
+
setDefaults(arg?: Record<string, unknown>): void;
|
|
159
|
+
addDefault(key: string, value: unknown): void;
|
|
160
|
+
setPrefix(prefix?: string): void;
|
|
161
|
+
setPattern(pattern?: string): string;
|
|
162
|
+
setHostname(hostname?: string | string[]): void;
|
|
163
|
+
/**
|
|
164
|
+
* Pré-compile les patterns de domaine de la route (`host` + `requirements.domain`)
|
|
165
|
+
* en `RegExp[]` ancrées, via le matcher partagé `@nodefony/http`. Appelé par
|
|
166
|
+
* {@link compile} (kernel ↔ route = même politique). `undefined` si aucun
|
|
167
|
+
* domaine → route servie sur tous les vhosts.
|
|
168
|
+
*/
|
|
169
|
+
compileHost(): void;
|
|
170
|
+
matchHostname(context: ContextType): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Empreinte stable de la route — sert d'identité pour la comparer à
|
|
173
|
+
* elle-même (deux déclarations identiques donnent la même empreinte, deux
|
|
174
|
+
* chemins différents non). Ce n'est PAS un secret, et rien ne la vérifie :
|
|
175
|
+
* elle n'est ni persistée, ni exposée, ni transmise.
|
|
176
|
+
*
|
|
177
|
+
* SHA-256 et non MD5, bien qu'aucune propriété cryptographique ne soit
|
|
178
|
+
* requise ici : `JSON.stringify(this)` sérialise la route ENTIÈRE, donc ses
|
|
179
|
+
* `defaults` et ses `requirements` — ce que l'analyse statique lit, à juste
|
|
180
|
+
* titre, comme une donnée d'application passée dans un condensat cassé. Le
|
|
181
|
+
* coût est nul (une fois à la déclaration) et personne ne dépend de la
|
|
182
|
+
* valeur ; garder MD5 n'aurait acheté qu'une alerte à réexpliquer.
|
|
183
|
+
*
|
|
184
|
+
* @returns l'empreinte hexadécimale, également posée sur {@link hash}.
|
|
185
|
+
*/
|
|
186
|
+
generateId(): string;
|
|
187
|
+
addRequirement<K extends keyof RouteRequirements>(key: K, value: RouteRequirements[K]): RouteRequirements[K] | undefined;
|
|
188
|
+
getRequirement<K extends keyof RouteRequirements>(key: K): RouteRequirements[K] | undefined;
|
|
189
|
+
hasRequirements(): number;
|
|
190
|
+
matchRequirements(context: ContextType, methodOverride?: string): boolean;
|
|
191
|
+
}
|
|
192
|
+
export default Route;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ISyslog, IAdminApi } from "nodefony";
|
|
2
|
+
/** Options du producteur syslog — viewer de fichiers (DEV only). */
|
|
3
|
+
export interface SyslogAdminApiOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Répertoire des fichiers de log (`kernel.tmpDir`). Sans lui, l'endpoint
|
|
6
|
+
* `files` répond « désactivé » (cas prod cloud-native : logs → stdout).
|
|
7
|
+
*/
|
|
8
|
+
logDir?: string;
|
|
9
|
+
/**
|
|
10
|
+
* `true` en dev/staging uniquement. La rotation/rétention des logs n'est PAS
|
|
11
|
+
* le rôle de Nodefony (cf cloud-native, PM2 déprécié) : en prod les logs vont
|
|
12
|
+
* sur stdout/stderr → collecteur. Le viewer fichiers est un confort DEV qui
|
|
13
|
+
* remplace `tail -f` localement.
|
|
14
|
+
*/
|
|
15
|
+
enableFiles?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Environnement du kernel (`"development"` | `"production"` | …). Garde la
|
|
18
|
+
* **switch du driver de relecture** (`POST backplane/driver`) en **dev-only**
|
|
19
|
+
* (403 hors `development`) — action de contrôle runtime, jamais en prod.
|
|
20
|
+
*/
|
|
21
|
+
environment?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Producteur `IAdminApi` du **syslog** (core) — exposé sous
|
|
25
|
+
* `/nodefony/syslog/api/*`. 4ᵉ et dernier producteur de P10.3.
|
|
26
|
+
*
|
|
27
|
+
* Le syslog vit dans `@nodefony/core` et ne peut pas importer framework →
|
|
28
|
+
* framework le wrappe (comme le kernel) via `createSyslogAdminApi(syslog)`.
|
|
29
|
+
* Lecture seule du ring buffer (`ISyslog.ringStack`, FIFO O(1)).
|
|
30
|
+
*
|
|
31
|
+
* Endpoints :
|
|
32
|
+
* - `GET /nodefony/syslog/api/logs` → Pdu récents (`?severity=ERROR&limit=N`)
|
|
33
|
+
* - `GET /nodefony/syslog/api/info` → compteurs (valid/invalid/missed/buffer)
|
|
34
|
+
*
|
|
35
|
+
* @param syslog - instance Syslog du kernel (`kernel.syslog`).
|
|
36
|
+
* @param options - viewer de fichiers (DEV) : `logDir` + `enableFiles`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createSyslogAdminApi(syslog: ISyslog, options?: SyslogAdminApiOptions): IAdminApi;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Service, Module } from "nodefony";
|
|
2
|
+
declare class Template extends Service {
|
|
3
|
+
engine: unknown;
|
|
4
|
+
module: Module;
|
|
5
|
+
cache: boolean;
|
|
6
|
+
constructor(name: string, engine: unknown, module: Module, options?: Record<string, unknown>);
|
|
7
|
+
}
|
|
8
|
+
export default Template;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutation de configuration en direct (édition live admin, page Studio config).
|
|
3
|
+
*
|
|
4
|
+
* Brique PURE et testable derrière l'endpoint `PATCH /nodefony/kernel/api/config/{module}`
|
|
5
|
+
* ({@link createKernelAdminApi}). Une mutation de config runtime par un admin est une
|
|
6
|
+
* **surface sensible** : ces helpers fail-closed décident *si* un champ est éditable à
|
|
7
|
+
* chaud, *valident* la valeur contre le JSON Schema du module (même esprit que les
|
|
8
|
+
* overrides `NF__*` validés par Zod), et produisent la **recette** d'override pour les
|
|
9
|
+
* champs non mutables (12-factor : la majorité se change au redémarrage, jamais en RAM).
|
|
10
|
+
*
|
|
11
|
+
* Périmètre assumé (MVP) : on édite une **feuille scalaire** (`string`/`number`/
|
|
12
|
+
* `boolean`/`null`/enum/union de scalaires). Les objets/arrays imbriqués ne sont pas
|
|
13
|
+
* éditables en place (recette uniquement) — un `runtimeMutable` se pose sur un scalaire.
|
|
14
|
+
* Les `.refine()` Zod custom ne sont PAS dans le JSON Schema : la validation feuille
|
|
15
|
+
* couvre type/enum/bornes/longueur/pattern, le module reste juge au prochain boot.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Vue minimale d'un nœud JSON Schema (produit par `z.toJSONSchema`), incluant les
|
|
19
|
+
* **flags Nodefony** recopiés au top-level par le `.meta()` natif zod des modules.
|
|
20
|
+
*/
|
|
21
|
+
export interface IJsonSchemaNode {
|
|
22
|
+
type?: string | string[];
|
|
23
|
+
enum?: readonly unknown[];
|
|
24
|
+
anyOf?: readonly unknown[];
|
|
25
|
+
oneOf?: readonly unknown[];
|
|
26
|
+
properties?: Record<string, unknown>;
|
|
27
|
+
minimum?: number;
|
|
28
|
+
maximum?: number;
|
|
29
|
+
exclusiveMinimum?: number;
|
|
30
|
+
exclusiveMaximum?: number;
|
|
31
|
+
minLength?: number;
|
|
32
|
+
maxLength?: number;
|
|
33
|
+
pattern?: string;
|
|
34
|
+
default?: unknown;
|
|
35
|
+
/** Éditable à chaud (relu par requête) — seul cas autorisé en édition live. */
|
|
36
|
+
runtimeMutable?: boolean;
|
|
37
|
+
/** Réservé à une feature future — jamais éditable. */
|
|
38
|
+
reserved?: boolean;
|
|
39
|
+
/** Dérivé par le kernel au boot — jamais éditable. */
|
|
40
|
+
kernelDerived?: boolean;
|
|
41
|
+
/** Donnée sensible — jamais éditée via l'API (recette `*_FILE`). */
|
|
42
|
+
secret?: boolean;
|
|
43
|
+
[k: string]: unknown;
|
|
44
|
+
}
|
|
45
|
+
/** Drapeaux d'éditabilité d'un champ, dérivés de son nœud JSON Schema. */
|
|
46
|
+
export interface IFieldFlags {
|
|
47
|
+
runtimeMutable: boolean;
|
|
48
|
+
reserved: boolean;
|
|
49
|
+
kernelDerived: boolean;
|
|
50
|
+
secret: boolean;
|
|
51
|
+
}
|
|
52
|
+
/** Résultat d'une validation de feuille : succès, ou échec avec message humain. */
|
|
53
|
+
export type LeafValidation = {
|
|
54
|
+
ok: true;
|
|
55
|
+
} | {
|
|
56
|
+
ok: false;
|
|
57
|
+
message: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Descend dans un JSON Schema le long d'un chemin pointé (`upload.maxFileSize`)
|
|
61
|
+
* et renvoie le nœud feuille, ou `null` si un segment ne résout pas.
|
|
62
|
+
*
|
|
63
|
+
* @param schema - JSON Schema racine du module (`mod.configSchema()`).
|
|
64
|
+
* @param segments - segments du chemin (casse réelle ou insensible).
|
|
65
|
+
* @returns le nœud feuille, ou `null` si le chemin est inconnu.
|
|
66
|
+
*/
|
|
67
|
+
export declare function navigateSchemaNode(schema: unknown, segments: string[]): IJsonSchemaNode | null;
|
|
68
|
+
/** Extrait les flags Nodefony d'un nœud (défaut `false` partout). */
|
|
69
|
+
export declare function nodeFlags(node: IJsonSchemaNode): IFieldFlags;
|
|
70
|
+
/**
|
|
71
|
+
* Valide une valeur scalaire contre un nœud JSON Schema feuille (type(s), `enum`,
|
|
72
|
+
* `anyOf`/`oneOf`, bornes numériques, longueur/pattern de chaîne). Fail-closed :
|
|
73
|
+
* un nœud objet/array non scalaire est refusé (édition feuille uniquement).
|
|
74
|
+
*
|
|
75
|
+
* @param node - nœud JSON Schema cible.
|
|
76
|
+
* @param value - valeur candidate (déjà typée — provient d'un body JSON).
|
|
77
|
+
* @returns succès, ou échec avec message explicatif.
|
|
78
|
+
*/
|
|
79
|
+
export declare function validateLeafValue(node: IJsonSchemaNode, value: unknown): LeafValidation;
|
|
80
|
+
/** Raison machine du refus d'édition live (`null` = éditable). */
|
|
81
|
+
export type NotEditableReason = "secret" | "reserved" | "kernel_derived" | "boot_only";
|
|
82
|
+
/**
|
|
83
|
+
* Décide si un champ est éditable à chaud. Ordre de refus : secret > réservé >
|
|
84
|
+
* dérivé kernel > non-`runtimeMutable` (boot). `null` = éditable.
|
|
85
|
+
*
|
|
86
|
+
* @param flags - flags du nœud ({@link nodeFlags}).
|
|
87
|
+
* @returns la raison du refus, ou `null` si éditable live.
|
|
88
|
+
*/
|
|
89
|
+
export declare function notEditableReason(flags: IFieldFlags): NotEditableReason | null;
|
|
90
|
+
/**
|
|
91
|
+
* Construit la **recette** d'override à appliquer dans le déploiement pour un champ
|
|
92
|
+
* non mutable à chaud (12-factor). Un secret passe par la variante `*_FILE` (jamais
|
|
93
|
+
* la valeur en clair dans l'environnement).
|
|
94
|
+
*
|
|
95
|
+
* @param seg - segment d'adressage du module (`http`, `security`, `app`…).
|
|
96
|
+
* @param segments - chemin pointé du champ.
|
|
97
|
+
* @param isSecret - le champ porte-t-il le flag secret ?
|
|
98
|
+
* @returns la ligne d'override prête à copier.
|
|
99
|
+
*/
|
|
100
|
+
export declare function recipeFor(seg: string, segments: string[], isSecret: boolean): string;
|
|
101
|
+
/**
|
|
102
|
+
* Lit la valeur courante d'une config à un chemin pointé (insensible à la casse) —
|
|
103
|
+
* sert à journaliser l'ancienne valeur (`before`) avant mutation.
|
|
104
|
+
*
|
|
105
|
+
* @param obj - objet de config (`mod.options`).
|
|
106
|
+
* @param segments - chemin pointé.
|
|
107
|
+
* @returns la valeur, ou `undefined` si le chemin ne résout pas.
|
|
108
|
+
*/
|
|
109
|
+
export declare function getResolvedPath(obj: Record<string, unknown>, segments: string[]): unknown;
|