@obsidiane/auth-client-js 1.0.3 → 1.0.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.
Files changed (142) hide show
  1. package/{index.ts → dist/index.d.ts} +0 -1
  2. package/dist/index.js.map +1 -0
  3. package/dist/src/lib/bridge/rest/api-platform.adapter.d.ts +18 -0
  4. package/dist/src/lib/bridge/rest/api-platform.adapter.js +67 -0
  5. package/dist/src/lib/bridge/rest/api-platform.adapter.js.map +1 -0
  6. package/dist/src/lib/bridge/rest/http-request.options.d.ts +4 -0
  7. package/dist/src/lib/bridge/rest/http-request.options.js +17 -0
  8. package/dist/src/lib/bridge/rest/http-request.options.js.map +1 -0
  9. package/dist/src/lib/bridge/rest/query-builder.d.ts +3 -0
  10. package/dist/src/lib/bridge/rest/query-builder.js +41 -0
  11. package/dist/src/lib/bridge/rest/query-builder.js.map +1 -0
  12. package/dist/src/lib/bridge/sse/eventsource-wrapper.d.ts +17 -0
  13. package/dist/src/lib/bridge/sse/eventsource-wrapper.js +57 -0
  14. package/dist/src/lib/bridge/sse/eventsource-wrapper.js.map +1 -0
  15. package/dist/src/lib/bridge/sse/mercure-topic.mapper.d.ts +19 -0
  16. package/dist/src/lib/bridge/sse/mercure-topic.mapper.js +45 -0
  17. package/dist/src/lib/bridge/sse/mercure-topic.mapper.js.map +1 -0
  18. package/dist/src/lib/bridge/sse/mercure-url.builder.d.ts +7 -0
  19. package/dist/src/lib/bridge/sse/mercure-url.builder.js +18 -0
  20. package/dist/src/lib/bridge/sse/mercure-url.builder.js.map +1 -0
  21. package/dist/src/lib/bridge/sse/mercure.adapter.d.ts +37 -0
  22. package/dist/src/lib/bridge/sse/mercure.adapter.js +242 -0
  23. package/dist/src/lib/bridge/sse/mercure.adapter.js.map +1 -0
  24. package/dist/src/lib/bridge/sse/ref-count-topic.registry.d.ts +17 -0
  25. package/dist/src/lib/bridge/sse/ref-count-topic.registry.js +42 -0
  26. package/dist/src/lib/bridge/sse/ref-count-topic.registry.js.map +1 -0
  27. package/{src/lib/bridge.types.ts → dist/src/lib/bridge.types.d.ts} +8 -14
  28. package/dist/src/lib/bridge.types.js +8 -0
  29. package/dist/src/lib/bridge.types.js.map +1 -0
  30. package/dist/src/lib/facades/bridge.facade.d.ts +27 -0
  31. package/dist/src/lib/facades/bridge.facade.js +100 -0
  32. package/dist/src/lib/facades/bridge.facade.js.map +1 -0
  33. package/dist/src/lib/facades/facade.factory.d.ts +22 -0
  34. package/dist/src/lib/facades/facade.factory.js +36 -0
  35. package/dist/src/lib/facades/facade.factory.js.map +1 -0
  36. package/dist/src/lib/facades/facade.interface.d.ts +13 -0
  37. package/dist/src/lib/facades/facade.interface.js +2 -0
  38. package/dist/src/lib/facades/facade.interface.js.map +1 -0
  39. package/dist/src/lib/facades/resource.facade.d.ts +30 -0
  40. package/dist/src/lib/facades/resource.facade.js +61 -0
  41. package/dist/src/lib/facades/resource.facade.js.map +1 -0
  42. package/dist/src/lib/interceptors/bridge-debug.interceptor.d.ts +6 -0
  43. package/dist/src/lib/interceptors/bridge-debug.interceptor.js +27 -0
  44. package/dist/src/lib/interceptors/bridge-debug.interceptor.js.map +1 -0
  45. package/dist/src/lib/interceptors/bridge-defaults.interceptor.d.ts +5 -0
  46. package/dist/src/lib/interceptors/bridge-defaults.interceptor.js +43 -0
  47. package/dist/src/lib/interceptors/bridge-defaults.interceptor.js.map +1 -0
  48. package/dist/src/lib/interceptors/content-type.interceptor.d.ts +9 -0
  49. package/dist/src/lib/interceptors/content-type.interceptor.js +34 -0
  50. package/dist/src/lib/interceptors/content-type.interceptor.js.map +1 -0
  51. package/dist/src/lib/interceptors/singleflight.interceptor.d.ts +3 -0
  52. package/dist/src/lib/interceptors/singleflight.interceptor.js +42 -0
  53. package/dist/src/lib/interceptors/singleflight.interceptor.js.map +1 -0
  54. package/dist/src/lib/ports/realtime.port.d.ts +28 -0
  55. package/dist/src/lib/ports/realtime.port.js +2 -0
  56. package/dist/src/lib/ports/realtime.port.js.map +1 -0
  57. package/dist/src/lib/ports/resource-repository.port.d.ts +64 -0
  58. package/dist/src/lib/ports/resource-repository.port.js +2 -0
  59. package/dist/src/lib/ports/resource-repository.port.js.map +1 -0
  60. package/dist/src/lib/provide-bridge.d.ts +40 -0
  61. package/dist/src/lib/provide-bridge.js +81 -0
  62. package/dist/src/lib/provide-bridge.js.map +1 -0
  63. package/dist/src/lib/tokens.d.ts +14 -0
  64. package/dist/src/lib/tokens.js +14 -0
  65. package/dist/src/lib/tokens.js.map +1 -0
  66. package/dist/src/lib/utils/url.d.ts +6 -0
  67. package/dist/src/lib/utils/url.js +17 -0
  68. package/dist/src/lib/utils/url.js.map +1 -0
  69. package/{src/models/Auth.ts → dist/src/models/Auth.d.ts} +1 -2
  70. package/dist/src/models/Auth.js +2 -0
  71. package/dist/src/models/Auth.js.map +1 -0
  72. package/{src/models/AuthInviteCompleteInputInviteComplete.ts → dist/src/models/AuthInviteCompleteInputInviteComplete.d.ts} +3 -4
  73. package/dist/src/models/AuthInviteCompleteInputInviteComplete.js +2 -0
  74. package/dist/src/models/AuthInviteCompleteInputInviteComplete.js.map +1 -0
  75. package/{src/models/AuthInviteUserInputInviteSend.ts → dist/src/models/AuthInviteUserInputInviteSend.d.ts} +1 -2
  76. package/dist/src/models/AuthInviteUserInputInviteSend.js +2 -0
  77. package/dist/src/models/AuthInviteUserInputInviteSend.js.map +1 -0
  78. package/{src/models/AuthLdJson.ts → dist/src/models/AuthLdJson.d.ts} +1 -2
  79. package/dist/src/models/AuthLdJson.js +2 -0
  80. package/dist/src/models/AuthLdJson.js.map +1 -0
  81. package/{src/models/AuthPasswordForgotInputPasswordForgot.ts → dist/src/models/AuthPasswordForgotInputPasswordForgot.d.ts} +1 -2
  82. package/dist/src/models/AuthPasswordForgotInputPasswordForgot.js +2 -0
  83. package/dist/src/models/AuthPasswordForgotInputPasswordForgot.js.map +1 -0
  84. package/{src/models/AuthPasswordResetInputPasswordReset.ts → dist/src/models/AuthPasswordResetInputPasswordReset.d.ts} +2 -3
  85. package/dist/src/models/AuthPasswordResetInputPasswordReset.js +2 -0
  86. package/dist/src/models/AuthPasswordResetInputPasswordReset.js.map +1 -0
  87. package/{src/models/AuthRegisterUserInputUserRegister.ts → dist/src/models/AuthRegisterUserInputUserRegister.d.ts} +2 -3
  88. package/dist/src/models/AuthRegisterUserInputUserRegister.js +2 -0
  89. package/dist/src/models/AuthRegisterUserInputUserRegister.js.map +1 -0
  90. package/dist/src/models/FrontendConfig.d.ts +11 -0
  91. package/dist/src/models/FrontendConfig.js +2 -0
  92. package/dist/src/models/FrontendConfig.js.map +1 -0
  93. package/{src/models/InvitePreview.ts → dist/src/models/InvitePreview.d.ts} +4 -5
  94. package/dist/src/models/InvitePreview.js +2 -0
  95. package/dist/src/models/InvitePreview.js.map +1 -0
  96. package/{src/models/InviteUserInviteRead.ts → dist/src/models/InviteUserInviteRead.d.ts} +5 -6
  97. package/dist/src/models/InviteUserInviteRead.js +2 -0
  98. package/dist/src/models/InviteUserInviteRead.js.map +1 -0
  99. package/{src/models/Setup.ts → dist/src/models/Setup.d.ts} +1 -2
  100. package/dist/src/models/Setup.js +2 -0
  101. package/dist/src/models/Setup.js.map +1 -0
  102. package/{src/models/SetupRegisterUserInputUserRegister.ts → dist/src/models/SetupRegisterUserInputUserRegister.d.ts} +2 -3
  103. package/dist/src/models/SetupRegisterUserInputUserRegister.js +2 -0
  104. package/dist/src/models/SetupRegisterUserInputUserRegister.js.map +1 -0
  105. package/{src/models/UserUpdateUserRolesInputUserRoles.ts → dist/src/models/UserUpdateUserRolesInputUserRoles.d.ts} +1 -2
  106. package/dist/src/models/UserUpdateUserRolesInputUserRoles.js +2 -0
  107. package/dist/src/models/UserUpdateUserRolesInputUserRoles.js.map +1 -0
  108. package/dist/src/models/UserUserRead.d.ts +8 -0
  109. package/dist/src/models/UserUserRead.js +2 -0
  110. package/dist/src/models/UserUserRead.js.map +1 -0
  111. package/dist/src/models/index.js +2 -0
  112. package/dist/src/models/index.js.map +1 -0
  113. package/{src/public-api.ts → dist/src/public-api.d.ts} +0 -1
  114. package/dist/src/public-api.js +9 -0
  115. package/dist/src/public-api.js.map +1 -0
  116. package/package.json +5 -1
  117. package/DEVELOPMENT.md +0 -226
  118. package/src/lib/bridge/rest/api-platform.adapter.ts +0 -84
  119. package/src/lib/bridge/rest/http-request.options.ts +0 -21
  120. package/src/lib/bridge/rest/query-builder.ts +0 -43
  121. package/src/lib/bridge/sse/eventsource-wrapper.ts +0 -70
  122. package/src/lib/bridge/sse/mercure-topic.mapper.ts +0 -48
  123. package/src/lib/bridge/sse/mercure-url.builder.ts +0 -17
  124. package/src/lib/bridge/sse/mercure.adapter.ts +0 -261
  125. package/src/lib/bridge/sse/ref-count-topic.registry.ts +0 -45
  126. package/src/lib/facades/bridge.facade.ts +0 -108
  127. package/src/lib/facades/facade.factory.ts +0 -38
  128. package/src/lib/facades/facade.interface.ts +0 -30
  129. package/src/lib/facades/resource.facade.ts +0 -101
  130. package/src/lib/interceptors/bridge-debug.interceptor.ts +0 -32
  131. package/src/lib/interceptors/bridge-defaults.interceptor.ts +0 -53
  132. package/src/lib/interceptors/content-type.interceptor.ts +0 -49
  133. package/src/lib/interceptors/singleflight.interceptor.ts +0 -55
  134. package/src/lib/ports/realtime.port.ts +0 -36
  135. package/src/lib/ports/resource-repository.port.ts +0 -78
  136. package/src/lib/provide-bridge.ts +0 -148
  137. package/src/lib/tokens.ts +0 -20
  138. package/src/lib/utils/url.ts +0 -15
  139. package/src/models/FrontendConfig.ts +0 -12
  140. package/src/models/UserUserRead.ts +0 -9
  141. package/tsconfig.json +0 -23
  142. /package/{src/models/index.ts → dist/src/models/index.d.ts} +0 -0
@@ -6,5 +6,4 @@
6
6
  * - Facades (resource-based API)
7
7
  * - Models (auto-generated types from OpenAPI)
8
8
  */
9
-
10
9
  export * from './src/public-api';
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { Observable } from 'rxjs';
3
+ import { Collection, HttpCallOptions, HttpRequestConfig, Iri, IriRequired, Item, AnyQuery, ResourceRepository } from '../../ports/resource-repository.port';
4
+ export declare class ApiPlatformRestRepository<T extends Item> implements ResourceRepository<T> {
5
+ private readonly http;
6
+ private readonly apiBase;
7
+ private readonly resourcePath;
8
+ private readonly withCredentialsDefault;
9
+ constructor(http: HttpClient, apiBase: string, resourcePath: Iri, withCredentialsDefault: boolean);
10
+ getCollection$(query?: AnyQuery, opts?: HttpCallOptions): Observable<Collection<T>>;
11
+ get$(iri: IriRequired, opts?: HttpCallOptions): Observable<T>;
12
+ post$(payload: Partial<T>, opts?: HttpCallOptions): Observable<T>;
13
+ patch$(iri: IriRequired, changes: Partial<T>, opts?: HttpCallOptions): Observable<T>;
14
+ put$(iri: IriRequired, payload: Partial<T>, opts?: HttpCallOptions): Observable<T>;
15
+ delete$(iri: IriRequired, opts?: HttpCallOptions): Observable<void>;
16
+ request$<R = unknown, B = unknown>(req: HttpRequestConfig<B>): Observable<R>;
17
+ private resolveUrl;
18
+ }
@@ -0,0 +1,67 @@
1
+ import { toHttpParams } from './query-builder';
2
+ import { buildHttpRequestOptions } from './http-request.options';
3
+ import { resolveUrl } from '../../utils/url';
4
+ export class ApiPlatformRestRepository {
5
+ http;
6
+ apiBase;
7
+ resourcePath;
8
+ withCredentialsDefault;
9
+ constructor(http, apiBase, resourcePath, withCredentialsDefault) {
10
+ this.http = http;
11
+ this.apiBase = apiBase;
12
+ this.resourcePath = resourcePath;
13
+ this.withCredentialsDefault = withCredentialsDefault;
14
+ }
15
+ getCollection$(query, opts) {
16
+ const params = toHttpParams(query);
17
+ return this.http.get(this.resolveUrl(this.resourcePath), {
18
+ params,
19
+ headers: opts?.headers,
20
+ withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
21
+ });
22
+ }
23
+ get$(iri, opts) {
24
+ return this.http.get(this.resolveUrl(iri), {
25
+ headers: opts?.headers,
26
+ withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
27
+ });
28
+ }
29
+ post$(payload, opts) {
30
+ return this.http.post(this.resolveUrl(this.resourcePath), payload, {
31
+ headers: opts?.headers,
32
+ withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
33
+ });
34
+ }
35
+ patch$(iri, changes, opts) {
36
+ return this.http.patch(this.resolveUrl(iri), changes, {
37
+ headers: opts?.headers,
38
+ withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
39
+ });
40
+ }
41
+ put$(iri, payload, opts) {
42
+ return this.http.put(this.resolveUrl(iri), payload, {
43
+ headers: opts?.headers,
44
+ withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
45
+ });
46
+ }
47
+ delete$(iri, opts) {
48
+ return this.http.delete(this.resolveUrl(iri), {
49
+ headers: opts?.headers,
50
+ withCredentials: opts?.withCredentials ?? this.withCredentialsDefault,
51
+ });
52
+ }
53
+ request$(req) {
54
+ // Low-level escape hatch for non-standard endpoints (custom controllers, uploads, etc.).
55
+ const { method, url } = req;
56
+ const targetUrl = this.resolveUrl(url ?? this.resourcePath);
57
+ const mergedOptions = buildHttpRequestOptions(req, { withCredentialsDefault: this.withCredentialsDefault });
58
+ return this.http.request(method, targetUrl, mergedOptions);
59
+ }
60
+ resolveUrl(path) {
61
+ const effectivePath = path ?? this.resourcePath;
62
+ if (!effectivePath)
63
+ throw new Error('ApiPlatformRestRepository: missing url and resourcePath');
64
+ return resolveUrl(this.apiBase, effectivePath);
65
+ }
66
+ }
67
+ //# sourceMappingURL=api-platform.adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-platform.adapter.js","sourceRoot":"","sources":["../../../../../src/lib/bridge/rest/api-platform.adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { HttpRequestConfig } from '../../ports/resource-repository.port';
2
+ export declare function buildHttpRequestOptions(req: HttpRequestConfig, { withCredentialsDefault }: {
3
+ withCredentialsDefault: boolean;
4
+ }): Record<string, unknown>;
@@ -0,0 +1,17 @@
1
+ import { toHttpParams } from './query-builder';
2
+ export function buildHttpRequestOptions(req, { withCredentialsDefault }) {
3
+ const { query, body, headers, responseType, withCredentials, options = {} } = req;
4
+ const mergedOptions = { ...options };
5
+ if (headers)
6
+ mergedOptions['headers'] = headers;
7
+ if (query)
8
+ mergedOptions['params'] = toHttpParams(query);
9
+ if (body !== undefined)
10
+ mergedOptions['body'] = body;
11
+ mergedOptions['responseType'] = (responseType ?? mergedOptions['responseType'] ?? 'json');
12
+ mergedOptions['withCredentials'] =
13
+ withCredentials ?? mergedOptions['withCredentials'] ?? withCredentialsDefault;
14
+ mergedOptions['observe'] = 'body';
15
+ return mergedOptions;
16
+ }
17
+ //# sourceMappingURL=http-request.options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-request.options.js","sourceRoot":"","sources":["../../../../../src/lib/bridge/rest/http-request.options.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAE7C,MAAM,UAAU,uBAAuB,CACrC,GAAsB,EACtB,EAAC,sBAAsB,EAAoC;IAE3D,MAAM,EAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,OAAO,GAAG,EAAE,EAAC,GAAG,GAAG,CAAC;IAChF,MAAM,aAAa,GAA4B,EAAC,GAAG,OAAO,EAAC,CAAC;IAE5D,IAAI,OAAO;QAAE,aAAa,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC;IAChD,IAAI,KAAK;QAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACzD,IAAI,IAAI,KAAK,SAAS;QAAE,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAErD,aAAa,CAAC,cAAc,CAAC,GAAG,CAAC,YAAY,IAAK,aAAa,CAAC,cAAc,CAAS,IAAI,MAAM,CAAQ,CAAC;IAC1G,aAAa,CAAC,iBAAiB,CAAC;QAC9B,eAAe,IAAK,aAAa,CAAC,iBAAiB,CAAS,IAAI,sBAAsB,CAAC;IACzF,aAAa,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC;IAElC,OAAO,aAAa,CAAC;AACvB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { HttpParams } from '@angular/common/http';
2
+ import { AnyQuery } from '../../ports/resource-repository.port';
3
+ export declare function toHttpParams(q: AnyQuery | undefined): HttpParams;
@@ -0,0 +1,41 @@
1
+ import { HttpParams } from '@angular/common/http';
2
+ export function toHttpParams(q) {
3
+ if (!q)
4
+ return new HttpParams();
5
+ if (q instanceof HttpParams)
6
+ return q;
7
+ const fromObject = {};
8
+ const consumed = new Set();
9
+ const maybeQuery = q;
10
+ if (maybeQuery.page != null) {
11
+ fromObject['page'] = String(maybeQuery.page);
12
+ consumed.add('page');
13
+ }
14
+ if (maybeQuery.itemsPerPage != null) {
15
+ fromObject['itemsPerPage'] = String(maybeQuery.itemsPerPage);
16
+ consumed.add('itemsPerPage');
17
+ }
18
+ if (q.filters) {
19
+ consumed.add('filters');
20
+ for (const [k, v] of Object.entries(q.filters)) {
21
+ assign(fromObject, k, v);
22
+ }
23
+ }
24
+ for (const [k, v] of Object.entries(q)) {
25
+ if (consumed.has(k))
26
+ continue;
27
+ assign(fromObject, k, v);
28
+ }
29
+ return new HttpParams({ fromObject });
30
+ }
31
+ function assign(target, key, value) {
32
+ if (value == null)
33
+ return;
34
+ if (Array.isArray(value)) {
35
+ target[key] = value.map(String);
36
+ }
37
+ else {
38
+ target[key] = String(value);
39
+ }
40
+ }
41
+ //# sourceMappingURL=query-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-builder.js","sourceRoot":"","sources":["../../../../../src/lib/bridge/rest/query-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,sBAAsB,CAAC;AAGhD,MAAM,UAAU,YAAY,CAAC,CAAuB;IAClD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,UAAU,EAAE,CAAC;IAChC,IAAI,CAAC,YAAY,UAAU;QAAE,OAAO,CAAC,CAAC;IAEtC,MAAM,UAAU,GAAsC,EAAE,CAAC;IAEzD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,UAAU,GAAG,CAAU,CAAC;IAC9B,IAAI,UAAU,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QAC5B,UAAU,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC7C,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,UAAU,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;QACpC,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAC7D,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QACd,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACxB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/C,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAoC,CAAC,EAAE,CAAC;QAC1E,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,SAAS;QAC9B,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,IAAI,UAAU,CAAC,EAAC,UAAU,EAAC,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,MAAM,CAAC,MAAyC,EAAE,GAAW,EAAE,KAAkC;IACxG,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO;IAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { SseEvent, SseOptions, RealtimeStatus } from '../../ports/realtime.port';
2
+ import { BridgeLogger } from '../../bridge.types';
3
+ export declare class EventSourceWrapper {
4
+ private readonly url;
5
+ private readonly opts;
6
+ private readonly logger?;
7
+ private es?;
8
+ private readonly statusSub;
9
+ private readonly eventSub;
10
+ readonly status$: import("rxjs").Observable<RealtimeStatus>;
11
+ readonly events$: import("rxjs").Observable<SseEvent>;
12
+ constructor(url: string, opts?: SseOptions, logger?: BridgeLogger | undefined);
13
+ open(): void;
14
+ close(): void;
15
+ private setState;
16
+ private log;
17
+ }
@@ -0,0 +1,57 @@
1
+ import { ReplaySubject, Subject } from 'rxjs';
2
+ export class EventSourceWrapper {
3
+ url;
4
+ opts;
5
+ logger;
6
+ es;
7
+ statusSub = new ReplaySubject(1);
8
+ eventSub = new Subject();
9
+ status$ = this.statusSub.asObservable();
10
+ events$ = this.eventSub.asObservable();
11
+ constructor(url, opts = {}, logger) {
12
+ this.url = url;
13
+ this.opts = opts;
14
+ this.logger = logger;
15
+ this.setState('closed');
16
+ this.log('[SSE] init', { url, withCredentials: !!opts.withCredentials });
17
+ }
18
+ open() {
19
+ if (this.es) {
20
+ this.log('[SSE] open() ignored: already open');
21
+ return;
22
+ }
23
+ this.setState('connecting');
24
+ this.log('[SSE] open', { url: this.url });
25
+ const es = new EventSource(this.url, {
26
+ withCredentials: !!this.opts.withCredentials,
27
+ });
28
+ this.es = es;
29
+ es.onopen = () => {
30
+ this.setState('connected');
31
+ };
32
+ es.onmessage = (ev) => {
33
+ this.eventSub.next({ type: 'message', data: ev.data, lastEventId: ev.lastEventId || undefined });
34
+ };
35
+ es.onerror = () => {
36
+ // The browser will retry automatically. We stay in "connecting".
37
+ this.log('[SSE] error');
38
+ this.setState('connecting');
39
+ };
40
+ }
41
+ close() {
42
+ if (this.es) {
43
+ this.es.close();
44
+ this.es = undefined;
45
+ this.log('[SSE] closed');
46
+ }
47
+ this.setState('closed');
48
+ }
49
+ // ──────────────── internals ────────────────
50
+ setState(state) {
51
+ this.statusSub.next(state);
52
+ }
53
+ log(...args) {
54
+ this.logger?.debug?.(...args);
55
+ }
56
+ }
57
+ //# sourceMappingURL=eventsource-wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventsource-wrapper.js","sourceRoot":"","sources":["../../../../../src/lib/bridge/sse/eventsource-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAE,OAAO,EAAC,MAAM,MAAM,CAAC;AAI5C,MAAM,OAAO,kBAAkB;IAUV;IACA;IACA;IAXX,EAAE,CAAe;IAER,SAAS,GAAG,IAAI,aAAa,CAAiB,CAAC,CAAC,CAAC;IACjD,QAAQ,GAAG,IAAI,OAAO,EAAY,CAAC;IAE3C,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;IACxC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;IAEhD,YACmB,GAAW,EACX,OAAmB,EAAE,EACrB,MAAqB;QAFrB,QAAG,GAAH,GAAG,CAAQ;QACX,SAAI,GAAJ,IAAI,CAAiB;QACrB,WAAM,GAAN,MAAM,CAAe;QAEtC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,EAAC,GAAG,EAAE,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,EAAC,CAAC,CAAC;IACzE,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;YAC/C,OAAO;QACT,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,EAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAC,CAAC,CAAC;QAExC,MAAM,EAAE,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE;YACnC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe;SAC7C,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QAEb,EAAE,CAAC,MAAM,GAAG,GAAG,EAAE;YACf,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC7B,CAAC,CAAC;QAEF,EAAE,CAAC,SAAS,GAAG,CAAC,EAAE,EAAE,EAAE;YACpB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC,WAAW,IAAI,SAAS,EAAC,CAAC,CAAC;QACjG,CAAC,CAAC;QAEF,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;YAChB,iEAAiE;YACjE,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC9B,CAAC,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,EAAE,GAAG,SAAS,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;IAED,8CAA8C;IAEtC,QAAQ,CAAC,KAAqB;QACpC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAEO,GAAG,CAAC,GAAG,IAAe;QAC5B,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAChC,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import { MercureTopicMode } from '../../bridge.types';
2
+ export declare class MercureTopicMapper {
3
+ private readonly mode;
4
+ private readonly apiBaseUrl;
5
+ constructor(apiBase: string, mode: MercureTopicMode);
6
+ /**
7
+ * Canonical value used for ref-counting and as the "topic" query param value.
8
+ * - mode "url": always absolute, same-origin resolved
9
+ * - mode "iri": same-origin path+query+hash ("/api/..."), otherwise keep as-is
10
+ */
11
+ toTopic(input: string): string;
12
+ /**
13
+ * Canonical value used to compare incoming payload IRIs with subscribed IRIs.
14
+ * We keep payload matching stable by using same-origin relative IRIs ("/api/...").
15
+ */
16
+ toPayloadIri(input: string): string;
17
+ private toAbsoluteUrl;
18
+ private toRelativeIriIfSameOrigin;
19
+ }
@@ -0,0 +1,45 @@
1
+ export class MercureTopicMapper {
2
+ mode;
3
+ apiBaseUrl;
4
+ constructor(apiBase, mode) {
5
+ this.mode = mode;
6
+ this.apiBaseUrl = new URL(apiBase);
7
+ }
8
+ /**
9
+ * Canonical value used for ref-counting and as the "topic" query param value.
10
+ * - mode "url": always absolute, same-origin resolved
11
+ * - mode "iri": same-origin path+query+hash ("/api/..."), otherwise keep as-is
12
+ */
13
+ toTopic(input) {
14
+ if (this.mode === 'url')
15
+ return this.toAbsoluteUrl(input);
16
+ return this.toRelativeIriIfSameOrigin(input);
17
+ }
18
+ /**
19
+ * Canonical value used to compare incoming payload IRIs with subscribed IRIs.
20
+ * We keep payload matching stable by using same-origin relative IRIs ("/api/...").
21
+ */
22
+ toPayloadIri(input) {
23
+ return this.toRelativeIriIfSameOrigin(input);
24
+ }
25
+ toAbsoluteUrl(input) {
26
+ try {
27
+ return new URL(input, this.apiBaseUrl).toString();
28
+ }
29
+ catch {
30
+ return input;
31
+ }
32
+ }
33
+ toRelativeIriIfSameOrigin(input) {
34
+ try {
35
+ const url = new URL(input, this.apiBaseUrl);
36
+ if (url.origin !== this.apiBaseUrl.origin)
37
+ return input;
38
+ return `${url.pathname}${url.search}${url.hash}`;
39
+ }
40
+ catch {
41
+ return input;
42
+ }
43
+ }
44
+ }
45
+ //# sourceMappingURL=mercure-topic.mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mercure-topic.mapper.js","sourceRoot":"","sources":["../../../../../src/lib/bridge/sse/mercure-topic.mapper.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,kBAAkB;IAKV;IAJF,UAAU,CAAM;IAEjC,YACE,OAAe,EACE,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;QAEvC,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,KAAa;QACnB,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED;;;OAGG;IACH,YAAY,CAAC,KAAa;QACxB,OAAO,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;IAEO,aAAa,CAAC,KAAa;QACjC,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,yBAAyB,CAAC,KAAa;QAC7C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC5C,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,UAAU,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAC;YACxD,OAAO,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ export declare class MercureUrlBuilder {
2
+ /**
3
+ * Builds the Mercure hub URL with one `topic=` parameter per topic.
4
+ * The adapter is responsible for canonicalising topics beforehand.
5
+ */
6
+ build(hubUrl: string, topics: ReadonlySet<string>, lastEventId?: string): string;
7
+ }
@@ -0,0 +1,18 @@
1
+ export class MercureUrlBuilder {
2
+ /**
3
+ * Builds the Mercure hub URL with one `topic=` parameter per topic.
4
+ * The adapter is responsible for canonicalising topics beforehand.
5
+ */
6
+ build(hubUrl, topics, lastEventId) {
7
+ const url = new URL(hubUrl);
8
+ if (lastEventId) {
9
+ url.searchParams.set('lastEventID', lastEventId);
10
+ }
11
+ url.searchParams.delete('topic');
12
+ for (const topic of topics) {
13
+ url.searchParams.append('topic', topic);
14
+ }
15
+ return url.toString();
16
+ }
17
+ }
18
+ //# sourceMappingURL=mercure-url.builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mercure-url.builder.js","sourceRoot":"","sources":["../../../../../src/lib/bridge/sse/mercure-url.builder.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,iBAAiB;IAC5B;;;OAGG;IACH,KAAK,CAAC,MAAc,EAAE,MAA2B,EAAE,WAAoB;QACrE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,WAAW,EAAE,CAAC;YAChB,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QACnD,CAAC;QACD,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;CACF"}
@@ -0,0 +1,37 @@
1
+ import { OnDestroy } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ import { BridgeLogger, MercureTopicMode } from '../../bridge.types';
4
+ import { RealtimeEvent, RealtimePort, RealtimeStatus } from '../../ports/realtime.port';
5
+ export declare class MercureRealtimeAdapter implements RealtimePort, OnDestroy {
6
+ private readonly apiBase;
7
+ private readonly withCredentialsDefault;
8
+ private readonly platformId;
9
+ private readonly hubUrl?;
10
+ private readonly logger?;
11
+ private lastEventId?;
12
+ private es?;
13
+ private currentKey?;
14
+ private readonly topicsRegistry;
15
+ private readonly urlBuilder;
16
+ private readonly topicMapper;
17
+ private readonly destroy$;
18
+ private connectionStop$;
19
+ private readonly rebuild$;
20
+ private shuttingDown;
21
+ private readonly _status$;
22
+ private readonly incoming$;
23
+ constructor(apiBase: string, withCredentialsDefault: boolean, platformId: object, hubUrl?: string | undefined, topicMode?: MercureTopicMode, logger?: BridgeLogger | undefined);
24
+ status$(): Observable<RealtimeStatus>;
25
+ subscribe$<T>(iris: string[], _filter?: {
26
+ field?: string;
27
+ }): Observable<RealtimeEvent<T>>;
28
+ unsubscribe(iris: string[]): void;
29
+ shutdownBeforeExit(): void;
30
+ ngOnDestroy(): void;
31
+ private scheduleRebuild;
32
+ private rebuildOnce$;
33
+ private teardownConnection;
34
+ private updateGlobalStatus;
35
+ private safeParse;
36
+ private extractRelationIris;
37
+ }
@@ -0,0 +1,242 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { Inject, Injectable, Optional, PLATFORM_ID } from '@angular/core';
11
+ import { BehaviorSubject, defer, EMPTY, fromEvent, of, Subject } from 'rxjs';
12
+ import { auditTime, concatMap, filter, finalize, map, share, takeUntil } from 'rxjs/operators';
13
+ import { API_BASE_URL, BRIDGE_LOGGER, BRIDGE_WITH_CREDENTIALS, MERCURE_HUB_URL, MERCURE_TOPIC_MODE } from '../../tokens';
14
+ import { EventSourceWrapper } from './eventsource-wrapper';
15
+ import { isPlatformBrowser } from '@angular/common';
16
+ import { MercureUrlBuilder } from './mercure-url.builder';
17
+ import { RefCountTopicRegistry } from './ref-count-topic.registry';
18
+ import { MercureTopicMapper } from './mercure-topic.mapper';
19
+ let MercureRealtimeAdapter = class MercureRealtimeAdapter {
20
+ apiBase;
21
+ withCredentialsDefault;
22
+ platformId;
23
+ hubUrl;
24
+ logger;
25
+ lastEventId;
26
+ es;
27
+ currentKey;
28
+ topicsRegistry = new RefCountTopicRegistry();
29
+ urlBuilder;
30
+ topicMapper;
31
+ destroy$ = new Subject();
32
+ connectionStop$ = new Subject();
33
+ rebuild$ = new Subject();
34
+ shuttingDown = false;
35
+ _status$ = new BehaviorSubject('closed');
36
+ incoming$ = new Subject();
37
+ constructor(apiBase, withCredentialsDefault, platformId, hubUrl, topicMode, logger) {
38
+ this.apiBase = apiBase;
39
+ this.withCredentialsDefault = withCredentialsDefault;
40
+ this.platformId = platformId;
41
+ this.hubUrl = hubUrl;
42
+ this.logger = logger;
43
+ this.urlBuilder = new MercureUrlBuilder();
44
+ // `topicMode` affects only the `topic=` query param sent to the hub.
45
+ // Payload IRIs are always matched using same-origin relative IRIs (`/api/...`) when possible.
46
+ this.topicMapper = new MercureTopicMapper(apiBase, topicMode ?? 'url');
47
+ this.rebuild$
48
+ .pipe(auditTime(10), concatMap(() => this.rebuildOnce$()))
49
+ .subscribe();
50
+ if (isPlatformBrowser(this.platformId)) {
51
+ fromEvent(window, 'pagehide')
52
+ .pipe(takeUntil(this.destroy$))
53
+ .subscribe(() => this.shutdownBeforeExit());
54
+ fromEvent(window, 'beforeunload')
55
+ .pipe(takeUntil(this.destroy$))
56
+ .subscribe(() => this.shutdownBeforeExit());
57
+ }
58
+ }
59
+ // ──────────────── API publique ────────────────
60
+ status$() {
61
+ return this._status$.asObservable();
62
+ }
63
+ subscribe$(iris, _filter) {
64
+ return defer(() => {
65
+ const inputIris = iris.filter((v) => typeof v === 'string' && v.length > 0);
66
+ if (inputIris.length === 0)
67
+ return EMPTY;
68
+ if (!this.hubUrl) {
69
+ this.logger?.debug?.('[Mercure] hubUrl not configured → realtime disabled');
70
+ return EMPTY;
71
+ }
72
+ // Canonicalise topics (ref-count + URL) to avoid duplicates like:
73
+ // - "/api/conversations/1" and "http://localhost:8000/api/conversations/1"
74
+ const registeredTopics = Array.from(new Set(inputIris.map((i) => this.topicMapper.toTopic(i))));
75
+ this.topicsRegistry.addAll(registeredTopics);
76
+ this.scheduleRebuild();
77
+ // Matching is done against the payload IRIs (typically "/api/...").
78
+ const subscribed = inputIris.map((i) => normalizeIri(this.topicMapper.toPayloadIri(i)));
79
+ const fieldPath = _filter?.field;
80
+ return this.incoming$.pipe(map((evt) => this.safeParse(evt.data)), filter((raw) => !!raw), filter((raw) => {
81
+ if (fieldPath) {
82
+ const relIris = this.extractRelationIris(raw, fieldPath).map((i) => normalizeIri(this.topicMapper.toPayloadIri(i)));
83
+ return relIris.some((relIri) => matchesAnySubscribed(relIri, subscribed));
84
+ }
85
+ const rawId = raw?.['@id'];
86
+ const id = typeof rawId === 'string' ? normalizeIri(this.topicMapper.toPayloadIri(rawId)) : undefined;
87
+ return typeof id === 'string' && matchesAnySubscribed(id, subscribed);
88
+ }), map((payload) => ({ iri: payload['@id'], data: payload })), finalize(() => {
89
+ this.topicsRegistry.removeAll(registeredTopics);
90
+ this.scheduleRebuild();
91
+ }), share());
92
+ });
93
+ }
94
+ unsubscribe(iris) {
95
+ const inputIris = iris.filter((v) => typeof v === 'string' && v.length > 0);
96
+ if (inputIris.length === 0)
97
+ return;
98
+ const topics = Array.from(new Set(inputIris.map((i) => this.topicMapper.toTopic(i))));
99
+ this.topicsRegistry.removeAll(topics);
100
+ this.scheduleRebuild();
101
+ }
102
+ shutdownBeforeExit() {
103
+ if (this.shuttingDown)
104
+ return;
105
+ this.shuttingDown = true;
106
+ this.teardownConnection();
107
+ }
108
+ ngOnDestroy() {
109
+ this.teardownConnection();
110
+ this._status$.complete();
111
+ this.incoming$.complete();
112
+ this.destroy$.next();
113
+ this.destroy$.complete();
114
+ this.rebuild$.complete();
115
+ }
116
+ // ───────────────── PRIVATE ─────────────────
117
+ scheduleRebuild() {
118
+ if (this.shuttingDown)
119
+ return;
120
+ this.rebuild$.next();
121
+ }
122
+ rebuildOnce$() {
123
+ return defer(() => {
124
+ if (this.shuttingDown)
125
+ return of(void 0);
126
+ try {
127
+ if (!this.hubUrl) {
128
+ this.currentKey = undefined;
129
+ this._status$.next('closed');
130
+ return of(void 0);
131
+ }
132
+ const hasTopics = this.topicsRegistry.hasAny();
133
+ const key = hasTopics ? this.topicsRegistry.computeKey(this.hubUrl, this.withCredentialsDefault) : undefined;
134
+ if (!hasTopics) {
135
+ if (this.es)
136
+ this.teardownConnection();
137
+ this.currentKey = undefined;
138
+ this._status$.next('closed');
139
+ return of(void 0);
140
+ }
141
+ if (key && key === this.currentKey) {
142
+ return of(void 0);
143
+ }
144
+ this.teardownConnection();
145
+ const url = this.urlBuilder.build(this.hubUrl, this.topicsRegistry.snapshot(), this.lastEventId);
146
+ this.logger?.debug?.('[Mercure] connect', { hubUrl: this.hubUrl, topics: this.topicsRegistry.snapshot(), lastEventId: this.lastEventId });
147
+ this.es = new EventSourceWrapper(url, { withCredentials: this.withCredentialsDefault }, this.logger);
148
+ this.connectionStop$ = new Subject();
149
+ this.es.status$
150
+ .pipe(takeUntil(this.connectionStop$), takeUntil(this.destroy$))
151
+ .subscribe((st) => this.updateGlobalStatus(st));
152
+ this.es.events$
153
+ .pipe(takeUntil(this.connectionStop$), takeUntil(this.destroy$))
154
+ .subscribe((e) => {
155
+ this.lastEventId = e.lastEventId ?? this.lastEventId;
156
+ this.incoming$.next(e);
157
+ });
158
+ this._status$.next('connecting');
159
+ this.es.open();
160
+ this.currentKey = key;
161
+ }
162
+ catch (err) {
163
+ this.logger?.error?.('[Mercure] rebuild failed:', err);
164
+ this.currentKey = undefined;
165
+ this._status$.next(this.topicsRegistry.hasAny() ? 'connecting' : 'closed');
166
+ }
167
+ return of(void 0);
168
+ });
169
+ }
170
+ teardownConnection() {
171
+ this.es?.close();
172
+ this.es = undefined;
173
+ this.connectionStop$.next();
174
+ this.connectionStop$.complete();
175
+ }
176
+ updateGlobalStatus(sse) {
177
+ if (sse === 'connected') {
178
+ this._status$.next('connected');
179
+ return;
180
+ }
181
+ if (sse === 'connecting') {
182
+ this._status$.next('connecting');
183
+ return;
184
+ }
185
+ this._status$.next(this.topicsRegistry.hasAny() ? 'connecting' : 'closed');
186
+ }
187
+ safeParse(raw) {
188
+ try {
189
+ return JSON.parse(raw);
190
+ }
191
+ catch (err) {
192
+ this.logger?.debug?.('[Mercure] invalid JSON payload ignored', { raw });
193
+ return undefined;
194
+ }
195
+ }
196
+ extractRelationIris(raw, path) {
197
+ const readPath = (obj, dotPath) => {
198
+ return dotPath
199
+ .split('.')
200
+ .filter(Boolean)
201
+ .reduce((acc, key) => acc?.[key], obj);
202
+ };
203
+ const normalize = (value) => {
204
+ if (!value)
205
+ return [];
206
+ if (typeof value === 'string')
207
+ return value.length > 0 ? [value] : [];
208
+ if (typeof value === 'object' && typeof value['@id'] === 'string')
209
+ return [value['@id']];
210
+ if (Array.isArray(value))
211
+ return value.flatMap(normalize);
212
+ return [];
213
+ };
214
+ return normalize(readPath(raw, path));
215
+ }
216
+ };
217
+ MercureRealtimeAdapter = __decorate([
218
+ Injectable({ providedIn: 'root' }),
219
+ __param(0, Inject(API_BASE_URL)),
220
+ __param(1, Inject(BRIDGE_WITH_CREDENTIALS)),
221
+ __param(2, Inject(PLATFORM_ID)),
222
+ __param(3, Optional()),
223
+ __param(3, Inject(MERCURE_HUB_URL)),
224
+ __param(4, Optional()),
225
+ __param(4, Inject(MERCURE_TOPIC_MODE)),
226
+ __param(5, Optional()),
227
+ __param(5, Inject(BRIDGE_LOGGER))
228
+ ], MercureRealtimeAdapter);
229
+ export { MercureRealtimeAdapter };
230
+ function normalizeIri(iri) {
231
+ return iri.endsWith('/') ? iri.slice(0, -1) : iri;
232
+ }
233
+ function matchesAnySubscribed(candidate, subscribed) {
234
+ for (const iri of subscribed) {
235
+ if (candidate === iri)
236
+ return true;
237
+ if (candidate.startsWith(`${iri}/`))
238
+ return true;
239
+ }
240
+ return false;
241
+ }
242
+ //# sourceMappingURL=mercure.adapter.js.map