@acorex-platform/framework-client 0.0.30 → 0.0.33

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 (58) hide show
  1. package/fesm2022/{acorex-platform-framework-client-common-common-settings.provider-CLm2BVk-.mjs → acorex-platform-framework-client-common-common-settings.provider-CzBr0cRi.mjs} +23 -2
  2. package/fesm2022/acorex-platform-framework-client-common-common-settings.provider-CzBr0cRi.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-framework-client-common.mjs +673 -110
  4. package/fesm2022/acorex-platform-framework-client-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-framework-client-core.mjs +76 -7
  6. package/fesm2022/acorex-platform-framework-client-core.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-framework-client-layout-builder.mjs +3 -6
  8. package/fesm2022/acorex-platform-framework-client-layout-builder.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-framework-client-layout-components.mjs +505 -111
  10. package/fesm2022/acorex-platform-framework-client-layout-components.mjs.map +1 -1
  11. package/fesm2022/{acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-CJemNxCu.mjs → acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-D1prdDvf.mjs} +3404 -2157
  12. package/fesm2022/acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-D1prdDvf.mjs.map +1 -0
  13. package/fesm2022/{acorex-platform-framework-client-layout-entity-attachments-page.component-DQXGk8nF.mjs → acorex-platform-framework-client-layout-entity-attachments-page.component-CeVGNzup.mjs} +2 -2
  14. package/fesm2022/{acorex-platform-framework-client-layout-entity-attachments-page.component-DQXGk8nF.mjs.map → acorex-platform-framework-client-layout-entity-attachments-page.component-CeVGNzup.mjs.map} +1 -1
  15. package/fesm2022/{acorex-platform-framework-client-layout-entity-bulk-entity.command-DSLUUXfQ.mjs → acorex-platform-framework-client-layout-entity-bulk-entity.command-CFScb-L4.mjs} +43 -15
  16. package/fesm2022/acorex-platform-framework-client-layout-entity-bulk-entity.command-CFScb-L4.mjs.map +1 -0
  17. package/fesm2022/{acorex-platform-framework-client-layout-entity-file-list-popup.component-p0hxDb0W.mjs → acorex-platform-framework-client-layout-entity-file-list-popup.component-B3__csKW.mjs} +3 -3
  18. package/fesm2022/{acorex-platform-framework-client-layout-entity-file-list-popup.component-p0hxDb0W.mjs.map → acorex-platform-framework-client-layout-entity-file-list-popup.component-B3__csKW.mjs.map} +1 -1
  19. package/fesm2022/{acorex-platform-framework-client-layout-entity-gallery-page.component-uf51NO5m.mjs → acorex-platform-framework-client-layout-entity-gallery-page.component-B17l6mbm.mjs} +2 -2
  20. package/fesm2022/{acorex-platform-framework-client-layout-entity-gallery-page.component-uf51NO5m.mjs.map → acorex-platform-framework-client-layout-entity-gallery-page.component-B17l6mbm.mjs.map} +1 -1
  21. package/fesm2022/acorex-platform-framework-client-layout-entity.mjs +1 -1
  22. package/fesm2022/acorex-platform-framework-client-layout-views.mjs +37 -6
  23. package/fesm2022/acorex-platform-framework-client-layout-views.mjs.map +1 -1
  24. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs +148 -130
  25. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs.map +1 -1
  26. package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-3CO4xJB3.mjs → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-4mX8aYzA.mjs} +3 -3
  27. package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-3CO4xJB3.mjs.map → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-4mX8aYzA.mjs.map} +1 -1
  28. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs +1214 -860
  29. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs.map +1 -1
  30. package/fesm2022/acorex-platform-framework-client-realtime.mjs +70 -5
  31. package/fesm2022/acorex-platform-framework-client-realtime.mjs.map +1 -1
  32. package/fesm2022/acorex-platform-framework-client-runtime.mjs +121 -6
  33. package/fesm2022/acorex-platform-framework-client-runtime.mjs.map +1 -1
  34. package/fesm2022/{acorex-platform-framework-client-themes-default-entity-master-single-view.component-C2Abf7Lb.mjs → acorex-platform-framework-client-themes-default-entity-master-single-view.component-DCpl6AXq.mjs} +51 -12
  35. package/fesm2022/acorex-platform-framework-client-themes-default-entity-master-single-view.component-DCpl6AXq.mjs.map +1 -0
  36. package/fesm2022/acorex-platform-framework-client-themes-default.mjs +770 -679
  37. package/fesm2022/acorex-platform-framework-client-themes-default.mjs.map +1 -1
  38. package/fesm2022/{acorex-platform-framework-client-themes-shared-settings.provider-D2XPkc71.mjs → acorex-platform-framework-client-themes-shared-settings.provider-CpsAIsxj.mjs} +76 -1
  39. package/fesm2022/acorex-platform-framework-client-themes-shared-settings.provider-CpsAIsxj.mjs.map +1 -0
  40. package/fesm2022/acorex-platform-framework-client-themes-shared.mjs +345 -54
  41. package/fesm2022/acorex-platform-framework-client-themes-shared.mjs.map +1 -1
  42. package/package.json +7 -7
  43. package/types/acorex-platform-framework-client-common.d.ts +137 -9
  44. package/types/acorex-platform-framework-client-core.d.ts +4 -1
  45. package/types/acorex-platform-framework-client-layout-components.d.ts +141 -22
  46. package/types/acorex-platform-framework-client-layout-entity.d.ts +532 -255
  47. package/types/acorex-platform-framework-client-layout-views.d.ts +48 -0
  48. package/types/acorex-platform-framework-client-layout-widget-core.d.ts +2 -2
  49. package/types/acorex-platform-framework-client-layout-widgets.d.ts +143 -92
  50. package/types/acorex-platform-framework-client-realtime.d.ts +39 -2
  51. package/types/acorex-platform-framework-client-runtime.d.ts +56 -5
  52. package/types/acorex-platform-framework-client-themes-default.d.ts +144 -14
  53. package/types/acorex-platform-framework-client-themes-shared.d.ts +36 -3
  54. package/fesm2022/acorex-platform-framework-client-common-common-settings.provider-CLm2BVk-.mjs.map +0 -1
  55. package/fesm2022/acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-CJemNxCu.mjs.map +0 -1
  56. package/fesm2022/acorex-platform-framework-client-layout-entity-bulk-entity.command-DSLUUXfQ.mjs.map +0 -1
  57. package/fesm2022/acorex-platform-framework-client-themes-default-entity-master-single-view.component-C2Abf7Lb.mjs.map +0 -1
  58. package/fesm2022/acorex-platform-framework-client-themes-shared-settings.provider-D2XPkc71.mjs.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, Optional, Inject, Injectable, inject, DestroyRef, makeEnvironmentProviders } from '@angular/core';
3
+ import { DOCUMENT } from '@angular/common';
3
4
  import { AXPSessionService, AXPSessionStatus } from '@acorex-platform/framework-client/auth';
4
5
  import { io } from 'socket.io-client';
5
6
  import { BehaviorSubject, Subject } from 'rxjs';
7
+ import { AXPBulkProgressChannel, provideCommandSetups } from '@acorex-platform/framework-client/runtime';
6
8
  import { provideAppStartUpTask, AXP_APP_STARTUP_PRIORITY } from '@acorex-platform/framework-client/core';
7
- import { provideCommandSetups } from '@acorex-platform/framework-client/runtime';
8
9
  import { PRESENCE_SET_AVAILABILITY } from '@acorex-platform/framework-shared/runtime';
9
- import { DOCUMENT } from '@angular/common';
10
10
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
11
11
 
12
12
  //#region ---- Client realtime types ----
@@ -14,10 +14,12 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
14
14
 
15
15
  //#region ---- Client topic constants (mirror server) ----
16
16
  const AXP_REALTIME_TOPIC_INBOX_REFRESH = 'inbox.refresh';
17
+ const AXP_REALTIME_TOPIC_BACKGROUND_JOB_TRAY_REFRESH = 'background-job.tray.refresh';
17
18
  const AXP_REALTIME_TOPIC_CONVERSATION_MESSAGE = 'conversation.message';
18
19
  const AXP_REALTIME_TOPIC_CONVERSATION_TYPING = 'conversation.typing';
19
20
  const AXP_REALTIME_TOPIC_CONVERSATION_CALL = 'conversation.call';
20
21
  const AXP_REALTIME_TOPIC_ENTITY_MUTATION = 'entity.mutation';
22
+ const AXP_REALTIME_TOPIC_BULK_PROGRESS = 'runtime.bulk.progress';
21
23
  const AXP_REALTIME_TOPIC_USER_PRESENCE = 'user.presence';
22
24
  const AXP_REALTIME_SOCKET_EVENT = 'realtime';
23
25
  const AXP_REALTIME_SUBSCRIBE_CONVERSATION = 'subscribe.conversation';
@@ -100,6 +102,11 @@ class AXPRealtimeConnectionPort {
100
102
  }
101
103
  //#endregion
102
104
 
105
+ //#region ---- Constants ----
106
+ const RECONNECT_DELAY_MS = 1_000;
107
+ const RECONNECT_DELAY_MAX_MS = 10_000;
108
+ const CONNECT_TIMEOUT_MS = 20_000;
109
+ //#endregion
103
110
  //#region ---- Socket.IO connection (built-in) ----
104
111
  /**
105
112
  * Built-in always-on realtime connection via Socket.IO.
@@ -110,15 +117,28 @@ class AXPRealtimeConnectionService extends AXPRealtimeConnectionPort {
110
117
  this.config = config;
111
118
  this.session = inject(AXPSessionService);
112
119
  this.dispatcher = inject(AXPRealtimeDispatcherService);
120
+ this.bulkProgress = inject(AXPBulkProgressChannel, { optional: true });
121
+ this.document = inject(DOCUMENT);
113
122
  this.socket = null;
114
123
  this.statusSub = null;
124
+ this.wakeListenersBound = false;
115
125
  this.joinedConversations = new Set();
116
126
  this.connectionStatusSubject = new BehaviorSubject('disconnected');
117
127
  /** Latest Socket.IO connection state for feature modules (e.g. chat). */
118
128
  this.connectionStatus$ = this.connectionStatusSubject.asObservable();
129
+ this.onVisibilityResume = () => {
130
+ if (this.document.visibilityState === 'visible') {
131
+ this.resumeIfAuthorized();
132
+ }
133
+ };
134
+ this.onNetworkResume = () => {
135
+ this.resumeIfAuthorized();
136
+ };
137
+ this.registerBulkProgressHandler();
119
138
  if (config?.autoConnect === false) {
120
139
  return;
121
140
  }
141
+ this.bindWakeListeners();
122
142
  this.statusSub = this.session.status$.subscribe((status) => {
123
143
  if (status === AXPSessionStatus.Authorized) {
124
144
  this.connect();
@@ -130,6 +150,7 @@ class AXPRealtimeConnectionService extends AXPRealtimeConnectionPort {
130
150
  }
131
151
  ngOnDestroy() {
132
152
  this.statusSub?.unsubscribe();
153
+ this.unbindWakeListeners();
133
154
  this.disconnect();
134
155
  }
135
156
  /** Sign-out: tell the server to skip grace, then close the socket. */
@@ -146,8 +167,10 @@ class AXPRealtimeConnectionService extends AXPRealtimeConnectionPort {
146
167
  if (this.socket?.connected) {
147
168
  return;
148
169
  }
149
- // Avoid tearing down a socket that is still handshaking (duplicate connect calls).
150
- if (this.socket && !this.socket.connected) {
170
+ // Resume a dead manager (sleep / tab freeze / network drop) instead of creating a second client.
171
+ if (this.socket) {
172
+ this.connectionStatusSubject.next('connecting');
173
+ this.socket.connect();
151
174
  return;
152
175
  }
153
176
  this.connectionStatusSubject.next('connecting');
@@ -157,6 +180,10 @@ class AXPRealtimeConnectionService extends AXPRealtimeConnectionPort {
157
180
  withCredentials: true,
158
181
  autoConnect: true,
159
182
  reconnection: true,
183
+ reconnectionAttempts: Infinity,
184
+ reconnectionDelay: RECONNECT_DELAY_MS,
185
+ reconnectionDelayMax: RECONNECT_DELAY_MAX_MS,
186
+ timeout: CONNECT_TIMEOUT_MS,
160
187
  });
161
188
  this.socket.on(AXP_REALTIME_SOCKET_EVENT, (envelope) => {
162
189
  void this.dispatcher.dispatch(envelope);
@@ -254,6 +281,44 @@ class AXPRealtimeConnectionService extends AXPRealtimeConnectionPort {
254
281
  });
255
282
  });
256
283
  }
284
+ registerBulkProgressHandler() {
285
+ this.dispatcher.register({
286
+ topic: AXP_REALTIME_TOPIC_BULK_PROGRESS,
287
+ handle: async (envelope) => {
288
+ const payload = envelope.payload;
289
+ if (!payload?.executionId?.trim()) {
290
+ return;
291
+ }
292
+ this.bulkProgress?.notify(payload);
293
+ },
294
+ });
295
+ }
296
+ //#region ---- Wake / network resume ----
297
+ bindWakeListeners() {
298
+ if (this.wakeListenersBound) {
299
+ return;
300
+ }
301
+ this.wakeListenersBound = true;
302
+ this.document.addEventListener('visibilitychange', this.onVisibilityResume);
303
+ this.document.defaultView?.addEventListener('online', this.onNetworkResume);
304
+ }
305
+ unbindWakeListeners() {
306
+ if (!this.wakeListenersBound) {
307
+ return;
308
+ }
309
+ this.wakeListenersBound = false;
310
+ this.document.removeEventListener('visibilitychange', this.onVisibilityResume);
311
+ this.document.defaultView?.removeEventListener('online', this.onNetworkResume);
312
+ }
313
+ resumeIfAuthorized() {
314
+ if (!this.session.isAuthorized || !this.session.hasSessionCredentials()) {
315
+ return;
316
+ }
317
+ if (this.socket?.connected) {
318
+ return;
319
+ }
320
+ this.connect();
321
+ }
257
322
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPRealtimeConnectionService, deps: [{ token: AXP_REALTIME_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
258
323
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPRealtimeConnectionService }); }
259
324
  }
@@ -660,5 +725,5 @@ function presenceDurationBucket(ms) {
660
725
  * Generated bundle index. Do not edit.
661
726
  */
662
727
 
663
- export { AXPRealtimeConnectionPort, AXPRealtimeConnectionService, AXPRealtimeDispatcherService, AXPUserPresenceIdleService, AXPUserPresenceService, AXP_REALTIME_CONFIG, AXP_REALTIME_EMIT_TYPING, AXP_REALTIME_PRESENCE_LEAVE, AXP_REALTIME_PRESENCE_SET, AXP_REALTIME_SOCKET_EVENT, AXP_REALTIME_SUBSCRIBE_CONVERSATION, AXP_REALTIME_SUBSCRIBE_PRESENCE, AXP_REALTIME_TOPIC_CONVERSATION_CALL, AXP_REALTIME_TOPIC_CONVERSATION_MESSAGE, AXP_REALTIME_TOPIC_CONVERSATION_TYPING, AXP_REALTIME_TOPIC_ENTITY_MUTATION, AXP_REALTIME_TOPIC_HANDLER, AXP_REALTIME_TOPIC_INBOX_REFRESH, AXP_REALTIME_TOPIC_USER_PRESENCE, AXP_REALTIME_UNSUBSCRIBE_CONVERSATION, AXP_REALTIME_UNSUBSCRIBE_PRESENCE, AXP_USER_PRESENCE_IDLE_MS, isWatchablePresenceUserId, parseUserPresencePayload, presenceDurationBucket, provideRealtime, resolveRealtimeSocketUrl };
728
+ export { AXPRealtimeConnectionPort, AXPRealtimeConnectionService, AXPRealtimeDispatcherService, AXPUserPresenceIdleService, AXPUserPresenceService, AXP_REALTIME_CONFIG, AXP_REALTIME_EMIT_TYPING, AXP_REALTIME_PRESENCE_LEAVE, AXP_REALTIME_PRESENCE_SET, AXP_REALTIME_SOCKET_EVENT, AXP_REALTIME_SUBSCRIBE_CONVERSATION, AXP_REALTIME_SUBSCRIBE_PRESENCE, AXP_REALTIME_TOPIC_BACKGROUND_JOB_TRAY_REFRESH, AXP_REALTIME_TOPIC_BULK_PROGRESS, AXP_REALTIME_TOPIC_CONVERSATION_CALL, AXP_REALTIME_TOPIC_CONVERSATION_MESSAGE, AXP_REALTIME_TOPIC_CONVERSATION_TYPING, AXP_REALTIME_TOPIC_ENTITY_MUTATION, AXP_REALTIME_TOPIC_HANDLER, AXP_REALTIME_TOPIC_INBOX_REFRESH, AXP_REALTIME_TOPIC_USER_PRESENCE, AXP_REALTIME_UNSUBSCRIBE_CONVERSATION, AXP_REALTIME_UNSUBSCRIBE_PRESENCE, AXP_USER_PRESENCE_IDLE_MS, isWatchablePresenceUserId, parseUserPresencePayload, presenceDurationBucket, provideRealtime, resolveRealtimeSocketUrl };
664
729
  //# sourceMappingURL=acorex-platform-framework-client-realtime.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"acorex-platform-framework-client-realtime.mjs","sources":["../../../../../libs/framework/client/realtime/src/lib/realtime.types.ts","../../../../../libs/framework/client/realtime/src/lib/realtime.topics.ts","../../../../../libs/framework/client/realtime/src/lib/realtime-url.util.ts","../../../../../libs/framework/client/realtime/src/lib/tokens.ts","../../../../../libs/framework/client/realtime/src/lib/realtime-dispatcher.service.ts","../../../../../libs/framework/client/realtime/src/lib/realtime-connection.port.ts","../../../../../libs/framework/client/realtime/src/lib/realtime-connection.service.ts","../../../../../libs/framework/client/realtime/src/lib/presence-idle.constants.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence.util.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence.service.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence-idle.service.ts","../../../../../libs/framework/client/realtime/src/lib/realtime.providers.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence.types.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence-duration.util.ts","../../../../../libs/framework/client/realtime/src/acorex-platform-framework-client-realtime.ts"],"sourcesContent":["//#region ---- Client realtime types ----\n\nexport interface AXPRealtimeAudience {\n userIds?: string[];\n // TODO(realtime): See server realtime.types.ts — generic refType/refId scopes.\n conversationId?: string;\n /** When true, deliver to all connected users in the envelope tenant. */\n tenant?: boolean;\n}\n\nexport interface AXPRealtimeEnvelope {\n topic: string;\n tenantId: string;\n audience: AXPRealtimeAudience;\n payload: unknown;\n correlationId?: string;\n emittedAt: string;\n}\n\nexport interface AXPRealtimeInboxRefreshPayload {\n deliveryId?: string;\n deliveryIds?: string[];\n /** Optional hint so clients can apply deletes/archives without a fetch. */\n op?: 'created' | 'updated' | 'deleted' | 'archived';\n}\n\nexport interface AXPRealtimeConversationMessagePayload {\n conversationId: string;\n messageId: string;\n op: 'created' | 'updated' | 'deleted';\n /** Optional entity snapshot so clients can skip a follow-up GET. */\n message?: Record<string, unknown>;\n}\n\nexport interface AXPRealtimeConversationTypingPayload {\n conversationId: string;\n userId: string;\n userName?: string;\n active: boolean;\n}\n\nexport type AXPRealtimeConversationCallAction =\n | 'invite'\n | 'ring'\n | 'accept'\n | 'decline'\n | 'cancel'\n | 'end';\n\nexport type AXPRealtimeConversationCallMedia = 'voice' | 'video';\n\n/** Built-in realtime signaling for chat calls (media joins via RTC when configured). */\nexport interface AXPRealtimeConversationCallPayload {\n conversationId: string;\n action: AXPRealtimeConversationCallAction;\n media: AXPRealtimeConversationCallMedia;\n /** Caller / actor user id. */\n fromUserId: string;\n fromUserName?: string;\n /** Optional call correlation id shared across invite → accept. */\n callId?: string;\n}\n\nexport interface AXPRealtimeEntityMutationPayload {\n entityName: string;\n operation: 'created' | 'updated' | 'deleted';\n id?: string;\n /** True when the mutation originated from a server bulk command fan-out. */\n bulk?: boolean;\n /** Number of successfully mutated records in a bulk operation. */\n count?: number;\n bulkExecutionId?: string;\n}\n\nexport type AXPRealtimeUserPresenceStatus = 'online' | 'offline' | 'away' | 'busy';\nexport type AXPRealtimeUserPresenceSource = 'auto' | 'manual';\n\nexport interface AXPRealtimeUserPresencePayload {\n userId: string;\n status: AXPRealtimeUserPresenceStatus;\n lastSeen?: string;\n since?: string;\n source?: AXPRealtimeUserPresenceSource;\n}\n\nexport interface AXPRealtimeUserPresenceSnapshotItem {\n userId: string;\n status: AXPRealtimeUserPresenceStatus;\n lastSeen?: string;\n since?: string;\n source?: AXPRealtimeUserPresenceSource;\n}\n\nexport interface AXPRealtimePresenceSetResult {\n ok: boolean;\n reason?: string;\n item?: AXPRealtimeUserPresenceSnapshotItem;\n}\n\nexport interface AXPRealtimePresenceSubscribeResult {\n ok: boolean;\n reason?: string;\n items?: AXPRealtimeUserPresenceSnapshotItem[];\n}\n\nexport interface AXPRealtimeConfig {\n /**\n * Socket.IO namespace URL, e.g. `http://localhost:5500/realtime`.\n * Derived from API baseUrl when omitted (strip trailing `/api`).\n */\n url?: string;\n /** When false, connection is not started automatically. Default true. */\n autoConnect?: boolean;\n}\n\nexport type AXPRealtimeTopicHandler = (envelope: AXPRealtimeEnvelope) => void | Promise<void>;\n\nexport interface AXPRealtimeTopicHandlerRegistration {\n topic: string;\n handle: AXPRealtimeTopicHandler;\n}\n\n//#endregion\n","//#region ---- Client topic constants (mirror server) ----\n\nexport const AXP_REALTIME_TOPIC_INBOX_REFRESH = 'inbox.refresh';\nexport const AXP_REALTIME_TOPIC_CONVERSATION_MESSAGE = 'conversation.message';\nexport const AXP_REALTIME_TOPIC_CONVERSATION_TYPING = 'conversation.typing';\nexport const AXP_REALTIME_TOPIC_CONVERSATION_CALL = 'conversation.call';\nexport const AXP_REALTIME_TOPIC_ENTITY_MUTATION = 'entity.mutation';\nexport const AXP_REALTIME_TOPIC_USER_PRESENCE = 'user.presence';\n\nexport const AXP_REALTIME_SOCKET_EVENT = 'realtime';\nexport const AXP_REALTIME_SUBSCRIBE_CONVERSATION = 'subscribe.conversation';\nexport const AXP_REALTIME_UNSUBSCRIBE_CONVERSATION = 'unsubscribe.conversation';\nexport const AXP_REALTIME_SUBSCRIBE_PRESENCE = 'subscribe.presence';\nexport const AXP_REALTIME_UNSUBSCRIBE_PRESENCE = 'unsubscribe.presence';\nexport const AXP_REALTIME_PRESENCE_LEAVE = 'presence.leave';\nexport const AXP_REALTIME_PRESENCE_SET = 'presence.set';\nexport const AXP_REALTIME_EMIT_TYPING = 'conversation.typing.emit';\n\n//#endregion\n","//#region ---- Realtime URL helpers ----\n\n/**\n * Builds Socket.IO namespace URL from an HTTP API baseUrl (`…/api` → `…/realtime`).\n */\nexport function resolveRealtimeSocketUrl(apiBaseUrl: string): string {\n const trimmed = apiBaseUrl.trim().replace(/\\/+$/, '');\n const withoutApi = trimmed.endsWith('/api') ? trimmed.slice(0, -4) : trimmed;\n return `${withoutApi}/realtime`;\n}\n\n//#endregion\n","import { InjectionToken } from '@angular/core';\nimport type {\n AXPRealtimeConfig,\n AXPRealtimeTopicHandlerRegistration,\n} from './realtime.types';\n\n//#region ---- DI tokens ----\n\nexport const AXP_REALTIME_CONFIG = new InjectionToken<AXPRealtimeConfig>('AXP_REALTIME_CONFIG');\n\nexport const AXP_REALTIME_TOPIC_HANDLER = new InjectionToken<AXPRealtimeTopicHandlerRegistration>(\n 'AXP_REALTIME_TOPIC_HANDLER',\n);\n\n//#endregion\n","import { Inject, Injectable, Optional } from '@angular/core';\nimport { AXP_REALTIME_TOPIC_HANDLER } from './tokens';\nimport type {\n AXPRealtimeEnvelope,\n AXPRealtimeTopicHandlerRegistration,\n} from './realtime.types';\n\n//#region ---- Topic dispatcher ----\n\n@Injectable()\nexport class AXPRealtimeDispatcherService {\n private readonly handlers = new Map<string, AXPRealtimeTopicHandlerRegistration[]>();\n\n constructor(\n @Optional()\n @Inject(AXP_REALTIME_TOPIC_HANDLER)\n registrations?: AXPRealtimeTopicHandlerRegistration[] | AXPRealtimeTopicHandlerRegistration,\n ) {\n const list = !registrations\n ? []\n : Array.isArray(registrations)\n ? registrations\n : [registrations];\n for (const registration of list) {\n this.register(registration);\n }\n }\n\n register(registration: AXPRealtimeTopicHandlerRegistration): void {\n const topic = registration.topic?.trim();\n if (!topic || typeof registration.handle !== 'function') {\n return;\n }\n const existing = this.handlers.get(topic) ?? [];\n existing.push(registration);\n this.handlers.set(topic, existing);\n }\n\n async dispatch(envelope: AXPRealtimeEnvelope): Promise<void> {\n const topic = envelope?.topic?.trim();\n if (!topic) {\n return;\n }\n const list = this.handlers.get(topic);\n if (!list?.length) {\n return;\n }\n for (const registration of list) {\n await registration.handle(envelope);\n }\n }\n}\n\n//#endregion\n","import type { Observable } from 'rxjs';\n\n//#region ---- Connection port ----\n\nexport type AXPRealtimeConnectionStatus = 'connected' | 'connecting' | 'disconnected';\n\n/**\n * Always-on realtime connection used by the app shell.\n * Built-in implementation uses Socket.IO; alternate backends may replace this port.\n */\nexport abstract class AXPRealtimeConnectionPort {\n abstract readonly connectionStatus$: Observable<AXPRealtimeConnectionStatus>;\n\n abstract connect(): void;\n abstract disconnect(): void;\n abstract reconnectWithCurrentToken(): void;\n abstract isSocketConnected(): boolean;\n abstract subscribeConversation(conversationId: string): void;\n abstract unsubscribeConversation(conversationId: string): void;\n abstract emitConversationTyping(conversationId: string, active: boolean): void;\n}\n\n//#endregion\n","import { Inject, Injectable, OnDestroy, Optional, inject } from '@angular/core';\nimport { AXPSessionService, AXPSessionStatus } from '@acorex-platform/framework-client/auth';\nimport { io, type Socket } from 'socket.io-client';\nimport { BehaviorSubject, Subscription } from 'rxjs';\nimport {\n AXPRealtimeConnectionPort,\n type AXPRealtimeConnectionStatus,\n} from './realtime-connection.port';\nimport { AXPRealtimeDispatcherService } from './realtime-dispatcher.service';\nimport {\n AXP_REALTIME_EMIT_TYPING,\n AXP_REALTIME_PRESENCE_LEAVE,\n AXP_REALTIME_PRESENCE_SET,\n AXP_REALTIME_SOCKET_EVENT,\n AXP_REALTIME_SUBSCRIBE_CONVERSATION,\n AXP_REALTIME_SUBSCRIBE_PRESENCE,\n AXP_REALTIME_UNSUBSCRIBE_CONVERSATION,\n AXP_REALTIME_UNSUBSCRIBE_PRESENCE,\n} from './realtime.topics';\nimport type {\n AXPRealtimeConfig,\n AXPRealtimeEnvelope,\n AXPRealtimePresenceSetResult,\n AXPRealtimePresenceSubscribeResult,\n AXPRealtimeUserPresenceSnapshotItem,\n} from './realtime.types';\nimport { AXP_REALTIME_CONFIG } from './tokens';\n\n//#region ---- Socket.IO connection (built-in) ----\n\n/**\n * Built-in always-on realtime connection via Socket.IO.\n */\n@Injectable()\nexport class AXPRealtimeConnectionService extends AXPRealtimeConnectionPort implements OnDestroy {\n private readonly session = inject(AXPSessionService);\n private readonly dispatcher = inject(AXPRealtimeDispatcherService);\n private socket: Socket | null = null;\n private statusSub: Subscription | null = null;\n private readonly joinedConversations = new Set<string>();\n private readonly connectionStatusSubject = new BehaviorSubject<AXPRealtimeConnectionStatus>(\n 'disconnected',\n );\n\n /** Latest Socket.IO connection state for feature modules (e.g. chat). */\n override readonly connectionStatus$ = this.connectionStatusSubject.asObservable();\n\n constructor(\n @Optional()\n @Inject(AXP_REALTIME_CONFIG)\n private readonly config: AXPRealtimeConfig | null,\n ) {\n super();\n if (config?.autoConnect === false) {\n return;\n }\n this.statusSub = this.session.status$.subscribe((status) => {\n if (status === AXPSessionStatus.Authorized) {\n this.connect();\n } else {\n void this.leaveAndDisconnect();\n }\n });\n }\n\n ngOnDestroy(): void {\n this.statusSub?.unsubscribe();\n this.disconnect();\n }\n\n /** Sign-out: tell the server to skip grace, then close the socket. */\n async leaveAndDisconnect(): Promise<void> {\n await this.leavePresence();\n this.disconnect();\n }\n\n connect(): void {\n const url = this.config?.url?.trim();\n if (!url || !this.session.hasSessionCredentials()) {\n this.connectionStatusSubject.next('disconnected');\n return;\n }\n\n if (this.socket?.connected) {\n return;\n }\n\n // Avoid tearing down a socket that is still handshaking (duplicate connect calls).\n if (this.socket && !this.socket.connected) {\n return;\n }\n\n this.connectionStatusSubject.next('connecting');\n\n // Auth uses HttpOnly access cookie (same-site / proxied); no token in JS.\n this.socket = io(url, {\n transports: ['websocket', 'polling'],\n withCredentials: true,\n autoConnect: true,\n reconnection: true,\n });\n\n this.socket.on(AXP_REALTIME_SOCKET_EVENT, (envelope: AXPRealtimeEnvelope) => {\n void this.dispatcher.dispatch(envelope);\n });\n\n this.socket.on('connect', () => {\n this.connectionStatusSubject.next('connected');\n for (const conversationId of this.joinedConversations) {\n this.socket?.emit(AXP_REALTIME_SUBSCRIBE_CONVERSATION, { conversationId });\n }\n });\n\n this.socket.on('disconnect', () => {\n this.connectionStatusSubject.next('disconnected');\n });\n\n this.socket.on('connect_error', () => {\n this.connectionStatusSubject.next('disconnected');\n });\n }\n\n override disconnect(): void {\n if (this.socket) {\n this.socket.removeAllListeners();\n this.socket.disconnect();\n this.socket = null;\n }\n this.connectionStatusSubject.next('disconnected');\n }\n\n /** Re-auth with the latest access token (e.g. after refresh). */\n override reconnectWithCurrentToken(): void {\n this.disconnect();\n this.connect();\n }\n\n /** Whether the underlying Socket.IO client is connected. */\n override isSocketConnected(): boolean {\n return this.socket?.connected === true;\n }\n\n override subscribeConversation(conversationId: string): void {\n const id = conversationId?.trim();\n if (!id) {\n return;\n }\n this.joinedConversations.add(id);\n this.socket?.emit(AXP_REALTIME_SUBSCRIBE_CONVERSATION, { conversationId: id });\n }\n\n override unsubscribeConversation(conversationId: string): void {\n const id = conversationId?.trim();\n if (!id) {\n return;\n }\n this.joinedConversations.delete(id);\n this.socket?.emit(AXP_REALTIME_UNSUBSCRIBE_CONVERSATION, { conversationId: id });\n }\n\n override emitConversationTyping(conversationId: string, active: boolean): void {\n const id = conversationId?.trim();\n if (!id || !this.socket?.connected) {\n return;\n }\n this.socket.emit(AXP_REALTIME_EMIT_TYPING, { conversationId: id, active });\n }\n\n subscribePresence(userIds: readonly string[]): Promise<AXPRealtimeUserPresenceSnapshotItem[]> {\n const ids = userIds.map((id) => id.trim()).filter(Boolean);\n if (ids.length === 0 || !this.socket?.connected) {\n return Promise.resolve([]);\n }\n\n return new Promise((resolve) => {\n this.socket?.emit(\n AXP_REALTIME_SUBSCRIBE_PRESENCE,\n { userIds: ids },\n (result: AXPRealtimePresenceSubscribeResult | undefined) => {\n resolve(Array.isArray(result?.items) ? result.items : []);\n },\n );\n });\n }\n\n unsubscribePresence(userIds: readonly string[]): void {\n const ids = userIds.map((id) => id.trim()).filter(Boolean);\n if (ids.length === 0) {\n return;\n }\n this.socket?.emit(AXP_REALTIME_UNSUBSCRIBE_PRESENCE, { userIds: ids });\n }\n\n leavePresence(): Promise<void> {\n if (!this.socket?.connected) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, 400);\n this.socket?.emit(AXP_REALTIME_PRESENCE_LEAVE, {}, () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n setPresence(\n status: 'online' | 'away' | 'busy',\n source: 'auto' | 'manual' = 'manual',\n ): Promise<AXPRealtimeUserPresenceSnapshotItem | undefined> {\n if (!this.socket?.connected) {\n return Promise.resolve(undefined);\n }\n\n return new Promise((resolve) => {\n this.socket?.emit(\n AXP_REALTIME_PRESENCE_SET,\n { status, source },\n (result: AXPRealtimePresenceSetResult | undefined) => {\n resolve(result?.ok ? result.item : undefined);\n },\n );\n });\n }\n}\n\n//#endregion\n","//#region ----- Constants -----\n\n/** Idle without input before automatic Away. Keep in sync with server `AXP_USER_PRESENCE_IDLE_MS`. */\nexport const AXP_USER_PRESENCE_IDLE_MS = 5 * 60_000;\n\n//#endregion\n","import type { AXPRealtimeUserPresencePayload, AXPRealtimeUserPresenceStatus } from '../realtime.types';\nimport type { AXPUserPresence, AXPUserPresenceSource } from './user-presence.types';\n\n//#region ----- Presence helpers -----\n\nconst PRESENCE_STATUSES: readonly AXPRealtimeUserPresenceStatus[] = ['online', 'offline', 'away', 'busy'];\n\nexport function isWatchablePresenceUserId(userId: string | null | undefined): boolean {\n const id = userId?.trim() ?? '';\n if (!id || id === 'system') {\n return false;\n }\n return !id.startsWith('assist-');\n}\n\nexport function parseUserPresencePayload(payload: unknown): AXPUserPresence | null {\n if (!payload || typeof payload !== 'object') {\n return null;\n }\n\n const raw = payload as AXPRealtimeUserPresencePayload;\n const userId = raw.userId?.trim();\n if (!userId) {\n return null;\n }\n\n const status = PRESENCE_STATUSES.includes(raw.status) ? raw.status : 'offline';\n const lastSeen = typeof raw.lastSeen === 'string' && raw.lastSeen.trim() ? raw.lastSeen.trim() : undefined;\n const since = typeof raw.since === 'string' && raw.since.trim() ? raw.since.trim() : undefined;\n const source: AXPUserPresenceSource | undefined =\n raw.source === 'auto' || raw.source === 'manual' ? raw.source : undefined;\n return {\n userId,\n status,\n ...(lastSeen ? { lastSeen } : {}),\n ...(since ? { since } : {}),\n ...(source ? { source } : {}),\n };\n}\n\n//#endregion\n","import { Injectable, inject } from '@angular/core';\nimport { BehaviorSubject, Observable, Subject } from 'rxjs';\nimport { AXPRealtimeConnectionService } from '../realtime-connection.service';\nimport type { AXPUserPresence } from './user-presence.types';\nimport { isWatchablePresenceUserId, parseUserPresencePayload } from './user-presence.util';\n\n//#region ----- User presence store -----\n\nconst FLUSH_DEBOUNCE_MS = 40;\n\n@Injectable({ providedIn: 'root' })\nexport class AXPUserPresenceService {\n //#region ----- Services & Dependencies -----\n\n private readonly connection = inject(AXPRealtimeConnectionService, { optional: true });\n\n //#endregion\n\n //#region ----- State -----\n\n private readonly presenceByUserId = new Map<string, AXPUserPresence>();\n private readonly watchCounts = new Map<string, number>();\n private readonly subjects = new Map<string, BehaviorSubject<AXPUserPresence>>();\n private readonly updatesSubject = new Subject<AXPUserPresence>();\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private pendingSubscribe = new Set<string>();\n private pendingUnsubscribe = new Set<string>();\n\n readonly updates$ = this.updatesSubject.asObservable();\n\n //#endregion\n\n constructor() {\n this.connection?.connectionStatus$.subscribe((status) => {\n if (status === 'connected') {\n this.resubscribeAll();\n }\n });\n }\n\n //#region ----- Public API -----\n\n get(userId: string): AXPUserPresence | undefined {\n const id = userId?.trim();\n if (!id) {\n return undefined;\n }\n return this.presenceByUserId.get(id);\n }\n\n presence$(userId: string): Observable<AXPUserPresence> {\n const id = userId?.trim();\n const fallback: AXPUserPresence = { userId: id, status: 'offline' };\n if (!id) {\n return new BehaviorSubject(fallback).asObservable();\n }\n\n let subject = this.subjects.get(id);\n if (!subject) {\n subject = new BehaviorSubject<AXPUserPresence>(this.presenceByUserId.get(id) ?? fallback);\n this.subjects.set(id, subject);\n }\n return subject.asObservable();\n }\n\n watch(userId: string): void {\n if (!isWatchablePresenceUserId(userId)) {\n return;\n }\n const id = userId.trim();\n const next = (this.watchCounts.get(id) ?? 0) + 1;\n this.watchCounts.set(id, next);\n if (next === 1) {\n this.pendingUnsubscribe.delete(id);\n this.pendingSubscribe.add(id);\n this.scheduleFlush();\n }\n }\n\n watchMany(userIds: readonly string[]): void {\n for (const userId of userIds) {\n this.watch(userId);\n }\n }\n\n /** Watch only if this user is not already in the local watch set. */\n ensureWatch(userId: string): void {\n const id = userId?.trim();\n if (!id || (this.watchCounts.get(id) ?? 0) > 0) {\n return;\n }\n this.watch(id);\n }\n\n ensureWatchMany(userIds: readonly string[]): void {\n for (const userId of userIds) {\n this.ensureWatch(userId);\n }\n }\n\n unwatch(userId: string): void {\n const id = userId?.trim();\n if (!id) {\n return;\n }\n const current = this.watchCounts.get(id) ?? 0;\n if (current <= 1) {\n this.watchCounts.delete(id);\n this.pendingSubscribe.delete(id);\n this.pendingUnsubscribe.add(id);\n this.scheduleFlush();\n return;\n }\n this.watchCounts.set(id, current - 1);\n }\n\n applySnapshot(items: readonly AXPUserPresence[]): void {\n for (const item of items) {\n this.applyPresence(item);\n }\n }\n\n applyEnvelopePayload(payload: unknown): void {\n const parsed = parseUserPresencePayload(payload);\n if (parsed) {\n this.applyPresence(parsed);\n }\n }\n\n async setAvailability(\n status: 'online' | 'away' | 'busy',\n source: 'auto' | 'manual' = 'manual',\n ): Promise<void> {\n const item = await this.connection?.setPresence(status, source);\n if (item) {\n this.applyPresence(item);\n }\n }\n\n //#endregion\n\n //#region ----- Store updates -----\n\n private applyPresence(presence: AXPUserPresence): void {\n const previous = this.presenceByUserId.get(presence.userId);\n if (\n previous &&\n previous.status === presence.status &&\n previous.lastSeen === presence.lastSeen &&\n previous.since === presence.since\n ) {\n return;\n }\n\n this.presenceByUserId.set(presence.userId, presence);\n const subject = this.subjects.get(presence.userId);\n if (subject && !subject.closed) {\n subject.next(presence);\n }\n this.updatesSubject.next(presence);\n }\n\n private scheduleFlush(): void {\n if (this.flushTimer) {\n return;\n }\n this.flushTimer = setTimeout(() => {\n this.flushTimer = null;\n void this.flush();\n }, FLUSH_DEBOUNCE_MS);\n }\n\n private async flush(): Promise<void> {\n const subscribeIds = Array.from(this.pendingSubscribe);\n const unsubscribeIds = Array.from(this.pendingUnsubscribe);\n this.pendingSubscribe.clear();\n this.pendingUnsubscribe.clear();\n\n if (unsubscribeIds.length > 0) {\n this.connection?.unsubscribePresence(unsubscribeIds);\n }\n if (subscribeIds.length === 0) {\n return;\n }\n\n const items = (await this.connection?.subscribePresence(subscribeIds)) ?? [];\n this.applySnapshot(items);\n }\n\n private resubscribeAll(): void {\n const watched = Array.from(this.watchCounts.keys());\n if (watched.length === 0) {\n return;\n }\n this.pendingUnsubscribe.clear();\n for (const id of watched) {\n this.pendingSubscribe.add(id);\n }\n this.scheduleFlush();\n }\n\n //#endregion\n}\n\n//#endregion\n","import { DOCUMENT } from '@angular/common';\nimport { DestroyRef, Injectable, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { AXPSessionService, AXPSessionStatus } from '@acorex-platform/framework-client/auth';\nimport { AXP_USER_PRESENCE_IDLE_MS } from '../presence-idle.constants';\nimport { AXPUserPresenceService } from './user-presence.service';\n\n//#region ----- Automatic away from idle -----\n\nconst IDLE_CHECK_MS = 15_000;\nconst ACTIVITY_THROTTLE_MS = 1_000;\n\n@Injectable({ providedIn: 'root' })\nexport class AXPUserPresenceIdleService {\n //#region ----- Services & Dependencies -----\n\n private readonly document = inject(DOCUMENT);\n private readonly session = inject(AXPSessionService);\n private readonly presence = inject(AXPUserPresenceService);\n private readonly destroyRef = inject(DestroyRef);\n\n //#endregion\n\n //#region ----- State -----\n\n private lastActivityAt = Date.now();\n private lastActivityEmitAt = 0;\n private idle = false;\n private checkTimer: ReturnType<typeof setInterval> | null = null;\n private started = false;\n\n //#endregion\n\n constructor() {\n this.session.status$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((status) => {\n if (status === AXPSessionStatus.Authorized) {\n this.start();\n return;\n }\n this.stop();\n });\n }\n\n //#region ----- Lifecycle -----\n\n start(): void {\n if (this.started) {\n return;\n }\n this.started = true;\n this.lastActivityAt = Date.now();\n this.idle = false;\n const target = this.document.defaultView ?? this.document;\n target.addEventListener('mousemove', this.onActivity, { passive: true });\n target.addEventListener('keydown', this.onActivity, { passive: true });\n target.addEventListener('mousedown', this.onActivity, { passive: true });\n target.addEventListener('touchstart', this.onActivity, { passive: true });\n this.document.addEventListener('visibilitychange', this.onVisibility);\n this.checkTimer = setInterval(() => this.checkIdle(), IDLE_CHECK_MS);\n }\n\n stop(): void {\n if (!this.started) {\n return;\n }\n this.started = false;\n this.idle = false;\n const target = this.document.defaultView ?? this.document;\n target.removeEventListener('mousemove', this.onActivity);\n target.removeEventListener('keydown', this.onActivity);\n target.removeEventListener('mousedown', this.onActivity);\n target.removeEventListener('touchstart', this.onActivity);\n this.document.removeEventListener('visibilitychange', this.onVisibility);\n if (this.checkTimer) {\n clearInterval(this.checkTimer);\n this.checkTimer = null;\n }\n }\n\n //#endregion\n\n //#region ----- Activity -----\n\n private readonly onActivity = (): void => {\n const now = Date.now();\n this.lastActivityAt = now;\n if (now - this.lastActivityEmitAt < ACTIVITY_THROTTLE_MS) {\n return;\n }\n this.lastActivityEmitAt = now;\n if (this.idle) {\n this.idle = false;\n void this.presence.setAvailability('online', 'auto');\n }\n };\n\n private readonly onVisibility = (): void => {\n if (!this.document.hidden) {\n this.onActivity();\n }\n };\n\n private checkIdle(): void {\n if (!this.started || this.idle) {\n return;\n }\n if (Date.now() - this.lastActivityAt < AXP_USER_PRESENCE_IDLE_MS) {\n return;\n }\n this.idle = true;\n void this.presence.setAvailability('away', 'auto');\n }\n\n //#endregion\n}\n\n//#endregion\n","import {\n inject,\n makeEnvironmentProviders,\n type EnvironmentProviders,\n} from '@angular/core';\nimport {\n AXP_APP_STARTUP_PRIORITY,\n provideAppStartUpTask,\n} from '@acorex-platform/framework-client/core';\nimport { provideCommandSetups } from '@acorex-platform/framework-client/runtime';\nimport { PRESENCE_SET_AVAILABILITY } from '@acorex-platform/framework-shared/runtime';\nimport { AXPUserPresenceIdleService } from './presence/user-presence-idle.service';\nimport { AXPUserPresenceService } from './presence/user-presence.service';\nimport { AXPRealtimeConnectionPort } from './realtime-connection.port';\nimport { AXPRealtimeConnectionService } from './realtime-connection.service';\nimport { AXPRealtimeDispatcherService } from './realtime-dispatcher.service';\nimport type { AXPRealtimeConfig } from './realtime.types';\nimport { resolveRealtimeSocketUrl } from './realtime-url.util';\nimport { AXP_REALTIME_TOPIC_USER_PRESENCE } from './realtime.topics';\nimport { AXP_REALTIME_CONFIG } from './tokens';\n\n//#region ---- provideRealtime ----\n\nexport interface AXPProvideRealtimeOptions extends AXPRealtimeConfig {\n apiBaseUrl?: string;\n /**\n * Always-on backend. Default `builtin` (Socket.IO).\n * Call/media uses extensions/rtc when configured — not this switch.\n */\n backend?: 'builtin';\n}\n\n/**\n * Registers built-in always-on realtime (Socket.IO) + topic dispatcher.\n */\nexport function provideRealtime(config: AXPProvideRealtimeOptions = {}): EnvironmentProviders {\n const backend = config.backend ?? 'builtin';\n if (backend !== 'builtin') {\n throw new Error(`Unsupported realtime backend '${String(backend)}'. Use 'builtin'.`);\n }\n\n const url =\n config.url?.trim() ||\n (config.apiBaseUrl?.trim() ? resolveRealtimeSocketUrl(config.apiBaseUrl) : undefined);\n\n return makeEnvironmentProviders([\n {\n provide: AXP_REALTIME_CONFIG,\n useValue: {\n autoConnect: config.autoConnect !== false,\n url,\n } satisfies AXPRealtimeConfig,\n },\n AXPRealtimeDispatcherService,\n AXPRealtimeConnectionService,\n {\n provide: AXPRealtimeConnectionPort,\n useExisting: AXPRealtimeConnectionService,\n },\n provideCommandSetups([\n {\n key: PRESENCE_SET_AVAILABILITY,\n command: () =>\n import('./presence/set-presence-availability.command').then((c) => c.AXPSetPresenceAvailabilityCommand),\n },\n ]),\n provideAppStartUpTask(() => {\n inject(AXPUserPresenceIdleService);\n return {\n name: 'user-presence-idle',\n priority: AXP_APP_STARTUP_PRIORITY.realtimeSubscriptions,\n run: async () => undefined,\n };\n }),\n provideAppStartUpTask(() => {\n const dispatcher = inject(AXPRealtimeDispatcherService);\n const presence = inject(AXPUserPresenceService);\n return {\n name: 'user-presence-handler',\n priority: AXP_APP_STARTUP_PRIORITY.realtimeHandlers,\n run: async () => {\n dispatcher.register({\n topic: AXP_REALTIME_TOPIC_USER_PRESENCE,\n handle: (envelope) => {\n presence.applyEnvelopePayload(envelope.payload);\n },\n });\n },\n };\n }),\n provideAppStartUpTask(() => {\n const connection = inject(AXPRealtimeConnectionPort);\n return {\n name: 'realtime-connect',\n priority: AXP_APP_STARTUP_PRIORITY.realtimeConnect,\n run: async () => {\n // Connection lifecycle is owned by the connection service (session.status$).\n // Eagerly invoke connect once so an already-authenticated session connects on bootstrap.\n connection.connect();\n },\n };\n }),\n ]);\n}\n\n//#endregion\n","import type { AXPRealtimeUserPresenceStatus, AXPRealtimeUserPresenceSource } from '../realtime.types';\n\n//#region ----- Types -----\n\nexport type AXPUserPresenceStatus = AXPRealtimeUserPresenceStatus;\nexport type AXPUserPresenceSource = AXPRealtimeUserPresenceSource;\n\nexport interface AXPUserPresence {\n userId: string;\n status: AXPUserPresenceStatus;\n lastSeen?: string;\n since?: string;\n source?: AXPUserPresenceSource;\n}\n\nexport interface AXPUserPresenceSetInput {\n status: 'online' | 'away' | 'busy';\n source?: AXPUserPresenceSource;\n}\n\n//#endregion\n","//#region ----- Presence duration tooltip -----\n\nexport type AXPPresenceDurationBucket = {\n key:\n | 'duration.less-than-a-minute'\n | 'duration.one-minute'\n | 'duration.minutes'\n | 'duration.one-hour'\n | 'duration.hours'\n | 'duration.one-day'\n | 'duration.days';\n params?: { count: number };\n};\n\nexport function presenceDurationBucket(ms: number): AXPPresenceDurationBucket {\n const elapsed = Math.max(0, ms);\n if (elapsed < 60_000) {\n return { key: 'duration.less-than-a-minute' };\n }\n\n const minutes = Math.floor(elapsed / 60_000);\n if (minutes < 60) {\n return minutes === 1 ? { key: 'duration.one-minute' } : { key: 'duration.minutes', params: { count: minutes } };\n }\n\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return hours === 1 ? { key: 'duration.one-hour' } : { key: 'duration.hours', params: { count: hours } };\n }\n\n const days = Math.floor(hours / 24);\n return days === 1 ? { key: 'duration.one-day' } : { key: 'duration.days', params: { count: days } };\n}\n\n//#endregion\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acorex-platform-framework-client-realtime.mjs","sources":["../../../../../libs/framework/client/realtime/src/lib/realtime.types.ts","../../../../../libs/framework/client/realtime/src/lib/realtime.topics.ts","../../../../../libs/framework/client/realtime/src/lib/realtime-url.util.ts","../../../../../libs/framework/client/realtime/src/lib/tokens.ts","../../../../../libs/framework/client/realtime/src/lib/realtime-dispatcher.service.ts","../../../../../libs/framework/client/realtime/src/lib/realtime-connection.port.ts","../../../../../libs/framework/client/realtime/src/lib/realtime-connection.service.ts","../../../../../libs/framework/client/realtime/src/lib/presence-idle.constants.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence.util.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence.service.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence-idle.service.ts","../../../../../libs/framework/client/realtime/src/lib/realtime.providers.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence.types.ts","../../../../../libs/framework/client/realtime/src/lib/presence/user-presence-duration.util.ts","../../../../../libs/framework/client/realtime/src/acorex-platform-framework-client-realtime.ts"],"sourcesContent":["//#region ---- Client realtime types ----\n\nexport interface AXPRealtimeAudience {\n userIds?: string[];\n // TODO(realtime): See server realtime.types.ts — generic refType/refId scopes.\n conversationId?: string;\n /** When true, deliver to all connected users in the envelope tenant. */\n tenant?: boolean;\n}\n\nexport interface AXPRealtimeEnvelope {\n topic: string;\n tenantId: string;\n audience: AXPRealtimeAudience;\n payload: unknown;\n correlationId?: string;\n emittedAt: string;\n}\n\nexport interface AXPRealtimeInboxRefreshPayload {\n deliveryId?: string;\n deliveryIds?: string[];\n /** Optional hint so clients can apply deletes/archives without a fetch. */\n op?: 'created' | 'updated' | 'deleted' | 'archived';\n}\n\nexport interface AXPRealtimeBackgroundJobTrayRefreshPayload {\n jobId?: string;\n /**\n * Hint for client tray sync.\n * Prefer applying locally; full list fetch only when the job is missing (e.g. `created`).\n */\n op?: 'created' | 'updated' | 'completed' | 'failed' | 'cancelled' | 'dismissed';\n status?: string;\n progress?: number;\n statusText?: string;\n currentStep?: string;\n supportsProgress?: boolean;\n keepInTrayAfterComplete?: boolean;\n completedAt?: string;\n trayDismissedAt?: string;\n}\n\nexport interface AXPRealtimeConversationMessagePayload {\n conversationId: string;\n messageId: string;\n op: 'created' | 'updated' | 'deleted';\n /** Optional entity snapshot so clients can skip a follow-up GET. */\n message?: Record<string, unknown>;\n}\n\nexport interface AXPRealtimeConversationTypingPayload {\n conversationId: string;\n userId: string;\n userName?: string;\n active: boolean;\n}\n\nexport type AXPRealtimeConversationCallAction =\n | 'invite'\n | 'ring'\n | 'accept'\n | 'decline'\n | 'cancel'\n | 'end';\n\nexport type AXPRealtimeConversationCallMedia = 'voice' | 'video';\n\n/** Built-in realtime signaling for chat calls (media joins via RTC when configured). */\nexport interface AXPRealtimeConversationCallPayload {\n conversationId: string;\n action: AXPRealtimeConversationCallAction;\n media: AXPRealtimeConversationCallMedia;\n /** Caller / actor user id. */\n fromUserId: string;\n fromUserName?: string;\n /** Optional call correlation id shared across invite → accept. */\n callId?: string;\n}\n\nexport interface AXPRealtimeBulkProgressPayload {\n executionId: string;\n entity: string;\n name: string;\n current: number;\n total: number;\n succeeded: number;\n failed: number;\n status: 'running' | 'completed';\n}\n\nexport interface AXPRealtimeEntityMutationPayload {\n entityName: string;\n operation: 'created' | 'updated' | 'deleted';\n id?: string;\n /** True when the mutation originated from a server bulk command fan-out. */\n bulk?: boolean;\n /** Number of successfully mutated records in a bulk operation. */\n count?: number;\n bulkExecutionId?: string;\n}\n\nexport type AXPRealtimeUserPresenceStatus = 'online' | 'offline' | 'away' | 'busy';\nexport type AXPRealtimeUserPresenceSource = 'auto' | 'manual';\n\nexport interface AXPRealtimeUserPresencePayload {\n userId: string;\n status: AXPRealtimeUserPresenceStatus;\n lastSeen?: string;\n since?: string;\n source?: AXPRealtimeUserPresenceSource;\n}\n\nexport interface AXPRealtimeUserPresenceSnapshotItem {\n userId: string;\n status: AXPRealtimeUserPresenceStatus;\n lastSeen?: string;\n since?: string;\n source?: AXPRealtimeUserPresenceSource;\n}\n\nexport interface AXPRealtimePresenceSetResult {\n ok: boolean;\n reason?: string;\n item?: AXPRealtimeUserPresenceSnapshotItem;\n}\n\nexport interface AXPRealtimePresenceSubscribeResult {\n ok: boolean;\n reason?: string;\n items?: AXPRealtimeUserPresenceSnapshotItem[];\n}\n\nexport interface AXPRealtimeConfig {\n /**\n * Socket.IO namespace URL, e.g. `http://localhost:5500/realtime`.\n * Derived from API baseUrl when omitted (strip trailing `/api`).\n */\n url?: string;\n /** When false, connection is not started automatically. Default true. */\n autoConnect?: boolean;\n}\n\nexport type AXPRealtimeTopicHandler = (envelope: AXPRealtimeEnvelope) => void | Promise<void>;\n\nexport interface AXPRealtimeTopicHandlerRegistration {\n topic: string;\n handle: AXPRealtimeTopicHandler;\n}\n\n//#endregion\n","//#region ---- Client topic constants (mirror server) ----\n\nexport const AXP_REALTIME_TOPIC_INBOX_REFRESH = 'inbox.refresh';\nexport const AXP_REALTIME_TOPIC_BACKGROUND_JOB_TRAY_REFRESH = 'background-job.tray.refresh';\nexport const AXP_REALTIME_TOPIC_CONVERSATION_MESSAGE = 'conversation.message';\nexport const AXP_REALTIME_TOPIC_CONVERSATION_TYPING = 'conversation.typing';\nexport const AXP_REALTIME_TOPIC_CONVERSATION_CALL = 'conversation.call';\nexport const AXP_REALTIME_TOPIC_ENTITY_MUTATION = 'entity.mutation';\nexport const AXP_REALTIME_TOPIC_BULK_PROGRESS = 'runtime.bulk.progress';\nexport const AXP_REALTIME_TOPIC_USER_PRESENCE = 'user.presence';\n\nexport const AXP_REALTIME_SOCKET_EVENT = 'realtime';\nexport const AXP_REALTIME_SUBSCRIBE_CONVERSATION = 'subscribe.conversation';\nexport const AXP_REALTIME_UNSUBSCRIBE_CONVERSATION = 'unsubscribe.conversation';\nexport const AXP_REALTIME_SUBSCRIBE_PRESENCE = 'subscribe.presence';\nexport const AXP_REALTIME_UNSUBSCRIBE_PRESENCE = 'unsubscribe.presence';\nexport const AXP_REALTIME_PRESENCE_LEAVE = 'presence.leave';\nexport const AXP_REALTIME_PRESENCE_SET = 'presence.set';\nexport const AXP_REALTIME_EMIT_TYPING = 'conversation.typing.emit';\n\n//#endregion\n","//#region ---- Realtime URL helpers ----\n\n/**\n * Builds Socket.IO namespace URL from an HTTP API baseUrl (`…/api` → `…/realtime`).\n */\nexport function resolveRealtimeSocketUrl(apiBaseUrl: string): string {\n const trimmed = apiBaseUrl.trim().replace(/\\/+$/, '');\n const withoutApi = trimmed.endsWith('/api') ? trimmed.slice(0, -4) : trimmed;\n return `${withoutApi}/realtime`;\n}\n\n//#endregion\n","import { InjectionToken } from '@angular/core';\nimport type {\n AXPRealtimeConfig,\n AXPRealtimeTopicHandlerRegistration,\n} from './realtime.types';\n\n//#region ---- DI tokens ----\n\nexport const AXP_REALTIME_CONFIG = new InjectionToken<AXPRealtimeConfig>('AXP_REALTIME_CONFIG');\n\nexport const AXP_REALTIME_TOPIC_HANDLER = new InjectionToken<AXPRealtimeTopicHandlerRegistration>(\n 'AXP_REALTIME_TOPIC_HANDLER',\n);\n\n//#endregion\n","import { Inject, Injectable, Optional } from '@angular/core';\nimport { AXP_REALTIME_TOPIC_HANDLER } from './tokens';\nimport type {\n AXPRealtimeEnvelope,\n AXPRealtimeTopicHandlerRegistration,\n} from './realtime.types';\n\n//#region ---- Topic dispatcher ----\n\n@Injectable()\nexport class AXPRealtimeDispatcherService {\n private readonly handlers = new Map<string, AXPRealtimeTopicHandlerRegistration[]>();\n\n constructor(\n @Optional()\n @Inject(AXP_REALTIME_TOPIC_HANDLER)\n registrations?: AXPRealtimeTopicHandlerRegistration[] | AXPRealtimeTopicHandlerRegistration,\n ) {\n const list = !registrations\n ? []\n : Array.isArray(registrations)\n ? registrations\n : [registrations];\n for (const registration of list) {\n this.register(registration);\n }\n }\n\n register(registration: AXPRealtimeTopicHandlerRegistration): void {\n const topic = registration.topic?.trim();\n if (!topic || typeof registration.handle !== 'function') {\n return;\n }\n const existing = this.handlers.get(topic) ?? [];\n existing.push(registration);\n this.handlers.set(topic, existing);\n }\n\n async dispatch(envelope: AXPRealtimeEnvelope): Promise<void> {\n const topic = envelope?.topic?.trim();\n if (!topic) {\n return;\n }\n const list = this.handlers.get(topic);\n if (!list?.length) {\n return;\n }\n for (const registration of list) {\n await registration.handle(envelope);\n }\n }\n}\n\n//#endregion\n","import type { Observable } from 'rxjs';\n\n//#region ---- Connection port ----\n\nexport type AXPRealtimeConnectionStatus = 'connected' | 'connecting' | 'disconnected';\n\n/**\n * Always-on realtime connection used by the app shell.\n * Built-in implementation uses Socket.IO; alternate backends may replace this port.\n */\nexport abstract class AXPRealtimeConnectionPort {\n abstract readonly connectionStatus$: Observable<AXPRealtimeConnectionStatus>;\n\n abstract connect(): void;\n abstract disconnect(): void;\n abstract reconnectWithCurrentToken(): void;\n abstract isSocketConnected(): boolean;\n abstract subscribeConversation(conversationId: string): void;\n abstract unsubscribeConversation(conversationId: string): void;\n abstract emitConversationTyping(conversationId: string, active: boolean): void;\n}\n\n//#endregion\n","import { DOCUMENT } from '@angular/common';\nimport { Inject, Injectable, OnDestroy, Optional, inject } from '@angular/core';\nimport { AXPSessionService, AXPSessionStatus } from '@acorex-platform/framework-client/auth';\nimport { io, type Socket } from 'socket.io-client';\nimport { BehaviorSubject, Subscription } from 'rxjs';\nimport {\n AXPRealtimeConnectionPort,\n type AXPRealtimeConnectionStatus,\n} from './realtime-connection.port';\nimport { AXPBulkProgressChannel } from '@acorex-platform/framework-client/runtime';\nimport { AXPRealtimeDispatcherService } from './realtime-dispatcher.service';\nimport {\n AXP_REALTIME_EMIT_TYPING,\n AXP_REALTIME_PRESENCE_LEAVE,\n AXP_REALTIME_PRESENCE_SET,\n AXP_REALTIME_SOCKET_EVENT,\n AXP_REALTIME_SUBSCRIBE_CONVERSATION,\n AXP_REALTIME_SUBSCRIBE_PRESENCE,\n AXP_REALTIME_TOPIC_BULK_PROGRESS,\n AXP_REALTIME_UNSUBSCRIBE_CONVERSATION,\n AXP_REALTIME_UNSUBSCRIBE_PRESENCE,\n} from './realtime.topics';\nimport type {\n AXPRealtimeBulkProgressPayload,\n AXPRealtimeConfig,\n AXPRealtimeEnvelope,\n AXPRealtimePresenceSetResult,\n AXPRealtimePresenceSubscribeResult,\n AXPRealtimeUserPresenceSnapshotItem,\n} from './realtime.types';\nimport { AXP_REALTIME_CONFIG } from './tokens';\n\n//#region ---- Constants ----\n\nconst RECONNECT_DELAY_MS = 1_000;\nconst RECONNECT_DELAY_MAX_MS = 10_000;\nconst CONNECT_TIMEOUT_MS = 20_000;\n\n//#endregion\n\n//#region ---- Socket.IO connection (built-in) ----\n\n/**\n * Built-in always-on realtime connection via Socket.IO.\n */\n@Injectable()\nexport class AXPRealtimeConnectionService extends AXPRealtimeConnectionPort implements OnDestroy {\n private readonly session = inject(AXPSessionService);\n private readonly dispatcher = inject(AXPRealtimeDispatcherService);\n private readonly bulkProgress = inject(AXPBulkProgressChannel, { optional: true });\n private readonly document = inject(DOCUMENT);\n private socket: Socket | null = null;\n private statusSub: Subscription | null = null;\n private wakeListenersBound = false;\n private readonly joinedConversations = new Set<string>();\n private readonly connectionStatusSubject = new BehaviorSubject<AXPRealtimeConnectionStatus>(\n 'disconnected',\n );\n\n /** Latest Socket.IO connection state for feature modules (e.g. chat). */\n override readonly connectionStatus$ = this.connectionStatusSubject.asObservable();\n\n constructor(\n @Optional()\n @Inject(AXP_REALTIME_CONFIG)\n private readonly config: AXPRealtimeConfig | null,\n ) {\n super();\n this.registerBulkProgressHandler();\n if (config?.autoConnect === false) {\n return;\n }\n this.bindWakeListeners();\n this.statusSub = this.session.status$.subscribe((status) => {\n if (status === AXPSessionStatus.Authorized) {\n this.connect();\n } else {\n void this.leaveAndDisconnect();\n }\n });\n }\n\n ngOnDestroy(): void {\n this.statusSub?.unsubscribe();\n this.unbindWakeListeners();\n this.disconnect();\n }\n\n /** Sign-out: tell the server to skip grace, then close the socket. */\n async leaveAndDisconnect(): Promise<void> {\n await this.leavePresence();\n this.disconnect();\n }\n\n connect(): void {\n const url = this.config?.url?.trim();\n if (!url || !this.session.hasSessionCredentials()) {\n this.connectionStatusSubject.next('disconnected');\n return;\n }\n\n if (this.socket?.connected) {\n return;\n }\n\n // Resume a dead manager (sleep / tab freeze / network drop) instead of creating a second client.\n if (this.socket) {\n this.connectionStatusSubject.next('connecting');\n this.socket.connect();\n return;\n }\n\n this.connectionStatusSubject.next('connecting');\n\n // Auth uses HttpOnly access cookie (same-site / proxied); no token in JS.\n this.socket = io(url, {\n transports: ['websocket', 'polling'],\n withCredentials: true,\n autoConnect: true,\n reconnection: true,\n reconnectionAttempts: Infinity,\n reconnectionDelay: RECONNECT_DELAY_MS,\n reconnectionDelayMax: RECONNECT_DELAY_MAX_MS,\n timeout: CONNECT_TIMEOUT_MS,\n });\n\n this.socket.on(AXP_REALTIME_SOCKET_EVENT, (envelope: AXPRealtimeEnvelope) => {\n void this.dispatcher.dispatch(envelope);\n });\n\n this.socket.on('connect', () => {\n this.connectionStatusSubject.next('connected');\n for (const conversationId of this.joinedConversations) {\n this.socket?.emit(AXP_REALTIME_SUBSCRIBE_CONVERSATION, { conversationId });\n }\n });\n\n this.socket.on('disconnect', () => {\n this.connectionStatusSubject.next('disconnected');\n });\n\n this.socket.on('connect_error', () => {\n this.connectionStatusSubject.next('disconnected');\n });\n }\n\n override disconnect(): void {\n if (this.socket) {\n this.socket.removeAllListeners();\n this.socket.disconnect();\n this.socket = null;\n }\n this.connectionStatusSubject.next('disconnected');\n }\n\n /** Re-auth with the latest access token (e.g. after refresh). */\n override reconnectWithCurrentToken(): void {\n this.disconnect();\n this.connect();\n }\n\n /** Whether the underlying Socket.IO client is connected. */\n override isSocketConnected(): boolean {\n return this.socket?.connected === true;\n }\n\n override subscribeConversation(conversationId: string): void {\n const id = conversationId?.trim();\n if (!id) {\n return;\n }\n this.joinedConversations.add(id);\n this.socket?.emit(AXP_REALTIME_SUBSCRIBE_CONVERSATION, { conversationId: id });\n }\n\n override unsubscribeConversation(conversationId: string): void {\n const id = conversationId?.trim();\n if (!id) {\n return;\n }\n this.joinedConversations.delete(id);\n this.socket?.emit(AXP_REALTIME_UNSUBSCRIBE_CONVERSATION, { conversationId: id });\n }\n\n override emitConversationTyping(conversationId: string, active: boolean): void {\n const id = conversationId?.trim();\n if (!id || !this.socket?.connected) {\n return;\n }\n this.socket.emit(AXP_REALTIME_EMIT_TYPING, { conversationId: id, active });\n }\n\n subscribePresence(userIds: readonly string[]): Promise<AXPRealtimeUserPresenceSnapshotItem[]> {\n const ids = userIds.map((id) => id.trim()).filter(Boolean);\n if (ids.length === 0 || !this.socket?.connected) {\n return Promise.resolve([]);\n }\n\n return new Promise((resolve) => {\n this.socket?.emit(\n AXP_REALTIME_SUBSCRIBE_PRESENCE,\n { userIds: ids },\n (result: AXPRealtimePresenceSubscribeResult | undefined) => {\n resolve(Array.isArray(result?.items) ? result.items : []);\n },\n );\n });\n }\n\n unsubscribePresence(userIds: readonly string[]): void {\n const ids = userIds.map((id) => id.trim()).filter(Boolean);\n if (ids.length === 0) {\n return;\n }\n this.socket?.emit(AXP_REALTIME_UNSUBSCRIBE_PRESENCE, { userIds: ids });\n }\n\n leavePresence(): Promise<void> {\n if (!this.socket?.connected) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, 400);\n this.socket?.emit(AXP_REALTIME_PRESENCE_LEAVE, {}, () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n setPresence(\n status: 'online' | 'away' | 'busy',\n source: 'auto' | 'manual' = 'manual',\n ): Promise<AXPRealtimeUserPresenceSnapshotItem | undefined> {\n if (!this.socket?.connected) {\n return Promise.resolve(undefined);\n }\n\n return new Promise((resolve) => {\n this.socket?.emit(\n AXP_REALTIME_PRESENCE_SET,\n { status, source },\n (result: AXPRealtimePresenceSetResult | undefined) => {\n resolve(result?.ok ? result.item : undefined);\n },\n );\n });\n }\n\n private registerBulkProgressHandler(): void {\n this.dispatcher.register({\n topic: AXP_REALTIME_TOPIC_BULK_PROGRESS,\n handle: async (envelope) => {\n const payload = envelope.payload as AXPRealtimeBulkProgressPayload;\n if (!payload?.executionId?.trim()) {\n return;\n }\n this.bulkProgress?.notify(payload);\n },\n });\n }\n\n //#region ---- Wake / network resume ----\n\n private bindWakeListeners(): void {\n if (this.wakeListenersBound) {\n return;\n }\n this.wakeListenersBound = true;\n this.document.addEventListener('visibilitychange', this.onVisibilityResume);\n this.document.defaultView?.addEventListener('online', this.onNetworkResume);\n }\n\n private unbindWakeListeners(): void {\n if (!this.wakeListenersBound) {\n return;\n }\n this.wakeListenersBound = false;\n this.document.removeEventListener('visibilitychange', this.onVisibilityResume);\n this.document.defaultView?.removeEventListener('online', this.onNetworkResume);\n }\n\n private readonly onVisibilityResume = (): void => {\n if (this.document.visibilityState === 'visible') {\n this.resumeIfAuthorized();\n }\n };\n\n private readonly onNetworkResume = (): void => {\n this.resumeIfAuthorized();\n };\n\n private resumeIfAuthorized(): void {\n if (!this.session.isAuthorized || !this.session.hasSessionCredentials()) {\n return;\n }\n if (this.socket?.connected) {\n return;\n }\n this.connect();\n }\n\n //#endregion\n}\n\n//#endregion\n","//#region ----- Constants -----\n\n/** Idle without input before automatic Away. Keep in sync with server `AXP_USER_PRESENCE_IDLE_MS`. */\nexport const AXP_USER_PRESENCE_IDLE_MS = 5 * 60_000;\n\n//#endregion\n","import type { AXPRealtimeUserPresencePayload, AXPRealtimeUserPresenceStatus } from '../realtime.types';\nimport type { AXPUserPresence, AXPUserPresenceSource } from './user-presence.types';\n\n//#region ----- Presence helpers -----\n\nconst PRESENCE_STATUSES: readonly AXPRealtimeUserPresenceStatus[] = ['online', 'offline', 'away', 'busy'];\n\nexport function isWatchablePresenceUserId(userId: string | null | undefined): boolean {\n const id = userId?.trim() ?? '';\n if (!id || id === 'system') {\n return false;\n }\n return !id.startsWith('assist-');\n}\n\nexport function parseUserPresencePayload(payload: unknown): AXPUserPresence | null {\n if (!payload || typeof payload !== 'object') {\n return null;\n }\n\n const raw = payload as AXPRealtimeUserPresencePayload;\n const userId = raw.userId?.trim();\n if (!userId) {\n return null;\n }\n\n const status = PRESENCE_STATUSES.includes(raw.status) ? raw.status : 'offline';\n const lastSeen = typeof raw.lastSeen === 'string' && raw.lastSeen.trim() ? raw.lastSeen.trim() : undefined;\n const since = typeof raw.since === 'string' && raw.since.trim() ? raw.since.trim() : undefined;\n const source: AXPUserPresenceSource | undefined =\n raw.source === 'auto' || raw.source === 'manual' ? raw.source : undefined;\n return {\n userId,\n status,\n ...(lastSeen ? { lastSeen } : {}),\n ...(since ? { since } : {}),\n ...(source ? { source } : {}),\n };\n}\n\n//#endregion\n","import { Injectable, inject } from '@angular/core';\nimport { BehaviorSubject, Observable, Subject } from 'rxjs';\nimport { AXPRealtimeConnectionService } from '../realtime-connection.service';\nimport type { AXPUserPresence } from './user-presence.types';\nimport { isWatchablePresenceUserId, parseUserPresencePayload } from './user-presence.util';\n\n//#region ----- User presence store -----\n\nconst FLUSH_DEBOUNCE_MS = 40;\n\n@Injectable({ providedIn: 'root' })\nexport class AXPUserPresenceService {\n //#region ----- Services & Dependencies -----\n\n private readonly connection = inject(AXPRealtimeConnectionService, { optional: true });\n\n //#endregion\n\n //#region ----- State -----\n\n private readonly presenceByUserId = new Map<string, AXPUserPresence>();\n private readonly watchCounts = new Map<string, number>();\n private readonly subjects = new Map<string, BehaviorSubject<AXPUserPresence>>();\n private readonly updatesSubject = new Subject<AXPUserPresence>();\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private pendingSubscribe = new Set<string>();\n private pendingUnsubscribe = new Set<string>();\n\n readonly updates$ = this.updatesSubject.asObservable();\n\n //#endregion\n\n constructor() {\n this.connection?.connectionStatus$.subscribe((status) => {\n if (status === 'connected') {\n this.resubscribeAll();\n }\n });\n }\n\n //#region ----- Public API -----\n\n get(userId: string): AXPUserPresence | undefined {\n const id = userId?.trim();\n if (!id) {\n return undefined;\n }\n return this.presenceByUserId.get(id);\n }\n\n presence$(userId: string): Observable<AXPUserPresence> {\n const id = userId?.trim();\n const fallback: AXPUserPresence = { userId: id, status: 'offline' };\n if (!id) {\n return new BehaviorSubject(fallback).asObservable();\n }\n\n let subject = this.subjects.get(id);\n if (!subject) {\n subject = new BehaviorSubject<AXPUserPresence>(this.presenceByUserId.get(id) ?? fallback);\n this.subjects.set(id, subject);\n }\n return subject.asObservable();\n }\n\n watch(userId: string): void {\n if (!isWatchablePresenceUserId(userId)) {\n return;\n }\n const id = userId.trim();\n const next = (this.watchCounts.get(id) ?? 0) + 1;\n this.watchCounts.set(id, next);\n if (next === 1) {\n this.pendingUnsubscribe.delete(id);\n this.pendingSubscribe.add(id);\n this.scheduleFlush();\n }\n }\n\n watchMany(userIds: readonly string[]): void {\n for (const userId of userIds) {\n this.watch(userId);\n }\n }\n\n /** Watch only if this user is not already in the local watch set. */\n ensureWatch(userId: string): void {\n const id = userId?.trim();\n if (!id || (this.watchCounts.get(id) ?? 0) > 0) {\n return;\n }\n this.watch(id);\n }\n\n ensureWatchMany(userIds: readonly string[]): void {\n for (const userId of userIds) {\n this.ensureWatch(userId);\n }\n }\n\n unwatch(userId: string): void {\n const id = userId?.trim();\n if (!id) {\n return;\n }\n const current = this.watchCounts.get(id) ?? 0;\n if (current <= 1) {\n this.watchCounts.delete(id);\n this.pendingSubscribe.delete(id);\n this.pendingUnsubscribe.add(id);\n this.scheduleFlush();\n return;\n }\n this.watchCounts.set(id, current - 1);\n }\n\n applySnapshot(items: readonly AXPUserPresence[]): void {\n for (const item of items) {\n this.applyPresence(item);\n }\n }\n\n applyEnvelopePayload(payload: unknown): void {\n const parsed = parseUserPresencePayload(payload);\n if (parsed) {\n this.applyPresence(parsed);\n }\n }\n\n async setAvailability(\n status: 'online' | 'away' | 'busy',\n source: 'auto' | 'manual' = 'manual',\n ): Promise<void> {\n const item = await this.connection?.setPresence(status, source);\n if (item) {\n this.applyPresence(item);\n }\n }\n\n //#endregion\n\n //#region ----- Store updates -----\n\n private applyPresence(presence: AXPUserPresence): void {\n const previous = this.presenceByUserId.get(presence.userId);\n if (\n previous &&\n previous.status === presence.status &&\n previous.lastSeen === presence.lastSeen &&\n previous.since === presence.since\n ) {\n return;\n }\n\n this.presenceByUserId.set(presence.userId, presence);\n const subject = this.subjects.get(presence.userId);\n if (subject && !subject.closed) {\n subject.next(presence);\n }\n this.updatesSubject.next(presence);\n }\n\n private scheduleFlush(): void {\n if (this.flushTimer) {\n return;\n }\n this.flushTimer = setTimeout(() => {\n this.flushTimer = null;\n void this.flush();\n }, FLUSH_DEBOUNCE_MS);\n }\n\n private async flush(): Promise<void> {\n const subscribeIds = Array.from(this.pendingSubscribe);\n const unsubscribeIds = Array.from(this.pendingUnsubscribe);\n this.pendingSubscribe.clear();\n this.pendingUnsubscribe.clear();\n\n if (unsubscribeIds.length > 0) {\n this.connection?.unsubscribePresence(unsubscribeIds);\n }\n if (subscribeIds.length === 0) {\n return;\n }\n\n const items = (await this.connection?.subscribePresence(subscribeIds)) ?? [];\n this.applySnapshot(items);\n }\n\n private resubscribeAll(): void {\n const watched = Array.from(this.watchCounts.keys());\n if (watched.length === 0) {\n return;\n }\n this.pendingUnsubscribe.clear();\n for (const id of watched) {\n this.pendingSubscribe.add(id);\n }\n this.scheduleFlush();\n }\n\n //#endregion\n}\n\n//#endregion\n","import { DOCUMENT } from '@angular/common';\nimport { DestroyRef, Injectable, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { AXPSessionService, AXPSessionStatus } from '@acorex-platform/framework-client/auth';\nimport { AXP_USER_PRESENCE_IDLE_MS } from '../presence-idle.constants';\nimport { AXPUserPresenceService } from './user-presence.service';\n\n//#region ----- Automatic away from idle -----\n\nconst IDLE_CHECK_MS = 15_000;\nconst ACTIVITY_THROTTLE_MS = 1_000;\n\n@Injectable({ providedIn: 'root' })\nexport class AXPUserPresenceIdleService {\n //#region ----- Services & Dependencies -----\n\n private readonly document = inject(DOCUMENT);\n private readonly session = inject(AXPSessionService);\n private readonly presence = inject(AXPUserPresenceService);\n private readonly destroyRef = inject(DestroyRef);\n\n //#endregion\n\n //#region ----- State -----\n\n private lastActivityAt = Date.now();\n private lastActivityEmitAt = 0;\n private idle = false;\n private checkTimer: ReturnType<typeof setInterval> | null = null;\n private started = false;\n\n //#endregion\n\n constructor() {\n this.session.status$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((status) => {\n if (status === AXPSessionStatus.Authorized) {\n this.start();\n return;\n }\n this.stop();\n });\n }\n\n //#region ----- Lifecycle -----\n\n start(): void {\n if (this.started) {\n return;\n }\n this.started = true;\n this.lastActivityAt = Date.now();\n this.idle = false;\n const target = this.document.defaultView ?? this.document;\n target.addEventListener('mousemove', this.onActivity, { passive: true });\n target.addEventListener('keydown', this.onActivity, { passive: true });\n target.addEventListener('mousedown', this.onActivity, { passive: true });\n target.addEventListener('touchstart', this.onActivity, { passive: true });\n this.document.addEventListener('visibilitychange', this.onVisibility);\n this.checkTimer = setInterval(() => this.checkIdle(), IDLE_CHECK_MS);\n }\n\n stop(): void {\n if (!this.started) {\n return;\n }\n this.started = false;\n this.idle = false;\n const target = this.document.defaultView ?? this.document;\n target.removeEventListener('mousemove', this.onActivity);\n target.removeEventListener('keydown', this.onActivity);\n target.removeEventListener('mousedown', this.onActivity);\n target.removeEventListener('touchstart', this.onActivity);\n this.document.removeEventListener('visibilitychange', this.onVisibility);\n if (this.checkTimer) {\n clearInterval(this.checkTimer);\n this.checkTimer = null;\n }\n }\n\n //#endregion\n\n //#region ----- Activity -----\n\n private readonly onActivity = (): void => {\n const now = Date.now();\n this.lastActivityAt = now;\n if (now - this.lastActivityEmitAt < ACTIVITY_THROTTLE_MS) {\n return;\n }\n this.lastActivityEmitAt = now;\n if (this.idle) {\n this.idle = false;\n void this.presence.setAvailability('online', 'auto');\n }\n };\n\n private readonly onVisibility = (): void => {\n if (!this.document.hidden) {\n this.onActivity();\n }\n };\n\n private checkIdle(): void {\n if (!this.started || this.idle) {\n return;\n }\n if (Date.now() - this.lastActivityAt < AXP_USER_PRESENCE_IDLE_MS) {\n return;\n }\n this.idle = true;\n void this.presence.setAvailability('away', 'auto');\n }\n\n //#endregion\n}\n\n//#endregion\n","import {\n inject,\n makeEnvironmentProviders,\n type EnvironmentProviders,\n} from '@angular/core';\nimport {\n AXP_APP_STARTUP_PRIORITY,\n provideAppStartUpTask,\n} from '@acorex-platform/framework-client/core';\nimport { provideCommandSetups } from '@acorex-platform/framework-client/runtime';\nimport { PRESENCE_SET_AVAILABILITY } from '@acorex-platform/framework-shared/runtime';\nimport { AXPUserPresenceIdleService } from './presence/user-presence-idle.service';\nimport { AXPUserPresenceService } from './presence/user-presence.service';\nimport { AXPRealtimeConnectionPort } from './realtime-connection.port';\nimport { AXPRealtimeConnectionService } from './realtime-connection.service';\nimport { AXPRealtimeDispatcherService } from './realtime-dispatcher.service';\nimport type { AXPRealtimeConfig } from './realtime.types';\nimport { resolveRealtimeSocketUrl } from './realtime-url.util';\nimport { AXP_REALTIME_TOPIC_USER_PRESENCE } from './realtime.topics';\nimport { AXP_REALTIME_CONFIG } from './tokens';\n\n//#region ---- provideRealtime ----\n\nexport interface AXPProvideRealtimeOptions extends AXPRealtimeConfig {\n apiBaseUrl?: string;\n /**\n * Always-on backend. Default `builtin` (Socket.IO).\n * Call/media uses extensions/rtc when configured — not this switch.\n */\n backend?: 'builtin';\n}\n\n/**\n * Registers built-in always-on realtime (Socket.IO) + topic dispatcher.\n */\nexport function provideRealtime(config: AXPProvideRealtimeOptions = {}): EnvironmentProviders {\n const backend = config.backend ?? 'builtin';\n if (backend !== 'builtin') {\n throw new Error(`Unsupported realtime backend '${String(backend)}'. Use 'builtin'.`);\n }\n\n const url =\n config.url?.trim() ||\n (config.apiBaseUrl?.trim() ? resolveRealtimeSocketUrl(config.apiBaseUrl) : undefined);\n\n return makeEnvironmentProviders([\n {\n provide: AXP_REALTIME_CONFIG,\n useValue: {\n autoConnect: config.autoConnect !== false,\n url,\n } satisfies AXPRealtimeConfig,\n },\n AXPRealtimeDispatcherService,\n AXPRealtimeConnectionService,\n {\n provide: AXPRealtimeConnectionPort,\n useExisting: AXPRealtimeConnectionService,\n },\n provideCommandSetups([\n {\n key: PRESENCE_SET_AVAILABILITY,\n command: () =>\n import('./presence/set-presence-availability.command').then((c) => c.AXPSetPresenceAvailabilityCommand),\n },\n ]),\n provideAppStartUpTask(() => {\n inject(AXPUserPresenceIdleService);\n return {\n name: 'user-presence-idle',\n priority: AXP_APP_STARTUP_PRIORITY.realtimeSubscriptions,\n run: async () => undefined,\n };\n }),\n provideAppStartUpTask(() => {\n const dispatcher = inject(AXPRealtimeDispatcherService);\n const presence = inject(AXPUserPresenceService);\n return {\n name: 'user-presence-handler',\n priority: AXP_APP_STARTUP_PRIORITY.realtimeHandlers,\n run: async () => {\n dispatcher.register({\n topic: AXP_REALTIME_TOPIC_USER_PRESENCE,\n handle: (envelope) => {\n presence.applyEnvelopePayload(envelope.payload);\n },\n });\n },\n };\n }),\n provideAppStartUpTask(() => {\n const connection = inject(AXPRealtimeConnectionPort);\n return {\n name: 'realtime-connect',\n priority: AXP_APP_STARTUP_PRIORITY.realtimeConnect,\n run: async () => {\n // Connection lifecycle is owned by the connection service (session.status$).\n // Eagerly invoke connect once so an already-authenticated session connects on bootstrap.\n connection.connect();\n },\n };\n }),\n ]);\n}\n\n//#endregion\n","import type { AXPRealtimeUserPresenceStatus, AXPRealtimeUserPresenceSource } from '../realtime.types';\n\n//#region ----- Types -----\n\nexport type AXPUserPresenceStatus = AXPRealtimeUserPresenceStatus;\nexport type AXPUserPresenceSource = AXPRealtimeUserPresenceSource;\n\nexport interface AXPUserPresence {\n userId: string;\n status: AXPUserPresenceStatus;\n lastSeen?: string;\n since?: string;\n source?: AXPUserPresenceSource;\n}\n\nexport interface AXPUserPresenceSetInput {\n status: 'online' | 'away' | 'busy';\n source?: AXPUserPresenceSource;\n}\n\n//#endregion\n","//#region ----- Presence duration tooltip -----\n\nexport type AXPPresenceDurationBucket = {\n key:\n | 'duration.less-than-a-minute'\n | 'duration.one-minute'\n | 'duration.minutes'\n | 'duration.one-hour'\n | 'duration.hours'\n | 'duration.one-day'\n | 'duration.days';\n params?: { count: number };\n};\n\nexport function presenceDurationBucket(ms: number): AXPPresenceDurationBucket {\n const elapsed = Math.max(0, ms);\n if (elapsed < 60_000) {\n return { key: 'duration.less-than-a-minute' };\n }\n\n const minutes = Math.floor(elapsed / 60_000);\n if (minutes < 60) {\n return minutes === 1 ? { key: 'duration.one-minute' } : { key: 'duration.minutes', params: { count: minutes } };\n }\n\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return hours === 1 ? { key: 'duration.one-hour' } : { key: 'duration.hours', params: { count: hours } };\n }\n\n const days = Math.floor(hours / 24);\n return days === 1 ? { key: 'duration.one-day' } : { key: 'duration.days', params: { count: days } };\n}\n\n//#endregion\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, InjectionToken, EnvironmentInjector, runInInjectionContext, makeEnvironmentProviders, input, ElementRef, effect, Directive, isDevMode, NgModule } from '@angular/core';
2
+ import { inject, Injectable, NgZone, InjectionToken, EnvironmentInjector, runInInjectionContext, makeEnvironmentProviders, input, ElementRef, effect, Directive, isDevMode, NgModule } from '@angular/core';
3
3
  import { AXPHookService, AXPBroadcastEventService, AXPDistributedEventListenerService, AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER } from '@acorex-platform/framework-client/core';
4
+ import { Subject, Observable } from 'rxjs';
5
+ import { filter } from 'rxjs/operators';
6
+ import { createRandomUuid } from '@acorex-platform/framework-shared/core';
4
7
  import { normalizeCommandInputForRemote, composeCommandMiddlewares, composeQueryMiddlewares } from '@acorex-platform/framework-shared/runtime';
5
8
  export { composeCommandMiddlewares, composeQueryMiddlewares } from '@acorex-platform/framework-shared/runtime';
6
9
  import { castArray } from 'lodash-es';
@@ -15,13 +18,15 @@ import { castArray } from 'lodash-es';
15
18
  *
16
19
  * Host apps that only consume the client lib and call a different API stack should
17
20
  * register {@link provideExternalRuntimeQueryTransport},
18
- * {@link provideExternalRuntimeCommandTransport}, and
19
- * {@link provideExternalRuntimeBulkTransport}
21
+ * {@link provideExternalRuntimeCommandTransport},
22
+ * {@link provideExternalRuntimeBulkTransport} for {@link AXPRuntimeRemoteHookKeys.CommandExecuteBulk},
23
+ * and {@link provideBulkProgressPollTransport} for {@link AXPRuntimeRemoteHookKeys.CommandBulkProgress}
20
24
  * (see `RUNTIME_REMOTE_BULK_TRANSPORT.md`).
21
25
  */
22
26
  const AXPRuntimeRemoteHookKeys = {
23
27
  CommandExecute: 'runtime.command.execute',
24
28
  CommandExecuteBulk: 'runtime.command.execute-bulk',
29
+ CommandBulkProgress: 'runtime.command.bulk-progress',
25
30
  QueryExecute: 'runtime.query.execute',
26
31
  };
27
32
  //#endregion
@@ -62,6 +67,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
62
67
  args: [{ providedIn: 'root' }]
63
68
  }] });
64
69
 
70
+ //#region ---- Imports ----
71
+ //#endregion
72
+ //#region ---- Constants ----
73
+ const DEFAULT_POLL_INTERVAL_MS = 250;
74
+ //#endregion
75
+ //#region ---- Bulk progress channel ----
76
+ /**
77
+ * Actor-only progress bus for in-flight bulk commands.
78
+ *
79
+ * Prefer realtime (`runtime.bulk.progress` → {@link notify}).
80
+ * GET /progress only when the caller sets `poll: true` (socket down).
81
+ */
82
+ class AXPBulkProgressChannel {
83
+ constructor() {
84
+ this.hooks = inject(AXPHookService);
85
+ this.zone = inject(NgZone);
86
+ this.subject = new Subject();
87
+ }
88
+ /** Called by the realtime topic handler when a socket tick arrives. */
89
+ notify(progress) {
90
+ const executionId = progress?.executionId?.trim();
91
+ if (!executionId) {
92
+ return;
93
+ }
94
+ this.emit(progress, executionId);
95
+ }
96
+ watch(executionId, options) {
97
+ const id = executionId.trim();
98
+ const stream = this.subject.pipe(filter((progress) => progress.executionId === id));
99
+ if (!options?.poll) {
100
+ return stream;
101
+ }
102
+ const intervalMs = typeof options?.intervalMs === 'number' && options.intervalMs > 0
103
+ ? options.intervalMs
104
+ : DEFAULT_POLL_INTERVAL_MS;
105
+ return new Observable((subscriber) => {
106
+ const sub = stream.subscribe(subscriber);
107
+ const timer = setInterval(() => {
108
+ void this.pollOnce(id);
109
+ }, intervalMs);
110
+ return () => {
111
+ sub.unsubscribe();
112
+ this.clearPoll(timer);
113
+ };
114
+ });
115
+ }
116
+ emit(progress, executionId) {
117
+ this.zone.run(() => {
118
+ this.subject.next({ ...progress, executionId });
119
+ });
120
+ }
121
+ clearPoll(timer) {
122
+ if (timer !== undefined) {
123
+ clearInterval(timer);
124
+ }
125
+ }
126
+ async pollOnce(executionId) {
127
+ const payload = await this.hooks.runAsync(AXPRuntimeRemoteHookKeys.CommandBulkProgress, { executionId });
128
+ if (payload.handled && payload.progress) {
129
+ const id = payload.progress.executionId?.trim() || executionId;
130
+ this.emit(payload.progress, id);
131
+ }
132
+ }
133
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPBulkProgressChannel, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
134
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPBulkProgressChannel, providedIn: 'root' }); }
135
+ }
136
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPBulkProgressChannel, decorators: [{
137
+ type: Injectable,
138
+ args: [{ providedIn: 'root' }]
139
+ }] });
140
+
65
141
  //#region ---- Imports ----
66
142
  //#endregion
67
143
  const COMMAND_EXECUTION_EVENT_KEY = '@commands:execution';
@@ -258,7 +334,7 @@ class AXPCommandExecutor {
258
334
  return this.runWithEvents(key, input, () => composed({ input, key, options }), options);
259
335
  }
260
336
  async runWithEvents(key, input, run, options) {
261
- const executionId = crypto.randomUUID();
337
+ const executionId = createRandomUuid();
262
338
  const startedAt = performance.now();
263
339
  const beforeEvent = {
264
340
  executionId,
@@ -673,7 +749,7 @@ class AXPQueryExecutor {
673
749
  return this.runWithEvents(key, input, () => composed({ input, key, options }), options);
674
750
  }
675
751
  async runWithEvents(key, input, run, options) {
676
- const executionId = crypto.randomUUID();
752
+ const executionId = createRandomUuid();
677
753
  const startedAt = performance.now();
678
754
  const beforeEvent = {
679
755
  executionId,
@@ -1355,11 +1431,50 @@ function provideExternalRuntimeQueryTransport(transport, options = {}) {
1355
1431
  }
1356
1432
  //#endregion
1357
1433
 
1434
+ //#region ---- Imports ----
1435
+ //#endregion
1436
+ //#region ---- Provider factories ----
1437
+ /** Replace the default {@link AXPBulkProgressChannel} (e.g. SSE or a host-specific bus). */
1438
+ function provideBulkProgressChannel(factory) {
1439
+ return [
1440
+ {
1441
+ provide: AXPBulkProgressChannel,
1442
+ useFactory: factory,
1443
+ },
1444
+ ];
1445
+ }
1446
+ /**
1447
+ * Registers a poll transport for hosts that have a progress HTTP API but no realtime.
1448
+ * Same pattern as {@link provideExternalRuntimeBulkTransport}.
1449
+ */
1450
+ function provideBulkProgressPollTransport(transport, options = {}) {
1451
+ const priority = options.priority ?? -100;
1452
+ const provider = {
1453
+ key: AXPRuntimeRemoteHookKeys.CommandBulkProgress,
1454
+ priority,
1455
+ async execute(payload) {
1456
+ if (payload.handled) {
1457
+ return payload;
1458
+ }
1459
+ const progress = await transport(payload.executionId);
1460
+ return { ...payload, handled: true, progress: progress ?? null };
1461
+ },
1462
+ };
1463
+ return [
1464
+ {
1465
+ provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
1466
+ useValue: provider,
1467
+ multi: true,
1468
+ },
1469
+ ];
1470
+ }
1471
+ //#endregion
1472
+
1358
1473
  // Commands
1359
1474
 
1360
1475
  /**
1361
1476
  * Generated bundle index. Do not edit.
1362
1477
  */
1363
1478
 
1364
- export { AXPBulkCommandService, AXPCommandEventsService, AXPCommandExecutor, AXPCommandRegistry, AXPCommandService, AXPPolicyEngineContext, AXPPolicyEngineDirective, AXPPolicyEngineRegistry, AXPPolicyEngineService, AXPQueryEventsService, AXPQueryExecutor, AXPQueryRegistry, AXPQueryService, AXPRuntimeModule, AXPRuntimeRemoteHookKeys, AXPRuntimeTransportHookKeys, AXPRuntimeTransportService, AXPViewExecutor, AXPViewRegistry, AXPViewService, AXP_COMMAND_EXTENSION, AXP_COMMAND_MIDDLEWARE_SETUP, AXP_COMMAND_SETUP, AXP_POLICY_ENGINE_MIDDLEWARE_SETUP, AXP_POLICY_EXTENSION, AXP_QUERY_EXTENSION, AXP_QUERY_MIDDLEWARE_SETUP, AXP_QUERY_SETUP, AXP_VIEW_EXTENSION, AXP_VIEW_SETUP, composePolicyEngineMiddlewares, composeViewMiddlewares, provideCommand, provideCommandMiddleware, provideCommandSetups, provideExternalRuntimeBulkTransport, provideExternalRuntimeCommandTransport, provideExternalRuntimeQueryTransport, providePolicySetups, provideQueryMiddleware, provideQuerySetups, provideViewSetup, provideViewSetups };
1479
+ export { AXPBulkCommandService, AXPBulkProgressChannel, AXPCommandEventsService, AXPCommandExecutor, AXPCommandRegistry, AXPCommandService, AXPPolicyEngineContext, AXPPolicyEngineDirective, AXPPolicyEngineRegistry, AXPPolicyEngineService, AXPQueryEventsService, AXPQueryExecutor, AXPQueryRegistry, AXPQueryService, AXPRuntimeModule, AXPRuntimeRemoteHookKeys, AXPRuntimeTransportHookKeys, AXPRuntimeTransportService, AXPViewExecutor, AXPViewRegistry, AXPViewService, AXP_COMMAND_EXTENSION, AXP_COMMAND_MIDDLEWARE_SETUP, AXP_COMMAND_SETUP, AXP_POLICY_ENGINE_MIDDLEWARE_SETUP, AXP_POLICY_EXTENSION, AXP_QUERY_EXTENSION, AXP_QUERY_MIDDLEWARE_SETUP, AXP_QUERY_SETUP, AXP_VIEW_EXTENSION, AXP_VIEW_SETUP, composePolicyEngineMiddlewares, composeViewMiddlewares, provideBulkProgressChannel, provideBulkProgressPollTransport, provideCommand, provideCommandMiddleware, provideCommandSetups, provideExternalRuntimeBulkTransport, provideExternalRuntimeCommandTransport, provideExternalRuntimeQueryTransport, providePolicySetups, provideQueryMiddleware, provideQuerySetups, provideViewSetup, provideViewSetups };
1365
1480
  //# sourceMappingURL=acorex-platform-framework-client-runtime.mjs.map