@nodefony/framework 10.0.0-alpha.2 → 10.0.0-alpha.4

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.
@@ -1,4 +1,4 @@
1
- //#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorate.js
1
+ //#region \0@oxc-project+runtime@0.149.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.148.0/helpers/esm/decorateMetadata.js
1
+ //#region \0@oxc-project+runtime@0.149.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.148.0/helpers/esm/decorateMetadata.js";
11
- import __decorate from "./_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
10
+ import __decorateMetadata from "./_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
11
+ import __decorate from "./_virtual/_@oxc-project_runtime@0.149.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";
@@ -29,7 +29,7 @@ import { createFrameworkAdminApi } from "./nodefony/src/FrameworkAdminApi.js";
29
29
  import { createSyslogAdminApi } from "./nodefony/src/SyslogAdminApi.js";
30
30
  import Eta from "./nodefony/service/Eta.js";
31
31
  import path from "node:path";
32
- import { AUTO_STORE, EMPTY_INFRA, Kernel, Module, readStoreLocation, resolveAutoStore, services } from "nodefony";
32
+ import { AUTO_STORE, EMPTY_INFRA, Kernel, Module, durableStoreRemedy, readStoreLocation, resolveAutoStore, runNeedsExternalServices, services } from "nodefony";
33
33
  import { mergeResolvers, mergeTypeDefs } from "@graphql-tools/merge";
34
34
  import { makeExecutableSchema, mergeSchemas } from "@graphql-tools/schema";
35
35
  //#region index.ts
@@ -91,13 +91,13 @@ let Framework = class Framework extends Module {
91
91
  let name = configured;
92
92
  let reason = `store explicitement configuré ("${configured}")`;
93
93
  if (name === AUTO_STORE) {
94
- const auto = resolveAutoStore("ephemeral", this.kernel?.infra ?? EMPTY_INFRA, listIdempotencyBackends());
94
+ const auto = resolveAutoStore("ephemeral", this.kernel?.infra ?? EMPTY_INFRA, listIdempotencyBackends(), "memory", runNeedsExternalServices(this.kernel));
95
95
  name = auto.store;
96
96
  reason = auto.reason;
97
97
  this.log(`idempotency.store "auto" → "${name}" (${auto.reason})`, "INFO");
98
98
  }
99
99
  if (name === "memory") {
100
- if (this.kernel?.environment === "production") this.log("idempotency.store \"memory\" en PRODUCTION — déduplication per-pod uniquement : un rejeu routé vers un autre pod n'est pas dédupliqué (double-effet possible). Déclarer une infra partagée (NF_REDIS_URL ou NF_DATABASE_URL).", "WARNING");
100
+ if (this.kernel?.environment === "production") this.log("idempotency.store \"memory\" en PRODUCTION — déduplication per-pod uniquement : un rejeu routé vers un autre pod n'est pas dédupliqué (double-effet possible). " + durableStoreRemedy(runNeedsExternalServices(this.kernel)), "WARNING");
101
101
  this.kernel?.registerStoreResolution({
102
102
  brick: "idempotency",
103
103
  nature: "ephemeral",
@@ -30,13 +30,22 @@ var OAuth2Controller = class extends Controller {
30
30
  super("OAuth2Controller", context);
31
31
  }
32
32
  /**
33
- * Liste PUBLIQUE des fournisseurs activés (configurés ET connus du registre).
34
- * Consommé par l'UI de login pour n'afficher QUE les boutons opérationnels —
35
- * jamais de bouton mort. Aucun secret n'est exposé (uniquement les noms).
33
+ * Liste PUBLIQUE des fournisseurs à proposer à l'écran de connexion.
34
+ *
35
+ * Rend `{ name, label }` : le libellé vient du serveur, seul à connaître la
36
+ * configuration — un écran ne doit jamais avoir à deviner comment nommer un
37
+ * fournisseur, ni s'autoriser à en masquer un qu'il ne reconnaît pas. Un
38
+ * fournisseur déclaré `hidden` n'y figure pas, mais reste autorisable :
39
+ * masquer n'est pas désactiver. Aucun secret n'est exposé.
36
40
  */
37
41
  providers() {
38
42
  const svc = this.#service();
39
- return this.renderJson({ providers: svc ? svc.listProviders() : [] });
43
+ if (!svc) return this.renderJson({ providers: [] });
44
+ const providers = svc.listDisplayProviders ? svc.listDisplayProviders() : svc.listProviders().map((name) => ({
45
+ name,
46
+ label: name
47
+ }));
48
+ return this.renderJson({ providers });
40
49
  }
41
50
  /** Démarre le flux : URL d'autorisation + état anti-replay en session, 302. */
42
51
  async authorize(provider) {
@@ -44,7 +53,13 @@ var OAuth2Controller = class extends Controller {
44
53
  const flow = this.#flow();
45
54
  if (!svc || !flow) return this.renderJson({ error: "OAuth unavailable" }, 503);
46
55
  if (!svc.listProviders().includes(provider)) return this.renderJson({ error: "Unknown provider" }, 404);
47
- const auth = await svc.createAuthorization(provider);
56
+ let auth;
57
+ try {
58
+ auth = await svc.createAuthorization(provider);
59
+ } catch (error) {
60
+ this.log(`oauth2 authorize "${provider}" : ${error.message}`, "ERROR");
61
+ return this.renderJson({ error: "OAuth provider unavailable" }, 503);
62
+ }
48
63
  const session = await flow.ensureSession(this.context);
49
64
  if (!session) return this.renderJson({ error: "Session unavailable" }, 503);
50
65
  session.set(STATE_KEY, auth.state);
@@ -75,7 +90,8 @@ var OAuth2Controller = class extends Controller {
75
90
  const { identifier } = await svc.exchangeAndProvision(provider, code, typeof storedVerifier === "string" ? storedVerifier : null, returnedIss);
76
91
  await flow.establishSessionFor(this.context, identifier, "oauth");
77
92
  return this.redirect(success, 302);
78
- } catch {
93
+ } catch (error) {
94
+ this.log(`oauth2 callback "${provider}" : ${error.message.slice(0, 200)}`, "WARNING");
79
95
  return this.redirect(failure, 302);
80
96
  }
81
97
  }
@@ -1,5 +1,5 @@
1
- import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
1
+ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
2
+ import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.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.148.0/helpers/esm/decorateMetadata.js";
2
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
1
+ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
2
+ import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.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.148.0/helpers/esm/decorateMetadata.js";
5
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
4
+ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
5
+ import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
6
6
  import { Module, Service, injectable } from "nodefony";
7
7
  import { HttpError, isDomainAllowed } from "@nodefony/http";
8
8
  //#region nodefony/service/router.ts
@@ -2,7 +2,7 @@ import { CORE_PACKAGE, checkOutdated, countModuleDocs, listModuleDocs, listModul
2
2
  import { getResolvedPath, navigateSchemaNode, nodeFlags, notEditableReason, recipeFor, validateLeafValue } from "./configMutation.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { join } from "node:path";
5
- import { GitService, Syslog, applyResolvedPath, collectDevStatus, computeConfigProvenance, defaultAppConfig, extractJsonSchemaDefaults, extractMarkdownSection, getActiveLogDriver, listLogDrivers, outlineMarkdown, parseNfEnvOverrides } from "nodefony";
5
+ import { GitService, Syslog, aggregateProvenance, applyResolvedPath, collectDevStatus, computeConfigProvenance, defaultAppConfig, extractJsonSchemaDefaults, extractMarkdownSection, flattenConfigSchema, getActiveLogDriver, listLogDrivers, outlineMarkdown, parseNfEnvOverrides, readResolvedPath } from "nodefony";
6
6
  import { randomUUID } from "node:crypto";
7
7
  import { existsSync, readFileSync } from "node:fs";
8
8
  //#region nodefony/src/KernelAdminApi.ts
@@ -617,6 +617,63 @@ function createKernelAdminApi(kernel) {
617
617
  summary: "Aggregated config of all modules (effective values redacted + JSON Schema + per-field provenance) for the global config page",
618
618
  handler: async () => ({ modules: buildConfigEntries() })
619
619
  },
620
+ {
621
+ path: "config/schema",
622
+ summary: "Assignable config keys of every module (dotted path, type, default, effective value, provenance, description) — the CATALOG, where `config` gives the STATE",
623
+ handler: (request) => {
624
+ const wanted = request.query.module;
625
+ const filter = typeof wanted === "string" ? wanted.toLowerCase() : null;
626
+ const rows = [];
627
+ const entries = buildConfigEntries();
628
+ const matches = (name, key) => name.toLowerCase() === filter || key.toLowerCase() === filter;
629
+ if (filter !== null) {
630
+ const entry = entries.find((e) => matches(e.name, e.key));
631
+ if (!entry || entry.configSchema == null) {
632
+ const modules = kernel.getModules();
633
+ const nameOf = (k) => modules[k].getModuleName?.() ?? k;
634
+ const loadedKey = Object.keys(modules).find((k) => matches(nameOf(k), k));
635
+ if (loadedKey !== void 0) {
636
+ const name = nameOf(loadedKey);
637
+ return {
638
+ status: 404,
639
+ body: {
640
+ error: "Schema not published",
641
+ module: name,
642
+ loaded: true,
643
+ hint: `Le module ${name} est chargé mais ne publie pas son schéma de configuration : ajouter dans son index.ts \`override configSchema(): unknown { return z.toJSONSchema(schema); }\` (schéma Zod de nodefony/config/config.ts). Sans lui, ses clés sont indécouvrables ici.`
644
+ }
645
+ };
646
+ }
647
+ return {
648
+ status: 404,
649
+ body: {
650
+ error: "Unknown module",
651
+ module: wanted,
652
+ available: entries.map((e) => e.name)
653
+ }
654
+ };
655
+ }
656
+ }
657
+ for (const entry of entries) {
658
+ if (filter !== null && entry.name.toLowerCase() !== filter && entry.key.toLowerCase() !== filter) continue;
659
+ for (const leaf of flattenConfigSchema(entry.configSchema)) {
660
+ const path = leaf.key.split(".");
661
+ const note = SECRET_KEY.test(path[path.length - 1]) && !leaf.note.includes("secret") ? [leaf.note, "secret"].filter(Boolean).join(", ") : leaf.note;
662
+ rows.push({
663
+ key: leaf.key,
664
+ module: entry.name,
665
+ type: leaf.type,
666
+ default: leaf.default,
667
+ effective: readResolvedPath(entry.config, path),
668
+ source: aggregateProvenance(entry.provenance, leaf.key),
669
+ note,
670
+ description: leaf.description
671
+ });
672
+ }
673
+ }
674
+ return rows;
675
+ }
676
+ },
620
677
  {
621
678
  path: "stores",
622
679
  summary: "Runtime persistence stores per brick (resolved store, provenance, available backends) + declared infra",
@@ -1,5 +1,5 @@
1
1
  import { Kernel, Module } from "nodefony";
2
- import type { FrameworkConfigInput, FrameworkConfig } from "./nodefony/config/config.js";
2
+ import type { IFrameworkConfigInput, IFrameworkConfig } from "./nodefony/config/config.js";
3
3
  import { getIdempotencyStoreFactory, registerIdempotencyStore, listIdempotencyStores } from "./nodefony/src/idempotencyStoreRegistry.js";
4
4
  import Router from "./nodefony/service/router.js";
5
5
  import Route from "./nodefony/src/Route.js";
@@ -28,10 +28,10 @@ import { mergeSchemas, makeExecutableSchema } from "@graphql-tools/schema";
28
28
  import { controllers, route, controller, Get, Post, Put, Delete, Patch, Options, Head, All, Domain, BypassFirewall, IsGranted, RequireScope, Anonymous, Csp, CsrfProtect, CsrfExempt, Idempotent, CurrentUser, Scope, UseSession, HttpCode, Header, Redirect, Param, Body, Query, Headers, Cookie, Session, Req, Res, UploadedFile, UploadedFiles, routeExpectsBodyStream } from "./nodefony/decorators/routerDecorators.js";
29
29
  declare module "nodefony" {
30
30
  interface NodefonyModuleConfig {
31
- "@nodefony/framework": FrameworkConfigInput;
31
+ "@nodefony/framework": IFrameworkConfigInput;
32
32
  }
33
33
  }
34
- declare class Framework extends Module<FrameworkConfig> {
34
+ declare class Framework extends Module<IFrameworkConfig> {
35
35
  #private;
36
36
  constructor(kernel: Kernel);
37
37
  /** JSON Schema de la config framework → data plane admin (config riche Studio). */
@@ -91,6 +91,6 @@ export type { ControllerScope } from "./nodefony/src/Controller.js";
91
91
  export type { FrameworkAdminApiOptions } from "./nodefony/src/FrameworkAdminApi.js";
92
92
  export type { PlaygroundAction, PlaygroundController, PlaygroundGuards, PlaygroundParam, } from "./nodefony/src/PlaygroundAdminApi.js";
93
93
  export type { IResourceService, IResourceReadOptions, IResourcePageQuery, } from "./nodefony/src/ResourceController.js";
94
- export type { FrameworkConfig, FrameworkConfigInput, } from "./nodefony/config/config.js";
94
+ export type { IFrameworkConfig, IFrameworkConfigInput, } from "./nodefony/config/config.js";
95
95
  export { defineFrameworkConfig, frameworkConfigJsonSchema, } from "./nodefony/config/defineModuleConfig.js";
96
96
  export type { IController, IRoute, IResolver, IAdminBroker, IAdminRoute, IIdempotencyStore, IdempotencyOutcome, IdempotentResponse, } from "./nodefony/interfaces/index.js";
@@ -9,9 +9,9 @@ export declare const frameworkConfigSchema: z.ZodObject<{
9
9
  }, z.core.$strict>>;
10
10
  }, z.core.$strict>;
11
11
  /** Type de sortie (config normalisée + défauts appliqués). */
12
- export type FrameworkConfig = z.infer<typeof frameworkConfigSchema>;
12
+ export type IFrameworkConfig = z.infer<typeof frameworkConfigSchema>;
13
13
  /** Type d'entrée (toutes sections omissibles — défauts du schéma). */
14
- export type FrameworkConfigInput = z.input<typeof frameworkConfigSchema>;
14
+ export type IFrameworkConfigInput = z.input<typeof frameworkConfigSchema>;
15
15
  declare const _default: {
16
16
  router?: {
17
17
  [x: string]: unknown;
@@ -1,4 +1,4 @@
1
- import type { FrameworkConfig, FrameworkConfigInput } from "./config.js";
1
+ import type { IFrameworkConfig, IFrameworkConfigInput } from "./config.js";
2
2
  /**
3
3
  * Builder type-safe de la configuration de `@nodefony/framework` (PUR — ne
4
4
  * retape JAMAIS un défaut : source unique = `./config.ts`).
@@ -18,7 +18,7 @@ import type { FrameworkConfig, FrameworkConfigInput } from "./config.js";
18
18
  * @throws BootConfigurationError si la config est invalide ou porte une clé
19
19
  * inconnue — le boot s'interrompt, en dev comme en prod.
20
20
  */
21
- export declare function defineFrameworkConfig(config?: FrameworkConfigInput): FrameworkConfig;
21
+ export declare function defineFrameworkConfig(config?: IFrameworkConfigInput): IFrameworkConfig;
22
22
  /**
23
23
  * JSON Schema introspectable de la config framework — destiné au formulaire
24
24
  * d'édition Studio et à la documentation générée (les flags de champ posés via
@@ -3,12 +3,23 @@ import type { ContextType } from "@nodefony/http";
3
3
  import Controller from "../src/Controller.js";
4
4
  /**
5
5
  * Vue MINIMALE du service `oauth2` (`@nodefony/security`) — couplage par NOM
6
- * (framework ne dépend ni de security ni d'arctic). Contrat structurel imposé par
6
+ * (framework ne dépend pas de security). Contrat structurel imposé par
7
7
  * cast (`this.get<…>`), aucune liaison de build.
8
8
  */
9
9
  export interface IOAuth2Service {
10
10
  isEnabled(): boolean;
11
+ /** Fournisseurs OPÉRATIONNELS — la garde de `/authorize`, jamais l'affichage. */
11
12
  listProviders(): string[];
13
+ /**
14
+ * Fournisseurs à AFFICHER, libellés compris. Optionnel à dessein : le
15
+ * couplage à `@nodefony/security` se fait par NOM, sans liaison de build —
16
+ * une version du module qui ne l'expose pas encore doit dégrader, pas
17
+ * casser l'écran de connexion (repli sur {@link listProviders}).
18
+ */
19
+ listDisplayProviders?(): {
20
+ name: string;
21
+ label: string;
22
+ }[];
12
23
  getRedirects(provider?: string): {
13
24
  success: string;
14
25
  failure: string;
@@ -63,9 +74,13 @@ declare class OAuth2Controller extends Controller {
63
74
  #private;
64
75
  constructor(context: ContextType);
65
76
  /**
66
- * Liste PUBLIQUE des fournisseurs activés (configurés ET connus du registre).
67
- * Consommé par l'UI de login pour n'afficher QUE les boutons opérationnels —
68
- * jamais de bouton mort. Aucun secret n'est exposé (uniquement les noms).
77
+ * Liste PUBLIQUE des fournisseurs à proposer à l'écran de connexion.
78
+ *
79
+ * Rend `{ name, label }` : le libellé vient du serveur, seul à connaître la
80
+ * configuration — un écran ne doit jamais avoir à deviner comment nommer un
81
+ * fournisseur, ni s'autoriser à en masquer un qu'il ne reconnaît pas. Un
82
+ * fournisseur déclaré `hidden` n'y figure pas, mais reste autorisable :
83
+ * masquer n'est pas désactiver. Aucun secret n'est exposé.
69
84
  */
70
85
  providers(): Promise<import("@nodefony/http").Http2Response | import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse>;
71
86
  /** Démarre le flux : URL d'autorisation + état anti-replay en session, 302. */
@@ -38,6 +38,38 @@ export interface IConfigEntry {
38
38
  */
39
39
  overriddenBy: Record<string, string>;
40
40
  }
41
+ /**
42
+ * Une clé assignable du catalogue de configuration — ce qu'on a le DROIT
43
+ * d'écrire, par opposition à {@link IConfigEntry} qui dit ce QUI EST écrit.
44
+ *
45
+ * Les noms de champs deviennent les en-têtes de colonnes de
46
+ * `nodefony inspect schema`, et les clés du JSON qu'un agent filtre.
47
+ */
48
+ export interface ISchemaCatalogRow {
49
+ /**
50
+ * Chemin pointé de la clé (`certificates.selfSigned.hash`).
51
+ *
52
+ * EN PREMIER, et ce n'est pas cosmétique : le rendu tient la première
53
+ * colonne pour l'identité de la ligne et ne l'élague jamais, quand il retire
54
+ * les suivantes si elles valent partout pareil. `module` d'abord aurait donc
55
+ * fait répéter le nom du module sur les cent fiches d'un lot filtré.
56
+ */
57
+ key: string;
58
+ /** Nom de paquet du module qui porte la clé, tel qu'on l'écrit dans `use()`. */
59
+ module: string;
60
+ /** Type déclaré, ou les valeurs de l'énumération quand il y en a une. */
61
+ type: string;
62
+ /** Défaut du schéma — `undefined` si le schéma n'en pose aucun. */
63
+ default?: unknown;
64
+ /** Valeur résolue au boot, secrets déjà REDACTÉS par `computeConfigEntry`. */
65
+ effective: unknown;
66
+ /** D'où vient la valeur effective : `default`, `app`, `env` ou `runtime`. */
67
+ source: string;
68
+ /** Ce que les métadonnées disent de la clé (`réservé`, `secret`…), vide sinon. */
69
+ note: string;
70
+ /** La phrase du schéma (`.describe()`) — c'est elle qu'on venait chercher. */
71
+ description: string;
72
+ }
41
73
  /**
42
74
  * Paquets à essayer pour une clé de module, **dans l'ordre**, et bornés au
43
75
  * périmètre du framework.
@@ -1,5 +1,5 @@
1
1
  import type { Module, IIdempotencyStore } from "nodefony";
2
- import type { FrameworkConfig } from "../config/config.js";
2
+ import type { IFrameworkConfig } from "../config/config.js";
3
3
  /**
4
4
  * Registre de **fabriques de stores d'idempotence DISTRIBUÉS** — résout le nom
5
5
  * configuré (`framework.idempotency.store`) vers une instance d'
@@ -29,7 +29,7 @@ export interface IIdempotencyStoreFactoryContext {
29
29
  /** Module framework (porte `kernel.container` pour résoudre `redis`, etc.). */
30
30
  readonly module: Module;
31
31
  /** Config framework validée + gelée. */
32
- readonly config: FrameworkConfig;
32
+ readonly config: IFrameworkConfig;
33
33
  }
34
34
  /** Fabrique d'un store d'idempotence pour un nom donné. */
35
35
  export type IdempotencyStoreFactory = (ctx: IIdempotencyStoreFactoryContext) => IIdempotencyStore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodefony/framework",
3
- "version": "10.0.0-alpha.2",
3
+ "version": "10.0.0-alpha.4",
4
4
  "description": "Le modèle de programmation Nodefony : routeur, contrôleurs, décorateurs et vues — HTTP et WebSocket dans le même contexte",
5
5
  "author": "Christophe CAMENSULI <ccamensuli@gmail.com>",
6
6
  "main": "./dist/index.js",
@@ -43,20 +43,20 @@
43
43
  "directory": "src/packages/@nodefony/framework"
44
44
  },
45
45
  "dependencies": {
46
- "@graphql-tools/merge": "9.2.3",
47
- "@graphql-tools/schema": "10.1.0",
46
+ "@graphql-tools/merge": "9.2.4",
47
+ "@graphql-tools/schema": "10.1.1",
48
48
  "eta": "4.6.0",
49
49
  "graphql": "17.0.2",
50
50
  "reflect-metadata": "0.2.2",
51
51
  "tslib": "2.8.1"
52
52
  },
53
53
  "devDependencies": {
54
- "@nodefony/http": "^10.0.0-alpha.2",
54
+ "@nodefony/http": "^10.0.0-alpha.4",
55
55
  "@types/chai": "5.2.3",
56
56
  "@types/node": "26.4.1",
57
57
  "@vitest/coverage-v8": "5.0.0",
58
58
  "chai": "6.2.2",
59
- "nodefony": "^10.0.0-alpha.2",
59
+ "nodefony": "^10.0.0-alpha.4",
60
60
  "rimraf": "6.1.3",
61
61
  "tsx": "4.23.13",
62
62
  "vitest": "5.0.0"
@@ -65,8 +65,8 @@
65
65
  "readmeFilename": "README.md",
66
66
  "contributors": [],
67
67
  "peerDependencies": {
68
- "@nodefony/http": "^10.0.0-alpha.2",
69
- "nodefony": "^10.0.0-alpha.2",
68
+ "@nodefony/http": "^10.0.0-alpha.4",
69
+ "nodefony": "^10.0.0-alpha.4",
70
70
  "zod": "^4.4.3"
71
71
  },
72
72
  "files": [