@meltwater/conversations-api-services 1.3.2 → 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.
- package/.github/workflows/release.yml +4 -6
- package/CLAUDE.md +70 -0
- package/dist/cjs/data-access/http/facebook.native.js +122 -106
- package/dist/cjs/data-access/http/instagram.native.js +92 -49
- package/dist/cjs/data-access/http/linkedin.native.js +135 -56
- package/dist/cjs/data-access/http/threads.native.js +53 -18
- package/dist/cjs/data-access/http/tiktok.native.js +18 -12
- package/dist/cjs/data-access/http/twitter.native.js +142 -40
- package/dist/cjs/data-access/http/youtube.native.js +19 -13
- package/dist/esm/data-access/http/facebook.native.js +123 -107
- package/dist/esm/data-access/http/instagram.native.js +93 -50
- package/dist/esm/data-access/http/linkedin.native.js +136 -57
- package/dist/esm/data-access/http/threads.native.js +54 -19
- package/dist/esm/data-access/http/tiktok.native.js +19 -13
- package/dist/esm/data-access/http/twitter.native.js +143 -41
- package/dist/esm/data-access/http/youtube.native.js +20 -14
- package/package.json +1 -3
- package/src/data-access/http/README.md +50 -0
- package/src/data-access/http/facebook.native.js +122 -144
- package/src/data-access/http/instagram.native.js +113 -93
- package/src/data-access/http/linkedin.native.js +144 -83
- package/src/data-access/http/threads.native.js +58 -27
- package/src/data-access/http/tiktok.native.js +19 -39
- package/src/data-access/http/twitter.native.js +145 -65
- package/src/data-access/http/youtube.native.js +21 -40
- package/dist/cjs/lib/hiddenComment.helper.js +0 -119
- package/dist/esm/lib/hiddenComment.helper.js +0 -112
- package/src/lib/hiddenComment.helper.js +0 -107
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import superagent from 'superagent';
|
|
2
2
|
import { removePrefix } from '../../lib/externalId.helpers.js';
|
|
3
|
-
import { loggerDebug,
|
|
3
|
+
import { loggerDebug, loggerInfo, loggerWarn, MeltwaterAttributes } from '../../lib/logger.helpers.js';
|
|
4
4
|
import OAuth from 'oauth-1.0a';
|
|
5
5
|
import crypto from 'crypto';
|
|
6
6
|
import axios from 'axios';
|
|
@@ -69,7 +69,12 @@ async function makeTwitterV2Request(v2Endpoint, v1FallbackQuery, token, logger)
|
|
|
69
69
|
source: 'v1.1'
|
|
70
70
|
};
|
|
71
71
|
} catch (fallbackError) {
|
|
72
|
-
|
|
72
|
+
loggerInfo(logger, `Failed to call twitter api - makeTwitterV2Request`, {
|
|
73
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
74
|
+
v2Endpoint,
|
|
75
|
+
error: fallbackError?.message
|
|
76
|
+
})
|
|
77
|
+
});
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
return {
|
|
@@ -119,17 +124,25 @@ function normalizeUsersData(users) {
|
|
|
119
124
|
* @returns {Promise<Object>} User data from v2 API
|
|
120
125
|
*/
|
|
121
126
|
export async function getAuthenticatedUser(token, logger) {
|
|
127
|
+
const apiUrl = 'https://api.x.com/2/users/me';
|
|
122
128
|
try {
|
|
123
129
|
const result = await getRequest({
|
|
124
130
|
token,
|
|
125
|
-
uri:
|
|
131
|
+
uri: apiUrl,
|
|
126
132
|
attachUrlPrefix: false,
|
|
127
133
|
convertPayloadToUri: false,
|
|
128
134
|
logger
|
|
129
135
|
});
|
|
130
136
|
return result.data;
|
|
131
137
|
} catch (e) {
|
|
132
|
-
|
|
138
|
+
loggerInfo(logger, `Failed to call twitter api - getAuthenticatedUser`, {
|
|
139
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
140
|
+
apiUrl,
|
|
141
|
+
status: e?.response?.status,
|
|
142
|
+
responseBody: e?.response?.body,
|
|
143
|
+
error: e?.response?.body?.errors?.[0]?.message ?? e?.message
|
|
144
|
+
})
|
|
145
|
+
});
|
|
133
146
|
throw e;
|
|
134
147
|
}
|
|
135
148
|
}
|
|
@@ -173,8 +186,12 @@ export async function getUserInfoFromHandles(token, handles, logger) {
|
|
|
173
186
|
const normalizedData = normalizeUsersData(result.data, result.source);
|
|
174
187
|
return normalizedData || [];
|
|
175
188
|
} catch (e) {
|
|
176
|
-
|
|
177
|
-
|
|
189
|
+
loggerInfo(logger, `Failed to call twitter api - getUserInfoFromHandles`, {
|
|
190
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
191
|
+
error: e?.message
|
|
192
|
+
})
|
|
193
|
+
});
|
|
194
|
+
throw e;
|
|
178
195
|
}
|
|
179
196
|
}
|
|
180
197
|
export async function getUserInfoFromHandle(token, handleId, logger) {
|
|
@@ -196,7 +213,13 @@ export async function getUserInfoFromHandle(token, handleId, logger) {
|
|
|
196
213
|
throw result.error || new Error('Failed to get user info from both APIs');
|
|
197
214
|
}
|
|
198
215
|
} catch (e) {
|
|
199
|
-
|
|
216
|
+
loggerInfo(logger, `Failed to call twitter api - getUserInfoFromHandle`, {
|
|
217
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
218
|
+
handleId,
|
|
219
|
+
error: e?.message
|
|
220
|
+
})
|
|
221
|
+
});
|
|
222
|
+
throw e;
|
|
200
223
|
}
|
|
201
224
|
}
|
|
202
225
|
export async function getDirectMessageImage(token, imageUrl, logger) {
|
|
@@ -212,7 +235,12 @@ export async function getDirectMessageImage(token, imageUrl, logger) {
|
|
|
212
235
|
contentType: result.contentType
|
|
213
236
|
};
|
|
214
237
|
} catch (e) {
|
|
215
|
-
|
|
238
|
+
loggerInfo(logger, `Failed to call twitter api - getDirectMessageImage`, {
|
|
239
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
240
|
+
imageUrl,
|
|
241
|
+
error: e?.message
|
|
242
|
+
})
|
|
243
|
+
});
|
|
216
244
|
throw e;
|
|
217
245
|
}
|
|
218
246
|
}
|
|
@@ -232,7 +260,13 @@ export async function getCurrentInfo(token, externalId, logger) {
|
|
|
232
260
|
result.data.retweeted = !!result.data.current_user_retweet;
|
|
233
261
|
return result.data.data[0].public_metrics;
|
|
234
262
|
} catch (error) {
|
|
235
|
-
|
|
263
|
+
loggerInfo(logger, `Failed to call twitter api - getCurrentInfo`, {
|
|
264
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
265
|
+
externalId,
|
|
266
|
+
error: error?.message
|
|
267
|
+
})
|
|
268
|
+
});
|
|
269
|
+
throw error;
|
|
236
270
|
}
|
|
237
271
|
}
|
|
238
272
|
export async function getMentionHandleInfo(token, externalId, logger) {
|
|
@@ -247,7 +281,13 @@ export async function getMentionHandleInfo(token, externalId, logger) {
|
|
|
247
281
|
});
|
|
248
282
|
return result.data;
|
|
249
283
|
} catch (error) {
|
|
250
|
-
|
|
284
|
+
loggerInfo(logger, `Failed to call twitter api - getMentionHandleInfo`, {
|
|
285
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
286
|
+
externalId,
|
|
287
|
+
error: error?.message
|
|
288
|
+
})
|
|
289
|
+
});
|
|
290
|
+
throw error;
|
|
251
291
|
}
|
|
252
292
|
}
|
|
253
293
|
export async function retweet(token, sourceId, externalId, logger) {
|
|
@@ -268,7 +308,14 @@ export async function retweet(token, sourceId, externalId, logger) {
|
|
|
268
308
|
return false;
|
|
269
309
|
}
|
|
270
310
|
} catch (error) {
|
|
271
|
-
|
|
311
|
+
loggerInfo(logger, `Failed to call twitter api - retweet`, {
|
|
312
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
313
|
+
sourceId,
|
|
314
|
+
externalId,
|
|
315
|
+
error: error?.message
|
|
316
|
+
})
|
|
317
|
+
});
|
|
318
|
+
throw error;
|
|
272
319
|
}
|
|
273
320
|
}
|
|
274
321
|
export async function unRetweet(token, sourceId, externalId, logger) {
|
|
@@ -284,15 +331,20 @@ export async function unRetweet(token, sourceId, externalId, logger) {
|
|
|
284
331
|
return false;
|
|
285
332
|
}
|
|
286
333
|
} catch (error) {
|
|
287
|
-
|
|
288
|
-
[MeltwaterAttributes.
|
|
334
|
+
loggerInfo(logger, `Failed to call twitter api - unRetweet`, {
|
|
335
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
336
|
+
sourceId,
|
|
337
|
+
externalId,
|
|
338
|
+
error: error?.message
|
|
339
|
+
})
|
|
289
340
|
});
|
|
341
|
+
throw error;
|
|
290
342
|
}
|
|
291
343
|
}
|
|
292
344
|
export async function like(token, externalId, logger) {
|
|
345
|
+
let authenticatedUser = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
293
346
|
try {
|
|
294
|
-
|
|
295
|
-
const userInfo = await getAuthenticatedUser(token, logger);
|
|
347
|
+
const userInfo = authenticatedUser ?? (await getAuthenticatedUser(token, logger));
|
|
296
348
|
const userId = userInfo.data.id;
|
|
297
349
|
let response = await postRequest({
|
|
298
350
|
token,
|
|
@@ -313,14 +365,19 @@ export async function like(token, externalId, logger) {
|
|
|
313
365
|
return false;
|
|
314
366
|
}
|
|
315
367
|
} catch (error) {
|
|
316
|
-
|
|
368
|
+
loggerInfo(logger, `Failed to call twitter api - like`, {
|
|
369
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
370
|
+
externalId,
|
|
371
|
+
error: error?.message
|
|
372
|
+
})
|
|
373
|
+
});
|
|
317
374
|
throw error;
|
|
318
375
|
}
|
|
319
376
|
}
|
|
320
377
|
export async function unLike(token, externalId, logger) {
|
|
378
|
+
let authenticatedUser = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
321
379
|
try {
|
|
322
|
-
|
|
323
|
-
const userInfo = await getAuthenticatedUser(token, logger);
|
|
380
|
+
const userInfo = authenticatedUser ?? (await getAuthenticatedUser(token, logger));
|
|
324
381
|
const userId = userInfo.data.id;
|
|
325
382
|
let response = await deleteRequest({
|
|
326
383
|
token,
|
|
@@ -335,14 +392,19 @@ export async function unLike(token, externalId, logger) {
|
|
|
335
392
|
return false;
|
|
336
393
|
}
|
|
337
394
|
} catch (error) {
|
|
338
|
-
|
|
395
|
+
loggerInfo(logger, `Failed to call twitter api - unLike`, {
|
|
396
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
397
|
+
externalId,
|
|
398
|
+
error: error?.message
|
|
399
|
+
})
|
|
400
|
+
});
|
|
339
401
|
throw error;
|
|
340
402
|
}
|
|
341
403
|
}
|
|
342
404
|
export async function followUser(token, profileId, logger) {
|
|
405
|
+
let authenticatedUser = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
343
406
|
try {
|
|
344
|
-
|
|
345
|
-
const userInfo = await getAuthenticatedUser(token, logger);
|
|
407
|
+
const userInfo = authenticatedUser ?? (await getAuthenticatedUser(token, logger));
|
|
346
408
|
const userId = userInfo.data.id;
|
|
347
409
|
let response = await postRequest({
|
|
348
410
|
token,
|
|
@@ -360,13 +422,19 @@ export async function followUser(token, profileId, logger) {
|
|
|
360
422
|
return false;
|
|
361
423
|
}
|
|
362
424
|
} catch (error) {
|
|
363
|
-
|
|
425
|
+
loggerInfo(logger, `Failed to call twitter api - followUser`, {
|
|
426
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
427
|
+
profileId,
|
|
428
|
+
error: error?.message
|
|
429
|
+
})
|
|
430
|
+
});
|
|
431
|
+
throw error;
|
|
364
432
|
}
|
|
365
433
|
}
|
|
366
434
|
export async function unFollowUser(token, profileId, logger) {
|
|
435
|
+
let authenticatedUser = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
367
436
|
try {
|
|
368
|
-
|
|
369
|
-
const userInfo = await getAuthenticatedUser(token, logger);
|
|
437
|
+
const userInfo = authenticatedUser ?? (await getAuthenticatedUser(token, logger));
|
|
370
438
|
const userId = userInfo.data.id;
|
|
371
439
|
let response = await deleteRequest({
|
|
372
440
|
token,
|
|
@@ -381,13 +449,19 @@ export async function unFollowUser(token, profileId, logger) {
|
|
|
381
449
|
return false;
|
|
382
450
|
}
|
|
383
451
|
} catch (error) {
|
|
384
|
-
|
|
452
|
+
loggerInfo(logger, `Failed to call twitter api - unFollowUser`, {
|
|
453
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
454
|
+
profileId,
|
|
455
|
+
error: error?.message
|
|
456
|
+
})
|
|
457
|
+
});
|
|
458
|
+
throw error;
|
|
385
459
|
}
|
|
386
460
|
}
|
|
387
461
|
export async function userFollowStatus(token, profileId, logger) {
|
|
462
|
+
let authenticatedUser = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
388
463
|
try {
|
|
389
|
-
|
|
390
|
-
const userInfo = await getAuthenticatedUser(token, logger);
|
|
464
|
+
const userInfo = authenticatedUser ?? (await getAuthenticatedUser(token, logger));
|
|
391
465
|
const userId = userInfo.data.id;
|
|
392
466
|
|
|
393
467
|
// Check if authenticated user is following the target user
|
|
@@ -419,7 +493,7 @@ export async function userFollowStatus(token, profileId, logger) {
|
|
|
419
493
|
if (error.message != 'Bad Request') {
|
|
420
494
|
// if we hit a minor rate limit here, we wait for 5 seconds before attempting again, usually long enough to continue
|
|
421
495
|
await new Promise(r => setTimeout(r, 5000));
|
|
422
|
-
return userFollowStatus(token, profileId, logger);
|
|
496
|
+
return userFollowStatus(token, profileId, logger, authenticatedUser);
|
|
423
497
|
}
|
|
424
498
|
}
|
|
425
499
|
}
|
|
@@ -478,7 +552,14 @@ export async function getBrandUserRelationship(token, profileId, brandProfileId,
|
|
|
478
552
|
}
|
|
479
553
|
};
|
|
480
554
|
} catch (error) {
|
|
481
|
-
|
|
555
|
+
loggerInfo(logger, `Failed to call twitter api - getBrandUserRelationship`, {
|
|
556
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
557
|
+
profileId,
|
|
558
|
+
brandProfileId,
|
|
559
|
+
error: error?.message
|
|
560
|
+
})
|
|
561
|
+
});
|
|
562
|
+
throw error;
|
|
482
563
|
}
|
|
483
564
|
}
|
|
484
565
|
export async function createTweet(token, text, attachment, logger) {
|
|
@@ -690,7 +771,6 @@ async function publishTweet(token, payload, query, isDirectMessage, logger) {
|
|
|
690
771
|
);
|
|
691
772
|
return normalizedResponse;
|
|
692
773
|
} catch (err) {
|
|
693
|
-
loggerError(logger, `Twitter publish exception details`, err);
|
|
694
774
|
throw err;
|
|
695
775
|
}
|
|
696
776
|
}
|
|
@@ -723,7 +803,6 @@ async function publishDirectMessage(token, payload, query, logger) {
|
|
|
723
803
|
const normalizedResponse = normalizeTwitterResponse(response, 'dm', logger);
|
|
724
804
|
return normalizedResponse;
|
|
725
805
|
} catch (err) {
|
|
726
|
-
loggerError(logger, `Twitter DM send failed`, err);
|
|
727
806
|
throw err;
|
|
728
807
|
}
|
|
729
808
|
}
|
|
@@ -844,10 +923,14 @@ async function doRequest(_ref5) {
|
|
|
844
923
|
});
|
|
845
924
|
return reject(e);
|
|
846
925
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
926
|
+
loggerInfo(logger, `Failed to call twitter api - doRequest`, {
|
|
927
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
928
|
+
url,
|
|
929
|
+
convertPayloadToUri,
|
|
930
|
+
payload: JSON.stringify(payload),
|
|
931
|
+
status: e?.response?.status,
|
|
932
|
+
error: e?.response?.body?.errors?.[0]?.message ?? e?.message
|
|
933
|
+
})
|
|
851
934
|
});
|
|
852
935
|
reject(e);
|
|
853
936
|
}
|
|
@@ -917,7 +1000,6 @@ async function uploadMedia(attachment, token, discussionType, logger) {
|
|
|
917
1000
|
return mediaIdString;
|
|
918
1001
|
}
|
|
919
1002
|
} catch (e) {
|
|
920
|
-
loggerError(logger, `Failed uploading media`, e);
|
|
921
1003
|
if (filePath) {
|
|
922
1004
|
removeMedia(filePath, logger);
|
|
923
1005
|
}
|
|
@@ -952,7 +1034,13 @@ async function simpleMediaUpload(fileData, mimeType, mediaCategory, token, logge
|
|
|
952
1034
|
});
|
|
953
1035
|
return result.body.media_id_string;
|
|
954
1036
|
} catch (e) {
|
|
955
|
-
|
|
1037
|
+
loggerInfo(logger, `Failed to call twitter api - simpleMediaUpload`, {
|
|
1038
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
1039
|
+
mimeType,
|
|
1040
|
+
mediaCategory,
|
|
1041
|
+
error: e?.message
|
|
1042
|
+
})
|
|
1043
|
+
});
|
|
956
1044
|
throw e;
|
|
957
1045
|
}
|
|
958
1046
|
}
|
|
@@ -1009,7 +1097,6 @@ async function chunkedMediaUpload(filePath, fileSize, mimeType, mediaCategory, t
|
|
|
1009
1097
|
}
|
|
1010
1098
|
return mediaId;
|
|
1011
1099
|
} catch (e) {
|
|
1012
|
-
loggerError(logger, 'Error in chunked media upload', e);
|
|
1013
1100
|
throw e;
|
|
1014
1101
|
}
|
|
1015
1102
|
}
|
|
@@ -1060,7 +1147,12 @@ async function mediaUploadRequest(params, token, logger) {
|
|
|
1060
1147
|
const result = await request;
|
|
1061
1148
|
return result.body;
|
|
1062
1149
|
} catch (e) {
|
|
1063
|
-
|
|
1150
|
+
loggerInfo(logger, `Failed to call twitter api - mediaUploadRequest`, {
|
|
1151
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
1152
|
+
command: params.command,
|
|
1153
|
+
error: e?.message
|
|
1154
|
+
})
|
|
1155
|
+
});
|
|
1064
1156
|
throw e;
|
|
1065
1157
|
}
|
|
1066
1158
|
}
|
|
@@ -1101,10 +1193,20 @@ function removeMedia(file, logger) {
|
|
|
1101
1193
|
try {
|
|
1102
1194
|
fs.unlink(file, function (err) {
|
|
1103
1195
|
if (err) {
|
|
1104
|
-
|
|
1196
|
+
loggerInfo(logger, `Failed to call twitter api - removeMedia`, {
|
|
1197
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
1198
|
+
file,
|
|
1199
|
+
error: err?.message
|
|
1200
|
+
})
|
|
1201
|
+
});
|
|
1105
1202
|
}
|
|
1106
1203
|
});
|
|
1107
1204
|
} catch (e) {
|
|
1108
|
-
|
|
1205
|
+
loggerInfo(logger, `Failed to call twitter api - removeMedia`, {
|
|
1206
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
1207
|
+
file,
|
|
1208
|
+
error: e?.message
|
|
1209
|
+
})
|
|
1210
|
+
});
|
|
1109
1211
|
}
|
|
1110
1212
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import superagent from 'superagent';
|
|
2
2
|
import { removePrefix } from '../../lib/externalId.helpers.js';
|
|
3
|
-
import {
|
|
3
|
+
import { loggerInfo, MeltwaterAttributes } from '../../lib/logger.helpers.js';
|
|
4
4
|
const YOUTUBE_API_URL = "https://www.googleapis.com/youtube/v3/";
|
|
5
5
|
async function sendPost(token) {
|
|
6
6
|
let paramString = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
|
|
@@ -10,11 +10,12 @@ async function sendPost(token) {
|
|
|
10
10
|
try {
|
|
11
11
|
response = await superagent.post(YOUTUBE_API_URL + paramString).set('Accept', 'application/json').set('Content-Type', 'application/json').set('Authorization', `Bearer ${token}`).send(postData);
|
|
12
12
|
} catch (err) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
loggerInfo(logger, 'Failed to call youtube api - sendPost', {
|
|
14
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
15
|
+
paramString,
|
|
16
|
+
error: err?.response?.body?.error?.message ?? err?.message
|
|
17
|
+
})
|
|
18
|
+
});
|
|
18
19
|
throw err;
|
|
19
20
|
}
|
|
20
21
|
return response;
|
|
@@ -26,18 +27,23 @@ export async function sendRequest(token) {
|
|
|
26
27
|
try {
|
|
27
28
|
response = await superagent.get(YOUTUBE_API_URL + paramString).set('Accept', 'application/json').set('Content-Type', 'application/json').set('Authorization', `Bearer ${token}`).send();
|
|
28
29
|
} catch (err) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
loggerInfo(logger, 'Failed to call youtube api - sendRequest', {
|
|
31
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
32
|
+
paramString,
|
|
33
|
+
error: err?.response?.body?.error?.message ?? err?.message
|
|
34
|
+
})
|
|
35
|
+
});
|
|
34
36
|
throw err;
|
|
35
37
|
}
|
|
36
38
|
if (response.status !== 200) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
loggerInfo(logger, 'Failed to call youtube api - sendRequest', {
|
|
40
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
41
|
+
paramString,
|
|
42
|
+
status: response.status,
|
|
43
|
+
body: response.body
|
|
44
|
+
})
|
|
39
45
|
});
|
|
40
|
-
let error = new Error(`Failed to call
|
|
46
|
+
let error = new Error(`Failed to call youtube api`);
|
|
41
47
|
error.code = response.status;
|
|
42
48
|
throw error;
|
|
43
49
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meltwater/conversations-api-services",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Repository to contain all conversations api services shared across our services",
|
|
5
5
|
"main": "dist/cjs/data-access/index.js",
|
|
6
6
|
"module": "dist/esm/data-access/index.js",
|
|
@@ -39,8 +39,6 @@
|
|
|
39
39
|
"@hapi/joi": "^17.1.1",
|
|
40
40
|
"@meltwater/date-range": "^3.6.0",
|
|
41
41
|
"@meltwater/engage-conversations-schemas": "^2.3.10",
|
|
42
|
-
"@meltwater/xrunes": "^1.1.1",
|
|
43
|
-
"@meltwater/xrunes-core": "^3.0.2",
|
|
44
42
|
"apollo-server-hapi": "^3.13.0",
|
|
45
43
|
"aws-sdk": "^2.1562.0",
|
|
46
44
|
"dataloader": "^2.2.2",
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Native API HTTP Modules
|
|
2
|
+
|
|
3
|
+
Files matching `*.native.js` in this directory are thin HTTP clients for third-party social platform APIs (Instagram, Facebook, Twitter, LinkedIn, TikTok, YouTube, Threads). We do not control these APIs.
|
|
4
|
+
|
|
5
|
+
## Logging contract
|
|
6
|
+
|
|
7
|
+
Because external API failures are expected and noisy, these modules follow a strict logging convention:
|
|
8
|
+
|
|
9
|
+
- **No `loggerError`** — use `loggerInfo` for all failures
|
|
10
|
+
- **`loggerWarn`** is allowed for known/expected failure cases
|
|
11
|
+
- **Every log must include a `PAYLOADDATA` block** — structured context that makes the log searchable and useful without being noisy
|
|
12
|
+
|
|
13
|
+
### Pattern
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
loggerInfo(logger, 'Failed to call <platform> api', {
|
|
17
|
+
[MeltwaterAttributes.PAYLOADDATA]: JSON.stringify({
|
|
18
|
+
apiUrl, // endpoint called (no tokens in the URL)
|
|
19
|
+
someId, // relevant IDs
|
|
20
|
+
status, // HTTP status if available
|
|
21
|
+
error: err?.response?.body?.error ?? err?.message,
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Rules for PAYLOADDATA contents
|
|
27
|
+
|
|
28
|
+
| Include | Exclude |
|
|
29
|
+
|---|---|
|
|
30
|
+
| API URL (path only, no credentials) | `accessToken`, `token`, any keys |
|
|
31
|
+
| IDs: `externalId`, `sourceId`, `inReplyToId`, etc. | Raw `err` objects |
|
|
32
|
+
| Operation params: `discussionType`, `hideStatus`, `fields`, etc. | Stack traces |
|
|
33
|
+
| HTTP `status` and `responseBody` on non-200 | |
|
|
34
|
+
| `error: err?.response?.body?.error ?? err?.message` | |
|
|
35
|
+
|
|
36
|
+
## Reference implementation
|
|
37
|
+
|
|
38
|
+
See [instagram.native.js](./instagram.native.js) for a fully converted example.
|
|
39
|
+
|
|
40
|
+
## Files
|
|
41
|
+
|
|
42
|
+
| File | Platform |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `instagram.native.js` | Instagram Graph API |
|
|
45
|
+
| `facebook.native.js` | Facebook Graph API |
|
|
46
|
+
| `twitter.native.js` | Twitter/X API |
|
|
47
|
+
| `linkedin.native.js` | LinkedIn API |
|
|
48
|
+
| `tiktok.native.js` | TikTok API |
|
|
49
|
+
| `youtube.native.js` | YouTube Data API |
|
|
50
|
+
| `threads.native.js` | Threads API |
|