@periskope/types 0.6.261 → 0.6.263

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/src/types.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import type { default as _Stripe } from 'stripe';
2
2
  import { Merge, OverrideProperties } from 'type-fest';
3
3
  import { Filter, Rule } from './rules.types';
4
- import { Tables, TablesInsert, TablesUpdate } from './supabase.types';
4
+ import { Enums, Tables, TablesInsert, TablesUpdate } from './supabase.types';
5
+ import { WorkflowActionTypes } from './workflows.types';
5
6
 
6
7
  /* ----------------------------- TYPE SHORTHANDS ---------------------------- */
7
8
 
@@ -64,7 +65,6 @@ export type MicrosurveyData = {
64
65
 
65
66
  export type OrgPreferences = {
66
67
  disable_ai_flagging?: boolean;
67
- disable_ai_responder?: boolean;
68
68
  disable_allow_exports?: boolean;
69
69
  sync_phone_contacts?: boolean;
70
70
  mask_phone_numbers?: boolean;
@@ -1229,4 +1229,4 @@ export type FreshdeskCustomFieldType = {
1229
1229
  created_at: string;
1230
1230
  updated_at: string;
1231
1231
  choices?: Choice[];
1232
- };
1232
+ };
@@ -0,0 +1,692 @@
1
+ import { Merge, OverrideProperties } from 'type-fest';
2
+ import { AppendTypes } from './rules.types';
3
+ import { Tables } from './supabase.types';
4
+ import { TaskType } from './types';
5
+
6
+ /***************************** WORKFLOWS *****************************/
7
+
8
+ type WorkflowActions = {
9
+ id: string;
10
+ action_metadata: NormalWorkflowActionTypes;
11
+ next: string;
12
+ };
13
+
14
+ type SplitPathActions = {
15
+ id: string;
16
+ action_metadata: SplitPathAction;
17
+ };
18
+
19
+ export type WorkflowType = OverrideProperties<
20
+ Tables<'tbl_org_workflows'>,
21
+ {
22
+ trigger_metadata: {
23
+ org_phones: string[];
24
+ allow_internal_messages?: boolean;
25
+ first_action_id: string;
26
+ };
27
+ trigger: Triggers;
28
+ actions: Array<WorkflowActions | SplitPathActions>;
29
+ }
30
+ >;
31
+
32
+ export function isSplitPathAction(
33
+ workflow_action: WorkflowType['actions'][number]
34
+ ): workflow_action is SplitPathActions {
35
+ return workflow_action.action_metadata.type === 'split_path';
36
+ }
37
+
38
+ /***************************** CONDITIONS TYPES *****************************/
39
+
40
+ // {
41
+ // "operator": "AND",
42
+ // "conditions": [
43
+ // {
44
+ // "id": "cond1",
45
+ // "variable_name": "message",
46
+ // "variable_type": "string",
47
+ // "condition": "CONTAINS",
48
+ // "value": "urgent"
49
+ // },
50
+ // {
51
+ // "operator": "OR",
52
+ // "conditions": [
53
+ // {
54
+ // "id": "cond2",
55
+ // "variable_name": "priority",
56
+ // "variable_type": "number",
57
+ // "condition": "GT",
58
+ // "value": 2
59
+ // },
60
+ // {
61
+ // "id": "cond3",
62
+ // "variable_name": "assigned",
63
+ // "variable_type": "boolean",
64
+ // "condition": "NKNOWN"
65
+ // }
66
+ // ]
67
+ // }
68
+ // ]
69
+ // }
70
+
71
+ enum Conditions {
72
+ // string
73
+ CONTAINS = 'contains',
74
+ NCONTAINS = 'not contains',
75
+ EQUALS = 'equals',
76
+ NEQUALS = 'not equals',
77
+ STARTS_WITH = 'starts with',
78
+ ENDS_WITH = 'ends with',
79
+
80
+ // number, date, time
81
+ GREATER_THAN = 'greater than',
82
+ GREATER_THAN_OR_EQUAL = 'greater than or equal',
83
+ LESS_THAN = 'less than',
84
+ LESS_THAN_OR_EQUAL = 'less than or equal',
85
+
86
+ // none
87
+ IS_KNOWN = 'is known',
88
+ IS_UNKNOWN = 'is unknown',
89
+
90
+ // boolean
91
+ IS = 'is',
92
+ IS_NOT = 'is not',
93
+
94
+ // array
95
+ IS_ANY_OF = 'is any of',
96
+ IS_NOT_ANY_OF = 'is not any of',
97
+
98
+ // day
99
+ ON = 'on',
100
+ }
101
+
102
+ type BaseCondition<T extends Triggers> = {
103
+ id: string;
104
+ variable_name: keyof WorkflowDataType<T>;
105
+ };
106
+
107
+ type StringCondition = BaseCondition<Triggers> & {
108
+ condition:
109
+ | 'CONTAINS'
110
+ | 'NCONTAINS'
111
+ | 'EQUALS'
112
+ | 'NEQUALS'
113
+ | 'STARTS_WITH'
114
+ | 'ENDS_WITH';
115
+ value: string;
116
+ variable_type: 'string';
117
+ };
118
+
119
+ type DateTimeNumberCondition = BaseCondition<Triggers> & {
120
+ condition:
121
+ | 'GREATER_THAN'
122
+ | 'GREATER_THAN_OR_EQUAL'
123
+ | 'LESS_THAN'
124
+ | 'LESS_THAN_OR_EQUAL';
125
+ } & (
126
+ | {
127
+ value: string;
128
+ variable_type: 'number';
129
+ }
130
+ | {
131
+ value: string;
132
+ timezone: string;
133
+ variable_type: 'date' | 'time';
134
+ }
135
+ );
136
+
137
+ type ExistsCondition = BaseCondition<Triggers> & {
138
+ condition: 'IS_KNOWN' | 'IS_UNKNOWN';
139
+ value: undefined | null;
140
+ variable_type: null;
141
+ };
142
+
143
+ type OnCondition = BaseCondition<Triggers> & {
144
+ condition: 'ON';
145
+ value: string | string[];
146
+ timezone: string;
147
+ variable_type: 'day';
148
+ };
149
+
150
+ type BooleanCondition = BaseCondition<Triggers> & {
151
+ condition: 'IS' | 'IS_NOT';
152
+ value: boolean | 'true' | 'false';
153
+ variable_type: 'boolean';
154
+ };
155
+
156
+ type ArrayCondition = BaseCondition<Triggers> & {
157
+ condition: 'IS_ANY_OF' | 'IS_NOT_ANY_OF';
158
+ value: string[];
159
+ variable_type: 'array';
160
+ };
161
+
162
+ export type ConditionLeaf =
163
+ | StringCondition
164
+ | DateTimeNumberCondition
165
+ | ExistsCondition
166
+ | OnCondition
167
+ | BooleanCondition
168
+ | ArrayCondition;
169
+
170
+ type ConditionOperator = 'AND' | 'OR';
171
+
172
+ export type WorkflowConditionGroup = {
173
+ operator: ConditionOperator;
174
+ conditions: Array<ConditionLeaf | WorkflowConditionGroup>;
175
+ };
176
+
177
+ export function isConditionLeaf(
178
+ condition: ConditionLeaf | WorkflowConditionGroup
179
+ ): condition is ConditionLeaf {
180
+ return 'id' in condition && !('operator' in condition);
181
+ }
182
+
183
+ /***************************** WORKFLOW DATA TYPES *****************************/
184
+
185
+ export type WorkflowRawDataTypes = {
186
+ message: Tables<'tbl_chat_messages'>;
187
+ reaction: Tables<'tbl_chat_reactions'>;
188
+ chat: Merge<
189
+ Merge<Tables<'tbl_chats'>, Tables<'tbl_chat_properties'>>,
190
+ {
191
+ has_flagged_messages: boolean;
192
+ last_message_self: boolean;
193
+ members: string[];
194
+ }
195
+ >;
196
+ ticket: Tables<'tbl_chat_tickets'>;
197
+ task: Tables<'tbl_org_tasks'>;
198
+ sender: Tables<'tbl_contacts'> & Tables<'tbl_chat_participants'>;
199
+ };
200
+
201
+ export type MessageWorkflowDataTypes = AppendTypes<
202
+ {
203
+ message: WorkflowRawDataTypes['message'];
204
+ sender: WorkflowRawDataTypes['sender'];
205
+ chat: WorkflowRawDataTypes['chat'];
206
+ ticket: WorkflowRawDataTypes['ticket'];
207
+ },
208
+ '.'
209
+ >;
210
+
211
+ export type ReactionWorkflowDataTypes = AppendTypes<
212
+ {
213
+ reaction: WorkflowRawDataTypes['reaction'];
214
+ sender: WorkflowRawDataTypes['sender'];
215
+ message: MessageWorkflowDataTypes;
216
+ },
217
+ '.'
218
+ >;
219
+
220
+ export type TicketWorkflowDataTypes = AppendTypes<
221
+ {
222
+ ticket: WorkflowRawDataTypes['ticket'];
223
+ message: MessageWorkflowDataTypes;
224
+ },
225
+ '.'
226
+ >;
227
+
228
+ export type TaskWorkflowDataTypes = AppendTypes<
229
+ {
230
+ task: WorkflowRawDataTypes['task'];
231
+ associated_object: TaskType['associated_object_metadata'];
232
+ },
233
+ '.'
234
+ >;
235
+
236
+ export type ChatWorkflowDataTypes = AppendTypes<
237
+ {
238
+ chat: WorkflowRawDataTypes['chat'];
239
+ },
240
+ '.'
241
+ >;
242
+
243
+ export enum Triggers {
244
+ MESSAGE_CREATED = 'message.created',
245
+ MESSAGE_UPDATED = 'message.updated',
246
+ MESSAGE_DELETED = 'message.deleted',
247
+ MESSAGE_FLAGGED = 'message.flagged',
248
+ MESSAGE_UNFLAGGED = 'message.unflagged',
249
+ REACTION_ADDED = 'reaction.added',
250
+ TICKET_CREATED = 'ticket.created',
251
+ TICKET_UPDATED = 'ticket.updated',
252
+ TICKET_DELETED = 'ticket.deleted',
253
+ TICKET_CLOSED = 'ticket.closed',
254
+ TICKET_DUE = 'ticket.due',
255
+ CHAT_CREATED = 'chat.created',
256
+ CHAT_LABEL_UPDATED = 'chat.label.updated',
257
+ CHAT_CLOSED = 'chat.closed',
258
+ TASK_CREATED = 'task.created',
259
+ TASK_DUE = 'task.due',
260
+ }
261
+
262
+ export type WorkflowDataType<T extends Triggers> = T extends
263
+ | Triggers.MESSAGE_CREATED
264
+ | Triggers.MESSAGE_DELETED
265
+ | Triggers.MESSAGE_UPDATED
266
+ | Triggers.MESSAGE_FLAGGED
267
+ | Triggers.MESSAGE_UNFLAGGED
268
+ ? MessageWorkflowDataTypes
269
+ : T extends
270
+ | Triggers.CHAT_CREATED
271
+ | Triggers.CHAT_LABEL_UPDATED
272
+ | Triggers.CHAT_CLOSED
273
+ ? ChatWorkflowDataTypes
274
+ : T extends
275
+ | Triggers.TICKET_CREATED
276
+ | Triggers.TICKET_UPDATED
277
+ | Triggers.TICKET_DELETED
278
+ | Triggers.TICKET_CLOSED
279
+ | Triggers.TICKET_DUE
280
+ ? TicketWorkflowDataTypes
281
+ : T extends Triggers.REACTION_ADDED
282
+ ? ReactionWorkflowDataTypes
283
+ : T extends Triggers.TASK_CREATED | Triggers.TASK_DUE
284
+ ? TaskWorkflowDataTypes
285
+ : never;
286
+
287
+ /***************************** ACTION TYPES *****************************/
288
+
289
+ export type SendMessageToChatWorkflowAction = {
290
+ type: 'send_message_to_chat';
291
+ metadata: {
292
+ message: string;
293
+ media?: {
294
+ url: string;
295
+ type: 'image' | 'video' | 'audio' | 'document';
296
+ name: string;
297
+ };
298
+ debounce?: `${number} ${'seconds' | 'minutes' | 'hours' | 'days'}` | null;
299
+ chat_id: `${string}${'@g.us' | '@c.us'}` | 'trigger_chat' | null;
300
+ unflag_chat?: boolean;
301
+ };
302
+ };
303
+
304
+ export type SendReplyWorkflowAction = {
305
+ type: 'send_reply_message';
306
+ metadata: {
307
+ message: string;
308
+ media?: {
309
+ url: string;
310
+ type: 'image' | 'video' | 'audio' | 'document';
311
+ name: string;
312
+ };
313
+ debounce?: `${number} ${'seconds' | 'minutes' | 'hours' | 'days'}` | null;
314
+ unflag_chat?: boolean;
315
+ };
316
+ };
317
+
318
+ export type CreateTicketWorkflowAction = {
319
+ type: 'create_ticket';
320
+ metadata: {
321
+ subject: string;
322
+ assignee:
323
+ | {
324
+ round_robin: true;
325
+ emails: string[];
326
+ assignee_check_for?: 'shift_times' | 'online_offline' | 'all';
327
+ }
328
+ | {
329
+ email: string;
330
+ };
331
+ priority?: '0' | '1' | '2' | '3' | '4';
332
+ status: 'open' | 'inprogress' | 'closed';
333
+ labels: string[];
334
+ due_date: `${number} ${'seconds' | 'minutes' | 'hours' | 'days'}` | null;
335
+ };
336
+ };
337
+
338
+ export type AttachToLatestTicket = {
339
+ type: 'attach_to_latest_ticket';
340
+ metadata: {
341
+ status: ('open' | 'inprogress' | 'closed')[];
342
+ };
343
+ };
344
+
345
+ export type NotifyHTTPWorkflowAction = {
346
+ type: 'notify_http';
347
+ metadata: {
348
+ url: string;
349
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
350
+ headers: Record<string, string>;
351
+ body: string;
352
+ };
353
+ };
354
+
355
+ export type FlagMessageWorkflowAction = {
356
+ type: 'flag_message';
357
+ metadata: {};
358
+ };
359
+
360
+ export type UnflagMessageWorkflowAction = {
361
+ type: 'unflag_message';
362
+ metadata: {};
363
+ };
364
+
365
+ export type AssignTicketWorkflowAction = {
366
+ type: 'assign_ticket';
367
+ metadata: {
368
+ assignee:
369
+ | {
370
+ round_robin: true;
371
+ emails: string[];
372
+ assignee_check_for?: 'shift_times' | 'online_offline' | 'all';
373
+ }
374
+ | {
375
+ email: string;
376
+ };
377
+ };
378
+ };
379
+
380
+ export type CloseTicketWorkflowAction = {
381
+ type: 'close_ticket';
382
+ metadata: {
383
+ bypass_mandatory_fields?: boolean;
384
+ closing_note: string;
385
+ };
386
+ };
387
+
388
+ export type AddChatLabelWorkflowAction = {
389
+ type: 'add_chat_label';
390
+ metadata: {
391
+ labels: string[];
392
+ };
393
+ };
394
+
395
+ export type RemoveChatLabelWorkflowAction = {
396
+ type: 'remove_chat_label';
397
+ metadata: {
398
+ labels: string[];
399
+ };
400
+ };
401
+
402
+ export type AddTicketLabelWorkflowAction = {
403
+ type: 'add_ticket_label';
404
+ metadata: {
405
+ labels: string[];
406
+ };
407
+ };
408
+
409
+ export type RemoveTicketLabelWorkflowAction = {
410
+ type: 'remove_ticket_label';
411
+ metadata: {
412
+ labels: string[];
413
+ };
414
+ };
415
+
416
+ export type AssignChatWorkflowAction = {
417
+ type: 'assign_chat';
418
+ metadata: {
419
+ assignee:
420
+ | {
421
+ round_robin: true;
422
+ emails: string[];
423
+ assignee_check_for?: 'shift_times' | 'online_offline' | 'all';
424
+ }
425
+ | {
426
+ email: string;
427
+ };
428
+ };
429
+ };
430
+
431
+ export type ForwardMessageWorkflowAction = {
432
+ type: 'forward_message';
433
+ metadata: {
434
+ chat_id: `${string}${'@g.us' | '@c.us'}`;
435
+ };
436
+ };
437
+
438
+ export type SendEmailWorkflowAction = {
439
+ type: 'send_email';
440
+ metadata: {
441
+ email: string;
442
+ subject: string;
443
+ body: string;
444
+ };
445
+ };
446
+
447
+ export type DeleteMessageWorkflowAction = {
448
+ type: 'delete_message';
449
+ metadata: {};
450
+ };
451
+
452
+ export type CloseChatWorkflowAction = {
453
+ type: 'close_chat';
454
+ metadata: {};
455
+ };
456
+
457
+ export type ValidateWorkflowAction = {
458
+ type: 'validate_action';
459
+ metadata: WorkflowConditionGroup;
460
+ };
461
+
462
+ export type DelayAction = {
463
+ type: 'delay';
464
+ metadata: {
465
+ delay: `${number} ${'seconds' | 'minutes' | 'hours' | 'days'}`;
466
+ };
467
+ };
468
+
469
+ export type SendSlackNotification = {
470
+ type: 'send_slack_notification';
471
+ metadata: {
472
+ slack_payload: string;
473
+ url: string;
474
+ };
475
+ };
476
+
477
+ export type SplitPathAction = {
478
+ type: 'split_path';
479
+ metadata: {
480
+ paths: Array<{
481
+ id: string;
482
+ condition_action_id: string;
483
+ }>;
484
+ };
485
+ };
486
+
487
+ // experimental
488
+ export type AIPromptCheckWorkflowAction = {
489
+ type: 'ai_prompt_check';
490
+ metadata: {
491
+ query: string;
492
+ body: string;
493
+ };
494
+ };
495
+
496
+ export type NormalWorkflowActionTypes =
497
+ | SendMessageToChatWorkflowAction
498
+ | SendReplyWorkflowAction
499
+ | CreateTicketWorkflowAction
500
+ | AttachToLatestTicket
501
+ | NotifyHTTPWorkflowAction
502
+ | FlagMessageWorkflowAction
503
+ | UnflagMessageWorkflowAction
504
+ | AssignTicketWorkflowAction
505
+ | CloseTicketWorkflowAction
506
+ | AddChatLabelWorkflowAction
507
+ | RemoveChatLabelWorkflowAction
508
+ | AddTicketLabelWorkflowAction
509
+ | RemoveTicketLabelWorkflowAction
510
+ | AssignChatWorkflowAction
511
+ | ForwardMessageWorkflowAction
512
+ | SendEmailWorkflowAction
513
+ | DeleteMessageWorkflowAction
514
+ | CloseChatWorkflowAction
515
+ | ValidateWorkflowAction
516
+ | DelayAction
517
+ | SendSlackNotification
518
+ | AIPromptCheckWorkflowAction;
519
+
520
+ export type WorkflowActionTypes = NormalWorkflowActionTypes | SplitPathAction;
521
+
522
+
523
+ // Example workflow type ->
524
+
525
+ // const demoWorkflow: WorkflowType = {
526
+ // id: 'workflow-1',
527
+ // name: 'Urgent Chat Auto-Responder',
528
+ // trigger: Triggers.MESSAGE_CREATED,
529
+ // trigger_metadata: {
530
+ // org_phones: ['phone-1'],
531
+ // allow_internal_messages: false,
532
+ // first_action_id: 'action-validate',
533
+ // },
534
+ // actions: [
535
+ // {
536
+ // id: 'action-validate',
537
+ // action_metadata: {
538
+ // type: 'validate_action',
539
+ // metadata: {
540
+ // operator: 'AND',
541
+ // conditions: [
542
+ // {
543
+ // id: 'cond-1',
544
+ // variable_name: 'message.text',
545
+ // variable_type: 'string',
546
+ // condition: 'CONTAINS',
547
+ // value: 'urgent',
548
+ // },
549
+ // {
550
+ // id: 'cond-2',
551
+ // variable_name: 'chat.assigned',
552
+ // variable_type: 'boolean',
553
+ // condition: 'IS',
554
+ // value: false,
555
+ // },
556
+ // ],
557
+ // },
558
+ // },
559
+ // next: 'action-add-label',
560
+ // },
561
+ // {
562
+ // id: 'action-add-label',
563
+ // action_metadata: {
564
+ // type: 'add_chat_label',
565
+ // metadata: {
566
+ // labels: ['urgent'],
567
+ // },
568
+ // },
569
+ // next: 'action-assign-chat',
570
+ // },
571
+ // {
572
+ // id: 'action-assign-chat',
573
+ // action_metadata: {
574
+ // type: 'assign_chat',
575
+ // metadata: {
576
+ // assignee: {
577
+ // round_robin: true,
578
+ // emails: ['agent1@example.com', 'agent2@example.com'],
579
+ // assignee_check_for: 'all',
580
+ // },
581
+ // },
582
+ // },
583
+ // next: 'action-delay',
584
+ // },
585
+ // {
586
+ // id: 'action-delay',
587
+ // action_metadata: {
588
+ // type: 'delay',
589
+ // metadata: {
590
+ // delay: '5 minutes',
591
+ // },
592
+ // },
593
+ // next: 'action-send-message',
594
+ // },
595
+ // {
596
+ // id: 'action-send-message',
597
+ // action_metadata: {
598
+ // type: 'send_message_to_chat',
599
+ // metadata: {
600
+ // message: 'We’re on it!',
601
+ // chat_id: 'trigger_chat',
602
+ // },
603
+ // },
604
+ // next: 'action-split',
605
+ // },
606
+ // {
607
+ // id: 'action-split',
608
+ // action_metadata: {
609
+ // type: 'split_path',
610
+ // metadata: {
611
+ // paths: [
612
+ // {
613
+ // id: 'path-flagged',
614
+ // condition_action_id: 'action-condition-flagged',
615
+ // },
616
+ // {
617
+ // id: 'path-not-flagged',
618
+ // condition_action_id: 'action-condition-not-flagged',
619
+ // },
620
+ // ],
621
+ // },
622
+ // },
623
+ // {
624
+ // id: 'action-condition-flagged',
625
+ // action_metadata: {
626
+ // type: 'validate_action',
627
+ // metadata: {
628
+ // operator: 'AND',
629
+ // conditions: [
630
+ // {
631
+ // id: 'cond-flagged',
632
+ // variable_name: 'chat.has_flagged_messages',
633
+ // variable_type: 'boolean',
634
+ // condition: 'IS',
635
+ // value: true,
636
+ // },
637
+ // ],
638
+ // },
639
+ // },
640
+ // next: 'action-create-ticket',
641
+ // },
642
+ // {
643
+ // id: 'action-condition-not-flagged',
644
+ // action_metadata: {
645
+ // type: 'validate_action',
646
+ // metadata: {
647
+ // operator: 'AND',
648
+ // conditions: [
649
+ // {
650
+ // id: 'cond-unflagged',
651
+ // variable_name: 'chat.has_flagged_messages',
652
+ // variable_type: 'boolean',
653
+ // condition: 'IS',
654
+ // value: false,
655
+ // },
656
+ // ],
657
+ // },
658
+ // },
659
+ // next: 'action-send-slack',
660
+ // },
661
+ // {
662
+ // id: 'action-create-ticket',
663
+ // action_metadata: {
664
+ // type: 'create_ticket',
665
+ // metadata: {
666
+ // subject: 'Urgent Chat Follow-up',
667
+ // assignee: {
668
+ // email: 'manager@example.com',
669
+ // },
670
+ // priority: '4',
671
+ // status: 'open',
672
+ // labels: ['urgent', 'auto-created'],
673
+ // due_date: '30 minutes',
674
+ // },
675
+ // },
676
+ // next: '', // End
677
+ // },
678
+ // {
679
+ // id: 'action-send-slack',
680
+ // action_metadata: {
681
+ // type: 'send_slack_notification',
682
+ // metadata: {
683
+ // slack_payload: JSON.stringify({
684
+ // text: 'An urgent chat was received, no flagged messages.',
685
+ // }),
686
+ // url: 'https://hooks.slack.com/services/XXX/YYY/ZZZ',
687
+ // },
688
+ // },
689
+ // next: '', // End
690
+ // },
691
+ // ],
692
+ // };