@devrev/ts-adaas 1.1.5 → 1.2.0-beta

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 (34) hide show
  1. package/README.md +44 -2
  2. package/dist/common/constants.d.ts +1 -1
  3. package/dist/common/constants.js +3 -3
  4. package/dist/common/helpers.d.ts +3 -3
  5. package/dist/common/helpers.js +9 -5
  6. package/dist/deprecated/uploader/index.js +20 -13
  7. package/dist/http/axios-devrev-client.d.ts +3 -0
  8. package/dist/http/axios-devrev-client.js +37 -0
  9. package/dist/http/client.js +17 -7
  10. package/dist/repo/repo.d.ts +1 -1
  11. package/dist/repo/repo.js +25 -28
  12. package/dist/tests/from_devrev/loading.test.js +17 -5
  13. package/dist/tests/test-worker.js +0 -2
  14. package/dist/types/extraction.d.ts +3 -1
  15. package/dist/types/extraction.js +3 -1
  16. package/dist/types/index.d.ts +1 -1
  17. package/dist/types/loading.d.ts +34 -5
  18. package/dist/types/loading.js +6 -0
  19. package/dist/types/workers.d.ts +2 -2
  20. package/dist/uploader/uploader.d.ts +1 -1
  21. package/dist/uploader/uploader.js +38 -24
  22. package/dist/workers/default-workers/delete-loader-attachment-state.d.ts +1 -0
  23. package/dist/workers/default-workers/delete-loader-attachment-state.js +15 -0
  24. package/dist/workers/default-workers/delete-loader-state.d.ts +1 -0
  25. package/dist/workers/default-workers/delete-loader-state.js +15 -0
  26. package/dist/workers/default-workers/load-attachments.d.ts +1 -0
  27. package/dist/workers/default-workers/load-attachments.js +19 -0
  28. package/dist/workers/default-workers/load-data.d.ts +1 -0
  29. package/dist/workers/default-workers/load-data.js +19 -0
  30. package/dist/workers/process-task.js +1 -1
  31. package/dist/workers/spawn.js +22 -18
  32. package/dist/workers/worker-adapter.d.ts +11 -1
  33. package/dist/workers/worker-adapter.js +133 -73
  34. package/package.json +2 -2
package/README.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Release Notes
4
4
 
5
+ ### v1.2.0
6
+
7
+ - Add support for loading attachments from DevRev to external system.
8
+
9
+ ### v1.1.6
10
+
11
+ - Add exponential retry and handle rate-limiting towards DevRev.
12
+ - Gracefully handle failure to upload extracted attachments.
13
+
5
14
  ### v1.1.5
6
15
 
7
16
  - Increase `delayFactor` and number of retries for the exponential backoff retry mechanism for HTTP requests.
@@ -302,9 +311,9 @@ export interface NormalizedAttachment {
302
311
 
303
312
  ## Loading phases
304
313
 
305
- ### 1. Data Loading
314
+ ### 1. Loading Data
306
315
 
307
- This phase is defined in `data-loading.ts` and is responsible for loading the data to the external system.
316
+ This phase is defined in `load-data.ts` and is responsible for loading the data to the external system.
308
317
 
309
318
  Loading is done by providing an ordered list of itemTypes to load and their respective create and update functions.
310
319
 
@@ -342,3 +351,36 @@ Loading is done by providing an ordered list of itemTypes to load and their resp
342
351
  The loading functions `create` and `update` provide loading to the external system. They provide denormalization of the records to the schema of the external system and provide HTTP calls to the external system. Both loading functions must handle rate limiting for the external system and handle errors.
343
352
 
344
353
  Functions return an ID and modified date of the record in the external system, or specify rate-liming offset or errors, if the record could not be created or updated.
354
+
355
+ ### 2. Loading Attachments
356
+
357
+ This phase is defined in `load-attachments.ts` and is responsible for loading the attachments to the external system.
358
+
359
+ Loading is done by providing the create function to create attachments in the external system.
360
+
361
+ ```typescript
362
+ processTask({
363
+ task: async ({ adapter }) => {
364
+ const { reports, processed_files } = await adapter.loadAttachments({
365
+ create,
366
+ });
367
+
368
+ await adapter.emit(LoaderEventType.AttachmentLoadingDone, {
369
+ reports,
370
+ processed_files,
371
+ });
372
+ },
373
+ onTimeout: async ({ adapter }) => {
374
+ await adapter.postState();
375
+ await adapter.emit(LoaderEventType.AttachmentLoadingProgress, {
376
+ reports: adapter.reports,
377
+ processed_files: adapter.processedFiles,
378
+ });
379
+ },
380
+ });
381
+
382
+ ```
383
+
384
+ The loading function `create` provides loading to the external system, to make API calls to the external system to create the attachments and handle errors and external system's rate limiting.
385
+
386
+ Functions return an ID and modified date of the record in the external system, specify rate-liming back-off, or log errors, if the attachment could not be created.
@@ -4,7 +4,7 @@ export declare const ALLOWED_EXTRACTION_EVENT_TYPES: EventType[];
4
4
  export declare const ALLOWED_LOADING_EVENT_TYPES: EventType[];
5
5
  export declare const ALLOWED_EVENT_TYPES: EventType[];
6
6
  export declare const ARTIFACT_BATCH_SIZE = 2000;
7
- export declare const MAX_DEVREV_ARTIFACT_SIZE = 536870912;
7
+ export declare const MAX_DEVREV_ARTIFACT_SIZE = 262144000;
8
8
  export declare const AIRDROP_DEFAULT_ITEM_TYPES: {
9
9
  EXTERNAL_DOMAIN_METADATA: string;
10
10
  ATTACHMENTS: string;
@@ -8,7 +8,7 @@ exports.STATELESS_EVENT_TYPES = [
8
8
  extraction_1.EventType.ExtractionDataDelete,
9
9
  extraction_1.EventType.ExtractionAttachmentsDelete,
10
10
  extraction_1.EventType.StartDeletingLoaderState,
11
- extraction_1.EventType.StartDeletingLoaderAttachmentsState,
11
+ extraction_1.EventType.StartDeletingLoaderAttachmentState,
12
12
  ];
13
13
  exports.ALLOWED_EXTRACTION_EVENT_TYPES = [
14
14
  extraction_1.EventType.ExtractionExternalSyncUnitsStart,
@@ -24,14 +24,14 @@ exports.ALLOWED_LOADING_EVENT_TYPES = [
24
24
  extraction_1.EventType.StartLoadingData,
25
25
  extraction_1.EventType.ContinueLoadingData,
26
26
  extraction_1.EventType.StartDeletingLoaderState,
27
- extraction_1.EventType.StartDeletingLoaderAttachmentsState,
27
+ extraction_1.EventType.StartDeletingLoaderAttachmentState,
28
28
  ];
29
29
  exports.ALLOWED_EVENT_TYPES = [
30
30
  ...exports.ALLOWED_EXTRACTION_EVENT_TYPES,
31
31
  ...exports.ALLOWED_LOADING_EVENT_TYPES,
32
32
  ];
33
33
  exports.ARTIFACT_BATCH_SIZE = 2000;
34
- exports.MAX_DEVREV_ARTIFACT_SIZE = 536870912; // 512MB
34
+ exports.MAX_DEVREV_ARTIFACT_SIZE = 262144000; // 250MB
35
35
  exports.AIRDROP_DEFAULT_ITEM_TYPES = {
36
36
  EXTERNAL_DOMAIN_METADATA: 'external_domain_metadata',
37
37
  ATTACHMENTS: 'attachments',
@@ -1,13 +1,13 @@
1
1
  import { AirdropEvent, EventType, ExtractorEventType } from '../types/extraction';
2
- import { FileToLoad, ItemTypeToLoad, LoaderEventType, LoaderReport, StatsFileObject } from '../types/loading';
2
+ import { FileToLoad, LoaderEventType, LoaderReport, StatsFileObject } from '../types/loading';
3
3
  export declare function getTimeoutErrorEventType(eventType: EventType): {
4
4
  eventType: ExtractorEventType | LoaderEventType;
5
5
  } | null;
6
6
  export declare function getSyncDirection({ event }: {
7
7
  event: AirdropEvent;
8
8
  }): string;
9
- export declare function getFilesToLoad({ itemTypesToLoad, statsFile, }: {
10
- itemTypesToLoad: ItemTypeToLoad[];
9
+ export declare function getFilesToLoad({ supportedItemTypes, statsFile, }: {
10
+ supportedItemTypes: string[];
11
11
  statsFile: StatsFileObject[];
12
12
  }): FileToLoad[];
13
13
  export declare function addReportToLoaderReport({ loaderReports, report, }: {
@@ -41,25 +41,29 @@ function getTimeoutErrorEventType(eventType) {
41
41
  eventType: loading_1.LoaderEventType.DataLoadingError,
42
42
  };
43
43
  case extraction_1.EventType.StartDeletingLoaderState:
44
- case extraction_1.EventType.StartDeletingLoaderAttachmentsState:
45
44
  return {
46
45
  eventType: loading_1.LoaderEventType.LoaderStateDeletionError,
47
46
  };
47
+ case extraction_1.EventType.StartDeletingLoaderAttachmentState:
48
+ return {
49
+ eventType: loading_1.LoaderEventType.LoaderAttachmentStateDeletionError,
50
+ };
48
51
  default:
49
52
  console.error('Event type not recognized in getTimeoutErrorEventType function: ' +
50
53
  eventType);
51
- return null;
54
+ return {
55
+ eventType: loading_1.LoaderEventType.UnknownEventType,
56
+ };
52
57
  }
53
58
  }
54
59
  function getSyncDirection({ event }) {
55
60
  return event.payload.event_context.mode;
56
61
  }
57
- function getFilesToLoad({ itemTypesToLoad, statsFile, }) {
62
+ function getFilesToLoad({ supportedItemTypes, statsFile, }) {
58
63
  const filesToLoad = [];
59
- if (itemTypesToLoad.length === 0 || statsFile.length === 0) {
64
+ if (supportedItemTypes.length === 0 || statsFile.length === 0) {
60
65
  return [];
61
66
  }
62
- const supportedItemTypes = itemTypesToLoad.map((itemTypeToLoad) => itemTypeToLoad.itemType);
63
67
  const filteredStatsFile = statsFile.filter((file) => supportedItemTypes.includes(file.item_type));
64
68
  const orderedFiles = filteredStatsFile.sort((a, b) => {
65
69
  const aIndex = supportedItemTypes.indexOf(a.item_type);
@@ -15,19 +15,26 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
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
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
28
35
  Object.defineProperty(exports, "__esModule", { value: true });
29
36
  exports.Uploader = void 0;
30
- const axios_1 = __importDefault(require("axios"));
37
+ const axios_devrev_client_1 = require("../../http/axios-devrev-client");
31
38
  const typescript_sdk_1 = require("@devrev/typescript-sdk");
32
39
  const fs_1 = __importStar(require("fs"));
33
40
  const helpers_1 = require("../common/helpers");
@@ -65,7 +72,7 @@ class Uploader {
65
72
  */
66
73
  async upload(filename, entity, fetchedObjects, filetype = 'application/jsonl+json') {
67
74
  if (this.local) {
68
- this.downloadToLocal(filename, fetchedObjects);
75
+ await this.downloadToLocal(filename, fetchedObjects);
69
76
  }
70
77
  const preparedArtifact = await this.prepareArtifact(filename, filetype);
71
78
  if (!preparedArtifact) {
@@ -111,7 +118,7 @@ class Uploader {
111
118
  ) {
112
119
  const formData = (0, helpers_1.createFormData)(preparedArtifact, fetchedObjects);
113
120
  try {
114
- const response = await axios_1.default.post(preparedArtifact.url, formData, {
121
+ const response = await axios_devrev_client_1.axiosDevRevClient.post(preparedArtifact.url, formData, {
115
122
  headers: {
116
123
  'Content-Type': 'multipart/form',
117
124
  },
@@ -0,0 +1,3 @@
1
+ import axios from 'axios';
2
+ declare const axiosDevRevClient: import("axios").AxiosInstance;
3
+ export { axios, axiosDevRevClient };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.axiosDevRevClient = exports.axios = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ exports.axios = axios_1.default;
9
+ const axios_retry_1 = __importDefault(require("axios-retry"));
10
+ const axiosDevRevClient = axios_1.default.create();
11
+ exports.axiosDevRevClient = axiosDevRevClient;
12
+ (0, axios_retry_1.default)(axiosDevRevClient, {
13
+ retries: 5,
14
+ retryDelay: (retryCount, error) => {
15
+ var _a, _b;
16
+ console.warn('Retry attempt: ' + retryCount + 'to url: ' + ((_a = error.config) === null || _a === void 0 ? void 0 : _a.url) + '.');
17
+ if (error.response) {
18
+ const retry_after = (_b = error.response) === null || _b === void 0 ? void 0 : _b.headers['retry-after'];
19
+ if (retry_after) {
20
+ return retry_after;
21
+ }
22
+ }
23
+ // Exponential backoff algorithm: 1 * 2 ^ retryCount * 1000ms
24
+ return axios_retry_1.default.exponentialDelay(retryCount, error, 1000);
25
+ },
26
+ retryCondition: (error) => {
27
+ var _a;
28
+ return (axios_retry_1.default.isNetworkOrIdempotentRequestError(error) ||
29
+ ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429);
30
+ },
31
+ onMaxRetryTimesExceeded(error, retryCount) {
32
+ var _a;
33
+ console.log(`Max retries attempted: ${retryCount}`);
34
+ (_a = error.config) === null || _a === void 0 ? true : delete _a.headers.Authorization;
35
+ delete error.request._header;
36
+ },
37
+ });
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
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
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  exports.HTTPClient = exports.defaultResponse = void 0;
27
37
  const axios_1 = __importStar(require("axios"));
@@ -10,5 +10,5 @@ export declare class Repo {
10
10
  constructor({ event, itemType, normalize, onUpload, options, }: RepoFactoryInterface);
11
11
  getItems(): (NormalizedItem | NormalizedAttachment | Item)[];
12
12
  upload(batch?: (NormalizedItem | NormalizedAttachment | Item)[]): Promise<void | ErrorRecord>;
13
- push(items: Item[]): Promise<void | ErrorRecord>;
13
+ push(items: Item[]): Promise<boolean | ErrorRecord>;
14
14
  }
package/dist/repo/repo.js CHANGED
@@ -35,36 +35,33 @@ class Repo {
35
35
  }
36
36
  }
37
37
  async push(items) {
38
- return new Promise(async (resolve, reject) => {
39
- let recordsToPush;
40
- // Normalize items if needed
41
- if (this.normalize &&
42
- this.itemType != constants_1.AIRDROP_DEFAULT_ITEM_TYPES.EXTERNAL_DOMAIN_METADATA &&
43
- this.itemType != constants_1.AIRDROP_DEFAULT_ITEM_TYPES.SSOR_ATTACHMENT) {
44
- recordsToPush = items.map((item) => this.normalize(item));
45
- }
46
- else {
47
- recordsToPush = items;
38
+ let recordsToPush;
39
+ // Normalize items if needed
40
+ if (this.normalize &&
41
+ this.itemType != constants_1.AIRDROP_DEFAULT_ITEM_TYPES.EXTERNAL_DOMAIN_METADATA &&
42
+ this.itemType != constants_1.AIRDROP_DEFAULT_ITEM_TYPES.SSOR_ATTACHMENT) {
43
+ recordsToPush = items.map((item) => this.normalize(item));
44
+ }
45
+ else {
46
+ recordsToPush = items;
47
+ }
48
+ // Add the new records to the items array
49
+ this.items.push(...recordsToPush);
50
+ console.info(`Extracted ${recordsToPush.length} new items of type ${this.itemType}. Total number of items in repo: ${this.items.length}.`);
51
+ // Upload in batches while the number of items exceeds the batch size
52
+ while (this.items.length >= constants_1.ARTIFACT_BATCH_SIZE) {
53
+ // Slice out a batch of ARTIFACT_BATCH_SIZE items to upload
54
+ const batch = this.items.splice(0, constants_1.ARTIFACT_BATCH_SIZE);
55
+ try {
56
+ // Upload the batch
57
+ await this.upload(batch);
48
58
  }
49
- // Add the new records to the items array
50
- this.items.push(...recordsToPush);
51
- console.log(`Extracted ${recordsToPush.length} new items of type ${this.itemType}. Total number of items in repo: ${this.items.length}.`);
52
- // Upload in batches while the number of items exceeds the batch size
53
- while (this.items.length >= constants_1.ARTIFACT_BATCH_SIZE) {
54
- // Slice out a batch of ARTIFACT_BATCH_SIZE items to upload
55
- const batch = this.items.splice(0, constants_1.ARTIFACT_BATCH_SIZE);
56
- try {
57
- // Upload the batch
58
- await this.upload(batch);
59
- }
60
- catch (error) {
61
- console.error('Error while uploading batch', error);
62
- reject(error);
63
- return;
64
- }
59
+ catch (error) {
60
+ console.error('Error while uploading batch', error);
61
+ return false;
65
62
  }
66
- resolve();
67
- });
63
+ }
64
+ return true;
68
65
  }
69
66
  }
70
67
  exports.Repo = Repo;
@@ -52,19 +52,28 @@ describe('getFilesToLoad', () => {
52
52
  it('should return an empty array if statsFile is empty', () => {
53
53
  statsFile = [];
54
54
  const itemTypesToLoad = [];
55
- const result = (0, helpers_1.getFilesToLoad)({ itemTypesToLoad, statsFile });
55
+ const result = (0, helpers_1.getFilesToLoad)({
56
+ supportedItemTypes: itemTypesToLoad.map((it) => it.itemType),
57
+ statsFile,
58
+ });
56
59
  expect(result).toEqual([]);
57
60
  });
58
61
  it('should return an empty array if itemTypesToLoad is empty', () => {
59
62
  const itemTypesToLoad = [];
60
- const result = (0, helpers_1.getFilesToLoad)({ itemTypesToLoad, statsFile });
63
+ const result = (0, helpers_1.getFilesToLoad)({
64
+ supportedItemTypes: itemTypesToLoad.map((it) => it.itemType),
65
+ statsFile,
66
+ });
61
67
  expect(result).toEqual([]);
62
68
  });
63
69
  it('should return an empty array if statsFile has no matching items', () => {
64
70
  const itemTypesToLoad = [
65
71
  { itemType: 'users', create: jest.fn(), update: jest.fn() },
66
72
  ];
67
- const result = (0, helpers_1.getFilesToLoad)({ itemTypesToLoad, statsFile });
73
+ const result = (0, helpers_1.getFilesToLoad)({
74
+ supportedItemTypes: itemTypesToLoad.map((it) => it.itemType),
75
+ statsFile,
76
+ });
68
77
  expect(result).toEqual([]);
69
78
  });
70
79
  it('should filter out files not in itemTypesToLoad and order them by itemTypesToLoad', () => {
@@ -72,7 +81,10 @@ describe('getFilesToLoad', () => {
72
81
  { itemType: 'attachments', create: jest.fn(), update: jest.fn() },
73
82
  { itemType: 'issues', create: jest.fn(), update: jest.fn() },
74
83
  ];
75
- const result = (0, helpers_1.getFilesToLoad)({ itemTypesToLoad, statsFile });
84
+ const result = (0, helpers_1.getFilesToLoad)({
85
+ supportedItemTypes: itemTypesToLoad.map((it) => it.itemType),
86
+ statsFile,
87
+ });
76
88
  expect(result).toEqual([
77
89
  {
78
90
  id: 'don:core:dvrv-us-1:devo/1:artifact/99',
@@ -113,7 +125,7 @@ describe('getFilesToLoad', () => {
113
125
  { itemType: 'issues', create: jest.fn(), update: jest.fn() },
114
126
  ];
115
127
  const result = (0, helpers_1.getFilesToLoad)({
116
- itemTypesToLoad,
128
+ supportedItemTypes: itemTypesToLoad.map((it) => it.itemType),
117
129
  statsFile,
118
130
  });
119
131
  expect(result).toEqual([
@@ -5,12 +5,10 @@ const extraction_1 = require("../types/extraction");
5
5
  (0, process_task_1.processTask)({
6
6
  task: async ({ adapter }) => {
7
7
  await adapter.emit(extraction_1.ExtractorEventType.ExtractionExternalSyncUnitsDone, {});
8
- return 0;
9
8
  },
10
9
  onTimeout: async ({ adapter }) => {
11
10
  await adapter.emit(extraction_1.ExtractorEventType.ExtractionExternalSyncUnitsError, {
12
11
  error: { message: 'External sync unit failed.' },
13
12
  });
14
- return 0;
15
13
  },
16
14
  });
@@ -19,8 +19,10 @@ export declare enum EventType {
19
19
  ExtractionAttachmentsDelete = "EXTRACTION_ATTACHMENTS_DELETE",
20
20
  StartLoadingData = "START_LOADING_DATA",
21
21
  ContinueLoadingData = "CONTINUE_LOADING_DATA",
22
+ StartLoadingAttachments = "START_LOADING_ATTACHMENTS",
23
+ ContinueLoadingAttachments = "CONTINUE_LOADING_ATTACHMENTS",
22
24
  StartDeletingLoaderState = "START_DELETING_LOADER_STATE",
23
- StartDeletingLoaderAttachmentsState = "START_DELETING_LOADER_ATTACHMENTS_STATE"
25
+ StartDeletingLoaderAttachmentState = "START_DELETING_LOADER_ATTACHMENT_STATE"
24
26
  }
25
27
  /**
26
28
  * ExtractorEventType is an enum that defines the different types of events that can be sent from the external extractor to ADaaS.
@@ -19,8 +19,10 @@ var EventType;
19
19
  // Loading
20
20
  EventType["StartLoadingData"] = "START_LOADING_DATA";
21
21
  EventType["ContinueLoadingData"] = "CONTINUE_LOADING_DATA";
22
+ EventType["StartLoadingAttachments"] = "START_LOADING_ATTACHMENTS";
23
+ EventType["ContinueLoadingAttachments"] = "CONTINUE_LOADING_ATTACHMENTS";
22
24
  EventType["StartDeletingLoaderState"] = "START_DELETING_LOADER_STATE";
23
- EventType["StartDeletingLoaderAttachmentsState"] = "START_DELETING_LOADER_ATTACHMENTS_STATE";
25
+ EventType["StartDeletingLoaderAttachmentState"] = "START_DELETING_LOADER_ATTACHMENT_STATE";
24
26
  })(EventType || (exports.EventType = EventType = {}));
25
27
  /**
26
28
  * ExtractorEventType is an enum that defines the different types of events that can be sent from the external extractor to ADaaS.
@@ -1,6 +1,6 @@
1
1
  export { ErrorLevel, ErrorRecord, LogRecord, AdapterUpdateParams, InitialDomainMapping, } from './common';
2
2
  export { EventType, ExtractorEventType, ExtractionMode, ExternalSyncUnit, EventContextIn, EventContextOut, ConnectionData, EventData, DomainObjectState, AirdropEvent, AirdropMessage, ExtractorEvent, SyncMode, ExternalSystemAttachmentStreamingParams, ExternalSystemAttachmentStreamingResponse, ExternalSystemAttachmentStreamingFunction, } from './extraction';
3
- export { LoaderEventType, ExternalSystemItem, ExternalSystemItemLoadingResponse, ExternalSystemItemLoadingParams, } from './loading';
3
+ export { LoaderEventType, ExternalSystemItem, ExternalSystemItemLoadingResponse, ExternalSystemItemLoadingParams, ExternalSystemAttachment, } from './loading';
4
4
  export { NormalizedItem, NormalizedAttachment, RepoInterface, } from '../repo/repo.interfaces';
5
5
  export { AdapterState } from '../state/state.interfaces';
6
6
  export { Artifact, ArtifactsPrepareResponse, UploadResponse, StreamResponse, StreamAttachmentsResponse, SsorAttachment, } from '../uploader/uploader.interfaces';
@@ -15,6 +15,29 @@ export interface FileToLoad {
15
15
  lineToProcess: number;
16
16
  completed: boolean;
17
17
  }
18
+ export interface ExternalSystemAttachment {
19
+ reference_id: DonV2;
20
+ parent_type: string;
21
+ parent_reference_id: DonV2;
22
+ file_name: string;
23
+ file_type: string;
24
+ file_size: number;
25
+ url: string;
26
+ valid_until: string;
27
+ created_by_id: string;
28
+ created_date: string;
29
+ modified_by_id: string;
30
+ modified_date: string;
31
+ }
32
+ export interface ExternalSystemItem {
33
+ id: {
34
+ devrev: DonV2;
35
+ external?: string;
36
+ };
37
+ created_date: string;
38
+ modified_date: string;
39
+ data: any;
40
+ }
18
41
  export interface ExternalSystemItem {
19
42
  id: {
20
43
  devrev: DonV2;
@@ -24,8 +47,8 @@ export interface ExternalSystemItem {
24
47
  modified_date: string;
25
48
  data: any;
26
49
  }
27
- export interface ExternalSystemItemLoadingParams {
28
- item: ExternalSystemItem;
50
+ export interface ExternalSystemItemLoadingParams<Type> {
51
+ item: Type;
29
52
  mappers: Mappers;
30
53
  event: AirdropEvent;
31
54
  }
@@ -40,11 +63,11 @@ export interface ExternalSystemItemLoadedItem {
40
63
  error?: string;
41
64
  modifiedDate?: string;
42
65
  }
43
- export type ExternalSystemLoadingFunction = ({ item, mappers, event, }: ExternalSystemItemLoadingParams) => Promise<ExternalSystemItemLoadingResponse>;
66
+ export type ExternalSystemLoadingFunction<Item> = ({ item, mappers, event, }: ExternalSystemItemLoadingParams<Item>) => Promise<ExternalSystemItemLoadingResponse>;
44
67
  export interface ItemTypeToLoad {
45
68
  itemType: string;
46
- create: ExternalSystemLoadingFunction;
47
- update: ExternalSystemLoadingFunction;
69
+ create: ExternalSystemLoadingFunction<ExternalSystemItem>;
70
+ update: ExternalSystemLoadingFunction<ExternalSystemItem>;
48
71
  }
49
72
  export interface ItemTypesToLoadParams {
50
73
  itemTypesToLoad: ItemTypeToLoad[];
@@ -89,7 +112,13 @@ export declare enum LoaderEventType {
89
112
  DataLoadingDelay = "DATA_LOADING_DELAYED",
90
113
  DataLoadingDone = "DATA_LOADING_DONE",
91
114
  DataLoadingError = "DATA_LOADING_ERROR",
115
+ AttachmentLoadingProgress = "ATTACHMENT_LOADING_PROGRESS",
116
+ AttachmentLoadingDelayed = "ATTACHMENT_LOADING_DELAYED",
117
+ AttachmentLoadingDone = "ATTACHMENT_LOADING_DONE",
118
+ AttachmentLoadingError = "ATTACHMENT_LOADING_ERROR",
92
119
  LoaderStateDeletionDone = "LOADER_STATE_DELETION_DONE",
93
120
  LoaderStateDeletionError = "LOADER_STATE_DELETION_ERROR",
121
+ LoaderAttachmentStateDeletionDone = "LOADER_ATTACHMENT_STATE_DELETION_DONE",
122
+ LoaderAttachmentStateDeletionError = "LOADER_ATTACHMENT_STATE_DELETION_ERROR",
94
123
  UnknownEventType = "UNKNOWN_EVENT_TYPE"
95
124
  }
@@ -15,7 +15,13 @@ var LoaderEventType;
15
15
  LoaderEventType["DataLoadingDelay"] = "DATA_LOADING_DELAYED";
16
16
  LoaderEventType["DataLoadingDone"] = "DATA_LOADING_DONE";
17
17
  LoaderEventType["DataLoadingError"] = "DATA_LOADING_ERROR";
18
+ LoaderEventType["AttachmentLoadingProgress"] = "ATTACHMENT_LOADING_PROGRESS";
19
+ LoaderEventType["AttachmentLoadingDelayed"] = "ATTACHMENT_LOADING_DELAYED";
20
+ LoaderEventType["AttachmentLoadingDone"] = "ATTACHMENT_LOADING_DONE";
21
+ LoaderEventType["AttachmentLoadingError"] = "ATTACHMENT_LOADING_ERROR";
18
22
  LoaderEventType["LoaderStateDeletionDone"] = "LOADER_STATE_DELETION_DONE";
19
23
  LoaderEventType["LoaderStateDeletionError"] = "LOADER_STATE_DELETION_ERROR";
24
+ LoaderEventType["LoaderAttachmentStateDeletionDone"] = "LOADER_ATTACHMENT_STATE_DELETION_DONE";
25
+ LoaderEventType["LoaderAttachmentStateDeletionError"] = "LOADER_ATTACHMENT_STATE_DELETION_ERROR";
20
26
  LoaderEventType["UnknownEventType"] = "UNKNOWN_EVENT_TYPE";
21
27
  })(LoaderEventType || (exports.LoaderEventType = LoaderEventType = {}));
@@ -79,8 +79,8 @@ export interface TaskAdapterInterface<ConnectorState> {
79
79
  * @param {function} onTimeout - The task to be executed on timeout, returns exit code
80
80
  */
81
81
  export interface ProcessTaskInterface<ConnectorState> {
82
- task: (params: TaskAdapterInterface<ConnectorState>) => void;
83
- onTimeout: (params: TaskAdapterInterface<ConnectorState>) => void;
82
+ task: (params: TaskAdapterInterface<ConnectorState>) => Promise<void>;
83
+ onTimeout: (params: TaskAdapterInterface<ConnectorState>) => Promise<void>;
84
84
  }
85
85
  /**
86
86
  * WorkerEvent represents the standard worker events.
@@ -1,7 +1,7 @@
1
- import { AxiosResponse } from 'axios';
2
1
  import { betaSDK } from '@devrev/typescript-sdk';
3
2
  import { NormalizedAttachment } from '../repo/repo.interfaces';
4
3
  import { UploadResponse, UploaderFactoryInterface } from './uploader.interfaces';
4
+ import { AxiosResponse } from 'axios';
5
5
  export declare class Uploader {
6
6
  private event;
7
7
  private betaDevrevSdk;
@@ -15,20 +15,30 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
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
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
39
  exports.Uploader = void 0;
30
40
  const fs_1 = __importStar(require("fs"));
31
- const axios_client_1 = require("../http/axios-client");
41
+ const axios_devrev_client_1 = require("../http/axios-devrev-client");
32
42
  const zlib_1 = __importDefault(require("zlib"));
33
43
  const js_jsonl_1 = require("js-jsonl");
34
44
  const form_data_1 = __importDefault(require("form-data"));
@@ -55,10 +65,10 @@ class Uploader {
55
65
  */
56
66
  async upload(itemType, fetchedObjects) {
57
67
  if (this.isLocalDevelopment) {
58
- this.downloadToLocal(itemType, fetchedObjects);
68
+ await this.downloadToLocal(itemType, fetchedObjects);
59
69
  }
60
70
  // 1. Compress the fetched objects to a gzipped jsonl object
61
- const file = await this.compressGzip(js_jsonl_1.jsonl.stringify(fetchedObjects));
71
+ const file = this.compressGzip(js_jsonl_1.jsonl.stringify(fetchedObjects));
62
72
  if (!file) {
63
73
  return {
64
74
  error: { message: 'Error while compressing jsonl object.' },
@@ -98,7 +108,7 @@ class Uploader {
98
108
  return response.data;
99
109
  }
100
110
  catch (error) {
101
- if (axios_client_1.axios.isAxiosError(error)) {
111
+ if (axios_devrev_client_1.axios.isAxiosError(error)) {
102
112
  console.error('Error while preparing artifact.', (0, logger_1.serializeAxiosError)(error));
103
113
  }
104
114
  else {
@@ -115,13 +125,13 @@ class Uploader {
115
125
  }
116
126
  formData.append('file', file);
117
127
  try {
118
- const response = await axios_client_1.axiosClient.post(preparedArtifact.url, formData, {
128
+ const response = await axios_devrev_client_1.axiosDevRevClient.post(preparedArtifact.url, formData, {
119
129
  headers: Object.assign({}, formData.getHeaders()),
120
130
  });
121
131
  return response;
122
132
  }
123
133
  catch (error) {
124
- if (axios_client_1.axios.isAxiosError(error)) {
134
+ if (axios_devrev_client_1.axios.isAxiosError(error)) {
125
135
  console.error('Error while uploading artifact.', (0, logger_1.serializeAxiosError)(error));
126
136
  }
127
137
  else {
@@ -137,8 +147,11 @@ class Uploader {
137
147
  formData.append(field.key, field.value);
138
148
  }
139
149
  formData.append('file', fileStreamResponse.data);
150
+ if (fileStreamResponse.headers['content-length'] > constants_1.MAX_DEVREV_ARTIFACT_SIZE) {
151
+ return;
152
+ }
140
153
  try {
141
- const response = await axios_client_1.axiosClient.post(preparedArtifact.url, formData, {
154
+ const response = await axios_devrev_client_1.axiosDevRevClient.post(preparedArtifact.url, formData, {
142
155
  headers: Object.assign(Object.assign({}, formData.getHeaders()), (!fileStreamResponse.headers['content-length'] && {
143
156
  'Content-Length': constants_1.MAX_DEVREV_ARTIFACT_SIZE,
144
157
  })),
@@ -146,7 +159,7 @@ class Uploader {
146
159
  return response;
147
160
  }
148
161
  catch (error) {
149
- if (axios_client_1.axios.isAxiosError(error)) {
162
+ if (axios_devrev_client_1.axios.isAxiosError(error)) {
150
163
  console.error('Error while streaming artifact.', (0, logger_1.serializeAxiosError)(error));
151
164
  }
152
165
  else {
@@ -171,14 +184,14 @@ class Uploader {
171
184
  };
172
185
  }
173
186
  // 3. Decompress the gzipped jsonl object
174
- const jsonlObject = await this.decompressGzip(gzippedJsonlObject);
187
+ const jsonlObject = this.decompressGzip(gzippedJsonlObject);
175
188
  if (!jsonlObject) {
176
189
  return {
177
190
  error: { message: 'Error while decompressing gzipped jsonl object.' },
178
191
  };
179
192
  }
180
193
  // 4. Parse the jsonl object to get the attachment metadata
181
- const jsonObject = (await this.parseJsonl(jsonlObject));
194
+ const jsonObject = this.parseJsonl(jsonlObject);
182
195
  if (!jsonObject) {
183
196
  return {
184
197
  error: { message: 'Error while parsing jsonl object.' },
@@ -199,13 +212,13 @@ class Uploader {
199
212
  }
200
213
  async downloadArtifact(artifactUrl) {
201
214
  try {
202
- const response = await axios_client_1.axiosClient.get(artifactUrl, {
215
+ const response = await axios_devrev_client_1.axiosDevRevClient.get(artifactUrl, {
203
216
  responseType: 'arraybuffer',
204
217
  });
205
218
  return response.data;
206
219
  }
207
220
  catch (error) {
208
- if (axios_client_1.axios.isAxiosError(error)) {
221
+ if (axios_devrev_client_1.axios.isAxiosError(error)) {
209
222
  console.error('Error while downloading artifact from URL.', (0, logger_1.serializeAxiosError)(error));
210
223
  }
211
224
  else {
@@ -213,7 +226,7 @@ class Uploader {
213
226
  }
214
227
  }
215
228
  }
216
- async compressGzip(jsonlObject) {
229
+ compressGzip(jsonlObject) {
217
230
  try {
218
231
  return zlib_1.default.gzipSync(jsonlObject);
219
232
  }
@@ -221,22 +234,23 @@ class Uploader {
221
234
  console.error('Error while compressing jsonl object.', error);
222
235
  }
223
236
  }
224
- async decompressGzip(gzippedJsonlObject) {
237
+ decompressGzip(gzippedJsonlObject) {
225
238
  try {
226
- const jsonlObject = await zlib_1.default.gunzipSync(gzippedJsonlObject);
239
+ const jsonlObject = zlib_1.default.gunzipSync(gzippedJsonlObject);
227
240
  return jsonlObject.toString();
228
241
  }
229
242
  catch (error) {
230
243
  console.error('Error while decompressing gzipped jsonl object.', error);
231
244
  }
232
245
  }
233
- async parseJsonl(jsonlObject) {
246
+ parseJsonl(jsonlObject) {
234
247
  try {
235
248
  return js_jsonl_1.jsonl.parse(jsonlObject);
236
249
  }
237
250
  catch (error) {
238
251
  console.error('Error while parsing jsonl object.', error);
239
252
  }
253
+ return null;
240
254
  }
241
255
  async getJsonObjectByArtifactId({ artifactId, isGzipped = false, }) {
242
256
  const artifactUrl = await this.getArtifactDownloadUrl(artifactId);
@@ -248,7 +262,7 @@ class Uploader {
248
262
  return;
249
263
  }
250
264
  if (isGzipped) {
251
- const decompressedArtifact = await this.decompressGzip(artifact);
265
+ const decompressedArtifact = this.decompressGzip(artifact);
252
266
  if (!decompressedArtifact) {
253
267
  return;
254
268
  }
@@ -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.LoaderEventType.LoaderAttachmentStateDeletionDone);
7
+ },
8
+ onTimeout: async ({ adapter }) => {
9
+ await adapter.emit(index_1.LoaderEventType.LoaderAttachmentStateDeletionError, {
10
+ error: {
11
+ message: 'Failed to delete attachment state. Timeout.',
12
+ },
13
+ });
14
+ },
15
+ });
@@ -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.LoaderEventType.LoaderStateDeletionDone);
7
+ },
8
+ onTimeout: async ({ adapter }) => {
9
+ await adapter.emit(index_1.LoaderEventType.LoaderStateDeletionError, {
10
+ error: {
11
+ message: 'Failed to delete data. Lambda timeout.',
12
+ },
13
+ });
14
+ },
15
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const process_task_1 = require("workers/process-task");
4
+ const types_1 = require("types");
5
+ (0, process_task_1.processTask)({
6
+ task: async ({ adapter }) => {
7
+ await adapter.emit(types_1.LoaderEventType.AttachmentLoadingDone, {
8
+ reports: adapter.reports,
9
+ processed_files: adapter.processedFiles,
10
+ });
11
+ },
12
+ onTimeout: async ({ adapter }) => {
13
+ await adapter.postState();
14
+ await adapter.emit(types_1.LoaderEventType.AttachmentLoadingError, {
15
+ reports: adapter.reports,
16
+ processed_files: adapter.processedFiles,
17
+ });
18
+ },
19
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const process_task_1 = require("workers/process-task");
4
+ const loading_1 = require("../../types/loading");
5
+ (0, process_task_1.processTask)({
6
+ task: async ({ adapter }) => {
7
+ await adapter.emit(loading_1.LoaderEventType.DataLoadingDone, {
8
+ reports: adapter.reports,
9
+ processed_files: adapter.processedFiles,
10
+ });
11
+ },
12
+ onTimeout: async ({ adapter }) => {
13
+ await adapter.postState();
14
+ await adapter.emit(loading_1.LoaderEventType.DataLoadingError, {
15
+ reports: adapter.reports,
16
+ processed_files: adapter.processedFiles,
17
+ });
18
+ },
19
+ });
@@ -8,7 +8,7 @@ const workers_1 = require("../types/workers");
8
8
  const logger_1 = require("../logger/logger");
9
9
  function processTask({ task, onTimeout, }) {
10
10
  if (!node_worker_threads_1.isMainThread) {
11
- (async () => {
11
+ void (async () => {
12
12
  const event = node_worker_threads_1.workerData.event;
13
13
  const initialState = node_worker_threads_1.workerData.initialState;
14
14
  const options = node_worker_threads_1.workerData.options;
@@ -6,13 +6,9 @@ const extraction_1 = require("../types/extraction");
6
6
  const control_protocol_1 = require("../common/control-protocol");
7
7
  const helpers_1 = require("../common/helpers");
8
8
  const logger_1 = require("../logger/logger");
9
- const constants_1 = require("../common/constants");
10
9
  const workers_1 = require("../types/workers");
11
10
  const create_worker_1 = require("./create-worker");
12
11
  function getWorkerPath({ event, connectorWorkerPath, }) {
13
- if (!constants_1.ALLOWED_EVENT_TYPES.includes(event.payload.event_type)) {
14
- return null;
15
- }
16
12
  if (connectorWorkerPath)
17
13
  return connectorWorkerPath;
18
14
  let path = null;
@@ -41,23 +37,20 @@ function getWorkerPath({ event, connectorWorkerPath, }) {
41
37
  // Loading
42
38
  case extraction_1.EventType.StartLoadingData:
43
39
  case extraction_1.EventType.ContinueLoadingData:
44
- path = __dirname + '/default-workers/data-loading';
40
+ path = __dirname + '/default-workers/load-data';
41
+ break;
42
+ case extraction_1.EventType.StartLoadingAttachments:
43
+ case extraction_1.EventType.ContinueLoadingAttachments:
44
+ path = __dirname + '/default-workers/load-attachments';
45
45
  break;
46
46
  case extraction_1.EventType.StartDeletingLoaderState:
47
- path = __dirname + '/default-workers/loader-state-deletion';
47
+ path = __dirname + '/default-workers/delete-loader-state';
48
+ break;
49
+ case extraction_1.EventType.StartDeletingLoaderAttachmentState:
50
+ path = __dirname + '/default-workers/delete-loader-attachment-state';
48
51
  break;
49
52
  default:
50
- (0, control_protocol_1.emit)({
51
- event,
52
- eventType: extraction_1.ExtractorEventType.UnknownEventType,
53
- data: {
54
- error: {
55
- message: 'Unrecognized event type in spawn ' +
56
- event.payload.event_type +
57
- '.',
58
- },
59
- },
60
- });
53
+ path = null;
61
54
  }
62
55
  return path;
63
56
  }
@@ -102,7 +95,18 @@ async function spawn({ event, initialState, workerPath, options, }) {
102
95
  }
103
96
  }
104
97
  else {
105
- throw new Error('Worker script not found.');
98
+ await (0, control_protocol_1.emit)({
99
+ event,
100
+ eventType: extraction_1.ExtractorEventType.UnknownEventType,
101
+ data: {
102
+ error: {
103
+ message: 'Unrecognized event type in spawn ' +
104
+ event.payload.event_type +
105
+ '.',
106
+ },
107
+ },
108
+ });
109
+ return false;
106
110
  }
107
111
  }
108
112
  class Spawn {
@@ -1,5 +1,5 @@
1
1
  import { AirdropEvent, ExtractorEventType, EventData, ExternalSystemAttachmentStreamingFunction } from '../types/extraction';
2
- import { LoaderEventType } from '../types/loading';
2
+ import { ExternalSystemAttachment, ExternalSystemLoadingFunction, FileToLoad, LoaderEventType } from '../types/loading';
3
3
  import { AdapterState } from '../state/state.interfaces';
4
4
  import { Artifact } from '../uploader/uploader.interfaces';
5
5
  import { WorkerAdapterInterface, WorkerAdapterOptions } from '../types/workers';
@@ -54,10 +54,20 @@ export declare class WorkerAdapter<ConnectorState> {
54
54
  uploadAllRepos(): Promise<void>;
55
55
  handleTimeout(): void;
56
56
  loadItemTypes({ itemTypesToLoad, }: ItemTypesToLoadParams): Promise<LoadItemTypesResponse>;
57
+ getLoaderBatches({ supportedItemTypes, }: {
58
+ supportedItemTypes: string[];
59
+ }): Promise<FileToLoad[]>;
60
+ loadAttachments({ create, }: {
61
+ create: ExternalSystemLoadingFunction<ExternalSystemAttachment>;
62
+ }): Promise<LoadItemTypesResponse>;
57
63
  loadItem({ item, itemTypeToLoad, }: {
58
64
  item: ExternalSystemItem;
59
65
  itemTypeToLoad: ItemTypeToLoad;
60
66
  }): Promise<LoadItemResponse>;
67
+ loadAttachment({ item, create, }: {
68
+ item: ExternalSystemAttachment;
69
+ create: ExternalSystemLoadingFunction<ExternalSystemAttachment>;
70
+ }): Promise<LoadItemResponse>;
61
71
  /**
62
72
  * Streams the attachments to the DevRev platform.
63
73
  * The attachments are streamed to the platform and the artifact information is returned.
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WorkerAdapter = void 0;
4
4
  exports.createWorkerAdapter = createWorkerAdapter;
5
- const axios_client_1 = require("../http/axios-client");
5
+ const axios_devrev_client_1 = require("../http/axios-devrev-client");
6
6
  const extraction_1 = require("../types/extraction");
7
7
  const loading_1 = require("../types/loading");
8
8
  const constants_1 = require("../common/constants");
@@ -163,68 +163,22 @@ class WorkerAdapter {
163
163
  }
164
164
  async loadItemTypes({ itemTypesToLoad, }) {
165
165
  var _a, _b, _c;
166
- const statsFileArtifactId = (_a = this.event.payload.event_data) === null || _a === void 0 ? void 0 : _a.stats_file;
167
- if (!statsFileArtifactId) {
168
- console.error('Stats file artifact id not found in event data.');
169
- await (0, control_protocol_1.emit)({
170
- event: this.event,
171
- eventType: loading_1.LoaderEventType.DataLoadingError,
172
- data: {
173
- error: {
174
- message: 'Stats file artifact id not found in event data.',
175
- },
176
- },
177
- });
178
- return {
179
- reports: this.reports,
180
- processed_files: this.processedFiles,
166
+ if (this.event.payload.event_type === extraction_1.EventType.StartLoadingData) {
167
+ this.adapterState.state.fromDevRev = {
168
+ filesToLoad: await this.getLoaderBatches({
169
+ supportedItemTypes: itemTypesToLoad.map((it) => it.itemType),
170
+ }),
181
171
  };
182
172
  }
183
- const statsFile = (await this.uploader.getJsonObjectByArtifactId({
184
- artifactId: statsFileArtifactId,
185
- }));
186
- console.log('Stats file', statsFile);
187
- if (!statsFile || statsFile.length === 0) {
188
- console.warn('Stats file not found or empty.');
173
+ if (((_a = this.adapterState.state.fromDevRev) === null || _a === void 0 ? void 0 : _a.filesToLoad.length) === 0) {
174
+ console.warn('No files to load, returning.');
189
175
  return {
190
176
  reports: this.reports,
191
177
  processed_files: this.processedFiles,
192
178
  };
193
179
  }
194
- if (this.event.payload.event_type === extraction_1.EventType.StartLoadingData) {
195
- console.log('Recieved event type ' +
196
- extraction_1.EventType.StartLoadingData +
197
- '. Preparing files to load.');
198
- const filesToLoad = (0, helpers_1.getFilesToLoad)({
199
- itemTypesToLoad,
200
- statsFile,
201
- });
202
- if (filesToLoad.length === 0) {
203
- console.warn('No files to load, returning.');
204
- return {
205
- reports: this.reports,
206
- processed_files: this.processedFiles,
207
- };
208
- }
209
- this.adapterState.state.fromDevRev = { filesToLoad };
210
- }
211
180
  console.log('Files to load in state', (_b = this.adapterState.state.fromDevRev) === null || _b === void 0 ? void 0 : _b.filesToLoad);
212
- if (!this.adapterState.state.fromDevRev) {
213
- await (0, control_protocol_1.emit)({
214
- event: this.event,
215
- eventType: loading_1.LoaderEventType.DataLoadingError,
216
- data: {
217
- error: {
218
- message: 'Unexpected state set in LOAD_DATA.',
219
- },
220
- },
221
- });
222
- return {
223
- reports: this.reports,
224
- processed_files: this.processedFiles,
225
- };
226
- }
227
- outerloop: for (const fileToLoad of (_c = this.adapterState.state.fromDevRev) === null || _c === void 0 ? void 0 : _c.filesToLoad) {
181
+ outerloop: for (const fileToLoad of ((_c = this.adapterState.state.fromDevRev) === null || _c === void 0 ? void 0 : _c.filesToLoad) || []) {
228
182
  const itemTypeToLoad = itemTypesToLoad.find((itemTypeToLoad) => itemTypeToLoad.itemType === fileToLoad.itemType);
229
183
  if (!itemTypeToLoad) {
230
184
  console.error(`Item type to load not found for item type: ${fileToLoad.itemType}.`);
@@ -249,20 +203,88 @@ class WorkerAdapter {
249
203
  break outerloop;
250
204
  }
251
205
  for (let i = fileToLoad.lineToProcess; i < fileToLoad.count; i++) {
252
- const { report, rateLimit, error } = await this.loadItem({
206
+ const { report, rateLimit } = await this.loadItem({
253
207
  item: transformerFile[i],
254
208
  itemTypeToLoad,
255
209
  });
256
- if (error) {
210
+ if (rateLimit === null || rateLimit === void 0 ? void 0 : rateLimit.delay) {
257
211
  await (0, control_protocol_1.emit)({
258
212
  event: this.event,
259
- eventType: loading_1.LoaderEventType.DataLoadingError,
213
+ eventType: loading_1.LoaderEventType.DataLoadingDelay,
260
214
  data: {
261
- error,
215
+ delay: rateLimit.delay,
216
+ reports: this.reports,
217
+ processed_files: this.processedFiles,
262
218
  },
263
219
  });
264
220
  break outerloop;
265
221
  }
222
+ if (report) {
223
+ (0, helpers_1.addReportToLoaderReport)({
224
+ loaderReports: this.loaderReports,
225
+ report,
226
+ });
227
+ fileToLoad.lineToProcess = fileToLoad.lineToProcess + 1;
228
+ }
229
+ }
230
+ fileToLoad.completed = true;
231
+ this._processedFiles.push(fileToLoad.id);
232
+ }
233
+ }
234
+ return {
235
+ reports: this.reports,
236
+ processed_files: this.processedFiles,
237
+ };
238
+ }
239
+ async getLoaderBatches({ supportedItemTypes, }) {
240
+ var _a;
241
+ const statsFileArtifactId = (_a = this.event.payload.event_data) === null || _a === void 0 ? void 0 : _a.stats_file;
242
+ if (statsFileArtifactId) {
243
+ const statsFile = (await this.uploader.getJsonObjectByArtifactId({
244
+ artifactId: statsFileArtifactId,
245
+ }));
246
+ if (!statsFile || statsFile.length === 0) {
247
+ return [];
248
+ }
249
+ const filesToLoad = (0, helpers_1.getFilesToLoad)({
250
+ supportedItemTypes,
251
+ statsFile,
252
+ });
253
+ return filesToLoad;
254
+ }
255
+ return [];
256
+ }
257
+ async loadAttachments({ create, }) {
258
+ var _a, _b;
259
+ if (this.event.payload.event_type === extraction_1.EventType.StartLoadingAttachments) {
260
+ this.adapterState.state.fromDevRev = {
261
+ filesToLoad: await this.getLoaderBatches({
262
+ supportedItemTypes: ['attachment'],
263
+ }),
264
+ };
265
+ }
266
+ if (!this.adapterState.state.fromDevRev ||
267
+ ((_a = this.adapterState.state.fromDevRev) === null || _a === void 0 ? void 0 : _a.filesToLoad.length) === 0) {
268
+ return {
269
+ reports: this.reports,
270
+ processed_files: this.processedFiles,
271
+ };
272
+ }
273
+ outerloop: for (const fileToLoad of (_b = this.adapterState.state.fromDevRev) === null || _b === void 0 ? void 0 : _b.filesToLoad) {
274
+ if (!fileToLoad.completed) {
275
+ const transformerFile = (await this.uploader.getJsonObjectByArtifactId({
276
+ artifactId: fileToLoad.id,
277
+ isGzipped: true,
278
+ }));
279
+ if (!transformerFile) {
280
+ console.error('Transformer file not found.');
281
+ break outerloop;
282
+ }
283
+ for (let i = fileToLoad.lineToProcess; i < fileToLoad.count; i++) {
284
+ const { report, rateLimit } = await this.loadAttachment({
285
+ item: transformerFile[i],
286
+ create,
287
+ });
266
288
  if (rateLimit === null || rateLimit === void 0 ? void 0 : rateLimit.delay) {
267
289
  await (0, control_protocol_1.emit)({
268
290
  event: this.event,
@@ -340,7 +362,7 @@ class WorkerAdapter {
340
362
  console.log('Updated sync mapper record', JSON.stringify(updateSyncMapperRecordResponse.data));
341
363
  }
342
364
  catch (error) {
343
- if (axios_client_1.axios.isAxiosError(error)) {
365
+ if (axios_devrev_client_1.axios.isAxiosError(error)) {
344
366
  console.error('Failed to update sync mapper record', (0, logger_1.serializeAxiosError)(error));
345
367
  return {
346
368
  error: {
@@ -385,7 +407,7 @@ class WorkerAdapter {
385
407
  // Update mapper (optional)
386
408
  }
387
409
  catch (error) {
388
- if (axios_client_1.axios.isAxiosError(error)) {
410
+ if (axios_devrev_client_1.axios.isAxiosError(error)) {
389
411
  if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
390
412
  // Create item
391
413
  const { id, delay, error } = await itemTypeToLoad.create({
@@ -411,7 +433,7 @@ class WorkerAdapter {
411
433
  };
412
434
  }
413
435
  catch (error) {
414
- if (axios_client_1.axios.isAxiosError(error)) {
436
+ if (axios_devrev_client_1.axios.isAxiosError(error)) {
415
437
  console.error('Failed to create sync mapper record', (0, logger_1.serializeAxiosError)(error));
416
438
  return {
417
439
  error: {
@@ -461,6 +483,38 @@ class WorkerAdapter {
461
483
  };
462
484
  }
463
485
  }
486
+ async loadAttachment({ item, create, }) {
487
+ // Create item
488
+ const { id, delay, error } = await create({
489
+ item,
490
+ mappers: this.mappers,
491
+ event: this.event,
492
+ });
493
+ if (delay) {
494
+ return {
495
+ rateLimit: {
496
+ delay,
497
+ },
498
+ };
499
+ }
500
+ else if (id) {
501
+ return {
502
+ report: {
503
+ item_type: 'attachment',
504
+ [loading_1.ActionType.CREATED]: 1,
505
+ },
506
+ };
507
+ }
508
+ else {
509
+ console.error('Failed to create item', error);
510
+ return {
511
+ report: {
512
+ item_type: 'attachment',
513
+ [loading_1.ActionType.FAILED]: 1,
514
+ },
515
+ };
516
+ }
517
+ }
464
518
  /**
465
519
  * Streams the attachments to the DevRev platform.
466
520
  * The attachments are streamed to the platform and the artifact information is returned.
@@ -469,7 +523,7 @@ class WorkerAdapter {
469
523
  * or error information if there was an error
470
524
  */
471
525
  async streamAttachments({ stream, }) {
472
- var _a, _b, _c, _d, _e, _f, _g;
526
+ var _a, _b, _c, _d, _e, _f;
473
527
  const repos = [
474
528
  {
475
529
  itemType: 'ssor_attachment',
@@ -487,9 +541,8 @@ class WorkerAdapter {
487
541
  if (error) {
488
542
  return { error };
489
543
  }
490
- console.log('this.state.toDevRev?.attachmentsMetadata :>> ', (_c = this.state.toDevRev) === null || _c === void 0 ? void 0 : _c.attachmentsMetadata);
491
544
  if (attachments) {
492
- const attachmentsToProcess = attachments.slice((_e = (_d = this.state.toDevRev) === null || _d === void 0 ? void 0 : _d.attachmentsMetadata) === null || _e === void 0 ? void 0 : _e.lastProcessed, attachments.length);
545
+ const attachmentsToProcess = attachments.slice((_d = (_c = this.state.toDevRev) === null || _c === void 0 ? void 0 : _c.attachmentsMetadata) === null || _d === void 0 ? void 0 : _d.lastProcessed, attachments.length);
493
546
  for (const attachment of attachmentsToProcess) {
494
547
  const { httpStream, delay, error } = await stream({
495
548
  item: attachment,
@@ -503,19 +556,26 @@ class WorkerAdapter {
503
556
  return { delay };
504
557
  }
505
558
  if (httpStream) {
506
- const fileType = ((_f = httpStream.headers) === null || _f === void 0 ? void 0 : _f['content-type']) ||
559
+ const fileType = ((_e = httpStream.headers) === null || _e === void 0 ? void 0 : _e['content-type']) ||
507
560
  'application/octet-stream';
508
561
  const preparedArtifact = await this.uploader.prepareArtifact(attachment.file_name, fileType);
509
562
  if (!preparedArtifact) {
510
- return {
511
- error: { message: 'Error while preparing artifact.' },
512
- };
563
+ console.warn('Error while preparing artifact for attachment ID ' +
564
+ attachment.id +
565
+ '. Skipping attachment');
566
+ if (this.state.toDevRev) {
567
+ this.state.toDevRev.attachmentsMetadata.lastProcessed++;
568
+ }
569
+ continue;
513
570
  }
514
571
  const uploadedArtifact = await this.uploader.streamToArtifact(preparedArtifact, httpStream);
515
572
  if (!uploadedArtifact) {
516
- return {
517
- error: { message: 'Error while streaming artifact.' },
518
- };
573
+ console.warn('Error while preparing artifact for attachment ID ' +
574
+ attachment.id);
575
+ if (this.state.toDevRev) {
576
+ this.state.toDevRev.attachmentsMetadata.lastProcessed++;
577
+ }
578
+ continue;
519
579
  }
520
580
  const ssorAttachment = {
521
581
  id: {
@@ -529,7 +589,7 @@ class WorkerAdapter {
529
589
  external: attachment.author_id,
530
590
  },
531
591
  };
532
- await ((_g = this.getRepo('ssor_attachment')) === null || _g === void 0 ? void 0 : _g.push([ssorAttachment]));
592
+ await ((_f = this.getRepo('ssor_attachment')) === null || _f === void 0 ? void 0 : _f.push([ssorAttachment]));
533
593
  if (this.state.toDevRev) {
534
594
  this.state.toDevRev.attachmentsMetadata.lastProcessed++;
535
595
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@devrev/ts-adaas",
3
- "version": "1.1.5",
4
- "description": "Typescript library containing the ADaaS(AirDrop as a Service) control protocol.",
3
+ "version": "1.2.0-beta",
4
+ "description": "DevRev ADaaS (AirDrop-as-a-Service) Typescript SDK.",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
7
7
  "typings": "./dist/index.d.ts",