@obsidiane/meridiane 2.0.4 → 2.0.6
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 +45 -41
- package/package.json +3 -3
- package/templates/_lib_template/README.md +77 -8
- package/templates/_lib_template/package.json +2 -2
- package/templates/_lib_template/src/lib/bridge/sse/mercure.adapter.ts +635 -90
- package/templates/_lib_template/src/lib/bridge.types.ts +37 -0
- package/templates/_lib_template/src/lib/facades/bridge.facade.ts +77 -2
- package/templates/_lib_template/src/lib/facades/facade.interface.ts +2 -1
- package/templates/_lib_template/src/lib/facades/resource.facade.ts +8 -6
- package/templates/_lib_template/src/lib/ports/realtime.port.ts +33 -2
- package/templates/_lib_template/src/lib/provide-bridge.ts +23 -1
- package/templates/_lib_template/src/lib/tokens.ts +5 -1
- package/tools/app/bridge-workflow.js +8 -0
- package/tools/infra/dev-support.js +77 -0
- package/tools/infra/standalone-workspace.js +49 -15
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @obsidiane/meridiane
|
|
2
2
|
|
|
3
|
-
CLI pour générer
|
|
3
|
+
CLI pour générer un bridge Angular (API Platform + Mercure) depuis une spec OpenAPI.
|
|
4
4
|
|
|
5
|
-
Documentation
|
|
5
|
+
Documentation complète (repo) : `docs/guide-bridge.md`.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -16,54 +16,58 @@ Ou en global :
|
|
|
16
16
|
npm i -g @obsidiane/meridiane
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Commandes
|
|
20
|
+
|
|
21
|
+
### `meridiane generate <packageName>`
|
|
22
|
+
|
|
23
|
+
Génère uniquement les fichiers du bridge dans le workspace courant (pas de build, pas de `npm pack`).
|
|
20
24
|
|
|
21
25
|
```bash
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
npx meridiane dev <packageName> --spec <url|file> [--formats <mimeTypes>]... [--include <substr>]... [--exclude <substr>]... [--no-models] [--debug]
|
|
26
|
+
npx meridiane generate @acme/backend-bridge --spec ./openapi.json
|
|
27
|
+
```
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
npx meridiane generate <packageName> --spec <url|file> [--formats <mimeTypes>]... [--include <substr>]... [--exclude <substr>]... [--no-models] [--out <dir>] [--debug]
|
|
29
|
+
Sortie par défaut : `projects/<libName>/` (modifiable via `--out`).
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
### `meridiane dev [packageName]`
|
|
32
|
+
|
|
33
|
+
Build standalone + installation locale dans `node_modules`.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx meridiane dev @acme/backend-bridge --spec http://localhost:8000/api/docs.json
|
|
31
37
|
```
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Bonnes pratiques :
|
|
42
|
-
- utiliser `--formats application/ld+json` (ou plusieurs formats) pour un mode “contract-driven” :
|
|
43
|
-
- modèles générés uniquement s’ils sont utilisés par les endpoints (pour ces formats)
|
|
44
|
-
- groups conservés
|
|
45
|
-
- pas de modèles `*.jsonMergePatch` (PATCH = `Partial<...>`)
|
|
46
|
-
- noms normalisés (pas de suffixe `.jsonld`)
|
|
47
|
-
- utiliser `--no-models` si vous voulez uniquement le runtime (pas besoin de `--spec`)
|
|
48
|
-
- le `README.md` du projet (si présent à la racine) est ajouté à la fin du README du bridge
|
|
49
|
-
- laisser le registry à la CI (`.npmrc`, variables d’environnement, `npm publish --registry …`)
|
|
50
|
-
|
|
51
|
-
Note (repo Meridiane) :
|
|
52
|
-
- dans le repo Meridiane, `meridiane dev` peut être exécutée sans `packageName` et se préconfigure pour `apps/sandbox` (`@obsidiane/bridge-sandbox`).
|
|
53
|
-
|
|
54
|
-
## Exemple CI (générer + build + publish)
|
|
39
|
+
Sorties :
|
|
40
|
+
- `dist/<libName>/` + `dist/<libName>/*.tgz`
|
|
41
|
+
- `node_modules/<packageName>/`
|
|
42
|
+
|
|
43
|
+
### `meridiane build <packageName>`
|
|
44
|
+
|
|
45
|
+
Build standalone + `npm pack` (artefact publiable).
|
|
55
46
|
|
|
56
47
|
```bash
|
|
57
|
-
npx
|
|
58
|
-
npm publish dist/backend-bridge
|
|
48
|
+
npx meridiane build @acme/backend-bridge --version 0.1.0 --spec https://staging.example/api/docs.json
|
|
59
49
|
```
|
|
60
50
|
|
|
61
|
-
|
|
51
|
+
Sorties :
|
|
52
|
+
- `dist/<libName>/`
|
|
53
|
+
- `dist/<libName>/*.tgz`
|
|
54
|
+
|
|
55
|
+
## Options
|
|
56
|
+
|
|
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.
|
|
64
|
+
|
|
65
|
+
## Notes importantes
|
|
66
|
+
|
|
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.
|
|
62
70
|
|
|
63
|
-
##
|
|
71
|
+
## Note (repo Meridiane)
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
- `tools/domain/` : logique pure (options, naming).
|
|
67
|
-
- `tools/infra/` : I/O (spec, workspace, exec, logs) + génération.
|
|
68
|
-
- `tools/generator/` : génération des modèles TypeScript.
|
|
69
|
-
- `templates/_lib_template/` : runtime Angular du bridge.
|
|
73
|
+
Dans ce repo, `meridiane dev` peut être exécutée sans `packageName` et cible l’app sandbox (`apps/sandbox`).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obsidiane/meridiane",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
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": ">=
|
|
26
|
+
"node": ">=20.19"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"commander": "^14.0.
|
|
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.
|
|
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 +
|
|
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
|
|
190
|
-
-
|
|
191
|
-
-
|
|
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 :
|