@devrev/ts-adaas 1.8.1 → 1.9.0-beta.1

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.
@@ -1,8 +1,13 @@
1
1
  import { EventType } from '../types/extraction';
2
- export declare const STATELESS_EVENT_TYPES: EventType[];
3
2
  export declare const ALLOWED_EXTRACTION_EVENT_TYPES: EventType[];
4
3
  export declare const ALLOWED_LOADING_EVENT_TYPES: EventType[];
5
4
  export declare const ALLOWED_EVENT_TYPES: EventType[];
5
+ export declare const STATELESS_EXTRACTION_EVENT_TYPES: EventType[];
6
+ export declare const STATELESS_LOADING_EVENT_TYPES: EventType[];
7
+ export declare const STATELESS_EVENT_TYPES: EventType[];
8
+ export declare const STATEFUL_EXTRACTION_EVENT_TYPES: EventType[];
9
+ export declare const STATEFUL_LOADING_EVENT_TYPES: EventType[];
10
+ export declare const STATEFUL_EVENT_TYPES: EventType[];
6
11
  export declare const ARTIFACT_BATCH_SIZE = 2000;
7
12
  export declare const MAX_DEVREV_ARTIFACT_SIZE = 262144000;
8
13
  export declare const MAX_DEVREV_FILENAME_LENGTH = 256;
@@ -1,16 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_SLEEP_DELAY_MS = exports.HARD_TIMEOUT_MULTIPLIER = exports.DEFAULT_LAMBDA_TIMEOUT = exports.LIBRARY_VERSION = exports.AIRDROP_DEFAULT_ITEM_TYPES = exports.MAX_DEVREV_FILENAME_EXTENSION_LENGTH = exports.MAX_DEVREV_FILENAME_LENGTH = exports.MAX_DEVREV_ARTIFACT_SIZE = exports.ARTIFACT_BATCH_SIZE = exports.ALLOWED_EVENT_TYPES = exports.ALLOWED_LOADING_EVENT_TYPES = exports.ALLOWED_EXTRACTION_EVENT_TYPES = exports.STATELESS_EVENT_TYPES = void 0;
3
+ exports.DEFAULT_SLEEP_DELAY_MS = exports.HARD_TIMEOUT_MULTIPLIER = exports.DEFAULT_LAMBDA_TIMEOUT = exports.LIBRARY_VERSION = exports.AIRDROP_DEFAULT_ITEM_TYPES = exports.MAX_DEVREV_FILENAME_EXTENSION_LENGTH = exports.MAX_DEVREV_FILENAME_LENGTH = exports.MAX_DEVREV_ARTIFACT_SIZE = exports.ARTIFACT_BATCH_SIZE = exports.STATEFUL_EVENT_TYPES = exports.STATEFUL_LOADING_EVENT_TYPES = exports.STATEFUL_EXTRACTION_EVENT_TYPES = exports.STATELESS_EVENT_TYPES = exports.STATELESS_LOADING_EVENT_TYPES = exports.STATELESS_EXTRACTION_EVENT_TYPES = exports.ALLOWED_EVENT_TYPES = exports.ALLOWED_LOADING_EVENT_TYPES = exports.ALLOWED_EXTRACTION_EVENT_TYPES = void 0;
4
4
  const extraction_1 = require("../types/extraction");
5
5
  const helpers_1 = require("./helpers");
6
- exports.STATELESS_EVENT_TYPES = [
7
- extraction_1.EventType.ExtractionExternalSyncUnitsStart,
8
- extraction_1.EventType.ExtractionMetadataStart,
9
- extraction_1.EventType.ExtractionDataDelete,
10
- extraction_1.EventType.ExtractionAttachmentsDelete,
11
- extraction_1.EventType.StartDeletingLoaderState,
12
- extraction_1.EventType.StartDeletingLoaderAttachmentState,
13
- ];
14
6
  exports.ALLOWED_EXTRACTION_EVENT_TYPES = [
15
7
  extraction_1.EventType.ExtractionExternalSyncUnitsStart,
16
8
  extraction_1.EventType.ExtractionMetadataStart,
@@ -31,6 +23,25 @@ exports.ALLOWED_EVENT_TYPES = [
31
23
  ...exports.ALLOWED_EXTRACTION_EVENT_TYPES,
32
24
  ...exports.ALLOWED_LOADING_EVENT_TYPES,
33
25
  ];
26
+ exports.STATELESS_EXTRACTION_EVENT_TYPES = [
27
+ extraction_1.EventType.ExtractionExternalSyncUnitsStart,
28
+ extraction_1.EventType.ExtractionDataDelete,
29
+ extraction_1.EventType.ExtractionAttachmentsDelete,
30
+ ];
31
+ exports.STATELESS_LOADING_EVENT_TYPES = [
32
+ extraction_1.EventType.StartDeletingLoaderState,
33
+ extraction_1.EventType.StartDeletingLoaderAttachmentState,
34
+ ];
35
+ exports.STATELESS_EVENT_TYPES = [
36
+ ...exports.STATELESS_EXTRACTION_EVENT_TYPES,
37
+ ...exports.STATELESS_LOADING_EVENT_TYPES,
38
+ ];
39
+ exports.STATEFUL_EXTRACTION_EVENT_TYPES = exports.ALLOWED_EXTRACTION_EVENT_TYPES.filter((eventType) => !exports.STATELESS_EXTRACTION_EVENT_TYPES.includes(eventType));
40
+ exports.STATEFUL_LOADING_EVENT_TYPES = exports.ALLOWED_LOADING_EVENT_TYPES.filter((eventType) => !exports.STATELESS_LOADING_EVENT_TYPES.includes(eventType));
41
+ exports.STATEFUL_EVENT_TYPES = [
42
+ ...exports.STATEFUL_EXTRACTION_EVENT_TYPES,
43
+ ...exports.STATEFUL_LOADING_EVENT_TYPES,
44
+ ];
34
45
  exports.ARTIFACT_BATCH_SIZE = 2000;
35
46
  exports.MAX_DEVREV_ARTIFACT_SIZE = 262144000; // 250MB
36
47
  exports.MAX_DEVREV_FILENAME_LENGTH = 256;
@@ -1,25 +1,29 @@
1
- import { ErrorRecord } from '../types/common';
2
1
  import { AdapterState, StateInterface } from './state.interfaces';
3
2
  export declare function createAdapterState<ConnectorState>({ event, initialState, initialDomainMapping, options, }: StateInterface<ConnectorState>): Promise<State<ConnectorState>>;
4
3
  export declare class State<ConnectorState> {
5
4
  private _state;
6
5
  private initialSdkState;
7
- private event;
8
6
  private workerUrl;
9
7
  private devrevToken;
8
+ private syncUnitId;
9
+ private requestId;
10
10
  constructor({ event, initialState }: StateInterface<ConnectorState>);
11
11
  get state(): AdapterState<ConnectorState>;
12
12
  set state(value: AdapterState<ConnectorState>);
13
13
  /**
14
- * Updates the state of the adapter.
15
- *
14
+ * Initializes the state for this adapter instance by fetching from API
15
+ * or creating an initial state if none exists (404).
16
+ * @param initialState The initial connector state provided by the spawn function
17
+ */
18
+ init(initialState: ConnectorState): Promise<void>;
19
+ /**
20
+ * Updates the state of the adapter by posting to API.
16
21
  * @param {object} state - The state to be updated
17
22
  */
18
23
  postState(state?: AdapterState<ConnectorState>): Promise<void>;
19
24
  /**
20
- * Fetches the state of the adapter.
21
- *
22
- * @return The state of the adapter
25
+ * Fetches the state of the adapter from API.
26
+ * @return The raw state data from API
23
27
  */
24
- fetchState(initialState: ConnectorState): Promise<AdapterState<ConnectorState> | ErrorRecord>;
28
+ fetchState(): Promise<string>;
25
29
  }
@@ -30,3 +30,21 @@ export interface StateInterface<ConnectorState> {
30
30
  initialDomainMapping?: InitialDomainMapping;
31
31
  options?: WorkerAdapterOptions;
32
32
  }
33
+ export declare const extractionSdkState: {
34
+ lastSyncStarted: string;
35
+ lastSuccessfulSyncStarted: string;
36
+ snapInVersionId: string;
37
+ toDevRev: {
38
+ attachmentsMetadata: {
39
+ artifactIds: never[];
40
+ lastProcessed: number;
41
+ lastProcessedAttachmentsIdsList: never[];
42
+ };
43
+ };
44
+ };
45
+ export declare const loadingSdkState: {
46
+ snapInVersionId: string;
47
+ fromDevRev: {
48
+ filesToLoad: never[];
49
+ };
50
+ };
@@ -1,2 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadingSdkState = exports.extractionSdkState = void 0;
4
+ exports.extractionSdkState = {
5
+ lastSyncStarted: '',
6
+ lastSuccessfulSyncStarted: '',
7
+ snapInVersionId: '',
8
+ toDevRev: {
9
+ attachmentsMetadata: {
10
+ artifactIds: [],
11
+ lastProcessed: 0,
12
+ lastProcessedAttachmentsIdsList: [],
13
+ },
14
+ },
15
+ };
16
+ exports.loadingSdkState = {
17
+ snapInVersionId: '',
18
+ fromDevRev: {
19
+ filesToLoad: [],
20
+ },
21
+ };
@@ -8,39 +8,44 @@ exports.createAdapterState = createAdapterState;
8
8
  const axios_1 = __importDefault(require("axios"));
9
9
  const axios_client_internal_1 = require("../http/axios-client-internal");
10
10
  const extraction_1 = require("../types/extraction");
11
+ const common_1 = require("../types/common");
11
12
  const constants_1 = require("../common/constants");
12
13
  const logger_1 = require("../logger/logger");
13
14
  const install_initial_domain_mapping_1 = require("../common/install-initial-domain-mapping");
14
15
  const helpers_1 = require("../common/helpers");
16
+ const state_interfaces_1 = require("./state.interfaces");
15
17
  async function createAdapterState({ event, initialState, initialDomainMapping, options, }) {
16
- const newInitialState = structuredClone(initialState);
18
+ // Deep clone the initial state to avoid mutating the original state
19
+ const deepCloneInitialState = structuredClone(initialState);
17
20
  const as = new State({
18
21
  event,
19
- initialState: newInitialState,
22
+ initialState: deepCloneInitialState,
20
23
  initialDomainMapping,
21
24
  options,
22
25
  });
23
26
  if (!constants_1.STATELESS_EVENT_TYPES.includes(event.payload.event_type)) {
24
- await as.fetchState(newInitialState);
27
+ await as.init(deepCloneInitialState);
25
28
  // Check if IDM needs to be updated
26
29
  const snapInVersionId = event.context.snap_in_version_id;
27
30
  const hasSnapInVersionInState = 'snapInVersionId' in as.state;
28
31
  const shouldUpdateIDM = !hasSnapInVersionInState || as.state.snapInVersionId !== snapInVersionId;
29
32
  if (!shouldUpdateIDM) {
30
- console.log(`Snap-in version in state matches the version in event context (${snapInVersionId}). Skipping initial domain mapping installation.`);
33
+ console.log(`Snap-in version in state matches the version in event context "${snapInVersionId}". Skipping initial domain mapping installation.`);
31
34
  }
32
35
  else {
33
36
  try {
37
+ console.log(`Snap-in version in state "${as.state.snapInVersionId}" does not match the version in event context "${snapInVersionId}". Installing initial domain mapping.`);
34
38
  if (initialDomainMapping) {
35
39
  await (0, install_initial_domain_mapping_1.installInitialDomainMapping)(event, initialDomainMapping);
36
40
  as.state.snapInVersionId = snapInVersionId;
37
41
  }
38
42
  else {
39
- console.warn('No initial domain mapping was passed to spawn function. Skipping initial domain mapping installation.');
43
+ throw new Error('No initial domain mapping was passed to spawn function. Skipping initial domain mapping installation.');
40
44
  }
41
45
  }
42
46
  catch (error) {
43
47
  console.error('Error while installing initial domain mapping.', (0, logger_1.serializeError)(error));
48
+ process.exit(1);
44
49
  }
45
50
  }
46
51
  // Set lastSyncStarted if the event type is ExtractionDataStart
@@ -55,29 +60,14 @@ async function createAdapterState({ event, initialState, initialDomainMapping, o
55
60
  class State {
56
61
  constructor({ event, initialState }) {
57
62
  this.initialSdkState =
58
- (0, helpers_1.getSyncDirection)({ event }) === extraction_1.SyncMode.LOADING
59
- ? {
60
- snapInVersionId: '',
61
- fromDevRev: {
62
- filesToLoad: [],
63
- },
64
- }
65
- : {
66
- lastSyncStarted: '',
67
- lastSuccessfulSyncStarted: '',
68
- snapInVersionId: '',
69
- toDevRev: {
70
- attachmentsMetadata: {
71
- artifactIds: [],
72
- lastProcessed: 0,
73
- lastProcessedAttachmentsIdsList: [],
74
- },
75
- },
76
- };
63
+ (0, helpers_1.getSyncDirection)({ event }) === common_1.SyncMode.LOADING
64
+ ? state_interfaces_1.loadingSdkState
65
+ : state_interfaces_1.extractionSdkState;
77
66
  this._state = Object.assign(Object.assign({}, initialState), this.initialSdkState);
78
- this.event = event;
79
67
  this.workerUrl = event.payload.event_context.worker_data_url;
80
68
  this.devrevToken = event.context.secrets.service_account_token;
69
+ this.syncUnitId = event.payload.event_context.sync_unit_id;
70
+ this.requestId = event.payload.event_context.request_id_adaas;
81
71
  }
82
72
  get state() {
83
73
  return this._state;
@@ -86,24 +76,67 @@ class State {
86
76
  this._state = value;
87
77
  }
88
78
  /**
89
- * Updates the state of the adapter.
90
- *
79
+ * Initializes the state for this adapter instance by fetching from API
80
+ * or creating an initial state if none exists (404).
81
+ * @param initialState The initial connector state provided by the spawn function
82
+ */
83
+ async init(initialState) {
84
+ var _a;
85
+ try {
86
+ const stringifiedState = await this.fetchState();
87
+ if (!stringifiedState) {
88
+ throw new Error('No state found in response.');
89
+ }
90
+ let parsedState;
91
+ try {
92
+ parsedState = JSON.parse(stringifiedState);
93
+ }
94
+ catch (error) {
95
+ throw new Error('Failed to parse state.');
96
+ }
97
+ this.state = parsedState;
98
+ console.log('State fetched successfully. Current state', (0, logger_1.getPrintableState)(this.state));
99
+ }
100
+ catch (error) {
101
+ if (axios_1.default.isAxiosError(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
102
+ console.log('State not found. Initializing state with initial state.');
103
+ const initialAdapterState = Object.assign(Object.assign({}, initialState), this.initialSdkState);
104
+ this.state = initialAdapterState;
105
+ await this.postState(initialAdapterState);
106
+ }
107
+ else {
108
+ console.error('Failed to init state.', (0, logger_1.serializeError)(error));
109
+ process.exit(1);
110
+ }
111
+ }
112
+ }
113
+ /**
114
+ * Updates the state of the adapter by posting to API.
91
115
  * @param {object} state - The state to be updated
92
116
  */
93
117
  async postState(state) {
118
+ const url = this.workerUrl + '.update';
119
+ this.state = state || this.state;
120
+ let stringifiedState;
94
121
  try {
95
- await axios_client_internal_1.axiosClient.post(this.workerUrl + '.update', {
96
- state: JSON.stringify(state || this.state),
122
+ stringifiedState = JSON.stringify(this.state);
123
+ }
124
+ catch (error) {
125
+ console.error('Failed to stringify state.', (0, logger_1.serializeError)(error));
126
+ process.exit(1);
127
+ }
128
+ try {
129
+ await axios_client_internal_1.axiosClient.post(url, {
130
+ state: stringifiedState,
97
131
  }, {
98
132
  headers: {
99
133
  Authorization: this.devrevToken,
100
134
  },
101
135
  params: {
102
- sync_unit: this.event.payload.event_context.sync_unit_id,
103
- request_id: this.event.payload.event_context.request_id_adaas,
136
+ sync_unit: this.syncUnitId,
137
+ request_id: this.requestId,
104
138
  },
105
139
  });
106
- this.state = state || this.state;
107
140
  console.log('State updated successfully to', (0, logger_1.getPrintableState)(this.state));
108
141
  }
109
142
  catch (error) {
@@ -112,42 +145,23 @@ class State {
112
145
  }
113
146
  }
114
147
  /**
115
- * Fetches the state of the adapter.
116
- *
117
- * @return The state of the adapter
148
+ * Fetches the state of the adapter from API.
149
+ * @return The raw state data from API
118
150
  */
119
- async fetchState(initialState) {
151
+ async fetchState() {
120
152
  var _a;
121
- console.log('Fetching state with sync unit id: ' +
122
- this.event.payload.event_context.sync_unit_id +
123
- '.');
124
- try {
125
- const response = await axios_client_internal_1.axiosClient.get(this.workerUrl + '.get', {
126
- headers: {
127
- Authorization: this.devrevToken,
128
- },
129
- params: {
130
- sync_unit: this.event.payload.event_context.sync_unit_id,
131
- request_id: this.event.payload.event_context.request_id_adaas,
132
- },
133
- });
134
- this.state = JSON.parse(response.data.state);
135
- console.log('State fetched successfully. Current state', (0, logger_1.getPrintableState)(this.state));
136
- return this.state;
137
- }
138
- catch (error) {
139
- if (axios_1.default.isAxiosError(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
140
- const state = Object.assign(Object.assign({}, initialState), this.initialSdkState);
141
- this.state = state;
142
- console.log('State not found, returning initial state. Current state', (0, logger_1.getPrintableState)(this.state));
143
- await this.postState(this.state);
144
- return this.state;
145
- }
146
- else {
147
- console.error('Failed to fetch state.', error);
148
- process.exit(1);
149
- }
150
- }
153
+ console.log(`Fetching state with sync unit id ${this.syncUnitId} and request id ${this.requestId}.`);
154
+ const url = this.workerUrl + '.get';
155
+ const response = await axios_client_internal_1.axiosClient.get(url, {
156
+ headers: {
157
+ Authorization: this.devrevToken,
158
+ },
159
+ params: {
160
+ sync_unit: this.syncUnitId,
161
+ request_id: this.requestId,
162
+ },
163
+ });
164
+ return (_a = response.data) === null || _a === void 0 ? void 0 : _a.state;
151
165
  }
152
166
  }
153
167
  exports.State = State;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const state_1 = require("./state");
4
+ const extraction_1 = require("../types/extraction");
5
+ const test_helpers_1 = require("../tests/test-helpers");
6
+ const constants_1 = require("../common/constants");
7
+ const state_interfaces_1 = require("./state.interfaces");
8
+ describe(state_1.State.name, () => {
9
+ let initSpy;
10
+ let postStateSpy;
11
+ let fetchStateSpy;
12
+ let installInitialDomainMappingSpy;
13
+ let processExitSpy;
14
+ beforeEach(() => {
15
+ jest.clearAllMocks();
16
+ jest.restoreAllMocks();
17
+ initSpy = jest.spyOn(state_1.State.prototype, 'init');
18
+ postStateSpy = jest.spyOn(state_1.State.prototype, 'postState');
19
+ fetchStateSpy = jest.spyOn(state_1.State.prototype, 'fetchState');
20
+ installInitialDomainMappingSpy = jest.spyOn(require('../common/install-initial-domain-mapping'), 'installInitialDomainMapping');
21
+ processExitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {
22
+ throw new Error('process.exit called');
23
+ });
24
+ });
25
+ it.each(constants_1.STATELESS_EVENT_TYPES)('should not init, fetch, post or install IDM for stateless event type %s', async (eventType) => {
26
+ // Arrange
27
+ const event = (0, test_helpers_1.createEvent)({
28
+ eventType: eventType,
29
+ });
30
+ // Act
31
+ await (0, state_1.createAdapterState)({
32
+ event,
33
+ initialState: {},
34
+ initialDomainMapping: {},
35
+ });
36
+ // Assert
37
+ expect(initSpy).not.toHaveBeenCalled();
38
+ expect(fetchStateSpy).not.toHaveBeenCalled();
39
+ expect(postStateSpy).not.toHaveBeenCalled();
40
+ expect(installInitialDomainMappingSpy).not.toHaveBeenCalled();
41
+ });
42
+ it.each(constants_1.STATEFUL_EVENT_TYPES)('should exit the process if fetching the state fails', async (eventType) => {
43
+ // Arrange
44
+ const event = (0, test_helpers_1.createEvent)({
45
+ eventType: eventType,
46
+ });
47
+ fetchStateSpy.mockRejectedValue({
48
+ isAxiosError: true,
49
+ response: { status: 500 },
50
+ });
51
+ jest.spyOn(console, 'error').mockImplementation(() => { });
52
+ // Act & Assert
53
+ await expect((0, state_1.createAdapterState)({
54
+ event,
55
+ initialState: {},
56
+ initialDomainMapping: {},
57
+ })).rejects.toThrow('process.exit called');
58
+ expect(processExitSpy).toHaveBeenCalledWith(1);
59
+ });
60
+ it.each(constants_1.STATEFUL_EVENT_TYPES)('should exit the process if parsing the state fails', async (eventType) => {
61
+ // Arrange
62
+ const event = (0, test_helpers_1.createEvent)({
63
+ eventType: eventType,
64
+ });
65
+ fetchStateSpy.mockResolvedValue('invalid-json');
66
+ jest.spyOn(console, 'error').mockImplementation(() => { });
67
+ // Act & Assert
68
+ await expect((0, state_1.createAdapterState)({
69
+ event,
70
+ initialState: {},
71
+ initialDomainMapping: {},
72
+ })).rejects.toThrow('process.exit called');
73
+ expect(processExitSpy).toHaveBeenCalledWith(1);
74
+ });
75
+ it.each(constants_1.STATEFUL_EVENT_TYPES)('should exit the process if fetching is successful but there is no state in the response', async (eventType) => {
76
+ // Arrange
77
+ const event = (0, test_helpers_1.createEvent)({
78
+ eventType: eventType,
79
+ });
80
+ fetchStateSpy.mockResolvedValue(null);
81
+ jest.spyOn(console, 'error').mockImplementation(() => { });
82
+ // Act & Assert
83
+ await expect((0, state_1.createAdapterState)({
84
+ event,
85
+ initialState: {},
86
+ initialDomainMapping: {},
87
+ })).rejects.toThrow('process.exit called');
88
+ expect(processExitSpy).toHaveBeenCalledWith(1);
89
+ });
90
+ it.each(constants_1.STATEFUL_EVENT_TYPES.filter((eventType) => eventType !== extraction_1.EventType.ExtractionDataStart))('should call post state with full adapter state if fetching returns 404 for event type %s', async (eventType) => {
91
+ // Arrange
92
+ const initialState = {
93
+ test: 'test',
94
+ };
95
+ const event = (0, test_helpers_1.createEvent)({
96
+ eventType: eventType,
97
+ contextOverrides: {
98
+ snap_in_version_id: '',
99
+ },
100
+ });
101
+ fetchStateSpy.mockRejectedValue({
102
+ isAxiosError: true,
103
+ response: { status: 404 },
104
+ });
105
+ installInitialDomainMappingSpy.mockResolvedValue({
106
+ success: true,
107
+ });
108
+ postStateSpy.mockResolvedValue({
109
+ success: true,
110
+ });
111
+ jest.spyOn(console, 'log').mockImplementation(() => { });
112
+ // Act
113
+ await (0, state_1.createAdapterState)({
114
+ event,
115
+ initialState,
116
+ initialDomainMapping: {},
117
+ });
118
+ const expectedState = Object.assign(Object.assign({}, initialState), state_interfaces_1.extractionSdkState);
119
+ expect(postStateSpy).toHaveBeenCalledWith(expectedState);
120
+ });
121
+ it(extraction_1.EventType.ExtractionDataStart, async () => {
122
+ // Arrange
123
+ const initialState = {
124
+ test: 'test',
125
+ };
126
+ const event = (0, test_helpers_1.createEvent)({
127
+ eventType: extraction_1.EventType.ExtractionDataStart,
128
+ contextOverrides: {
129
+ snap_in_version_id: '',
130
+ },
131
+ });
132
+ fetchStateSpy.mockRejectedValue({
133
+ isAxiosError: true,
134
+ response: { status: 404 },
135
+ });
136
+ installInitialDomainMappingSpy.mockResolvedValue({
137
+ success: true,
138
+ });
139
+ postStateSpy.mockResolvedValue({
140
+ success: true,
141
+ });
142
+ jest.spyOn(console, 'log').mockImplementation(() => { });
143
+ // Act
144
+ await (0, state_1.createAdapterState)({
145
+ event,
146
+ initialState,
147
+ initialDomainMapping: {},
148
+ });
149
+ // Assert
150
+ // Verify that post state is called with object that contains
151
+ // lastSyncStarted which is not empty string
152
+ expect(postStateSpy).toHaveBeenCalledWith(expect.objectContaining({
153
+ lastSyncStarted: expect.not.stringMatching(/^$/),
154
+ }));
155
+ });
156
+ it.each(constants_1.STATEFUL_EVENT_TYPES)('should exit the process if initialDomainMapping is not provided for event type %s', async (eventType) => {
157
+ // Arrange
158
+ const event = (0, test_helpers_1.createEvent)({
159
+ eventType: eventType,
160
+ });
161
+ fetchStateSpy.mockResolvedValue(JSON.stringify({
162
+ test: 'test',
163
+ }));
164
+ jest.spyOn(console, 'log').mockImplementation(() => { });
165
+ jest.spyOn(console, 'error').mockImplementation(() => { });
166
+ // Act & Assert
167
+ await expect((0, state_1.createAdapterState)({
168
+ event,
169
+ initialState: {},
170
+ initialDomainMapping: undefined,
171
+ })).rejects.toThrow('process.exit called');
172
+ expect(processExitSpy).toHaveBeenCalledWith(1);
173
+ });
174
+ it.each(constants_1.STATEFUL_EVENT_TYPES)('should not install IDM if version matches for event type %s', async (eventType) => {
175
+ // Arrange
176
+ const event = (0, test_helpers_1.createEvent)({
177
+ eventType: eventType,
178
+ contextOverrides: {
179
+ snap_in_version_id: '1.0.0',
180
+ },
181
+ });
182
+ const stringifiedState = JSON.stringify({
183
+ test: 'test',
184
+ snapInVersionId: '1.0.0',
185
+ });
186
+ fetchStateSpy.mockResolvedValue(stringifiedState);
187
+ jest.spyOn(console, 'log').mockImplementation(() => { });
188
+ // Act & Assert
189
+ await (0, state_1.createAdapterState)({
190
+ event,
191
+ initialState: {},
192
+ initialDomainMapping: {},
193
+ });
194
+ // Assert
195
+ expect(installInitialDomainMappingSpy).not.toHaveBeenCalled();
196
+ });
197
+ it.each(constants_1.STATEFUL_EVENT_TYPES)('should install IDM if version does not match for event type %s', async (eventType) => {
198
+ // Arrange
199
+ const event = (0, test_helpers_1.createEvent)({
200
+ eventType: eventType,
201
+ contextOverrides: {
202
+ snap_in_version_id: '2.0.0',
203
+ },
204
+ });
205
+ const stringifiedState = JSON.stringify({
206
+ test: 'test',
207
+ snapInVersionId: '1.0.0',
208
+ });
209
+ fetchStateSpy.mockResolvedValue(stringifiedState);
210
+ installInitialDomainMappingSpy.mockResolvedValue({
211
+ success: true,
212
+ });
213
+ jest.spyOn(console, 'log').mockImplementation(() => { });
214
+ // Act
215
+ await (0, state_1.createAdapterState)({
216
+ event,
217
+ initialState: {},
218
+ initialDomainMapping: {},
219
+ });
220
+ // Assert
221
+ expect(installInitialDomainMappingSpy).toHaveBeenCalled();
222
+ });
223
+ });
@@ -36,3 +36,14 @@ export interface InitialDomainMapping {
36
36
  starting_recipe_blueprint?: object;
37
37
  additional_mappings?: object;
38
38
  }
39
+ /**
40
+ * SyncMode is an enum that defines the different modes of sync that can be used by the external extractor.
41
+ * It can be either INITIAL, INCREMENTAL or LOADING. INITIAL mode is used for
42
+ * the first/initial import, while INCREMENTAL mode is used for doing syncs. LOADING mode is used for
43
+ * loading data from DevRev to the external system.
44
+ */
45
+ export declare enum SyncMode {
46
+ INITIAL = "INITIAL",
47
+ INCREMENTAL = "INCREMENTAL",
48
+ LOADING = "LOADING"
49
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ErrorLevel = void 0;
3
+ exports.SyncMode = exports.ErrorLevel = void 0;
4
4
  /**
5
5
  * ErrorLevel is an enum that represents the level of an error.
6
6
  * @deprecated
@@ -11,3 +11,15 @@ var ErrorLevel;
11
11
  ErrorLevel["Error"] = "ERROR";
12
12
  ErrorLevel["Info"] = "INFO";
13
13
  })(ErrorLevel || (exports.ErrorLevel = ErrorLevel = {}));
14
+ /**
15
+ * SyncMode is an enum that defines the different modes of sync that can be used by the external extractor.
16
+ * It can be either INITIAL, INCREMENTAL or LOADING. INITIAL mode is used for
17
+ * the first/initial import, while INCREMENTAL mode is used for doing syncs. LOADING mode is used for
18
+ * loading data from DevRev to the external system.
19
+ */
20
+ var SyncMode;
21
+ (function (SyncMode) {
22
+ SyncMode["INITIAL"] = "INITIAL";
23
+ SyncMode["INCREMENTAL"] = "INCREMENTAL";
24
+ SyncMode["LOADING"] = "LOADING";
25
+ })(SyncMode || (exports.SyncMode = SyncMode = {}));
@@ -57,15 +57,6 @@ export declare enum ExtractionMode {
57
57
  INITIAL = "INITIAL",
58
58
  INCREMENTAL = "INCREMENTAL"
59
59
  }
60
- /**
61
- * ExtractionMode is an enum that defines the different modes of extraction that can be used by the external extractor.
62
- * It can be either INITIAL or INCREMENTAL. INITIAL mode is used for the first/initial import, while INCREMENTAL mode is used for doing syncs.
63
- */
64
- export declare enum SyncMode {
65
- INITIAL = "INITIAL",
66
- INCREMENTAL = "INCREMENTAL",
67
- LOADING = "LOADING"
68
- }
69
60
  /**
70
61
  * ExternalSyncUnit is an interface that defines the structure of an external sync unit (repos, projects, ...) that can be extracted.
71
62
  * It must contain an ID, a name, and a description. It can also contain the number of items in the external sync unit.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InitialSyncScope = exports.SyncMode = exports.ExtractionMode = exports.ExtractorEventType = exports.EventType = void 0;
3
+ exports.InitialSyncScope = exports.ExtractionMode = exports.ExtractorEventType = exports.EventType = void 0;
4
4
  /**
5
5
  * EventType is an enum that defines the different types of events that can be sent to the external extractor from ADaaS.
6
6
  * The external extractor can use these events to know what to do next in the extraction process.
@@ -60,16 +60,6 @@ var ExtractionMode;
60
60
  ExtractionMode["INITIAL"] = "INITIAL";
61
61
  ExtractionMode["INCREMENTAL"] = "INCREMENTAL";
62
62
  })(ExtractionMode || (exports.ExtractionMode = ExtractionMode = {}));
63
- /**
64
- * ExtractionMode is an enum that defines the different modes of extraction that can be used by the external extractor.
65
- * It can be either INITIAL or INCREMENTAL. INITIAL mode is used for the first/initial import, while INCREMENTAL mode is used for doing syncs.
66
- */
67
- var SyncMode;
68
- (function (SyncMode) {
69
- SyncMode["INITIAL"] = "INITIAL";
70
- SyncMode["INCREMENTAL"] = "INCREMENTAL";
71
- SyncMode["LOADING"] = "LOADING";
72
- })(SyncMode || (exports.SyncMode = SyncMode = {}));
73
63
  /**
74
64
  * InitialSyncScope is an enum that defines the different scopes of initial sync that can be used by the external extractor.
75
65
  */
@@ -1,5 +1,5 @@
1
- export { ErrorLevel, ErrorRecord, LogRecord, AdapterUpdateParams, InitialDomainMapping, } from './common';
2
- export { EventType, ExtractorEventType, ExtractionMode, ExternalSyncUnit, EventContextIn, EventContextOut, ConnectionData, EventData, DomainObjectState, AirdropEvent, AirdropMessage, ExtractorEvent, SyncMode, ExternalSystemAttachmentStreamingParams, ExternalSystemAttachmentStreamingResponse, ExternalSystemAttachmentStreamingFunction, ExternalProcessAttachmentFunction, ExternalSystemAttachmentReducerFunction, ExternalSystemAttachmentIteratorFunction, ProcessAttachmentReturnType, } from './extraction';
1
+ export { ErrorLevel, ErrorRecord, LogRecord, AdapterUpdateParams, InitialDomainMapping, SyncMode, } from './common';
2
+ export { EventType, ExtractorEventType, ExtractionMode, ExternalSyncUnit, EventContextIn, EventContextOut, ConnectionData, EventData, DomainObjectState, AirdropEvent, AirdropMessage, ExtractorEvent, ExternalSystemAttachmentStreamingParams, ExternalSystemAttachmentStreamingResponse, ExternalSystemAttachmentStreamingFunction, ExternalProcessAttachmentFunction, ExternalSystemAttachmentReducerFunction, ExternalSystemAttachmentIteratorFunction, ProcessAttachmentReturnType, } from './extraction';
3
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';
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LoaderEventType = exports.SyncMode = exports.ExtractionMode = exports.ExtractorEventType = exports.EventType = exports.ErrorLevel = void 0;
3
+ exports.LoaderEventType = exports.ExtractionMode = exports.ExtractorEventType = exports.EventType = exports.SyncMode = exports.ErrorLevel = void 0;
4
4
  // Common
5
5
  var common_1 = require("./common");
6
6
  Object.defineProperty(exports, "ErrorLevel", { enumerable: true, get: function () { return common_1.ErrorLevel; } });
7
+ Object.defineProperty(exports, "SyncMode", { enumerable: true, get: function () { return common_1.SyncMode; } });
7
8
  // Extraction
8
9
  var extraction_1 = require("./extraction");
9
10
  Object.defineProperty(exports, "EventType", { enumerable: true, get: function () { return extraction_1.EventType; } });
10
11
  Object.defineProperty(exports, "ExtractorEventType", { enumerable: true, get: function () { return extraction_1.ExtractorEventType; } });
11
12
  Object.defineProperty(exports, "ExtractionMode", { enumerable: true, get: function () { return extraction_1.ExtractionMode; } });
12
- Object.defineProperty(exports, "SyncMode", { enumerable: true, get: function () { return extraction_1.SyncMode; } });
13
13
  // Loading
14
14
  var loading_1 = require("./loading");
15
15
  Object.defineProperty(exports, "LoaderEventType", { enumerable: true, get: function () { return loading_1.LoaderEventType; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrev/ts-adaas",
3
- "version": "1.8.1",
3
+ "version": "1.9.0-beta.1",
4
4
  "description": "Typescript library containing the ADaaS(AirDrop as a Service) control protocol.",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -11,7 +11,7 @@
11
11
  "start": "ts-node src/index.ts",
12
12
  "lint": "eslint .",
13
13
  "lint:fix": "eslint . --fix",
14
- "test": "jest --forceExit --coverage --runInBand --testPathIgnorePatterns='./dist/'"
14
+ "test": "jest --forceExit --coverage --runInBand"
15
15
  },
16
16
  "repository": {
17
17
  "type": "git",