@devrev/ts-adaas 1.2.5 → 1.3.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 CHANGED
@@ -1,135 +1,297 @@
1
- # ADaaS Library
1
+ # Airdrop SDK
2
2
 
3
- ## Release Notes
3
+ [![Coverage Status](https://coveralls.io/repos/github/devrev/adaas-sdk/badge.svg?branch=main&t=s4Otlm)](https://coveralls.io/github/devrev/adaas-sdk?branch=main)
4
4
 
5
- ### v1.2.5
5
+ ## Overview
6
6
 
7
- - Add batch size option.
8
- - Replace DevRev Typescript SDK requests with Axios for uploading and downloading artifacts.
9
- - Remove unneccessary postState from default workers.
10
- - Fix bugs related to attachment streaming.
7
+ The Airdrop SDK for TypeScript helps developers build snap-ins that integrate with DevRev’s Airdrop platform.
8
+ This SDK simplifies the workflow for handling data extraction and loading, event-driven actions, state management, and artifact handling.
11
9
 
12
- ### v1.2.4
10
+ It provides features such as:
13
11
 
14
- - Do not fail the extraction of attachments if streaming of single attachment fails.
12
+ - Type Definitions: Structured types for Airdrop control protocol
13
+ - Event Management: Easily emit events for different extraction or loading phases
14
+ - State Handling: Update and access state in real-time within tasks
15
+ - Artifact Management: Supports batched storage of artifacts
16
+ - Error & Timeout Support: Error handling and timeout management for long-running tasks
15
17
 
16
- ### v1.2.3
18
+ ## Installation
17
19
 
18
- - Add `local` flag to use for local development of the ADaaS snap-ins.
19
- - Send library version, snap-in version and snap-in slug in headers while emitting.
20
- - Make `actor_id` field optional for `SsorAttachment` interface.
21
- - Fix bugs related to event handling, error logging.
20
+ ```bash
21
+ npm install @devrev/ts-adaas
22
+ ```
22
23
 
23
- ### v1.2.2
24
+ ## Reference
24
25
 
25
- - Add library version as a part of control protocol.
26
- - Improve axios client and adapter logging.
27
- - Fix bugs related to state handling.
26
+ ### `spawn` function
28
27
 
29
- ### v1.2.1
28
+ This function initializes a new worker thread and oversees its lifecycle.
29
+ It should be invoked when the snap-in receives a message from the Airdrop platform.
30
+ The worker script provided then handles the event accordingly.
30
31
 
31
- - Reduced the `delayFactor` to minimize unnecessary delays.
32
- - Correct the setting of the `lastSyncStarted` timestamp.
33
- - Improve logging for attachment extraction and loading.
34
- - Fix several bugs related to the control protocol.
32
+ #### Usage
35
33
 
36
- ### v1.2.0
34
+ ```typescript
35
+ spawn({ event, initialState, workerPath, options })
36
+ ```
37
37
 
38
- - Add support for loading attachments from DevRev to external system.
38
+ #### Parameters
39
39
 
40
- ### v1.1.6
40
+ * _event_
41
+
42
+ Required. An object of type __AirdropEvent__ that is received from the Airdrop platform.
41
43
 
42
- - Add exponential retry and handle rate-limiting towards DevRev.
43
- - Gracefully handle failure to upload extracted attachments.
44
+ * _initialState_
44
45
 
45
- ### v1.1.5
46
+ Required. Object of __any__ type that represents the initial state of the snap-in.
46
47
 
47
- - Increase `delayFactor` and number of retries for the exponential backoff retry mechanism for HTTP requests.
48
- - Provide an inject function for streaming attachments.
49
- - Fix the attachments streaming bug.
48
+ * _workerPath_
50
49
 
51
- ### v1.1.4
50
+ Required. A __string__ that represents the path to the worker file.
52
51
 
53
- - Provide log lines and stack traces for runtime worker errors.
52
+ * _options_
54
53
 
55
- ### v1.1.3
54
+ Optional. An object of type **WorkerAdapterOptions**, which will be passed to the newly created worker. This worker will then initialize a `WorkerAdapter` by invoking the `processTask` function. The options include:
55
+
56
+ * `isLocalDevelopment`
57
+
58
+ A __boolean__ flag. If set to `true`, intermediary files containing extracted data will be stored on the local machine, which is useful during development. The default value is `false`.
56
59
 
57
- - Export `axios` and `axiosClient` with the exponential backoff retry mechanism for HTTP requests and omit Authorization headers from Axios errors.
58
- - Resolve circular structure logging issues.
59
- - Fix the attachments metadata normalization bug.
60
- - Improve repository logging.
60
+ * `timeout`
61
+
62
+ A __number__ that specifies the timeout duration for the lambda function, in milliseconds. The default is 10 minutes (10 * 60 * 1000 milliseconds), with a maximum allowable duration of 13 minutes (13 * 60 * 1000 milliseconds).
63
+
64
+ * `batchSize`
61
65
 
62
- ### v1.1.2
66
+ A __number__ that determines the maximum number of items to be processed and saved to an intermediary file before being sent to the Airdrop platform. The default batch size is 2,000.
63
67
 
64
- - Unify incoming and outgoing event context.
65
- - Add `dev_oid` to logger tags.
68
+ #### Return value
66
69
 
67
- ### v1.1.1
70
+ A __promise__ that resolves once the worker has completed processing.
68
71
 
69
- - Add default workers for loading deletion events.
72
+ #### Example
70
73
 
71
- ### v1.1.0
74
+ ```typescript
75
+ const run = async (events: AirdropEvent[]) => {
76
+ for (const event of events) {
77
+ const file = getWorkerPerExtractionPhase(event);
78
+ await spawn<ExtractorState>({
79
+ event,
80
+ initialState,
81
+ workerPath: file,
82
+ });
83
+ }
84
+ };
85
+ ```
72
86
 
73
- - Support sync from DevRev to the external system. (Known limitations: no support for loading attachments.)
87
+ ### `processTask` function
74
88
 
75
- ### v1.0.4
89
+ The `processTask` function retrieves the current state from the Airdrop platform and initializes a new `WorkerAdapter`.
90
+ It executes the code specified in the `task` parameter, which contains the worker's functionality.
91
+ If a timeout occurs, the function handles it by executing the `onTimeout` callback, ensuring the worker exits gracefully.
92
+ Both functions receive an `adapter` parameter, representing the initialized `WorkerAdapter` object.
76
93
 
77
- - Fix logging from worker threads.
78
94
 
79
- ### v1.0.3
95
+ #### Usage
96
+ ```typescript
97
+ processTask({ task, onTimeout })
98
+ ```
80
99
 
81
- - Add release notes.
100
+ #### Parameters
82
101
 
83
- ### v1.0.2
102
+ * _task_
103
+
104
+ Required. A __function__ that defines the logic associated with the given event type.
84
105
 
85
- - Fix bugs and improve local development.
86
- - Expose `formatAxiosError` function for error handling.
106
+ * _onTimeout_
107
+
108
+ Required. A __function__ managing the timeout of the lambda invocation, including saving any necessary progress at the time of timeout.
87
109
 
88
- ### v1.0.1
110
+ #### Example
89
111
 
90
- - Fix bugs and improve logging.
112
+ ````typescript
113
+ // External sync units extraction
114
+ processTask({
115
+ task: async ({ adapter }) => {
116
+ const httpClient = new HttpClient(adapter.event);
91
117
 
92
- ### v1.0.0
118
+ const todoLists = await httpClient.getTodoLists();
93
119
 
94
- - Enable extractions to use the full lambda runtime and gracefully handle execution context timeout.
95
- - Simplify metadata and data normalization and uploading with the repo implementation.
96
- - Provide default handling of the attachment extraction phase in the ADaaS SDK library.
97
- - Reduce file size and streamline processes with gzip compression.
98
- - Fix bugs and improve error handling.
120
+ const externalSyncUnits: ExternalSyncUnit[] = todoLists.map((todoList) => normalizeTodoList(todoList));
99
121
 
100
- ### v0.0.3
122
+ await adapter.emit(ExtractorEventType.ExtractionExternalSyncUnitsDone, {
123
+ external_sync_units: externalSyncUnits,
124
+ });
125
+ },
126
+ onTimeout: async ({ adapter }) => {
127
+ await adapter.emit(ExtractorEventType.ExtractionExternalSyncUnitsError, {
128
+ error: {
129
+ message: 'Failed to extract external sync units. Lambda timeout.',
130
+ },
131
+ });
132
+ },
133
+ });
134
+ ````
101
135
 
102
- - Support new recipe management.
136
+ ### `WorkerAdapter` class
103
137
 
104
- ### v0.0.2
138
+ Used to interact with Airdrop platform.
139
+ Provides utilities to emit events to the Airdrop platform, update the state of the snap-in and upload artifacts (files with data) to the platform.
105
140
 
106
- - Support the State API.
107
- - Provide an HTTP client for API requests.
108
- - Create local artifact files in the local development environment.
109
- - Improve logging.
141
+ ### Usage
110
142
 
111
- ### v0.0.1
143
+ ```typescript
144
+ new WorkerAdapter({
145
+ event,
146
+ adapterState,
147
+ options,
148
+ });
149
+ ```
112
150
 
113
- - Implement a demo of the ADaaS snap-in.
114
- - Add an adapter for the ADaaS control protocol with helper functions.
115
- - Provide an uploader for uploading artifacts.
151
+ #### Parameters
116
152
 
117
- # Overview
153
+ * _event_
154
+
155
+ Required. An object of type __AirdropEvent__ that is received from the Airdrop platform.
118
156
 
119
- [![Coverage Status](https://coveralls.io/repos/github/devrev/adaas-sdk/badge.svg?branch=main&t=s4Otlm)](https://coveralls.io/github/devrev/adaas-sdk?branch=main)
157
+ * _adapterState_
158
+
159
+ Required. An object of type __State__, which represents the initial state of the adapter.
120
160
 
121
- The ADaaS (Airdrop-as-a-Service) Library for TypeScript helps developers build Snap-ins that integrate with DevRev’s ADaaS platform. This library simplifies the workflow for handling data extraction and loading, event-driven actions, state management, and artifact handling.
161
+ * _options_
162
+
163
+ Optional. An object of type __WorkerAdapterOptions__ that specifies additional configuration options for the `WorkerAdapter`. This object is passed via the `spawn` function.
122
164
 
123
- It provides features such as:
165
+ #### Example
124
166
 
125
- - Type Definitions: Structured types for ADaaS control protocol
126
- - Event Management: Easily emit events for different extraction or loading phases
127
- - State Handling: Update and access state in real-time within tasks
128
- - Artifact Management: Supports batched storage of artifacts
129
- - Error & Timeout Support: Error handling and timeout management for long-running tasks
167
+ ```typescript
168
+ const adapter = new WorkerAdapter<ConnectorState>({
169
+ event,
170
+ adapterState,
171
+ options,
172
+ });
173
+ ```
130
174
 
131
- # Installation
175
+ ### `WorkerAdapter.state` property
132
176
 
133
- ```bash
134
- npm install @devrev/ts-adaas
177
+ Getter and setter methods for working with the adapter state.
178
+
179
+ ### Usage
180
+
181
+ ```typescript
182
+ // get state
183
+ const adapterState = adapter.state;
184
+
185
+ // set state
186
+ adapter.state = newAdapterState;
187
+ ```
188
+
189
+ #### Example
190
+
191
+ ```typescript
192
+ export const initialState: ExtractorState = {
193
+ users: { completed: false },
194
+ tasks: { completed: false },
195
+ attachments: { completed: false },
196
+ };
197
+
198
+ adapter.state = initialState;
199
+ ```
200
+
201
+ ### `WorkerAdapter.initializeRepos` method
202
+
203
+ Initializes a `Repo` object for each item provided.
204
+
205
+ ### Usage
206
+
207
+ ```typescript
208
+ adapter.initializeRepos(repos);
209
+ ```
210
+
211
+ #### Parameters
212
+
213
+ * _repos_
214
+
215
+ Required. An array of objects of type `RepoInterface`.
216
+
217
+ #### Example
218
+
219
+ This should typically be called within the function passed as a parameter to the `processTask` function in the data extraction phase.
220
+
221
+ ```typescript
222
+ const repos = [
223
+ {
224
+ itemType: 'tasks',
225
+ normalize: normalizeTask,
226
+ }
227
+ ];
228
+
229
+ adapter.initializeRepos(repos);
230
+ ```
231
+
232
+ ### `WorkerAdapter.getRepo` method
233
+
234
+ Finds a Repo from the initialized repos.
235
+
236
+ ### Usage
237
+
238
+ ```typescript
239
+ adapter.getRepo(itemType);
240
+ ```
241
+
242
+ #### Parameters
243
+
244
+ * _itemType_
245
+
246
+ Required. A __string__ that represents the itemType property for the searched repo.
247
+
248
+ #### Return value
249
+
250
+ An object of type __Repo__ if the repo is found, otherwise __undefined__.
251
+
252
+ #### Example
253
+
254
+ This should typically be called within the function passed as a parameter to the `processTask` function.
255
+
256
+ ```typescript
257
+ // Push users to the repository designated for 'users' data.
258
+ await adapter.getRepo('users')?.push(users);
259
+ ```
260
+
261
+ ### `WorkerAdapter.emit` method
262
+
263
+ Emits an event to the Airdrop platform.
264
+
265
+ ### Usage
266
+
267
+ ```typescript
268
+ adapter.emit( newEventType, data ):
269
+ ```
270
+
271
+ #### Parameters
272
+
273
+ * _newEventType_
274
+
275
+ Required. The event type to be emitted, of type __ExtractorEventType__ or __LoaderEventType__.
276
+
277
+ * _data_
278
+
279
+ Optional. An object of type __EventData__ which represents the data to be sent with the event.
280
+
281
+ #### Return value
282
+
283
+ A __promise__, which resolves to undefined after the emit function completes its execution or rejects with an error.
284
+
285
+ #### Example
286
+
287
+ This should typically be called within the function passed as a parameter to the `processTask` function.
288
+
289
+ ```typescript
290
+ // Emitting successfully finished data extraction.
291
+ await adapter.emit(ExtractorEventType.ExtractionDataDone);
292
+
293
+ // Emitting a delay in attachments extraction phase.
294
+ await adapter.emit(ExtractorEventType.ExtractionAttachmentsDelay, {
295
+ delay: 10,
296
+ });
135
297
  ```
@@ -1,3 +1,3 @@
1
- import { FunctionInput } from '@devrev/typescript-sdk/dist/snap-ins';
1
+ import { AirdropEvent } from '../types/extraction';
2
2
  import { InitialDomainMapping } from '../types/common';
3
- export declare function installInitialDomainMapping(event: FunctionInput, initialDomainMappingJson: InitialDomainMapping): Promise<void>;
3
+ export declare function installInitialDomainMapping(event: AirdropEvent, initialDomainMappingJson: InitialDomainMapping): Promise<void>;
@@ -1,3 +1,26 @@
1
+ /**
2
+ * Axios client setup with retry capabilities using axios-retry.
3
+ *
4
+ * This module exports an Axios client instance (`axiosClient`) that is configured to automatically retry
5
+ * failed requests under certain conditions.
6
+ *
7
+ * Retry Conditions:
8
+ * 1. Network errors (where no response is received).
9
+ * 2. Idempotent requests (defaults include GET, HEAD, OPTIONS, PUT).
10
+ * 3. All 5xx server errors.
11
+ *
12
+ * Retry Strategy:
13
+ * - A maximum of 5 retries are attempted.
14
+ * - Exponential backoff delay is applied between retries, increasing with each retry attempt.
15
+ *
16
+ * Additional Features:
17
+ * - When the maximum number of retry attempts is reached, sensitive headers (like authorization)
18
+ * are removed from error logs for security reasons.
19
+ *
20
+ * Exported:
21
+ * - `axios`: Original axios instance for additional customizations or direct use.
22
+ * - `axiosClient`: Configured axios instance with retry logic.
23
+ */
1
24
  import axios from 'axios';
2
25
  declare const axiosClient: import("axios").AxiosInstance;
3
26
  export { axios, axiosClient };
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ /**
3
+ * Axios client setup with retry capabilities using axios-retry.
4
+ *
5
+ * This module exports an Axios client instance (`axiosClient`) that is configured to automatically retry
6
+ * failed requests under certain conditions.
7
+ *
8
+ * Retry Conditions:
9
+ * 1. Network errors (where no response is received).
10
+ * 2. Idempotent requests (defaults include GET, HEAD, OPTIONS, PUT).
11
+ * 3. All 5xx server errors.
12
+ *
13
+ * Retry Strategy:
14
+ * - A maximum of 5 retries are attempted.
15
+ * - Exponential backoff delay is applied between retries, increasing with each retry attempt.
16
+ *
17
+ * Additional Features:
18
+ * - When the maximum number of retry attempts is reached, sensitive headers (like authorization)
19
+ * are removed from error logs for security reasons.
20
+ *
21
+ * Exported:
22
+ * - `axios`: Original axios instance for additional customizations or direct use.
23
+ * - `axiosClient`: Configured axios instance with retry logic.
24
+ */
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
@@ -19,9 +42,10 @@ exports.axiosClient = axiosClient;
19
42
  return delay;
20
43
  },
21
44
  retryCondition: (error) => {
22
- var _a;
23
- return (axios_retry_1.default.isNetworkOrIdempotentRequestError(error) &&
24
- ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) !== 429);
45
+ var _a, _b, _c;
46
+ return ((axios_retry_1.default.isNetworkOrIdempotentRequestError(error) &&
47
+ ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) !== 429) ||
48
+ ((_c = (_b = error.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : 0) >= 500);
25
49
  },
26
50
  onMaxRetryTimesExceeded(error) {
27
51
  var _a, _b, _c, _d;
@@ -1,6 +1,6 @@
1
1
  import { ErrorRecord } from '../types/common';
2
2
  import { AdapterState, StateInterface } from './state.interfaces';
3
- export declare function createAdapterState<ConnectorState>({ event, initialState, options, }: StateInterface<ConnectorState>): Promise<State<ConnectorState>>;
3
+ export declare function createAdapterState<ConnectorState>({ event, initialState, initialDomainMapping, options, }: StateInterface<ConnectorState>): Promise<State<ConnectorState>>;
4
4
  export declare class State<ConnectorState> {
5
5
  private _state;
6
6
  private initialSdkState;
@@ -1,14 +1,17 @@
1
1
  import { AirdropEvent } from '../types/extraction';
2
2
  import { FileToLoad } from '../types/loading';
3
3
  import { WorkerAdapterOptions } from '../types/workers';
4
+ import { InitialDomainMapping } from '../types/common';
4
5
  export interface SdkState {
5
6
  lastSyncStarted?: string;
6
7
  lastSuccessfulSyncStarted?: string;
7
8
  toDevRev?: ToDevRev;
8
9
  fromDevRev?: FromDevRev;
10
+ snapInVersionId?: string;
9
11
  }
10
12
  /**
11
- * AdapterState is an interface that defines the structure of the adapter state that is used by the external extractor. It extends the connector state with additional fields: lastSyncStarted, lastSuccessfulSyncStarted, and attachmentsMetadata.
13
+ * AdapterState is an interface that defines the structure of the adapter state that is used by the external extractor.
14
+ * It extends the connector state with additional fields: lastSyncStarted, lastSuccessfulSyncStarted, snapInVersionId and attachmentsMetadata.
12
15
  */
13
16
  export type AdapterState<ConnectorState> = ConnectorState & SdkState;
14
17
  export interface ToDevRev {
@@ -23,5 +26,6 @@ export interface FromDevRev {
23
26
  export interface StateInterface<ConnectorState> {
24
27
  event: AirdropEvent;
25
28
  initialState: ConnectorState;
29
+ initialDomainMapping?: InitialDomainMapping;
26
30
  options?: WorkerAdapterOptions;
27
31
  }
@@ -6,16 +6,36 @@ const axios_client_1 = require("../http/axios-client");
6
6
  const extraction_1 = require("../types/extraction");
7
7
  const constants_1 = require("../common/constants");
8
8
  const logger_1 = require("../logger/logger");
9
+ const install_initial_domain_mapping_1 = require("../common/install-initial-domain-mapping");
9
10
  const helpers_1 = require("../common/helpers");
10
- async function createAdapterState({ event, initialState, options, }) {
11
+ async function createAdapterState({ event, initialState, initialDomainMapping, options, }) {
12
+ var _a;
11
13
  const newInitialState = structuredClone(initialState);
12
14
  const as = new State({
13
15
  event,
14
16
  initialState: newInitialState,
17
+ initialDomainMapping,
15
18
  options,
16
19
  });
17
20
  if (!constants_1.STATELESS_EVENT_TYPES.includes(event.payload.event_type)) {
18
21
  await as.fetchState(newInitialState);
22
+ const snapInVersionId = event.context.snap_in_version_id;
23
+ const hasSnapInVersionInState = 'snapInVersionId' in as.state;
24
+ const shouldUpdateIDM = !hasSnapInVersionInState || as.state.snapInVersionId !== snapInVersionId;
25
+ if (shouldUpdateIDM) {
26
+ console.log(`Snap-in version in state (${(_a = as.state) === null || _a === void 0 ? void 0 : _a.snapInVersionId}) differs from the version in event context (${snapInVersionId}) - initial domain mapping needs to be updated.`);
27
+ if (initialDomainMapping) {
28
+ await (0, install_initial_domain_mapping_1.installInitialDomainMapping)(event, initialDomainMapping);
29
+ as.state.snapInVersionId = snapInVersionId;
30
+ console.log('Successfully installed new initial domain mapping.');
31
+ }
32
+ else {
33
+ console.warn('No initial domain mapping was passed to spawn function. Skipping initial domain mapping installation.');
34
+ }
35
+ }
36
+ else {
37
+ console.log(`Snap-in version in state matches the version in event context (${snapInVersionId}). Skipping initial domain mapping installation.`);
38
+ }
19
39
  if (event.payload.event_type === extraction_1.EventType.ExtractionDataStart &&
20
40
  !as.state.lastSyncStarted) {
21
41
  as.state.lastSyncStarted = new Date().toISOString();
@@ -29,6 +49,7 @@ class State {
29
49
  this.initialSdkState =
30
50
  (0, helpers_1.getSyncDirection)({ event }) === extraction_1.SyncMode.LOADING
31
51
  ? {
52
+ snapInVersionId: '',
32
53
  fromDevRev: {
33
54
  filesToLoad: [],
34
55
  },
@@ -36,6 +57,7 @@ class State {
36
57
  : {
37
58
  lastSyncStarted: '',
38
59
  lastSuccessfulSyncStarted: '',
60
+ snapInVersionId: '',
39
61
  toDevRev: {
40
62
  attachmentsMetadata: {
41
63
  artifactIds: [],
@@ -96,7 +118,7 @@ class State {
96
118
  this.event.payload.event_context.sync_unit_id +
97
119
  '.');
98
120
  try {
99
- const response = await axios_client_1.axiosClient.post(this.workerUrl + '.get', {}, {
121
+ const response = await axios_client_1.axiosClient.get(this.workerUrl + '.get', {
100
122
  headers: {
101
123
  Authorization: this.devrevToken,
102
124
  },
@@ -10,7 +10,7 @@ function createEvent({ eventType, externalSyncUnits = [], progress, error, delay
10
10
  return {
11
11
  context: Object.assign({ secrets: {
12
12
  service_account_token: 'test_token',
13
- }, snap_in_version_id: 'test_snap_in_version_id' }, contextOverrides),
13
+ }, snap_in_version_id: 'test_snap_in_version_id', snap_in_id: 'test_snap_in_id' }, contextOverrides),
14
14
  payload: Object.assign({ connection_data: {
15
15
  org_id: 'test_org_id',
16
16
  org_name: 'test_org_name',
@@ -197,6 +197,7 @@ export interface AirdropEvent {
197
197
  service_account_token: string;
198
198
  };
199
199
  snap_in_version_id: string;
200
+ snap_in_id: string;
200
201
  };
201
202
  payload: AirdropMessage;
202
203
  execution_metadata: {
@@ -3,6 +3,7 @@ import { State } from '../state/state';
3
3
  import { WorkerAdapter } from '../workers/worker-adapter';
4
4
  import { ExtractorEventType, AirdropEvent } from './extraction';
5
5
  import { LoaderEventType } from './loading';
6
+ import { InitialDomainMapping } from './common';
6
7
  /**
7
8
  * WorkerAdapterInterface is an interface for WorkerAdapter class.
8
9
  * @interface WorkerAdapterInterface
@@ -52,6 +53,7 @@ export interface SpawnInterface {
52
53
  * @param {AirdropEvent} event - The event object received from the platform
53
54
  * @param {object=} initialState - The initial state of the adapter
54
55
  * @param {string} workerPath - The path to the worker file
56
+ * @param {string} initialDomainMapping - The initial domain mapping
55
57
  * @param {WorkerAdapterOptions} options - The options to create a new instance of Spawn class
56
58
  */
57
59
  export interface SpawnFactoryInterface<ConnectorState> {
@@ -59,6 +61,7 @@ export interface SpawnFactoryInterface<ConnectorState> {
59
61
  initialState: ConnectorState;
60
62
  workerPath?: string;
61
63
  options?: WorkerAdapterOptions;
64
+ initialDomainMapping?: InitialDomainMapping;
62
65
  }
63
66
  /**
64
67
  * TaskAdapterInterface is an interface for TaskAdapter class.
@@ -130,6 +133,7 @@ export interface WorkerData<ConnectorState> {
130
133
  event: AirdropEvent;
131
134
  initialState: ConnectorState;
132
135
  workerPath: string;
136
+ initialDomainMapping?: InitialDomainMapping;
133
137
  options?: WorkerAdapterOptions;
134
138
  }
135
139
  /**
@@ -11,11 +11,13 @@ function processTask({ task, onTimeout, }) {
11
11
  void (async () => {
12
12
  const event = node_worker_threads_1.workerData.event;
13
13
  const initialState = node_worker_threads_1.workerData.initialState;
14
+ const initialDomainMapping = node_worker_threads_1.workerData.initialDomainMapping;
14
15
  const options = node_worker_threads_1.workerData.options;
15
16
  console = new logger_1.Logger({ event, options });
16
17
  const adapterState = await (0, state_1.createAdapterState)({
17
18
  event,
18
19
  initialState,
20
+ initialDomainMapping,
19
21
  options,
20
22
  });
21
23
  if (node_worker_threads_1.parentPort && node_worker_threads_1.workerData.event) {
@@ -10,7 +10,7 @@ import { SpawnFactoryInterface, SpawnInterface } from '../types/workers';
10
10
  * @param {string} workerPath - The path to the worker file
11
11
  * @returns {Promise<Spawn>} - A new instance of Spawn class
12
12
  */
13
- export declare function spawn<ConnectorState>({ event, initialState, workerPath, options, }: SpawnFactoryInterface<ConnectorState>): Promise<void>;
13
+ export declare function spawn<ConnectorState>({ event, initialState, workerPath, initialDomainMapping, options, }: SpawnFactoryInterface<ConnectorState>): Promise<void>;
14
14
  export declare class Spawn {
15
15
  private event;
16
16
  private alreadyEmitted;
@@ -71,7 +71,7 @@ function getWorkerPath({ event, connectorWorkerPath, }) {
71
71
  * @param {string} workerPath - The path to the worker file
72
72
  * @returns {Promise<Spawn>} - A new instance of Spawn class
73
73
  */
74
- async function spawn({ event, initialState, workerPath, options, }) {
74
+ async function spawn({ event, initialState, workerPath, initialDomainMapping, options, }) {
75
75
  const logger = new logger_1.Logger({ event, options });
76
76
  const script = getWorkerPath({
77
77
  event,
@@ -91,6 +91,7 @@ async function spawn({ event, initialState, workerPath, options, }) {
91
91
  event,
92
92
  initialState,
93
93
  workerPath: script,
94
+ initialDomainMapping,
94
95
  options,
95
96
  });
96
97
  return new Promise((resolve) => {
@@ -72,7 +72,7 @@ export declare class WorkerAdapter<ConnectorState> {
72
72
  * Streams the attachments to the DevRev platform.
73
73
  * The attachments are streamed to the platform and the artifact information is returned.
74
74
  * @param {{ stream, processors }: { stream: ExternalSystemAttachmentStreamingFunction, processors?: ExternalSystemAttachmentProcessors }} Params - The parameters to stream the attachments
75
- * @returns {Promise<StreamAttachmentsReturnType>} - The response object containing the ssoAttachment artifact information
75
+ * @returns {Promise<StreamAttachmentsReturnType>} - The response object containing the ssorAttachment artifact information
76
76
  * or error information if there was an error
77
77
  */
78
78
  streamAttachments<NewBatch>({ stream, processors, }: {
@@ -117,7 +117,14 @@ class WorkerAdapter {
117
117
  }
118
118
  // We want to upload all the repos before emitting the event, except for the external sync units done event
119
119
  if (newEventType !== extraction_1.ExtractorEventType.ExtractionExternalSyncUnitsDone) {
120
- await this.uploadAllRepos();
120
+ try {
121
+ await this.uploadAllRepos();
122
+ }
123
+ catch (error) {
124
+ console.error('Error while uploading repos', error);
125
+ node_worker_threads_1.parentPort === null || node_worker_threads_1.parentPort === void 0 ? void 0 : node_worker_threads_1.parentPort.postMessage(workers_1.WorkerMessageSubject.WorkerMessageExit);
126
+ return;
127
+ }
121
128
  }
122
129
  // If the extraction is done, we want to save the timestamp of the last successful sync
123
130
  if (newEventType === extraction_1.ExtractorEventType.ExtractionAttachmentsDone) {
@@ -164,7 +171,10 @@ class WorkerAdapter {
164
171
  }
165
172
  async uploadAllRepos() {
166
173
  for (const repo of this.repos) {
167
- await repo.upload();
174
+ const error = await repo.upload();
175
+ if (error) {
176
+ throw error;
177
+ }
168
178
  }
169
179
  }
170
180
  handleTimeout() {
@@ -501,7 +511,7 @@ class WorkerAdapter {
501
511
  event: this.event,
502
512
  });
503
513
  if (error) {
504
- console.warn('Error while streaming attachment', error === null || error === void 0 ? void 0 : error.message);
514
+ console.warn('Error while streaming attachment', error);
505
515
  return { error };
506
516
  }
507
517
  else if (delay) {
@@ -573,27 +583,27 @@ class WorkerAdapter {
573
583
  * Streams the attachments to the DevRev platform.
574
584
  * The attachments are streamed to the platform and the artifact information is returned.
575
585
  * @param {{ stream, processors }: { stream: ExternalSystemAttachmentStreamingFunction, processors?: ExternalSystemAttachmentProcessors }} Params - The parameters to stream the attachments
576
- * @returns {Promise<StreamAttachmentsReturnType>} - The response object containing the ssoAttachment artifact information
586
+ * @returns {Promise<StreamAttachmentsReturnType>} - The response object containing the ssorAttachment artifact information
577
587
  * or error information if there was an error
578
588
  */
579
589
  async streamAttachments({ stream, processors, }) {
580
- var _a, _b, _c, _d;
590
+ var _a, _b;
581
591
  const repos = [
582
592
  {
583
593
  itemType: 'ssor_attachment',
584
594
  },
585
595
  ];
586
596
  this.initializeRepos(repos);
587
- const attachmentsMetadataArtifactIds = (_b = (_a = this.state.toDevRev) === null || _a === void 0 ? void 0 : _a.attachmentsMetadata) === null || _b === void 0 ? void 0 : _b.artifactIds;
588
- if (!attachmentsMetadataArtifactIds ||
589
- attachmentsMetadataArtifactIds.length === 0) {
597
+ if (!((_b = (_a = this.state.toDevRev) === null || _a === void 0 ? void 0 : _a.attachmentsMetadata) === null || _b === void 0 ? void 0 : _b.artifactIds) ||
598
+ this.state.toDevRev.attachmentsMetadata.artifactIds.length === 0) {
590
599
  console.log(`No attachments metadata artifact IDs found in state.`);
591
600
  return;
592
601
  }
593
602
  else {
594
- console.log(`Found ${attachmentsMetadataArtifactIds.length} attachments metadata artifact IDs in state.`);
603
+ console.log(`Found ${this.state.toDevRev.attachmentsMetadata.artifactIds.length} attachments metadata artifact IDs in state.`);
595
604
  }
596
- for (const attachmentsMetadataArtifactId of attachmentsMetadataArtifactIds) {
605
+ while (this.state.toDevRev.attachmentsMetadata.artifactIds.length > 0) {
606
+ const attachmentsMetadataArtifactId = this.state.toDevRev.attachmentsMetadata.artifactIds[0];
597
607
  console.log(`Started processing attachments for attachments metadata artifact ID: ${attachmentsMetadataArtifactId}.`);
598
608
  const { attachments, error } = await this.uploader.getAttachmentsFromArtifactId({
599
609
  artifact: attachmentsMetadataArtifactId,
@@ -604,6 +614,9 @@ class WorkerAdapter {
604
614
  }
605
615
  if (!attachments || attachments.length === 0) {
606
616
  console.warn(`No attachments found for artifact ID: ${attachmentsMetadataArtifactId}.`);
617
+ // Remove empty artifact and reset lastProcessed
618
+ this.state.toDevRev.attachmentsMetadata.artifactIds.shift();
619
+ this.state.toDevRev.attachmentsMetadata.lastProcessed = 0;
607
620
  continue;
608
621
  }
609
622
  console.log(`Found ${attachments.length} attachments for artifact ID: ${attachmentsMetadataArtifactId}.`);
@@ -622,25 +635,24 @@ class WorkerAdapter {
622
635
  }
623
636
  else {
624
637
  console.log(`Using default processors for attachments.`);
625
- 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);
638
+ const startIndex = this.state.toDevRev.attachmentsMetadata.lastProcessed || 0;
639
+ const attachmentsToProcess = attachments.slice(startIndex);
626
640
  for (const attachment of attachmentsToProcess) {
627
641
  const response = await this.processAttachment(attachment, stream);
628
642
  if (response === null || response === void 0 ? void 0 : response.delay) {
629
643
  return response;
630
644
  }
631
645
  else if (response === null || response === void 0 ? void 0 : response.error) {
632
- console.warn(`Skipping attachment with ID ${attachment.id} due to error.`);
646
+ console.warn('Skipping attachment due to an error while processing', attachment);
633
647
  }
634
648
  if (this.state.toDevRev) {
635
649
  this.state.toDevRev.attachmentsMetadata.lastProcessed += 1;
636
650
  }
637
651
  }
638
652
  }
639
- if (this.state.toDevRev) {
640
- console.log(`Finished processing attachments for artifact ID. Setting last processed to 0 and removing artifact ID from state.`);
641
- this.state.toDevRev.attachmentsMetadata.artifactIds.shift();
642
- this.state.toDevRev.attachmentsMetadata.lastProcessed = 0;
643
- }
653
+ console.log(`Finished processing all attachments for artifact ID: ${attachmentsMetadataArtifactId}.`);
654
+ this.state.toDevRev.attachmentsMetadata.artifactIds.shift();
655
+ this.state.toDevRev.attachmentsMetadata.lastProcessed = 0;
644
656
  }
645
657
  return;
646
658
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrev/ts-adaas",
3
- "version": "1.2.5",
3
+ "version": "1.3.0",
4
4
  "description": "DevRev ADaaS (AirDrop-as-a-Service) Typescript SDK.",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -37,7 +37,7 @@
37
37
  "typescript": "^5.3.3"
38
38
  },
39
39
  "dependencies": {
40
- "@devrev/typescript-sdk": "^1.1.27",
40
+ "@devrev/typescript-sdk": "^1.1.54",
41
41
  "axios": "^1.7.9",
42
42
  "axios-retry": "^4.5.0",
43
43
  "form-data": "^4.0.1",