@trii/types 2.10.753 → 2.10.755

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 (31) hide show
  1. package/dist/Common/Messages/Message.d.ts +2 -0
  2. package/dist/Conversations/Assignment.d.ts +0 -1
  3. package/dist/Conversations/Assignment.js +0 -2
  4. package/dist/Conversations/Classifications/ClassificationTaxonomy.d.ts +0 -2
  5. package/dist/Conversations/Classifications/ClassificationTaxonomy.js +0 -3
  6. package/dist/Conversations/Conversation.d.ts +65 -204
  7. package/dist/Conversations/Conversation.js +1 -0
  8. package/dist/Conversations/ConversationAutomationState.d.ts +27 -0
  9. package/dist/Conversations/ConversationPendingTransfer.d.ts +16 -0
  10. package/dist/Conversations/ConversationPendingTransfer.js +2 -0
  11. package/dist/Conversations/ConversationReadState.d.ts +16 -0
  12. package/dist/Conversations/ConversationReadState.js +2 -0
  13. package/dist/Conversations/ConversationSlaClockState.d.ts +66 -0
  14. package/dist/Conversations/ConversationSlaClockState.js +2 -0
  15. package/dist/Conversations/InboxQueries.d.ts +30 -0
  16. package/dist/Conversations/InboxQueries.js +2 -0
  17. package/dist/Conversations/Outbox.d.ts +0 -1
  18. package/dist/Conversations/Outbox.js +0 -2
  19. package/dist/Conversations/Queue.d.ts +1 -3
  20. package/dist/Conversations/Queue.js +0 -2
  21. package/dist/Conversations/Sla.d.ts +15 -6
  22. package/dist/Conversations/Sla.js +0 -4
  23. package/dist/Conversations/SocialWalls.d.ts +9 -51
  24. package/dist/Conversations/Transfer.d.ts +1 -0
  25. package/dist/Conversations/index.d.ts +5 -2
  26. package/dist/Conversations/index.js +5 -2
  27. package/package.json +1 -1
  28. package/dist/Conversations/InboxMongo.d.ts +0 -154
  29. package/dist/Conversations/InboxMongo.js +0 -128
  30. package/dist/Conversations/InboxProjection.d.ts +0 -162
  31. /package/dist/Conversations/{InboxProjection.js → ConversationAutomationState.js} +0 -0
@@ -415,6 +415,8 @@ export interface IMessage {
415
415
  idLocal?: number;
416
416
  spaceId: string;
417
417
  conversationId: string;
418
+ /** Deduplicated incoming ordinal within Conversation; null for outgoing/internal/legacy. */
419
+ conversationIncomingSequence?: number | null;
418
420
  workflowId?: string;
419
421
  /**only for Front-End */
420
422
  contactId?: string;
@@ -1,5 +1,4 @@
1
1
  import { ID } from './Conversation';
2
- export declare const CONVERSATION_ASSIGNMENT_EVENTS_COLLECTION = "conversation_assignment_events";
3
2
  export type ConversationAssignmentEventType = 'enqueued' | 'routing_started' | 'offered' | 'assigned' | 'accepted' | 'transferred' | 'released' | 'timed_out' | 'requeued';
4
3
  export type ConversationAssignmentReason = 'conversation_created' | 'routing_selected' | 'manual_assignment' | 'manual_transfer' | 'flow_routing' | 'offer_timeout' | 'assignment_timeout' | 'agent_accepted' | 'agent_released' | 'supervisor_released' | 'capacity_rebalance' | 'sla_escalation' | 'system_recovery' | 'transfer_cancelled' | 'transfer_declined';
5
4
  export type AssignmentOwnerReference = {
@@ -1,4 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONVERSATION_ASSIGNMENT_EVENTS_COLLECTION = void 0;
4
- exports.CONVERSATION_ASSIGNMENT_EVENTS_COLLECTION = 'conversation_assignment_events';
@@ -1,6 +1,4 @@
1
1
  import type { ClassificationSeverity } from './ConversationClassificationEvaluation';
2
- export declare const CLASSIFICATION_TAXONOMY_VERSIONS_COLLECTION = "classification_taxonomy_versions";
3
- export declare const CONVERSATION_EVALUATIONS_COLLECTION = "conversation_evaluations";
4
2
  export type ConversationClassificationDimension = 'contact_reason' | 'incident' | 'outcome' | 'recovery';
5
3
  export type ClassificationTaxonomyStatus = 'draft' | 'published' | 'archived';
6
4
  /**
@@ -1,5 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONVERSATION_EVALUATIONS_COLLECTION = exports.CLASSIFICATION_TAXONOMY_VERSIONS_COLLECTION = void 0;
4
- exports.CLASSIFICATION_TAXONOMY_VERSIONS_COLLECTION = 'classification_taxonomy_versions';
5
- exports.CONVERSATION_EVALUATIONS_COLLECTION = 'conversation_evaluations';
@@ -1,4 +1,8 @@
1
1
  import { UserInfo } from "../Users/UserTrii";
2
+ import type { ConversationReadState } from './ConversationReadState';
3
+ import type { ConversationAutomationState } from './ConversationAutomationState';
4
+ import type { ConversationPendingTransfer } from './ConversationPendingTransfer';
5
+ import type { ConversationSlaSnapshot, ConversationSlaStatus } from './ConversationSlaClockState';
2
6
  import { ILabel } from "./Label";
3
7
  import { GroupInfo } from "./Groups/Group";
4
8
  import { Channels } from "../Common/index";
@@ -38,46 +42,46 @@ export interface IConversation {
38
42
  status: ConversationStatus;
39
43
  priority: 'low' | 'normal' | 'high' | 'urgent';
40
44
  assignment: ConversationAssignmentSnapshot;
41
- /** @deprecated Use owner and assignment.*/
42
- assignedTo?: ConversationAssigned;
43
- sla: {
44
- status: 'none' | 'running' | 'warning' | 'breached' | 'met';
45
- deadlineAt?: Date;
46
- policyId?: string;
47
- version: number;
48
- };
45
+ /** Preserve assignment until acceptance atomically replaces it and clears this handoff. */
46
+ pendingTransfer?: ConversationPendingTransfer | null;
47
+ sla: ConversationSlaSnapshot;
49
48
  lastMessage: string;
50
49
  lastMessageId?: string;
51
- newMessagesCount: number;
52
- newMessagesUnread: boolean;
50
+ readState: ConversationReadState;
53
51
  lastActivityAt: Date;
54
52
  lastCustomerActivityAt?: Date;
55
53
  lastAgentActivityAt?: Date;
56
54
  labels: ILabel[];
57
- /**
58
- * Fijado/favorito. En chats internos (GROUP/DIRECT) el documento está duplicado por miembro
59
- * (`shardKey = "User|{userId}"`), por lo que este flag es por copia/usuario (B1), no del grupo.
60
- */
55
+ /** Shared pin for every viewer of this conversation. */
61
56
  pinned: boolean;
57
+ /** Shared outstanding work; reading does not answer or resolve it. */
58
+ requiresAction: boolean;
62
59
  /**
63
- * Silenciado hasta (B3). Por copia/usuario, igual que `pinned`. null/undefined = no silenciado.
60
+ * Legacy internal-chat preference. Not the shared pin or customer conversation state.
64
61
  * El front compara contra la hora actual; una fecha lejana representa "siempre".
65
62
  */
66
63
  mutedUntil?: Date | null;
67
- /** @deprecated A transfer is represented by an event and the resulting current state. */
68
- transferBy?: string;
69
- /** @deprecated A transfer is represented by an event and the resulting current state. */
70
- transferTo?: ConversationAssigned;
71
64
  expired: boolean;
72
- /** @deprecated Expiration does not own a separate assignment snapshot.*/
73
- expiredAssignedTo: ConversationAssigned;
74
65
  participants: UserInfo[];
75
66
  archived: boolean;
76
67
  spam: boolean;
77
68
  externalMessagingWindowEndAt?: Date;
69
+ /**
70
+ * Automatización que controla la conversación; null si no hay ejecución registrada.
71
+ * Actualizar con control de version y executionId para rechazar eventos antiguos.
72
+ */
73
+ automation?: ConversationAutomationState | null;
74
+ /** @deprecated Id de ejecución legacy. Usar automation.executionId. */
78
75
  workflowId?: string;
76
+ /** @deprecated Usar automation.status; con automation presente no controla SLA. */
79
77
  botStatus: ConversationBotStatus;
80
- botVars: ConversationBotVar[];
78
+ /**
79
+ * Datos relevantes para atender esta conversación, de solo lectura en el CRM.
80
+ * No almacena variables internas del flujo ni reemplaza datos de Contact.
81
+ * Cada key es única: publicar nuevamente la misma clave actualiza el dato.
82
+ * Se conservan al finalizar la automatización.
83
+ */
84
+ contextFields: ConversationContextField[];
81
85
  metadata: IConversationMetadata;
82
86
  /** Domain objects discussed or served by this conversation. */
83
87
  finalizedOnWebChat: Date;
@@ -93,7 +97,18 @@ export interface IConversation {
93
97
  resolutionReasonId?: string;
94
98
  finalizedAt: Date;
95
99
  finalizedBy?: string;
100
+ /** Presentation kind, not a separate lifecycle. Public conversations belong to one contact. */
101
+ interactionKind: InteractionKind;
102
+ /** Internal Post.id, required for public views. Null for private conversations. */
103
+ wallPostId?: string | null;
104
+ /** Stable internal WallMessage.id root; required for comment/mention, null for wall_post/private.
105
+ * Correlate by tenant/channel/contact/post/root, never by post alone.
106
+ */
107
+ wallRootCommentId?: string | null;
108
+ /** Mutable navigation focus in the public thread, not its identity. */
109
+ lastCommentId?: string | null;
96
110
  }
111
+ export type InteractionKind = 'private' | 'wall_post' | 'comment' | 'mention';
97
112
  export interface IWhatsAppGroupInfo {
98
113
  whatsappGroupId: string;
99
114
  groupInviteCode: string;
@@ -145,6 +160,7 @@ export interface IConversationMetadata {
145
160
  sessionId?: string;
146
161
  screenResolution?: string;
147
162
  }
163
+ /** @deprecated Estado legacy. Usar ConversationAutomationStatus para ejecuciones nuevas. */
148
164
  export declare enum ConversationBotStatus {
149
165
  NONE = 0,
150
166
  WAITING = 1,
@@ -152,9 +168,18 @@ export declare enum ConversationBotStatus {
152
168
  FINALIZED = 4,
153
169
  CANCELED = 5
154
170
  }
155
- export interface ConversationBotVar {
156
- title: string;
171
+ /** Dato publicado explícitamente para la atención de la conversación. */
172
+ export interface ConversationContextField {
173
+ /** Clave estable y única dentro de la conversación. Ejemplo: motivo_consulta. */
174
+ key: string;
175
+ /** Etiqueta visible para el usuario del CRM. */
176
+ label: string;
177
+ /** Valor de texto preparado para mostrar. */
157
178
  value: string;
179
+ /** Fecha UTC de la última actualización del dato. */
180
+ updatedAt: Date;
181
+ /** Ejecución que lo publicó; null para otro origen. Se conserva al terminar o cambiar la ejecución. */
182
+ automationExecutionId?: string | null;
158
183
  }
159
184
  /**
160
185
  * @deprecated Legacy channel assignment configuration. Use QueueRoutingConfig.
@@ -185,7 +210,7 @@ export declare enum ConversationStatus {
185
210
  FINALIZED = 3,// Alias for RESOLVED
186
211
  WAITING = 10
187
212
  }
188
- export type InboxViewId = 'pending' | 'following' | 'sla_warning' | 'sla_breached' | 'team_sla_breached' | 'resolved' | 'label';
213
+ export type InboxViewId = 'pending' | 'following' | 'sla_warning' | 'sla_breached' | 'team_sla_breached';
189
214
  export type OwnerType = 'user' | 'bot' | 'flow' | 'none';
190
215
  export interface NoConversationOwner {
191
216
  type: 'none';
@@ -308,194 +333,41 @@ export interface PutConversationSubscriptionRequest {
308
333
  expectedVersion?: number;
309
334
  notifications: ConversationSubscriptionNotifications;
310
335
  }
311
- export interface UserConversationState {
312
- id: ID;
313
- spaceId: ID;
314
- conversationId: ID;
315
- userId: ID;
316
- pinned: boolean;
317
- pinnedAt?: Date;
318
- lastReadMessageId?: ID;
319
- lastReadAt?: Date;
320
- updatedAt: Date;
321
- version: number;
322
- }
323
336
  export type ConversationReadStateMode = 'read' | 'unread';
324
337
  export interface PutConversationReadStateRequest {
325
338
  mode: ConversationReadStateMode;
326
- lastReadMessageId?: ID;
327
- lastReadAt?: Date;
339
+ commandId: string;
340
+ expectedConversationVersion: number;
341
+ /** Required for read, null for unread. Observed cursor, never silently server-latest. */
342
+ throughIncomingSequence?: number | null;
328
343
  }
329
344
  export interface PutConversationPinRequest {
345
+ commandId: string;
346
+ expectedConversationVersion: number;
330
347
  pinned: boolean;
331
348
  }
332
- export type InboxVisibilityReason = 'manual_follow' | 'assigned_to_user' | 'shared_queue_member' | 'queue_claimable' | 'active_participant' | 'sla_warning_owner' | 'sla_breached_owner' | 'supervised_queue_sla' | 'supervisor_escalation' | 'resolved_visible' | 'labeled';
333
- export interface ConversationInboxSnapshot {
334
- interactionKind: 'private' | 'wall_post' | 'comment' | 'mention';
335
- channelType: string;
336
- channelId?: ID;
337
- contact: {
338
- id?: ID;
339
- displayName: string;
340
- initials?: string;
341
- isBusiness: boolean;
342
- };
343
- status: ConversationStatus;
344
- owner: ConversationOwner;
345
- queueId?: ID;
346
- preview?: string;
347
- lastMessageId?: ID;
348
- unreadCount: number;
349
- priority: 'low' | 'normal' | 'high' | 'urgent';
350
- sla: {
351
- status: 'none' | 'running' | 'warning' | 'breached' | 'met';
352
- deadlineAt?: Date;
353
- };
354
- lastActivityAt: Date;
355
- labels: {
356
- id: ID;
357
- name: string;
358
- color?: string;
359
- }[];
360
- /** Solo poblado para interactionKind='comment'|'mention' - el WallMessage.id del comentario mas
361
- * reciente, para abrir el hilo posicionado ahi (igual que lastMessageId para conversaciones). */
362
- commentId?: ID;
363
- participants: {
364
- id: ID;
365
- displayName?: string;
366
- avatarUrl?: string;
367
- }[];
368
- /**
369
- * Transferencia pendiente que nadie tomo todavia: el assignment vigente
370
- * tiene source='transfer' y status 'offered' o 'queued'.
371
- *
372
- * Resuelta POR USUARIO. `UserInboxItemDocument` es un documento por
373
- * espacio+usuario+conversacion, asi que el backend puede decir de que lado
374
- * queda cada uno — que es lo que la card previa a la migracion del inbox
375
- * calculaba en el cliente comparando el destino contra el uid propio:
376
- *
377
- * - 'in' -> se la transfirieron a este usuario; `counterpartName` es quien
378
- * la transfirio.
379
- * - 'out' -> la transferencia va hacia otro; `counterpartName` es el
380
- * destino (usuario o cola).
381
- *
382
- * Los dos nombres estan a mano en el momento de la transferencia, asi que
383
- * el proyector no necesita releer el historial de eventos.
384
- *
385
- * Ausente cuando no hay transferencia pendiente y en documentos anteriores
386
- * al campo. `counterpartName` no es opcional: sin nombre la fila no puede
387
- * rotular el icono y descarta el indicador, igual que hace con los
388
- * `participants` sin `displayName`.
389
- */
390
- pendingTransfer?: {
391
- direction: 'in' | 'out';
392
- counterpartName: string;
393
- };
394
- }
395
- /**
396
- * Membership of one materialized conversation in one logical inbox view.
397
- *
398
- * visibilityReasons has set semantics: values must be unique and non-empty.
399
- * Removing one reason preserves the view while at least one reason remains.
400
- *
401
- * labelId is only populated when viewId is 'label' - identifies which of the
402
- * space's labels this particular view entry represents (InboxViewId is a
403
- * fixed enum, but labels are dynamic per space).
404
- */
405
- export interface UserInboxItemView {
406
- viewId: InboxViewId;
407
- visibilityReasons: [
408
- InboxVisibilityReason,
409
- ...InboxVisibilityReason[]
410
- ];
411
- requiresAction: boolean;
412
- labelId?: ID;
413
- }
414
- /**
415
- * Materialized read model. There is exactly one document for each
416
- * spaceId + userId + conversationId tuple.
417
- *
418
- * views must contain unique viewId values, EXCEPT for viewId='label': a
419
- * conversation can carry multiple labels, so multiple entries with
420
- * viewId='label' are allowed as long as their labelId differs (unique
421
- * (viewId, labelId) pairs for that case). Delete the document when the last
422
- * view is removed.
423
- */
424
- export interface UserInboxItemDocument {
425
- id: ID;
426
- spaceId: ID;
427
- userId: ID;
428
- conversationId: ID;
429
- views: UserInboxItemView[];
430
- snapshot: ConversationInboxSnapshot;
431
- pinned: boolean;
432
- priorityScore: number;
433
- sortAt: Date;
434
- conversationVersion: number;
435
- subscriptionVersion?: number;
436
- projectionVersion: number;
437
- lastSourceEventId: ID;
438
- projectedAt: Date;
439
- }
440
- /**
441
- * Materialized counters for exactly one user/view pair (user/view/label when
442
- * viewId is 'label' - labelId becomes part of the logical key in that case).
443
- *
444
- * total and requiresAction count conversations, never visibility reasons.
445
- * unread counts conversations whose snapshot.unreadCount is greater than zero,
446
- * not the number of unread messages.
447
- */
448
- export interface UserInboxCounterDocument {
449
- id: ID;
450
- spaceId: ID;
451
- userId: ID;
452
- viewId: InboxViewId;
453
- labelId?: ID;
454
- total: number;
455
- requiresAction: number;
456
- unread: number;
457
- projectionVersion: number;
458
- updatedAt: Date;
459
- }
349
+ /** Conversation lists return CursorPage<IConversation> directly; authorization stays in backend. */
460
350
  export interface CursorPage<T> {
461
351
  items: T[];
462
- nextCursor?: string;
352
+ nextCursor?: string | null;
463
353
  hasMore: boolean;
464
354
  generatedAt: Date;
465
355
  }
466
- export interface ConversationCapabilitiesDto {
467
- canView: boolean;
468
- canReply: boolean;
469
- canFollow: boolean;
470
- canAbandon: boolean;
471
- canClaim: boolean;
472
- canAccept: boolean;
473
- canRelease: boolean;
474
- canTransfer: boolean;
475
- canResolve: boolean;
476
- canReopen: boolean;
477
- canChangePriority: boolean;
478
- canManageLabels: boolean;
479
- canManageSla: boolean;
480
- canViewAssignmentHistory: boolean;
481
- canViewRoutingDecisions: boolean;
482
- }
356
+ /** Counts distinct authorized conversations on demand; unread includes manual unread. */
483
357
  export interface InboxViewSummaryDto {
484
- id: InboxViewId | 'supervised_target' | `label:${string}`;
358
+ id: string;
485
359
  label: string;
486
- scope: 'personal' | 'supervision' | 'history' | 'labels';
360
+ scope: string;
487
361
  order: number;
488
362
  total: number;
489
363
  requiresAction: number;
490
364
  unread: number;
491
365
  enabled: boolean;
492
366
  targetRequired: boolean;
493
- capabilities: string[];
494
367
  }
495
368
  export interface InboxViewsResponse {
496
369
  views: InboxViewSummaryDto[];
497
370
  countersGeneratedAt: Date;
498
- projectionLagMs?: number;
499
371
  }
500
372
  export interface InboxFilterDto {
501
373
  text?: string;
@@ -504,7 +376,8 @@ export interface InboxFilterDto {
504
376
  channelTypes?: string[];
505
377
  statuses?: ConversationStatus[];
506
378
  priorities?: Array<'low' | 'normal' | 'high' | 'urgent'>;
507
- slaStatuses?: Array<'none' | 'running' | 'warning' | 'breached' | 'met'>;
379
+ slaStatuses?: ConversationSlaStatus[];
380
+ /** OR within the authorized view; labels never grant access. */
508
381
  labelIds?: ID[];
509
382
  unread?: boolean;
510
383
  requiresAction?: boolean;
@@ -519,16 +392,6 @@ export interface InboxFilterDto {
519
392
  type: 'priority';
520
393
  };
521
394
  }
522
- export type InboxConversationItemDto = Pick<UserInboxItemDocument, 'conversationId' | 'views' | 'snapshot' | 'pinned' | 'priorityScore' | 'sortAt'> & {
523
- capabilities: Pick<ConversationCapabilitiesDto, 'canView' | 'canReply' | 'canClaim' | 'canTransfer'>;
524
- };
525
- export interface InboxConversationPage extends CursorPage<InboxConversationItemDto> {
526
- appliedFilter: InboxFilterDto;
527
- facets?: unknown;
528
- }
529
- /**
530
- * DTO API - GET /inbox/views/{viewId}/filter-options.
531
- */
532
395
  export interface InboxFacetOptionDto {
533
396
  id: string;
534
397
  label: string;
@@ -541,9 +404,11 @@ export interface InboxFacetsDto {
541
404
  statuses: InboxFacetOptionDto[];
542
405
  priorities: InboxFacetOptionDto[];
543
406
  slaStatuses: InboxFacetOptionDto[];
407
+ /** Full selected view, before label filters/pagination; only positive counts, once per label/conversation. */
544
408
  labels: InboxFacetOptionDto[];
545
409
  }
546
410
  export interface InboxFilterOptionsResponse {
411
+ viewId: InboxViewId;
547
412
  facets: InboxFacetsDto;
548
413
  generatedAt: Date;
549
414
  }
@@ -558,14 +423,10 @@ export interface ConversationUserRelationDto {
558
423
  isOwner: boolean;
559
424
  isParticipant: boolean;
560
425
  isFollowing: boolean;
561
- isPinned: boolean;
562
- unreadCount: number;
563
426
  }
564
427
  export interface ConversationDetailResponse {
565
428
  conversation: IConversation;
566
429
  relation: ConversationUserRelationDto;
567
- capabilities: ConversationCapabilitiesDto;
568
- availableActions: string[];
569
430
  }
570
431
  export interface AddConversationParticipantRequest {
571
432
  userId: string;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ConversationStatus = exports.AssignMethod = exports.ConversationDirection = exports.ConversationBotStatus = void 0;
4
+ /** @deprecated Estado legacy. Usar ConversationAutomationStatus para ejecuciones nuevas. */
4
5
  var ConversationBotStatus;
5
6
  (function (ConversationBotStatus) {
6
7
  ConversationBotStatus[ConversationBotStatus["NONE"] = 0] = "NONE";
@@ -0,0 +1,27 @@
1
+ export type ConversationAutomationStatus = 'running' | 'completed' | 'cancelled' | 'failed';
2
+ /**
3
+ * Automatización que controla la conversación, como máximo una a la vez.
4
+ * No representa tareas auxiliares en segundo plano ni su historial.
5
+ * running incluye esperas internas y reintentos; failed significa fallo terminal.
6
+ */
7
+ export interface ConversationAutomationState {
8
+ /**
9
+ * Id de ejecución (WorkFlow.id), no de definición del flujo.
10
+ * Una ejecución nueva reemplaza este objeto con otro executionId.
11
+ * Eventos de otra ejecución no pueden modificar el estado ni reanudar sus SLA.
12
+ */
13
+ workflowId: string;
14
+ /**
15
+ * Solo running pausa SLA humanos de respuesta. completed incluye la derivación efectiva
16
+ * a un humano. Ningún estado terminal finaliza por sí solo la conversación.
17
+ */
18
+ status: ConversationAutomationStatus;
19
+ /** Fecha efectiva UTC en que tomó el control, no la recepción del evento. */
20
+ startedAt: Date;
21
+ /**
22
+ * Null mientras running; obligatoria en estados terminales y no anterior a startedAt.
23
+ * Fecha efectiva UTC de devolución del control. Conservar el objeto terminal hasta
24
+ * la siguiente ejecución permite reconocer eventos atrasados.
25
+ */
26
+ endedAt?: Date | null;
27
+ }
@@ -0,0 +1,16 @@
1
+ import type { TransferConversationReason, TransferConversationTarget } from './Transfer';
2
+ /** Single current handoff, not history. Keep assignment unchanged until acceptance.
3
+ * Accept atomically with matching transferId, sourceAssignmentId and Conversation.version.
4
+ * First valid acceptance wins. Reject/cancel/expire clears this state without moving source.
5
+ * Resolve authorized target audience at query time, checking expiration even before cleanup.
6
+ */
7
+ export interface ConversationPendingTransfer {
8
+ transferId: string;
9
+ sourceAssignmentId: string;
10
+ target: TransferConversationTarget;
11
+ /** Null for automated requests; full actor is recorded in events. */
12
+ requestedByUserId?: string | null;
13
+ requestedAt: Date;
14
+ expiresAt?: Date | null;
15
+ reason: TransferConversationReason;
16
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,16 @@
1
+ /** Shared state; 0 <= readThroughSequence <= lastIncomingSequence.
2
+ * Incoming ordinals are assigned once per deduplicated message in ingestion order.
3
+ * Reading advances only to the observed ordinal; manual unread preserves the cursor.
4
+ * Numeric counters must remain within JavaScript's safe integer range.
5
+ */
6
+ export interface ConversationReadState {
7
+ lastIncomingSequence: number;
8
+ readThroughSequence: number;
9
+ manuallyMarkedUnread: boolean;
10
+ changedAt?: Date | null;
11
+ changedByUserId?: string | null;
12
+ /** Derived by the backend; not persisted in BSON. */
13
+ readonly unreadCount: number;
14
+ /** Includes manual unread even when unreadCount is zero. */
15
+ readonly isUnread: boolean;
16
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,66 @@
1
+ import type { ConversationSlaMetric, ConversationSlaCycleStatus } from './Sla';
2
+ export type ConversationSlaStatus = 'none' | 'running' | 'warning' | 'breached' | 'met' | 'paused' | 'cancelled';
3
+ /** Current operational state, at most one clock per metric. No configuration/history.
4
+ * A replacement gets a new cycleId; archive the previous cycle outside Conversation.
5
+ * Updates use Conversation.version plus expected cycleId/SLA revision. All times UTC.
6
+ */
7
+ export interface ConversationSlaClockState {
8
+ cycleId: string;
9
+ metric: ConversationSlaMetric;
10
+ sequence: number;
11
+ /** breached is unfinished; late completion preserves breachedAt. */
12
+ status: ConversationSlaCycleStatus;
13
+ /** Immutable applied reference must resolve historical calendar/timezone rules. */
14
+ policyId: string;
15
+ policyVersion: number;
16
+ startedByEventId: string;
17
+ startedByMessageId?: string | null;
18
+ assignmentId?: string | null;
19
+ startedAt: Date;
20
+ deadlineAt?: Date | null;
21
+ nextWarningAt?: Date | null;
22
+ warningAt?: Date | null;
23
+ /** Current pause only; clear on resume. */
24
+ pausedAt?: Date | null;
25
+ /**
26
+ * Causas activas, no historial. Un reloj pendiente permanece paused mientras alguna sea true.
27
+ * Actualizar con status, pausedAt, deadlines y resumen en la misma escritura.
28
+ * Completar/cancelar limpia las causas. Un paused legacy sin causas requiere migración;
29
+ * no asumir pausa de automatización ni reanudarlo automáticamente.
30
+ */
31
+ pauseReasons: ConversationSlaPauseReasons;
32
+ /** Chargeable seconds through elapsedCalculatedAt, within JS safe integer range. */
33
+ elapsedSeconds: number;
34
+ /** Accounting watermark; on resume reset to resume time preserving consumed seconds. */
35
+ elapsedCalculatedAt: Date;
36
+ breachedAt?: Date | null;
37
+ completedAt?: Date | null;
38
+ cancelledAt?: Date | null;
39
+ }
40
+ /** Las causas pueden coexistir; cada operación agrega o retira únicamente la suya. */
41
+ export interface ConversationSlaPauseReasons {
42
+ /** Se retira solo por una reanudación manual autorizada. */
43
+ manual: boolean;
44
+ /** La política pauseOnStatuses exige pausa en el estado actual de Conversation. */
45
+ conversationStatus: boolean;
46
+ /**
47
+ * Solo first_response/next_response mientras automation.status sea running,
48
+ * incluidos relojes que nacen durante la ejecución. Al terminar, retirar esta causa
49
+ * conservando ciclo, consumo y breachedAt, aunque onResume sea restart.
50
+ * Si queda otra causa, continúa pausado. No afecta assignment/acceptance/resolution.
51
+ */
52
+ automation: boolean;
53
+ }
54
+ /** Summary updated atomically with clocks; never an independent state source. */
55
+ export interface ConversationSlaSnapshot {
56
+ /** Precedence: breached, active warning, running, paused, met, cancelled, none. */
57
+ status: ConversationSlaStatus;
58
+ /** Earliest unfinished/unpaused deadline. Compare against UTC even if evaluator lags. */
59
+ deadlineAt?: Date | null;
60
+ /** Selection for new clocks; current clocks retain their applied references. */
61
+ policyId?: string | null;
62
+ policyVersion?: number | null;
63
+ clocks: ConversationSlaClockState[];
64
+ /** SLA state revision, not policy version. */
65
+ version: number;
66
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,30 @@
1
+ import type { ID, InboxViewId, InboxFilterDto } from './Conversation';
2
+ export type InboxPaginationSort = 'activity' | 'priority';
3
+ /** Cursor over current authorized conversations, after filtering.
4
+ * Bind to tenant/user/view/filter/sort; live updates may move rows between pages.
5
+ */
6
+ export interface InboxActivityCursor {
7
+ sort: 'activity';
8
+ pinned: boolean;
9
+ lastActivityAt: Date;
10
+ conversationId: ID;
11
+ }
12
+ export interface InboxPriorityCursor {
13
+ sort: 'priority';
14
+ pinned: boolean;
15
+ /** Explicit rank urgent > high > normal > low, not lexical order. */
16
+ priority: 'low' | 'normal' | 'high' | 'urgent';
17
+ lastActivityAt: Date;
18
+ conversationId: ID;
19
+ }
20
+ export type InboxPaginationCursor = InboxActivityCursor | InboxPriorityCursor;
21
+ export interface InboxPageQuery {
22
+ /** Trusted server context, not client authorization claims. */
23
+ spaceId: ID;
24
+ userId: ID;
25
+ viewId: InboxViewId;
26
+ limit: number;
27
+ filter: InboxFilterDto;
28
+ /** Must match filter.sort. */
29
+ cursor?: InboxPaginationCursor | null;
30
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,4 +1,3 @@
1
- export declare const OUTBOX_EVENTS_COLLECTION = "outbox_events";
2
1
  export type OutboxEventStatus = 'pending' | 'publishing' | 'published' | 'failed';
3
2
  /**
4
3
  * Transactional outbox record persisted with the aggregate mutation.
@@ -1,4 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OUTBOX_EVENTS_COLLECTION = void 0;
4
- exports.OUTBOX_EVENTS_COLLECTION = 'outbox_events';
@@ -1,6 +1,5 @@
1
1
  import { ID } from './Conversation';
2
2
  import { QueueRoutingPolicy } from './Routing';
3
- export declare const CONVERSATION_QUEUES_COLLECTION = "conversation_queues";
4
3
  export type QueueSlaTransferBehavior = 'preserve' | 'restart' | 'recalculate';
5
4
  export type ConversationQueueSlaConfig = {
6
5
  enabled: false;
@@ -21,15 +20,14 @@ export type ConversationQueueSlaConfig = {
21
20
  */
22
21
  export type QueueMemberAudienceMode = 'distribution' | 'all_current' | 'none';
23
22
  export type QueueSupervisorAudienceMode = 'all_current' | 'sla_only' | 'escalations_only' | 'none';
23
+ /** Open conversations only. Finalization retains authorized following, not queue visibility. */
24
24
  export interface ConversationQueueAudienceConfig {
25
25
  members: {
26
26
  mode: QueueMemberAudienceMode;
27
27
  requireActiveParticipation: boolean;
28
- includeResolved: boolean;
29
28
  };
30
29
  supervisors: {
31
30
  mode: QueueSupervisorAudienceMode;
32
- includeResolved: boolean;
33
31
  };
34
32
  }
35
33
  export interface ConversationQueueInfo {
@@ -1,4 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONVERSATION_QUEUES_COLLECTION = void 0;
4
- exports.CONVERSATION_QUEUES_COLLECTION = 'conversation_queues';
@@ -1,9 +1,6 @@
1
1
  import type { ISchedule } from '../Common/Schedules/Schedules';
2
2
  import type { ConversationEventType, ConversationStatus, ID } from './Conversation';
3
3
  import type { OutboxEvent } from './Outbox';
4
- export declare const CONVERSATION_SLA_POLICIES_COLLECTION = "conversation_sla_policies";
5
- export declare const CONVERSATION_SLA_CYCLES_COLLECTION = "conversation_sla_cycles";
6
- export declare const CONVERSATION_SLA_EVENTS_COLLECTION = "conversation_sla_events";
7
4
  export type ConversationSlaMetric = 'first_response' | 'next_response' | 'assignment' | 'acceptance' | 'resolution';
8
5
  /**
9
6
  * continuous counts natural elapsed time, including nights and holidays.
@@ -138,7 +135,13 @@ export interface PublishConversationSlaPolicyVersionRequest {
138
135
  definition: ConversationSlaPolicyDefinitionInput;
139
136
  }
140
137
  export type ConversationSlaClockAction = 'start' | 'evaluate' | 'pause' | 'resume' | 'complete' | 'recalculate' | 'cancel';
141
- export type ConversationSlaClockReason = 'conversation_created' | 'conversation_enqueued' | 'customer_message' | 'agent_response' | 'assignment_changed' | 'status_changed' | 'queue_transfer' | 'conversation_reopened' | 'deadline_due' | 'policy_override';
138
+ export type ConversationSlaClockReason = 'conversation_created' | 'conversation_enqueued' | 'customer_message'
139
+ /** Solo respuesta humana aceptada por el proveedor; IA, flujos y notas internas no califican. */
140
+ | 'agent_response' | 'assignment_changed' | 'status_changed' | 'queue_transfer' | 'conversation_reopened' | 'deadline_due' | 'policy_override'
141
+ /** La ejecución toma control; pausa solo first_response/next_response. */
142
+ | 'automation_started'
143
+ /** Fin, cancelación, fallo terminal o derivación; retira solo la pausa de automatización. */
144
+ | 'automation_finished';
142
145
  /**
143
146
  * Idempotent input for the conversation-sla-worker.
144
147
  * policyId/policyVersion identify the immutable policy snapshot to apply.
@@ -155,6 +158,12 @@ export interface SlaClockCommand {
155
158
  policyId: ID;
156
159
  policyVersion: number;
157
160
  queueId?: ID;
161
+ /**
162
+ * Obligatorio para automation_started/automation_finished; null para otros motivos.
163
+ * Debe coincidir con Conversation.automation.executionId; descartar eventos de otra ejecución.
164
+ * occurredAt es la fecha efectiva del cambio; el fin conserva el tiempo SLA consumido.
165
+ */
166
+ automationExecutionId?: ID | null;
158
167
  occurredAt: Date;
159
168
  requestedAt: Date;
160
169
  }
@@ -166,8 +175,8 @@ export interface ConversationSlaPausePeriod {
166
175
  sourceEventId: ID;
167
176
  }
168
177
  /**
169
- * Durable metric cycle. The target and time calculation are copied from the
170
- * selected policy version so later policy edits cannot alter active history.
178
+ * External history/read model. Current clocks live only in Conversation.sla.clocks.
179
+ * Policy copies here describe historical configuration, not another live state source.
171
180
  */
172
181
  export interface ConversationSlaCycle {
173
182
  id: ID;
@@ -1,6 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONVERSATION_SLA_EVENTS_COLLECTION = exports.CONVERSATION_SLA_CYCLES_COLLECTION = exports.CONVERSATION_SLA_POLICIES_COLLECTION = void 0;
4
- exports.CONVERSATION_SLA_POLICIES_COLLECTION = 'conversation_sla_policies';
5
- exports.CONVERSATION_SLA_CYCLES_COLLECTION = 'conversation_sla_cycles';
6
- exports.CONVERSATION_SLA_EVENTS_COLLECTION = 'conversation_sla_events';
@@ -1,7 +1,6 @@
1
1
  import { Channels } from "../Common/index";
2
2
  import { UserInfo } from "../Users/UserTrii";
3
- import { ConversationAssignmentSnapshot, ConversationCapabilitiesDto, ConversationStatus, ConversationUserRelationDto } from "./Conversation";
4
- import { ILabel } from "./Label";
3
+ import { ConversationAssignmentSnapshot, IConversation, InteractionKind, ConversationUserRelationDto } from "./Conversation";
5
4
  export interface Post {
6
5
  id: string;
7
6
  spaceId: string;
@@ -30,6 +29,9 @@ export interface PostStats {
30
29
  }
31
30
  export interface WallMessage {
32
31
  id: string;
32
+ /** Canonical conversation owning shared read/SLA state. */
33
+ conversationId?: string | null;
34
+ conversationIncomingSequence?: number | null;
33
35
  spaceId: string;
34
36
  postId: string;
35
37
  parentId: string;
@@ -75,56 +77,12 @@ export interface ExternalUserInfo {
75
77
  name: string;
76
78
  imageUrl: string;
77
79
  }
78
- /**
79
- * Estado de una interaccion wall (post/comment/mention), equivalente a lo que para una
80
- * conversacion vive directo en IConversation. Post no tiene estos campos persistidos (no hay
81
- * assignment/sla reales para posts todavia), asi que este objeto se arma al vuelo del lado del
82
- * backend a partir de UserInboxItemDocument.snapshot (owner/status/queueId/unreadCount) y del
83
- * propio Post (participants/channelInfo/fechas).
84
- */
85
- export interface WallInteractionState {
86
- id: string;
87
- spaceId: string;
88
- status: ConversationStatus;
89
- priority: 'low' | 'normal' | 'high' | 'urgent';
90
- assignment: ConversationAssignmentSnapshot;
91
- sla: {
92
- status: 'none' | 'running' | 'warning' | 'breached' | 'met';
93
- deadlineAt?: Date;
94
- policyId?: string;
95
- version: number;
96
- };
97
- labels: ILabel[];
98
- participants: UserInfo[];
99
- channelInfo: Channels.IChannelInfo;
100
- unreadCount: number;
101
- lastActivityAt: Date;
102
- createdAt: Date;
103
- updatedAt: Date;
104
- finalizedAt?: Date;
105
- }
106
- /**
107
- * DTO API - GET /Walls/{postId}/detail. Rama "wall" del sobre que en conversaciones da
108
- * ConversationDetailResponse. interactionKind viaja igual (wall_post/comment/mention) aunque el
109
- * front ya sepa que pego en el endpoint de walls, por si quiere distinguir el motivo de la fila.
110
- */
80
+ /** Public content plus its canonical conversation; no independent attention lifecycle. */
111
81
  export interface WallPostDetailResponse {
112
- interactionKind: 'wall_post' | 'comment' | 'mention';
82
+ interactionKind: InteractionKind;
113
83
  post: Post;
114
- interaction: WallInteractionState;
115
- /** Comentario que origino la interaccion (comment/mention). Ausente para wall_post o cuando
116
- * todavia no se implementa el tracking de comentario puntual (P1, ver discusion). */
117
- focusCommentId?: string;
84
+ conversation: IConversation;
85
+ /** Navigation focus only; stable identity is conversation.wallRootCommentId. */
86
+ focusCommentId?: string | null;
118
87
  relation: ConversationUserRelationDto;
119
- capabilities: ConversationCapabilitiesDto;
120
- availableActions: string[];
121
- }
122
- /**
123
- * DTO API - GET /inbox/items/{id}. Resuelve deep-link (F5, link compartido) sin tener el snapshot
124
- * del listado: solo dice de que tipo es el id para que el front pegue en
125
- * /Conversations/{id}/detail o en /Walls/{postId}/detail segun corresponda.
126
- */
127
- export interface InboxItemKindDto {
128
- id: string;
129
- interactionKind: 'private' | 'wall_post' | 'comment' | 'mention';
130
88
  }
@@ -5,6 +5,7 @@ export type TransferConversationReason = Extract<ConversationAssignmentReason, '
5
5
  export type TransferConversationTarget = {
6
6
  type: 'queue';
7
7
  queueId: ID;
8
+ userId?: null;
8
9
  } | {
9
10
  type: 'user';
10
11
  queueId: ID;
@@ -2,8 +2,11 @@ export * as Flows from './Flows/index';
2
2
  export * as Groups from './Groups/Group';
3
3
  export * from './Assignment';
4
4
  export * from './Conversation';
5
- export * from './InboxMongo';
6
- export * from './InboxProjection';
5
+ export * from './ConversationAutomationState';
6
+ export * from './InboxQueries';
7
+ export * from './ConversationReadState';
8
+ export * from './ConversationPendingTransfer';
9
+ export * from './ConversationSlaClockState';
7
10
  export * from './Outbox';
8
11
  export * from './Ending';
9
12
  export * from './Label';
@@ -41,8 +41,11 @@ exports.Flows = __importStar(require("./Flows/index"));
41
41
  exports.Groups = __importStar(require("./Groups/Group"));
42
42
  __exportStar(require("./Assignment"), exports);
43
43
  __exportStar(require("./Conversation"), exports);
44
- __exportStar(require("./InboxMongo"), exports);
45
- __exportStar(require("./InboxProjection"), exports);
44
+ __exportStar(require("./ConversationAutomationState"), exports);
45
+ __exportStar(require("./InboxQueries"), exports);
46
+ __exportStar(require("./ConversationReadState"), exports);
47
+ __exportStar(require("./ConversationPendingTransfer"), exports);
48
+ __exportStar(require("./ConversationSlaClockState"), exports);
46
49
  __exportStar(require("./Outbox"), exports);
47
50
  __exportStar(require("./Ending"), exports);
48
51
  __exportStar(require("./Label"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trii/types",
3
- "version": "2.10.753",
3
+ "version": "2.10.755",
4
4
  "description": "Types definitions for Trii projects - ",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,154 +0,0 @@
1
- import { ID, InboxViewId } from './Conversation';
2
- export declare const CONVERSATION_SUBSCRIPTIONS_COLLECTION = "conversation_subscriptions";
3
- export declare const USER_INBOX_ITEMS_COLLECTION = "user_inbox_items";
4
- export declare const USER_INBOX_COUNTERS_COLLECTION = "user_inbox_counters";
5
- export declare const INBOX_PROCESSOR_RECEIPTS_COLLECTION = "inbox_processor_receipts";
6
- /**
7
- * MongoDB indexes for conversation_subscriptions.
8
- *
9
- * The unique index enforces one current subscription state per
10
- * user/conversation. The follower index resolves the active followers that
11
- * InboxAudienceResolver receives as input.
12
- */
13
- export declare const CONVERSATION_SUBSCRIPTION_INDEXES: readonly [{
14
- readonly name: "uq_subscription_user_conversation";
15
- readonly key: {
16
- readonly spaceId: 1;
17
- readonly userId: 1;
18
- readonly conversationId: 1;
19
- };
20
- readonly unique: true;
21
- }, {
22
- readonly name: "ix_subscription_conversation_followers";
23
- readonly key: {
24
- readonly spaceId: 1;
25
- readonly conversationId: 1;
26
- readonly status: 1;
27
- readonly userId: 1;
28
- };
29
- }];
30
- /**
31
- * MongoDB indexes for user_inbox_items.
32
- *
33
- * views.viewId is the only array field in each compound index. Do not add
34
- * views.visibilityReasons to these indexes: MongoDB compound multikey indexes
35
- * must not combine multiple array paths.
36
- */
37
- export declare const USER_INBOX_ITEM_INDEXES: readonly [{
38
- readonly name: "uq_inbox_item_user_conversation";
39
- readonly key: {
40
- readonly spaceId: 1;
41
- readonly userId: 1;
42
- readonly conversationId: 1;
43
- };
44
- readonly unique: true;
45
- }, {
46
- readonly name: "ix_inbox_view_activity";
47
- readonly key: {
48
- readonly spaceId: 1;
49
- readonly userId: 1;
50
- readonly 'views.viewId': 1;
51
- readonly pinned: -1;
52
- readonly sortAt: -1;
53
- readonly id: -1;
54
- };
55
- }, {
56
- readonly name: "ix_inbox_view_priority";
57
- readonly key: {
58
- readonly spaceId: 1;
59
- readonly userId: 1;
60
- readonly 'views.viewId': 1;
61
- readonly pinned: -1;
62
- readonly priorityScore: -1;
63
- readonly sortAt: -1;
64
- readonly id: -1;
65
- };
66
- }, {
67
- readonly name: "ix_inbox_view_status_activity";
68
- readonly key: {
69
- readonly spaceId: 1;
70
- readonly userId: 1;
71
- readonly 'views.viewId': 1;
72
- readonly 'snapshot.status': 1;
73
- readonly sortAt: -1;
74
- readonly id: -1;
75
- };
76
- }, {
77
- readonly name: "ix_inbox_view_queue_activity";
78
- readonly key: {
79
- readonly spaceId: 1;
80
- readonly userId: 1;
81
- readonly 'views.viewId': 1;
82
- readonly 'snapshot.queueId': 1;
83
- readonly sortAt: -1;
84
- readonly id: -1;
85
- };
86
- }];
87
- /**
88
- * MongoDB indexes for user_inbox_counters.
89
- *
90
- * The unique index also serves reads for all views of a user through its
91
- * spaceId + userId prefix.
92
- */
93
- export declare const USER_INBOX_COUNTER_INDEXES: readonly [{
94
- readonly name: "uq_inbox_counter_user_view";
95
- readonly key: {
96
- readonly spaceId: 1;
97
- readonly userId: 1;
98
- readonly viewId: 1;
99
- };
100
- readonly unique: true;
101
- }];
102
- /**
103
- * MongoDB indexes for durable processor idempotency receipts.
104
- */
105
- export declare const INBOX_PROCESSOR_RECEIPT_INDEXES: readonly [{
106
- readonly name: "uq_inbox_processor_source_scope";
107
- readonly key: {
108
- readonly processor: 1;
109
- readonly sourceEventId: 1;
110
- readonly scopeKey: 1;
111
- };
112
- readonly unique: true;
113
- }];
114
- export type InboxPaginationSort = 'activity' | 'priority';
115
- /**
116
- * Seek-pagination cursor matching ix_inbox_view_activity.
117
- */
118
- export interface InboxActivityCursor {
119
- sort: 'activity';
120
- pinned: boolean;
121
- sortAt: Date;
122
- id: ID;
123
- }
124
- /**
125
- * Seek-pagination cursor matching ix_inbox_view_priority.
126
- */
127
- export interface InboxPriorityCursor {
128
- sort: 'priority';
129
- pinned: boolean;
130
- priorityScore: number;
131
- sortAt: Date;
132
- id: ID;
133
- }
134
- export type InboxPaginationCursor = InboxActivityCursor | InboxPriorityCursor;
135
- /**
136
- * Query contract for one logical inbox view.
137
- *
138
- * Implementations must use seek pagination with cursor; skip pagination is not
139
- * compatible with frequently changing sortAt values.
140
- */
141
- interface InboxPageQueryBase {
142
- spaceId: ID;
143
- userId: ID;
144
- viewId: InboxViewId;
145
- limit: number;
146
- }
147
- export type InboxPageQuery = InboxPageQueryBase & {
148
- sort: 'activity';
149
- cursor?: InboxActivityCursor;
150
- } | InboxPageQueryBase & {
151
- sort: 'priority';
152
- cursor?: InboxPriorityCursor;
153
- };
154
- export {};
@@ -1,128 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.INBOX_PROCESSOR_RECEIPT_INDEXES = exports.USER_INBOX_COUNTER_INDEXES = exports.USER_INBOX_ITEM_INDEXES = exports.CONVERSATION_SUBSCRIPTION_INDEXES = exports.INBOX_PROCESSOR_RECEIPTS_COLLECTION = exports.USER_INBOX_COUNTERS_COLLECTION = exports.USER_INBOX_ITEMS_COLLECTION = exports.CONVERSATION_SUBSCRIPTIONS_COLLECTION = void 0;
4
- exports.CONVERSATION_SUBSCRIPTIONS_COLLECTION = 'conversation_subscriptions';
5
- exports.USER_INBOX_ITEMS_COLLECTION = 'user_inbox_items';
6
- exports.USER_INBOX_COUNTERS_COLLECTION = 'user_inbox_counters';
7
- exports.INBOX_PROCESSOR_RECEIPTS_COLLECTION = 'inbox_processor_receipts';
8
- /**
9
- * MongoDB indexes for conversation_subscriptions.
10
- *
11
- * The unique index enforces one current subscription state per
12
- * user/conversation. The follower index resolves the active followers that
13
- * InboxAudienceResolver receives as input.
14
- */
15
- exports.CONVERSATION_SUBSCRIPTION_INDEXES = [
16
- {
17
- name: 'uq_subscription_user_conversation',
18
- key: {
19
- spaceId: 1,
20
- userId: 1,
21
- conversationId: 1,
22
- },
23
- unique: true,
24
- },
25
- {
26
- name: 'ix_subscription_conversation_followers',
27
- key: {
28
- spaceId: 1,
29
- conversationId: 1,
30
- status: 1,
31
- userId: 1,
32
- },
33
- },
34
- ];
35
- /**
36
- * MongoDB indexes for user_inbox_items.
37
- *
38
- * views.viewId is the only array field in each compound index. Do not add
39
- * views.visibilityReasons to these indexes: MongoDB compound multikey indexes
40
- * must not combine multiple array paths.
41
- */
42
- exports.USER_INBOX_ITEM_INDEXES = [
43
- {
44
- name: 'uq_inbox_item_user_conversation',
45
- key: {
46
- spaceId: 1,
47
- userId: 1,
48
- conversationId: 1,
49
- },
50
- unique: true,
51
- },
52
- {
53
- name: 'ix_inbox_view_activity',
54
- key: {
55
- spaceId: 1,
56
- userId: 1,
57
- 'views.viewId': 1,
58
- pinned: -1,
59
- sortAt: -1,
60
- id: -1,
61
- },
62
- },
63
- {
64
- name: 'ix_inbox_view_priority',
65
- key: {
66
- spaceId: 1,
67
- userId: 1,
68
- 'views.viewId': 1,
69
- pinned: -1,
70
- priorityScore: -1,
71
- sortAt: -1,
72
- id: -1,
73
- },
74
- },
75
- {
76
- name: 'ix_inbox_view_status_activity',
77
- key: {
78
- spaceId: 1,
79
- userId: 1,
80
- 'views.viewId': 1,
81
- 'snapshot.status': 1,
82
- sortAt: -1,
83
- id: -1,
84
- },
85
- },
86
- {
87
- name: 'ix_inbox_view_queue_activity',
88
- key: {
89
- spaceId: 1,
90
- userId: 1,
91
- 'views.viewId': 1,
92
- 'snapshot.queueId': 1,
93
- sortAt: -1,
94
- id: -1,
95
- },
96
- },
97
- ];
98
- /**
99
- * MongoDB indexes for user_inbox_counters.
100
- *
101
- * The unique index also serves reads for all views of a user through its
102
- * spaceId + userId prefix.
103
- */
104
- exports.USER_INBOX_COUNTER_INDEXES = [
105
- {
106
- name: 'uq_inbox_counter_user_view',
107
- key: {
108
- spaceId: 1,
109
- userId: 1,
110
- viewId: 1,
111
- },
112
- unique: true,
113
- },
114
- ];
115
- /**
116
- * MongoDB indexes for durable processor idempotency receipts.
117
- */
118
- exports.INBOX_PROCESSOR_RECEIPT_INDEXES = [
119
- {
120
- name: 'uq_inbox_processor_source_scope',
121
- key: {
122
- processor: 1,
123
- sourceEventId: 1,
124
- scopeKey: 1,
125
- },
126
- unique: true,
127
- },
128
- ];
@@ -1,162 +0,0 @@
1
- import { ConversationInboxSnapshot, ID, InboxViewId, UserInboxItemView } from './Conversation';
2
- import { ConversationQueue } from './Queue';
3
- import { ConversationAssignmentChanged } from './Transfer';
4
- export type InboxProcessorName = 'inbox-audience-resolver' | 'inbox-item-projector' | 'inbox-counter-projector';
5
- /**
6
- * Queue membership snapshot used while resolving an assignment change.
7
- *
8
- * Produced by: assignment-change consumer.
9
- * Consumed by: InboxAudienceResolver.
10
- * Used when: previous/current queue audiences must be expanded from groups
11
- * into concrete users without embedding membership in the integration event.
12
- */
13
- export interface QueueAudienceResolutionContext {
14
- queue: ConversationQueue;
15
- memberUserIds: ID[];
16
- activeMemberUserIds: ID[];
17
- supervisorUserIds: ID[];
18
- }
19
- /**
20
- * Complete input for calculating desired inbox visibility.
21
- *
22
- * Produced by: ConversationAssignmentChanged consumer.
23
- * Consumed by: InboxAudienceResolver.
24
- * Used when: an assignment/transfer changes queue, owner or status and the
25
- * desired per-user inbox audience must be recalculated.
26
- */
27
- export interface InboxAudienceResolverInput {
28
- sourceEvent: ConversationAssignmentChanged;
29
- snapshot: ConversationInboxSnapshot;
30
- previousQueue?: QueueAudienceResolutionContext;
31
- currentQueue?: QueueAudienceResolutionContext;
32
- participantUserIds: ID[];
33
- followerUserIds: ID[];
34
- }
35
- /**
36
- * Visibility of one conversation inside one logical inbox view.
37
- *
38
- * Produced by: InboxAudienceResolver.
39
- * Consumed by: inbox item projection planner/projector.
40
- * Used when: multiple independent reasons can preserve the same view without
41
- * generating duplicate inbox items or duplicate counter increments.
42
- */
43
- export type ResolvedInboxView = UserInboxItemView;
44
- /**
45
- * Desired inbox visibility for a single user after applying the source event.
46
- *
47
- * Produced by: InboxAudienceResolver.
48
- * Consumed by: inbox item projection planner/projector.
49
- * Used when: the projector compares desired visibility with the materialized
50
- * user_inbox_items state.
51
- */
52
- export interface ResolvedInboxUserVisibility {
53
- userId: ID;
54
- views: ResolvedInboxView[];
55
- }
56
- /**
57
- * Full audience resolution result for one conversation version.
58
- *
59
- * Produced by: InboxAudienceResolver.
60
- * Consumed by: inbox item projection planner/projector.
61
- * Used when: all affected users must be diffed against their existing
62
- * user_inbox_items documents.
63
- */
64
- export interface ResolvedInboxAudience {
65
- sourceEventId: ID;
66
- spaceId: ID;
67
- conversationId: ID;
68
- conversationVersion: number;
69
- snapshot: ConversationInboxSnapshot;
70
- users: ResolvedInboxUserVisibility[];
71
- resolvedAt: Date;
72
- }
73
- /**
74
- * Processor boundary for pure audience calculation.
75
- *
76
- * Called by: ConversationAssignmentChanged consumer.
77
- * Returns to: inbox item projection planner/projector.
78
- */
79
- export interface InboxAudienceResolver {
80
- resolve(input: InboxAudienceResolverInput): Promise<ResolvedInboxAudience>;
81
- }
82
- export type InboxProjectionOperation = 'insert' | 'update' | 'delete';
83
- /**
84
- * Idempotent mutation plan for one user's materialized conversation item.
85
- *
86
- * Produced by: inbox item projection planner.
87
- * Consumed by: inbox item projector; after persistence it is also the input
88
- * used to derive InboxCounterDelta messages.
89
- * Used when: desired audience is compared with the existing projection.
90
- *
91
- * id must be deterministic from:
92
- * sourceEventId + userId + conversationId.
93
- */
94
- export interface InboxProjectionDelta {
95
- id: ID;
96
- sourceEventId: ID;
97
- spaceId: ID;
98
- userId: ID;
99
- conversationId: ID;
100
- conversationVersion: number;
101
- operation: InboxProjectionOperation;
102
- previous?: ResolvedInboxUserVisibility;
103
- current?: ResolvedInboxUserVisibility;
104
- snapshot?: ConversationInboxSnapshot;
105
- createdAt: Date;
106
- }
107
- /**
108
- * Atomic counter change for one user/view caused by one projection delta.
109
- *
110
- * Produced by: inbox item projector after determining the actual persisted
111
- * before/after state.
112
- * Consumed by: InboxCounterProjector.
113
- * Used when: view membership, requiresAction or unread state changes.
114
- *
115
- * id must be deterministic from:
116
- * sourceEventId + userId + conversationId + viewId.
117
- */
118
- export interface InboxCounterDelta {
119
- id: ID;
120
- sourceEventId: ID;
121
- spaceId: ID;
122
- userId: ID;
123
- conversationId: ID;
124
- viewId: InboxViewId;
125
- conversationVersion: number;
126
- totalDelta: -1 | 0 | 1;
127
- requiresActionDelta: -1 | 0 | 1;
128
- unreadDelta: -1 | 0 | 1;
129
- createdAt: Date;
130
- }
131
- /**
132
- * Durable idempotency receipt for a processor side effect.
133
- *
134
- * Produced and consumed by: inbox item projector or InboxCounterProjector.
135
- * Used when: the same outbox event/delta is delivered more than once.
136
- *
137
- * Unique key:
138
- * processor + sourceEventId + scopeKey.
139
- *
140
- * scopeKey examples:
141
- * - item projector: userId + conversationId
142
- * - counter projector: userId + conversationId + viewId
143
- */
144
- export interface InboxProcessorReceipt {
145
- id: ID;
146
- processor: InboxProcessorName;
147
- sourceEventId: ID;
148
- scopeKey: string;
149
- spaceId: ID;
150
- conversationId: ID;
151
- conversationVersion: number;
152
- processedAt: Date;
153
- }
154
- /**
155
- * Processor boundary for applying counter deltas idempotently.
156
- *
157
- * Called by: inbox item projector.
158
- * Mutates: user_inbox_counters and InboxProcessorReceipt in one transaction.
159
- */
160
- export interface InboxCounterProjector {
161
- apply(delta: InboxCounterDelta): Promise<void>;
162
- }