@meltwater/conversations-api-services 1.0.3 → 1.0.5
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/package.json
CHANGED
|
@@ -394,7 +394,7 @@ export class FacebookApiClient {
|
|
|
394
394
|
const {
|
|
395
395
|
documentId,
|
|
396
396
|
appData: { hidden: hiddenOnNative },
|
|
397
|
-
metaData: { externalId
|
|
397
|
+
metaData: { externalId },
|
|
398
398
|
systemData: {
|
|
399
399
|
connectionsCredential: credentialId,
|
|
400
400
|
policies: { storage: { privateTo: companyId } = {} } = {},
|
|
@@ -82,7 +82,12 @@ export class LinkedInApiClient {
|
|
|
82
82
|
|
|
83
83
|
this.logger.info(
|
|
84
84
|
`Native Linkedin API Like Comment Response for documentId ${documentId}`,
|
|
85
|
-
{
|
|
85
|
+
{
|
|
86
|
+
ok: response.ok,
|
|
87
|
+
status: response.status,
|
|
88
|
+
message: JSON.parse(response.text),
|
|
89
|
+
likedByUser,
|
|
90
|
+
}
|
|
86
91
|
);
|
|
87
92
|
} catch (err) {
|
|
88
93
|
this.logger.error(documentId + ' - exception details', {
|
|
@@ -141,12 +146,20 @@ export class LinkedInApiClient {
|
|
|
141
146
|
|
|
142
147
|
this.logger.info(
|
|
143
148
|
`Native Linkedin API Delete Comment Response for documentId ${documentId}`,
|
|
144
|
-
{ response }
|
|
149
|
+
{ status: response.status, ok: response.ok }
|
|
145
150
|
);
|
|
146
151
|
} catch (err) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
if (err && err.response && err.response.text) {
|
|
153
|
+
this.logger.error(
|
|
154
|
+
`Call to linkedin api with documentId ${documentId} failed`,
|
|
155
|
+
{ message: JSON.parse(err.response.text) }
|
|
156
|
+
);
|
|
157
|
+
} else {
|
|
158
|
+
this.logger.error(
|
|
159
|
+
`Call to linkedin api with documentId ${documentId} failed`,
|
|
160
|
+
err
|
|
161
|
+
);
|
|
162
|
+
}
|
|
150
163
|
throw err;
|
|
151
164
|
}
|
|
152
165
|
return response;
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import superagent from 'superagent';
|
|
2
|
+
import { removePrefix } from '../../lib/externalId.helpers.js';
|
|
3
|
+
import configuration from '../../lib/configuration.js';
|
|
4
|
+
|
|
5
|
+
export class TikTokApiClient {
|
|
6
|
+
constructor({ services }) {
|
|
7
|
+
this.tiktokURL = configuration.get('TIKTOK_API_URL');
|
|
8
|
+
this.tokenService = services.token;
|
|
9
|
+
this.logger = services.logger;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async getAuthorization(document) {
|
|
13
|
+
const {
|
|
14
|
+
documentId,
|
|
15
|
+
systemData: { connectionsCredential: credentialId } = {},
|
|
16
|
+
} = document;
|
|
17
|
+
try {
|
|
18
|
+
const token = await this.tokenService.getByCredentialId(
|
|
19
|
+
credentialId
|
|
20
|
+
);
|
|
21
|
+
return `${token.token}`;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
this.logger.error(
|
|
24
|
+
`${documentId} - error getting tiktok token - ${error.code}`,
|
|
25
|
+
error
|
|
26
|
+
);
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async sendPost({
|
|
32
|
+
paramString = '',
|
|
33
|
+
headers = {},
|
|
34
|
+
document,
|
|
35
|
+
postData = undefined,
|
|
36
|
+
}) {
|
|
37
|
+
let response = {};
|
|
38
|
+
try {
|
|
39
|
+
response = await superagent
|
|
40
|
+
.post(this.tiktokURL + paramString)
|
|
41
|
+
.set('Accept', 'application/json')
|
|
42
|
+
.set('Content-Type', 'application/json')
|
|
43
|
+
.set('Access-Token', await this.getAuthorization(document))
|
|
44
|
+
.send(postData);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if (
|
|
47
|
+
err &&
|
|
48
|
+
err.response &&
|
|
49
|
+
err.response.body &&
|
|
50
|
+
err.response.body.error
|
|
51
|
+
) {
|
|
52
|
+
this.logger.error(
|
|
53
|
+
`Failed to call tiktok api for paramString ${paramString}: ${err.response.body.error.message}`
|
|
54
|
+
);
|
|
55
|
+
} else {
|
|
56
|
+
this.logger.error(
|
|
57
|
+
`Failed to call tiktok api for paramString ${paramString}`,
|
|
58
|
+
err
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return response;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// assumes batch calls are using the same credential
|
|
69
|
+
async sendRequest({ paramString = '', headers = {}, document }) {
|
|
70
|
+
let response = {};
|
|
71
|
+
try {
|
|
72
|
+
response = await superagent
|
|
73
|
+
.get(this.tiktokURL + paramString)
|
|
74
|
+
.set('Accept', 'application/json')
|
|
75
|
+
.set('Content-Type', 'application/json')
|
|
76
|
+
.set('Access-Token', await this.getAuthorization(document))
|
|
77
|
+
.send();
|
|
78
|
+
} catch (err) {
|
|
79
|
+
if (
|
|
80
|
+
err &&
|
|
81
|
+
err.response &&
|
|
82
|
+
err.response.body &&
|
|
83
|
+
err.response.body.error
|
|
84
|
+
) {
|
|
85
|
+
this.logger.error(
|
|
86
|
+
`Failed to call tiktok api for paramString ${paramString}: ${err.response.body.error.message}`
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
this.logger.error(
|
|
90
|
+
`Failed to call tiktok api for paramString ${paramString}`,
|
|
91
|
+
err
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (response.status !== 200) {
|
|
99
|
+
this.logger.error(
|
|
100
|
+
`Failed to call tiktok api for documentId ${documentId}`,
|
|
101
|
+
response.body
|
|
102
|
+
);
|
|
103
|
+
let error = new Error(
|
|
104
|
+
`Failed to call tiktok api for documentId ${documentId}`
|
|
105
|
+
);
|
|
106
|
+
error.code = response.status;
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return response.body;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async getChannelInfoForDocuments(documents) {
|
|
114
|
+
const channelInfo = await this.getStatsForDocuments(
|
|
115
|
+
documents,
|
|
116
|
+
'metaData.authors.0.authorInfo.externalId',
|
|
117
|
+
{
|
|
118
|
+
og: ['video/list/'],
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
return channelInfo;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async getStatsForDocuments(
|
|
125
|
+
documents,
|
|
126
|
+
externalIdFrom = 'metaData.externalId',
|
|
127
|
+
paramsByType = {
|
|
128
|
+
og: ['video/list/'],
|
|
129
|
+
}
|
|
130
|
+
) {
|
|
131
|
+
// for batching separate og and comment/reply requests per credential
|
|
132
|
+
const documentsByTypeAndCredentials = documents.reduce(
|
|
133
|
+
(retObj, document, index) => {
|
|
134
|
+
const paramArray =
|
|
135
|
+
paramsByType[document.metaData.discussionType];
|
|
136
|
+
if (paramArray) {
|
|
137
|
+
paramArray.forEach((paramString) => {
|
|
138
|
+
let discussionTypeBucket =
|
|
139
|
+
retObj[
|
|
140
|
+
`${paramString}${document.systemData.connectionsCredential}`
|
|
141
|
+
];
|
|
142
|
+
if (!discussionTypeBucket) {
|
|
143
|
+
discussionTypeBucket = {
|
|
144
|
+
paramString,
|
|
145
|
+
document,
|
|
146
|
+
externalIds: [],
|
|
147
|
+
externalIdToDocumentIndex: {},
|
|
148
|
+
};
|
|
149
|
+
retObj[
|
|
150
|
+
`${paramString}${document.systemData.connectionsCredential}`
|
|
151
|
+
] = discussionTypeBucket;
|
|
152
|
+
}
|
|
153
|
+
const externalIdTrimmed = removePrefix(
|
|
154
|
+
// javascript weirdness to get around '.' notation
|
|
155
|
+
externalIdFrom
|
|
156
|
+
.split('.')
|
|
157
|
+
.reduce((a, b) => a[b], document)
|
|
158
|
+
);
|
|
159
|
+
discussionTypeBucket.externalIds.push(
|
|
160
|
+
externalIdTrimmed
|
|
161
|
+
);
|
|
162
|
+
discussionTypeBucket.externalIdToDocumentIndex[
|
|
163
|
+
externalIdTrimmed
|
|
164
|
+
] = index;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return retObj;
|
|
168
|
+
},
|
|
169
|
+
{}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const sortedResults = Array(documents.length).fill();
|
|
173
|
+
await Promise.all(
|
|
174
|
+
Object.values(documentsByTypeAndCredentials).map(
|
|
175
|
+
async (documentsByTypeAndCredential) => {
|
|
176
|
+
if (documentsByTypeAndCredential.externalIds.length) {
|
|
177
|
+
const {
|
|
178
|
+
metaData: {
|
|
179
|
+
inReplyTo: { profileId: business_id },
|
|
180
|
+
},
|
|
181
|
+
} = documentsByTypeAndCredential.document;
|
|
182
|
+
const trimmedBusinessId = removePrefix(business_id);
|
|
183
|
+
const requestResult = await this.sendRequest({
|
|
184
|
+
paramString: `${
|
|
185
|
+
documentsByTypeAndCredential.paramString
|
|
186
|
+
}?business_id=${trimmedBusinessId}&fields=["item_id","create_time","thumbnail_url","share_url","embed_url","caption","video_views","likes","comments","shares"]&filters=${JSON.stringify(
|
|
187
|
+
{
|
|
188
|
+
video_ids:
|
|
189
|
+
documentsByTypeAndCredential.externalIds,
|
|
190
|
+
}
|
|
191
|
+
)}`,
|
|
192
|
+
document: documentsByTypeAndCredential.document,
|
|
193
|
+
});
|
|
194
|
+
requestResult.data.videos.forEach(
|
|
195
|
+
({
|
|
196
|
+
item_id,
|
|
197
|
+
create_time,
|
|
198
|
+
thumbnail_url,
|
|
199
|
+
share_url,
|
|
200
|
+
embed_url,
|
|
201
|
+
caption,
|
|
202
|
+
video_views,
|
|
203
|
+
likes,
|
|
204
|
+
comments,
|
|
205
|
+
shares,
|
|
206
|
+
...args
|
|
207
|
+
}) => {
|
|
208
|
+
const documentIndex =
|
|
209
|
+
documentsByTypeAndCredential
|
|
210
|
+
.externalIdToDocumentIndex[item_id];
|
|
211
|
+
sortedResults[documentIndex] = {
|
|
212
|
+
...sortedResults[documentIndex],
|
|
213
|
+
item_id,
|
|
214
|
+
create_time,
|
|
215
|
+
thumbnail_url,
|
|
216
|
+
externalId:
|
|
217
|
+
documents[documentIndex].metaData
|
|
218
|
+
.externalId,
|
|
219
|
+
share_url,
|
|
220
|
+
embed_url,
|
|
221
|
+
caption,
|
|
222
|
+
video_views,
|
|
223
|
+
likes,
|
|
224
|
+
comments,
|
|
225
|
+
shares,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
return sortedResults;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async publish(message, videoId, markMessageAsCompleteDocumentId) {
|
|
237
|
+
const {
|
|
238
|
+
metaData: { discussionType },
|
|
239
|
+
} = message;
|
|
240
|
+
let publishedMessage;
|
|
241
|
+
|
|
242
|
+
switch (discussionType) {
|
|
243
|
+
case 'qt':
|
|
244
|
+
publishedMessage = await this.insertComment(message);
|
|
245
|
+
break;
|
|
246
|
+
case 're':
|
|
247
|
+
publishedMessage = await this.insertReply(
|
|
248
|
+
videoId,
|
|
249
|
+
message,
|
|
250
|
+
markMessageAsCompleteDocumentId
|
|
251
|
+
);
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return publishedMessage;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async insertComment(document) {
|
|
259
|
+
const {
|
|
260
|
+
body: {
|
|
261
|
+
content: { text: text },
|
|
262
|
+
},
|
|
263
|
+
metaData: {
|
|
264
|
+
source: { id: business_id },
|
|
265
|
+
inReplyTo: { id: video_id },
|
|
266
|
+
},
|
|
267
|
+
} = document;
|
|
268
|
+
const { body: publishedMessage } =
|
|
269
|
+
(await this.sendPost({
|
|
270
|
+
paramString: 'comment/create/',
|
|
271
|
+
postData: {
|
|
272
|
+
business_id,
|
|
273
|
+
video_id,
|
|
274
|
+
text,
|
|
275
|
+
},
|
|
276
|
+
document,
|
|
277
|
+
})) || {};
|
|
278
|
+
return publishedMessage;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async insertReply(videoId, document, markMessageAsCompleteDocumentId) {
|
|
282
|
+
const {
|
|
283
|
+
body: {
|
|
284
|
+
content: { text: text },
|
|
285
|
+
},
|
|
286
|
+
metaData: {
|
|
287
|
+
inReplyTo: { id: comment_id, profileId: business_id },
|
|
288
|
+
},
|
|
289
|
+
} = document;
|
|
290
|
+
|
|
291
|
+
const { body: publishedMessage } =
|
|
292
|
+
(await this.sendPost({
|
|
293
|
+
paramString: 'comment/reply/create/',
|
|
294
|
+
postData: {
|
|
295
|
+
business_id: document.metaData.source.id,
|
|
296
|
+
comment_id: markMessageAsCompleteDocumentId || comment_id,
|
|
297
|
+
video_id: removePrefix(videoId),
|
|
298
|
+
text,
|
|
299
|
+
},
|
|
300
|
+
document,
|
|
301
|
+
})) || {};
|
|
302
|
+
|
|
303
|
+
return publishedMessage;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async toggleLike(document) {
|
|
307
|
+
const {
|
|
308
|
+
enrichments: {
|
|
309
|
+
socialScores: { tt_liked_by_user: likedByUser },
|
|
310
|
+
},
|
|
311
|
+
} = document;
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
let likeResponse = await (!likedByUser
|
|
315
|
+
? this.like(document)
|
|
316
|
+
: this.unlike(document));
|
|
317
|
+
return likeResponse;
|
|
318
|
+
} catch (error) {
|
|
319
|
+
this.logger.error(`${document} - error recieved - ${error.code}`, error);
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async toggleHide(document) {
|
|
325
|
+
const {
|
|
326
|
+
documentId,
|
|
327
|
+
appData: { hidden: hiddenOnNative },
|
|
328
|
+
systemData: {
|
|
329
|
+
policies: { storage: { privateTo: companyId } = {} } = {},
|
|
330
|
+
} = {},
|
|
331
|
+
} = document;
|
|
332
|
+
let hideResponse;
|
|
333
|
+
let notificationPayload = document;
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
if (hiddenOnNative) {
|
|
337
|
+
hideResponse = await this.hide(document);
|
|
338
|
+
} else {
|
|
339
|
+
hideResponse = await this.unhide(document);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
notificationPayload.appData.hideStatus = {
|
|
343
|
+
code: hideResponse.success === true ? 200 : 500,
|
|
344
|
+
message:
|
|
345
|
+
hideResponse.success === true
|
|
346
|
+
? 'Success'
|
|
347
|
+
: 'Failed to Hide',
|
|
348
|
+
};
|
|
349
|
+
this.logger.debug(
|
|
350
|
+
`Notification payload for ${documentId} on company ${companyId} `,
|
|
351
|
+
notificationPayload
|
|
352
|
+
);
|
|
353
|
+
} catch (error) {
|
|
354
|
+
this.logger.error(
|
|
355
|
+
`${documentId} - error recieved - ${error.code}`,
|
|
356
|
+
error
|
|
357
|
+
);
|
|
358
|
+
// message failed ot send, mark as such
|
|
359
|
+
notificationPayload.appData.hideStatus = {
|
|
360
|
+
code: 405,
|
|
361
|
+
message: 'Exception Occurred',
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
setTimeout(() => {
|
|
365
|
+
PushRepository.publish(
|
|
366
|
+
`${companyId}-${documentId}`,
|
|
367
|
+
notificationPayload
|
|
368
|
+
);
|
|
369
|
+
}, 5000);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async like(document) {
|
|
373
|
+
const {
|
|
374
|
+
metaData: {
|
|
375
|
+
externalId: comment_id,
|
|
376
|
+
source: { id: sourceId },
|
|
377
|
+
},
|
|
378
|
+
} = document;
|
|
379
|
+
const { body: publishedMessage } =
|
|
380
|
+
(await this.sendPost({
|
|
381
|
+
paramString: 'comment/like/',
|
|
382
|
+
postData: {
|
|
383
|
+
business_id: removePrefix(sourceId),
|
|
384
|
+
comment_id: removePrefix(comment_id),
|
|
385
|
+
action: 'LIKE',
|
|
386
|
+
},
|
|
387
|
+
document,
|
|
388
|
+
})) || {};
|
|
389
|
+
return publishedMessage;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async unlike(document) {
|
|
393
|
+
const {
|
|
394
|
+
metaData: {
|
|
395
|
+
inReplyTo: { id: comment_id },
|
|
396
|
+
source: { id: sourceId },
|
|
397
|
+
},
|
|
398
|
+
} = document;
|
|
399
|
+
const { body: publishedMessage } =
|
|
400
|
+
(await this.sendPost({
|
|
401
|
+
paramString: 'comment/like/',
|
|
402
|
+
postData: {
|
|
403
|
+
business_id: removePrefix(sourceId),
|
|
404
|
+
comment_id: removePrefix(comment_id),
|
|
405
|
+
action: 'unlike',
|
|
406
|
+
},
|
|
407
|
+
document,
|
|
408
|
+
})) || {};
|
|
409
|
+
return publishedMessage;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
async hide(document) {
|
|
413
|
+
const {
|
|
414
|
+
metaData: {
|
|
415
|
+
inReplyTo: { id: comment_id, profileId: business_id },
|
|
416
|
+
},
|
|
417
|
+
} = document;
|
|
418
|
+
const { body: publishedMessage } =
|
|
419
|
+
(await this.sendPost({
|
|
420
|
+
paramString: 'comment/hide/',
|
|
421
|
+
postData: {
|
|
422
|
+
business_id,
|
|
423
|
+
comment_id,
|
|
424
|
+
action: 'HIDE',
|
|
425
|
+
},
|
|
426
|
+
document,
|
|
427
|
+
})) || {};
|
|
428
|
+
return publishedMessage;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async unhide(document) {
|
|
432
|
+
const {
|
|
433
|
+
metaData: {
|
|
434
|
+
inReplyTo: { id: comment_id, profileId: business_id },
|
|
435
|
+
},
|
|
436
|
+
} = document;
|
|
437
|
+
const { body: publishedMessage } =
|
|
438
|
+
(await this.sendPost({
|
|
439
|
+
paramString: 'comment/hide/',
|
|
440
|
+
postData: {
|
|
441
|
+
business_id,
|
|
442
|
+
comment_id,
|
|
443
|
+
action: 'UNHIDE',
|
|
444
|
+
},
|
|
445
|
+
document,
|
|
446
|
+
})) || {};
|
|
447
|
+
return publishedMessage;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async deleteComment(document) {
|
|
451
|
+
const {
|
|
452
|
+
metaData: {
|
|
453
|
+
inReplyTo: { id: comment_id, profileId: business_id },
|
|
454
|
+
},
|
|
455
|
+
} = document;
|
|
456
|
+
const { body: publishedMessage } =
|
|
457
|
+
(await this.sendPost({
|
|
458
|
+
paramString: 'comment/delete/',
|
|
459
|
+
postData: {
|
|
460
|
+
business_id,
|
|
461
|
+
comment_id,
|
|
462
|
+
},
|
|
463
|
+
document,
|
|
464
|
+
})) || {};
|
|
465
|
+
return publishedMessage;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async getProfile(business_id, document) {
|
|
469
|
+
const fields = '["username", "display_name", "profile_image"]';
|
|
470
|
+
const profile =
|
|
471
|
+
(await this.sendRequest({
|
|
472
|
+
paramString: `get/?business_id=${business_id}&fields=${fields}`,
|
|
473
|
+
document,
|
|
474
|
+
})) || {};
|
|
475
|
+
return profile;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async getPostData(business_id, video_id, document) {
|
|
479
|
+
const fields =
|
|
480
|
+
'["item_id", "thumbnail_url", "create_time", "username", "display_name", "profile_image"]';
|
|
481
|
+
const video_ids = `["${video_id}"]`;
|
|
482
|
+
const profile =
|
|
483
|
+
(await this.sendRequest({
|
|
484
|
+
paramString: `video/list?business_id=${business_id}&fields=${fields}&filters={"video_ids":${video_ids}}`,
|
|
485
|
+
document,
|
|
486
|
+
})) || {};
|
|
487
|
+
return profile;
|
|
488
|
+
}
|
|
489
|
+
}
|
package/src/data-access/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { InstagramApiClient } from './http/instagramApi.client.js';
|
|
|
10
10
|
import { InstagramVideoClient } from './http/InstagramVideoClient.js';
|
|
11
11
|
import { IRClient } from './http/ir.client.js';
|
|
12
12
|
import { LinkedInApiClient } from './http/linkedInApi.client.js';
|
|
13
|
+
import { TikTokApiClient } from './http/tiktokApi.client.js';
|
|
13
14
|
import { MasfClient } from './http/masf.client.js';
|
|
14
15
|
import { WarpZoneApiClient } from './http/WarpZoneApi.client.js';
|
|
15
16
|
|
|
@@ -26,6 +27,7 @@ export {
|
|
|
26
27
|
InstagramVideoClient,
|
|
27
28
|
IRClient,
|
|
28
29
|
LinkedInApiClient,
|
|
30
|
+
TikTokApiClient,
|
|
29
31
|
MasfClient,
|
|
30
32
|
WarpZoneApiClient,
|
|
31
33
|
};
|