@acorex-platform/module-conversation-client 0.0.21

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 (35) hide show
  1. package/fesm2022/acorex-platform-module-conversation-client-acorex-platform-module-conversation-client-DsjrXRZ6.mjs +12766 -0
  2. package/fesm2022/acorex-platform-module-conversation-client-acorex-platform-module-conversation-client-DsjrXRZ6.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-module-conversation-client-after-message-sent.command-D-DZ9ylV.mjs +35 -0
  4. package/fesm2022/acorex-platform-module-conversation-client-after-message-sent.command-D-DZ9ylV.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-module-conversation-client-assist-delegated-agent-detail-popup.component-BfjJCQ-e.mjs +492 -0
  6. package/fesm2022/acorex-platform-module-conversation-client-assist-delegated-agent-detail-popup.component-BfjJCQ-e.mjs.map +1 -0
  7. package/fesm2022/acorex-platform-module-conversation-client-assist-tool-detail-popup.component-GC58B_n0.mjs +120 -0
  8. package/fesm2022/acorex-platform-module-conversation-client-assist-tool-detail-popup.component-GC58B_n0.mjs.map +1 -0
  9. package/fesm2022/acorex-platform-module-conversation-client-chat-call-session-page.component-DkX4JSbN.mjs +871 -0
  10. package/fesm2022/acorex-platform-module-conversation-client-chat-call-session-page.component-DkX4JSbN.mjs.map +1 -0
  11. package/fesm2022/acorex-platform-module-conversation-client-chat-call-start-popup.component-D4go5xbr.mjs +89 -0
  12. package/fesm2022/acorex-platform-module-conversation-client-chat-call-start-popup.component-D4go5xbr.mjs.map +1 -0
  13. package/fesm2022/acorex-platform-module-conversation-client-chat-conversation-info-media-view.component-BVJdVPke.mjs +108 -0
  14. package/fesm2022/acorex-platform-module-conversation-client-chat-conversation-info-media-view.component-BVJdVPke.mjs.map +1 -0
  15. package/fesm2022/acorex-platform-module-conversation-client-comments-page.component-Bq4SdK0_.mjs +83 -0
  16. package/fesm2022/acorex-platform-module-conversation-client-comments-page.component-Bq4SdK0_.mjs.map +1 -0
  17. package/fesm2022/acorex-platform-module-conversation-client-contracts.mjs +225 -0
  18. package/fesm2022/acorex-platform-module-conversation-client-contracts.mjs.map +1 -0
  19. package/fesm2022/acorex-platform-module-conversation-client-emit-typing-indicator.command-BzsN1_ns.mjs +29 -0
  20. package/fesm2022/acorex-platform-module-conversation-client-emit-typing-indicator.command-BzsN1_ns.mjs.map +1 -0
  21. package/fesm2022/acorex-platform-module-conversation-client-mark-conversation-unread.command-BlYDwGVe.mjs +30 -0
  22. package/fesm2022/acorex-platform-module-conversation-client-mark-conversation-unread.command-BlYDwGVe.mjs.map +1 -0
  23. package/fesm2022/acorex-platform-module-conversation-client-open-chat.command-B03q60Qx.mjs +42 -0
  24. package/fesm2022/acorex-platform-module-conversation-client-open-chat.command-B03q60Qx.mjs.map +1 -0
  25. package/fesm2022/acorex-platform-module-conversation-client-retry-assist-response.command-BQLK6F69.mjs +34 -0
  26. package/fesm2022/acorex-platform-module-conversation-client-retry-assist-response.command-BQLK6F69.mjs.map +1 -0
  27. package/fesm2022/acorex-platform-module-conversation-client-start-direct-chat.command-CfSIVHDu.mjs +80 -0
  28. package/fesm2022/acorex-platform-module-conversation-client-start-direct-chat.command-CfSIVHDu.mjs.map +1 -0
  29. package/fesm2022/acorex-platform-module-conversation-client-sync-read-state.command-B1Z_gZ6O.mjs +142 -0
  30. package/fesm2022/acorex-platform-module-conversation-client-sync-read-state.command-B1Z_gZ6O.mjs.map +1 -0
  31. package/fesm2022/acorex-platform-module-conversation-client.mjs +2 -0
  32. package/fesm2022/acorex-platform-module-conversation-client.mjs.map +1 -0
  33. package/package.json +28 -0
  34. package/types/acorex-platform-module-conversation-client-contracts.d.ts +497 -0
  35. package/types/acorex-platform-module-conversation-client.d.ts +1614 -0
@@ -0,0 +1,83 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, inject, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { ActivatedRoute } from '@angular/router';
4
+ import { AXPPageLayoutBaseComponent, AXPPageLayoutBase } from '@acorex-platform/framework-client/layout/views';
5
+ import { e as AXMCommentComponent } from './acorex-platform-module-conversation-client-acorex-platform-module-conversation-client-DsjrXRZ6.mjs';
6
+
7
+ //#region ---- Comments Page Component ----
8
+ /**
9
+ * Page component that renders comments using AXMCommentComponent.
10
+ * Used when comments plugin has display: 'page'.
11
+ * Receives rootContext (entity data) and derives refrenceType/refrenceId from route params and context.
12
+ */
13
+ class AXMCommentsPageComponent extends AXPPageLayoutBaseComponent {
14
+ constructor() {
15
+ super(...arguments);
16
+ //#region ---- Inputs ----
17
+ /** Entity data context passed by the page host */
18
+ this.rootContext = input.required(/* @ts-ignore */
19
+ ...(ngDevMode ? [{ debugName: "rootContext" }] : /* istanbul ignore next */ []));
20
+ /** Page-level configuration from the entity page definition */
21
+ this.pageConfig = input(/* @ts-ignore */
22
+ ...(ngDevMode ? [undefined, { debugName: "pageConfig" }] : /* istanbul ignore next */ []));
23
+ //#endregion
24
+ //#region ---- Services & Dependencies ----
25
+ this.route = inject(ActivatedRoute);
26
+ //#endregion
27
+ //#region ---- Computed Properties ----
28
+ this.refrenceType = computed(() => {
29
+ const moduleName = this.route.snapshot.parent?.paramMap.get('module');
30
+ const entityName = this.route.snapshot.paramMap.get('entity');
31
+ if (moduleName && entityName) {
32
+ return `${moduleName}.${entityName}`;
33
+ }
34
+ return null;
35
+ }, /* @ts-ignore */
36
+ ...(ngDevMode ? [{ debugName: "refrenceType" }] : /* istanbul ignore next */ []));
37
+ this.refrenceId = computed(() => {
38
+ const ctx = this.rootContext();
39
+ return ctx?.['id'] ?? null;
40
+ }, /* @ts-ignore */
41
+ ...(ngDevMode ? [{ debugName: "refrenceId" }] : /* istanbul ignore next */ []));
42
+ this.subject = computed(() => {
43
+ const ctx = this.rootContext();
44
+ return ctx?.['title'] ?? '';
45
+ }, /* @ts-ignore */
46
+ ...(ngDevMode ? [{ debugName: "subject" }] : /* istanbul ignore next */ []));
47
+ }
48
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommentsPageComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
49
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMCommentsPageComponent, isStandalone: true, selector: "axm-comments-page", inputs: { rootContext: { classPropertyName: "rootContext", publicName: "rootContext", isSignal: true, isRequired: true, transformFunction: null }, pageConfig: { classPropertyName: "pageConfig", publicName: "pageConfig", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
50
+ {
51
+ provide: AXPPageLayoutBase,
52
+ useExisting: AXMCommentsPageComponent,
53
+ },
54
+ ], usesInheritance: true, ngImport: i0, template: `
55
+ @if (refrenceType() && refrenceId()) {
56
+ <axm-comment
57
+ [refrenceType]="refrenceType()!"
58
+ [refrenceId]="refrenceId()!"
59
+ [subject]="subject()"
60
+ ></axm-comment>
61
+ }
62
+ `, isInline: true, styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXMCommentComponent, selector: "axm-comment", inputs: ["refrenceType", "refrenceId", "subject"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
63
+ }
64
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommentsPageComponent, decorators: [{
65
+ type: Component,
66
+ args: [{ selector: 'axm-comments-page', imports: [AXMCommentComponent], template: `
67
+ @if (refrenceType() && refrenceId()) {
68
+ <axm-comment
69
+ [refrenceType]="refrenceType()!"
70
+ [refrenceId]="refrenceId()!"
71
+ [subject]="subject()"
72
+ ></axm-comment>
73
+ }
74
+ `, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
75
+ {
76
+ provide: AXPPageLayoutBase,
77
+ useExisting: AXMCommentsPageComponent,
78
+ },
79
+ ], styles: [":host{display:block;width:100%;height:100%}\n"] }]
80
+ }], propDecorators: { rootContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootContext", required: true }] }], pageConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageConfig", required: false }] }] } });
81
+
82
+ export { AXMCommentsPageComponent };
83
+ //# sourceMappingURL=acorex-platform-module-conversation-client-comments-page.component-Bq4SdK0_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acorex-platform-module-conversation-client-comments-page.component-Bq4SdK0_.mjs","sources":["../../../../libs/modules/conversation/client/src/lib/features/comment/comments-page/comments-page.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { AXPPageLayoutBase, AXPPageLayoutBaseComponent } from '@acorex-platform/framework-client/layout/views';\nimport { AXMCommentComponent } from '../comment.component';\n\n//#region ---- Comments Page Component ----\n\n/**\n * Page component that renders comments using AXMCommentComponent.\n * Used when comments plugin has display: 'page'.\n * Receives rootContext (entity data) and derives refrenceType/refrenceId from route params and context.\n */\n@Component({\n selector: 'axm-comments-page',\n imports: [AXMCommentComponent],\n template: `\n @if (refrenceType() && refrenceId()) {\n <axm-comment\n [refrenceType]=\"refrenceType()!\"\n [refrenceId]=\"refrenceId()!\"\n [subject]=\"subject()\"\n ></axm-comment>\n }\n `,\n styles: `\n\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: AXPPageLayoutBase,\n useExisting: AXMCommentsPageComponent,\n },\n ],\n})\nexport class AXMCommentsPageComponent extends AXPPageLayoutBaseComponent {\n\n //#region ---- Inputs ----\n\n /** Entity data context passed by the page host */\n rootContext = input.required<Record<string, any>>();\n\n /** Page-level configuration from the entity page definition */\n pageConfig = input<Record<string, unknown>>();\n\n //#endregion\n\n //#region ---- Services & Dependencies ----\n\n private route = inject(ActivatedRoute);\n\n //#endregion\n\n //#region ---- Computed Properties ----\n\n protected refrenceType = computed(() => {\n const moduleName = this.route.snapshot.parent?.paramMap.get('module');\n const entityName = this.route.snapshot.paramMap.get('entity');\n if (moduleName && entityName) {\n return `${moduleName}.${entityName}`;\n }\n return null;\n });\n\n protected refrenceId = computed(() => {\n const ctx = this.rootContext();\n return ctx?.['id'] ?? null;\n });\n\n protected subject = computed(() => {\n const ctx = this.rootContext();\n return ctx?.['title'] ?? '';\n });\n\n //#endregion\n\n}\n\n//#endregion\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,225 @@
1
+ //#region ---- Comment entity reference ----
2
+ //#endregion
3
+
4
+ const AXPConversationMenuKeys = {
5
+ Conversations: 'Conversation:Menu:Conversations',
6
+ };
7
+
8
+ /**
9
+ * Collaboration capabilities used by this module.
10
+ * Domain capability keys for this module. Root groups live in `AXPCommonPermissionGroupKeys` (common contracts).
11
+ */
12
+ const AXPCollaborationPermissionKeys = {
13
+ Access: 'Collaboration:Permission:Access',
14
+ MaintainConversations: 'Collaboration:Permission:MaintainConversations',
15
+ MaintainMeetings: 'Collaboration:Permission:MaintainMeetings',
16
+ MaintainCalendars: 'Collaboration:Permission:MaintainCalendars',
17
+ MaintainCommunications: 'Collaboration:Permission:MaintainCommunications',
18
+ MaintainReservations: 'Collaboration:Permission:MaintainReservations',
19
+ MaintainHelpDesk: 'Collaboration:Permission:MaintainHelpDesk',
20
+ Setup: 'Collaboration:Permission:Setup',
21
+ };
22
+ /**
23
+ * @deprecated Prefer {@link AXPCollaborationPermissionKeys}.
24
+ * Legacy nested shape kept so existing imports compile during migration.
25
+ */
26
+ const AXMPermissionsKeys = {
27
+ Conversation: {
28
+ Management: AXPCollaborationPermissionKeys.MaintainConversations,
29
+ },
30
+ };
31
+
32
+ const config = {
33
+ i18n: 'conversation',
34
+ module: 'Conversation',
35
+ route: 'chat',
36
+ };
37
+ const RootConfig = {
38
+ config,
39
+ module: {
40
+ route: 'conversation',
41
+ name: config.module,
42
+ title: `@${config.i18n}:module.title`,
43
+ icon: 'fa-light fa-comments',
44
+ },
45
+ entities: {
46
+ room: {
47
+ name: 'Room',
48
+ title: `t("room.plural-title", { scope: "${config.i18n}" })`,
49
+ source: `${config.module}.Room`,
50
+ icon: 'fa-light fa-comments',
51
+ },
52
+ message: {
53
+ name: 'Message',
54
+ title: `t("message.plural-title", { scope: "${config.i18n}" })`,
55
+ source: `${config.module}.Message`,
56
+ icon: 'fa-light fa-message',
57
+ },
58
+ },
59
+ };
60
+
61
+ //#region ---- Media helpers ----
62
+ //#endregion
63
+
64
+ //#region ---- Imports ----
65
+ //#endregion
66
+ //#region ---- Constants ----
67
+ /** Emoji used for comment "like" reactions (maps to {@link AXReaction.emoji}). */
68
+ const AXM_COMMENT_LIKE_EMOJI = '👍';
69
+ //#endregion
70
+
71
+ //#region ---- Participant ----
72
+ //#endregion
73
+
74
+ //#region ---- Imports ----
75
+ //#endregion
76
+
77
+ //#region ---- Assist stream wire events (shared with server) ----
78
+ //#endregion
79
+
80
+ //#region ---- Assist metadata helpers (shared) ----
81
+ function axmExtractAssistIdFromMetadata(metadata) {
82
+ if (!metadata) {
83
+ return undefined;
84
+ }
85
+ const direct = metadata['assistId'];
86
+ if (typeof direct === 'string' && direct.trim()) {
87
+ return direct.trim();
88
+ }
89
+ const nested = metadata['metadata'];
90
+ if (nested && typeof nested === 'object' && nested !== null) {
91
+ const inner = nested['assistId'];
92
+ if (typeof inner === 'string' && inner.trim()) {
93
+ return inner.trim();
94
+ }
95
+ }
96
+ return undefined;
97
+ }
98
+ function axmExtractDirectAgentIdFromMetadata(metadata) {
99
+ if (!metadata) {
100
+ return undefined;
101
+ }
102
+ const direct = metadata['directAgentId'];
103
+ if (typeof direct === 'string' && direct.trim()) {
104
+ return direct.trim();
105
+ }
106
+ const nested = metadata['metadata'];
107
+ if (nested && typeof nested === 'object' && nested !== null) {
108
+ const inner = nested['directAgentId'];
109
+ if (typeof inner === 'string' && inner.trim()) {
110
+ return inner.trim();
111
+ }
112
+ }
113
+ return undefined;
114
+ }
115
+ function axmConversationHasAiChat(metadata) {
116
+ return !!(axmExtractAssistIdFromMetadata(metadata) ?? axmExtractDirectAgentIdFromMetadata(metadata));
117
+ }
118
+ function axmChatAiPeerParticipantId(catalogId) {
119
+ return `assist-${catalogId.trim()}`;
120
+ }
121
+ function axmReadAssistResponseStatus(metadata) {
122
+ const status = metadata?.['assistResponseStatus'];
123
+ return typeof status === 'string' ? status : undefined;
124
+ }
125
+ function axmReadReplyToUserMessageId(metadata) {
126
+ const replyTo = metadata?.['replyToUserMessageId'];
127
+ return typeof replyTo === 'string' && replyTo.trim() ? replyTo.trim() : undefined;
128
+ }
129
+ function extractMessageTextFromPayload(payload) {
130
+ const record = payload;
131
+ if (record?.type === 'text' && typeof record.text === 'string') {
132
+ return record.text;
133
+ }
134
+ return '';
135
+ }
136
+ function axmNormalizeConversationTitle(raw) {
137
+ const normalized = raw
138
+ .replace(/\r?\n+/g, ' ')
139
+ .replace(/^["'`]+|["'`]+$/g, '')
140
+ .replace(/\s+/g, ' ')
141
+ .trim();
142
+ return normalized.slice(0, 90).trim();
143
+ }
144
+ /** System prompt for a lightweight title-only model call (first user message → sidebar title). */
145
+ const AXM_ASSIST_CONVERSATION_TITLE_SYSTEM_PROMPT = `You generate short conversation titles for chat sidebars.
146
+
147
+ Given the user's first message, reply with ONLY a concise title (3–8 words, max 90 characters).
148
+ Use the same language as the user's message (for example Persian if they wrote in Persian).
149
+ Do not use quotes, colons, hashtags, or explanation. Output the title text only.`;
150
+ function axmSanitizeAiGeneratedConversationTitle(raw) {
151
+ let text = raw.trim();
152
+ if (!text) {
153
+ return null;
154
+ }
155
+ text = text.replace(/^["'`«»""]+|["'`«»""]+$/g, '').trim();
156
+ text = text.replace(/^(title|عنوان|topic|subject)\s*[::\-–—]\s*/i, '').trim();
157
+ text = text.replace(/^#+\s*/, '').trim();
158
+ const normalized = axmNormalizeConversationTitle(text);
159
+ return normalized || null;
160
+ }
161
+ /** Fallback when the title model is unavailable (max 6 words, 90 chars). */
162
+ function axmBuildHeuristicConversationTitleFallback(raw) {
163
+ const trimmed = raw.trim();
164
+ if (!trimmed) {
165
+ return null;
166
+ }
167
+ const normalized = axmNormalizeConversationTitle(trimmed.split(/\s+/).slice(0, 6).join(' '));
168
+ return normalized || null;
169
+ }
170
+ function axmCoerceMessageTimestampMs(value) {
171
+ if (value instanceof Date) {
172
+ return value.getTime();
173
+ }
174
+ if (typeof value === 'string' || typeof value === 'number') {
175
+ const ms = new Date(value).getTime();
176
+ return Number.isFinite(ms) ? ms : 0;
177
+ }
178
+ return 0;
179
+ }
180
+ /** Assist rows must sort after the user turn they reply to (client/server clocks may differ). */
181
+ function axmResolveAssistMessageTimestamp(options) {
182
+ const serverMs = options.serverNow?.getTime() ?? Date.now();
183
+ const userMs = axmCoerceMessageTimestampMs(options.replyToUserMessageTimestamp);
184
+ if (userMs > 0) {
185
+ return new Date(Math.max(serverMs, userMs + 1));
186
+ }
187
+ return new Date(serverMs);
188
+ }
189
+ function axmEnsureAssistMessageSortsAfterReplyTarget(message, replyTargetTimestamp) {
190
+ const replyMs = axmCoerceMessageTimestampMs(replyTargetTimestamp);
191
+ const assistMs = axmCoerceMessageTimestampMs(message.timestamp);
192
+ if (replyMs > 0 && assistMs <= replyMs) {
193
+ return { ...message, timestamp: new Date(replyMs + 1) };
194
+ }
195
+ return message;
196
+ }
197
+ /** Chronological sort with assist→user reply linkage when timestamps disagree across clocks. */
198
+ function axmCompareMessagesChronologically(a, b) {
199
+ const aReplyTo = axmReadReplyToUserMessageId(a.metadata);
200
+ const bReplyTo = axmReadReplyToUserMessageId(b.metadata);
201
+ if (aReplyTo === b.id) {
202
+ const diff = axmCoerceMessageTimestampMs(a.timestamp) - axmCoerceMessageTimestampMs(b.timestamp);
203
+ return diff > 0 ? diff : 1;
204
+ }
205
+ if (bReplyTo === a.id) {
206
+ const diff = axmCoerceMessageTimestampMs(a.timestamp) - axmCoerceMessageTimestampMs(b.timestamp);
207
+ return diff < 0 ? diff : -1;
208
+ }
209
+ const diff = axmCoerceMessageTimestampMs(a.timestamp) - axmCoerceMessageTimestampMs(b.timestamp);
210
+ return diff !== 0 ? diff : a.id.localeCompare(b.id);
211
+ }
212
+ //#endregion
213
+
214
+ //#region ---- Assist message handler port (server) ----
215
+ const AXM_CONVERSATION_ASSIST_MESSAGE_HANDLER = Symbol('AXM_CONVERSATION_ASSIST_MESSAGE_HANDLER');
216
+ //#endregion
217
+
218
+ //#region ---- Contracts barrel ----
219
+
220
+ /**
221
+ * Generated bundle index. Do not edit.
222
+ */
223
+
224
+ export { AXMPermissionsKeys, AXM_ASSIST_CONVERSATION_TITLE_SYSTEM_PROMPT, AXM_COMMENT_LIKE_EMOJI, AXM_CONVERSATION_ASSIST_MESSAGE_HANDLER, AXPCollaborationPermissionKeys, AXPConversationMenuKeys, RootConfig, axmBuildHeuristicConversationTitleFallback, axmChatAiPeerParticipantId, axmCoerceMessageTimestampMs, axmCompareMessagesChronologically, axmConversationHasAiChat, axmEnsureAssistMessageSortsAfterReplyTarget, axmExtractAssistIdFromMetadata, axmExtractDirectAgentIdFromMetadata, axmNormalizeConversationTitle, axmReadAssistResponseStatus, axmReadReplyToUserMessageId, axmResolveAssistMessageTimestamp, axmSanitizeAiGeneratedConversationTitle, extractMessageTextFromPayload };
225
+ //# sourceMappingURL=acorex-platform-module-conversation-client-contracts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acorex-platform-module-conversation-client-contracts.mjs","sources":["../../../../libs/modules/conversation/contracts/src/comment-entity-data.ts","../../../../libs/modules/conversation/contracts/src/menu.keys.ts","../../../../libs/modules/conversation/contracts/src/permission.keys.ts","../../../../libs/modules/conversation/contracts/src/root-config.ts","../../../../libs/modules/conversation/contracts/src/entities/message/message.contracts.ts","../../../../libs/modules/conversation/contracts/src/entities/message/message.types.ts","../../../../libs/modules/conversation/contracts/src/entities/room/room.contracts.ts","../../../../libs/modules/conversation/contracts/src/entities/room/room.types.ts","../../../../libs/modules/conversation/contracts/src/assist/conversation-assist-stream.types.ts","../../../../libs/modules/conversation/contracts/src/assist/conversation-assist-metadata.util.ts","../../../../libs/modules/conversation/contracts/src/assist/conversation-assist-handler.port.ts","../../../../libs/modules/conversation/contracts/src/index.ts","../../../../libs/modules/conversation/contracts/src/acorex-platform-module-conversation-client-contracts.ts"],"sourcesContent":["//#region ---- Comment entity reference ----\n\nexport interface AXMCommentEntityData {\n entityId: string;\n entityTypeId: string;\n moduleName?: string;\n entityName?: string;\n}\n\n//#endregion\n","export const AXPConversationMenuKeys = {\n Conversations: 'Conversation:Menu:Conversations',\n} as const;\n\n","/**\n * Collaboration capabilities used by this module.\n * Domain capability keys for this module. Root groups live in `AXPCommonPermissionGroupKeys` (common contracts).\n */\nexport const AXPCollaborationPermissionKeys = {\n Access: 'Collaboration:Permission:Access',\n MaintainConversations: 'Collaboration:Permission:MaintainConversations',\n MaintainMeetings: 'Collaboration:Permission:MaintainMeetings',\n MaintainCalendars: 'Collaboration:Permission:MaintainCalendars',\n MaintainCommunications: 'Collaboration:Permission:MaintainCommunications',\n MaintainReservations: 'Collaboration:Permission:MaintainReservations',\n MaintainHelpDesk: 'Collaboration:Permission:MaintainHelpDesk',\n Setup: 'Collaboration:Permission:Setup',\n} as const;\n\n/**\n * @deprecated Prefer {@link AXPCollaborationPermissionKeys}.\n * Legacy nested shape kept so existing imports compile during migration.\n */\nexport const AXMPermissionsKeys = {\n Conversation: {\n Management: AXPCollaborationPermissionKeys.MaintainConversations,\n },\n} as const;\n","const config = {\n i18n: 'conversation',\n module: 'Conversation',\n route: 'chat',\n};\n\nexport const RootConfig = {\n config,\n module: {\n route: 'conversation',\n name: config.module,\n title: `@${config.i18n}:module.title`,\n icon: 'fa-light fa-comments',\n },\n entities: {\n room: {\n name: 'Room',\n title: `t(\"room.plural-title\", { scope: \"${config.i18n}\" })`,\n source: `${config.module}.Room`,\n icon: 'fa-light fa-comments',\n },\n message: {\n name: 'Message',\n title: `t(\"message.plural-title\", { scope: \"${config.i18n}\" })`,\n source: `${config.module}.Message`,\n icon: 'fa-light fa-message',\n },\n },\n} as const;\n","//#region ---- Media helpers ----\n\n/** Fields for one uploaded or remote media item. */\nexport interface AXMediaItemFields {\n /** HTTP(S) or other persistable URL; omit when only {@link mediaId} is stored. */\n url?: string;\n mediaId?: string;\n mimeType?: string;\n size?: number;\n metadata?: Record<string, unknown>;\n}\n\n//#endregion\n\n//#region ---- Text payload ----\n\nexport interface AXTextFormat {\n start: number;\n end: number;\n type: 'bold' | 'italic' | 'code' | 'strikethrough' | 'underline' | 'spoiler';\n}\n\nexport interface AXMention {\n start: number;\n end: number;\n userId: string;\n userName: string;\n}\n\nexport interface AXLink {\n start: number;\n end: number;\n url: string;\n preview?: AXLinkPreview;\n}\n\nexport interface AXLinkPreview {\n title?: string;\n description?: string;\n image?: string;\n siteName?: string;\n}\n\nexport interface AXTextPayload {\n type: 'text';\n text: string;\n formatting?: AXTextFormat[];\n mentions?: AXMention[];\n links?: AXLink[];\n}\n\n//#endregion\n\n//#region ---- Media payloads ----\n\nexport interface AXImageMediaItem extends AXMediaItemFields {\n thumbnailUrl?: string;\n width: number;\n height: number;\n blurhash?: string;\n}\n\nexport interface AXImagePayload {\n type: 'image';\n images: AXImageMediaItem[];\n caption?: string;\n}\n\nexport interface AXVideoMediaItem extends AXMediaItemFields {\n thumbnailUrl?: string;\n duration: number;\n width: number;\n height: number;\n}\n\nexport interface AXVideoPayload {\n type: 'video';\n videos: AXVideoMediaItem[];\n caption?: string;\n}\n\nexport interface AXAudioMediaItem extends AXMediaItemFields {\n duration: number;\n title?: string;\n artist?: string;\n coverUrl?: string;\n waveform?: number[];\n}\n\nexport interface AXAudioPayload {\n type: 'audio';\n audios: AXAudioMediaItem[];\n caption?: string;\n}\n\nexport interface AXVoicePayload extends AXMediaItemFields {\n type: 'voice';\n duration: number;\n waveform?: number[];\n played?: boolean;\n}\n\nexport interface AXFileMediaItem extends AXMediaItemFields {\n name: string;\n mimeType: string;\n thumbnailUrl?: string;\n extension?: string;\n}\n\nexport interface AXFilePayload {\n type: 'file';\n files: AXFileMediaItem[];\n caption?: string;\n}\n\nexport interface AXLocationPayload {\n type: 'location';\n latitude: number;\n longitude: number;\n name?: string;\n address?: string;\n mapImageUrl?: string;\n accuracy?: number;\n}\n\nexport interface AXStickerPayload extends AXMediaItemFields {\n type: 'sticker';\n id: string;\n packId: string;\n animated: boolean;\n width?: number;\n height?: number;\n emoji?: string;\n}\n\n//#endregion\n\n//#region ---- Poll & system payloads ----\n\nexport interface AXPollOption {\n id: string;\n text: string;\n votes: number;\n voters?: string[];\n}\n\nexport interface AXPollPayload {\n type: 'poll';\n question: string;\n options: AXPollOption[];\n multipleChoice: boolean;\n anonymous: boolean;\n expiresAt?: Date;\n totalVotes?: number;\n}\n\nexport type AXSystemEventType =\n | 'user_joined'\n | 'user_left'\n | 'title_changed'\n | 'avatar_changed'\n | 'call_declined'\n | 'call_missed'\n | 'call_cancelled'\n | 'custom';\n\nexport interface AXSystemPayload {\n type: 'system';\n eventType: AXSystemEventType;\n text: string;\n userIds?: string[];\n data?: Record<string, unknown>;\n}\n\n//#endregion\n\n//#region ---- Platform extensions ----\n\n/** Layout/node payload used by assist transcripts and dynamic UI messages. */\nexport interface AXNodePayload {\n type: 'node';\n content: unknown;\n}\n\n//#endregion\n\n//#region ---- Message core types ----\n\n/** Aligned with `@acorex/components/conversation` — node payloads use {@link AXNodePayload} at runtime with an explicit cast. */\nexport type AXMessagePayload =\n | AXTextPayload\n | AXImagePayload\n | AXVideoPayload\n | AXAudioPayload\n | AXVoicePayload\n | AXFilePayload\n | AXLocationPayload\n | AXStickerPayload\n | AXPollPayload\n | AXSystemPayload;\n\nexport type AXMessageStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'failed';\n\nexport type AXMessageType =\n | 'text'\n | 'image'\n | 'video'\n | 'audio'\n | 'voice'\n | 'file'\n | 'location'\n | 'sticker'\n | 'poll'\n | 'system'\n | 'node'\n | 'assist-response'\n | string;\n\n/** Reaction on a message. */\nexport interface AXReaction {\n /** Emoji character */\n emoji: string;\n /** User ID who reacted */\n userId: string;\n /** Reaction timestamp */\n timestamp: Date;\n}\n\n//#endregion\n","//#region ---- Imports ----\n\nimport { AXPEntityModel } from '@acorex-platform/framework-shared/entity';\n\nimport type {\n AXMessagePayload,\n AXMessageStatus,\n AXMessageType,\n AXReaction,\n} from './message.contracts';\n\n//#endregion\n\n//#region ---- Re-exports ----\n\nexport type {\n AXAudioMediaItem,\n AXAudioPayload,\n AXFileMediaItem,\n AXFilePayload,\n AXImageMediaItem,\n AXImagePayload,\n AXLink,\n AXLinkPreview,\n AXMediaItemFields,\n AXMention,\n AXMessagePayload,\n AXMessageStatus,\n AXMessageType,\n AXNodePayload,\n AXPollOption,\n AXPollPayload,\n AXReaction,\n AXStickerPayload,\n AXSystemEventType,\n AXSystemPayload,\n AXTextFormat,\n AXTextPayload,\n AXVideoMediaItem,\n AXVideoPayload,\n AXVoicePayload,\n} from './message.contracts';\n\n//#endregion\n\n//#region ---- Constants ----\n\n/** Emoji used for comment \"like\" reactions (maps to {@link AXReaction.emoji}). */\nexport const AXM_COMMENT_LIKE_EMOJI = '👍';\n\n//#endregion\n\n//#region ---- Legacy aliases (comment feature) ----\n\n/** @deprecated Use emoji string with AXReaction instead. */\nexport type AXMReactionType = string;\n\n/** @deprecated Use AXReaction instead. */\nexport type AXMConversationReaction = AXReaction;\n\n//#endregion\n\n//#region ---- Entity model ----\n\n/**\n * Persisted message entity — conversation message shape plus platform entity base.\n */\nexport interface AXMConversationMessage extends AXPEntityModel<string> {\n /** Conversation (room) this message belongs to */\n conversationId: string;\n /** Sender user id */\n senderId: string;\n /** Message type */\n type: AXMessageType;\n /** File-type catalog name when this message uses a composer file type */\n fileType?: string;\n /** Message creation timestamp */\n timestamp: Date;\n /** Type-specific message payload */\n payload: AXMessagePayload;\n /** Message delivery/read status */\n status: AXMessageStatus;\n /** Replied message reference (for quote replies) */\n replyTo?: AXMConversationMessage;\n /** Whether this message was forwarded */\n forwarded?: boolean;\n /** Original sender information (if forwarded) */\n forwardedFrom?: {\n messageId: string;\n senderId: string;\n senderName?: string;\n conversationId: string;\n conversationTitle?: string;\n };\n /** Message reactions */\n reactions: AXReaction[];\n /** Whether message is pinned */\n pinned?: boolean;\n /** Edit timestamp (if edited) */\n editedAt?: Date;\n /** Whether message is deleted */\n deleted?: boolean;\n /** Deleted timestamp */\n deletedAt?: Date;\n /** Local-only flag (not synced to server yet) */\n isLocal?: boolean;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n /** Plain-text snippet for entity admin list column */\n title?: string;\n /** Programmatic name for entity admin */\n name?: string;\n}\n\n//#endregion\n","//#region ---- Participant ----\n\nexport type AXParticipantRole = 'admin' | 'moderator' | 'member';\n\nexport type AXParticipantStatus = 'online' | 'offline' | 'away';\n\n/** Extended profile fields shown in private-chat info panels. */\nexport interface AXUserProfile {\n bio?: string;\n phone?: string;\n email?: string;\n username?: string;\n location?: string;\n company?: string;\n title?: string;\n}\n\n/** Represents a user/member in a conversation. */\nexport interface AXParticipant {\n /** Unique identifier for the participant */\n id: string;\n /** Display name of the participant */\n name: string;\n /**\n * Short line shown under the name in lists (e.g. job title, status line).\n * Distinct from long-form bio in optional `profile.bio`.\n */\n description?: string;\n /** Optional extended profile details for private chats. */\n profile?: AXUserProfile;\n /** Avatar/profile image URL */\n avatar?: string;\n /**\n * Font Awesome icon class(es) used when `avatar` is not set (e.g. `'fa-light fa-user'`).\n */\n icon?: string;\n /** Role in the conversation (for groups/channels) */\n role?: AXParticipantRole;\n /** Current online status */\n status?: AXParticipantStatus;\n /** Last seen timestamp (when offline/away) */\n lastSeen?: Date;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n}\n\n//#endregion\n\n//#region ---- Conversation ----\n\nexport type AXConversationType = 'private' | 'group' | 'channel' | 'bot';\n\n/** Conversation status information. */\nexport interface AXConversationStatus {\n /** Whether someone is typing */\n isTyping: boolean;\n /** User IDs currently typing */\n typingUsers: string[];\n /** Online presence (for private chats) */\n presence?: 'online' | 'offline' | 'away';\n /** Last seen timestamp (for private chats when offline) */\n lastSeen?: Date;\n}\n\n/** Conversation settings. */\nexport interface AXConversationSettings {\n /** Muted until timestamp */\n mutedUntil?: Date;\n /** Show notifications */\n notifications: boolean;\n /** Custom notification sound */\n notificationSound?: string;\n /** Show message preview in notifications */\n showPreview: boolean;\n /** Custom settings */\n custom?: Record<string, unknown>;\n}\n\n/** Theme-specific CSS `background` values for the message list area. */\nexport interface AXConversationMessageListThemeBackground {\n light: string;\n dark: string;\n}\n\n/** Single CSS value (both themes) or per-theme `{ light, dark }` backgrounds. */\nexport type AXConversationMessageListBackground =\n | string\n | AXConversationMessageListThemeBackground;\n\n/**\n * Extensible map for app-specific conversation data.\n * Aligned with `@acorex/components/conversation` — UI-only keys such as\n * `messageListEmptyComponent` are stored as opaque values when persisted.\n */\nexport interface AXConversationMetadata extends Record<string, unknown> {\n /** Optional custom background CSS for message list (per light/dark theme). */\n messageListBackground?: AXConversationMessageListBackground;\n /**\n * When `false`, hides reaction UI for this conversation.\n * Defaults to `true` when omitted.\n */\n reactionsEnabled?: boolean;\n}\n\n//#endregion\n","//#region ---- Imports ----\n\nimport { AXPEntityModel } from '@acorex-platform/framework-shared/entity';\n\nimport { AXMCommentEntityData } from '../../index';\nimport { AXMConversationMessage } from '../message/message.types';\n\nimport type {\n AXConversationMetadata,\n AXConversationSettings,\n AXConversationStatus,\n AXConversationType,\n AXParticipant,\n} from './room.contracts';\n\n//#endregion\n\n//#region ---- Re-exports ----\n\nexport type {\n AXConversationMessageListBackground,\n AXConversationMessageListThemeBackground,\n AXConversationMetadata,\n AXConversationSettings,\n AXConversationStatus,\n AXConversationType,\n AXParticipant,\n AXParticipantRole,\n AXParticipantStatus,\n AXUserProfile,\n} from './room.contracts';\n\n//#endregion\n\n//#region ---- Domain enums ----\n\n/** Distinguishes chat inbox rooms from entity comment threads in the unified store. */\nexport type AXMConversationRoomKind = 'chat' | 'comment';\n\n//#endregion\n\n//#region ---- Entity model ----\n\n/**\n * Persisted room entity — conversation shape plus platform entity base.\n */\nexport interface AXMConversationRoom extends AXPEntityModel<string> {\n /** Chat vs comment thread discriminator */\n kind: AXMConversationRoomKind;\n /** Conversation type (private, group, channel, bot) */\n type: AXConversationType;\n /** User who created this conversation */\n creatorId?: string;\n /** Conversation title/name */\n title: string;\n /** Conversation avatar/image URL */\n avatar?: string;\n /** Font Awesome icon class(es) when no image avatar is used */\n icon?: string;\n /** Conversation description (for groups/channels) */\n description?: string;\n /** List of participants */\n participants: AXParticipant[];\n /** Last message in the conversation */\n lastMessage?: AXMConversationMessage;\n /** Timestamp of last message */\n lastMessageAt: Date;\n /** Number of unread messages */\n unreadCount: number;\n /** Number of unread mentions */\n unreadMentions?: number;\n /** Current status (typing, presence, etc.) */\n status: AXConversationStatus;\n /** User-specific settings */\n settings: AXConversationSettings;\n /** Pinned messages IDs */\n pinnedMessageIds?: string[];\n /** Conversation creation timestamp */\n createdAt: Date;\n /** Last update timestamp */\n updatedAt: Date;\n /** Whether conversation is blocked */\n blocked?: boolean;\n /** Whether conversation is pinned */\n pinned?: boolean;\n /** Whether conversation is archived */\n archived?: boolean;\n /** Draft message text */\n draft?: string;\n /** Custom metadata */\n metadata?: AXConversationMetadata;\n /** Programmatic name for entity admin */\n name?: string;\n /** Entity reference for comment threads */\n entityRef?: AXMCommentEntityData;\n /** Comment thread topic/subject */\n topic?: string;\n}\n\n//#endregion\n","//#region ---- Assist stream wire events (shared with server) ----\n\nimport type { AXMConversationMessage, AXMConversationRoom } from '@acorex-platform/module-conversation-contracts';\n\n/** Minimal tool-call shape for assist-stream frontend broker round-trips (mirrors AXPAiToolCall). */\nexport interface ConversationAssistFrontendToolCall {\n id: string;\n name: string;\n arguments?: unknown;\n}\n\nexport type ConversationAssistWireEvent =\n | {\n type: 'assist_started';\n conversationId: string;\n messageId: string;\n userMessageId: string;\n message: AXMConversationMessage;\n }\n | { type: 'message_patch'; message: AXMConversationMessage }\n | { type: 'conversation_patch'; room: AXMConversationRoom }\n | {\n type: 'assist_completed';\n conversationId: string;\n messageId: string;\n message: AXMConversationMessage;\n /** Present when an auto-generated title was applied at finalize time. */\n room?: AXMConversationRoom;\n }\n | { type: 'assist_failed'; conversationId: string; messageId: string; error: string; message: AXMConversationMessage }\n | {\n type: 'frontend_tool_call';\n runId: string;\n call: ConversationAssistFrontendToolCall;\n };\n\n//#endregion\n","//#region ---- Assist metadata helpers (shared) ----\n\nexport function axmExtractAssistIdFromMetadata(metadata: Record<string, unknown> | undefined): string | undefined {\n if (!metadata) {\n return undefined;\n }\n const direct = metadata['assistId'];\n if (typeof direct === 'string' && direct.trim()) {\n return direct.trim();\n }\n const nested = metadata['metadata'];\n if (nested && typeof nested === 'object' && nested !== null) {\n const inner = (nested as Record<string, unknown>)['assistId'];\n if (typeof inner === 'string' && inner.trim()) {\n return inner.trim();\n }\n }\n return undefined;\n}\n\nexport function axmExtractDirectAgentIdFromMetadata(\n metadata: Record<string, unknown> | undefined,\n): string | undefined {\n if (!metadata) {\n return undefined;\n }\n const direct = metadata['directAgentId'];\n if (typeof direct === 'string' && direct.trim()) {\n return direct.trim();\n }\n const nested = metadata['metadata'];\n if (nested && typeof nested === 'object' && nested !== null) {\n const inner = (nested as Record<string, unknown>)['directAgentId'];\n if (typeof inner === 'string' && inner.trim()) {\n return inner.trim();\n }\n }\n return undefined;\n}\n\nexport function axmConversationHasAiChat(metadata: Record<string, unknown> | undefined): boolean {\n return !!(axmExtractAssistIdFromMetadata(metadata) ?? axmExtractDirectAgentIdFromMetadata(metadata));\n}\n\nexport function axmChatAiPeerParticipantId(catalogId: string): string {\n return `assist-${catalogId.trim()}`;\n}\n\nexport function axmReadAssistResponseStatus(metadata: Record<string, unknown> | undefined): string | undefined {\n const status = metadata?.['assistResponseStatus'];\n return typeof status === 'string' ? status : undefined;\n}\n\nexport function axmReadReplyToUserMessageId(metadata: Record<string, unknown> | undefined): string | undefined {\n const replyTo = metadata?.['replyToUserMessageId'];\n return typeof replyTo === 'string' && replyTo.trim() ? replyTo.trim() : undefined;\n}\n\nexport function extractMessageTextFromPayload(payload: unknown): string {\n const record = payload as { type?: string; text?: string } | undefined;\n if (record?.type === 'text' && typeof record.text === 'string') {\n return record.text;\n }\n return '';\n}\n\nexport function axmNormalizeConversationTitle(raw: string): string {\n const normalized = raw\n .replace(/\\r?\\n+/g, ' ')\n .replace(/^[\"'`]+|[\"'`]+$/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n return normalized.slice(0, 90).trim();\n}\n\n/** System prompt for a lightweight title-only model call (first user message → sidebar title). */\nexport const AXM_ASSIST_CONVERSATION_TITLE_SYSTEM_PROMPT = `You generate short conversation titles for chat sidebars.\n\nGiven the user's first message, reply with ONLY a concise title (3–8 words, max 90 characters).\nUse the same language as the user's message (for example Persian if they wrote in Persian).\nDo not use quotes, colons, hashtags, or explanation. Output the title text only.`;\n\nexport function axmSanitizeAiGeneratedConversationTitle(raw: string): string | null {\n let text = raw.trim();\n if (!text) {\n return null;\n }\n text = text.replace(/^[\"'`«»\"\"]+|[\"'`«»\"\"]+$/g, '').trim();\n text = text.replace(/^(title|عنوان|topic|subject)\\s*[::\\-–—]\\s*/i, '').trim();\n text = text.replace(/^#+\\s*/, '').trim();\n const normalized = axmNormalizeConversationTitle(text);\n return normalized || null;\n}\n\n/** Fallback when the title model is unavailable (max 6 words, 90 chars). */\nexport function axmBuildHeuristicConversationTitleFallback(raw: string): string | null {\n const trimmed = raw.trim();\n if (!trimmed) {\n return null;\n }\n const normalized = axmNormalizeConversationTitle(trimmed.split(/\\s+/).slice(0, 6).join(' '));\n return normalized || null;\n}\n\nexport function axmCoerceMessageTimestampMs(value: unknown): number {\n if (value instanceof Date) {\n return value.getTime();\n }\n if (typeof value === 'string' || typeof value === 'number') {\n const ms = new Date(value).getTime();\n return Number.isFinite(ms) ? ms : 0;\n }\n return 0;\n}\n\n/** Assist rows must sort after the user turn they reply to (client/server clocks may differ). */\nexport function axmResolveAssistMessageTimestamp(options: {\n replyToUserMessageTimestamp?: unknown;\n serverNow?: Date;\n}): Date {\n const serverMs = options.serverNow?.getTime() ?? Date.now();\n const userMs = axmCoerceMessageTimestampMs(options.replyToUserMessageTimestamp);\n if (userMs > 0) {\n return new Date(Math.max(serverMs, userMs + 1));\n }\n return new Date(serverMs);\n}\n\nexport function axmEnsureAssistMessageSortsAfterReplyTarget<T extends { timestamp: unknown }>(\n message: T,\n replyTargetTimestamp: unknown,\n): T {\n const replyMs = axmCoerceMessageTimestampMs(replyTargetTimestamp);\n const assistMs = axmCoerceMessageTimestampMs(message.timestamp);\n if (replyMs > 0 && assistMs <= replyMs) {\n return { ...message, timestamp: new Date(replyMs + 1) };\n }\n return message;\n}\n\n/** Chronological sort with assist→user reply linkage when timestamps disagree across clocks. */\nexport function axmCompareMessagesChronologically(\n a: { id: string; timestamp: unknown; metadata?: Record<string, unknown> },\n b: { id: string; timestamp: unknown; metadata?: Record<string, unknown> },\n): number {\n const aReplyTo = axmReadReplyToUserMessageId(a.metadata);\n const bReplyTo = axmReadReplyToUserMessageId(b.metadata);\n if (aReplyTo === b.id) {\n const diff = axmCoerceMessageTimestampMs(a.timestamp) - axmCoerceMessageTimestampMs(b.timestamp);\n return diff > 0 ? diff : 1;\n }\n if (bReplyTo === a.id) {\n const diff = axmCoerceMessageTimestampMs(a.timestamp) - axmCoerceMessageTimestampMs(b.timestamp);\n return diff < 0 ? diff : -1;\n }\n const diff = axmCoerceMessageTimestampMs(a.timestamp) - axmCoerceMessageTimestampMs(b.timestamp);\n return diff !== 0 ? diff : a.id.localeCompare(b.id);\n}\n\n//#endregion\n","//#region ---- Assist message handler port (server) ----\n\nimport type { AXMConversationMessage } from '../entities/message/message.types';\n\nexport interface AXMConversationAssistMessageHandler {\n maybeStartAfterUserMessage(userMessage: AXMConversationMessage): Promise<void>;\n\n retryAssistResponse(\n conversationId: string,\n messageId: string,\n options?: { replyToUserMessageId?: string },\n ): Promise<AXMConversationMessage>;\n}\n\nexport const AXM_CONVERSATION_ASSIST_MESSAGE_HANDLER = Symbol('AXM_CONVERSATION_ASSIST_MESSAGE_HANDLER');\n\n//#endregion\n","//#region ---- Contracts barrel ----\n\nexport * from './comment-entity-data';\n\nexport * from './menu.keys';\nexport * from './permission.keys';\n\nexport * from './root-config';\n\n//#endregion\n\nexport * from './entities';\nexport * from './assist/conversation-assist-stream.types';\nexport * from './assist/conversation-assist-metadata.util';\nexport * from './assist/conversation-assist-handler.port';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { AXPRealtimeConnectionPort } from '@acorex-platform/framework-client/realtime';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, Injectable } from '@angular/core';
4
+
5
+ //#region ---- Imports ----
6
+ //#endregion
7
+ //#region ---- Command ----
8
+ class AXMConversationEmitTypingIndicatorCommand {
9
+ constructor() {
10
+ this.realtime = inject(AXPRealtimeConnectionPort, { optional: true });
11
+ }
12
+ async execute(input) {
13
+ const options = input;
14
+ const conversationId = options.conversationId?.trim();
15
+ if (conversationId) {
16
+ this.realtime?.emitConversationTyping(conversationId, options.active !== false);
17
+ }
18
+ return { success: true, kind: 'object', data: undefined };
19
+ }
20
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationEmitTypingIndicatorCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
21
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationEmitTypingIndicatorCommand, providedIn: 'root' }); }
22
+ }
23
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationEmitTypingIndicatorCommand, decorators: [{
24
+ type: Injectable,
25
+ args: [{ providedIn: 'root' }]
26
+ }] });
27
+
28
+ export { AXMConversationEmitTypingIndicatorCommand };
29
+ //# sourceMappingURL=acorex-platform-module-conversation-client-emit-typing-indicator.command-BzsN1_ns.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acorex-platform-module-conversation-client-emit-typing-indicator.command-BzsN1_ns.mjs","sources":["../../../../libs/modules/conversation/client/src/lib/features/commands/emit-typing-indicator.command.ts"],"sourcesContent":["//#region ---- Imports ----\n\nimport { AXPRealtimeConnectionPort } from '@acorex-platform/framework-client/realtime';\nimport { AXPCommand, type AXPCommandExecuteResultPromise } from '@acorex-platform/framework-shared/runtime';\n\nimport { inject, Injectable } from '@angular/core';\n\n//#endregion\n\n//#region ---- Types ----\n\nexport interface AXMEmitTypingIndicatorOptions {\n conversationId: string;\n userId: string;\n userName: string;\n active: boolean;\n}\n\n//#endregion\n\n//#region ---- Command ----\n\n@Injectable({ providedIn: 'root' })\nexport class AXMConversationEmitTypingIndicatorCommand implements AXPCommand<AXMEmitTypingIndicatorOptions, void> {\n private readonly realtime = inject(AXPRealtimeConnectionPort, { optional: true });\n\n async execute(input: AXMEmitTypingIndicatorOptions | unknown): AXPCommandExecuteResultPromise<void> {\n const options = input as AXMEmitTypingIndicatorOptions;\n const conversationId = options.conversationId?.trim();\n if (conversationId) {\n this.realtime?.emitConversationTyping(conversationId, options.active !== false);\n }\n return { success: true, kind: 'object', data: undefined };\n }\n}\n\n//#endregion\n"],"names":[],"mappings":";;;;AAAA;AAkBA;AAEA;MAGa,yCAAyC,CAAA;AADtD,IAAA,WAAA,GAAA;QAEmB,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,yBAAyB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAUlF,IAAA;IARC,MAAM,OAAO,CAAC,KAA8C,EAAA;QAC1D,MAAM,OAAO,GAAG,KAAsC;QACtD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE;QACrD,IAAI,cAAc,EAAE;AAClB,YAAA,IAAI,CAAC,QAAQ,EAAE,sBAAsB,CAAC,cAAc,EAAE,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC;QACjF;AACA,QAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;IAC3D;8GAVW,yCAAyC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAzC,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,yCAAyC,cAD5B,MAAM,EAAA,CAAA,CAAA;;2FACnB,yCAAyC,EAAA,UAAA,EAAA,CAAA;kBADrD,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}
@@ -0,0 +1,30 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, Injectable } from '@angular/core';
3
+ import { A as AXMConversationEntityStoreService } from './acorex-platform-module-conversation-client-acorex-platform-module-conversation-client-DsjrXRZ6.mjs';
4
+
5
+ //#endregion
6
+ //#region ---- Command ----
7
+ class AXMConversationMarkConversationUnreadCommand {
8
+ constructor() {
9
+ this.store = inject(AXMConversationEntityStoreService);
10
+ }
11
+ async execute(input) {
12
+ const options = input;
13
+ const conversation = await this.store.getConversation(options.conversationId);
14
+ if (!conversation) {
15
+ return { success: false };
16
+ }
17
+ const unreadCount = Math.max(1, conversation.unreadCount ?? 0);
18
+ await this.store.setUnreadCount(options.conversationId, unreadCount);
19
+ return { success: true, kind: 'object', data: undefined };
20
+ }
21
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationMarkConversationUnreadCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
22
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationMarkConversationUnreadCommand, providedIn: 'root' }); }
23
+ }
24
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationMarkConversationUnreadCommand, decorators: [{
25
+ type: Injectable,
26
+ args: [{ providedIn: 'root' }]
27
+ }] });
28
+
29
+ export { AXMConversationMarkConversationUnreadCommand };
30
+ //# sourceMappingURL=acorex-platform-module-conversation-client-mark-conversation-unread.command-BlYDwGVe.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acorex-platform-module-conversation-client-mark-conversation-unread.command-BlYDwGVe.mjs","sources":["../../../../libs/modules/conversation/client/src/lib/features/commands/mark-conversation-unread.command.ts"],"sourcesContent":["//#region ---- Imports ----\n\nimport { AXPCommand, type AXPCommandExecuteResultPromise } from '@acorex-platform/framework-shared/runtime';\nimport { AXPRuntimeCommandResult } from '@acorex-platform/framework-shared/core';\n\nimport { inject, Injectable } from '@angular/core';\n\nimport { AXMConversationEntityStoreService } from '../chat/services/conversation-entity-store.service';\n\n//#endregion\n\n//#region ---- Types ----\n\nexport interface AXMMarkConversationUnreadOptions {\n conversationId: string;\n}\n\n//#endregion\n\n//#region ---- Command ----\n\n@Injectable({ providedIn: 'root' })\nexport class AXMConversationMarkConversationUnreadCommand implements AXPCommand<AXMMarkConversationUnreadOptions, void> {\n private readonly store = inject(AXMConversationEntityStoreService);\n\n async execute(input: AXMMarkConversationUnreadOptions | unknown): AXPCommandExecuteResultPromise<void> {\n const options = input as AXMMarkConversationUnreadOptions;\n const conversation = await this.store.getConversation(options.conversationId);\n if (!conversation) {\n return { success: false };\n }\n const unreadCount = Math.max(1, conversation.unreadCount ?? 0);\n await this.store.setUnreadCount(options.conversationId, unreadCount);\n return { success: true, kind: 'object', data: undefined };\n }\n}\n\n//#endregion\n"],"names":[],"mappings":";;;;AAiBA;AAEA;MAGa,4CAA4C,CAAA;AADzD,IAAA,WAAA,GAAA;AAEmB,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,iCAAiC,CAAC;AAYnE,IAAA;IAVC,MAAM,OAAO,CAAC,KAAiD,EAAA;QAC7D,MAAM,OAAO,GAAG,KAAyC;AACzD,QAAA,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,cAAc,CAAC;QAC7E,IAAI,CAAC,YAAY,EAAE;AACjB,YAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;QAC3B;AACA,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,WAAW,IAAI,CAAC,CAAC;AAC9D,QAAA,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,cAAc,EAAE,WAAW,CAAC;AACpE,QAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;IAC3D;8GAZW,4CAA4C,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAA5C,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,4CAA4C,cAD/B,MAAM,EAAA,CAAA,CAAA;;2FACnB,4CAA4C,EAAA,UAAA,EAAA,CAAA;kBADxD,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}
@@ -0,0 +1,42 @@
1
+ import { AXConversationService } from '@acorex/components/conversation';
2
+ import { AXPSessionService } from '@acorex-platform/framework-client/auth';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, Injectable } from '@angular/core';
5
+ import { Router } from '@angular/router';
6
+
7
+ //#endregion
8
+ //#region ----- Command -----
9
+ /** Opens an existing conversation in the chat app. */
10
+ class AXMConversationOpenChatCommand {
11
+ constructor() {
12
+ //#region ----- Services & Dependencies -----
13
+ this.conversationService = inject(AXConversationService);
14
+ this.sessionService = inject(AXPSessionService);
15
+ this.router = inject(Router);
16
+ }
17
+ //#endregion
18
+ async execute(input) {
19
+ const conversationId = typeof input?.conversationId === 'string'
20
+ ? input.conversationId.trim()
21
+ : '';
22
+ if (!conversationId) {
23
+ return { success: false, message: { text: '@conversation:chat.route.conversation-not-found' } };
24
+ }
25
+ await this.conversationService.selectConversation(conversationId);
26
+ await this.router.navigate([this.applicationRouteSegment(), 'chat', conversationId]);
27
+ return { success: true, kind: 'object', data: { conversationId } };
28
+ }
29
+ //#region ----- Private -----
30
+ applicationRouteSegment() {
31
+ return this.sessionService.application?.name?.trim() || 'platform';
32
+ }
33
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationOpenChatCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
34
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationOpenChatCommand, providedIn: 'root' }); }
35
+ }
36
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationOpenChatCommand, decorators: [{
37
+ type: Injectable,
38
+ args: [{ providedIn: 'root' }]
39
+ }] });
40
+
41
+ export { AXMConversationOpenChatCommand };
42
+ //# sourceMappingURL=acorex-platform-module-conversation-client-open-chat.command-B03q60Qx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acorex-platform-module-conversation-client-open-chat.command-B03q60Qx.mjs","sources":["../../../../libs/modules/conversation/client/src/lib/features/commands/open-chat.command.ts"],"sourcesContent":["import { AXConversationService } from '@acorex/components/conversation';\nimport { AXPSessionService } from '@acorex-platform/framework-client/auth';\nimport { AXPCommand, type AXPCommandExecuteResultPromise } from '@acorex-platform/framework-shared/runtime';\nimport { inject, Injectable } from '@angular/core';\nimport { Router } from '@angular/router';\n\n//#region ----- Types -----\n\nexport interface AXMOpenChatOptions {\n conversationId?: string;\n}\n\n//#endregion\n\n//#region ----- Command -----\n\n/** Opens an existing conversation in the chat app. */\n@Injectable({ providedIn: 'root' })\nexport class AXMConversationOpenChatCommand implements AXPCommand<AXMOpenChatOptions, { conversationId: string }> {\n //#region ----- Services & Dependencies -----\n\n private readonly conversationService = inject(AXConversationService);\n private readonly sessionService = inject(AXPSessionService);\n private readonly router = inject(Router);\n\n //#endregion\n\n async execute(input: AXMOpenChatOptions | unknown): AXPCommandExecuteResultPromise<{ conversationId: string }> {\n const conversationId =\n typeof (input as AXMOpenChatOptions)?.conversationId === 'string'\n ? (input as AXMOpenChatOptions).conversationId!.trim()\n : '';\n\n if (!conversationId) {\n return { success: false, message: { text: '@conversation:chat.route.conversation-not-found' } };\n }\n\n await this.conversationService.selectConversation(conversationId);\n await this.router.navigate([this.applicationRouteSegment(), 'chat', conversationId]);\n return { success: true, kind: 'object', data: { conversationId } };\n }\n\n //#region ----- Private -----\n\n private applicationRouteSegment(): string {\n return this.sessionService.application?.name?.trim() || 'platform';\n }\n\n //#endregion\n}\n\n//#endregion\n"],"names":[],"mappings":";;;;;;AAYA;AAEA;AAEA;MAEa,8BAA8B,CAAA;AAD3C,IAAA,WAAA,GAAA;;AAImB,QAAA,IAAA,CAAA,mBAAmB,GAAG,MAAM,CAAC,qBAAqB,CAAC;AACnD,QAAA,IAAA,CAAA,cAAc,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAC1C,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AA0BzC,IAAA;;IAtBC,MAAM,OAAO,CAAC,KAAmC,EAAA;AAC/C,QAAA,MAAM,cAAc,GAClB,OAAQ,KAA4B,EAAE,cAAc,KAAK;AACvD,cAAG,KAA4B,CAAC,cAAe,CAAC,IAAI;cAClD,EAAE;QAER,IAAI,CAAC,cAAc,EAAE;AACnB,YAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,iDAAiD,EAAE,EAAE;QACjG;QAEA,MAAM,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,cAAc,CAAC;AACjE,QAAA,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;AACpF,QAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,EAAE;IACpE;;IAIQ,uBAAuB,GAAA;AAC7B,QAAA,OAAO,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,UAAU;IACpE;8GA5BW,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAA9B,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,8BAA8B,cADjB,MAAM,EAAA,CAAA,CAAA;;2FACnB,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAD1C,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}
@@ -0,0 +1,34 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, Injectable } from '@angular/core';
3
+ import { a as AXM_CONVERSATION_ASSIST_RESPONSE_PORT } from './acorex-platform-module-conversation-client-acorex-platform-module-conversation-client-DsjrXRZ6.mjs';
4
+
5
+ //#endregion
6
+ //#region ---- Command ----
7
+ class AXMConversationRetryAssistResponseCommand {
8
+ constructor() {
9
+ this.assistResponse = inject(AXM_CONVERSATION_ASSIST_RESPONSE_PORT, { optional: true });
10
+ }
11
+ async execute(input) {
12
+ const options = input;
13
+ if (!this.assistResponse) {
14
+ return { success: false, message: { text: 'Assist response service is not available.' } };
15
+ }
16
+ try {
17
+ const message = await this.assistResponse.retryAssistResponse(options.conversationId, options.messageId);
18
+ return { success: true, kind: 'object', data: { message } };
19
+ }
20
+ catch (error) {
21
+ console.error('[Conversation:RetryAssistResponse] Failed:', error);
22
+ return { success: false };
23
+ }
24
+ }
25
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationRetryAssistResponseCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
26
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationRetryAssistResponseCommand, providedIn: 'root' }); }
27
+ }
28
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMConversationRetryAssistResponseCommand, decorators: [{
29
+ type: Injectable,
30
+ args: [{ providedIn: 'root' }]
31
+ }] });
32
+
33
+ export { AXMConversationRetryAssistResponseCommand };
34
+ //# sourceMappingURL=acorex-platform-module-conversation-client-retry-assist-response.command-BQLK6F69.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acorex-platform-module-conversation-client-retry-assist-response.command-BQLK6F69.mjs","sources":["../../../../libs/modules/conversation/client/src/lib/features/commands/retry-assist-response.command.ts"],"sourcesContent":["//#region ---- Imports ----\n\nimport { AXPCommand, type AXPCommandExecuteResultPromise } from '@acorex-platform/framework-shared/runtime';\nimport type { AXConversationMessage } from '@acorex/components/conversation';\nimport { AXPRuntimeCommandResult } from '@acorex-platform/framework-shared/core';\n\nimport { Injectable, inject } from '@angular/core';\n\nimport { AXM_CONVERSATION_ASSIST_RESPONSE_PORT } from '../chat/services/conversation-assist-response.port';\n\n//#endregion\n\n//#region ---- Types ----\n\nexport interface AXMRetryAssistResponseOptions {\n conversationId: string;\n messageId: string;\n}\n\nexport interface AXMRetryAssistResponseResult {\n message: AXConversationMessage;\n}\n\n//#endregion\n\n//#region ---- Command ----\n\n@Injectable({ providedIn: 'root' })\nexport class AXMConversationRetryAssistResponseCommand\n implements AXPCommand<AXMRetryAssistResponseOptions, AXMRetryAssistResponseResult>\n{\n private readonly assistResponse = inject(AXM_CONVERSATION_ASSIST_RESPONSE_PORT, { optional: true });\n\n async execute(input: AXMRetryAssistResponseOptions | unknown): AXPCommandExecuteResultPromise<AXMRetryAssistResponseResult> {\n const options = input as AXMRetryAssistResponseOptions;\n if (!this.assistResponse) {\n return { success: false, message: { text: 'Assist response service is not available.' } };\n }\n\n try {\n const message = await this.assistResponse.retryAssistResponse(options.conversationId, options.messageId);\n return { success: true, kind: 'object', data: { message } };\n } catch (error: unknown) {\n console.error('[Conversation:RetryAssistResponse] Failed:', error);\n return { success: false };\n }\n }\n}\n\n//#endregion\n"],"names":[],"mappings":";;;;AAuBA;AAEA;MAGa,yCAAyC,CAAA;AADtD,IAAA,WAAA,GAAA;QAImB,IAAA,CAAA,cAAc,GAAG,MAAM,CAAC,qCAAqC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAgBpG,IAAA;IAdC,MAAM,OAAO,CAAC,KAA8C,EAAA;QAC1D,MAAM,OAAO,GAAG,KAAsC;AACtD,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;AACxB,YAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,2CAA2C,EAAE,EAAE;QAC3F;AAEA,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,SAAS,CAAC;AACxG,YAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE;QAC7D;QAAE,OAAO,KAAc,EAAE;AACvB,YAAA,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE,KAAK,CAAC;AAClE,YAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;QAC3B;IACF;8GAlBW,yCAAyC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAzC,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,yCAAyC,cAD5B,MAAM,EAAA,CAAA,CAAA;;2FACnB,yCAAyC,EAAA,UAAA,EAAA,CAAA;kBADrD,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}