@trii/types 2.10.753 → 2.10.754
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Common/Messages/Message.d.ts +2 -0
- package/dist/Conversations/Assignment.d.ts +0 -1
- package/dist/Conversations/Assignment.js +0 -2
- package/dist/Conversations/Classifications/ClassificationTaxonomy.d.ts +0 -2
- package/dist/Conversations/Classifications/ClassificationTaxonomy.js +0 -3
- package/dist/Conversations/Conversation.d.ts +38 -201
- package/dist/Conversations/ConversationPendingTransfer.d.ts +16 -0
- package/dist/Conversations/ConversationReadState.d.ts +16 -0
- package/dist/Conversations/ConversationReadState.js +2 -0
- package/dist/Conversations/ConversationSlaClockState.d.ts +45 -0
- package/dist/Conversations/ConversationSlaClockState.js +2 -0
- package/dist/Conversations/InboxQueries.d.ts +30 -0
- package/dist/Conversations/InboxQueries.js +2 -0
- package/dist/Conversations/Outbox.d.ts +0 -1
- package/dist/Conversations/Outbox.js +0 -2
- package/dist/Conversations/Queue.d.ts +1 -3
- package/dist/Conversations/Queue.js +0 -2
- package/dist/Conversations/Sla.d.ts +2 -5
- package/dist/Conversations/Sla.js +0 -4
- package/dist/Conversations/SocialWalls.d.ts +9 -51
- package/dist/Conversations/Transfer.d.ts +1 -0
- package/dist/Conversations/index.d.ts +4 -2
- package/dist/Conversations/index.js +4 -2
- package/package.json +1 -1
- package/dist/Conversations/InboxMongo.d.ts +0 -154
- package/dist/Conversations/InboxMongo.js +0 -128
- package/dist/Conversations/InboxProjection.d.ts +0 -162
- /package/dist/Conversations/{InboxProjection.js → ConversationPendingTransfer.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,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,7 @@
|
|
|
1
1
|
import { UserInfo } from "../Users/UserTrii";
|
|
2
|
+
import type { ConversationReadState } from './ConversationReadState';
|
|
3
|
+
import type { ConversationPendingTransfer } from './ConversationPendingTransfer';
|
|
4
|
+
import type { ConversationSlaSnapshot, ConversationSlaStatus } from './ConversationSlaClockState';
|
|
2
5
|
import { ILabel } from "./Label";
|
|
3
6
|
import { GroupInfo } from "./Groups/Group";
|
|
4
7
|
import { Channels } from "../Common/index";
|
|
@@ -38,39 +41,26 @@ export interface IConversation {
|
|
|
38
41
|
status: ConversationStatus;
|
|
39
42
|
priority: 'low' | 'normal' | 'high' | 'urgent';
|
|
40
43
|
assignment: ConversationAssignmentSnapshot;
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
sla:
|
|
44
|
-
status: 'none' | 'running' | 'warning' | 'breached' | 'met';
|
|
45
|
-
deadlineAt?: Date;
|
|
46
|
-
policyId?: string;
|
|
47
|
-
version: number;
|
|
48
|
-
};
|
|
44
|
+
/** Preserve assignment until acceptance atomically replaces it and clears this handoff. */
|
|
45
|
+
pendingTransfer?: ConversationPendingTransfer | null;
|
|
46
|
+
sla: ConversationSlaSnapshot;
|
|
49
47
|
lastMessage: string;
|
|
50
48
|
lastMessageId?: string;
|
|
51
|
-
|
|
52
|
-
newMessagesUnread: boolean;
|
|
49
|
+
readState: ConversationReadState;
|
|
53
50
|
lastActivityAt: Date;
|
|
54
51
|
lastCustomerActivityAt?: Date;
|
|
55
52
|
lastAgentActivityAt?: Date;
|
|
56
53
|
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
|
-
*/
|
|
54
|
+
/** Shared pin for every viewer of this conversation. */
|
|
61
55
|
pinned: boolean;
|
|
56
|
+
/** Shared outstanding work; reading does not answer or resolve it. */
|
|
57
|
+
requiresAction: boolean;
|
|
62
58
|
/**
|
|
63
|
-
*
|
|
59
|
+
* Legacy internal-chat preference. Not the shared pin or customer conversation state.
|
|
64
60
|
* El front compara contra la hora actual; una fecha lejana representa "siempre".
|
|
65
61
|
*/
|
|
66
62
|
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
63
|
expired: boolean;
|
|
72
|
-
/** @deprecated Expiration does not own a separate assignment snapshot.*/
|
|
73
|
-
expiredAssignedTo: ConversationAssigned;
|
|
74
64
|
participants: UserInfo[];
|
|
75
65
|
archived: boolean;
|
|
76
66
|
spam: boolean;
|
|
@@ -93,7 +83,18 @@ export interface IConversation {
|
|
|
93
83
|
resolutionReasonId?: string;
|
|
94
84
|
finalizedAt: Date;
|
|
95
85
|
finalizedBy?: string;
|
|
86
|
+
/** Presentation kind, not a separate lifecycle. Public conversations belong to one contact. */
|
|
87
|
+
interactionKind: InteractionKind;
|
|
88
|
+
/** Internal Post.id, required for public views. Null for private conversations. */
|
|
89
|
+
wallPostId?: string | null;
|
|
90
|
+
/** Stable internal WallMessage.id root; required for comment/mention, null for wall_post/private.
|
|
91
|
+
* Correlate by tenant/channel/contact/post/root, never by post alone.
|
|
92
|
+
*/
|
|
93
|
+
wallRootCommentId?: string | null;
|
|
94
|
+
/** Mutable navigation focus in the public thread, not its identity. */
|
|
95
|
+
lastCommentId?: string | null;
|
|
96
96
|
}
|
|
97
|
+
export type InteractionKind = 'private' | 'wall_post' | 'comment' | 'mention';
|
|
97
98
|
export interface IWhatsAppGroupInfo {
|
|
98
99
|
whatsappGroupId: string;
|
|
99
100
|
groupInviteCode: string;
|
|
@@ -185,7 +186,7 @@ export declare enum ConversationStatus {
|
|
|
185
186
|
FINALIZED = 3,// Alias for RESOLVED
|
|
186
187
|
WAITING = 10
|
|
187
188
|
}
|
|
188
|
-
export type InboxViewId = 'pending' | 'following' | 'sla_warning' | 'sla_breached' | 'team_sla_breached'
|
|
189
|
+
export type InboxViewId = 'pending' | 'following' | 'sla_warning' | 'sla_breached' | 'team_sla_breached';
|
|
189
190
|
export type OwnerType = 'user' | 'bot' | 'flow' | 'none';
|
|
190
191
|
export interface NoConversationOwner {
|
|
191
192
|
type: 'none';
|
|
@@ -308,194 +309,41 @@ export interface PutConversationSubscriptionRequest {
|
|
|
308
309
|
expectedVersion?: number;
|
|
309
310
|
notifications: ConversationSubscriptionNotifications;
|
|
310
311
|
}
|
|
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
312
|
export type ConversationReadStateMode = 'read' | 'unread';
|
|
324
313
|
export interface PutConversationReadStateRequest {
|
|
325
314
|
mode: ConversationReadStateMode;
|
|
326
|
-
|
|
327
|
-
|
|
315
|
+
commandId: string;
|
|
316
|
+
expectedConversationVersion: number;
|
|
317
|
+
/** Required for read, null for unread. Observed cursor, never silently server-latest. */
|
|
318
|
+
throughIncomingSequence?: number | null;
|
|
328
319
|
}
|
|
329
320
|
export interface PutConversationPinRequest {
|
|
321
|
+
commandId: string;
|
|
322
|
+
expectedConversationVersion: number;
|
|
330
323
|
pinned: boolean;
|
|
331
324
|
}
|
|
332
|
-
|
|
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
|
-
}
|
|
325
|
+
/** Conversation lists return CursorPage<IConversation> directly; authorization stays in backend. */
|
|
460
326
|
export interface CursorPage<T> {
|
|
461
327
|
items: T[];
|
|
462
|
-
nextCursor?: string;
|
|
328
|
+
nextCursor?: string | null;
|
|
463
329
|
hasMore: boolean;
|
|
464
330
|
generatedAt: Date;
|
|
465
331
|
}
|
|
466
|
-
|
|
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
|
-
}
|
|
332
|
+
/** Counts distinct authorized conversations on demand; unread includes manual unread. */
|
|
483
333
|
export interface InboxViewSummaryDto {
|
|
484
|
-
id:
|
|
334
|
+
id: string;
|
|
485
335
|
label: string;
|
|
486
|
-
scope:
|
|
336
|
+
scope: string;
|
|
487
337
|
order: number;
|
|
488
338
|
total: number;
|
|
489
339
|
requiresAction: number;
|
|
490
340
|
unread: number;
|
|
491
341
|
enabled: boolean;
|
|
492
342
|
targetRequired: boolean;
|
|
493
|
-
capabilities: string[];
|
|
494
343
|
}
|
|
495
344
|
export interface InboxViewsResponse {
|
|
496
345
|
views: InboxViewSummaryDto[];
|
|
497
346
|
countersGeneratedAt: Date;
|
|
498
|
-
projectionLagMs?: number;
|
|
499
347
|
}
|
|
500
348
|
export interface InboxFilterDto {
|
|
501
349
|
text?: string;
|
|
@@ -504,7 +352,8 @@ export interface InboxFilterDto {
|
|
|
504
352
|
channelTypes?: string[];
|
|
505
353
|
statuses?: ConversationStatus[];
|
|
506
354
|
priorities?: Array<'low' | 'normal' | 'high' | 'urgent'>;
|
|
507
|
-
slaStatuses?:
|
|
355
|
+
slaStatuses?: ConversationSlaStatus[];
|
|
356
|
+
/** OR within the authorized view; labels never grant access. */
|
|
508
357
|
labelIds?: ID[];
|
|
509
358
|
unread?: boolean;
|
|
510
359
|
requiresAction?: boolean;
|
|
@@ -519,16 +368,6 @@ export interface InboxFilterDto {
|
|
|
519
368
|
type: 'priority';
|
|
520
369
|
};
|
|
521
370
|
}
|
|
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
371
|
export interface InboxFacetOptionDto {
|
|
533
372
|
id: string;
|
|
534
373
|
label: string;
|
|
@@ -541,9 +380,11 @@ export interface InboxFacetsDto {
|
|
|
541
380
|
statuses: InboxFacetOptionDto[];
|
|
542
381
|
priorities: InboxFacetOptionDto[];
|
|
543
382
|
slaStatuses: InboxFacetOptionDto[];
|
|
383
|
+
/** Full selected view, before label filters/pagination; only positive counts, once per label/conversation. */
|
|
544
384
|
labels: InboxFacetOptionDto[];
|
|
545
385
|
}
|
|
546
386
|
export interface InboxFilterOptionsResponse {
|
|
387
|
+
viewId: InboxViewId;
|
|
547
388
|
facets: InboxFacetsDto;
|
|
548
389
|
generatedAt: Date;
|
|
549
390
|
}
|
|
@@ -558,14 +399,10 @@ export interface ConversationUserRelationDto {
|
|
|
558
399
|
isOwner: boolean;
|
|
559
400
|
isParticipant: boolean;
|
|
560
401
|
isFollowing: boolean;
|
|
561
|
-
isPinned: boolean;
|
|
562
|
-
unreadCount: number;
|
|
563
402
|
}
|
|
564
403
|
export interface ConversationDetailResponse {
|
|
565
404
|
conversation: IConversation;
|
|
566
405
|
relation: ConversationUserRelationDto;
|
|
567
|
-
capabilities: ConversationCapabilitiesDto;
|
|
568
|
-
availableActions: string[];
|
|
569
406
|
}
|
|
570
407
|
export interface AddConversationParticipantRequest {
|
|
571
408
|
userId: string;
|
|
@@ -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,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,45 @@
|
|
|
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
|
+
/** Chargeable seconds through elapsedCalculatedAt, within JS safe integer range. */
|
|
26
|
+
elapsedSeconds: number;
|
|
27
|
+
/** Accounting watermark; on resume reset to resume time preserving consumed seconds. */
|
|
28
|
+
elapsedCalculatedAt: Date;
|
|
29
|
+
breachedAt?: Date | null;
|
|
30
|
+
completedAt?: Date | null;
|
|
31
|
+
cancelledAt?: Date | null;
|
|
32
|
+
}
|
|
33
|
+
/** Summary updated atomically with clocks; never an independent state source. */
|
|
34
|
+
export interface ConversationSlaSnapshot {
|
|
35
|
+
/** Precedence: breached, active warning, running, paused, met, cancelled, none. */
|
|
36
|
+
status: ConversationSlaStatus;
|
|
37
|
+
/** Earliest unfinished/unpaused deadline. Compare against UTC even if evaluator lags. */
|
|
38
|
+
deadlineAt?: Date | null;
|
|
39
|
+
/** Selection for new clocks; current clocks retain their applied references. */
|
|
40
|
+
policyId?: string | null;
|
|
41
|
+
policyVersion?: number | null;
|
|
42
|
+
clocks: ConversationSlaClockState[];
|
|
43
|
+
/** SLA state revision, not policy version. */
|
|
44
|
+
version: number;
|
|
45
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -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,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.
|
|
@@ -166,8 +163,8 @@ export interface ConversationSlaPausePeriod {
|
|
|
166
163
|
sourceEventId: ID;
|
|
167
164
|
}
|
|
168
165
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
166
|
+
* External history/read model. Current clocks live only in Conversation.sla.clocks.
|
|
167
|
+
* Policy copies here describe historical configuration, not another live state source.
|
|
171
168
|
*/
|
|
172
169
|
export interface ConversationSlaCycle {
|
|
173
170
|
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,
|
|
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:
|
|
82
|
+
interactionKind: InteractionKind;
|
|
113
83
|
post: Post;
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
|
|
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
|
}
|
|
@@ -2,8 +2,10 @@ 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 './
|
|
6
|
-
export * from './
|
|
5
|
+
export * from './InboxQueries';
|
|
6
|
+
export * from './ConversationReadState';
|
|
7
|
+
export * from './ConversationPendingTransfer';
|
|
8
|
+
export * from './ConversationSlaClockState';
|
|
7
9
|
export * from './Outbox';
|
|
8
10
|
export * from './Ending';
|
|
9
11
|
export * from './Label';
|
|
@@ -41,8 +41,10 @@ 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("./
|
|
45
|
-
__exportStar(require("./
|
|
44
|
+
__exportStar(require("./InboxQueries"), exports);
|
|
45
|
+
__exportStar(require("./ConversationReadState"), exports);
|
|
46
|
+
__exportStar(require("./ConversationPendingTransfer"), exports);
|
|
47
|
+
__exportStar(require("./ConversationSlaClockState"), exports);
|
|
46
48
|
__exportStar(require("./Outbox"), exports);
|
|
47
49
|
__exportStar(require("./Ending"), exports);
|
|
48
50
|
__exportStar(require("./Label"), exports);
|
package/package.json
CHANGED
|
@@ -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
|
-
}
|
|
File without changes
|