@obsidiane/meridiane 2.0.7 → 2.0.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obsidiane/meridiane",
3
- "version": "2.0.7",
3
+ "version": "2.0.10",
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",
@@ -60,6 +60,7 @@ export class AppModule {}
60
60
  `provideBridge({ ... })` accepte notamment :
61
61
  - `baseUrl` (requis) ;
62
62
  - `auth` (Bearer ou interceptor custom) ;
63
+ - `http` (`withCredentials` HTTP par défaut) ;
63
64
  - `mercure` (hubUrl + `topicMode` + stratégie de connexions SSE `connectionMode`/`maxUrlLength`) ;
64
65
  - `defaults` (headers/timeout/retries) ;
65
66
  - `singleFlight` (déduplication “in-flight” des requêtes HTTP identiques `GET/HEAD/OPTIONS`) ;
@@ -70,17 +71,25 @@ export class AppModule {}
70
71
 
71
72
  Le bridge peut envoyer des cookies (sessions) côté HTTP et SSE.
72
73
 
73
- Le comportement `withCredentials` par défaut est déduit de `mercure.init` :
74
- - `credentials: 'include'` (défaut) → cookies envoyés
75
- - `credentials: 'omit'` → cookies non envoyés
74
+ Vous pouvez configurer explicitement le HTTP via `http.withCredentials` :
75
+ - `true` → cookies envoyés sur les requêtes HTTP
76
+ - `false` → cookies désactivés côté HTTP
76
77
 
77
- Vous pouvez aussi surcharger au cas par cas via `opts.withCredentials` sur les appels HTTP.
78
+ `mercure.init.credentials` pilote uniquement Mercure/SSE :
79
+ - `credentials: 'include'` (défaut) → cookies envoyés sur EventSource
80
+ - `credentials: 'omit'` → cookies désactivés côté SSE
81
+
82
+ Compat legacy :
83
+ - si `http.withCredentials` est absent, le bridge conserve le comportement historique et le déduit de `mercure.init.credentials`
84
+
85
+ Vous pouvez aussi surcharger appel par appel via `opts.withCredentials` sur les appels HTTP.
78
86
 
79
87
  ```ts
80
88
  import {provideBridge} from '__PACKAGE_NAME__';
81
89
 
82
90
  provideBridge({
83
91
  baseUrl: 'https://api.example.com',
92
+ http: {withCredentials: true},
84
93
  mercure: {
85
94
  hubUrl: 'https://api.example.com/.well-known/mercure',
86
95
  init: {credentials: 'omit'},
@@ -19,7 +19,7 @@ export class ApiPlatformRestRepository<T extends Item> implements ResourceReposi
19
19
  private readonly http: HttpClient,
20
20
  private readonly apiBase: string,
21
21
  private readonly resourcePath: Iri,
22
- private readonly withCredentialsDefault: boolean,
22
+ private readonly httpWithCredentialsDefault: boolean,
23
23
  ) {
24
24
  }
25
25
 
@@ -28,42 +28,42 @@ export class ApiPlatformRestRepository<T extends Item> implements ResourceReposi
28
28
  return this.http.get<Collection<T>>(this.resolveUrl(this.resourcePath), {
29
29
  params,
30
30
  headers: opts?.headers,
31
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
31
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
32
32
  });
33
33
  }
34
34
 
35
35
  get$(iri: IriRequired, opts?: HttpCallOptions): Observable<T> {
36
36
  return this.http.get<T>(this.resolveUrl(iri), {
37
37
  headers: opts?.headers,
38
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
38
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
39
39
  });
40
40
  }
41
41
 
42
42
  post$(payload: Partial<T>, opts?: HttpCallOptions): Observable<T> {
43
43
  return this.http.post<T>(this.resolveUrl(this.resourcePath), payload, {
44
44
  headers: opts?.headers,
45
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
45
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
46
46
  });
47
47
  }
48
48
 
49
49
  patch$(iri: IriRequired, changes: Partial<T>, opts?: HttpCallOptions): Observable<T> {
50
50
  return this.http.patch<T>(this.resolveUrl(iri), changes, {
51
51
  headers: opts?.headers,
52
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
52
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
53
53
  });
54
54
  }
55
55
 
56
56
  put$(iri: IriRequired, payload: Partial<T>, opts?: HttpCallOptions): Observable<T> {
57
57
  return this.http.put<T>(this.resolveUrl(iri), payload, {
58
58
  headers: opts?.headers,
59
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
59
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
60
60
  });
61
61
  }
62
62
 
63
63
  delete$(iri: IriRequired, opts?: HttpCallOptions): Observable<void> {
64
64
  return this.http.delete<void>(this.resolveUrl(iri), {
65
65
  headers: opts?.headers,
66
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
66
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
67
67
  });
68
68
  }
69
69
 
@@ -72,7 +72,7 @@ export class ApiPlatformRestRepository<T extends Item> implements ResourceReposi
72
72
  const {method, url} = req;
73
73
 
74
74
  const targetUrl = this.resolveUrl(url ?? this.resourcePath);
75
- const mergedOptions = buildHttpRequestOptions(req, {withCredentialsDefault: this.withCredentialsDefault});
75
+ const mergedOptions = buildHttpRequestOptions(req, {withCredentialsDefault: this.httpWithCredentialsDefault});
76
76
  return this.http.request<R>(method, targetUrl, mergedOptions as {observe: 'body'});
77
77
  }
78
78
 
@@ -4,7 +4,7 @@ import {auditTime, concatMap, filter, finalize, map, share, takeUntil} from 'rxj
4
4
  import {
5
5
  API_BASE_URL,
6
6
  BRIDGE_LOGGER,
7
- BRIDGE_WITH_CREDENTIALS,
7
+ BRIDGE_MERCURE_WITH_CREDENTIALS,
8
8
  MERCURE_CONNECTION_MODE,
9
9
  MERCURE_HUB_URL,
10
10
  MERCURE_MAX_URL_LENGTH,
@@ -88,7 +88,7 @@ export class MercureRealtimeAdapter implements RealtimePort, OnDestroy {
88
88
 
89
89
  constructor(
90
90
  @Inject(API_BASE_URL) private readonly apiBase: string,
91
- @Inject(BRIDGE_WITH_CREDENTIALS) private readonly withCredentialsDefault: boolean,
91
+ @Inject(BRIDGE_MERCURE_WITH_CREDENTIALS) private readonly mercureWithCredentials: boolean,
92
92
  @Inject(PLATFORM_ID) private readonly platformId: object,
93
93
  @Optional() @Inject(MERCURE_HUB_URL) private readonly hubUrl?: string,
94
94
  @Optional() @Inject(MERCURE_TOPIC_MODE) topicMode?: MercureTopicMode,
@@ -364,7 +364,7 @@ export class MercureRealtimeAdapter implements RealtimePort, OnDestroy {
364
364
  lastEventId,
365
365
  });
366
366
 
367
- const wrapper = new EventSourceWrapper(url, {withCredentials: this.withCredentialsDefault}, this.logger);
367
+ const wrapper = new EventSourceWrapper(url, {withCredentials: this.mercureWithCredentials}, this.logger);
368
368
  const stop$ = new Subject<void>();
369
369
 
370
370
  const conn: ManagedConnection = {
@@ -704,7 +704,7 @@ export class MercureRealtimeAdapter implements RealtimePort, OnDestroy {
704
704
  private computeConnectionKey(topics: ReadonlySet<string>, scope: ManagedConnectionScope, groupId?: string): string {
705
705
  const topicsSorted = Array.from(topics).sort().join('|');
706
706
  const hub = this.hubUrl ?? '';
707
- const creds = this.withCredentialsDefault ? '1' : '0';
707
+ const creds = this.mercureWithCredentials ? '1' : '0';
708
708
  const mode = this.connectionMode;
709
709
  const group = groupId ?? '';
710
710
  return `${scope}::${group}::${hub}::${creds}::${mode}::${topicsSorted}`;
@@ -5,7 +5,7 @@ import {filter, map, share} from 'rxjs/operators';
5
5
  import {toHttpParams} from '../bridge/rest/query-builder';
6
6
  import {buildHttpRequestOptions} from '../bridge/rest/http-request.options';
7
7
  import {MercureRealtimeAdapter} from '../bridge/sse/mercure.adapter';
8
- import {API_BASE_URL, BRIDGE_WITH_CREDENTIALS} from '../tokens';
8
+ import {API_BASE_URL, BRIDGE_HTTP_WITH_CREDENTIALS} from '../tokens';
9
9
  import {AnyQuery, Collection, HttpCallOptions, HttpRequestConfig, Iri, IriRequired, Item} from '../ports/resource-repository.port';
10
10
  import {SubscribeFilter} from '../ports/realtime.port';
11
11
  import {resolveUrl} from '../utils/url';
@@ -37,7 +37,7 @@ export class BridgeFacade {
37
37
  private readonly http: HttpClient,
38
38
  private readonly realtime: MercureRealtimeAdapter,
39
39
  @Inject(API_BASE_URL) private readonly apiBase: string,
40
- @Inject(BRIDGE_WITH_CREDENTIALS) private readonly withCredentialsDefault: boolean,
40
+ @Inject(BRIDGE_HTTP_WITH_CREDENTIALS) private readonly httpWithCredentialsDefault: boolean,
41
41
  ) {
42
42
  }
43
43
 
@@ -46,7 +46,7 @@ export class BridgeFacade {
46
46
  get$<R = unknown>(url: IriRequired, opts?: HttpCallOptions): Observable<R> {
47
47
  return this.http.get<R>(this.resolveUrl(url), {
48
48
  headers: opts?.headers,
49
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
49
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
50
50
  });
51
51
  }
52
52
 
@@ -59,35 +59,35 @@ export class BridgeFacade {
59
59
  return this.http.get<Collection<T>>(this.resolveUrl(url), {
60
60
  params,
61
61
  headers: opts?.headers,
62
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
62
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
63
63
  });
64
64
  }
65
65
 
66
66
  post$<R = unknown, B = unknown>(url: IriRequired, payload: B, opts?: HttpCallOptions): Observable<R> {
67
67
  return this.http.post<R>(this.resolveUrl(url), payload, {
68
68
  headers: opts?.headers,
69
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
69
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
70
70
  });
71
71
  }
72
72
 
73
73
  patch$<R = unknown, B = unknown>(url: IriRequired, changes: B, opts?: HttpCallOptions): Observable<R> {
74
74
  return this.http.patch<R>(this.resolveUrl(url), changes, {
75
75
  headers: opts?.headers,
76
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
76
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
77
77
  });
78
78
  }
79
79
 
80
80
  put$<R = unknown, B = unknown>(url: IriRequired, payload: B, opts?: HttpCallOptions): Observable<R> {
81
81
  return this.http.put<R>(this.resolveUrl(url), payload, {
82
82
  headers: opts?.headers,
83
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
83
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
84
84
  });
85
85
  }
86
86
 
87
87
  delete$(url: IriRequired, opts?: HttpCallOptions): Observable<void> {
88
88
  return this.http.delete<void>(this.resolveUrl(url), {
89
89
  headers: opts?.headers,
90
- withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
90
+ withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
91
91
  });
92
92
  }
93
93
 
@@ -95,7 +95,7 @@ export class BridgeFacade {
95
95
  const {method, url} = req;
96
96
  const targetUrl = this.resolveUrl(url);
97
97
 
98
- const mergedOptions = buildHttpRequestOptions(req, {withCredentialsDefault: this.withCredentialsDefault});
98
+ const mergedOptions = buildHttpRequestOptions(req, {withCredentialsDefault: this.httpWithCredentialsDefault});
99
99
  return this.http.request<R>(method, targetUrl, mergedOptions as {observe: 'body'});
100
100
  }
101
101
 
@@ -2,7 +2,7 @@ import {EnvironmentInjector, inject, Injectable, runInInjectionContext} from '@a
2
2
  import {HttpClient} from '@angular/common/http';
3
3
  import {RealtimePort} from '../ports/realtime.port';
4
4
  import {Item, ResourceRepository} from '../ports/resource-repository.port';
5
- import {API_BASE_URL, BRIDGE_WITH_CREDENTIALS} from '../tokens';
5
+ import {API_BASE_URL, BRIDGE_HTTP_WITH_CREDENTIALS} from '../tokens';
6
6
  import {MercureRealtimeAdapter} from '../bridge/sse/mercure.adapter';
7
7
  import {ApiPlatformRestRepository} from '../bridge/rest/api-platform.adapter';
8
8
  import {ResourceFacade} from './resource.facade';
@@ -19,7 +19,7 @@ export class FacadeFactory {
19
19
  private readonly env = inject(EnvironmentInjector);
20
20
  private readonly http = inject(HttpClient);
21
21
  private readonly baseUrl = inject(API_BASE_URL);
22
- private readonly withCredentials = inject(BRIDGE_WITH_CREDENTIALS);
22
+ private readonly httpWithCredentials = inject(BRIDGE_HTTP_WITH_CREDENTIALS);
23
23
  private readonly mercure = inject(MercureRealtimeAdapter);
24
24
 
25
25
  /**
@@ -30,7 +30,7 @@ export class FacadeFactory {
30
30
  */
31
31
  create<T extends Item>(config: FacadeConfig<T>): ResourceFacade<T> {
32
32
  const url = config.url;
33
- const repo = config.repo ?? new ApiPlatformRestRepository<T>(this.http, this.baseUrl, url, this.withCredentials);
33
+ const repo = config.repo ?? new ApiPlatformRestRepository<T>(this.http, this.baseUrl, url, this.httpWithCredentials);
34
34
  const realtime = config.realtime ?? this.mercure;
35
35
 
36
36
  return runInInjectionContext(this.env, () => new ResourceFacade<T>(repo, realtime));
@@ -3,8 +3,9 @@ import {HttpInterceptorFn, provideHttpClient, withFetch, withInterceptors} from
3
3
  import {
4
4
  API_BASE_URL,
5
5
  BRIDGE_DEFAULTS,
6
+ BRIDGE_HTTP_WITH_CREDENTIALS,
6
7
  BRIDGE_LOGGER,
7
- BRIDGE_WITH_CREDENTIALS,
8
+ BRIDGE_MERCURE_WITH_CREDENTIALS,
8
9
  MERCURE_CONNECTION_MODE,
9
10
  MERCURE_HUB_URL,
10
11
  MERCURE_MAX_URL_LENGTH,
@@ -40,11 +41,23 @@ export interface BridgeMercureOptions {
40
41
  maxUrlLength?: number;
41
42
  }
42
43
 
44
+ export interface BridgeHttpOptions {
45
+ /**
46
+ * Enables cookies / credentials on HTTP requests by default.
47
+ *
48
+ * When omitted, the bridge preserves the historical behavior and derives the
49
+ * HTTP value from `mercure.init.credentials`.
50
+ */
51
+ withCredentials?: boolean;
52
+ }
53
+
43
54
  export interface BridgeOptions {
44
55
  /** Base URL of the API (e.g. `http://localhost:8000`). */
45
56
  baseUrl: string;
46
57
  /** Auth strategy used to attach an Authorization header. */
47
58
  auth?: BridgeAuth;
59
+ /** Default HTTP transport options. */
60
+ http?: BridgeHttpOptions;
48
61
  /**
49
62
  * Use `topicMode` to control the `topic=` values sent to the hub.
50
63
  */
@@ -69,6 +82,7 @@ export function provideBridge(opts: BridgeOptions): EnvironmentProviders {
69
82
  const {
70
83
  baseUrl,
71
84
  auth,
85
+ http,
72
86
  mercure,
73
87
  defaults,
74
88
  singleFlight = true,
@@ -85,7 +99,8 @@ export function provideBridge(opts: BridgeOptions): EnvironmentProviders {
85
99
  const resolvedMercureTopicMode: MercureTopicMode = mercure?.topicMode ?? 'url';
86
100
  const resolvedMercureConnectionMode: MercureConnectionMode = mercure?.connectionMode ?? 'auto';
87
101
  const resolvedMercureMaxUrlLength = normalizeMercureMaxUrlLength(mercure?.maxUrlLength, 1900);
88
- const withCredentials = resolveWithCredentials(resolvedMercureInit);
102
+ const mercureWithCredentials = resolveWithCredentials(resolvedMercureInit);
103
+ const httpWithCredentials = http?.withCredentials ?? mercureWithCredentials;
89
104
 
90
105
  const loggerProvider: BridgeLogger = createBridgeLogger(debug);
91
106
 
@@ -104,7 +119,8 @@ export function provideBridge(opts: BridgeOptions): EnvironmentProviders {
104
119
  withInterceptors(interceptors)
105
120
  ),
106
121
  {provide: API_BASE_URL, useValue: baseUrl},
107
- {provide: BRIDGE_WITH_CREDENTIALS, useValue: withCredentials},
122
+ {provide: BRIDGE_HTTP_WITH_CREDENTIALS, useValue: httpWithCredentials},
123
+ {provide: BRIDGE_MERCURE_WITH_CREDENTIALS, useValue: mercureWithCredentials},
108
124
  ...(resolvedMercureHubUrl ? [{provide: MERCURE_HUB_URL, useValue: resolvedMercureHubUrl}] : []),
109
125
  {provide: MERCURE_TOPIC_MODE, useValue: resolvedMercureTopicMode},
110
126
  {provide: MERCURE_CONNECTION_MODE, useValue: resolvedMercureConnectionMode},
@@ -8,10 +8,16 @@ export const API_BASE_URL = new InjectionToken<string>('API_BASE_URL');
8
8
  export const MERCURE_HUB_URL = new InjectionToken<string>('MERCURE_HUB_URL');
9
9
 
10
10
  /**
11
- * Default credential policy for HTTP requests and Mercure EventSource.
12
- * When `true`, the bridge sets `withCredentials: true` on HTTP calls and uses cookies for SSE.
11
+ * Default credential policy for HTTP requests.
12
+ * When `true`, the bridge sets `withCredentials: true` on HTTP calls.
13
13
  */
14
- export const BRIDGE_WITH_CREDENTIALS = new InjectionToken<boolean>('BRIDGE_WITH_CREDENTIALS');
14
+ export const BRIDGE_HTTP_WITH_CREDENTIALS = new InjectionToken<boolean>('BRIDGE_HTTP_WITH_CREDENTIALS');
15
+
16
+ /**
17
+ * Default credential policy for Mercure EventSource.
18
+ * When `true`, the bridge opens SSE connections with cookies enabled.
19
+ */
20
+ export const BRIDGE_MERCURE_WITH_CREDENTIALS = new InjectionToken<boolean>('BRIDGE_MERCURE_WITH_CREDENTIALS');
15
21
 
16
22
  export const MERCURE_TOPIC_MODE = new InjectionToken<MercureTopicMode>('MERCURE_TOPIC_MODE');
17
23