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.
Files changed (86) hide show
  1. package/README.md +121 -21
  2. package/dist/client.d.ts +38 -0
  3. package/dist/client.js +49 -5
  4. package/dist/client.js.map +1 -1
  5. package/dist/http.d.ts +15 -0
  6. package/dist/http.js +21 -1
  7. package/dist/http.js.map +1 -1
  8. package/dist/index.d.ts +11 -0
  9. package/dist/index.js +24 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal/bytes.d.ts +38 -0
  12. package/dist/internal/bytes.js +84 -0
  13. package/dist/internal/bytes.js.map +1 -0
  14. package/dist/internal/device.d.ts +24 -0
  15. package/dist/internal/device.js +91 -0
  16. package/dist/internal/device.js.map +1 -0
  17. package/dist/internal/md5.d.ts +4 -0
  18. package/dist/internal/md5.js +109 -0
  19. package/dist/internal/md5.js.map +1 -0
  20. package/dist/internal/receiver-file.d.ts +106 -0
  21. package/dist/internal/receiver-file.js +128 -0
  22. package/dist/internal/receiver-file.js.map +1 -0
  23. package/dist/realtime/client.d.ts +85 -0
  24. package/dist/realtime/client.js +126 -0
  25. package/dist/realtime/client.js.map +1 -0
  26. package/dist/realtime/events.d.ts +147 -0
  27. package/dist/realtime/events.js +3 -0
  28. package/dist/realtime/events.js.map +1 -0
  29. package/dist/realtime/inbox.d.ts +173 -0
  30. package/dist/realtime/inbox.js +263 -0
  31. package/dist/realtime/inbox.js.map +1 -0
  32. package/dist/realtime/index.d.ts +16 -0
  33. package/dist/realtime/index.js +37 -0
  34. package/dist/realtime/index.js.map +1 -0
  35. package/dist/resources/audience/contacts.d.ts +19 -3
  36. package/dist/resources/audience/contacts.js +19 -3
  37. package/dist/resources/audience/contacts.js.map +1 -1
  38. package/dist/resources/audience/inbox-media.d.ts +92 -0
  39. package/dist/resources/audience/inbox-media.js +127 -0
  40. package/dist/resources/audience/inbox-media.js.map +1 -0
  41. package/dist/resources/audience/notifications.d.ts +171 -0
  42. package/dist/resources/audience/notifications.js +215 -0
  43. package/dist/resources/audience/notifications.js.map +1 -0
  44. package/dist/resources/audience/scheduled-messages.d.ts +234 -0
  45. package/dist/resources/audience/scheduled-messages.js +259 -0
  46. package/dist/resources/audience/scheduled-messages.js.map +1 -0
  47. package/dist/resources/campaign-audience.d.ts +132 -0
  48. package/dist/resources/campaign-audience.js +224 -0
  49. package/dist/resources/campaign-audience.js.map +1 -0
  50. package/dist/resources/campaign-report-exports.d.ts +14 -0
  51. package/dist/resources/campaign-report-exports.js +28 -0
  52. package/dist/resources/campaign-report-exports.js.map +1 -0
  53. package/dist/resources/campaign-reports.d.ts +15 -0
  54. package/dist/resources/campaign-reports.js +25 -0
  55. package/dist/resources/campaign-reports.js.map +1 -0
  56. package/dist/resources/campaigns.d.ts +239 -0
  57. package/dist/resources/campaigns.js +300 -0
  58. package/dist/resources/campaigns.js.map +1 -0
  59. package/dist/types/audience.d.ts +93 -1
  60. package/dist/types/campaign.d.ts +229 -0
  61. package/dist/types/campaign.js +3 -0
  62. package/dist/types/campaign.js.map +1 -0
  63. package/dist/types/contact-filter.d.ts +3 -2
  64. package/dist/types/contact-filter.js +3 -2
  65. package/dist/types/contact-filter.js.map +1 -1
  66. package/dist/types/inbox.d.ts +391 -0
  67. package/dist/types/inbox.js +16 -0
  68. package/dist/types/inbox.js.map +1 -0
  69. package/dist/types/index.d.ts +3 -0
  70. package/dist/types/index.js +5 -0
  71. package/dist/types/index.js.map +1 -1
  72. package/dist/types/scheduled-message.d.ts +221 -0
  73. package/dist/types/scheduled-message.js +16 -0
  74. package/dist/types/scheduled-message.js.map +1 -0
  75. package/docs/audience/contacts.md +34 -4
  76. package/docs/audience/notifications.md +263 -0
  77. package/docs/audience/scheduled-messages.md +557 -0
  78. package/docs/campaign/campaigns.md +489 -0
  79. package/docs/contact-filter.md +2 -1
  80. package/docs/inbox/chats.md +356 -0
  81. package/docs/inbox/connection.md +171 -0
  82. package/docs/inbox/media.md +202 -0
  83. package/docs/inbox/messages.md +338 -0
  84. package/docs/inbox/referrals.md +72 -0
  85. package/docs/inbox/sessions.md +74 -0
  86. package/package.json +28 -2
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Inbox = exports.InboxMessages = exports.InboxChats = void 0;
4
+ const client_1 = require("./client");
5
+ const errors_1 = require("../errors");
6
+ /** The chat list and the thirteen actions that change one. */
7
+ class InboxChats {
8
+ client;
9
+ constructor(client) {
10
+ this.client = client;
11
+ }
12
+ /**
13
+ * One page of the inbox, ordered by last activity.
14
+ *
15
+ * `contact.list` · scope `contacts:read`
16
+ *
17
+ * The reply's `filter` is the filter that was *applied* -- a team member
18
+ * without the unassigned permission asking for `all` is narrowed to `me` -- and
19
+ * `nextPage` is the cursor for the page after this one, or `null` at the end.
20
+ */
21
+ list(payload = {}) {
22
+ return this.client.request('contact.list', payload);
23
+ }
24
+ /**
25
+ * One chat, and a subscription to it: messages and state changes for this
26
+ * thread reach the socket from here on without asking again.
27
+ *
28
+ * `contact.fetch` · scope `contacts:read`
29
+ */
30
+ get(id) {
31
+ return this.client.request('contact.fetch', { id });
32
+ }
33
+ /** Any action, for callers holding a payload they built elsewhere. */
34
+ act(payload) {
35
+ return this.client.request('chat.action', payload);
36
+ }
37
+ /** Trashes the chat. It leaves every inbox view; the contact row stays. */
38
+ delete(chat) {
39
+ return this.single({ action: 'delete', chat });
40
+ }
41
+ /** Assigns the chat to one member and flags it unread for them. */
42
+ transfer(chat, member) {
43
+ return this.single({ action: 'transfer', chat, member });
44
+ }
45
+ archive(chat) {
46
+ return this.single({ action: 'archive', chat });
47
+ }
48
+ unarchive(chat) {
49
+ return this.single({ action: 'unarchive', chat });
50
+ }
51
+ /** Flips one or more block flags. Flags left out keep their current value. */
52
+ block(chat, update) {
53
+ return this.single({ action: 'block', chat, update });
54
+ }
55
+ /** Clears the unread counter and the by-hand unread flag. */
56
+ markAsRead(chat) {
57
+ return this.single({ action: 'mark_as_read', chat });
58
+ }
59
+ markAsUnread(chat) {
60
+ return this.single({ action: 'mark_as_unread', chat });
61
+ }
62
+ /** Detaches the flow and holds automation for `chat_metadata.pause_duration`. */
63
+ pauseAutomation(chat) {
64
+ return this.single({ action: 'pause_automation', chat });
65
+ }
66
+ resumeAutomation(chat) {
67
+ return this.single({ action: 'resume_automation', chat });
68
+ }
69
+ /** Closes the chat and detaches the flow, leaving the assignment alone. */
70
+ close(chat) {
71
+ return this.single({ action: 'close', chat });
72
+ }
73
+ /** Marks the chat done, unassigns it and detaches the flow. */
74
+ done(chat, isEnded) {
75
+ return this.single({ action: 'done', chat, isEnded });
76
+ }
77
+ /** Re-arms the automation pause with a new duration, in seconds. */
78
+ pauseTimer(chat, duration) {
79
+ return this.single({ action: 'pause_timer', chat, duration });
80
+ }
81
+ /** Replaces the chat's tags outright. */
82
+ updateTags(chat, tags) {
83
+ return this.single({ action: 'update_tags', chat, tags });
84
+ }
85
+ /**
86
+ * Moves every chat held by one member -- or the unassigned queue -- to another
87
+ * member or a team. Capped at 500 chats per call; each moved chat is broadcast
88
+ * individually as a `transfer`.
89
+ */
90
+ bulkTransfer(payload) {
91
+ return this.client.request('chat.action', {
92
+ action: 'bulk_transfer',
93
+ ...payload,
94
+ });
95
+ }
96
+ /** The narrower action set, answering with the metadata alone. */
97
+ update(payload) {
98
+ return this.client.request('contact.update', payload);
99
+ }
100
+ /**
101
+ * Attaches a flow to the chat, or hands the chat to the bot server to place.
102
+ *
103
+ * `contact.bot_assign` · scope `contacts:write`
104
+ */
105
+ assignBot(payload) {
106
+ return this.client.request('contact.bot_assign', payload);
107
+ }
108
+ single(payload) {
109
+ return this.client.request('chat.action', payload);
110
+ }
111
+ }
112
+ exports.InboxChats = InboxChats;
113
+ /** Reading, sending and removing messages in one thread. */
114
+ class InboxMessages {
115
+ client;
116
+ constructor(client) {
117
+ this.client = client;
118
+ }
119
+ /**
120
+ * One page of a thread, oldest-first, and a subscription to it.
121
+ *
122
+ * `message.list` · scope `messages:read`
123
+ *
124
+ * Pass the `id` of the oldest message you hold as `last_message_id` to walk
125
+ * backwards through the history.
126
+ */
127
+ list(id, options = {}) {
128
+ return this.client.request('message.list', { id, ...options });
129
+ }
130
+ /** One message by its provider id -- a `wamid`, not the document id. */
131
+ get(messageId) {
132
+ return this.client.request('message.fetch', { message_id: messageId });
133
+ }
134
+ /**
135
+ * Sends a message and gets the bubble to draw back immediately.
136
+ *
137
+ * `message.send` · scope `messages:write`
138
+ *
139
+ * The returned message carries a queue id in `message_id`, not a provider id:
140
+ * nothing has been written yet. The stored row arrives moments later as a
141
+ * `message.received` push, with the provider's id in its place -- correlate on
142
+ * the queue id you got back here, not on the final `message_id`.
143
+ *
144
+ * Sending by hand also takes the conversation off its bot, which arrives as a
145
+ * `chat.action` with `action: 'pause_automation'`.
146
+ */
147
+ send(payload) {
148
+ return this.client.request('message.send', payload);
149
+ }
150
+ /**
151
+ * Sends media, uploading it first if you hand over a file.
152
+ *
153
+ * `message.send` · scope `messages:write`
154
+ *
155
+ * Two ways in. With a `link` -- from `crm.inboxMedia.upload()`, or any publicly
156
+ * fetchable URL -- this is `send()` with the content assembled for you:
157
+ *
158
+ * ```ts
159
+ * const link = await crm.inboxMedia.upload(file, { kind: 'image' });
160
+ * await inbox.messages.sendMedia({ channel, contact, kind: 'image', link, caption: 'Your order' });
161
+ * ```
162
+ *
163
+ * With a `file`, it uploads and sends in one call -- which needs an uploader,
164
+ * because a socket cannot presign. Pass `uploadMedia` when constructing the
165
+ * `Inbox`:
166
+ *
167
+ * ```ts
168
+ * const inbox = new Inbox({ url, clientId, token, uploadMedia: crm.inboxMedia.upload.bind(crm.inboxMedia) });
169
+ * await inbox.messages.sendMedia({ channel, contact, kind: 'image', file, caption: 'Your order' });
170
+ * ```
171
+ *
172
+ * The link is what gets stored on the message, and it does not expire, so the
173
+ * thread still renders the media months later.
174
+ *
175
+ * `filename` is worth setting on a `document`: it is what the recipient sees in
176
+ * their chat, where a bare key would otherwise appear.
177
+ */
178
+ async sendMedia(payload) {
179
+ const { kind, caption, filename, file, link: given, ...target } = payload;
180
+ const link = given ?? (await this.resolve(kind, file, filename));
181
+ // The provider reads `type` and then the key matching it -- the one structural
182
+ // promise the open content shape makes. A caption belongs on the media object
183
+ // rather than beside it, and a sticker takes neither a caption nor a name.
184
+ const media = { link };
185
+ if (caption && kind !== 'sticker')
186
+ media.caption = caption;
187
+ if (filename && kind === 'document')
188
+ media.filename = filename;
189
+ return this.send({ ...target, content: { type: kind, [kind]: media } });
190
+ }
191
+ /** Uploads a file through the hook the client was given, or explains its absence. */
192
+ async resolve(kind, file, filename) {
193
+ if (!file) {
194
+ throw new errors_1.CrmConfigError('sendMedia needs either a `link` or a `file`');
195
+ }
196
+ const upload = this.client.uploadMedia;
197
+ if (!upload) {
198
+ throw new errors_1.CrmConfigError('sendMedia was given a file but no uploader. Pass `uploadMedia` to the Inbox constructor ' +
199
+ '(for example `crm.inboxMedia.upload.bind(crm.inboxMedia)`), or upload first and pass `link`.');
200
+ }
201
+ return upload(file, { kind, filename });
202
+ }
203
+ /** Removes one message from a thread, for everyone with it open. */
204
+ delete(contactId, messageId) {
205
+ return this.client.request('message.delete', { id: contactId, message_id: messageId });
206
+ }
207
+ /**
208
+ * Re-fetches media whose first download failed. Inbound media only -- an
209
+ * outbound attachment was ours to begin with.
210
+ *
211
+ * `message.retry_download` · scope `messages:write`
212
+ */
213
+ retryDownload(messageId) {
214
+ return this.client.request('message.retry_download', {
215
+ message_id: messageId,
216
+ });
217
+ }
218
+ }
219
+ exports.InboxMessages = InboxMessages;
220
+ /**
221
+ * The live-chat inbox.
222
+ *
223
+ * ```ts
224
+ * const inbox = new Inbox({ url: 'https://inbox.example.com', clientId, token });
225
+ * await inbox.ready();
226
+ *
227
+ * const { contacts } = await inbox.chats.list({ filter: { assignment: 'me', unread: 'unread' } });
228
+ * inbox.on('message.received', (message) => append(message));
229
+ * ```
230
+ */
231
+ class Inbox extends client_1.InboxClient {
232
+ chats;
233
+ messages;
234
+ constructor(options) {
235
+ super(options);
236
+ this.chats = new InboxChats(this);
237
+ this.messages = new InboxMessages(this);
238
+ }
239
+ /**
240
+ * Where a lead came from: the click-to-WhatsApp ad payloads on one contact.
241
+ *
242
+ * `ctwa.list` · scope `contacts:read`
243
+ */
244
+ referrals(contactId, limit) {
245
+ return this.request('ctwa.list', { id: contactId, limit });
246
+ }
247
+ /**
248
+ * A contact's reply windows, one per channel they have written from. Read these
249
+ * to tell whether a free-form reply is still allowed on a channel or whether
250
+ * the agent has to start from a template.
251
+ *
252
+ * `chat_session.list` · scope `contacts:read`
253
+ */
254
+ sessions(contactId, channel) {
255
+ return this.request('chat_session.list', { id: contactId, channel });
256
+ }
257
+ /** Round-trips the payload. Useful for checking the connection is live. */
258
+ ping(payload) {
259
+ return this.request('ping', payload);
260
+ }
261
+ }
262
+ exports.Inbox = Inbox;
263
+ //# sourceMappingURL=inbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/realtime/inbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The live-chat inbox, over a socket.
3
+ *
4
+ * Published as a subpath so the core SDK stays dependency-free:
5
+ *
6
+ * ```ts
7
+ * import { Inbox } from 'ab-ecosystem-cpass/realtime';
8
+ * ```
9
+ *
10
+ * `socket.io-client` is an optional peer dependency -- install it alongside the
11
+ * SDK to use this, and nothing resolves it if you only use the REST client.
12
+ */
13
+ export { Inbox, InboxChats, InboxMessages } from './inbox';
14
+ export { InboxClient, type InboxClientOptions } from './client';
15
+ export type { InboxAck, InboxError, InboxPushName, InboxPushes, InboxRequestName, InboxRequests, } from './events';
16
+ export * from '../types/inbox';
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.InboxClient = exports.InboxMessages = exports.InboxChats = exports.Inbox = void 0;
18
+ /**
19
+ * The live-chat inbox, over a socket.
20
+ *
21
+ * Published as a subpath so the core SDK stays dependency-free:
22
+ *
23
+ * ```ts
24
+ * import { Inbox } from 'ab-ecosystem-cpass/realtime';
25
+ * ```
26
+ *
27
+ * `socket.io-client` is an optional peer dependency -- install it alongside the
28
+ * SDK to use this, and nothing resolves it if you only use the REST client.
29
+ */
30
+ var inbox_1 = require("./inbox");
31
+ Object.defineProperty(exports, "Inbox", { enumerable: true, get: function () { return inbox_1.Inbox; } });
32
+ Object.defineProperty(exports, "InboxChats", { enumerable: true, get: function () { return inbox_1.InboxChats; } });
33
+ Object.defineProperty(exports, "InboxMessages", { enumerable: true, get: function () { return inbox_1.InboxMessages; } });
34
+ var client_1 = require("./client");
35
+ Object.defineProperty(exports, "InboxClient", { enumerable: true, get: function () { return client_1.InboxClient; } });
36
+ __exportStar(require("../types/inbox"), exports);
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;GAWG;AACH,iCAA2D;AAAlD,8FAAA,KAAK,OAAA;AAAE,mGAAA,UAAU,OAAA;AAAE,sGAAA,aAAa,OAAA;AACzC,mCAAgE;AAAvD,qGAAA,WAAW,OAAA;AASpB,iDAA+B"}
@@ -36,9 +36,21 @@ export declare class Contacts {
36
36
  /**
37
37
  * `POST /v1/audience/contacts` -- 201 with the created contact.
38
38
  *
39
- * Every field is optional: an empty body creates a blank contact. Channel
40
- * identities are not settable here; they are written when a conversation
41
- * starts on a channel.
39
+ * Every field is optional: an empty body creates a blank contact. Such a
40
+ * contact has no channel identity, which means nothing can message it and an
41
+ * inbound message will not be matched to it -- so pass `whatsapp` unless the
42
+ * contact is genuinely a placeholder.
43
+ *
44
+ * `whatsapp` takes a number in any shape and is stored as digits only, which
45
+ * is the form an inbound message carries. It creates the contact's WhatsApp
46
+ * identity and is reflected back under `profile.whatsapp` on the response.
47
+ * Other channels' identities are still written by the conversation that starts
48
+ * on them.
49
+ *
50
+ * 409 `conflict` if the account already holds that WhatsApp number, on another
51
+ * contact or on this one -- a number identifies one contact per account, so
52
+ * nothing is created and the existing contact is left alone. 422 if the value
53
+ * contains no digits at all.
42
54
  *
43
55
  * Scope: `contacts:write`.
44
56
  */
@@ -48,6 +60,10 @@ export declare class Contacts {
48
60
  * untouched. `tags` and `custom_field_hash` replace their stored value rather
49
61
  * than merging into it.
50
62
  *
63
+ * `whatsapp` is not accepted: a channel identity lives in its own collection,
64
+ * and changing one is a different write from patching the contact. It is
65
+ * create-only for now.
66
+ *
51
67
  * Scope: `contacts:write`.
52
68
  */
53
69
  update(id: string, input: UpdateContactInput): Promise<Contact>;
@@ -45,9 +45,21 @@ class Contacts {
45
45
  /**
46
46
  * `POST /v1/audience/contacts` -- 201 with the created contact.
47
47
  *
48
- * Every field is optional: an empty body creates a blank contact. Channel
49
- * identities are not settable here; they are written when a conversation
50
- * starts on a channel.
48
+ * Every field is optional: an empty body creates a blank contact. Such a
49
+ * contact has no channel identity, which means nothing can message it and an
50
+ * inbound message will not be matched to it -- so pass `whatsapp` unless the
51
+ * contact is genuinely a placeholder.
52
+ *
53
+ * `whatsapp` takes a number in any shape and is stored as digits only, which
54
+ * is the form an inbound message carries. It creates the contact's WhatsApp
55
+ * identity and is reflected back under `profile.whatsapp` on the response.
56
+ * Other channels' identities are still written by the conversation that starts
57
+ * on them.
58
+ *
59
+ * 409 `conflict` if the account already holds that WhatsApp number, on another
60
+ * contact or on this one -- a number identifies one contact per account, so
61
+ * nothing is created and the existing contact is left alone. 422 if the value
62
+ * contains no digits at all.
51
63
  *
52
64
  * Scope: `contacts:write`.
53
65
  */
@@ -59,6 +71,10 @@ class Contacts {
59
71
  * untouched. `tags` and `custom_field_hash` replace their stored value rather
60
72
  * than merging into it.
61
73
  *
74
+ * `whatsapp` is not accepted: a channel identity lives in its own collection,
75
+ * and changing one is a different write from patching the contact. It is
76
+ * create-only for now.
77
+ *
62
78
  * Scope: `contacts:write`.
63
79
  */
64
80
  update(id, input) {
@@ -1 +1 @@
1
- {"version":3,"file":"contacts.js","sourceRoot":"","sources":["../../../src/resources/audience/contacts.ts"],"names":[],"mappings":";;;AASA,oCAAyC;AAEzC,MAAM,IAAI,GAAG,GAAG,gBAAQ,WAAW,CAAC;AAEpC;;;;;;;GAOG;AACH,MAAa,QAAQ;IACU;IAA7B,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjD;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,QAAoC,EAAE;QACzC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAqB,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACvE,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAU,KAAK,EAAE,GAAG,IAAI,IAAI,IAAA,WAAG,EAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,QAA4B,EAAE;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAU,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,EAAU,EAAE,KAAyB;QAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAU,OAAO,EAAE,GAAG,IAAI,IAAI,IAAA,WAAG,EAAC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAsB,QAAQ,EAAE,GAAG,IAAI,IAAI,IAAA,WAAG,EAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,CAAC,OAAO,CAAC,QAAoC,EAAE;QACnD,IAAI,IAAI,GAAG,CAAC,CAAC;QAEb,SAAS,CAAC;YACR,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI;gBAAE,MAAM,OAAO,CAAC;YACjD,IAAI,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YACxE,IAAI,IAAI,CAAC,CAAC;QACZ,CAAC;IACH,CAAC;CACF;AAzFD,4BAyFC"}
1
+ {"version":3,"file":"contacts.js","sourceRoot":"","sources":["../../../src/resources/audience/contacts.ts"],"names":[],"mappings":";;;AASA,oCAAyC;AAEzC,MAAM,IAAI,GAAG,GAAG,gBAAQ,WAAW,CAAC;AAEpC;;;;;;;GAOG;AACH,MAAa,QAAQ;IACU;IAA7B,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjD;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,QAAoC,EAAE;QACzC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAqB,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACvE,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAU,KAAK,EAAE,GAAG,IAAI,IAAI,IAAA,WAAG,EAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,QAA4B,EAAE;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAU,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,CAAC;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAU,EAAE,KAAyB;QAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAU,OAAO,EAAE,GAAG,IAAI,IAAI,IAAA,WAAG,EAAC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAsB,QAAQ,EAAE,GAAG,IAAI,IAAI,IAAA,WAAG,EAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,CAAC,OAAO,CAAC,QAAoC,EAAE;QACnD,IAAI,IAAI,GAAG,CAAC,CAAC;QAEb,SAAS,CAAC;YACR,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI;gBAAE,MAAM,OAAO,CAAC;YACjD,IAAI,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YACxE,IAAI,IAAI,CAAC,CAAC;QACZ,CAAC;IACH,CAAC;CACF;AAzGD,4BAyGC"}
@@ -0,0 +1,92 @@
1
+ import type { HttpClient } from '../../http';
2
+ import type { CreateMediaUploadPayload, MediaKind, MediaUpload } from '../../types/inbox';
3
+ /** What `uploadMedia` needs about a file, when it is not a `File` or `Blob`. */
4
+ export interface UploadMediaSource {
5
+ /** The bytes. A browser `File` or `Blob`, or anything `fetch` accepts as a body. */
6
+ body: BodyInit;
7
+ filename: string;
8
+ contentType: string;
9
+ /** Exact byte length. Must match the bytes, because the signature covers it. */
10
+ size: number;
11
+ }
12
+ export interface UploadMediaOptions {
13
+ /** Which kind of message this will become. Decides the size and type limits. */
14
+ kind: MediaKind;
15
+ /** Overrides the name taken from a `File`; required for a bare `Blob` or buffer. */
16
+ filename?: string;
17
+ /** Overrides the type taken from a `File`. */
18
+ contentType?: string;
19
+ signal?: AbortSignal;
20
+ }
21
+ /**
22
+ * Chat media.
23
+ *
24
+ * Uploads do not pass through the API. A client describes the file, gets a
25
+ * presigned URL, and sends the bytes straight to object storage -- so a 90 MB
26
+ * document costs the gateway a signature rather than 90 MB of transfer, and a
27
+ * stalled upload holds the browser's connection rather than one of ours.
28
+ */
29
+ export declare class InboxMedia {
30
+ private readonly http;
31
+ constructor(http: HttpClient);
32
+ /**
33
+ * `POST /v1/audience/inbox/media/upload-url` -- one presigned upload.
34
+ *
35
+ * Metadata only; no bytes. Prefer `upload()`, which does this and the transfer
36
+ * together. Reach for this directly when you need the `key`, or when something
37
+ * other than this SDK will perform the upload.
38
+ *
39
+ * `size` and `content_type` are signed into the URL, so the upload that follows
40
+ * has to match them exactly. They are also checked against the kind's limits
41
+ * here rather than at send time -- a file rejected now is one the agent can
42
+ * swap, where one rejected by the provider has already been uploaded and drawn
43
+ * on screen.
44
+ *
45
+ * | Kind | Limit | Accepts |
46
+ * |---|---|---|
47
+ * | `image` | 5 MB | jpeg, png, webp |
48
+ * | `video` | 16 MB | mp4, 3gpp, quicktime |
49
+ * | `audio` / `voice` | 16 MB | aac, mp4, mpeg, amr, ogg |
50
+ * | `sticker` | 100 KB | webp |
51
+ * | `document` | 100 MB | anything a browser will not execute |
52
+ *
53
+ * 422 `validation_failed` if the file is too large or the type is not allowed
54
+ * for the kind. 503 `media_unavailable` if the deployment has no storage
55
+ * configured.
56
+ *
57
+ * Scope: `messages:write`.
58
+ */
59
+ createUpload(payload: CreateMediaUploadPayload): Promise<MediaUpload>;
60
+ /**
61
+ * Uploads a file and answers with its permanent public link.
62
+ *
63
+ * Three steps, one call: ask for a ticket, `PUT` the bytes to storage, return
64
+ * the link. Pass the link straight to `inbox.messages.sendMedia()`, or as the
65
+ * `link` on media content you build yourself.
66
+ *
67
+ * ```ts
68
+ * const link = await crm.inboxMedia.upload(file, { kind: 'image' });
69
+ * await inbox.messages.sendMedia({ channel, contact, kind: 'image', link, caption: 'Your order' });
70
+ * ```
71
+ *
72
+ * In Node, where there is no `File`, describe the bytes instead:
73
+ *
74
+ * ```ts
75
+ * const bytes = await readFile('invoice.pdf');
76
+ * const link = await crm.inboxMedia.upload(
77
+ * { body: bytes, filename: 'invoice.pdf', contentType: 'application/pdf', size: bytes.byteLength },
78
+ * { kind: 'document' },
79
+ * );
80
+ * ```
81
+ *
82
+ * The returned link does not expire -- only the upload URL does, and only
83
+ * before it is used. So the link can be stored against the message and will
84
+ * still render in the thread months later.
85
+ *
86
+ * The `PUT` deliberately does not go through this SDK's request pipeline: it
87
+ * carries no bearer token, because that would hand our credential to the
88
+ * storage provider, and it sends exactly the headers the ticket named, because
89
+ * the signature covers them and one extra header fails the upload.
90
+ */
91
+ upload(file: Blob | UploadMediaSource, options: UploadMediaOptions): Promise<string>;
92
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InboxMedia = void 0;
4
+ const errors_1 = require("../../errors");
5
+ const paths_1 = require("../paths");
6
+ const BASE = `${paths_1.AUDIENCE}/inbox/media`;
7
+ const hasFileShape = (value) => typeof Blob !== 'undefined' && value instanceof Blob;
8
+ /**
9
+ * Chat media.
10
+ *
11
+ * Uploads do not pass through the API. A client describes the file, gets a
12
+ * presigned URL, and sends the bytes straight to object storage -- so a 90 MB
13
+ * document costs the gateway a signature rather than 90 MB of transfer, and a
14
+ * stalled upload holds the browser's connection rather than one of ours.
15
+ */
16
+ class InboxMedia {
17
+ http;
18
+ constructor(http) {
19
+ this.http = http;
20
+ }
21
+ /**
22
+ * `POST /v1/audience/inbox/media/upload-url` -- one presigned upload.
23
+ *
24
+ * Metadata only; no bytes. Prefer `upload()`, which does this and the transfer
25
+ * together. Reach for this directly when you need the `key`, or when something
26
+ * other than this SDK will perform the upload.
27
+ *
28
+ * `size` and `content_type` are signed into the URL, so the upload that follows
29
+ * has to match them exactly. They are also checked against the kind's limits
30
+ * here rather than at send time -- a file rejected now is one the agent can
31
+ * swap, where one rejected by the provider has already been uploaded and drawn
32
+ * on screen.
33
+ *
34
+ * | Kind | Limit | Accepts |
35
+ * |---|---|---|
36
+ * | `image` | 5 MB | jpeg, png, webp |
37
+ * | `video` | 16 MB | mp4, 3gpp, quicktime |
38
+ * | `audio` / `voice` | 16 MB | aac, mp4, mpeg, amr, ogg |
39
+ * | `sticker` | 100 KB | webp |
40
+ * | `document` | 100 MB | anything a browser will not execute |
41
+ *
42
+ * 422 `validation_failed` if the file is too large or the type is not allowed
43
+ * for the kind. 503 `media_unavailable` if the deployment has no storage
44
+ * configured.
45
+ *
46
+ * Scope: `messages:write`.
47
+ */
48
+ createUpload(payload) {
49
+ return this.http.request('POST', `${BASE}/upload-url`, { body: payload });
50
+ }
51
+ /**
52
+ * Uploads a file and answers with its permanent public link.
53
+ *
54
+ * Three steps, one call: ask for a ticket, `PUT` the bytes to storage, return
55
+ * the link. Pass the link straight to `inbox.messages.sendMedia()`, or as the
56
+ * `link` on media content you build yourself.
57
+ *
58
+ * ```ts
59
+ * const link = await crm.inboxMedia.upload(file, { kind: 'image' });
60
+ * await inbox.messages.sendMedia({ channel, contact, kind: 'image', link, caption: 'Your order' });
61
+ * ```
62
+ *
63
+ * In Node, where there is no `File`, describe the bytes instead:
64
+ *
65
+ * ```ts
66
+ * const bytes = await readFile('invoice.pdf');
67
+ * const link = await crm.inboxMedia.upload(
68
+ * { body: bytes, filename: 'invoice.pdf', contentType: 'application/pdf', size: bytes.byteLength },
69
+ * { kind: 'document' },
70
+ * );
71
+ * ```
72
+ *
73
+ * The returned link does not expire -- only the upload URL does, and only
74
+ * before it is used. So the link can be stored against the message and will
75
+ * still render in the thread months later.
76
+ *
77
+ * The `PUT` deliberately does not go through this SDK's request pipeline: it
78
+ * carries no bearer token, because that would hand our credential to the
79
+ * storage provider, and it sends exactly the headers the ticket named, because
80
+ * the signature covers them and one extra header fails the upload.
81
+ */
82
+ async upload(file, options) {
83
+ const source = describe(file, options);
84
+ const ticket = await this.createUpload({
85
+ kind: options.kind,
86
+ filename: source.filename,
87
+ content_type: source.contentType,
88
+ size: source.size,
89
+ });
90
+ const response = await this.http.fetchImpl(ticket.upload_url, {
91
+ method: 'PUT',
92
+ headers: ticket.headers,
93
+ body: source.body,
94
+ signal: options.signal,
95
+ });
96
+ if (!response.ok) {
97
+ // Storage answers XML, not our error envelope, so there is nothing to parse
98
+ // into a CrmApiError's shape -- the status and the body are the whole of
99
+ // what went wrong. A 403 here is almost always a mismatch between the
100
+ // declared size or type and the bytes actually sent.
101
+ throw new errors_1.CrmApiError(response.status, 'media_upload_failed', `Upload to storage failed with ${response.status}. ` +
102
+ 'Check that the bytes match the declared size and content type.', await response.text().catch(() => undefined));
103
+ }
104
+ return ticket.link;
105
+ }
106
+ }
107
+ exports.InboxMedia = InboxMedia;
108
+ /** Fills in what a `File` already knows, and insists on it otherwise. */
109
+ const describe = (file, options) => {
110
+ if (!hasFileShape(file)) {
111
+ const source = file;
112
+ return {
113
+ body: source.body,
114
+ filename: options.filename ?? source.filename,
115
+ contentType: options.contentType ?? source.contentType,
116
+ size: source.size,
117
+ };
118
+ }
119
+ const filename = options.filename ?? file.name;
120
+ const contentType = options.contentType ?? file.type;
121
+ if (!filename)
122
+ throw new errors_1.CrmApiError(400, 'validation_failed', 'filename is required for a Blob without a name');
123
+ if (!contentType)
124
+ throw new errors_1.CrmApiError(400, 'validation_failed', 'contentType is required for a Blob without a type');
125
+ return { body: file, filename, contentType, size: file.size };
126
+ };
127
+ //# sourceMappingURL=inbox-media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-media.js","sourceRoot":"","sources":["../../../src/resources/audience/inbox-media.ts"],"names":[],"mappings":"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"}