@meltwater/conversations-api-services 1.3.1 → 1.4.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.
Files changed (29) hide show
  1. package/.github/workflows/release.yml +4 -6
  2. package/CLAUDE.md +70 -0
  3. package/README.md +1 -1
  4. package/dist/cjs/data-access/http/facebook.native.js +122 -106
  5. package/dist/cjs/data-access/http/instagram.native.js +92 -49
  6. package/dist/cjs/data-access/http/linkedin.native.js +135 -56
  7. package/dist/cjs/data-access/http/threads.native.js +53 -18
  8. package/dist/cjs/data-access/http/tiktok.native.js +18 -12
  9. package/dist/cjs/data-access/http/twitter.native.js +142 -40
  10. package/dist/cjs/data-access/http/youtube.native.js +19 -13
  11. package/dist/esm/data-access/http/facebook.native.js +123 -107
  12. package/dist/esm/data-access/http/instagram.native.js +93 -50
  13. package/dist/esm/data-access/http/linkedin.native.js +136 -57
  14. package/dist/esm/data-access/http/threads.native.js +54 -19
  15. package/dist/esm/data-access/http/tiktok.native.js +19 -13
  16. package/dist/esm/data-access/http/twitter.native.js +143 -41
  17. package/dist/esm/data-access/http/youtube.native.js +20 -14
  18. package/package.json +1 -3
  19. package/src/data-access/http/README.md +50 -0
  20. package/src/data-access/http/facebook.native.js +122 -144
  21. package/src/data-access/http/instagram.native.js +113 -93
  22. package/src/data-access/http/linkedin.native.js +144 -83
  23. package/src/data-access/http/threads.native.js +58 -27
  24. package/src/data-access/http/tiktok.native.js +19 -39
  25. package/src/data-access/http/twitter.native.js +145 -65
  26. package/src/data-access/http/youtube.native.js +21 -40
  27. package/dist/cjs/lib/hiddenComment.helper.js +0 -119
  28. package/dist/esm/lib/hiddenComment.helper.js +0 -112
  29. package/src/lib/hiddenComment.helper.js +0 -107
@@ -1,5 +1,5 @@
1
1
  import superagent from 'superagent';
2
- import { loggerDebug, loggerError, loggerInfo } from '../../lib/logger.helpers.js';
2
+ import { loggerDebug, loggerInfo, MeltwaterAttributes } from '../../lib/logger.helpers.js';
3
3
 
4
4
 
5
5
  const LINKEDIN_API = "https://api.linkedin.com/v2";
@@ -33,7 +33,13 @@ export async function like(token, externalId, socialAccountId, logger) {
33
33
  { response: JSON.stringify(response) }
34
34
  );
35
35
  } catch (err) {
36
- loggerError(logger,`Linkedin Like or Unlike Exception`, err);
36
+ loggerInfo(logger, `Failed to call linkedin api - like`, {
37
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
38
+ externalId,
39
+ socialAccountId,
40
+ error: err?.message,
41
+ }),
42
+ });
37
43
  throw err;
38
44
  }
39
45
  return response.connection || response;
@@ -67,7 +73,13 @@ export async function unlike(token, externalId, socialAccountId, logger) {
67
73
  { response: JSON.stringify(response) }
68
74
  );
69
75
  } catch (err) {
70
- loggerError(logger,`Linkedin Like or Unlike Exception`, err);
76
+ loggerInfo(logger, `Failed to call linkedin api - unlike`, {
77
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
78
+ externalId,
79
+ socialAccountId,
80
+ error: err?.message,
81
+ }),
82
+ });
71
83
  throw err;
72
84
  }
73
85
  return response.connection || response;
@@ -101,8 +113,14 @@ export async function deleteMessage(token, externalId, sourceId, inReplyToId, lo
101
113
  { response: JSON.stringify(response) }
102
114
  );
103
115
  } catch (err) {
104
- loggerError(logger,`Linkedin Delete exception details`, {
105
- err,
116
+ loggerInfo(logger, `Failed to call linkedin api - deleteMessage`, {
117
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
118
+ externalId,
119
+ commentId,
120
+ inReplyToId,
121
+ sourceId,
122
+ error: err?.message,
123
+ }),
106
124
  });
107
125
  throw err;
108
126
  }
@@ -264,10 +282,14 @@ async function publish(token,discussionType, mediaId,inReplyToId,socialAccountId
264
282
  }
265
283
 
266
284
  } catch (err) {
267
- loggerError(logger,
268
- `Exception in linkedin publish `,
269
- err
270
- );
285
+ loggerInfo(logger, `Failed to call linkedin api - publish`, {
286
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
287
+ inReplyToId,
288
+ discussionType,
289
+ socialAccountId,
290
+ error: err?.response?.body?.message ?? err?.message,
291
+ }),
292
+ });
271
293
  throw err;
272
294
  }
273
295
 
@@ -297,17 +319,25 @@ async function getImageMedia(mediaId, token, logger) {
297
319
  'LinkedIn-Version': LINKEDIN_VERSION,
298
320
  });
299
321
  } catch (error) {
300
- loggerError(logger,'Error in getImageMedia', error);
322
+ loggerInfo(logger, `Failed to call linkedin api - getImageMedia`, {
323
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
324
+ mediaId,
325
+ error: error?.message,
326
+ }),
327
+ });
328
+ throw error;
301
329
  }
302
330
 
303
331
  let { downloadUrl } = response.body || {};
304
332
  if (downloadUrl) {
305
333
  return { downloadUrl };
306
334
  } else {
307
- loggerError(logger,
308
- `Invalid response getting Linkedin media for mediaId: ${mediaId} `,
309
- { response: JSON.stringify(response) }
310
- );
335
+ loggerInfo(logger, `Failed to call linkedin api - getImageMedia bad status`, {
336
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
337
+ mediaId,
338
+ responseBody: response.body,
339
+ }),
340
+ });
311
341
  return {};
312
342
  }
313
343
  }
@@ -346,17 +376,25 @@ export async function getVideoMedia(mediaId, token, logger) {
346
376
  'LinkedIn-Version': LINKEDIN_VERSION,
347
377
  });
348
378
  } catch (error) {
349
- loggerError(logger, 'Error in getVideoMedia', error);
379
+ loggerInfo(logger, `Failed to call linkedin api - getVideoMedia`, {
380
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
381
+ mediaId,
382
+ error: error?.message,
383
+ }),
384
+ });
385
+ throw error;
350
386
  }
351
387
 
352
388
  let { thumbnail, downloadUrl } = response.body || {};
353
389
  if (downloadUrl) {
354
390
  return { thumbnail, downloadUrl };
355
391
  } else {
356
- loggerError(logger,
357
- `Invalid response getting Linkedin media for mediaId: ${mediaId} `,
358
- { response: JSON.stringify(response) }
359
- );
392
+ loggerInfo(logger, `Failed to call linkedin api - getVideoMedia bad status`, {
393
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
394
+ mediaId,
395
+ responseBody: response.body,
396
+ }),
397
+ });
360
398
  return {};
361
399
  }
362
400
  }
@@ -367,34 +405,30 @@ export async function getMedia(token, mediaId, type, logger) {
367
405
  type = 'image/jpeg';
368
406
  }
369
407
 
370
- try {
371
- if (type.includes('image')) {
372
- const { downloadUrl } = await getImageMedia(
373
- mediaId,
374
- token,
375
- logger
376
- );
377
-
378
- return {
379
- downloadUrl,
380
- };
381
- } else if (type.includes('video')) {
382
- const { thumbnail, downloadUrl } = await getVideoMedia(
383
- mediaId,
384
- token,
385
- logger
386
- );
408
+ if (type.includes('image')) {
409
+ const { downloadUrl } = await getImageMedia(
410
+ mediaId,
411
+ token,
412
+ logger
413
+ );
387
414
 
388
- return {
389
- thumbnail,
390
- downloadUrl,
391
- };
392
- }
415
+ return {
416
+ downloadUrl,
417
+ };
418
+ } else if (type.includes('video')) {
419
+ const { thumbnail, downloadUrl } = await getVideoMedia(
420
+ mediaId,
421
+ token,
422
+ logger
423
+ );
393
424
 
394
- return {};
395
- } catch (error) {
396
- loggerError(logger,'Error in getMedia', error);
425
+ return {
426
+ thumbnail,
427
+ downloadUrl,
428
+ };
397
429
  }
430
+
431
+ return {};
398
432
  }
399
433
 
400
434
  export async function mediaUploadURL(
@@ -428,10 +462,13 @@ export async function mediaUploadURL(
428
462
  };
429
463
  return response;
430
464
  } catch (err) {
431
- loggerError(logger,
432
- `Exception linkedin media register `,
433
- err
434
- );
465
+ loggerInfo(logger, `Failed to call linkedin api - mediaUploadURL`, {
466
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
467
+ socialAccountId,
468
+ error: err?.response?.body?.message ?? err?.message,
469
+ }),
470
+ });
471
+ throw err;
435
472
  }
436
473
  }
437
474
 
@@ -454,11 +491,13 @@ export async function getProfile(urn, token, logger) {
454
491
  })
455
492
  .then((result) => result.body);
456
493
  } catch (error) {
457
- loggerError(logger,
458
- `Failed requesting LinkedIn API for profileId ${urn}`,
459
- error
460
- );
461
- return;
494
+ loggerInfo(logger, `Failed to call linkedin api - getProfile`, {
495
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
496
+ urn,
497
+ error: error?.message,
498
+ }),
499
+ });
500
+ throw error;
462
501
  }
463
502
 
464
503
  loggerInfo( logger,
@@ -492,10 +531,13 @@ export async function getOrganization(urn, token, logger) {
492
531
  return { id: 'private' };
493
532
  }
494
533
 
495
- loggerError(logger,
496
- `Failed requesting LinkedIn API for organizationId ${urn}`,
497
- error
498
- );
534
+ loggerInfo(logger, `Failed to call linkedin api - getOrganization`, {
535
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
536
+ urn,
537
+ error: error?.message,
538
+ }),
539
+ });
540
+ throw error;
499
541
  }
500
542
  loggerInfo(logger,
501
543
  `Finished requesting LinkedIn API for organizationId ${urn}`
@@ -517,7 +559,13 @@ export async function getMediaFromUrl(token, url, logger) {
517
559
 
518
560
  return response;
519
561
  } catch (error) {
520
- loggerError(logger,'Error in getMediaFromUrl', error);
562
+ loggerInfo(logger, `Failed to call linkedin api - getMediaFromUrl`, {
563
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
564
+ url,
565
+ error: error?.message,
566
+ }),
567
+ });
568
+ throw error;
521
569
  }
522
570
  }
523
571
 
@@ -540,10 +588,14 @@ export async function getOrganizations(urn, token, logger) {
540
588
  return res.results[id];
541
589
  });
542
590
  } catch (error) {
543
- loggerError(logger,
544
- `Failed requesting LinkedIn API for organization id ${id}`,
545
- error
546
- );
591
+ loggerInfo(logger, `Failed to call linkedin api - getOrganizations`, {
592
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
593
+ urn,
594
+ id,
595
+ error: error?.message,
596
+ }),
597
+ });
598
+ throw error;
547
599
  }
548
600
 
549
601
  loggerInfo(logger,
@@ -570,37 +622,41 @@ async function getAllStats(externalId, token, logger) {
570
622
  'LinkedIn-Version': LINKEDIN_VERSION,
571
623
  });
572
624
  } catch (error) {
573
- loggerError(logger,'Error in getAllStats', error);
625
+ loggerInfo(logger, `Failed to call linkedin api - getAllStats`, {
626
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
627
+ externalId,
628
+ error: error?.message,
629
+ }),
630
+ });
631
+ throw error;
574
632
  }
575
633
 
576
634
  let { commentSummary, reactionSummaries } = response.body || {};
577
635
  if (commentSummary && reactionSummaries) {
578
636
  return { commentSummary, reactionSummaries };
579
637
  } else {
580
- loggerError( logger,
581
- `Invalid response getting all Linkedin Stats for externalId: ${externalId}`,
582
- { response: JSON.stringify(response) }
583
- );
638
+ loggerInfo(logger, `Failed to call linkedin api - getAllStats bad status`, {
639
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
640
+ externalId,
641
+ responseBody: response.body,
642
+ }),
643
+ });
584
644
  return {};
585
645
  }
586
646
  }
587
647
 
588
648
  export async function getSocialStats(externalId, token, logger) {
589
- try {
590
- // get all stats (likes are not to be trusted) seems to only work
591
- // for og posts.
592
- const {
593
- commentSummary,
594
- reactionSummaries,
595
- } = await getAllStats(externalId, token, logger);
596
-
597
- return {
598
- commentSummary,
599
- reactionSummaries,
600
- };
601
- } catch (error) {
602
- loggerError(logger,'Error in getSocialStats', error);
603
- }
649
+ // get all stats (likes are not to be trusted) seems to only work
650
+ // for og posts.
651
+ const {
652
+ commentSummary,
653
+ reactionSummaries,
654
+ } = await getAllStats(externalId, token, logger);
655
+
656
+ return {
657
+ commentSummary,
658
+ reactionSummaries,
659
+ };
604
660
  }
605
661
 
606
662
  export async function likedByUser(
@@ -644,7 +700,12 @@ export async function uploadMedia(query, logger) {
644
700
  })
645
701
  .send(data)
646
702
  .catch((err) => {
647
- loggerError(logger,"Linkedin Error uploading Media",err);
703
+ loggerInfo(logger, `Failed to call linkedin api - uploadMedia`, {
704
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
705
+ url,
706
+ error: err?.message,
707
+ }),
708
+ });
648
709
  throw err;
649
710
  });
650
711
  }
@@ -2,8 +2,8 @@ import superagent from 'superagent';
2
2
  import { removePrefix } from '../../lib/externalId.helpers.js';
3
3
  import {
4
4
  loggerDebug,
5
- loggerError,
6
5
  loggerInfo,
6
+ MeltwaterAttributes,
7
7
  } from '../../lib/logger.helpers.js';
8
8
 
9
9
  const THREADS_URL = 'https://graph.threads.net/v1.0';
@@ -86,11 +86,12 @@ async function confirmCreationId(accessToken, creationId, logger) {
86
86
  logger
87
87
  );
88
88
  } catch (error) {
89
- loggerError(
90
- logger,
91
- `Creation ID ${creationId} confirmation failed: ${error.message}`,
92
- error
93
- );
89
+ loggerInfo(logger, `Failed to call threads api - confirmCreationId`, {
90
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
91
+ creationId,
92
+ error: error?.message,
93
+ }),
94
+ });
94
95
  error.code = 408; // Request Timeout
95
96
  throw error;
96
97
  }
@@ -105,25 +106,37 @@ async function confirmCreationId(accessToken, creationId, logger) {
105
106
  * @throws {Error} If the request fails.
106
107
  */
107
108
  async function sendRequest(apiUrl, params, logger) {
109
+ let response;
108
110
  try {
109
- const response = await superagent
111
+ response = await superagent
110
112
  .get(apiUrl)
111
113
  .set('Accept', 'application/json')
112
114
  .set('Content-Type', 'application/json')
113
115
  .query(params)
114
116
  .send();
115
-
116
- if (response.status !== 200) {
117
- throw new Error(`Unexpected response status: ${response.status}`);
118
- }
119
-
120
- loggerDebug(logger, 'Threads Response status', response.status);
121
- return response;
122
117
  } catch (err) {
123
- const errorMessage = err?.response?.body?.error?.message || err.message;
124
- loggerError(logger, `Failed to call Threads API: ${errorMessage}`, err);
118
+ loggerInfo(logger, `Failed to call threads api - sendRequest`, {
119
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
120
+ apiUrl,
121
+ error: err?.response?.body?.error?.message ?? err?.message,
122
+ }),
123
+ });
125
124
  throw err;
126
125
  }
126
+
127
+ if (response.status !== 200) {
128
+ loggerInfo(logger, `Failed to call threads api - sendRequest bad status`, {
129
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
130
+ apiUrl,
131
+ status: response.status,
132
+ responseBody: response.body,
133
+ }),
134
+ });
135
+ throw new Error(`Unexpected response status: ${response.status}`);
136
+ }
137
+
138
+ loggerDebug(logger, 'Threads Response status', response.status);
139
+ return response;
127
140
  }
128
141
 
129
142
  /**
@@ -135,25 +148,37 @@ async function sendRequest(apiUrl, params, logger) {
135
148
  * @throws {Error} If the request fails.
136
149
  */
137
150
  async function requestApi(apiUrl, params, logger) {
151
+ let response;
138
152
  try {
139
- const response = await superagent
153
+ response = await superagent
140
154
  .post(apiUrl)
141
155
  .set('Accept', 'application/json')
142
156
  .set('Content-Type', 'application/json')
143
157
  .query(params)
144
158
  .send();
145
-
146
- if (response.status !== 200) {
147
- throw new Error(`Unexpected response status: ${response.status}`);
148
- }
149
-
150
- loggerDebug(logger, 'Threads Response status', response.status);
151
- return response;
152
159
  } catch (err) {
153
- const errorMessage = err?.response?.body?.error?.message || err.message;
154
- loggerError(logger, `Failed to call Threads API: ${errorMessage}`, err);
160
+ loggerInfo(logger, `Failed to call threads api - requestApi`, {
161
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
162
+ apiUrl,
163
+ error: err?.response?.body?.error?.message ?? err?.message,
164
+ }),
165
+ });
155
166
  throw err;
156
167
  }
168
+
169
+ if (response.status !== 200) {
170
+ loggerInfo(logger, `Failed to call threads api - requestApi bad status`, {
171
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
172
+ apiUrl,
173
+ status: response.status,
174
+ responseBody: response.body,
175
+ }),
176
+ });
177
+ throw new Error(`Unexpected response status: ${response.status}`);
178
+ }
179
+
180
+ loggerDebug(logger, 'Threads Response status', response.status);
181
+ return response;
157
182
  }
158
183
 
159
184
  /**
@@ -355,7 +380,13 @@ async function constructReplyQuery(
355
380
 
356
381
  return { ...query, creation_id: containerResponse.body.id };
357
382
  } catch (error) {
358
- loggerError(logger, 'Error constructing reply query', error);
383
+ loggerInfo(logger, `Failed to call threads api - constructReplyQuery`, {
384
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
385
+ inReplyToId,
386
+ isQuote,
387
+ error: error?.message,
388
+ }),
389
+ });
359
390
  throw error;
360
391
  }
361
392
  }
@@ -1,5 +1,5 @@
1
1
  import superagent from 'superagent';
2
- import { loggerError, MeltwaterAttributes } from '../../lib/logger.helpers.js';
2
+ import { loggerInfo, MeltwaterAttributes } from '../../lib/logger.helpers.js';
3
3
  import { removePrefix } from '../../lib/externalId.helpers.js';
4
4
 
5
5
  const TIKTOK_API_URL =
@@ -244,30 +244,22 @@ async function sendRequest(token, paramString = '', logger) {
244
244
  .set('Access-Token', token)
245
245
  .send();
246
246
  } catch (err) {
247
- if (
248
- err &&
249
- err.response &&
250
- err.response.body &&
251
- err.response.body.error
252
- ) {
253
- loggerError(
254
- logger,
255
- `Failed to call tiktok api for paramString ${paramString}: ${err.response.body.error.message}`
256
- );
257
- } else {
258
- loggerError(
259
- logger,
260
- `Failed to call tiktok api for paramString ${paramString}`,
261
- err
262
- );
263
- }
264
-
247
+ loggerInfo(logger, 'Failed to call tiktok api - sendRequest', {
248
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
249
+ paramString,
250
+ error: err?.response?.body?.error?.message ?? err?.message,
251
+ }),
252
+ });
265
253
  throw err;
266
254
  }
267
255
 
268
256
  if (response.status !== 200) {
269
- loggerError(logger, `Failed to call tiktok api`, {
270
- [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify(response.body),
257
+ loggerInfo(logger, 'Failed to call tiktok api - sendRequest', {
258
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
259
+ paramString,
260
+ status: response.status,
261
+ body: response.body,
262
+ }),
271
263
  });
272
264
  let error = new Error(`Failed to call tiktok api`);
273
265
  error.code = response.status;
@@ -287,24 +279,12 @@ async function sendPost(token, paramString = '', postData = undefined, logger) {
287
279
  .set('Access-Token', token)
288
280
  .send(postData);
289
281
  } catch (err) {
290
- if (
291
- err &&
292
- err.response &&
293
- err.response.body &&
294
- err.response.body.error
295
- ) {
296
- loggerError(
297
- logger,
298
- `Failed to call tiktok api for paramString ${paramString}: ${err.response.body.error.message}`
299
- );
300
- } else {
301
- loggerError(
302
- logger,
303
- `Failed to call tiktok api for paramString ${paramString}`,
304
- err
305
- );
306
- }
307
-
282
+ loggerInfo(logger, 'Failed to call tiktok api - sendPost', {
283
+ [MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
284
+ paramString,
285
+ error: err?.response?.body?.error?.message ?? err?.message,
286
+ }),
287
+ });
308
288
  throw err;
309
289
  }
310
290