@meltwater/conversations-api-services 1.0.19 → 1.0.21

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 (70) hide show
  1. package/.github/workflows/release.yml +2 -0
  2. package/babel.config.js +18 -0
  3. package/dist/cjs/data-access/http/InstagramVideoClient.js +42 -0
  4. package/dist/cjs/data-access/http/WarpZoneApi.client.js +32 -0
  5. package/dist/cjs/data-access/http/amazonS3.js +44 -0
  6. package/dist/cjs/data-access/http/asset-manager-tvm.client.js +35 -0
  7. package/dist/cjs/data-access/http/companiesApi.client.js +38 -0
  8. package/dist/cjs/data-access/http/credentialsApi.client.js +102 -0
  9. package/dist/cjs/data-access/http/entitlementsApi.client.js +40 -0
  10. package/dist/cjs/data-access/http/facebook.native.js +344 -0
  11. package/dist/cjs/data-access/http/facebookApi.client.js +631 -0
  12. package/dist/cjs/data-access/http/featureToggleApi.client.js +31 -0
  13. package/dist/cjs/data-access/http/identityServices.client.js +97 -0
  14. package/dist/cjs/data-access/http/instagramApi.client.js +428 -0
  15. package/dist/cjs/data-access/http/ir.client.js +242 -0
  16. package/dist/cjs/data-access/http/linkedInApi.client.js +491 -0
  17. package/dist/cjs/data-access/http/masf.client.js +101 -0
  18. package/dist/cjs/data-access/http/tiktok.native.js +162 -0
  19. package/dist/cjs/data-access/http/tiktokApi.client.js +441 -0
  20. package/dist/cjs/data-access/index.js +132 -0
  21. package/dist/cjs/errors/engage-error.js +16 -0
  22. package/dist/cjs/errors/http-error.js +23 -0
  23. package/dist/cjs/lib/applicationTags.helpers.js +30 -0
  24. package/dist/cjs/lib/configuration.js +14 -0
  25. package/dist/cjs/lib/document-action-events.js +12 -0
  26. package/dist/cjs/lib/externalId.helpers.js +19 -0
  27. package/dist/cjs/lib/hidden.helpers.js +13 -0
  28. package/dist/cjs/lib/hiddenComment.helper.js +119 -0
  29. package/dist/cjs/lib/logger.helpers.js +68 -0
  30. package/dist/cjs/lib/logger.js +23 -0
  31. package/dist/cjs/lib/message.helpers.js +58 -0
  32. package/dist/cjs/lib/metrics.helper.js +97 -0
  33. package/dist/esm/data-access/http/InstagramVideoClient.js +34 -0
  34. package/dist/esm/data-access/http/WarpZoneApi.client.js +24 -0
  35. package/dist/esm/data-access/http/amazonS3.js +37 -0
  36. package/dist/esm/data-access/http/asset-manager-tvm.client.js +28 -0
  37. package/dist/esm/data-access/http/companiesApi.client.js +30 -0
  38. package/dist/esm/data-access/http/credentialsApi.client.js +92 -0
  39. package/dist/esm/data-access/http/entitlementsApi.client.js +32 -0
  40. package/dist/esm/data-access/http/facebook.native.js +325 -0
  41. package/dist/esm/data-access/http/facebookApi.client.js +621 -0
  42. package/dist/esm/data-access/http/featureToggleApi.client.js +23 -0
  43. package/dist/esm/data-access/http/identityServices.client.js +89 -0
  44. package/dist/esm/data-access/http/instagramApi.client.js +420 -0
  45. package/dist/esm/data-access/http/ir.client.js +234 -0
  46. package/dist/esm/data-access/http/linkedInApi.client.js +481 -0
  47. package/dist/esm/data-access/http/masf.client.js +93 -0
  48. package/dist/esm/data-access/http/tiktok.native.js +146 -0
  49. package/dist/esm/data-access/http/tiktokApi.client.js +433 -0
  50. package/dist/esm/data-access/index.js +30 -0
  51. package/dist/esm/errors/engage-error.js +9 -0
  52. package/dist/esm/errors/http-error.js +16 -0
  53. package/dist/esm/lib/applicationTags.helpers.js +22 -0
  54. package/dist/esm/lib/configuration.js +8 -0
  55. package/dist/esm/lib/document-action-events.js +6 -0
  56. package/dist/esm/lib/externalId.helpers.js +12 -0
  57. package/dist/esm/lib/hidden.helpers.js +6 -0
  58. package/dist/esm/lib/hiddenComment.helper.js +112 -0
  59. package/dist/esm/lib/logger.helpers.js +60 -0
  60. package/dist/esm/lib/logger.js +16 -0
  61. package/dist/esm/lib/message.helpers.js +52 -0
  62. package/dist/esm/lib/metrics.helper.js +90 -0
  63. package/package.json +14 -4
  64. package/src/data-access/http/facebook.native.js +542 -0
  65. package/src/data-access/http/tiktok.native.js +248 -0
  66. package/src/data-access/index.js +4 -0
  67. package/src/errors/engage-error.js +11 -0
  68. package/src/errors/http-error.js +19 -0
  69. package/src/lib/logger.helpers.js +15 -0
  70. package/src/lib/message.helpers.js +7 -1
@@ -0,0 +1,234 @@
1
+ import { v4 } from 'uuid';
2
+ import superagent from 'superagent';
3
+ import logger from '../../lib/logger.js';
4
+ import configuration from '../../lib/configuration.js';
5
+ import { metricN } from '../../lib/metrics.helper.js';
6
+ import { MeltwaterAttributes } from '../../lib/logger.helpers.js';
7
+ export class IRClient {
8
+ RETRY_COUNT = 50;
9
+ constructor(context) {
10
+ const {
11
+ company,
12
+ user,
13
+ traceId,
14
+ metrics
15
+ } = context;
16
+ this.company = company;
17
+ this.user = user;
18
+ this.traceId = traceId;
19
+ this.metrics = metrics;
20
+ }
21
+ async init() {
22
+ let irApiKey = configuration.get('IR_API_KEY');
23
+ this.searchServicesUrl = configuration.get('SEARCH_SERVICE_URL');
24
+ this.searchServicesKey = irApiKey;
25
+ this.documentRevisionsServiceUrl = configuration.get('DOCUMENT_REVISIONS_SERVICE_URL');
26
+ this.documentServiceUrl = configuration.get('DOCUMENT_SERVICE_URL');
27
+ this.documentServiceKey = irApiKey;
28
+ this.exportApiUrl = configuration.get('EXPORT_API_URL');
29
+ this.exportApiKey = irApiKey;
30
+ }
31
+ async addRevisionsToDocuments(operations) {
32
+ await this.init();
33
+ const wait = 100;
34
+ const url = `${this.documentRevisionsServiceUrl}/${this.company._id}/`;
35
+ const loggerChild = logger.child({
36
+ [MeltwaterAttributes.COMPANYID]: this.company._id
37
+ });
38
+ let result;
39
+ try {
40
+ result = await superagent.patch(url).query({
41
+ wait,
42
+ apikey: this.documentServiceKey
43
+ }).set('x-client-name', 'engage-conversations').send(operations).then(result => result.body);
44
+ } catch (error) {
45
+ loggerChild.error(`Failed adding a revisions with operations`, error, {
46
+ url,
47
+ [MeltwaterAttributes.COMPANYID]: this.company._id,
48
+ operations: JSON.stringify(operations)
49
+ });
50
+ return;
51
+ }
52
+ loggerChild.info(`Finished adding revision operations`, {
53
+ operations: JSON.stringify(operations)
54
+ });
55
+ return result;
56
+ }
57
+ async modifyDocuments(operations) {
58
+ let retryAttempt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
59
+ await this.init();
60
+ const wait = 100;
61
+ const url = `${this.documentServiceUrl}/`;
62
+ const loggerChild = logger.child({
63
+ [MeltwaterAttributes.COMPANYID]: this.company._id
64
+ });
65
+ let result;
66
+ try {
67
+ result = await superagent.patch(url).query({
68
+ wait,
69
+ apikey: this.documentServiceKey
70
+ }).set('x-client-name', 'engage-conversations').send(operations).then(result => result.body);
71
+ } catch (err) {
72
+ retryAttempt++;
73
+ if (retryAttempt > this.RETRY_COUNT) {
74
+ loggerChild.error(`Maximum Retrys hit for method modifyDocuments ${err.status} ${err.message}`, err, {
75
+ [MeltwaterAttributes.COMPANYID]: this.company._id
76
+ });
77
+ } else if (await this.retryBecauseRateLimiting(err, 'modifyDocuments')) {
78
+ return await this.modifyDocuments(operations, retryAttempt);
79
+ }
80
+ }
81
+ loggerChild.info(`Finished modifying documents operations`, {
82
+ operations: JSON.stringify(operations)
83
+ });
84
+ return result;
85
+ }
86
+ async getDocumentById(id) {
87
+ let retryAttempt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
88
+ await this.init();
89
+ try {
90
+ const uri = `${this.documentServiceUrl}/${id}/revisions/${this.company._id}?apikey=${this.documentServiceKey}`;
91
+ const metric = this.metrics.count(metricNames.irGetByDocumentId);
92
+ const result = await superagent.get(uri);
93
+ this.metrics.finishOperation(metricNames.irGetByDocumentId, metric);
94
+ return result.body;
95
+ } catch (err) {
96
+ retryAttempt++;
97
+ if (retryAttempt > this.RETRY_COUNT) {
98
+ logger.error(`Maximum Retrys hit for method getDocumentById ${err.status} ${err.message}`, err, {
99
+ [MeltwaterAttributes.COMPANYID]: this.company._id
100
+ });
101
+ } else if (await this.retryBecauseRateLimiting(err, 'getDocumentById')) {
102
+ return await this.getDocumentById(id, retryAttempt);
103
+ }
104
+ }
105
+ }
106
+ async retryBecauseRateLimiting(err, name) {
107
+ const loggerChild = logger.child({
108
+ [MeltwaterAttributes.COMPANYID]: this.company._id
109
+ });
110
+
111
+ // rate limit error
112
+ if (err.status === 429) {
113
+ this.metrics.count(metricNames.irRatelimited);
114
+ loggerChild.error(`Error Accessing ir.client method because rate limit: trying again ${name}`, err);
115
+ // should not be hitting rate limit in production
116
+ // this is a patch for staging testing
117
+ await new Promise(resolve => setTimeout(resolve, 100));
118
+ return true;
119
+ }
120
+ if (err.status == 404) {
121
+ loggerChild.info(`Document Not Found ir.client method ${name} ${err.status} ${err.message}`, err);
122
+ } else {
123
+ loggerChild.info(`Could not access ir.client method ${name} ${err.status} ${err.message}`, err);
124
+ }
125
+ return false;
126
+ }
127
+ async export(rune) {
128
+ await this.init();
129
+ const traceId = this.generateTraceId();
130
+ try {
131
+ let uri = `${this.exportApiUrl}?apikey=${this.exportApiKey}`;
132
+ logger.info(`Starting call to : ${this.exportApiUrl}`, {
133
+ rune
134
+ });
135
+ this.addCompanyToRuneForHorace(rune);
136
+ let result = await superagent.post(uri).query({
137
+ traceId
138
+ }).send(rune);
139
+ logger.info(`Finished calling Export API: ${result.body.exportKey}`, {
140
+ irTraceId: traceId
141
+ });
142
+ return result.body.exportKey;
143
+ } catch (err) {
144
+ logger.error('Error executing search against Export API', err);
145
+ }
146
+ }
147
+ async search(rune) {
148
+ await this.init();
149
+ const traceId = this.generateTraceId();
150
+ try {
151
+ let uri = `${this.searchServicesUrl}?apikey=${this.searchServicesKey}`;
152
+
153
+ // todo: remove changing rune searchResults size
154
+ // todo: remove reduce ( dedupes and trims to original rune limit )
155
+ // rune limit is a bandaid, hopefully better solution can be worked out with Horace
156
+ let limitActual = rune.viewRequests.searchResults.size;
157
+ rune.viewRequests.searchResults.size = limitActual * 2;
158
+ this.addCompanyToRuneForHorace(rune);
159
+ const metric = this.metrics.count(metricNames.irSearch);
160
+ let result = await superagent.post(uri).query({
161
+ traceId
162
+ }).send(rune);
163
+ this.metrics.finishOperation(metricNames.irSearch, metric);
164
+ rune.viewRequests.searchResults.size = limitActual;
165
+ const finalResults = result.body.views.searchResults.results.reduce((acc, document, index) => {
166
+ if (!index || acc.length <= limitActual && acc[acc.length - 1].documentId !== document.quiddity.id) {
167
+ acc.push(document.quiddity);
168
+ } else if (index && acc.length <= limitActual && acc[acc.length - 1].documentId === document.quiddity.id) {
169
+ logger.info(`Duplicates in IR Search Results for DocumentId`, {
170
+ irTraceId: traceId,
171
+ document: JSON.stringify(document),
172
+ [MeltwaterAttributes.DOCUMENTID]: document.quiddity.id
173
+ });
174
+ }
175
+ return acc;
176
+ }, []);
177
+ logger.info(`Final Results Calculated, ${finalResults ? finalResults.length : 'no results'}`, {
178
+ irTraceId: traceId,
179
+ rune
180
+ });
181
+ return finalResults;
182
+ // original return function
183
+ // return result.body.views.searchResults.results.map(document => {
184
+ // return document.quiddity;
185
+ // })
186
+ } catch (err) {
187
+ logger.error('Error executing search against Search Service', err, {
188
+ irTraceId: traceId,
189
+ rune
190
+ });
191
+ }
192
+ }
193
+ async latest(rune) {
194
+ let retryAttempt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
195
+ try {
196
+ const result = await this.executeSearch(rune);
197
+ return result.body.views.searchResults.results.length && [result.body.views.searchResults.results[0].quiddity] || [];
198
+ } catch (err) {
199
+ retryAttempt++;
200
+ if (retryAttempt > this.RETRY_COUNT) {
201
+ logger.error(`Maximum Retrys hit for method latest ${err.status} ${err.message}`, err, {
202
+ [MeltwaterAttributes.COMPANYID]: this.company._id
203
+ });
204
+ } else if (await this.retryBecauseRateLimiting(err, 'latest')) {
205
+ return await this.latest(rune, retryAttempt);
206
+ }
207
+ }
208
+ }
209
+ async count(rune) {
210
+ try {
211
+ const result = await this.executeSearch(rune);
212
+ return result.body.views.documentCount.totalCount;
213
+ } catch (err) {
214
+ logger.error('Error getting count from Search Service', err);
215
+ }
216
+ }
217
+ async executeSearch(rune) {
218
+ await this.init();
219
+ this.addCompanyToRuneForHorace(rune);
220
+ const uri = `${this.searchServicesUrl}?apikey=${this.searchServicesKey}`;
221
+ return await superagent.post(uri).send(rune);
222
+ }
223
+ addCompanyToRuneForHorace(rune) {
224
+ if (!rune.metaData) {
225
+ rune.metaData = {};
226
+ }
227
+
228
+ // Horace requires this for tracking purposes
229
+ rune.metaData.companyId = this.company._id;
230
+ }
231
+ generateTraceId() {
232
+ return `engage_${this.company._id}_${this.traceId}_${v4()}`;
233
+ }
234
+ }