@devrev/airsync-sdk 2.0.0-beta.1 → 2.0.0-beta.3

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 (191) hide show
  1. package/README.md +0 -4
  2. package/dist/airsync-sdk.d.ts +2059 -0
  3. package/dist/attachments-streaming/attachments-streaming-pool.d.ts +2 -1
  4. package/dist/attachments-streaming/attachments-streaming-pool.d.ts.map +1 -1
  5. package/dist/attachments-streaming/attachments-streaming-pool.interfaces.d.ts +8 -2
  6. package/dist/attachments-streaming/attachments-streaming-pool.interfaces.d.ts.map +1 -1
  7. package/dist/attachments-streaming/attachments-streaming-pool.js +27 -16
  8. package/dist/attachments-streaming/attachments-streaming-pool.test.js +246 -27
  9. package/dist/common/constants.d.ts +16 -5
  10. package/dist/common/constants.d.ts.map +1 -1
  11. package/dist/common/constants.js +20 -6
  12. package/dist/common/control-protocol.d.ts +2 -2
  13. package/dist/common/control-protocol.d.ts.map +1 -1
  14. package/dist/common/control-protocol.js +1 -5
  15. package/dist/common/helpers.d.ts +8 -0
  16. package/dist/common/helpers.d.ts.map +1 -1
  17. package/dist/common/helpers.js +15 -0
  18. package/dist/common/install-initial-domain-mapping.d.ts +2 -2
  19. package/dist/common/install-initial-domain-mapping.test.js +5 -2
  20. package/dist/common/test-utils.d.ts +19 -0
  21. package/dist/common/test-utils.d.ts.map +1 -0
  22. package/dist/common/test-utils.js +101 -0
  23. package/dist/common/time-value-resolver.d.ts +47 -0
  24. package/dist/common/time-value-resolver.d.ts.map +1 -0
  25. package/dist/common/time-value-resolver.js +141 -0
  26. package/dist/common/time-value-resolver.test.d.ts +2 -0
  27. package/dist/common/time-value-resolver.test.d.ts.map +1 -0
  28. package/dist/common/time-value-resolver.test.js +268 -0
  29. package/dist/http/axios-client-internal.d.ts.map +1 -1
  30. package/dist/http/axios-client-internal.js +7 -0
  31. package/dist/http/axios-client-internal.test.js +21 -0
  32. package/dist/http/axios-client.d.ts.map +1 -1
  33. package/dist/http/axios-client.js +6 -3
  34. package/dist/http/index.d.ts +0 -1
  35. package/dist/http/index.d.ts.map +1 -1
  36. package/dist/http/index.js +0 -1
  37. package/dist/index.d.ts +12 -10
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +18 -13
  40. package/dist/logger/logger.d.ts +1 -17
  41. package/dist/logger/logger.d.ts.map +1 -1
  42. package/dist/logger/logger.interfaces.d.ts +2 -2
  43. package/dist/logger/logger.js +35 -27
  44. package/dist/logger/logger.test.js +66 -19
  45. package/dist/mappers/mappers.interface.d.ts +5 -5
  46. package/dist/mappers/mappers.interface.js +3 -3
  47. package/dist/mappers/mappers.test.js +8 -10
  48. package/dist/mock-server/mock-server.d.ts +47 -0
  49. package/dist/mock-server/mock-server.d.ts.map +1 -0
  50. package/dist/mock-server/mock-server.interfaces.d.ts +73 -0
  51. package/dist/mock-server/mock-server.interfaces.d.ts.map +1 -0
  52. package/dist/mock-server/mock-server.interfaces.js +4 -0
  53. package/dist/mock-server/mock-server.js +278 -0
  54. package/dist/multithreading/adapters/base-adapter.d.ts +56 -0
  55. package/dist/multithreading/adapters/base-adapter.d.ts.map +1 -0
  56. package/dist/multithreading/adapters/base-adapter.emit.test.d.ts +2 -0
  57. package/dist/multithreading/adapters/base-adapter.emit.test.d.ts.map +1 -0
  58. package/dist/multithreading/adapters/base-adapter.emit.test.js +403 -0
  59. package/dist/multithreading/adapters/base-adapter.js +105 -0
  60. package/dist/multithreading/adapters/extraction-adapter.artifacts.test.d.ts +2 -0
  61. package/dist/multithreading/adapters/extraction-adapter.artifacts.test.d.ts.map +1 -0
  62. package/dist/multithreading/{worker-adapter/worker-adapter.artifacts.test.js → adapters/extraction-adapter.artifacts.test.js} +53 -5
  63. package/dist/multithreading/adapters/extraction-adapter.d.ts +58 -0
  64. package/dist/multithreading/adapters/extraction-adapter.d.ts.map +1 -0
  65. package/dist/multithreading/adapters/extraction-adapter.js +325 -0
  66. package/dist/multithreading/adapters/extraction-adapter.test.d.ts +2 -0
  67. package/dist/multithreading/adapters/extraction-adapter.test.d.ts.map +1 -0
  68. package/dist/multithreading/adapters/extraction-adapter.test.js +789 -0
  69. package/dist/multithreading/adapters/loading-adapter.d.ts +44 -0
  70. package/dist/multithreading/adapters/loading-adapter.d.ts.map +1 -0
  71. package/dist/multithreading/{worker-adapter/worker-adapter.helpers.d.ts → adapters/loading-adapter.helpers.d.ts} +1 -1
  72. package/dist/multithreading/adapters/loading-adapter.helpers.d.ts.map +1 -0
  73. package/dist/multithreading/adapters/loading-adapter.helpers.test.d.ts +2 -0
  74. package/dist/multithreading/adapters/loading-adapter.helpers.test.d.ts.map +1 -0
  75. package/dist/multithreading/{worker-adapter/worker-adapter.helpers.test.js → adapters/loading-adapter.helpers.test.js} +26 -26
  76. package/dist/multithreading/adapters/loading-adapter.js +461 -0
  77. package/dist/multithreading/adapters/loading-adapter.test.d.ts +2 -0
  78. package/dist/multithreading/adapters/loading-adapter.test.d.ts.map +1 -0
  79. package/dist/multithreading/adapters/loading-adapter.test.js +589 -0
  80. package/dist/multithreading/adapters/serialization.test.d.ts +2 -0
  81. package/dist/multithreading/adapters/serialization.test.d.ts.map +1 -0
  82. package/dist/multithreading/adapters/serialization.test.js +71 -0
  83. package/dist/multithreading/create-worker.test.js +36 -17
  84. package/dist/multithreading/process-task.d.ts +16 -1
  85. package/dist/multithreading/process-task.d.ts.map +1 -1
  86. package/dist/multithreading/process-task.js +97 -82
  87. package/dist/multithreading/process-task.test.d.ts +2 -0
  88. package/dist/multithreading/process-task.test.d.ts.map +1 -0
  89. package/dist/multithreading/process-task.test.js +146 -0
  90. package/dist/multithreading/spawn/spawn.d.ts +3 -3
  91. package/dist/multithreading/spawn/spawn.d.ts.map +1 -1
  92. package/dist/multithreading/spawn/spawn.helpers.d.ts.map +1 -1
  93. package/dist/multithreading/spawn/spawn.helpers.js +6 -14
  94. package/dist/multithreading/spawn/spawn.helpers.test.js +8 -8
  95. package/dist/multithreading/spawn/spawn.js +20 -25
  96. package/dist/multithreading/spawn/spawn.test.d.ts +2 -0
  97. package/dist/multithreading/spawn/spawn.test.d.ts.map +1 -0
  98. package/dist/multithreading/spawn/spawn.test.js +232 -0
  99. package/dist/repo/repo.d.ts.map +1 -1
  100. package/dist/repo/repo.interfaces.d.ts +4 -2
  101. package/dist/repo/repo.interfaces.d.ts.map +1 -1
  102. package/dist/repo/repo.js +4 -3
  103. package/dist/repo/repo.test.js +60 -7
  104. package/dist/state/base-state.d.ts +75 -0
  105. package/dist/state/base-state.d.ts.map +1 -0
  106. package/dist/state/base-state.js +261 -0
  107. package/dist/state/extraction-state.d.ts +29 -0
  108. package/dist/state/extraction-state.d.ts.map +1 -0
  109. package/dist/state/extraction-state.js +122 -0
  110. package/dist/state/loading-state.d.ts +19 -0
  111. package/dist/state/loading-state.d.ts.map +1 -0
  112. package/dist/state/loading-state.js +40 -0
  113. package/dist/state/state.extract-window.test.d.ts +2 -0
  114. package/dist/state/state.extract-window.test.d.ts.map +1 -0
  115. package/dist/state/state.extract-window.test.js +163 -0
  116. package/dist/state/state.interfaces.d.ts +44 -27
  117. package/dist/state/state.interfaces.d.ts.map +1 -1
  118. package/dist/state/state.interfaces.js +18 -5
  119. package/dist/state/state.pending-boundaries.test.d.ts +2 -0
  120. package/dist/state/state.pending-boundaries.test.d.ts.map +1 -0
  121. package/dist/state/state.pending-boundaries.test.js +189 -0
  122. package/dist/state/state.post-state.test.d.ts +2 -0
  123. package/dist/state/state.post-state.test.d.ts.map +1 -0
  124. package/dist/state/state.post-state.test.js +78 -0
  125. package/dist/state/state.test.js +135 -88
  126. package/dist/state/state.time-value-resolution.test.d.ts +2 -0
  127. package/dist/state/state.time-value-resolution.test.d.ts.map +1 -0
  128. package/dist/state/state.time-value-resolution.test.js +175 -0
  129. package/dist/tsdoc-metadata.json +11 -0
  130. package/dist/types/common.d.ts +0 -25
  131. package/dist/types/common.d.ts.map +1 -1
  132. package/dist/types/common.js +1 -11
  133. package/dist/types/external-domain-metadata.d.ts +20 -1
  134. package/dist/types/external-domain-metadata.d.ts.map +1 -1
  135. package/dist/types/extraction.d.ts +92 -221
  136. package/dist/types/extraction.d.ts.map +1 -1
  137. package/dist/types/extraction.js +56 -124
  138. package/dist/types/extraction.test.js +69 -43
  139. package/dist/types/index.d.ts +3 -3
  140. package/dist/types/index.d.ts.map +1 -1
  141. package/dist/types/index.js +6 -3
  142. package/dist/types/loading.d.ts +4 -24
  143. package/dist/types/loading.d.ts.map +1 -1
  144. package/dist/types/loading.js +1 -22
  145. package/dist/types/workers.d.ts +47 -29
  146. package/dist/types/workers.d.ts.map +1 -1
  147. package/dist/types/workers.js +1 -0
  148. package/dist/uploader/uploader.d.ts +1 -0
  149. package/dist/uploader/uploader.d.ts.map +1 -1
  150. package/dist/uploader/uploader.helpers.test.js +0 -11
  151. package/dist/uploader/uploader.interfaces.d.ts +3 -3
  152. package/dist/uploader/uploader.js +53 -20
  153. package/dist/uploader/uploader.test.js +22 -10
  154. package/package.json +10 -13
  155. package/dist/common/event-type-translation.d.ts +0 -24
  156. package/dist/common/event-type-translation.d.ts.map +0 -1
  157. package/dist/common/event-type-translation.js +0 -117
  158. package/dist/deprecated/adapter/index.d.ts +0 -62
  159. package/dist/deprecated/adapter/index.d.ts.map +0 -1
  160. package/dist/deprecated/adapter/index.js +0 -151
  161. package/dist/deprecated/common/helpers.d.ts +0 -7
  162. package/dist/deprecated/common/helpers.d.ts.map +0 -1
  163. package/dist/deprecated/common/helpers.js +0 -47
  164. package/dist/deprecated/demo-extractor/external_domain_metadata.json +0 -38
  165. package/dist/deprecated/demo-extractor/index.d.ts +0 -18
  166. package/dist/deprecated/demo-extractor/index.d.ts.map +0 -1
  167. package/dist/deprecated/demo-extractor/index.js +0 -161
  168. package/dist/deprecated/http/client.d.ts +0 -22
  169. package/dist/deprecated/http/client.d.ts.map +0 -1
  170. package/dist/deprecated/http/client.js +0 -161
  171. package/dist/deprecated/uploader/index.d.ts +0 -35
  172. package/dist/deprecated/uploader/index.d.ts.map +0 -1
  173. package/dist/deprecated/uploader/index.js +0 -161
  174. package/dist/http/types.d.ts +0 -17
  175. package/dist/http/types.d.ts.map +0 -1
  176. package/dist/http/types.js +0 -2
  177. package/dist/multithreading/worker-adapter/worker-adapter.artifacts.test.d.ts +0 -2
  178. package/dist/multithreading/worker-adapter/worker-adapter.artifacts.test.d.ts.map +0 -1
  179. package/dist/multithreading/worker-adapter/worker-adapter.d.ts +0 -91
  180. package/dist/multithreading/worker-adapter/worker-adapter.d.ts.map +0 -1
  181. package/dist/multithreading/worker-adapter/worker-adapter.helpers.d.ts.map +0 -1
  182. package/dist/multithreading/worker-adapter/worker-adapter.helpers.test.d.ts +0 -2
  183. package/dist/multithreading/worker-adapter/worker-adapter.helpers.test.d.ts.map +0 -1
  184. package/dist/multithreading/worker-adapter/worker-adapter.js +0 -745
  185. package/dist/multithreading/worker-adapter/worker-adapter.test.d.ts +0 -2
  186. package/dist/multithreading/worker-adapter/worker-adapter.test.d.ts.map +0 -1
  187. package/dist/multithreading/worker-adapter/worker-adapter.test.js +0 -483
  188. package/dist/state/state.d.ts +0 -30
  189. package/dist/state/state.d.ts.map +0 -1
  190. package/dist/state/state.js +0 -166
  191. /package/dist/multithreading/{worker-adapter/worker-adapter.helpers.js → adapters/loading-adapter.helpers.js} +0 -0
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jest_setup_1 = require("../tests/jest.setup");
4
+ const test_utils_1 = require("../common/test-utils");
5
+ const extraction_1 = require("../types/extraction");
6
+ const extraction_state_1 = require("./extraction-state");
7
+ describe('State — extraction window validation', () => {
8
+ let fetchStateSpy;
9
+ let processExitSpy;
10
+ beforeEach(() => {
11
+ jest.clearAllMocks();
12
+ jest.restoreAllMocks();
13
+ fetchStateSpy = jest.spyOn(extraction_state_1.ExtractionState.prototype, 'fetchState');
14
+ processExitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {
15
+ throw new Error('process.exit called');
16
+ });
17
+ });
18
+ describe('Enhanced Control Protocol - extraction window validation', () => {
19
+ it('should exit the process if extract_from >= extract_to', async () => {
20
+ // Arrange: start is after end (inverted window)
21
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
22
+ payload: {
23
+ event_type: extraction_1.EventType.StartExtractingMetadata,
24
+ event_context: {
25
+ extraction_start_time: {
26
+ type: extraction_1.TimeValueType.ABSOLUTE_TIME,
27
+ value: '2025-06-01T00:00:00Z',
28
+ },
29
+ extraction_end_time: {
30
+ type: extraction_1.TimeValueType.ABSOLUTE_TIME,
31
+ value: '2024-01-01T00:00:00Z',
32
+ },
33
+ },
34
+ },
35
+ });
36
+ const stringifiedState = JSON.stringify({
37
+ snapInVersionId: 'test_snap_in_version_id',
38
+ });
39
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
40
+ // Act & Assert
41
+ await expect((0, extraction_state_1.createExtractionState)({
42
+ event,
43
+ initialState: {},
44
+ initialDomainMapping: {},
45
+ })).rejects.toThrow('process.exit called');
46
+ expect(processExitSpy).toHaveBeenCalledWith(1);
47
+ });
48
+ it('should exit the process if extract_from equals extract_to', async () => {
49
+ // Arrange: start equals end (zero-width window)
50
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
51
+ payload: {
52
+ event_type: extraction_1.EventType.StartExtractingMetadata,
53
+ event_context: {
54
+ extraction_start_time: {
55
+ type: extraction_1.TimeValueType.ABSOLUTE_TIME,
56
+ value: '2024-06-01T00:00:00Z',
57
+ },
58
+ extraction_end_time: {
59
+ type: extraction_1.TimeValueType.ABSOLUTE_TIME,
60
+ value: '2024-06-01T00:00:00Z',
61
+ },
62
+ },
63
+ },
64
+ });
65
+ const stringifiedState = JSON.stringify({
66
+ snapInVersionId: 'test_snap_in_version_id',
67
+ });
68
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
69
+ // Act & Assert
70
+ await expect((0, extraction_state_1.createExtractionState)({
71
+ event,
72
+ initialState: {},
73
+ initialDomainMapping: {},
74
+ })).rejects.toThrow('process.exit called');
75
+ expect(processExitSpy).toHaveBeenCalledWith(1);
76
+ });
77
+ it('should not exit when extract_from < extract_to', async () => {
78
+ // Arrange: valid window
79
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
80
+ payload: {
81
+ event_type: extraction_1.EventType.StartExtractingMetadata,
82
+ event_context: {
83
+ extraction_start_time: {
84
+ type: extraction_1.TimeValueType.ABSOLUTE_TIME,
85
+ value: '2024-01-01T00:00:00Z',
86
+ },
87
+ extraction_end_time: {
88
+ type: extraction_1.TimeValueType.ABSOLUTE_TIME,
89
+ value: '2025-06-01T00:00:00Z',
90
+ },
91
+ },
92
+ },
93
+ });
94
+ const stringifiedState = JSON.stringify({
95
+ snapInVersionId: 'test_snap_in_version_id',
96
+ });
97
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
98
+ // Act
99
+ await (0, extraction_state_1.createExtractionState)({
100
+ event,
101
+ initialState: {},
102
+ initialDomainMapping: {},
103
+ });
104
+ // Assert: process.exit should NOT have been called
105
+ expect(processExitSpy).not.toHaveBeenCalled();
106
+ });
107
+ it('should not validate when only extract_from is set', async () => {
108
+ // Arrange: only start, no end
109
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
110
+ payload: {
111
+ event_type: extraction_1.EventType.StartExtractingMetadata,
112
+ event_context: {
113
+ extraction_start_time: {
114
+ type: extraction_1.TimeValueType.ABSOLUTE_TIME,
115
+ value: '2024-01-01T00:00:00Z',
116
+ },
117
+ },
118
+ },
119
+ });
120
+ const stringifiedState = JSON.stringify({
121
+ snapInVersionId: 'test_snap_in_version_id',
122
+ });
123
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
124
+ // Act
125
+ await (0, extraction_state_1.createExtractionState)({
126
+ event,
127
+ initialState: {},
128
+ initialDomainMapping: {},
129
+ });
130
+ // Assert: process.exit should NOT have been called
131
+ expect(processExitSpy).not.toHaveBeenCalled();
132
+ });
133
+ it('should not exit when extract_from is UNBOUNDED and extract_to is a real timestamp', async () => {
134
+ // Arrange: UNBOUNDED start (epoch) with a real ABSOLUTE end timestamp
135
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
136
+ payload: {
137
+ event_type: extraction_1.EventType.StartExtractingMetadata,
138
+ event_context: {
139
+ extraction_start_time: {
140
+ type: extraction_1.TimeValueType.UNBOUNDED,
141
+ },
142
+ extraction_end_time: {
143
+ type: extraction_1.TimeValueType.ABSOLUTE_TIME,
144
+ value: '2025-06-01T00:00:00Z',
145
+ },
146
+ },
147
+ },
148
+ });
149
+ const stringifiedState = JSON.stringify({
150
+ snapInVersionId: 'test_snap_in_version_id',
151
+ });
152
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
153
+ // Act
154
+ await (0, extraction_state_1.createExtractionState)({
155
+ event,
156
+ initialState: {},
157
+ initialDomainMapping: {},
158
+ });
159
+ // Assert: process.exit should NOT have been called
160
+ expect(processExitSpy).not.toHaveBeenCalled();
161
+ });
162
+ });
163
+ });
@@ -1,19 +1,44 @@
1
1
  import { InitialDomainMapping } from '../types/common';
2
- import { AirdropEvent } from '../types/extraction';
2
+ import { AirSyncEvent } from '../types/extraction';
3
3
  import { FileToLoad } from '../types/loading';
4
4
  import { WorkerAdapterOptions } from '../types/workers';
5
- export interface SdkState {
6
- lastSyncStarted?: string;
7
- lastSuccessfulSyncStarted?: string;
5
+ /**
6
+ * BaseSdkState holds SDK bookkeeping common to every sync mode.
7
+ */
8
+ export interface BaseSdkState {
9
+ snapInVersionId?: string;
10
+ }
11
+ /**
12
+ * ExtractionSdkState holds SDK bookkeeping owned by the extraction modes.
13
+ */
14
+ export interface ExtractionSdkState extends BaseSdkState {
15
+ /** The pending (not yet committed) oldest extraction boundary (ISO 8601 timestamp).
16
+ * Set on StartExtractingMetadata, reused across subsequent phases, cleared on AttachmentExtractionDone. */
17
+ pendingWorkersOldest?: string;
18
+ /** The pending (not yet committed) newest extraction boundary (ISO 8601 timestamp).
19
+ * Set on StartExtractingMetadata, reused across subsequent phases, cleared on AttachmentExtractionDone. */
20
+ pendingWorkersNewest?: string;
21
+ /** The oldest point of extraction (ISO 8601 timestamp). */
22
+ workersOldest?: string;
23
+ /** The newest point of extraction (ISO 8601 timestamp). */
24
+ workersNewest?: string;
8
25
  toDevRev?: ToDevRev;
26
+ }
27
+ /**
28
+ * LoadingSdkState holds SDK bookkeeping owned by the loading modes.
29
+ */
30
+ export interface LoadingSdkState extends BaseSdkState {
9
31
  fromDevRev?: FromDevRev;
10
- snapInVersionId?: string;
11
32
  }
12
33
  /**
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.
34
+ * AdapterStateEnvelope is the v2 on-disk state shape: connector state and SDK
35
+ * bookkeeping are stored as disjoint sub-objects so SDK internals stay
36
+ * encapsulated and never collide with connector keys.
15
37
  */
16
- export type AdapterState<ConnectorState> = ConnectorState & SdkState;
38
+ export interface AdapterStateEnvelope<ConnectorState, SdkState extends BaseSdkState> {
39
+ connectorState: ConnectorState;
40
+ sdkState: SdkState;
41
+ }
17
42
  export interface ToDevRev {
18
43
  attachmentsMetadata: {
19
44
  artifactIds: string[];
@@ -32,27 +57,19 @@ export interface FromDevRev {
32
57
  filesToLoad: FileToLoad[];
33
58
  }
34
59
  export interface StateInterface<ConnectorState> {
35
- event: AirdropEvent;
60
+ event: AirSyncEvent;
36
61
  initialState: ConnectorState;
37
62
  initialDomainMapping?: InitialDomainMapping;
38
63
  options?: WorkerAdapterOptions;
39
64
  }
40
- export declare const extractionSdkState: {
41
- lastSyncStarted: string;
42
- lastSuccessfulSyncStarted: string;
43
- snapInVersionId: string;
44
- toDevRev: {
45
- attachmentsMetadata: {
46
- artifactIds: never[];
47
- lastProcessed: number;
48
- lastProcessedAttachmentsIdsList: never[];
49
- };
50
- };
51
- };
52
- export declare const loadingSdkState: {
53
- snapInVersionId: string;
54
- fromDevRev: {
55
- filesToLoad: never[];
56
- };
57
- };
65
+ export declare const initialExtractionSdkState: ExtractionSdkState;
66
+ export declare const initialLoadingSdkState: LoadingSdkState;
67
+ /**
68
+ * The set of top-level state keys owned by the SDK. Derived from the initial
69
+ * SDK state constants so it auto-updates whenever a new SDK field is added.
70
+ * Used by the migration shim to split a flat v1 state blob into the
71
+ * `{ connectorState, sdkState }` envelope: keys in this set go to `sdkState`,
72
+ * everything else is connector state.
73
+ */
74
+ export declare const V1_SDK_STATE_KEYS: ReadonlySet<string>;
58
75
  //# sourceMappingURL=state.interfaces.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.interfaces.d.ts","sourceRoot":"","sources":["../../src/state/state.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,QAAQ;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,cAAc,IAAI,cAAc,GAAG,QAAQ,CAAC;AAErE,MAAM,WAAW,QAAQ;IACvB,mBAAmB,EAAE;QACnB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,+BAA+B,CAAC,EAAE,mBAAmB,EAAE,CAAC;KACzD,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc,CAAC,cAAc;IAC5C,KAAK,EAAE,YAAY,CAAC;IACpB,YAAY,EAAE,cAAc,CAAC;IAC7B,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;;CAW9B,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;CAK3B,CAAC"}
1
+ {"version":3,"file":"state.interfaces.d.ts","sourceRoot":"","sources":["../../src/state/state.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD;gHAC4G;IAC5G,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;gHAC4G;IAC5G,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB,CACnC,cAAc,EACd,QAAQ,SAAS,YAAY;IAE7B,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,mBAAmB,EAAE;QACnB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,+BAA+B,CAAC,EAAE,mBAAmB,EAAE,CAAC;KACzD,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc,CAAC,cAAc;IAC5C,KAAK,EAAE,YAAY,CAAC;IACpB,YAAY,EAAE,cAAc,CAAC;IAC7B,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED,eAAO,MAAM,yBAAyB,EAAE,kBAavC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAKpC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAGhD,CAAC"}
@@ -1,10 +1,12 @@
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: '',
3
+ exports.V1_SDK_STATE_KEYS = exports.initialLoadingSdkState = exports.initialExtractionSdkState = void 0;
4
+ exports.initialExtractionSdkState = {
7
5
  snapInVersionId: '',
6
+ pendingWorkersOldest: '',
7
+ pendingWorkersNewest: '',
8
+ workersOldest: '',
9
+ workersNewest: '',
8
10
  toDevRev: {
9
11
  attachmentsMetadata: {
10
12
  artifactIds: [],
@@ -13,9 +15,20 @@ exports.extractionSdkState = {
13
15
  },
14
16
  },
15
17
  };
16
- exports.loadingSdkState = {
18
+ exports.initialLoadingSdkState = {
17
19
  snapInVersionId: '',
18
20
  fromDevRev: {
19
21
  filesToLoad: [],
20
22
  },
21
23
  };
24
+ /**
25
+ * The set of top-level state keys owned by the SDK. Derived from the initial
26
+ * SDK state constants so it auto-updates whenever a new SDK field is added.
27
+ * Used by the migration shim to split a flat v1 state blob into the
28
+ * `{ connectorState, sdkState }` envelope: keys in this set go to `sdkState`,
29
+ * everything else is connector state.
30
+ */
31
+ exports.V1_SDK_STATE_KEYS = new Set([
32
+ ...Object.keys(exports.initialExtractionSdkState),
33
+ ...Object.keys(exports.initialLoadingSdkState),
34
+ ]);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state.pending-boundaries.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.pending-boundaries.test.d.ts","sourceRoot":"","sources":["../../src/state/state.pending-boundaries.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jest_setup_1 = require("../tests/jest.setup");
4
+ const test_utils_1 = require("../common/test-utils");
5
+ const extraction_1 = require("../types/extraction");
6
+ const extraction_state_1 = require("./extraction-state");
7
+ /* eslint-disable @typescript-eslint/no-require-imports */
8
+ const FIXED_NOW = '2026-03-26T10:00:00.000Z';
9
+ describe('State — pending extraction boundaries', () => {
10
+ let postStateSpy;
11
+ let fetchStateSpy;
12
+ let installInitialDomainMappingSpy;
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ jest.restoreAllMocks();
16
+ postStateSpy = jest.spyOn(extraction_state_1.ExtractionState.prototype, 'postState');
17
+ fetchStateSpy = jest.spyOn(extraction_state_1.ExtractionState.prototype, 'fetchState');
18
+ installInitialDomainMappingSpy = jest.spyOn(require('../common/install-initial-domain-mapping'), 'installInitialDomainMapping');
19
+ jest.spyOn(process, 'exit').mockImplementation(() => {
20
+ throw new Error('process.exit called');
21
+ });
22
+ jest.useFakeTimers();
23
+ jest.setSystemTime(new Date(FIXED_NOW));
24
+ });
25
+ afterEach(() => {
26
+ jest.useRealTimers();
27
+ });
28
+ it('should store resolved values in pendingWorkersOldest/pendingWorkersNewest on StartExtractingMetadata', async () => {
29
+ // Arrange
30
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
31
+ context: {
32
+ snap_in_version_id: '',
33
+ },
34
+ payload: {
35
+ event_type: extraction_1.EventType.StartExtractingMetadata,
36
+ event_context: {
37
+ extraction_start_time: {
38
+ type: extraction_1.TimeValueType.UNBOUNDED,
39
+ },
40
+ extraction_end_time: {
41
+ type: extraction_1.TimeValueType.CURRENT_TIME,
42
+ },
43
+ },
44
+ },
45
+ });
46
+ fetchStateSpy.mockRejectedValue({
47
+ isAxiosError: true,
48
+ response: { status: 404 },
49
+ });
50
+ installInitialDomainMappingSpy.mockResolvedValue({ success: true });
51
+ postStateSpy.mockResolvedValue({ success: true });
52
+ // Act
53
+ const state = await (0, extraction_state_1.createExtractionState)({
54
+ event,
55
+ initialState: {},
56
+ initialDomainMapping: {},
57
+ });
58
+ // Assert
59
+ expect(state.sdkState.pendingWorkersOldest).toBe('1970-01-01T00:00:00.000Z');
60
+ expect(state.sdkState.pendingWorkersNewest).toBe(FIXED_NOW);
61
+ expect(event.payload.event_context.extract_from).toBe('1970-01-01T00:00:00.000Z');
62
+ expect(event.payload.event_context.extract_to).toBe(FIXED_NOW);
63
+ });
64
+ it('should overwrite pending values on a retry (new StartExtractingMetadata after failure)', async () => {
65
+ // Arrange: state has stale pending values from a previous failed attempt
66
+ const staleOldest = '2026-03-25T08:00:00.000Z';
67
+ const staleNewest = '2026-03-25T09:00:00.000Z';
68
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
69
+ context: {
70
+ snap_in_version_id: 'test_snap_in_version_id',
71
+ },
72
+ payload: {
73
+ event_type: extraction_1.EventType.StartExtractingMetadata,
74
+ event_context: {
75
+ extraction_start_time: {
76
+ type: extraction_1.TimeValueType.UNBOUNDED,
77
+ },
78
+ extraction_end_time: {
79
+ type: extraction_1.TimeValueType.CURRENT_TIME,
80
+ },
81
+ },
82
+ },
83
+ });
84
+ const stringifiedState = JSON.stringify({
85
+ snapInVersionId: 'test_snap_in_version_id',
86
+ pendingWorkersOldest: staleOldest,
87
+ pendingWorkersNewest: staleNewest,
88
+ });
89
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
90
+ // Act
91
+ const state = await (0, extraction_state_1.createExtractionState)({
92
+ event,
93
+ initialState: {},
94
+ initialDomainMapping: {},
95
+ });
96
+ // Assert: pending values are overwritten with fresh resolution, not stale values
97
+ expect(state.sdkState.pendingWorkersOldest).toBe('1970-01-01T00:00:00.000Z');
98
+ expect(state.sdkState.pendingWorkersNewest).toBe(FIXED_NOW);
99
+ expect(state.sdkState.pendingWorkersNewest).not.toBe(staleNewest);
100
+ });
101
+ it('should reuse pending values from state on ContinueExtractingData instead of re-resolving', async () => {
102
+ // Arrange: state has pending values from a prior StartExtractingMetadata phase
103
+ const pendingOldest = '1970-01-01T00:00:00.000Z';
104
+ const pendingNewest = '2026-03-26T08:00:00.000Z'; // Earlier than FIXED_NOW
105
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
106
+ context: {
107
+ snap_in_version_id: 'test_snap_in_version_id',
108
+ },
109
+ payload: {
110
+ event_type: extraction_1.EventType.ContinueExtractingData,
111
+ event_context: {
112
+ // Platform still sends TimeValue objects, but they should be ignored
113
+ extraction_start_time: {
114
+ type: extraction_1.TimeValueType.CURRENT_TIME,
115
+ },
116
+ extraction_end_time: {
117
+ type: extraction_1.TimeValueType.CURRENT_TIME,
118
+ },
119
+ },
120
+ },
121
+ });
122
+ const stringifiedState = JSON.stringify({
123
+ snapInVersionId: 'test_snap_in_version_id',
124
+ pendingWorkersOldest: pendingOldest,
125
+ pendingWorkersNewest: pendingNewest,
126
+ });
127
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
128
+ // Act
129
+ const state = await (0, extraction_state_1.createExtractionState)({
130
+ event,
131
+ initialState: {},
132
+ initialDomainMapping: {},
133
+ });
134
+ // Assert: uses cached pending values, NOT new Date() resolution
135
+ expect(event.payload.event_context.extract_from).toBe(pendingOldest);
136
+ expect(event.payload.event_context.extract_to).toBe(pendingNewest);
137
+ // Pending values in state remain unchanged
138
+ expect(state.sdkState.pendingWorkersOldest).toBe(pendingOldest);
139
+ expect(state.sdkState.pendingWorkersNewest).toBe(pendingNewest);
140
+ });
141
+ it('should not set extract_from/extract_to on ContinueExtractingData if no pending values exist', async () => {
142
+ // Arrange: state has no pending values (e.g. old state from before this feature)
143
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
144
+ context: {
145
+ snap_in_version_id: 'test_snap_in_version_id',
146
+ },
147
+ payload: { event_type: extraction_1.EventType.ContinueExtractingData },
148
+ });
149
+ const stringifiedState = JSON.stringify({
150
+ snapInVersionId: 'test_snap_in_version_id',
151
+ });
152
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
153
+ // Act
154
+ await (0, extraction_state_1.createExtractionState)({
155
+ event,
156
+ initialState: {},
157
+ initialDomainMapping: {},
158
+ });
159
+ // Assert: no extraction timestamps are set
160
+ expect(event.payload.event_context.extract_from).toBeUndefined();
161
+ expect(event.payload.event_context.extract_to).toBeUndefined();
162
+ });
163
+ it('should reuse pending values on StartExtractingAttachments', async () => {
164
+ // Arrange: state has pending values from the StartExtractingMetadata phase
165
+ const pendingOldest = '1970-01-01T00:00:00.000Z';
166
+ const pendingNewest = '2026-03-26T08:00:00.000Z';
167
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
168
+ context: {
169
+ snap_in_version_id: 'test_snap_in_version_id',
170
+ },
171
+ payload: { event_type: extraction_1.EventType.StartExtractingAttachments },
172
+ });
173
+ const stringifiedState = JSON.stringify({
174
+ snapInVersionId: 'test_snap_in_version_id',
175
+ pendingWorkersOldest: pendingOldest,
176
+ pendingWorkersNewest: pendingNewest,
177
+ });
178
+ fetchStateSpy.mockResolvedValue({ state: stringifiedState });
179
+ // Act
180
+ await (0, extraction_state_1.createExtractionState)({
181
+ event,
182
+ initialState: {},
183
+ initialDomainMapping: {},
184
+ });
185
+ // Assert: pending values are reused
186
+ expect(event.payload.event_context.extract_from).toBe(pendingOldest);
187
+ expect(event.payload.event_context.extract_to).toBe(pendingNewest);
188
+ });
189
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state.post-state.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.post-state.test.d.ts","sourceRoot":"","sources":["../../src/state/state.post-state.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jest_setup_1 = require("../tests/jest.setup");
4
+ const test_utils_1 = require("../common/test-utils");
5
+ const extraction_1 = require("../types/extraction");
6
+ const extraction_state_1 = require("./extraction-state");
7
+ /* eslint-disable @typescript-eslint/no-require-imports */
8
+ describe('State.postState', () => {
9
+ let postStateSpy;
10
+ let fetchStateSpy;
11
+ let processExitSpy;
12
+ beforeEach(() => {
13
+ jest.clearAllMocks();
14
+ jest.restoreAllMocks();
15
+ postStateSpy = jest.spyOn(extraction_state_1.ExtractionState.prototype, 'postState');
16
+ fetchStateSpy = jest.spyOn(extraction_state_1.ExtractionState.prototype, 'fetchState');
17
+ processExitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {
18
+ throw new Error('process.exit called');
19
+ });
20
+ });
21
+ it('should POST the stringified state to the update endpoint', async () => {
22
+ // Arrange
23
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
24
+ context: {
25
+ snap_in_version_id: '1.0.0',
26
+ secrets: { service_account_token: 'test_token' },
27
+ },
28
+ payload: { event_type: extraction_1.EventType.StartExtractingData },
29
+ });
30
+ const stateToPost = { snapInVersionId: '1.0.0', foo: 'bar' };
31
+ fetchStateSpy.mockResolvedValue({
32
+ state: JSON.stringify({ snapInVersionId: '1.0.0' }),
33
+ });
34
+ postStateSpy.mockRestore();
35
+ const adapterState = await (0, extraction_state_1.createExtractionState)({
36
+ event,
37
+ initialState: {},
38
+ initialDomainMapping: {},
39
+ });
40
+ // Act
41
+ await adapterState.postState(stateToPost);
42
+ // Assert: the mock server records all incoming requests — inspect what was sent
43
+ const requests = jest_setup_1.mockServer.getRequests('POST', '/worker_data_url.update');
44
+ expect(requests).toHaveLength(1);
45
+ const body = requests[0].body;
46
+ // Body must contain the stringified v2 envelope: connector state and SDK
47
+ // bookkeeping stored as disjoint sub-objects.
48
+ expect(typeof body.state).toBe('string');
49
+ const parsed = JSON.parse(body.state);
50
+ expect(parsed.connectorState.foo).toBe('bar');
51
+ expect(parsed.sdkState.snapInVersionId).toBe('1.0.0');
52
+ });
53
+ it('should exit(1) when postState HTTP request fails', async () => {
54
+ // Arrange
55
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
56
+ context: { snap_in_version_id: '1.0.0' },
57
+ payload: { event_type: extraction_1.EventType.StartExtractingData },
58
+ });
59
+ fetchStateSpy.mockResolvedValue({
60
+ state: JSON.stringify({ snapInVersionId: '1.0.0' }),
61
+ });
62
+ postStateSpy.mockRestore();
63
+ const adapterState = await (0, extraction_state_1.createExtractionState)({
64
+ event,
65
+ initialState: {},
66
+ initialDomainMapping: {},
67
+ });
68
+ // Mock axiosClient.post directly to bypass the retry backoff
69
+ const axiosClientModule = require('../http/axios-client-internal');
70
+ const axiosPostSpy = jest
71
+ .spyOn(axiosClientModule.axiosClient, 'post')
72
+ .mockRejectedValue(new Error('network error'));
73
+ // Act & Assert
74
+ await expect(adapterState.postState()).rejects.toThrow('process.exit called');
75
+ expect(processExitSpy).toHaveBeenCalledWith(1);
76
+ axiosPostSpy.mockRestore();
77
+ });
78
+ });