@nodefony/frontend 10.0.0-alpha.3 → 10.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@
5
5
  * NAVIGATEUR utilise peut être toute autre chose — un forwarder TLS (Codespaces,
6
6
  * Gitpod), une passerelle de conteneur (`host.docker.internal`), un port remappé.
7
7
  * Ce module dissocie les deux : il produit l'origine publique (assets, `base`
8
- * Vite, WebSocket HMR) à partir d'un TEMPLATE (`{port}` substitué au port réel
8
+ * Vite) à partir d'un TEMPLATE (`{port}` substitué au port réel
9
9
  * du spawn) — explicite (`frontend.publicOrigin`) ou détecté depuis
10
10
  * l'environnement de la plateforme.
11
11
  *
@@ -14,7 +14,7 @@
14
14
  *
15
15
  * Formats VÉRIFIÉS (docs officielles + source Vite 8) :
16
16
  * - Codespaces : `https://${CODESPACE_NAME}-${port}.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}`
17
- * (TLS terminé par le forwarder WS HMR en `wss` sur 443).
17
+ * (TLS terminé par le forwarder ; le socket HMR s'en déduit côté client).
18
18
  * - Gitpod classic : `https://${port}-<hôte de GITPOD_WORKSPACE_URL>`.
19
19
  * - Vite `server.allowedHosts` : IP et `localhost`/`*.localhost` TOUJOURS
20
20
  * acceptés ; un préfixe `.` = le domaine ET tous ses sous-domaines.
@@ -27,15 +27,6 @@ export declare const PORT_PLACEHOLDER = "{port}";
27
27
  export interface IResolvedPublicOrigin {
28
28
  /** Origine que le navigateur utilise — verbatim dans les `<script>` et le `base` Vite. */
29
29
  readonly origin: string;
30
- /**
31
- * Config `server.hmr` cliente : le WS HMR doit suivre le MÊME chemin que les
32
- * assets. Port implicite → 443/80 selon le scheme (cas forwarder TLS).
33
- */
34
- readonly hmr: {
35
- readonly host: string;
36
- readonly clientPort: number;
37
- readonly protocol: "ws" | "wss";
38
- };
39
30
  }
40
31
  /** Environnement de dev déporté détecté depuis les variables de la plateforme. */
41
32
  export interface IRemoteDevDetection {
@@ -51,6 +42,31 @@ export interface IRemoteDevDetection {
51
42
  * sous Windows, une CONNEXION vers `0.0.0.0` échoue aussi (health check).
52
43
  */
53
44
  export declare function browserReachableHost(listenHost: string): string;
45
+ /**
46
+ * Le client est-il arrivé par la BOUCLE LOCALE de la machine qui sert ?
47
+ *
48
+ * Ce n'est pas une commodité : c'est un fait vérifiable qui prime sur toute
49
+ * déduction faite au démarrage. Une plateforme de dev déporté se détecte par
50
+ * une variable d'environnement — donc UNE FOIS, au lancement du serveur — alors
51
+ * qu'un même serveur reçoit simultanément des clients arrivés par des chemins
52
+ * différents : l'origine publique de la plateforme, et un tunnel local (VS Code
53
+ * Desktop redirige les ports d'un Codespace sur `localhost`, c'est sa
54
+ * configuration par défaut).
55
+ *
56
+ * Servir l'origine publique à un client venu du tunnel a un coût réel : cette
57
+ * origine exige la session de la plateforme. Un navigateur humain la porte et
58
+ * ne voit rien ; une intégration continue, une sonde ou un agent ne l'ont pas,
59
+ * se font refuser, et obtiennent une page blanche que rien n'explique.
60
+ *
61
+ * La liste est FERMÉE, et c'est ce qui la rend sûre : le `Host` est une donnée
62
+ * cliente, et seuls ces noms désignent la machine locale de façon non
63
+ * ambiguë. `0.0.0.0`/`::` en sont exclus — ce sont des adresses d'écoute, pas
64
+ * des destinations (cf `browserReachableHost`).
65
+ *
66
+ * @param hostname - nom d'hôte NU, sans port (`[::1]` pour l'IPv6 canonique).
67
+ * @returns `true` si ce nom désigne la boucle locale.
68
+ */
69
+ export declare function isLoopbackHostname(hostname: string): boolean;
54
70
  /** Un template d'origine est-il syntaxiquement valide ? (autorité unique) */
55
71
  export declare function isValidOriginTemplate(template: string): boolean;
56
72
  /**
@@ -76,9 +92,10 @@ export declare function originWithHostname(origin: string, hostname: string): st
76
92
  /**
77
93
  * Résout un template d'origine contre le port RÉEL du spawn. Pure.
78
94
  *
79
- * @returns origine + config HMR cliente, ou `null` si le template est invalide
95
+ * @returns l'origine publique, ou `null` si le template est invalide
80
96
  * (l'appelant retombe sur la dérivation locale en l'ANNONÇANT — jamais en
81
- * silence).
97
+ * silence). Aucune config HMR n'est rendue : le socket suit l'origine par
98
+ * laquelle le client Vite a été chargé, il n'a rien à recevoir.
82
99
  */
83
100
  export declare function resolveOriginTemplate(template: string, port: number): IResolvedPublicOrigin | null;
84
101
  /**
package/docs/index.md CHANGED
@@ -370,7 +370,7 @@ JSON Schema pour l'écran de configuration de Studio.
370
370
  > **`backendPort` n'est pas forcément le port écouté.** Avec une politique de port automatique, un
371
371
  > 5151 occupé fait glisser l'écoute sur 5153. Un proxy figé enverrait alors les appels de ton
372
372
  > interface vers le serveur d'une **autre** application. Le module lit donc le port réel sur le
373
- > serveur lui-même (`FrontendService.resolveBackendPort()`, `FrontendService.ts:455`) et journalise
373
+ > serveur lui-même (`FrontendService.resolveBackendPort()`, `FrontendService.ts:471`) et journalise
374
374
  > l'écart.
375
375
 
376
376
  ### Le build de production
@@ -490,8 +490,8 @@ intermittent, apparaissant seulement quand le navigateur est plus rapide que le
490
490
  | ----------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------- |
491
491
  | `FrontendService` | l'orchestrateur : entrées, familles, cycle de vie, rendu | `FrontendService.ts:70` |
492
492
  | `ViteProcessSupervisor` | lance, surveille, relance et arrête **un** processus Vite | `ViteProcessSupervisor.ts:215` |
493
- | `ViteConfigGenerator` | écrit la configuration Vite (fonction pure, testée seule) | `ViteConfigGenerator.toMjs()` (`ViteConfigGenerator.ts:80`) |
494
- | `ViteBuilder` | construit l'objet de configuration Vite pour le build en processus | `ViteBuilder.buildViteConfig()` (`ViteBuilder.ts:41`) |
493
+ | `ViteConfigGenerator` | écrit la configuration Vite (fonction pure, testée seule) | `ViteConfigGenerator.toMjs()` (`ViteConfigGenerator.ts:69`) |
494
+ | `ViteBuilder` | construit l'objet de configuration Vite pour le build en processus | `ViteBuilder.buildViteConfig()` (`ViteBuilder.ts:95`) |
495
495
  | `TemplateHelper` | produit les balises (dev) ou lit le manifeste (prod) | `TemplateHelper.ts:36` |
496
496
  | `isolationGroups` | à quelle famille appartient un preset, et sur quel bloc de ports | `isolationGroup()` (`isolationGroups.ts:39`) |
497
497
  | `FrontendAdminApi` | la vue sûre de l'état, pour Studio | `buildFrontendStatus()` (`FrontendAdminApi.ts:139`) |
@@ -597,7 +597,7 @@ et dans les types du paquet — jamais recopiées ici, où elles se périmeraien
597
597
 
598
598
  ### `registerEntry` — la déclaration d'une interface
599
599
 
600
- `FrontendService.registerEntry()` (`FrontendService.ts:221`) est appelée par le module consommateur,
600
+ `FrontendService.registerEntry()` (`FrontendService.ts:243`) est appelée par le module consommateur,
601
601
  dans son `onKernelBoot()`. Elle résout les chemins relatifs, calcule le préfixe public et renvoie
602
602
  l'entrée résolue (`IResolvedFrontendEntry`, `IFrontBuilder.ts:40`).
603
603
 
@@ -637,7 +637,7 @@ const tags = frontend.renderTags("shop", context.cspNonce);
637
637
  const html = frontend.renderDocument("shop", context.cspNonce);
638
638
  ```
639
639
 
640
- `renderDocument` (`FrontendService.ts:876`) lit l'`index.html` **de ton module**, retire le `<script>`
640
+ `renderDocument` (`FrontendService.ts:904`) lit l'`index.html` **de ton module**, retire le `<script>`
641
641
  d'entrée source, injecte les balises au marqueur (ou avant `</head>`), et renvoie le document.
642
642
  Pas d'`index.html` ? Une coquille minimale est générée. En production, l'index est mis en cache ; en
643
643
  développement il est relu à chaque appel, pour que tes modifications de la coquille apparaissent.
@@ -650,7 +650,7 @@ Ce qui est injecté en développement (`TemplateHelper.renderDevTags()`, `Templa
650
650
  3. ton entrée, servie par son **chemin absolu** (`/@fs/…`) plutôt que relatif — c'est ce qui permet à
651
651
  deux modules d'avoir chacun leur `frontend/src/main.tsx` sans collision ;
652
652
  4. un pont qui relaie les événements de rechargement vers la barre de débogage, **sans ouvrir de
653
- seconde connexion** (`hmrBridgeTag()`, `TemplateHelper.ts:226`) ;
653
+ seconde connexion** (`hmrBridgeTag()`, `TemplateHelper.ts:267`) ;
654
654
  5. la barre de débogage elle-même, résolue une fois et servie via Vite (`debugBarTag()`,
655
655
  `TemplateHelper.ts:252`).
656
656
 
@@ -660,7 +660,7 @@ l'état. Une page dégradée reste une page.
660
660
  ### Les helpers de vue
661
661
 
662
662
  Si tu rends une vue Eta plutôt qu'une chaîne, trois helpers sont déjà dans tes variables locales
663
- (`Controller.withFrontendLocals()`, `Controller.ts:345`) — inspirés des helpers d'assets de Symfony :
663
+ (`Controller.withFrontendLocals()`, `Controller.ts:448`) — inspirés des helpers d'assets de Symfony :
664
664
 
665
665
  ```html
666
666
  <%~ frontendDocument("shop") %>
@@ -699,7 +699,7 @@ Quatre comportements à connaître :
699
699
  les autres résultats.
700
700
  - **Le résultat est un bilan** : construits / ignorés / en échec, journalisé et renvoyé.
701
701
  - **Un démarrage en production sans build se répare — ou se dénonce.** `setupProd()`
702
- (`FrontendService.ts:655`) vérifie le manifeste de chaque entrée AVANT de monter les statics.
702
+ (`FrontendService.ts:683`) vérifie le manifeste de chaque entrée AVANT de monter les statics.
703
703
  Manifeste absent et Vite installé (poste de développement, devDependencies présentes) : le build
704
704
  tourne **une fois au démarrage**, annoncé en WARNING — fini l'écran blanc après un
705
705
  `nodefony production --detach` lancé trop tôt. Manifeste absent et Vite introuvable (image de
@@ -735,7 +735,7 @@ use("@nodefony/frontend", { assetBaseUrl: "https://cdn.example.com" });
735
735
  // → <script src="https://cdn.example.com/_assets/shop/main-a1b2c3.js">
736
736
  ```
737
737
 
738
- En production, `setupProd()` (`FrontendService.ts:655`) monte chaque dossier de sortie sur son
738
+ En production, `setupProd()` (`FrontendService.ts:683`) monte chaque dossier de sortie sur son
739
739
  `publicPath` via le serveur statique — résolu **par nom**, jamais par import, pour ne pas créer de
740
740
  cycle. Si ce service est absent (proxy frontal, CDN devant), un avertissement le dit et rien n'est
741
741
  monté : c'est un déploiement valide, pas une panne.
@@ -765,7 +765,7 @@ Deux points d'attention avant de se lancer :
765
765
 
766
766
  - le preset alimente le build en processus (`ViteBuilder`), mais la configuration du **serveur de
767
767
  développement** est écrite par le générateur, qui possède sa propre correspondance type → greffon
768
- (`ViteConfigGenerator.toMjs()`, `ViteConfigGenerator.ts:80`). Un nouveau type doit être ajouté aux
768
+ (`ViteConfigGenerator.toMjs()`, `ViteConfigGenerator.ts:69`). Un nouveau type doit être ajouté aux
769
769
  **deux** endroits, sinon il lève `FrontendPresetUnknownError` (`FrontendError.ts:19`) ;
770
770
  - si le nouveau framework transforme des fichiers qui ne lui appartiennent pas, il lui faut sa propre
771
771
  famille d'isolation — c'est la leçon d'Angular.
@@ -782,10 +782,10 @@ origine. Or en développement, tes modules viennent du port 5173 alors que ta pa
782
782
 
783
783
  La solution retenue n'est pas d'affaiblir la politique, mais de la **composer**. Une fois Vite prêt
784
784
  (donc ses ports réellement connus), le service déclare ses origines au pare-feu
785
- (`#registerCsp()`, `FrontendService.ts:948`), qui émet **un seul** en-tête, origines fusionnées et
785
+ (`#registerCsp()`, `FrontendService.ts:990`), qui émet **un seul** en-tête, origines fusionnées et
786
786
  nonce par requête. À l'arrêt, les origines sont retirées et la politique redevient stricte.
787
787
 
788
- Le fragment déclaré (`#viteCspFragment()`, `FrontendService.ts:909`) mérite deux explications, parce
788
+ Le fragment déclaré (`#viteCspFragment()`, `FrontendService.ts:1012`) mérite deux explications, parce
789
789
  qu'elles piègent tout le monde :
790
790
 
791
791
  - **`'self'` est répété dans chaque directive.** `connect-src`, `style-src`, `img-src` et `font-src`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodefony/frontend",
3
- "version": "10.0.0-alpha.3",
3
+ "version": "10.0.0-alpha.5",
4
4
  "description": "Construction et rechargement à chaud des frontends de chaque module Nodefony — Vite intégré, multi-framework (React, Vue, Angular, Svelte)",
5
5
  "author": "Christophe CAMENSULI <ccamensuli@gmail.com>",
6
6
  "type": "module",
@@ -36,28 +36,28 @@
36
36
  "esm"
37
37
  ],
38
38
  "peerDependencies": {
39
- "@nodefony/framework": "^10.0.0-alpha.3",
40
- "@nodefony/http": "^10.0.0-alpha.3",
41
- "nodefony": "^10.0.0-alpha.3",
42
- "zod": "^4.4.3"
39
+ "@nodefony/framework": "^10.0.0-alpha.5",
40
+ "@nodefony/http": "^10.0.0-alpha.5",
41
+ "nodefony": "^10.0.0-alpha.5",
42
+ "zod": "^4.6.1"
43
43
  },
44
44
  "devDependencies": {
45
- "@nodefony/framework": "^10.0.0-alpha.3",
46
- "@nodefony/http": "^10.0.0-alpha.3",
45
+ "@nodefony/framework": "^10.0.0-alpha.5",
46
+ "@nodefony/http": "^10.0.0-alpha.5",
47
47
  "@types/chai": "5.2.3",
48
- "@types/node": "26.4.1",
48
+ "@types/node": "26.5.1",
49
49
  "@vitest/coverage-v8": "5.0.0",
50
50
  "chai": "6.2.2",
51
- "nodefony": "^10.0.0-alpha.3",
51
+ "nodefony": "^10.0.0-alpha.5",
52
52
  "rimraf": "6.1.3",
53
- "vite": "8.2.2",
53
+ "vite": "8.3.0",
54
54
  "vitest": "5.0.0"
55
55
  },
56
56
  "private": false,
57
57
  "engines": {
58
58
  "node": ">=24.0.0"
59
59
  },
60
- "license": "CECILL-B",
60
+ "license": "Apache-2.0",
61
61
  "dependencies": {
62
62
  "tslib": "2.8.1"
63
63
  },