ab-ecosystem-cpass 1.0.0 → 1.0.6
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/README.md +121 -21
- package/dist/client.d.ts +38 -0
- package/dist/client.js +49 -5
- package/dist/client.js.map +1 -1
- package/dist/http.d.ts +15 -0
- package/dist/http.js +21 -1
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.js +24 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/bytes.d.ts +38 -0
- package/dist/internal/bytes.js +84 -0
- package/dist/internal/bytes.js.map +1 -0
- package/dist/internal/device.d.ts +24 -0
- package/dist/internal/device.js +91 -0
- package/dist/internal/device.js.map +1 -0
- package/dist/internal/md5.d.ts +4 -0
- package/dist/internal/md5.js +109 -0
- package/dist/internal/md5.js.map +1 -0
- package/dist/internal/receiver-file.d.ts +106 -0
- package/dist/internal/receiver-file.js +128 -0
- package/dist/internal/receiver-file.js.map +1 -0
- package/dist/realtime/client.d.ts +85 -0
- package/dist/realtime/client.js +126 -0
- package/dist/realtime/client.js.map +1 -0
- package/dist/realtime/events.d.ts +147 -0
- package/dist/realtime/events.js +3 -0
- package/dist/realtime/events.js.map +1 -0
- package/dist/realtime/inbox.d.ts +173 -0
- package/dist/realtime/inbox.js +263 -0
- package/dist/realtime/inbox.js.map +1 -0
- package/dist/realtime/index.d.ts +16 -0
- package/dist/realtime/index.js +37 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/resources/audience/contacts.d.ts +19 -3
- package/dist/resources/audience/contacts.js +19 -3
- package/dist/resources/audience/contacts.js.map +1 -1
- package/dist/resources/audience/inbox-media.d.ts +92 -0
- package/dist/resources/audience/inbox-media.js +127 -0
- package/dist/resources/audience/inbox-media.js.map +1 -0
- package/dist/resources/audience/notifications.d.ts +171 -0
- package/dist/resources/audience/notifications.js +215 -0
- package/dist/resources/audience/notifications.js.map +1 -0
- package/dist/resources/audience/scheduled-messages.d.ts +234 -0
- package/dist/resources/audience/scheduled-messages.js +259 -0
- package/dist/resources/audience/scheduled-messages.js.map +1 -0
- package/dist/resources/campaign-audience.d.ts +132 -0
- package/dist/resources/campaign-audience.js +224 -0
- package/dist/resources/campaign-audience.js.map +1 -0
- package/dist/resources/campaign-report-exports.d.ts +14 -0
- package/dist/resources/campaign-report-exports.js +28 -0
- package/dist/resources/campaign-report-exports.js.map +1 -0
- package/dist/resources/campaign-reports.d.ts +15 -0
- package/dist/resources/campaign-reports.js +25 -0
- package/dist/resources/campaign-reports.js.map +1 -0
- package/dist/resources/campaigns.d.ts +239 -0
- package/dist/resources/campaigns.js +300 -0
- package/dist/resources/campaigns.js.map +1 -0
- package/dist/types/audience.d.ts +93 -1
- package/dist/types/campaign.d.ts +229 -0
- package/dist/types/campaign.js +3 -0
- package/dist/types/campaign.js.map +1 -0
- package/dist/types/contact-filter.d.ts +3 -2
- package/dist/types/contact-filter.js +3 -2
- package/dist/types/contact-filter.js.map +1 -1
- package/dist/types/inbox.d.ts +391 -0
- package/dist/types/inbox.js +16 -0
- package/dist/types/inbox.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/scheduled-message.d.ts +221 -0
- package/dist/types/scheduled-message.js +16 -0
- package/dist/types/scheduled-message.js.map +1 -0
- package/docs/audience/contacts.md +34 -4
- package/docs/audience/notifications.md +263 -0
- package/docs/audience/scheduled-messages.md +557 -0
- package/docs/campaign/campaigns.md +489 -0
- package/docs/contact-filter.md +2 -1
- package/docs/inbox/chats.md +356 -0
- package/docs/inbox/connection.md +171 -0
- package/docs/inbox/media.md +202 -0
- package/docs/inbox/messages.md +338 -0
- package/docs/inbox/referrals.md +72 -0
- package/docs/inbox/sessions.md +74 -0
- package/package.json +28 -2
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import type { JsonObject } from './common';
|
|
2
|
+
import type { Contact, ContactChatMetadata, ContactName, ContactProfile, ContactTag } from './audience';
|
|
3
|
+
import type { ContactFilterEntry } from './contact-filter';
|
|
4
|
+
/**
|
|
5
|
+
* Delivery state, shared by every channel kind. Providers report more than these
|
|
6
|
+
* -- email bounces, carrier rejections -- and each maps onto one of the five, so
|
|
7
|
+
* the inbox, the campaign reports and the billing logs all read one field. The
|
|
8
|
+
* provider's own wording survives in `error`.
|
|
9
|
+
*/
|
|
10
|
+
export type MessageStatus = 'received' | 'sent' | 'delivered' | 'read' | 'failed';
|
|
11
|
+
/** `received` is the only inbound state, so direction is derived, not stored. */
|
|
12
|
+
export type MessageDirection = 'inbound' | 'outbound';
|
|
13
|
+
/** Who put the message on the wire, derived from the `sent_by_*` flags. */
|
|
14
|
+
export type MessageSource = 'contact' | 'agent' | 'bot' | 'campaign' | 'api' | 'business_app';
|
|
15
|
+
/**
|
|
16
|
+
* The message body, as the channel describes it.
|
|
17
|
+
*
|
|
18
|
+
* Open by design -- a WhatsApp interactive reply, an email part tree and an RCS
|
|
19
|
+
* card share no structure worth forcing into one schema. Only `type` is promised,
|
|
20
|
+
* and by convention the body for that kind sits under a key of the same name:
|
|
21
|
+
* `{ type: 'image', image: { id, link } }`.
|
|
22
|
+
*
|
|
23
|
+
* Narrow it yourself where you know the channel: `Message<MyWhatsAppContent>`.
|
|
24
|
+
*/
|
|
25
|
+
export interface MessageContent extends JsonObject {
|
|
26
|
+
type: string;
|
|
27
|
+
}
|
|
28
|
+
/** Per-status unix seconds. `0` means the message never reached that state. */
|
|
29
|
+
export interface MessageReceipts {
|
|
30
|
+
sent: number;
|
|
31
|
+
read: number;
|
|
32
|
+
failed: number;
|
|
33
|
+
replied: number;
|
|
34
|
+
received: number;
|
|
35
|
+
delivered: number;
|
|
36
|
+
}
|
|
37
|
+
export interface Message<C extends MessageContent = MessageContent, X = JsonObject> {
|
|
38
|
+
id: string;
|
|
39
|
+
contact: string;
|
|
40
|
+
/** Channel it travelled over. Lives in the channels service, so an id only. */
|
|
41
|
+
channel: string;
|
|
42
|
+
content: C;
|
|
43
|
+
/** Provider context: the replied-to id, forwarding flags, the CTWA referral. */
|
|
44
|
+
context: X;
|
|
45
|
+
/** The contact's identity on this channel -- phone number, handle, address. */
|
|
46
|
+
identifier: string;
|
|
47
|
+
/**
|
|
48
|
+
* The provider's id (a `wamid` for WhatsApp), unique across the account. An
|
|
49
|
+
* outbound message carries its queue id here until the provider answers.
|
|
50
|
+
*/
|
|
51
|
+
message_id: string;
|
|
52
|
+
status: MessageStatus;
|
|
53
|
+
/** Unix seconds as the provider reported it. Thread order is by this. */
|
|
54
|
+
timestamp: number;
|
|
55
|
+
direction: MessageDirection;
|
|
56
|
+
source: MessageSource;
|
|
57
|
+
sent_by_api: boolean;
|
|
58
|
+
sent_by_biz_app: boolean;
|
|
59
|
+
sent_by_campaign: boolean;
|
|
60
|
+
sent_by_bot: boolean;
|
|
61
|
+
agent: string | null;
|
|
62
|
+
receipts: MessageReceipts;
|
|
63
|
+
meta: {
|
|
64
|
+
bookmarked: boolean;
|
|
65
|
+
hide: boolean;
|
|
66
|
+
};
|
|
67
|
+
campaign: {
|
|
68
|
+
id: string | null;
|
|
69
|
+
cmid: number;
|
|
70
|
+
};
|
|
71
|
+
bot: {
|
|
72
|
+
id: string | null;
|
|
73
|
+
node: string;
|
|
74
|
+
};
|
|
75
|
+
error: string;
|
|
76
|
+
createdAt: string;
|
|
77
|
+
updatedAt: string;
|
|
78
|
+
}
|
|
79
|
+
/** Media kinds whose bytes the platform fetches from the provider and re-hosts. */
|
|
80
|
+
export type MediaContentType = 'image' | 'video' | 'audio' | 'document' | 'voice' | 'sticker';
|
|
81
|
+
export interface ListMessagesPayload {
|
|
82
|
+
/** Contact whose thread to read. */
|
|
83
|
+
id: string;
|
|
84
|
+
/** Default 20, max 100. */
|
|
85
|
+
limit?: number;
|
|
86
|
+
/** `id` of the oldest message already held; older ones follow. */
|
|
87
|
+
last_message_id?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface FetchMessagePayload {
|
|
90
|
+
/** The provider id, not the document id. */
|
|
91
|
+
message_id: string;
|
|
92
|
+
}
|
|
93
|
+
export interface SendMessagePayload {
|
|
94
|
+
channel: string;
|
|
95
|
+
contact: {
|
|
96
|
+
id: string;
|
|
97
|
+
identifier: string;
|
|
98
|
+
};
|
|
99
|
+
content: MessageContent;
|
|
100
|
+
context?: JsonObject;
|
|
101
|
+
/** Attribute to another member. Needs `live_chat.send.AS_OTHER`. */
|
|
102
|
+
agent?: string;
|
|
103
|
+
}
|
|
104
|
+
export interface DeleteMessagePayload {
|
|
105
|
+
/** Contact whose thread the message belongs to. */
|
|
106
|
+
id: string;
|
|
107
|
+
/** Either the document id or the provider id. */
|
|
108
|
+
message_id: string;
|
|
109
|
+
}
|
|
110
|
+
export interface RetryDownloadPayload {
|
|
111
|
+
/** The document id -- a retry targets a row the platform already stored. */
|
|
112
|
+
message_id: string;
|
|
113
|
+
}
|
|
114
|
+
export interface MessageDeleteResult {
|
|
115
|
+
success: boolean;
|
|
116
|
+
id: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The inbox's view of a contact: the chat-relevant projection, not the whole
|
|
120
|
+
* contact. Every chat event answers with this, so one shape updates the list row
|
|
121
|
+
* and the conversation header together.
|
|
122
|
+
*/
|
|
123
|
+
export interface Chat {
|
|
124
|
+
id: string;
|
|
125
|
+
name: ContactName;
|
|
126
|
+
profile: Record<string, ContactProfile>;
|
|
127
|
+
chat_metadata: ContactChatMetadata;
|
|
128
|
+
/** Unix seconds of the last inbound message. The list is ordered by this. */
|
|
129
|
+
last_seen: number;
|
|
130
|
+
/** Flow state. Open-ended on the stored schema, carried through as-is. */
|
|
131
|
+
bot: JsonObject;
|
|
132
|
+
/** Last-message preview, so a list of chats needs no thread reads. */
|
|
133
|
+
last_interaction_props: JsonObject;
|
|
134
|
+
agent: string | null;
|
|
135
|
+
team: string | null;
|
|
136
|
+
tags: ContactTag[];
|
|
137
|
+
/** Present on list rows; the chat header renders them. */
|
|
138
|
+
custom_field_hash?: JsonObject;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The inbox's own list filter. Every key is independent and omitting one means
|
|
142
|
+
* "don't care", so an empty filter is every live chat.
|
|
143
|
+
*/
|
|
144
|
+
export interface ChatListFilter {
|
|
145
|
+
/** `all` every chat, `me` the caller's own, `none` the unassigned queue. */
|
|
146
|
+
assignment?: 'all' | 'me' | 'none';
|
|
147
|
+
/** `unread` has unseen messages or a by-hand flag; `replied` is caught up. */
|
|
148
|
+
unread?: 'unread' | 'replied';
|
|
149
|
+
new?: 'new' | 'old';
|
|
150
|
+
/** `closed` covers closed and marked-done alike; `open` is neither. */
|
|
151
|
+
closed?: 'closed' | 'open';
|
|
152
|
+
archived?: 'archived' | 'unarchived';
|
|
153
|
+
/** `active_no_bot` is running with no flow attached. */
|
|
154
|
+
automation?: 'active' | 'paused' | 'active_no_bot';
|
|
155
|
+
block?: 'ic' | 'og' | 'api' | 'bot' | 'unblocked';
|
|
156
|
+
/** `active` means seen inside the last 24 hours -- the provider reply window. */
|
|
157
|
+
session?: 'active' | 'expired';
|
|
158
|
+
}
|
|
159
|
+
export interface ListChatsPayload {
|
|
160
|
+
filter?: ChatListFilter;
|
|
161
|
+
/** Conditions in the same DSL the contact list and segments use. */
|
|
162
|
+
conditions?: ContactFilterEntry[];
|
|
163
|
+
search?: string;
|
|
164
|
+
/** `last_seen` of the oldest row already held; omit for the first page. */
|
|
165
|
+
nextPage?: number;
|
|
166
|
+
/** Default 20, max 100. */
|
|
167
|
+
limit?: number;
|
|
168
|
+
department?: string;
|
|
169
|
+
team_member?: string;
|
|
170
|
+
}
|
|
171
|
+
export interface ChatList {
|
|
172
|
+
contacts: Chat[];
|
|
173
|
+
/**
|
|
174
|
+
* The filter after permission narrowing. A team member without the unassigned
|
|
175
|
+
* permission asking for `all` gets `me` back, so the UI can show what it got.
|
|
176
|
+
*/
|
|
177
|
+
filter: ChatListFilter;
|
|
178
|
+
/** Send as `nextPage` for the following page; `null` at the end. */
|
|
179
|
+
nextPage: number | null;
|
|
180
|
+
}
|
|
181
|
+
/** Every action `chat.action` accepts. */
|
|
182
|
+
export type ChatActionName = 'delete' | 'transfer' | 'bulk_transfer' | 'archive' | 'unarchive' | 'block' | 'mark_as_read' | 'mark_as_unread' | 'pause_automation' | 'resume_automation' | 'close' | 'done' | 'pause_timer' | 'update_tags';
|
|
183
|
+
/** The blocked flags; send only the ones to change. */
|
|
184
|
+
export interface ChatBlockUpdate {
|
|
185
|
+
incoming?: boolean;
|
|
186
|
+
outgoing?: boolean;
|
|
187
|
+
bot?: boolean;
|
|
188
|
+
api?: boolean;
|
|
189
|
+
}
|
|
190
|
+
/** `chat` names the target. `id` is accepted as an alias on every action. */
|
|
191
|
+
interface ChatTarget {
|
|
192
|
+
chat?: string;
|
|
193
|
+
id?: string;
|
|
194
|
+
}
|
|
195
|
+
export type ChatActionPayload = (ChatTarget & {
|
|
196
|
+
action: 'delete';
|
|
197
|
+
}) | (ChatTarget & {
|
|
198
|
+
action: 'transfer';
|
|
199
|
+
member: string;
|
|
200
|
+
}) | (ChatTarget & {
|
|
201
|
+
action: 'archive';
|
|
202
|
+
}) | (ChatTarget & {
|
|
203
|
+
action: 'unarchive';
|
|
204
|
+
}) | (ChatTarget & {
|
|
205
|
+
action: 'block';
|
|
206
|
+
update: ChatBlockUpdate;
|
|
207
|
+
}) | (ChatTarget & {
|
|
208
|
+
action: 'mark_as_read';
|
|
209
|
+
}) | (ChatTarget & {
|
|
210
|
+
action: 'mark_as_unread';
|
|
211
|
+
}) | (ChatTarget & {
|
|
212
|
+
action: 'pause_automation';
|
|
213
|
+
}) | (ChatTarget & {
|
|
214
|
+
action: 'resume_automation';
|
|
215
|
+
}) | (ChatTarget & {
|
|
216
|
+
action: 'close';
|
|
217
|
+
}) | (ChatTarget & {
|
|
218
|
+
action: 'done';
|
|
219
|
+
isEnded?: boolean;
|
|
220
|
+
}) | (ChatTarget & {
|
|
221
|
+
action: 'pause_timer';
|
|
222
|
+
duration: number;
|
|
223
|
+
}) | (ChatTarget & {
|
|
224
|
+
action: 'update_tags';
|
|
225
|
+
tags: string[];
|
|
226
|
+
}) | {
|
|
227
|
+
action: 'bulk_transfer';
|
|
228
|
+
/** Member to take chats from, or `UNASSIGN` for the unassigned queue. */
|
|
229
|
+
source: string | 'UNASSIGN';
|
|
230
|
+
/** Member or team to hand them to, or `UNASSIGN` to clear it. */
|
|
231
|
+
target: string | 'UNASSIGN';
|
|
232
|
+
target_type?: 'member' | 'department';
|
|
233
|
+
};
|
|
234
|
+
/** The envelope every chat action answers and broadcasts with. */
|
|
235
|
+
export interface ChatActionResult {
|
|
236
|
+
action: ChatActionName;
|
|
237
|
+
id: string;
|
|
238
|
+
/** `null` for `delete`: the row has left the list, so there is nothing to draw. */
|
|
239
|
+
chat?: Chat | null;
|
|
240
|
+
}
|
|
241
|
+
export interface BulkTransferResult {
|
|
242
|
+
action: 'bulk_transfer';
|
|
243
|
+
count: number;
|
|
244
|
+
chats: ChatActionResult[];
|
|
245
|
+
}
|
|
246
|
+
export interface UpdateChatPayload {
|
|
247
|
+
id: string;
|
|
248
|
+
action: 'done' | 'archive';
|
|
249
|
+
}
|
|
250
|
+
/** `contact.update` answers with the metadata alone. */
|
|
251
|
+
export interface UpdateChatResult {
|
|
252
|
+
id: string;
|
|
253
|
+
action: 'done' | 'archive';
|
|
254
|
+
chat_metadata?: ContactChatMetadata;
|
|
255
|
+
}
|
|
256
|
+
export interface AssignBotPayload {
|
|
257
|
+
chat: string;
|
|
258
|
+
channel: string;
|
|
259
|
+
bot: string;
|
|
260
|
+
node?: string;
|
|
261
|
+
/**
|
|
262
|
+
* `assign` attaches the flow and resumes automation. `trigger` hands the chat
|
|
263
|
+
* to the bot server, which decides where in the flow it belongs.
|
|
264
|
+
*/
|
|
265
|
+
action?: 'assign' | 'trigger';
|
|
266
|
+
}
|
|
267
|
+
/** A click-to-WhatsApp referral: the ad payload behind a conversation. */
|
|
268
|
+
/**
|
|
269
|
+
* A delivery state moved on a message already on screen.
|
|
270
|
+
*
|
|
271
|
+
* Its own push rather than another `message.received`, because a client updates
|
|
272
|
+
* the ticks in place and does not want to re-render the bubble. The row is the
|
|
273
|
+
* stored document as the sender service wrote it, so `_id` is a string and
|
|
274
|
+
* `receipts` carries the unix second each state was reached.
|
|
275
|
+
*/
|
|
276
|
+
export interface MessageStatusUpdate extends JsonObject {
|
|
277
|
+
/** The provider's message id -- what an echoed bubble's queue id is replaced by. */
|
|
278
|
+
message_id: string;
|
|
279
|
+
status: MessageStatus;
|
|
280
|
+
/** Owner the row belongs to. */
|
|
281
|
+
user: string;
|
|
282
|
+
contact?: string;
|
|
283
|
+
receipts?: Partial<MessageReceipts>;
|
|
284
|
+
/** Provider text when `status` is `failed`. */
|
|
285
|
+
error?: string;
|
|
286
|
+
}
|
|
287
|
+
/** Media kinds a chat message can carry. */
|
|
288
|
+
export type MediaKind = 'image' | 'video' | 'audio' | 'voice' | 'sticker' | 'document';
|
|
289
|
+
/**
|
|
290
|
+
* Per-kind ceilings, in bytes. WhatsApp's limits, enforced when the upload is
|
|
291
|
+
* requested rather than when the message is sent.
|
|
292
|
+
*/
|
|
293
|
+
export declare const MEDIA_LIMITS: Record<MediaKind, number>;
|
|
294
|
+
/** What `POST /v1/audience/inbox/media/upload-url` takes. Metadata, not bytes. */
|
|
295
|
+
export interface CreateMediaUploadPayload {
|
|
296
|
+
kind: MediaKind;
|
|
297
|
+
/** Only its extension and display name survive; the stored key is a uuid. */
|
|
298
|
+
filename: string;
|
|
299
|
+
content_type: string;
|
|
300
|
+
/** Exact byte length. Signed into the ticket, so the upload must match. */
|
|
301
|
+
size: number;
|
|
302
|
+
}
|
|
303
|
+
/** A presigned upload. `PUT` the bytes to `upload_url` with exactly `headers`. */
|
|
304
|
+
export interface MediaUpload {
|
|
305
|
+
upload_url: string;
|
|
306
|
+
/** Every header the signature covers. Anything else fails the upload. */
|
|
307
|
+
headers: Record<string, string>;
|
|
308
|
+
/**
|
|
309
|
+
* Where the object is readable once the upload succeeds. Permanent -- only
|
|
310
|
+
* `upload_url` expires, and only if unused.
|
|
311
|
+
*/
|
|
312
|
+
link: string;
|
|
313
|
+
key: string;
|
|
314
|
+
kind: MediaKind;
|
|
315
|
+
filename: string;
|
|
316
|
+
content_type: string;
|
|
317
|
+
size: number;
|
|
318
|
+
/** Unix seconds after which `upload_url` stops working. */
|
|
319
|
+
expires_at: number;
|
|
320
|
+
expires_in: number;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* The bytes `sendMedia` can take.
|
|
324
|
+
*
|
|
325
|
+
* A browser `File` or `Blob`, or a description of bytes for Node, where neither
|
|
326
|
+
* exists. Structurally the same thing `crm.inboxMedia.upload()` accepts, declared
|
|
327
|
+
* here so the realtime entrypoint does not have to import the REST one.
|
|
328
|
+
*/
|
|
329
|
+
export type MediaFile = Blob | {
|
|
330
|
+
body: unknown;
|
|
331
|
+
filename: string;
|
|
332
|
+
contentType: string;
|
|
333
|
+
size: number;
|
|
334
|
+
};
|
|
335
|
+
/**
|
|
336
|
+
* Uploads a file and answers with its permanent link.
|
|
337
|
+
*
|
|
338
|
+
* Satisfied by `crm.inboxMedia.upload`. Declared as a function so the socket
|
|
339
|
+
* client takes a capability rather than a dependency on the REST client: an app
|
|
340
|
+
* that only ever sends a `link` pulls none of it in.
|
|
341
|
+
*/
|
|
342
|
+
export type MediaUploader = (file: MediaFile, options: {
|
|
343
|
+
kind: MediaKind;
|
|
344
|
+
filename?: string;
|
|
345
|
+
}) => Promise<string>;
|
|
346
|
+
/**
|
|
347
|
+
* What `sendMedia` takes: a chat, a kind, and either a link or a file.
|
|
348
|
+
*
|
|
349
|
+
* `link` and `file` are alternatives -- a link is sent as it is, a file is
|
|
350
|
+
* uploaded first and needs the `Inbox` to have been given an uploader.
|
|
351
|
+
*/
|
|
352
|
+
export interface SendMediaPayload {
|
|
353
|
+
channel: string;
|
|
354
|
+
contact: {
|
|
355
|
+
id: string;
|
|
356
|
+
identifier: string;
|
|
357
|
+
};
|
|
358
|
+
kind: MediaKind;
|
|
359
|
+
/** Already uploaded. Takes precedence over `file`. */
|
|
360
|
+
link?: string;
|
|
361
|
+
/** Uploaded before sending. Requires `uploadMedia` on the Inbox. */
|
|
362
|
+
file?: MediaFile;
|
|
363
|
+
/** Shown under the media. Ignored for a sticker, which takes none. */
|
|
364
|
+
caption?: string;
|
|
365
|
+
/** What the recipient sees for a document. Also names the uploaded object. */
|
|
366
|
+
filename?: string;
|
|
367
|
+
context?: JsonObject;
|
|
368
|
+
/** Attribute to another member. Needs `live_chat.send.AS_OTHER`. */
|
|
369
|
+
agent?: string;
|
|
370
|
+
}
|
|
371
|
+
export interface CtwaReferral {
|
|
372
|
+
id: string;
|
|
373
|
+
contact: string;
|
|
374
|
+
channel: string | null;
|
|
375
|
+
/** The provider's referral object. `payload.source_id` is the ad id. */
|
|
376
|
+
payload: JsonObject;
|
|
377
|
+
createdAt: string;
|
|
378
|
+
updatedAt: string;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* When a contact was last seen on one channel. Providers only allow unprompted
|
|
382
|
+
* replies inside 24 hours of the last inbound message, and a contact reachable on
|
|
383
|
+
* several channels has one such window per channel.
|
|
384
|
+
*/
|
|
385
|
+
export interface ChatSession {
|
|
386
|
+
id: string;
|
|
387
|
+
channel: string;
|
|
388
|
+
last_seen: number;
|
|
389
|
+
}
|
|
390
|
+
/** Re-exported so a consumer importing `Chat` need not also reach for `Contact`. */
|
|
391
|
+
export type { Contact };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MEDIA_LIMITS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Per-kind ceilings, in bytes. WhatsApp's limits, enforced when the upload is
|
|
6
|
+
* requested rather than when the message is sent.
|
|
7
|
+
*/
|
|
8
|
+
exports.MEDIA_LIMITS = {
|
|
9
|
+
image: 5 * 1024 * 1024,
|
|
10
|
+
video: 16 * 1024 * 1024,
|
|
11
|
+
audio: 16 * 1024 * 1024,
|
|
12
|
+
voice: 16 * 1024 * 1024,
|
|
13
|
+
sticker: 100 * 1024,
|
|
14
|
+
document: 100 * 1024 * 1024,
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=inbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/types/inbox.ts"],"names":[],"mappings":";;;AAoTA;;;GAGG;AACU,QAAA,YAAY,GAA8B;IACrD,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;IACtB,KAAK,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;IACvB,KAAK,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;IACvB,KAAK,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;IACvB,OAAO,EAAE,GAAG,GAAG,IAAI;IACnB,QAAQ,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI;CAC5B,CAAC"}
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/index.js
CHANGED
|
@@ -18,4 +18,9 @@ __exportStar(require("./common"), exports);
|
|
|
18
18
|
__exportStar(require("./contact-filter"), exports);
|
|
19
19
|
__exportStar(require("./audience"), exports);
|
|
20
20
|
__exportStar(require("./channels"), exports);
|
|
21
|
+
__exportStar(require("./inbox"), exports);
|
|
22
|
+
// After './inbox': a scheduled message's body is a `MessageContent`.
|
|
23
|
+
__exportStar(require("./scheduled-message"), exports);
|
|
24
|
+
// After './contact-filter': a campaign's audience may be a list of its entries.
|
|
25
|
+
__exportStar(require("./campaign"), exports);
|
|
21
26
|
//# sourceMappingURL=index.js.map
|
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,mDAAiC;AACjC,6CAA2B;AAC3B,6CAA2B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,mDAAiC;AACjC,6CAA2B;AAC3B,6CAA2B;AAC3B,0CAAwB;AACxB,qEAAqE;AACrE,sDAAoC;AACpC,gFAAgF;AAChF,6CAA2B"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduled messages: a send with a time, and optionally a condition checked
|
|
3
|
+
* immediately before it goes out.
|
|
4
|
+
*
|
|
5
|
+
* The condition is what makes a drip safe to set and forget. A sequence of five
|
|
6
|
+
* messages over two weeks is five rows; each one re-reads the contact a moment
|
|
7
|
+
* before sending and stands down if the contact no longer matches. So "stop
|
|
8
|
+
* messaging a lead once they convert" is a field on the contact changing, not a
|
|
9
|
+
* job anybody has to remember to cancel.
|
|
10
|
+
*
|
|
11
|
+
* Declared here rather than imported from `@crm/contracts` so the published
|
|
12
|
+
* package has no private dependencies; kept in step with the zod schemas.
|
|
13
|
+
*/
|
|
14
|
+
import type { ContactFilter } from './contact-filter';
|
|
15
|
+
import type { IsoDate, JsonObject, ListQuery, ObjectId } from './common';
|
|
16
|
+
import type { MessageContent } from './inbox';
|
|
17
|
+
/** Units a schedule's spacing is expressed in. */
|
|
18
|
+
export type ScheduleUnit = 'minutes' | 'hours' | 'days' | 'weeks' | 'months';
|
|
19
|
+
/**
|
|
20
|
+
* Where one occurrence ended up.
|
|
21
|
+
*
|
|
22
|
+
* | Status | Meaning |
|
|
23
|
+
* | --- | --- |
|
|
24
|
+
* | `pending` | Waiting for its moment. The only status that can be rescheduled. |
|
|
25
|
+
* | `processing` | Claimed by the scheduler, mid-send. |
|
|
26
|
+
* | `sent` | Handed to the channel. Delivery is then a message status, not this. |
|
|
27
|
+
* | `skipped` | Its condition did not match. `result` says what was expected and what was found. |
|
|
28
|
+
* | `cancelled` | Stood down -- by a caller, or by an earlier occurrence failing its condition under `cancel_series`. |
|
|
29
|
+
* | `failed` | Could not be sent: the contact is gone, trashed, blocked for outbound, or has no channel identity. `result.reason` says which. |
|
|
30
|
+
*/
|
|
31
|
+
export type ScheduledMessageStatus = 'pending' | 'processing' | 'sent' | 'skipped' | 'failed' | 'cancelled';
|
|
32
|
+
/**
|
|
33
|
+
* What a failed condition does to the rest of the series.
|
|
34
|
+
*
|
|
35
|
+
* - `skip` -- this occurrence only. Later ones still run and are checked again,
|
|
36
|
+
* so a contact who leaves and re-enters the condition resumes receiving.
|
|
37
|
+
* - `cancel_series` -- this occurrence and every later one. The default for a
|
|
38
|
+
* series, because a converted lead should drop out of the sequence for good
|
|
39
|
+
* rather than re-enter it if someone edits their stage back.
|
|
40
|
+
*/
|
|
41
|
+
export type OnConditionFail = 'skip' | 'cancel_series';
|
|
42
|
+
/** A step's distance from the series start. Cumulative, never relative to the previous step. */
|
|
43
|
+
export interface ScheduleOffset {
|
|
44
|
+
value: number;
|
|
45
|
+
unit: ScheduleUnit;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* One message in a sequence, with its own copy.
|
|
49
|
+
*
|
|
50
|
+
* `after` is measured from the series' `starts_at`, so editing one step's delay
|
|
51
|
+
* does not shift the steps behind it.
|
|
52
|
+
*/
|
|
53
|
+
export interface ScheduledMessageStep {
|
|
54
|
+
after: ScheduleOffset;
|
|
55
|
+
content: MessageContent;
|
|
56
|
+
context?: JsonObject;
|
|
57
|
+
/**
|
|
58
|
+
* Narrows this step beyond the series condition. Both must pass. Use it for a
|
|
59
|
+
* step that needs an extra guard -- a final discount offer only if the contact
|
|
60
|
+
* has not already bought -- and leave it out to inherit the series condition
|
|
61
|
+
* alone.
|
|
62
|
+
*/
|
|
63
|
+
conditions?: ContactFilter | null;
|
|
64
|
+
}
|
|
65
|
+
/** Expands into evenly spaced occurrences, all carrying the same message. */
|
|
66
|
+
export interface ScheduleRepeat {
|
|
67
|
+
/** Spacing between occurrences. Must be at least 1. */
|
|
68
|
+
every: number;
|
|
69
|
+
unit: ScheduleUnit;
|
|
70
|
+
/**
|
|
71
|
+
* Inclusive end. The last occurrence is the final one at or before this
|
|
72
|
+
* instant, so `starts_at` + `every: 3, unit: 'days'` + `until` two weeks out
|
|
73
|
+
* produces five sends, not four or six.
|
|
74
|
+
*/
|
|
75
|
+
until: IsoDate;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Why an occurrence did not send, or how it did.
|
|
79
|
+
*
|
|
80
|
+
* Only the first failing condition is named: listing every one of them would be
|
|
81
|
+
* noise when the first already explains the skip.
|
|
82
|
+
*/
|
|
83
|
+
export interface ScheduledMessageResult {
|
|
84
|
+
/**
|
|
85
|
+
* `queued` | `condition_not_met` | `series_cancelled_by_condition` |
|
|
86
|
+
* `cancelled_by_user` | `contact_missing` | `contact_trashed` |
|
|
87
|
+
* `outgoing_blocked` | `no_channel_identity`
|
|
88
|
+
*/
|
|
89
|
+
reason?: string;
|
|
90
|
+
/** For `condition_not_met`: which condition refused -- the series' or the step's. */
|
|
91
|
+
scope?: 'series' | 'step';
|
|
92
|
+
/** For `condition_not_met`: the first condition that failed, and what it wanted. */
|
|
93
|
+
field_id?: string;
|
|
94
|
+
condition?: string;
|
|
95
|
+
expected?: unknown;
|
|
96
|
+
/** For `series_cancelled_by_condition`: the occurrence whose condition failed. */
|
|
97
|
+
at_occurrence?: number;
|
|
98
|
+
/** Anything else the server recorded. */
|
|
99
|
+
error?: string;
|
|
100
|
+
}
|
|
101
|
+
export interface ScheduledMessage {
|
|
102
|
+
id: ObjectId;
|
|
103
|
+
/** The series this belongs to, or `null` for a one-off. */
|
|
104
|
+
series: ObjectId | null;
|
|
105
|
+
/** 1-based position in the series. `1` for a one-off. */
|
|
106
|
+
occurrence: number;
|
|
107
|
+
title: string;
|
|
108
|
+
contact: ObjectId;
|
|
109
|
+
/** Channel it will go out on. Lives in the channels service, so an id only. */
|
|
110
|
+
channel: ObjectId;
|
|
111
|
+
content: MessageContent;
|
|
112
|
+
context: JsonObject;
|
|
113
|
+
/** IANA zone the schedule was expressed in, e.g. `Asia/Kolkata`. */
|
|
114
|
+
timezone: string;
|
|
115
|
+
/** The resolved instant, always UTC. This is what the scheduler fires on. */
|
|
116
|
+
scheduled_at: IsoDate;
|
|
117
|
+
/** The same moment as wall-clock in `timezone`, with no offset -- what the user chose. */
|
|
118
|
+
scheduled_at_local: string;
|
|
119
|
+
/** The series condition. `null` means send unconditionally. */
|
|
120
|
+
conditions: ContactFilter | null;
|
|
121
|
+
/**
|
|
122
|
+
* This occurrence's own extra narrowing, from its step. Both this and
|
|
123
|
+
* `conditions` have to pass.
|
|
124
|
+
*/
|
|
125
|
+
step_conditions: ContactFilter | null;
|
|
126
|
+
on_condition_fail: OnConditionFail;
|
|
127
|
+
status: ScheduledMessageStatus;
|
|
128
|
+
result: ScheduledMessageResult | null;
|
|
129
|
+
/** When the scheduler claimed it. */
|
|
130
|
+
processed_at: IsoDate | null;
|
|
131
|
+
/** When it reached a terminal status. */
|
|
132
|
+
completed_at: IsoDate | null;
|
|
133
|
+
createdAt: IsoDate;
|
|
134
|
+
updatedAt: IsoDate;
|
|
135
|
+
}
|
|
136
|
+
/** A series and the occurrences it expanded into. */
|
|
137
|
+
export interface ScheduledMessageSeries {
|
|
138
|
+
series: ObjectId;
|
|
139
|
+
title: string;
|
|
140
|
+
contact: ObjectId;
|
|
141
|
+
channel: ObjectId;
|
|
142
|
+
timezone: string;
|
|
143
|
+
conditions: ContactFilter | null;
|
|
144
|
+
on_condition_fail: OnConditionFail;
|
|
145
|
+
/** In send order. One row per message, each independently cancellable. */
|
|
146
|
+
occurrences: ScheduledMessage[];
|
|
147
|
+
}
|
|
148
|
+
/** What every create shares. */
|
|
149
|
+
interface ScheduledMessageBase {
|
|
150
|
+
/** Shown in the schedule list. Defaults to `'Untitled'`. */
|
|
151
|
+
title?: string;
|
|
152
|
+
channel: ObjectId;
|
|
153
|
+
contact: {
|
|
154
|
+
id: ObjectId;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* IANA zone name -- `Asia/Kolkata`, `Europe/London`. Not an abbreviation and
|
|
158
|
+
* not an offset: `IST` and `+05:30` are rejected.
|
|
159
|
+
*
|
|
160
|
+
* Required. When the time below carries no offset it is read as wall-clock in
|
|
161
|
+
* this zone; when it does, the instant is already pinned and this is kept for
|
|
162
|
+
* display and for later edits.
|
|
163
|
+
*/
|
|
164
|
+
timezone: string;
|
|
165
|
+
/**
|
|
166
|
+
* Checked against the contact immediately before each send. Omit to always
|
|
167
|
+
* send.
|
|
168
|
+
*
|
|
169
|
+
* Same DSL as `contacts.list({ filter })` and a saved `Segment` -- see the
|
|
170
|
+
* contact filter page. A custom field is addressed by its **slug**.
|
|
171
|
+
*/
|
|
172
|
+
conditions?: ContactFilter | null;
|
|
173
|
+
/** Default `skip` for a one-off, `cancel_series` for a series. */
|
|
174
|
+
on_condition_fail?: OnConditionFail;
|
|
175
|
+
}
|
|
176
|
+
/** One message, one time. */
|
|
177
|
+
export interface CreateScheduledMessageInput extends ScheduledMessageBase {
|
|
178
|
+
/**
|
|
179
|
+
* `2026-10-15T10:00:00` is 10:00 in `timezone`. `2026-10-15T04:30:00Z` is that
|
|
180
|
+
* instant regardless of it. Must be in the future.
|
|
181
|
+
*/
|
|
182
|
+
scheduled_at: IsoDate;
|
|
183
|
+
content: MessageContent;
|
|
184
|
+
context?: JsonObject;
|
|
185
|
+
}
|
|
186
|
+
/** A sequence with different copy per step. */
|
|
187
|
+
export interface CreateScheduledSeriesInput extends ScheduledMessageBase {
|
|
188
|
+
/** The first step's moment; every `after` is measured from here. */
|
|
189
|
+
starts_at: IsoDate;
|
|
190
|
+
/** 1..365 steps, in any order -- they are sorted by `after` before expansion. */
|
|
191
|
+
steps: ScheduledMessageStep[];
|
|
192
|
+
}
|
|
193
|
+
/** A sequence repeating one message on a fixed cadence. */
|
|
194
|
+
export interface CreateRepeatingScheduleInput extends ScheduledMessageBase {
|
|
195
|
+
starts_at: IsoDate;
|
|
196
|
+
repeat: ScheduleRepeat;
|
|
197
|
+
content: MessageContent;
|
|
198
|
+
context?: JsonObject;
|
|
199
|
+
}
|
|
200
|
+
/** Moves a `pending` occurrence. Anything else is a 409. */
|
|
201
|
+
export interface RescheduleMessageInput {
|
|
202
|
+
scheduled_at: IsoDate;
|
|
203
|
+
/** Re-reads `scheduled_at` in a different zone. Defaults to the one already stored. */
|
|
204
|
+
timezone?: string;
|
|
205
|
+
title?: string;
|
|
206
|
+
}
|
|
207
|
+
export interface ListScheduledMessagesQuery extends ListQuery {
|
|
208
|
+
/** Everything queued for one contact. */
|
|
209
|
+
contact?: ObjectId;
|
|
210
|
+
/** One drip's occurrences. */
|
|
211
|
+
series?: ObjectId;
|
|
212
|
+
status?: ScheduledMessageStatus;
|
|
213
|
+
channel?: ObjectId;
|
|
214
|
+
}
|
|
215
|
+
/** What `cancelSeries` answers with. */
|
|
216
|
+
export interface CancelSeriesResult {
|
|
217
|
+
series: ObjectId;
|
|
218
|
+
/** How many `pending` occurrences were stood down. Already-sent ones are untouched. */
|
|
219
|
+
cancelled: number;
|
|
220
|
+
}
|
|
221
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Scheduled messages: a send with a time, and optionally a condition checked
|
|
4
|
+
* immediately before it goes out.
|
|
5
|
+
*
|
|
6
|
+
* The condition is what makes a drip safe to set and forget. A sequence of five
|
|
7
|
+
* messages over two weeks is five rows; each one re-reads the contact a moment
|
|
8
|
+
* before sending and stands down if the contact no longer matches. So "stop
|
|
9
|
+
* messaging a lead once they convert" is a field on the contact changing, not a
|
|
10
|
+
* job anybody has to remember to cancel.
|
|
11
|
+
*
|
|
12
|
+
* Declared here rather than imported from `@crm/contracts` so the published
|
|
13
|
+
* package has no private dependencies; kept in step with the zod schemas.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
//# sourceMappingURL=scheduled-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-message.js","sourceRoot":"","sources":["../../src/types/scheduled-message.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG"}
|