@unboundcx/sdk 4.11.0 → 4.12.0
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/index.js +11 -0
- package/package.json +1 -1
- package/services/brand.js +166 -0
- package/services/chat.js +14 -4
- package/services/content.js +299 -0
- package/services/drive.js +21 -0
- package/services/messaging/EmailTemplatesService.js +182 -21
package/index.js
CHANGED
|
@@ -15,6 +15,8 @@ import { WorkflowsService } from './services/workflows.js';
|
|
|
15
15
|
import { NotesService } from './services/notes.js';
|
|
16
16
|
import { StorageService } from './services/storage.js';
|
|
17
17
|
import { BrandingService } from './services/branding.js';
|
|
18
|
+
import { BrandService } from './services/brand.js';
|
|
19
|
+
import { ContentService } from './services/content.js';
|
|
18
20
|
import { VerificationService } from './services/verification.js';
|
|
19
21
|
import { PortalsService } from './services/portals.js';
|
|
20
22
|
import { SipEndpointsService } from './services/sipEndpoints.js';
|
|
@@ -93,6 +95,8 @@ class UnboundSDK extends BaseSDK {
|
|
|
93
95
|
this.notes = new NotesService(this);
|
|
94
96
|
this.storage = new StorageService(this);
|
|
95
97
|
this.branding = new BrandingService(this);
|
|
98
|
+
this.brand = new BrandService(this);
|
|
99
|
+
this.content = new ContentService(this);
|
|
96
100
|
this.verification = new VerificationService(this);
|
|
97
101
|
this.portals = new PortalsService(this);
|
|
98
102
|
this.sipEndpoints = new SipEndpointsService(this);
|
|
@@ -275,6 +279,13 @@ export { WorkflowsService } from './services/workflows.js';
|
|
|
275
279
|
export { NotesService } from './services/notes.js';
|
|
276
280
|
export { StorageService } from './services/storage.js';
|
|
277
281
|
export { BrandingService, BrandingEmailTemplatesService } from './services/branding.js';
|
|
282
|
+
export { BrandService, BrandKitsService } from './services/brand.js';
|
|
283
|
+
export {
|
|
284
|
+
ContentService,
|
|
285
|
+
ContentBlocksService,
|
|
286
|
+
ContentLibraryService,
|
|
287
|
+
ContentStockService,
|
|
288
|
+
} from './services/content.js';
|
|
278
289
|
export { VerificationService } from './services/verification.js';
|
|
279
290
|
export { PortalsService } from './services/portals.js';
|
|
280
291
|
export { SipEndpointsService } from './services/sipEndpoints.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.12.0",
|
|
4
4
|
"description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { internalRequest } from '../base.js';
|
|
2
|
+
|
|
3
|
+
function pickDefined(fields) {
|
|
4
|
+
const body = {};
|
|
5
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
6
|
+
if (value !== undefined) body[key] = value;
|
|
7
|
+
}
|
|
8
|
+
return body;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Tenant brand kits used in content we send/host (emails, later landing
|
|
13
|
+
* pages). Distinct from white-label `sdk.branding`.
|
|
14
|
+
*
|
|
15
|
+
* @see app1-api src/services/brand/routes.js
|
|
16
|
+
*/
|
|
17
|
+
export class BrandService {
|
|
18
|
+
constructor(sdk) {
|
|
19
|
+
this.sdk = sdk;
|
|
20
|
+
this.kits = new BrandKitsService(sdk);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Brand kit CRUD + URL extract. `sdk.brand.kits.*`.
|
|
26
|
+
*/
|
|
27
|
+
export class BrandKitsService {
|
|
28
|
+
constructor(sdk) {
|
|
29
|
+
this.sdk = sdk;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* List brand kits for the account. First call may seed a Default kit.
|
|
34
|
+
*
|
|
35
|
+
* @returns {Promise<Array>} Kits
|
|
36
|
+
*/
|
|
37
|
+
async list() {
|
|
38
|
+
const result = await internalRequest(this.sdk, '/brand/kits', 'GET', {});
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create a brand kit.
|
|
44
|
+
*
|
|
45
|
+
* @param {Object} params
|
|
46
|
+
* @param {string} params.name - Kit name (required)
|
|
47
|
+
* @param {string} [params.logoStorageId]
|
|
48
|
+
* @param {string} [params.logoDarkStorageId]
|
|
49
|
+
* @param {string} [params.faviconStorageId]
|
|
50
|
+
* @param {Object} [params.colors]
|
|
51
|
+
* @param {Object} [params.fonts]
|
|
52
|
+
* @param {Object} [params.styles]
|
|
53
|
+
* @param {Object} [params.socialLinks]
|
|
54
|
+
* @param {string} [params.legalFooter]
|
|
55
|
+
* @param {string} [params.websiteUrl]
|
|
56
|
+
* @param {boolean} [params.isDefault]
|
|
57
|
+
* @returns {Promise<Object>} Created kit
|
|
58
|
+
*/
|
|
59
|
+
async create(params = {}) {
|
|
60
|
+
this.sdk.validateParams(
|
|
61
|
+
{ name: params.name },
|
|
62
|
+
{ name: { type: 'string', required: true } },
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const result = await internalRequest(this.sdk, '/brand/kits', 'POST', {
|
|
66
|
+
body: pickDefined(params),
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get a brand kit by id.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} id - Kit id
|
|
75
|
+
* @returns {Promise<Object>} Kit
|
|
76
|
+
*/
|
|
77
|
+
async get(id) {
|
|
78
|
+
this.sdk.validateParams(
|
|
79
|
+
{ id },
|
|
80
|
+
{ id: { type: 'string', required: true } },
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const result = await internalRequest(this.sdk, `/brand/kits/${id}`, 'GET', {});
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Update a brand kit. Only defined fields are sent.
|
|
89
|
+
*
|
|
90
|
+
* @param {string} id - Kit id
|
|
91
|
+
* @param {Object} params - Fields to update
|
|
92
|
+
* @returns {Promise<Object>} Updated kit
|
|
93
|
+
*/
|
|
94
|
+
async update(id, params = {}) {
|
|
95
|
+
this.sdk.validateParams(
|
|
96
|
+
{ id },
|
|
97
|
+
{ id: { type: 'string', required: true } },
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const result = await internalRequest(this.sdk, `/brand/kits/${id}`, 'PUT', {
|
|
101
|
+
body: pickDefined(params),
|
|
102
|
+
});
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Delete a brand kit.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} id - Kit id
|
|
110
|
+
* @returns {Promise<Object>} Confirmation
|
|
111
|
+
*/
|
|
112
|
+
async delete(id) {
|
|
113
|
+
this.sdk.validateParams(
|
|
114
|
+
{ id },
|
|
115
|
+
{ id: { type: 'string', required: true } },
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const result = await internalRequest(
|
|
119
|
+
this.sdk,
|
|
120
|
+
`/brand/kits/${id}`,
|
|
121
|
+
'DELETE',
|
|
122
|
+
{},
|
|
123
|
+
);
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Make this kit the account default. Exactly one kit is default.
|
|
129
|
+
*
|
|
130
|
+
* @param {string} id - Kit id
|
|
131
|
+
* @returns {Promise<Object>} Updated kit
|
|
132
|
+
*/
|
|
133
|
+
async setDefault(id) {
|
|
134
|
+
this.sdk.validateParams(
|
|
135
|
+
{ id },
|
|
136
|
+
{ id: { type: 'string', required: true } },
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const result = await internalRequest(
|
|
140
|
+
this.sdk,
|
|
141
|
+
`/brand/kits/${id}/default`,
|
|
142
|
+
'POST',
|
|
143
|
+
{},
|
|
144
|
+
);
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Extract a brand-kit proposal from a public https URL. Does not save.
|
|
150
|
+
*
|
|
151
|
+
* @param {Object} params
|
|
152
|
+
* @param {string} params.url - https URL to scrape
|
|
153
|
+
* @returns {Promise<Object>} Proposal (`logoCandidates`, `colors`, `fonts`)
|
|
154
|
+
*/
|
|
155
|
+
async extract({ url } = {}) {
|
|
156
|
+
this.sdk.validateParams(
|
|
157
|
+
{ url },
|
|
158
|
+
{ url: { type: 'string', required: true } },
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const result = await internalRequest(this.sdk, '/brand/kits/extract', 'POST', {
|
|
162
|
+
body: { url },
|
|
163
|
+
});
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
}
|
package/services/chat.js
CHANGED
|
@@ -825,7 +825,9 @@ export class ChatService {
|
|
|
825
825
|
|
|
826
826
|
/**
|
|
827
827
|
* Admin: get account-level chat settings.
|
|
828
|
-
* @returns {Promise<Object>} `{allowReports, reportReasons}`
|
|
828
|
+
* @returns {Promise<Object>} `{allowReports, reportReasons, reportNotifications}`
|
|
829
|
+
* `reportNotifications[]` items are `{channelId, channelName, channelKind, reasons}` —
|
|
830
|
+
* `reasons` is `null` when the rule notifies for every reason.
|
|
829
831
|
*/
|
|
830
832
|
async adminGetSettings() {
|
|
831
833
|
return internalRequest(this.sdk, "/chat/admin/settings", "GET");
|
|
@@ -836,18 +838,26 @@ export class ChatService {
|
|
|
836
838
|
* @param {Object} params
|
|
837
839
|
* @param {boolean} params.allowReports
|
|
838
840
|
* @param {string[]} [params.reportReasons]
|
|
839
|
-
* @
|
|
841
|
+
* @param {Object[]} [params.reportNotifications] - Channels to post a
|
|
842
|
+
* "message reported" card to. Each item: `{channelId: string, reasons:
|
|
843
|
+
* string[]|null}` — `reasons` null/empty means "notify for every
|
|
844
|
+
* reason"; channel must be a non-archived public/private channel.
|
|
845
|
+
* @returns {Promise<Object>} `{allowReports, reportReasons, reportNotifications}`
|
|
840
846
|
*/
|
|
841
|
-
async adminPutSettings({ allowReports, reportReasons } = {}) {
|
|
847
|
+
async adminPutSettings({ allowReports, reportReasons, reportNotifications } = {}) {
|
|
842
848
|
this.sdk.validateParams(
|
|
843
|
-
{ allowReports, reportReasons },
|
|
849
|
+
{ allowReports, reportReasons, reportNotifications },
|
|
844
850
|
{
|
|
845
851
|
allowReports: { type: "boolean", required: true },
|
|
846
852
|
reportReasons: { type: "array", required: false },
|
|
853
|
+
reportNotifications: { type: "array", required: false },
|
|
847
854
|
},
|
|
848
855
|
);
|
|
849
856
|
const body = { allowReports };
|
|
850
857
|
if (reportReasons !== undefined) body.reportReasons = reportReasons;
|
|
858
|
+
if (reportNotifications !== undefined) {
|
|
859
|
+
body.reportNotifications = reportNotifications;
|
|
860
|
+
}
|
|
851
861
|
return internalRequest(this.sdk, "/chat/admin/settings", "PUT", {
|
|
852
862
|
body,
|
|
853
863
|
});
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { internalRequest } from '../base.js';
|
|
2
|
+
|
|
3
|
+
function pickDefined(fields) {
|
|
4
|
+
const body = {};
|
|
5
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
6
|
+
if (value !== undefined) body[key] = value;
|
|
7
|
+
}
|
|
8
|
+
return body;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Content blocks, template library, and stock imagery.
|
|
13
|
+
*
|
|
14
|
+
* @see app1-api src/services/content/routes.js
|
|
15
|
+
*/
|
|
16
|
+
export class ContentService {
|
|
17
|
+
constructor(sdk) {
|
|
18
|
+
this.sdk = sdk;
|
|
19
|
+
this.blocks = new ContentBlocksService(sdk);
|
|
20
|
+
this.library = new ContentLibraryService(sdk);
|
|
21
|
+
this.stock = new ContentStockService(sdk);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Saved / synced content blocks. `sdk.content.blocks.*`.
|
|
27
|
+
*/
|
|
28
|
+
export class ContentBlocksService {
|
|
29
|
+
constructor(sdk) {
|
|
30
|
+
this.sdk = sdk;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* List content blocks.
|
|
35
|
+
*
|
|
36
|
+
* @param {Object} [filters]
|
|
37
|
+
* @param {string} [filters.channel] - `email` or `web`
|
|
38
|
+
* @param {string} [filters.category]
|
|
39
|
+
* @param {boolean} [filters.isSynced]
|
|
40
|
+
* @param {number} [filters.limit]
|
|
41
|
+
* @returns {Promise<Object>} `{ results }`
|
|
42
|
+
*/
|
|
43
|
+
async list({ channel, category, isSynced, limit } = {}) {
|
|
44
|
+
const query = pickDefined({ channel, category, isSynced, limit });
|
|
45
|
+
const options = Object.keys(query).length ? { query } : {};
|
|
46
|
+
const result = await internalRequest(
|
|
47
|
+
this.sdk,
|
|
48
|
+
'/content/blocks',
|
|
49
|
+
'GET',
|
|
50
|
+
options,
|
|
51
|
+
);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a content block.
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} params
|
|
59
|
+
* @param {string} params.name - Block name (required)
|
|
60
|
+
* @param {string} [params.channel]
|
|
61
|
+
* @param {boolean} [params.isSynced]
|
|
62
|
+
* @param {string} [params.category]
|
|
63
|
+
* @param {Object|Array} [params.design] - Block-tree JSON
|
|
64
|
+
* @param {string} [params.designStorageId]
|
|
65
|
+
* @param {string} [params.thumbnailStorageId]
|
|
66
|
+
* @returns {Promise<Object>} Created block
|
|
67
|
+
*/
|
|
68
|
+
async create(params = {}) {
|
|
69
|
+
this.sdk.validateParams(
|
|
70
|
+
{ name: params.name },
|
|
71
|
+
{ name: { type: 'string', required: true } },
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const result = await internalRequest(this.sdk, '/content/blocks', 'POST', {
|
|
75
|
+
body: pickDefined(params),
|
|
76
|
+
});
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get a content block by id.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} id
|
|
84
|
+
* @returns {Promise<Object>} Block
|
|
85
|
+
*/
|
|
86
|
+
async get(id) {
|
|
87
|
+
this.sdk.validateParams(
|
|
88
|
+
{ id },
|
|
89
|
+
{ id: { type: 'string', required: true } },
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const result = await internalRequest(
|
|
93
|
+
this.sdk,
|
|
94
|
+
`/content/blocks/${id}`,
|
|
95
|
+
'GET',
|
|
96
|
+
{},
|
|
97
|
+
);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Update a content block. Only defined fields are sent.
|
|
103
|
+
*
|
|
104
|
+
* @param {string} id
|
|
105
|
+
* @param {Object} params
|
|
106
|
+
* @returns {Promise<Object>} Updated block
|
|
107
|
+
*/
|
|
108
|
+
async update(id, params = {}) {
|
|
109
|
+
this.sdk.validateParams(
|
|
110
|
+
{ id },
|
|
111
|
+
{ id: { type: 'string', required: true } },
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const result = await internalRequest(this.sdk, `/content/blocks/${id}`, 'PUT', {
|
|
115
|
+
body: pickDefined(params),
|
|
116
|
+
});
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Delete a content block.
|
|
122
|
+
*
|
|
123
|
+
* @param {string} id
|
|
124
|
+
* @returns {Promise<Object>} Confirmation
|
|
125
|
+
*/
|
|
126
|
+
async delete(id) {
|
|
127
|
+
this.sdk.validateParams(
|
|
128
|
+
{ id },
|
|
129
|
+
{ id: { type: 'string', required: true } },
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const result = await internalRequest(
|
|
133
|
+
this.sdk,
|
|
134
|
+
`/content/blocks/${id}`,
|
|
135
|
+
'DELETE',
|
|
136
|
+
{},
|
|
137
|
+
);
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Platform template library. `sdk.content.library.*`.
|
|
144
|
+
* No `/use` route exists yet — list / get / create only.
|
|
145
|
+
*/
|
|
146
|
+
export class ContentLibraryService {
|
|
147
|
+
constructor(sdk) {
|
|
148
|
+
this.sdk = sdk;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* List library templates.
|
|
153
|
+
*
|
|
154
|
+
* @param {Object} [filters]
|
|
155
|
+
* @param {string} [filters.channel]
|
|
156
|
+
* @param {string} [filters.category]
|
|
157
|
+
* @param {string} [filters.appearance] - `client` or `marketing`
|
|
158
|
+
* @param {boolean} [filters.isPublished]
|
|
159
|
+
* @param {number} [filters.limit]
|
|
160
|
+
* @returns {Promise<Object>} `{ results }`
|
|
161
|
+
*/
|
|
162
|
+
async list({ channel, category, appearance, isPublished, limit } = {}) {
|
|
163
|
+
const query = pickDefined({
|
|
164
|
+
channel,
|
|
165
|
+
category,
|
|
166
|
+
appearance,
|
|
167
|
+
isPublished,
|
|
168
|
+
limit,
|
|
169
|
+
});
|
|
170
|
+
const options = Object.keys(query).length ? { query } : {};
|
|
171
|
+
const result = await internalRequest(
|
|
172
|
+
this.sdk,
|
|
173
|
+
'/content/library',
|
|
174
|
+
'GET',
|
|
175
|
+
options,
|
|
176
|
+
);
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Get a library template by id.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} id
|
|
184
|
+
* @returns {Promise<Object>} Library item
|
|
185
|
+
*/
|
|
186
|
+
async get(id) {
|
|
187
|
+
this.sdk.validateParams(
|
|
188
|
+
{ id },
|
|
189
|
+
{ id: { type: 'string', required: true } },
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const result = await internalRequest(
|
|
193
|
+
this.sdk,
|
|
194
|
+
`/content/library/${id}`,
|
|
195
|
+
'GET',
|
|
196
|
+
{},
|
|
197
|
+
);
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Create a library template.
|
|
203
|
+
*
|
|
204
|
+
* @param {Object} params
|
|
205
|
+
* @param {string} params.name - Name (required)
|
|
206
|
+
* @returns {Promise<Object>} Created item
|
|
207
|
+
*/
|
|
208
|
+
async create(params = {}) {
|
|
209
|
+
this.sdk.validateParams(
|
|
210
|
+
{ name: params.name },
|
|
211
|
+
{ name: { type: 'string', required: true } },
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const result = await internalRequest(this.sdk, '/content/library', 'POST', {
|
|
215
|
+
body: pickDefined(params),
|
|
216
|
+
});
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Stock / GIF search + import-to-storage. `sdk.content.stock.*`.
|
|
223
|
+
*/
|
|
224
|
+
export class ContentStockService {
|
|
225
|
+
constructor(sdk) {
|
|
226
|
+
this.sdk = sdk;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Search Unsplash.
|
|
231
|
+
*
|
|
232
|
+
* @param {Object} [params]
|
|
233
|
+
* @param {string} [params.q]
|
|
234
|
+
* @param {number} [params.page]
|
|
235
|
+
* @returns {Promise<Object>} `{ items }`
|
|
236
|
+
*/
|
|
237
|
+
async searchUnsplash({ q, page } = {}) {
|
|
238
|
+
return this._search('unsplash', { q, page });
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Search Pexels.
|
|
243
|
+
*
|
|
244
|
+
* @param {Object} [params]
|
|
245
|
+
* @param {string} [params.q]
|
|
246
|
+
* @param {number} [params.page]
|
|
247
|
+
* @returns {Promise<Object>} `{ items }`
|
|
248
|
+
*/
|
|
249
|
+
async searchPexels({ q, page } = {}) {
|
|
250
|
+
return this._search('pexels', { q, page });
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Search GIPHY.
|
|
255
|
+
*
|
|
256
|
+
* @param {Object} [params]
|
|
257
|
+
* @param {string} [params.q]
|
|
258
|
+
* @param {number} [params.page]
|
|
259
|
+
* @returns {Promise<Object>} `{ items }`
|
|
260
|
+
*/
|
|
261
|
+
async searchGiphy({ q, page } = {}) {
|
|
262
|
+
return this._search('giphy', { q, page });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Import a stock asset into account storage.
|
|
267
|
+
*
|
|
268
|
+
* @param {Object} params
|
|
269
|
+
* @param {string} params.source - `unsplash` | `pexels` | `giphy`
|
|
270
|
+
* @param {string} [params.remoteId]
|
|
271
|
+
* @param {string} [params.url]
|
|
272
|
+
* @returns {Promise<Object>} `{ storageId, url }`
|
|
273
|
+
*/
|
|
274
|
+
async import(params = {}) {
|
|
275
|
+
this.sdk.validateParams(
|
|
276
|
+
{ source: params.source },
|
|
277
|
+
{ source: { type: 'string', required: true } },
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const result = await internalRequest(
|
|
281
|
+
this.sdk,
|
|
282
|
+
'/content/stock/import',
|
|
283
|
+
'POST',
|
|
284
|
+
{ body: pickDefined(params) },
|
|
285
|
+
);
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async _search(source, { q, page } = {}) {
|
|
290
|
+
const query = pickDefined({ q, page });
|
|
291
|
+
const options = Object.keys(query).length ? { query } : {};
|
|
292
|
+
return internalRequest(
|
|
293
|
+
this.sdk,
|
|
294
|
+
`/content/stock/${source}`,
|
|
295
|
+
'GET',
|
|
296
|
+
options,
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
package/services/drive.js
CHANGED
|
@@ -228,4 +228,25 @@ export class DriveService {
|
|
|
228
228
|
);
|
|
229
229
|
return result;
|
|
230
230
|
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Walk/create a Drive folder path. Path is already interpolated.
|
|
234
|
+
* @param {Object} options
|
|
235
|
+
* @param {string} options.path - e.g. unbound/people/Ada Lovelace
|
|
236
|
+
* @param {string} [options.sharedDriveId]
|
|
237
|
+
* @param {boolean} [options.create]
|
|
238
|
+
*/
|
|
239
|
+
async resolvePath({ path, sharedDriveId, create } = {}) {
|
|
240
|
+
this.sdk.validateParams(
|
|
241
|
+
{ path, sharedDriveId },
|
|
242
|
+
{
|
|
243
|
+
path: { type: 'string', required: true },
|
|
244
|
+
sharedDriveId: { type: 'string', required: false },
|
|
245
|
+
},
|
|
246
|
+
);
|
|
247
|
+
const body = { path };
|
|
248
|
+
if (sharedDriveId !== undefined) body.sharedDriveId = sharedDriveId;
|
|
249
|
+
if (create !== undefined) body.create = create;
|
|
250
|
+
return internalRequest(this.sdk, '/drive/resolvePath', 'POST', { body });
|
|
251
|
+
}
|
|
231
252
|
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { internalRequest } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
function pickDefined(fields) {
|
|
4
|
+
const body = {};
|
|
5
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
6
|
+
if (value !== undefined) body[key] = value;
|
|
7
|
+
}
|
|
8
|
+
return body;
|
|
9
|
+
}
|
|
10
|
+
|
|
2
11
|
export class EmailTemplatesService {
|
|
3
12
|
constructor(sdk) {
|
|
4
13
|
this.sdk = sdk;
|
|
@@ -11,6 +20,12 @@ export class EmailTemplatesService {
|
|
|
11
20
|
* @param {string} params.subject - Template subject (required)
|
|
12
21
|
* @param {string} [params.html] - HTML template body
|
|
13
22
|
* @param {string} [params.text] - Plain text template body
|
|
23
|
+
* @param {Object} [params.design] - Block-tree design JSON (compiled server-side)
|
|
24
|
+
* @param {string} [params.appearance] - `client` or `marketing` (immutable after create)
|
|
25
|
+
* @param {boolean} [params.allowOneOff] - Usable as a one-off / compose send
|
|
26
|
+
* @param {boolean} [params.allowCampaign] - Usable in campaigns / journeys
|
|
27
|
+
* @param {string} [params.brandKitId] - Brand kit to apply
|
|
28
|
+
* @param {string} [params.category] - Template category
|
|
14
29
|
* @param {Array<Object>} [params.variables] - Variable metadata definitions
|
|
15
30
|
* @param {string} params.variables[].key - Variable key (unique, alphanumeric + underscores)
|
|
16
31
|
* @param {string} params.variables[].label - Human-readable display name
|
|
@@ -22,6 +37,10 @@ export class EmailTemplatesService {
|
|
|
22
37
|
* const template = await sdk.messaging.email.templates.create({
|
|
23
38
|
* name: 'Welcome Email',
|
|
24
39
|
* subject: 'Welcome {{firstName}}!',
|
|
40
|
+
* appearance: 'marketing',
|
|
41
|
+
* allowOneOff: true,
|
|
42
|
+
* allowCampaign: true,
|
|
43
|
+
* design: { type: 'email', children: [] },
|
|
25
44
|
* html: '<h1>Hello {{firstName}}</h1><p>{{body}}</p>',
|
|
26
45
|
* text: 'Hello {{firstName}}',
|
|
27
46
|
* variables: [
|
|
@@ -30,7 +49,19 @@ export class EmailTemplatesService {
|
|
|
30
49
|
* ],
|
|
31
50
|
* });
|
|
32
51
|
*/
|
|
33
|
-
async create({
|
|
52
|
+
async create({
|
|
53
|
+
name,
|
|
54
|
+
subject,
|
|
55
|
+
html,
|
|
56
|
+
text,
|
|
57
|
+
variables,
|
|
58
|
+
design,
|
|
59
|
+
appearance,
|
|
60
|
+
allowOneOff,
|
|
61
|
+
allowCampaign,
|
|
62
|
+
brandKitId,
|
|
63
|
+
category,
|
|
64
|
+
}) {
|
|
34
65
|
this.sdk.validateParams(
|
|
35
66
|
{ name, subject },
|
|
36
67
|
{
|
|
@@ -39,16 +70,29 @@ export class EmailTemplatesService {
|
|
|
39
70
|
html: { type: 'string', required: false },
|
|
40
71
|
text: { type: 'string', required: false },
|
|
41
72
|
variables: { type: 'array', required: false },
|
|
73
|
+
design: { type: 'object', required: false },
|
|
74
|
+
appearance: { type: 'string', required: false },
|
|
75
|
+
allowOneOff: { type: 'boolean', required: false },
|
|
76
|
+
allowCampaign: { type: 'boolean', required: false },
|
|
77
|
+
brandKitId: { type: 'string', required: false },
|
|
78
|
+
category: { type: 'string', required: false },
|
|
42
79
|
},
|
|
43
80
|
);
|
|
44
81
|
|
|
45
|
-
const templateData = { name, subject };
|
|
46
|
-
if (html) templateData.html = html;
|
|
47
|
-
if (text) templateData.text = text;
|
|
48
|
-
if (variables) templateData.variables = variables;
|
|
49
|
-
|
|
50
82
|
const options = {
|
|
51
|
-
body:
|
|
83
|
+
body: pickDefined({
|
|
84
|
+
name,
|
|
85
|
+
subject,
|
|
86
|
+
html,
|
|
87
|
+
text,
|
|
88
|
+
variables,
|
|
89
|
+
design,
|
|
90
|
+
appearance,
|
|
91
|
+
allowOneOff,
|
|
92
|
+
allowCampaign,
|
|
93
|
+
brandKitId,
|
|
94
|
+
category,
|
|
95
|
+
}),
|
|
52
96
|
};
|
|
53
97
|
|
|
54
98
|
const result = await internalRequest(this.sdk,
|
|
@@ -60,13 +104,20 @@ export class EmailTemplatesService {
|
|
|
60
104
|
}
|
|
61
105
|
|
|
62
106
|
/**
|
|
63
|
-
* Update email template
|
|
107
|
+
* Update email template. Only defined fields are sent. Appearance is
|
|
108
|
+
* immutable after create and should usually be omitted.
|
|
64
109
|
* @param {string} id - Template ID (required)
|
|
65
110
|
* @param {Object} params - Update parameters
|
|
66
111
|
* @param {string} [params.name] - Template name
|
|
67
112
|
* @param {string} [params.subject] - Template subject
|
|
68
113
|
* @param {string} [params.html] - HTML template body
|
|
69
114
|
* @param {string} [params.text] - Plain text template body
|
|
115
|
+
* @param {Object} [params.design] - Block-tree design JSON (compiled server-side)
|
|
116
|
+
* @param {string} [params.appearance] - Usually omit; immutable after create
|
|
117
|
+
* @param {boolean} [params.allowOneOff] - Usable as a one-off / compose send
|
|
118
|
+
* @param {boolean} [params.allowCampaign] - Usable in campaigns / journeys
|
|
119
|
+
* @param {string} [params.brandKitId] - Brand kit to apply
|
|
120
|
+
* @param {string} [params.category] - Template category
|
|
70
121
|
* @param {Array<Object>} [params.variables] - Variable metadata definitions
|
|
71
122
|
* @param {string} params.variables[].key - Variable key (unique, alphanumeric + underscores)
|
|
72
123
|
* @param {string} params.variables[].label - Human-readable display name
|
|
@@ -77,13 +128,31 @@ export class EmailTemplatesService {
|
|
|
77
128
|
* @example
|
|
78
129
|
* const updated = await sdk.messaging.email.templates.update('tpl_123', {
|
|
79
130
|
* subject: 'Hi {{firstName}}, welcome to {{companyName}}!',
|
|
131
|
+
* allowOneOff: true,
|
|
132
|
+
* allowCampaign: false,
|
|
133
|
+
* design: { type: 'email', children: [] },
|
|
80
134
|
* variables: [
|
|
81
135
|
* { key: 'firstName', label: 'First Name', type: 'text', required: true },
|
|
82
136
|
* { key: 'companyName', label: 'Company Name', type: 'text' },
|
|
83
137
|
* ],
|
|
84
138
|
* });
|
|
85
139
|
*/
|
|
86
|
-
async update(
|
|
140
|
+
async update(
|
|
141
|
+
id,
|
|
142
|
+
{
|
|
143
|
+
name,
|
|
144
|
+
subject,
|
|
145
|
+
html,
|
|
146
|
+
text,
|
|
147
|
+
variables,
|
|
148
|
+
design,
|
|
149
|
+
appearance,
|
|
150
|
+
allowOneOff,
|
|
151
|
+
allowCampaign,
|
|
152
|
+
brandKitId,
|
|
153
|
+
category,
|
|
154
|
+
},
|
|
155
|
+
) {
|
|
87
156
|
this.sdk.validateParams(
|
|
88
157
|
{ id },
|
|
89
158
|
{
|
|
@@ -93,18 +162,29 @@ export class EmailTemplatesService {
|
|
|
93
162
|
html: { type: 'string', required: false },
|
|
94
163
|
text: { type: 'string', required: false },
|
|
95
164
|
variables: { type: 'array', required: false },
|
|
165
|
+
design: { type: 'object', required: false },
|
|
166
|
+
appearance: { type: 'string', required: false },
|
|
167
|
+
allowOneOff: { type: 'boolean', required: false },
|
|
168
|
+
allowCampaign: { type: 'boolean', required: false },
|
|
169
|
+
brandKitId: { type: 'string', required: false },
|
|
170
|
+
category: { type: 'string', required: false },
|
|
96
171
|
},
|
|
97
172
|
);
|
|
98
173
|
|
|
99
|
-
const updateData = {};
|
|
100
|
-
if (name) updateData.name = name;
|
|
101
|
-
if (subject) updateData.subject = subject;
|
|
102
|
-
if (html) updateData.html = html;
|
|
103
|
-
if (text) updateData.text = text;
|
|
104
|
-
if (variables) updateData.variables = variables;
|
|
105
|
-
|
|
106
174
|
const options = {
|
|
107
|
-
body:
|
|
175
|
+
body: pickDefined({
|
|
176
|
+
name,
|
|
177
|
+
subject,
|
|
178
|
+
html,
|
|
179
|
+
text,
|
|
180
|
+
variables,
|
|
181
|
+
design,
|
|
182
|
+
appearance,
|
|
183
|
+
allowOneOff,
|
|
184
|
+
allowCampaign,
|
|
185
|
+
brandKitId,
|
|
186
|
+
category,
|
|
187
|
+
}),
|
|
108
188
|
};
|
|
109
189
|
|
|
110
190
|
const result = await internalRequest(this.sdk,
|
|
@@ -156,11 +236,22 @@ export class EmailTemplatesService {
|
|
|
156
236
|
}
|
|
157
237
|
|
|
158
238
|
/**
|
|
159
|
-
* List
|
|
239
|
+
* List email templates, optionally filtered by appearance / usage flags.
|
|
240
|
+
* @param {Object} [filters]
|
|
241
|
+
* @param {string} [filters.appearance] - `client` or `marketing`
|
|
242
|
+
* @param {boolean} [filters.allowOneOff]
|
|
243
|
+
* @param {boolean} [filters.allowCampaign]
|
|
160
244
|
* @returns {Promise<Array>} List of email templates
|
|
161
245
|
*/
|
|
162
|
-
async list() {
|
|
163
|
-
const
|
|
246
|
+
async list({ appearance, allowOneOff, allowCampaign } = {}) {
|
|
247
|
+
const query = pickDefined({ appearance, allowOneOff, allowCampaign });
|
|
248
|
+
const options = Object.keys(query).length ? { query } : {};
|
|
249
|
+
const result = await internalRequest(
|
|
250
|
+
this.sdk,
|
|
251
|
+
'/messaging/email/template',
|
|
252
|
+
'GET',
|
|
253
|
+
options,
|
|
254
|
+
);
|
|
164
255
|
return result;
|
|
165
256
|
}
|
|
166
257
|
|
|
@@ -173,13 +264,15 @@ export class EmailTemplatesService {
|
|
|
173
264
|
* @param {string} [body.html] - Draft HTML body
|
|
174
265
|
* @param {string} [body.text] - Draft plain-text body
|
|
175
266
|
* @param {Object} [body.variables] - Variable substitution values
|
|
176
|
-
* @returns {Promise<Object>} Rendered preview
|
|
267
|
+
* @returns {Promise<Object>} Rendered preview. May include `unresolvedTags`
|
|
268
|
+
* (string[]) for merge tags that were not substituted.
|
|
177
269
|
* @example
|
|
178
270
|
* const preview = await sdk.messaging.email.templates.preview('tpl_123', {
|
|
179
271
|
* subject: 'Welcome {{firstName}}',
|
|
180
272
|
* html: '<p>Hello {{firstName}}</p>',
|
|
181
273
|
* variables: { firstName: 'Jane' },
|
|
182
274
|
* });
|
|
275
|
+
* // preview.unresolvedTags → [] or ['companyName', ...]
|
|
183
276
|
*/
|
|
184
277
|
async preview(id, { subject, html, text, variables } = {}) {
|
|
185
278
|
this.sdk.validateParams(
|
|
@@ -240,4 +333,72 @@ export class EmailTemplatesService {
|
|
|
240
333
|
);
|
|
241
334
|
return result;
|
|
242
335
|
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Autosave a draft design tree without compiling or snapshotting a version.
|
|
339
|
+
* @param {string} id - Template ID (required)
|
|
340
|
+
* @param {Object} body
|
|
341
|
+
* @param {Object} body.design - Block-tree design JSON (required)
|
|
342
|
+
* @returns {Promise<Object>} `{ id, draftDesignStorageId }`
|
|
343
|
+
*/
|
|
344
|
+
async autosave(id, { design } = {}) {
|
|
345
|
+
this.sdk.validateParams(
|
|
346
|
+
{ id, design },
|
|
347
|
+
{
|
|
348
|
+
id: { type: 'string', required: true },
|
|
349
|
+
design: { type: 'object', required: true },
|
|
350
|
+
},
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
const result = await internalRequest(this.sdk,
|
|
354
|
+
`/messaging/email/template/${id}/autosave`,
|
|
355
|
+
'POST',
|
|
356
|
+
{ body: { design } },
|
|
357
|
+
);
|
|
358
|
+
return result;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* List saved versions of a template.
|
|
363
|
+
* @param {string} id - Template ID (required)
|
|
364
|
+
* @returns {Promise<Array>} Version rows
|
|
365
|
+
*/
|
|
366
|
+
async listVersions(id) {
|
|
367
|
+
this.sdk.validateParams(
|
|
368
|
+
{ id },
|
|
369
|
+
{
|
|
370
|
+
id: { type: 'string', required: true },
|
|
371
|
+
},
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
const result = await internalRequest(this.sdk,
|
|
375
|
+
`/messaging/email/template/${id}/versions`,
|
|
376
|
+
'GET',
|
|
377
|
+
);
|
|
378
|
+
return result;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Restore a previously saved version as the current template.
|
|
383
|
+
* @param {string} id - Template ID (required)
|
|
384
|
+
* @param {number|string} version - Version number (required)
|
|
385
|
+
* @returns {Promise<Object>} Restored template
|
|
386
|
+
*/
|
|
387
|
+
async restoreVersion(id, version) {
|
|
388
|
+
this.sdk.validateParams(
|
|
389
|
+
{ id },
|
|
390
|
+
{
|
|
391
|
+
id: { type: 'string', required: true },
|
|
392
|
+
},
|
|
393
|
+
);
|
|
394
|
+
if (version === undefined || version === null || version === '') {
|
|
395
|
+
throw new Error('Missing required parameter version');
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const result = await internalRequest(this.sdk,
|
|
399
|
+
`/messaging/email/template/${id}/versions/${version}/restore`,
|
|
400
|
+
'POST',
|
|
401
|
+
);
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
243
404
|
}
|