@devrev/ts-adaas 0.0.2 → 1.0.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/README.md +186 -116
- package/dist/common/constants.d.ts +10 -0
- package/dist/common/constants.js +27 -0
- package/dist/common/control-protocol.d.ts +7 -0
- package/dist/common/control-protocol.js +41 -0
- package/dist/common/helpers.d.ts +4 -0
- package/dist/common/helpers.js +38 -0
- package/dist/common/install-initial-domain-mapping.d.ts +3 -0
- package/dist/common/install-initial-domain-mapping.js +87 -0
- package/dist/{src → deprecated}/adapter/index.d.ts +10 -7
- package/dist/{src → deprecated}/adapter/index.js +13 -10
- package/dist/{src → deprecated}/common/helpers.d.ts +1 -2
- package/dist/deprecated/common/helpers.js +47 -0
- package/dist/deprecated/demo-extractor/external_domain_metadata.json +38 -0
- package/dist/deprecated/demo-extractor/index.d.ts +17 -0
- package/dist/deprecated/demo-extractor/index.js +161 -0
- package/dist/{src → deprecated}/uploader/index.d.ts +1 -1
- package/dist/{src → deprecated}/uploader/index.js +3 -1
- package/dist/{src/http → http}/client.d.ts +2 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +30 -0
- package/dist/logger/logger.d.ts +14 -0
- package/dist/logger/logger.interfaces.d.ts +14 -0
- package/dist/logger/logger.interfaces.js +9 -0
- package/dist/logger/logger.js +91 -0
- package/dist/logger/logger.test.js +49 -0
- package/dist/repo/repo.d.ts +14 -0
- package/dist/repo/repo.interfaces.d.ts +43 -0
- package/dist/repo/repo.interfaces.js +2 -0
- package/dist/repo/repo.js +68 -0
- package/dist/repo/repo.test.js +74 -0
- package/dist/state/state.d.ts +24 -0
- package/dist/state/state.interfaces.d.ts +24 -0
- package/dist/state/state.interfaces.js +2 -0
- package/dist/state/state.js +115 -0
- package/dist/tests/test-helpers.d.ts +9 -0
- package/dist/tests/test-helpers.interfaces.d.ts +11 -0
- package/dist/tests/test-helpers.interfaces.js +2 -0
- package/dist/tests/test-helpers.js +88 -0
- package/dist/tests/test-worker.js +16 -0
- package/dist/types/common.d.ts +39 -0
- package/dist/{src/types → types}/common.js +4 -0
- package/dist/{src/types → types}/extraction.d.ts +57 -12
- package/dist/{src/types → types}/extraction.js +12 -29
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +11 -0
- package/dist/types/workers.d.ts +142 -0
- package/dist/types/workers.js +23 -0
- package/dist/uploader/uploader.d.ts +38 -0
- package/dist/uploader/uploader.interfaces.d.ts +63 -0
- package/dist/uploader/uploader.interfaces.js +2 -0
- package/dist/uploader/uploader.js +351 -0
- package/dist/{tests → uploader}/uploader.test.js +7 -5
- package/dist/workers/create-worker.d.ts +4 -0
- package/dist/workers/create-worker.js +30 -0
- package/dist/workers/create-worker.test.js +25 -0
- package/dist/workers/default-workers/attachments-deletion.d.ts +1 -0
- package/dist/workers/default-workers/attachments-deletion.js +13 -0
- package/dist/workers/default-workers/attachments-extraction.d.ts +1 -0
- package/dist/workers/default-workers/attachments-extraction.js +49 -0
- package/dist/workers/default-workers/data-deletion.d.ts +1 -0
- package/dist/workers/default-workers/data-deletion.js +15 -0
- package/dist/workers/default-workers/data-extraction.d.ts +1 -0
- package/dist/workers/default-workers/data-extraction.js +101 -0
- package/dist/workers/default-workers/external-sync-units-extraction.d.ts +1 -0
- package/dist/workers/default-workers/external-sync-units-extraction.js +27 -0
- package/dist/workers/default-workers/metadata-extraction.d.ts +1 -0
- package/dist/workers/default-workers/metadata-extraction.js +26 -0
- package/dist/workers/dummy-extractor/data-normalization.d.ts +4 -0
- package/dist/workers/dummy-extractor/data-normalization.js +41 -0
- package/dist/workers/dummy-extractor/external_domain_metadata.json +58 -0
- package/dist/workers/process-task.d.ts +2 -0
- package/dist/workers/process-task.js +44 -0
- package/dist/workers/spawn.d.ts +25 -0
- package/dist/workers/spawn.js +163 -0
- package/dist/workers/worker-adapter.d.ts +48 -0
- package/dist/workers/worker-adapter.js +138 -0
- package/dist/workers/worker.d.ts +1 -0
- package/dist/workers/worker.js +6 -0
- package/package.json +9 -5
- package/dist/src/common/constants.d.ts +0 -2
- package/dist/src/common/constants.js +0 -10
- package/dist/src/common/helpers.js +0 -59
- package/dist/src/demo-extractor/index.d.ts +0 -11
- package/dist/src/demo-extractor/index.js +0 -157
- package/dist/src/demo-extractor/initial_domain_mapping.json +0 -107
- package/dist/src/index.d.ts +0 -5
- package/dist/src/index.js +0 -21
- package/dist/src/logging/index.d.ts +0 -18
- package/dist/src/logging/index.js +0 -39
- package/dist/src/state/index.d.ts +0 -23
- package/dist/src/state/index.js +0 -111
- package/dist/src/types/common.d.ts +0 -33
- package/dist/src/types/index.d.ts +0 -2
- package/dist/src/types/index.js +0 -18
- package/dist/tests/adapter.helpers.test.js +0 -60
- package/dist/tests/adapter.test.js +0 -122
- package/dist/tests/demo-extractor.test.js +0 -60
- package/dist/tests/state.test.js +0 -100
- /package/dist/{src/http → http}/client.js +0 -0
- /package/dist/{src/http → http}/constants.d.ts +0 -0
- /package/dist/{src/http → http}/constants.js +0 -0
- /package/dist/{src/http → http}/index.d.ts +0 -0
- /package/dist/{src/http → http}/index.js +0 -0
- /package/dist/{src/http → http}/types.d.ts +0 -0
- /package/dist/{src/http → http}/types.js +0 -0
- /package/dist/{tests/adapter.helpers.test.d.ts → logger/logger.test.d.ts} +0 -0
- /package/dist/{tests/adapter.test.d.ts → repo/repo.test.d.ts} +0 -0
- /package/dist/tests/{demo-extractor.test.d.ts → test-worker.d.ts} +0 -0
- /package/dist/{tests → uploader}/uploader.test.d.ts +0 -0
- /package/dist/{tests/state.test.d.ts → workers/create-worker.test.d.ts} +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.Uploader = void 0;
|
|
30
|
+
const axios_1 = __importDefault(require("axios"));
|
|
31
|
+
const fs_1 = __importStar(require("fs"));
|
|
32
|
+
const zlib_1 = __importDefault(require("zlib"));
|
|
33
|
+
const js_jsonl_1 = require("js-jsonl");
|
|
34
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
35
|
+
const typescript_sdk_1 = require("@devrev/typescript-sdk");
|
|
36
|
+
const constants_1 = require("../common/constants");
|
|
37
|
+
const logger_1 = require("../logger/logger");
|
|
38
|
+
class Uploader {
|
|
39
|
+
constructor({ event, options }) {
|
|
40
|
+
this.event = event;
|
|
41
|
+
this.betaDevrevSdk = typescript_sdk_1.client.setupBeta({
|
|
42
|
+
endpoint: event.execution_metadata.devrev_endpoint,
|
|
43
|
+
token: event.context.secrets.service_account_token,
|
|
44
|
+
});
|
|
45
|
+
this.isLocalDevelopment = options === null || options === void 0 ? void 0 : options.isLocalDevelopment;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Uploads the fetched objects to the DevRev platform.
|
|
49
|
+
* The fetched objects are uploaded to the platform and the artifact information is returned.
|
|
50
|
+
* @param {string} filename - The name of the file to be uploaded
|
|
51
|
+
* @param {string} itemType - The type of the item to be uploaded
|
|
52
|
+
* @param {object[] | object} fetchedObjects - The fetched objects to be uploaded
|
|
53
|
+
* @returns {Promise<UploadResponse>} - The response object containing the artifact information
|
|
54
|
+
* or error information if there was an error
|
|
55
|
+
*/
|
|
56
|
+
async upload(itemType, fetchedObjects) {
|
|
57
|
+
if (this.isLocalDevelopment) {
|
|
58
|
+
this.downloadToLocal(itemType, fetchedObjects);
|
|
59
|
+
}
|
|
60
|
+
// 1. Compress the fetched objects to a gzipped jsonl object
|
|
61
|
+
const file = await this.compressGzip(js_jsonl_1.jsonl.stringify(fetchedObjects));
|
|
62
|
+
if (!file) {
|
|
63
|
+
return {
|
|
64
|
+
error: { message: 'Error while compressing jsonl object.' },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const filename = itemType + '.jsonl.gz';
|
|
68
|
+
const fileType = 'application/x-gzip';
|
|
69
|
+
// 2. Prepare the artifact for uploading
|
|
70
|
+
const preparedArtifact = await this.prepareArtifact(filename, fileType);
|
|
71
|
+
if (!preparedArtifact) {
|
|
72
|
+
return {
|
|
73
|
+
error: { message: 'Error while preparing artifact.' },
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// 3. Upload the file to the prepared artifact
|
|
77
|
+
const uploadedArtifact = await this.uploadToArtifact(preparedArtifact, file);
|
|
78
|
+
if (!uploadedArtifact) {
|
|
79
|
+
return {
|
|
80
|
+
error: { message: 'Error while uploading artifact.' },
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// 4. Return the artifact information to the platform
|
|
84
|
+
const artifact = {
|
|
85
|
+
id: preparedArtifact.id,
|
|
86
|
+
item_type: itemType,
|
|
87
|
+
item_count: Array.isArray(fetchedObjects) ? fetchedObjects.length : 1,
|
|
88
|
+
};
|
|
89
|
+
console.log('Successful upload of artifact: ', artifact);
|
|
90
|
+
return { artifact };
|
|
91
|
+
}
|
|
92
|
+
async prepareArtifact(filename, fileType) {
|
|
93
|
+
try {
|
|
94
|
+
const response = await this.betaDevrevSdk.artifactsPrepare({
|
|
95
|
+
file_name: filename,
|
|
96
|
+
file_type: fileType,
|
|
97
|
+
});
|
|
98
|
+
return response.data;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
102
|
+
console.error('Error while preparing artifact.', (0, logger_1.formatAxiosError)(error));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.error('Error while preparing artifact.', error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async uploadToArtifact(preparedArtifact, file
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
|
+
) {
|
|
112
|
+
const formData = new form_data_1.default();
|
|
113
|
+
for (const field of preparedArtifact.form_data) {
|
|
114
|
+
formData.append(field.key, field.value);
|
|
115
|
+
}
|
|
116
|
+
formData.append('file', file);
|
|
117
|
+
try {
|
|
118
|
+
const response = await axios_1.default.post(preparedArtifact.url, formData, {
|
|
119
|
+
headers: Object.assign({}, formData.getHeaders()),
|
|
120
|
+
});
|
|
121
|
+
return response;
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
125
|
+
console.error('Error while uploading artifact.', (0, logger_1.formatAxiosError)(error));
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
console.error('Error while uploading artifact.', error);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async streamToArtifact(preparedArtifact,
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
134
|
+
fileStreamResponse) {
|
|
135
|
+
const formData = new form_data_1.default();
|
|
136
|
+
for (const field of preparedArtifact.form_data) {
|
|
137
|
+
formData.append(field.key, field.value);
|
|
138
|
+
}
|
|
139
|
+
formData.append('file', fileStreamResponse.data);
|
|
140
|
+
try {
|
|
141
|
+
const response = await axios_1.default.post(preparedArtifact.url, formData, {
|
|
142
|
+
headers: Object.assign(Object.assign({}, formData.getHeaders()), (!fileStreamResponse.headers['content-length'] && {
|
|
143
|
+
'Content-Length': constants_1.MAX_DEVREV_ARTIFACT_SIZE,
|
|
144
|
+
})),
|
|
145
|
+
});
|
|
146
|
+
return response;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
150
|
+
console.error('Error while streaming artifact.', (0, logger_1.formatAxiosError)(error));
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.error('Error while streaming artifact.', error);
|
|
154
|
+
}
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Streams the attachments to the DevRev platform.
|
|
160
|
+
* The attachments are streamed to the platform and the artifact information is returned.
|
|
161
|
+
* @param {string} attachmentsMetadataArtifactId - The artifact ID of the attachments metadata
|
|
162
|
+
* @returns {Promise<UploadResponse>} - The response object containing the ssoAttachment artifact information
|
|
163
|
+
* or error information if there was an error
|
|
164
|
+
*/
|
|
165
|
+
async streamAttachments({ attachmentsMetadataArtifactId, }) {
|
|
166
|
+
console.log('Started streaming attachments to the platform.');
|
|
167
|
+
// 1. Get the URL of the attachments metadata artifact
|
|
168
|
+
const artifactUrl = await this.getArtifactDownloadUrl(attachmentsMetadataArtifactId);
|
|
169
|
+
if (!artifactUrl) {
|
|
170
|
+
return {
|
|
171
|
+
error: { message: 'Error while getting artifact download URL.' },
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// 2. Download artifact from the URL
|
|
175
|
+
const gzippedJsonlObject = await this.downloadArtifact(artifactUrl);
|
|
176
|
+
if (!gzippedJsonlObject) {
|
|
177
|
+
return {
|
|
178
|
+
error: { message: 'Error while downloading gzipped jsonl object.' },
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// 3. Decompress the gzipped jsonl object
|
|
182
|
+
const jsonlObject = await this.decompressGzip(gzippedJsonlObject);
|
|
183
|
+
if (!jsonlObject) {
|
|
184
|
+
return {
|
|
185
|
+
error: { message: 'Error while decompressing gzipped jsonl object.' },
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
// 4. Parse the jsonl object to get the attachment metadata
|
|
189
|
+
const jsonObject = (await this.parseJsonl(jsonlObject));
|
|
190
|
+
if (!jsonObject) {
|
|
191
|
+
return {
|
|
192
|
+
error: { message: 'Error while parsing jsonl object.' },
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
// 5. Stream each attachment to the platform, and push the ssorAttachment to the ssorAttachments array
|
|
196
|
+
const ssorAttachments = [];
|
|
197
|
+
for (const attachmentMetadata of jsonObject) {
|
|
198
|
+
const { ssorAttachment, error } = await this.stream(attachmentMetadata);
|
|
199
|
+
if (error || !ssorAttachment) {
|
|
200
|
+
console.warn('Error while streaming attachment', error);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
ssorAttachments.push(ssorAttachment);
|
|
204
|
+
}
|
|
205
|
+
if (!ssorAttachments.length) {
|
|
206
|
+
console.warn('No attachments were streamed to the platform.');
|
|
207
|
+
return {
|
|
208
|
+
error: { message: 'No attachments were streamed to the platform.' },
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return { ssorAttachments };
|
|
212
|
+
}
|
|
213
|
+
async getArtifactDownloadUrl(artifactId) {
|
|
214
|
+
try {
|
|
215
|
+
const response = await this.betaDevrevSdk.artifactsLocate({
|
|
216
|
+
id: artifactId,
|
|
217
|
+
});
|
|
218
|
+
return response.data.url;
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
console.error('Error while getting artifact download URL.', error);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async downloadArtifact(artifactUrl) {
|
|
225
|
+
try {
|
|
226
|
+
const response = await axios_1.default.get(artifactUrl, {
|
|
227
|
+
responseType: 'arraybuffer',
|
|
228
|
+
});
|
|
229
|
+
return response.data;
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
233
|
+
console.error('Error while downloading artifact from URL.', (0, logger_1.formatAxiosError)(error));
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
console.error('Error while downloading artifact from URL.', error);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async compressGzip(jsonlObject) {
|
|
241
|
+
try {
|
|
242
|
+
return zlib_1.default.gzipSync(jsonlObject);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
console.error('Error while compressing jsonl object.', error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async decompressGzip(gzippedJsonlObject) {
|
|
249
|
+
try {
|
|
250
|
+
const jsonlObject = await zlib_1.default.gunzipSync(gzippedJsonlObject);
|
|
251
|
+
return jsonlObject.toString();
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
console.error('Error while decompressing gzipped jsonl object.', error);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async parseJsonl(jsonlObject) {
|
|
258
|
+
try {
|
|
259
|
+
return js_jsonl_1.jsonl.parse(jsonlObject);
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
console.error('Error while parsing jsonl object.', error);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
async stream(attachmentMetadata) {
|
|
266
|
+
var _a;
|
|
267
|
+
const { id: externalId, file_name: filename, url, parent_id: parentId, author_id: actorId, } = attachmentMetadata;
|
|
268
|
+
const fileStreamResponse = await this.getFileStreamResponse(url);
|
|
269
|
+
if (!fileStreamResponse) {
|
|
270
|
+
return {
|
|
271
|
+
error: { message: 'Error while fetching attachment from URL' },
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const fileType = ((_a = fileStreamResponse.headers) === null || _a === void 0 ? void 0 : _a['content-type']) ||
|
|
275
|
+
'application/octet-stream';
|
|
276
|
+
const preparedArtifact = await this.prepareArtifact(filename, fileType);
|
|
277
|
+
if (!preparedArtifact) {
|
|
278
|
+
return {
|
|
279
|
+
error: { message: 'Error while preparing artifact.' },
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const uploadedArtifact = await this.streamToArtifact(preparedArtifact, fileStreamResponse);
|
|
283
|
+
if (!uploadedArtifact) {
|
|
284
|
+
return {
|
|
285
|
+
error: { message: 'Error while streaming artifact.' },
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
const ssorAttachment = {
|
|
289
|
+
id: {
|
|
290
|
+
devrev: preparedArtifact.id,
|
|
291
|
+
external: externalId,
|
|
292
|
+
},
|
|
293
|
+
parent_id: {
|
|
294
|
+
external: parentId,
|
|
295
|
+
},
|
|
296
|
+
actor_id: {
|
|
297
|
+
external: actorId,
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
console.log('Successful stream of attachment: ', ssorAttachment);
|
|
301
|
+
return { ssorAttachment };
|
|
302
|
+
}
|
|
303
|
+
async getFileStreamResponse(url) {
|
|
304
|
+
try {
|
|
305
|
+
const fileStreamResponse = await axios_1.default.get(url, {
|
|
306
|
+
responseType: 'stream',
|
|
307
|
+
headers: {
|
|
308
|
+
Authorization: this.event.payload.connection_data.key,
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
return fileStreamResponse;
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
315
|
+
console.error('Error while fetching attachment from URL.', (0, logger_1.formatAxiosError)(error));
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
console.error('Error while fetching attachment from URL.', error);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async downloadToLocal(itemType, fetchedObjects) {
|
|
323
|
+
console.log(`Downloading ${itemType} to local file system.`);
|
|
324
|
+
try {
|
|
325
|
+
if (!fs_1.default.existsSync('extracted_files')) {
|
|
326
|
+
fs_1.default.mkdirSync('extracted_files');
|
|
327
|
+
}
|
|
328
|
+
const timestamp = new Date().getTime();
|
|
329
|
+
const filePath = `extracted_files/extractor_${itemType}_${timestamp}.${itemType === 'external_domain_metadata' ? 'json' : 'jsonl'}`;
|
|
330
|
+
const fileHandle = await fs_1.promises.open(filePath, 'w');
|
|
331
|
+
let objArray = [];
|
|
332
|
+
if (!Array.isArray(fetchedObjects)) {
|
|
333
|
+
objArray.push(fetchedObjects);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
objArray = fetchedObjects;
|
|
337
|
+
}
|
|
338
|
+
for (const jsonObject of objArray) {
|
|
339
|
+
const jsonLine = JSON.stringify(jsonObject) + '\n';
|
|
340
|
+
await fileHandle.write(jsonLine);
|
|
341
|
+
}
|
|
342
|
+
await fileHandle.close();
|
|
343
|
+
console.log('Data successfully written to', filePath);
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
console.error('Error writing data to file.', error);
|
|
347
|
+
return Promise.reject(error);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
exports.Uploader = Uploader;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
3
|
+
const test_helpers_1 = require("../tests/test-helpers");
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const uploader_1 = require("./uploader");
|
|
4
6
|
// mock uploader.upload method
|
|
5
|
-
jest.mock('
|
|
7
|
+
jest.mock('./uploader', () => {
|
|
6
8
|
return {
|
|
7
9
|
Uploader: jest.fn().mockImplementation(() => {
|
|
8
10
|
return {
|
|
@@ -15,12 +17,12 @@ jest.mock('../src/uploader', () => {
|
|
|
15
17
|
};
|
|
16
18
|
});
|
|
17
19
|
describe('uploader.ts', () => {
|
|
18
|
-
const
|
|
20
|
+
const mockEvent = (0, test_helpers_1.createEvent)({ eventType: types_1.EventType.ExtractionDataStart });
|
|
21
|
+
const uploader = new uploader_1.Uploader({ event: mockEvent });
|
|
19
22
|
it('should upload the file to the DevRev platform and return the artifact information', async () => {
|
|
20
|
-
const filename = 'filename';
|
|
21
23
|
const entity = 'entity';
|
|
22
24
|
const fetchedObjects = [{ key: 'value' }];
|
|
23
|
-
const uploadResponse = await uploader.upload(
|
|
25
|
+
const uploadResponse = await uploader.upload(entity, fetchedObjects);
|
|
24
26
|
expect(uploadResponse).toEqual({
|
|
25
27
|
artifact: { key: 'value' },
|
|
26
28
|
error: undefined,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWorker = createWorker;
|
|
4
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
5
|
+
const workers_1 = require("../types/workers");
|
|
6
|
+
const logger_1 = require("../logger/logger");
|
|
7
|
+
async function createWorker(workerData) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
if (node_worker_threads_1.isMainThread) {
|
|
10
|
+
const logger = new logger_1.Logger(workerData.event);
|
|
11
|
+
const workerFile = __dirname + '/worker.js';
|
|
12
|
+
const worker = new node_worker_threads_1.Worker(workerFile, {
|
|
13
|
+
workerData,
|
|
14
|
+
});
|
|
15
|
+
worker.on(workers_1.WorkerEvent.WorkerError, (error) => {
|
|
16
|
+
logger.error('Worker error', error);
|
|
17
|
+
reject(error);
|
|
18
|
+
});
|
|
19
|
+
worker.on(workers_1.WorkerEvent.WorkerOnline, () => {
|
|
20
|
+
resolve(worker);
|
|
21
|
+
logger.info('Worker is online. Started processing the task with event type: ' +
|
|
22
|
+
workerData.event.payload.event_type +
|
|
23
|
+
'.');
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
reject(new Error('Worker threads can not start more worker threads.'));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const worker_threads_1 = require("worker_threads");
|
|
4
|
+
const test_helpers_1 = require("../tests/test-helpers");
|
|
5
|
+
const extraction_1 = require("../types/extraction");
|
|
6
|
+
const create_worker_1 = require("./create-worker");
|
|
7
|
+
describe('createWorker function', () => {
|
|
8
|
+
it('should return a Worker instance when a valid worker script is found', async () => {
|
|
9
|
+
const workerPath = __dirname + '../tests/dummy-worker.ts';
|
|
10
|
+
const worker = worker_threads_1.isMainThread
|
|
11
|
+
? await (0, create_worker_1.createWorker)({
|
|
12
|
+
event: (0, test_helpers_1.createEvent)({
|
|
13
|
+
eventType: extraction_1.EventType.ExtractionExternalSyncUnitsStart,
|
|
14
|
+
}),
|
|
15
|
+
initialState: {},
|
|
16
|
+
workerPath,
|
|
17
|
+
})
|
|
18
|
+
: null;
|
|
19
|
+
expect(worker).not.toBeNull();
|
|
20
|
+
expect(worker).toBeInstanceOf(worker_threads_1.Worker);
|
|
21
|
+
if (worker) {
|
|
22
|
+
await worker.terminate();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../../index");
|
|
4
|
+
(0, index_1.processTask)({
|
|
5
|
+
task: async ({ adapter }) => {
|
|
6
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionAttachmentsDeleteDone);
|
|
7
|
+
},
|
|
8
|
+
onTimeout: async ({ adapter }) => {
|
|
9
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionAttachmentsDeleteError, {
|
|
10
|
+
error: { message: 'Failed to delete attachments. Lambda timeout.' },
|
|
11
|
+
});
|
|
12
|
+
},
|
|
13
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../../index");
|
|
4
|
+
const uploader_1 = require("../../uploader/uploader");
|
|
5
|
+
const repos = [
|
|
6
|
+
{
|
|
7
|
+
itemType: 'ssor_attachment',
|
|
8
|
+
},
|
|
9
|
+
];
|
|
10
|
+
(0, index_1.processTask)({
|
|
11
|
+
task: async ({ adapter }) => {
|
|
12
|
+
var _a, _b, _c, _d, _e;
|
|
13
|
+
if (!((_a = adapter.state.toDevRev) === null || _a === void 0 ? void 0 : _a.attachmentsMetadata.artifactIds) ||
|
|
14
|
+
adapter.state.toDevRev.attachmentsMetadata.artifactIds.length === 0) {
|
|
15
|
+
console.log('No attachments to extract, skipping.');
|
|
16
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionAttachmentsDone);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
adapter.initializeRepos(repos);
|
|
20
|
+
const uploader = new uploader_1.Uploader({
|
|
21
|
+
event: adapter.event,
|
|
22
|
+
options: adapter.options,
|
|
23
|
+
});
|
|
24
|
+
for (const attachmentsMetadataArtifactId of (_b = adapter.state.toDevRev) === null || _b === void 0 ? void 0 : _b.attachmentsMetadata.artifactIds) {
|
|
25
|
+
const { ssorAttachments, error } = await uploader.streamAttachments({
|
|
26
|
+
attachmentsMetadataArtifactId,
|
|
27
|
+
});
|
|
28
|
+
if (error || !ssorAttachments) {
|
|
29
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionAttachmentsError, {
|
|
30
|
+
error,
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
await ((_c = adapter.getRepo('ssor_attachment')) === null || _c === void 0 ? void 0 : _c.push(ssorAttachments));
|
|
35
|
+
(_d = adapter.state.toDevRev) === null || _d === void 0 ? void 0 : _d.attachmentsMetadata.artifactIds.shift();
|
|
36
|
+
adapter.state.toDevRev.attachmentsMetadata.lastProcessed = 0;
|
|
37
|
+
if (((_e = adapter.state.toDevRev) === null || _e === void 0 ? void 0 : _e.attachmentsMetadata.artifactIds.length) === 0) {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionAttachmentsDone);
|
|
42
|
+
},
|
|
43
|
+
onTimeout: async ({ adapter }) => {
|
|
44
|
+
await adapter.postState();
|
|
45
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionAttachmentsProgress, {
|
|
46
|
+
progress: 50,
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../../index");
|
|
4
|
+
(0, index_1.processTask)({
|
|
5
|
+
task: async ({ adapter }) => {
|
|
6
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionDataDeleteDone);
|
|
7
|
+
},
|
|
8
|
+
onTimeout: async ({ adapter }) => {
|
|
9
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionDataDeleteError, {
|
|
10
|
+
error: {
|
|
11
|
+
message: 'Failed to delete data. Lambda timeout.',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../../index");
|
|
4
|
+
const data_normalization_1 = require("../dummy-extractor/data-normalization");
|
|
5
|
+
// Dummy data that originally would be fetched from an external source
|
|
6
|
+
const issues = [
|
|
7
|
+
{
|
|
8
|
+
id: 'issue-1',
|
|
9
|
+
created_date: '1999-12-25T01:00:03+01:00',
|
|
10
|
+
modified_date: '1999-12-25T01:00:03+01:00',
|
|
11
|
+
body: '<p>This is issue 1</p>',
|
|
12
|
+
creator: 'user-1',
|
|
13
|
+
owner: 'user-1',
|
|
14
|
+
title: 'Issue 1',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'issue-2',
|
|
18
|
+
created_date: '1999-12-27T15:31:34+01:00',
|
|
19
|
+
modified_date: '2002-04-09T01:55:31+02:00',
|
|
20
|
+
body: '<p>This is issue 2</p>',
|
|
21
|
+
creator: 'user-2',
|
|
22
|
+
owner: 'user-2',
|
|
23
|
+
title: 'Issue 2',
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
const users = [
|
|
27
|
+
{
|
|
28
|
+
id: 'user-1',
|
|
29
|
+
created_date: '1999-12-25T01:00:03+01:00',
|
|
30
|
+
modified_date: '1999-12-25T01:00:03+01:00',
|
|
31
|
+
data: {
|
|
32
|
+
email: 'johndoe@test.com',
|
|
33
|
+
name: 'John Doe',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'user-2',
|
|
38
|
+
created_date: '1999-12-27T15:31:34+01:00',
|
|
39
|
+
modified_date: '2002-04-09T01:55:31+02:00',
|
|
40
|
+
data: {
|
|
41
|
+
email: 'janedoe@test.com',
|
|
42
|
+
name: 'Jane Doe',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
const attachments = [
|
|
47
|
+
{
|
|
48
|
+
url: 'https://app.dev.devrev-eng.ai/favicon.ico',
|
|
49
|
+
id: 'attachment-1',
|
|
50
|
+
file_name: 'dummy.jpg',
|
|
51
|
+
author_id: 'user-1',
|
|
52
|
+
parent_id: 'issue-1',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
url: 'https://app.dev.devrev-eng.ai/favicon.ico',
|
|
56
|
+
id: 'attachment-2',
|
|
57
|
+
file_name: 'dummy.ico',
|
|
58
|
+
author_id: 'user-2',
|
|
59
|
+
parent_id: 'issue-2',
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
const repos = [
|
|
63
|
+
{
|
|
64
|
+
itemType: 'issues',
|
|
65
|
+
normalize: data_normalization_1.normalizeIssue,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
itemType: 'users',
|
|
69
|
+
normalize: data_normalization_1.normalizeUser,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
itemType: 'attachments',
|
|
73
|
+
normalize: data_normalization_1.normalizeAttachment,
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
(0, index_1.processTask)({
|
|
77
|
+
task: async ({ adapter }) => {
|
|
78
|
+
var _a, _b, _c;
|
|
79
|
+
console.log('Logging something from worker thread', {});
|
|
80
|
+
adapter.initializeRepos(repos);
|
|
81
|
+
if (adapter.event.payload.event_type === index_1.EventType.ExtractionDataStart) {
|
|
82
|
+
await ((_a = adapter.getRepo('issues')) === null || _a === void 0 ? void 0 : _a.push(issues));
|
|
83
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionDataProgress, {
|
|
84
|
+
progress: 50,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
await ((_b = adapter.getRepo('users')) === null || _b === void 0 ? void 0 : _b.push(users));
|
|
89
|
+
await ((_c = adapter.getRepo('attachments')) === null || _c === void 0 ? void 0 : _c.push(attachments));
|
|
90
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionDataDone, {
|
|
91
|
+
progress: 100,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
onTimeout: async ({ adapter }) => {
|
|
96
|
+
await adapter.postState();
|
|
97
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionDataProgress, {
|
|
98
|
+
progress: 50,
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../../index");
|
|
4
|
+
// Dummy data that originally would be fetched from an external source
|
|
5
|
+
const externalSyncUnits = [
|
|
6
|
+
{
|
|
7
|
+
id: 'devrev',
|
|
8
|
+
name: 'devrev',
|
|
9
|
+
description: 'Demo external sync unit',
|
|
10
|
+
item_count: 2,
|
|
11
|
+
item_type: 'issues',
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
(0, index_1.processTask)({
|
|
15
|
+
task: async ({ adapter }) => {
|
|
16
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionExternalSyncUnitsDone, {
|
|
17
|
+
external_sync_units: externalSyncUnits,
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
onTimeout: async ({ adapter }) => {
|
|
21
|
+
await adapter.emit(index_1.ExtractorEventType.ExtractionExternalSyncUnitsError, {
|
|
22
|
+
error: {
|
|
23
|
+
message: 'Failed to extract external sync units. Lambda timeout.',
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|