@obsidiane/meridiane 2.0.5 → 2.0.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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @obsidiane/meridiane
2
2
 
3
- CLI pour générer un bridge Angular (API Platform + Mercure) depuis une spec OpenAPI.
3
+ CLI pour générer un bridge Angular (runtime + models TypeScript) depuis une spec OpenAPI (API Platform + Mercure).
4
4
 
5
- Documentation complète (repo) : `docs/guide-bridge.md`.
5
+ Documentation complète du repo : `docs/guide-bridge.md`.
6
6
 
7
7
  ## Installation
8
8
 
@@ -10,17 +10,11 @@ Documentation complète (repo) : `docs/guide-bridge.md`.
10
10
  npm i -D @obsidiane/meridiane
11
11
  ```
12
12
 
13
- Ou en global :
14
-
15
- ```bash
16
- npm i -g @obsidiane/meridiane
17
- ```
18
-
19
13
  ## Commandes
20
14
 
21
15
  ### `meridiane generate <packageName>`
22
16
 
23
- Génère uniquement les fichiers du bridge dans le workspace courant (pas de build, pas de `npm pack`).
17
+ Génère uniquement les sources du bridge dans le workspace courant.
24
18
 
25
19
  ```bash
26
20
  npx meridiane generate @acme/backend-bridge --spec ./openapi.json
@@ -30,7 +24,7 @@ Sortie par défaut : `projects/<libName>/` (modifiable via `--out`).
30
24
 
31
25
  ### `meridiane dev [packageName]`
32
26
 
33
- Build standalone + installation locale dans `node_modules`.
27
+ Génération + build standalone + `npm pack` + installation locale dans `node_modules`.
34
28
 
35
29
  ```bash
36
30
  npx meridiane dev @acme/backend-bridge --spec http://localhost:8000/api/docs.json
@@ -42,10 +36,10 @@ Sorties :
42
36
 
43
37
  ### `meridiane build <packageName>`
44
38
 
45
- Build standalone + `npm pack` (artefact publiable).
39
+ Génération + build standalone + `npm pack` (artefact publiable).
46
40
 
47
41
  ```bash
48
- npx meridiane build @acme/backend-bridge --version 0.1.0 --spec https://staging.example/api/docs.json
42
+ npx meridiane build @acme/backend-bridge --version 1.2.3 --spec https://staging.example/api/docs.json
49
43
  ```
50
44
 
51
45
  Sorties :
@@ -54,20 +48,21 @@ Sorties :
54
48
 
55
49
  ## Options
56
50
 
57
- - `--spec <url|file>` : source OpenAPI (URL ou fichier JSON local) ; requis sauf `--no-models`.
58
- - `--formats <mimeTypes>` : répétable ou liste `,` (ordre significatif). Active le mode contract-driven.
59
- - `--include/--exclude <substr>` : filtrer des noms de schémas OpenAPI.
60
- - `--no-models` : ne génère que le runtime (pas de models).
61
- - `--version <semver>` : version écrite dans le `package.json` (`build` + `generate`).
62
- - `--out <dir>` : répertoire de sortie pour `generate` (défaut `projects/<libName>`).
63
- - `--debug` : logs détaillés.
51
+ - `--spec <url|file>` : URL OpenAPI ou fichier JSON local (requis sauf `--no-models`)
52
+ - `--formats <mimeTypes>` : répétable ou liste `,` ; défaut `application/ld+json`
53
+ - `--include <substr>` / `--exclude <substr>` : filtres de noms de schémas (répétables, support `,`)
54
+ - `--no-models` : runtime only
55
+ - `--version <semver>` : `build` et `generate` (défaut `0.0.0`)
56
+ - `--out <dir>` : uniquement `generate`
57
+ - `--debug` : logs détaillés
64
58
 
65
59
  ## Notes importantes
66
60
 
67
- - `--formats` active un mode contract-driven : seuls les schemas réellement utilisés par les endpoints/paths sont générés.
68
- - Les modèles `*.jsonMergePatch` ne sont jamais générés (`PATCH` est typé en `Partial<T>`).
69
- - Meridiane **ne publie pas** : utilisez `npm publish` côté CI.
61
+ - fallback automatique `.../api/docs.json` -> `.../api/docs.jsonopenapi` si nécessaire
62
+ - mode contract-driven : uniquement les schémas atteignables via `paths` pour les formats sélectionnés
63
+ - modèles `*jsonMergePatch*` non générés (`PATCH` typé `Partial<T>`)
64
+ - Meridiane ne publie pas : publication via `npm publish` côté CI
70
65
 
71
- ## Note (repo Meridiane)
66
+ ## Spécifique à ce repo
72
67
 
73
- Dans ce repo, `meridiane dev` peut être exécutée sans `packageName` et cible l’app sandbox (`apps/sandbox`).
68
+ Dans ce monorepo, `meridiane dev` peut être exécuté sans `packageName` et cible alors `@obsidiane/bridge-sandbox` (app `apps/sandbox`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obsidiane/meridiane",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Générateur de librairie Angular et modèles TypeScript (OpenAPI) pour un bridge Symfony/API Platform + Mercure.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,10 +23,10 @@
23
23
  "README.md"
24
24
  ],
25
25
  "engines": {
26
- "node": ">=18"
26
+ "node": ">=20.19"
27
27
  },
28
28
  "dependencies": {
29
- "commander": "^14.0.2",
29
+ "commander": "^14.0.3",
30
30
  "handlebars": "^4.7.8",
31
31
  "tslib": "^2.3.0"
32
32
  }
@@ -17,7 +17,7 @@ Le bridge est conçu pour être installé dans une application Angular. Les dép
17
17
 
18
18
  ## Compatibilité
19
19
 
20
- - Angular `@angular/*` `^20.1.0`
20
+ - Angular `@angular/*` `^20.0.0 || ^21.0.0`
21
21
  - RxJS `^7.8.0`
22
22
 
23
23
  ## Démarrage rapide
@@ -60,7 +60,7 @@ export class AppModule {}
60
60
  `provideBridge({ ... })` accepte notamment :
61
61
  - `baseUrl` (requis) ;
62
62
  - `auth` (Bearer ou interceptor custom) ;
63
- - `mercure` (hubUrl + options SSE) ;
63
+ - `mercure` (hubUrl + `topicMode` + stratégie de connexions SSE `connectionMode`/`maxUrlLength`) ;
64
64
  - `defaults` (headers/timeout/retries) ;
65
65
  - `singleFlight` (déduplication “in-flight” des requêtes HTTP identiques `GET/HEAD/OPTIONS`) ;
66
66
  - `debug` (logs runtime) ;
@@ -186,9 +186,22 @@ provideBridge({
186
186
 
187
187
  ### Concurrence
188
188
 
189
- Le bridge maintient une seule connexion SSE (une seule `EventSource`) et mutualise les topics :
190
- - regarder plusieurs fois la même ressource ne crée pas plusieurs connexions ;
191
- - un même topic est dédoublonné et géré par ref-count (unsubscribe effectif quand plus personne n’écoute).
189
+ Le bridge propose 2 stratégies SSE configurables via `provideBridge({mercure: ...})` :
190
+ - `connectionMode: 'single'` : chaque appel `watch*` ouvre sa propre connexion SSE ;
191
+ - `connectionMode: 'auto'` (défaut) : les topics sont mutualisés, puis découpés automatiquement en plusieurs connexions si l’URL Mercure dépasse `maxUrlLength` (défaut `1900`).
192
+
193
+ Vous pouvez forcer une connexion dédiée par appel avec `newConnection: true` sur `watch$`, `watchSubResource$` et `watchTypes$`.
194
+
195
+ ```ts
196
+ provideBridge({
197
+ baseUrl: 'https://api.example.com',
198
+ mercure: {
199
+ hubUrl: 'https://api.example.com/.well-known/mercure',
200
+ connectionMode: 'auto',
201
+ maxUrlLength: 1900,
202
+ },
203
+ });
204
+ ```
192
205
 
193
206
  Côté HTTP, le bridge déduplique les requêtes identiques tant qu’elles sont en cours (single-flight, activé par défaut) :
194
207
  - `GET` / `HEAD` / `OPTIONS` : deux appels identiques partagent le même appel réseau et reçoivent la même réponse ;
@@ -203,12 +216,68 @@ provideBridge({baseUrl: 'https://api.example.com', singleFlight: false});
203
216
  ```
204
217
 
205
218
  API :
206
- - `ResourceFacade<T>.watch$(iri | iri[])` / `unwatch(iri | iri[])`
207
- - `ResourceFacade<T>.watchSubResource$(iri | iri[], 'field.path')`
208
- - `BridgeFacade.watch$(iri | iri[])` / `unwatch(iri | iri[])`
219
+ - `ResourceFacade<T>.watch$(iri | iri[], {newConnection?})` / `unwatch(iri | iri[])`
220
+ - `ResourceFacade<T>.watchSubResource$(iri | iri[], 'field.path', {newConnection?})`
221
+ - `BridgeFacade.watch$(iri | iri[], filter?, {newConnection?})` / `unwatch(iri | iri[])`
222
+ - `BridgeFacade.watchTypes$(iri | iri[], resourceTypes, cfg?, {newConnection?})` (topics “multi-entités”, filtrage par type)
223
+ - `BridgeFacade.realtimeDiagnostics$()` (état courant des connexions SSE actives)
209
224
 
210
225
  Note SSR : la connexion SSE ne s’ouvre que dans le navigateur.
211
226
 
227
+ ### Topic “multi-entités” (event-bus)
228
+
229
+ Quand un même topic Mercure publie plusieurs types de payloads (sans lien entre eux),
230
+ utilisez `BridgeFacade.watchTypes$()`.
231
+ Le flux renvoie une union discriminée par `resourceType` (par défaut via `@type` en JSON-LD).
232
+
233
+ Fonctionnement (résumé) :
234
+ - le bridge s’abonne au(x) topic(s) Mercure (connexion dédiée ou mutualisée selon `connectionMode`)
235
+ - chaque event JSON recu est testé sur le champ de discrimination (`@type` par défaut)
236
+ - seuls les `resourceType` explicitement demandés sont émis
237
+ - chaque event émis est `{ resourceType, payload }`
238
+
239
+ Important (provenance des events) :
240
+ - `watchTypes$` filtre par type (`payload[discriminator]`), pas par provenance réseau du topic.
241
+ - En mode mutualisé (`connectionMode: 'auto'` et sans `newConnection`), un event d’un autre topic partagé peut être émis s’il porte un type autorisé.
242
+ - Si vous voulez ecouter strictement un seul topic, utilisez une connexion dédiée :
243
+ `watchTypes$(..., {newConnection: true})` (ou `connectionMode: 'single'` globalement).
244
+
245
+ Configuration :
246
+ - `discriminator` : champ type (défaut `@type`)
247
+ - `resourceTypes` : liste de strings à accepter (`['Conversation', 'Message']`, etc.)
248
+
249
+ ```ts
250
+ import {inject} from '@angular/core';
251
+ import {BridgeFacade} from '__PACKAGE_NAME__';
252
+ import type {Item} from '__PACKAGE_NAME__';
253
+
254
+ type Conversation = Item & {title?: string | null};
255
+ type Message = Item & {originalText?: string | null};
256
+
257
+ type Registry = {
258
+ Conversation: Conversation;
259
+ Message: Message;
260
+ };
261
+
262
+ const bridge = inject(BridgeFacade);
263
+
264
+ bridge.watchTypes$<Registry>(
265
+ '/api/events/me',
266
+ ['Conversation', 'Message'],
267
+ {discriminator: '@type'},
268
+ {newConnection: true} // isolation stricte du topic
269
+ ).subscribe((evt) => {
270
+ switch (evt.resourceType) {
271
+ case 'Conversation':
272
+ // evt.payload: Conversation
273
+ break;
274
+ case 'Message':
275
+ // evt.payload: Message
276
+ break;
277
+ }
278
+ });
279
+ ```
280
+
212
281
  ## Models TypeScript
213
282
 
214
283
  Les models générés (si présents) sont exportés au même niveau que le runtime :
@@ -2,8 +2,8 @@
2
2
  "name": "__LIB_NAME__",
3
3
  "version": "0.0.1",
4
4
  "peerDependencies": {
5
- "@angular/common": "^20.1.0",
6
- "@angular/core": "^20.1.0",
5
+ "@angular/common": "^20.0.0 || ^21.0.0",
6
+ "@angular/core": "^20.0.0 || ^21.0.0",
7
7
  "rxjs": "^7.8.0"
8
8
  },
9
9
  "dependencies": {