@devrev/ts-adaas 1.17.1-beta.5 → 1.17.1-beta.7
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/dist/attachments-streaming/attachments-streaming-pool.d.ts.map +1 -1
- package/dist/common/constants.d.ts +8 -0
- package/dist/common/constants.d.ts.map +1 -1
- package/dist/common/constants.js +9 -1
- package/dist/common/time-value-resolver.d.ts +47 -0
- package/dist/common/time-value-resolver.d.ts.map +1 -0
- package/dist/common/time-value-resolver.js +149 -0
- package/dist/common/time-value-resolver.test.d.ts +2 -0
- package/dist/common/time-value-resolver.test.d.ts.map +1 -0
- package/dist/common/time-value-resolver.test.js +273 -0
- package/dist/mock-server/mock-server.d.ts +1 -34
- package/dist/mock-server/mock-server.d.ts.map +1 -1
- package/dist/mock-server/mock-server.interfaces.d.ts +18 -2
- package/dist/mock-server/mock-server.interfaces.d.ts.map +1 -1
- package/dist/mock-server/mock-server.js +87 -80
- package/dist/multithreading/worker-adapter/worker-adapter.d.ts.map +1 -1
- package/dist/multithreading/worker-adapter/worker-adapter.js +19 -0
- package/dist/multithreading/worker-adapter/worker-adapter.test.js +192 -6
- package/dist/state/state.d.ts.map +1 -1
- package/dist/state/state.interfaces.d.ts +22 -0
- package/dist/state/state.interfaces.d.ts.map +1 -1
- package/dist/state/state.interfaces.js +4 -0
- package/dist/state/state.js +68 -0
- package/dist/state/state.test.js +369 -0
- package/dist/types/extraction.d.ts +77 -1
- package/dist/types/extraction.d.ts.map +1 -1
- package/dist/types/extraction.js +43 -1
- package/dist/types/extraction.test.js +22 -11
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +6 -1
- package/package.json +1 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachments-streaming-pool.d.ts","sourceRoot":"","sources":["../../src/attachments-streaming/attachments-streaming-pool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"attachments-streaming-pool.d.ts","sourceRoot":"","sources":["../../src/attachments-streaming/attachments-streaming-pool.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,2BAA2B,EAC5B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AAEzF,qBAAa,wBAAwB,CAAC,cAAc;IAClD,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,MAAM,CAA4C;IAE1D,OAAO,CAAC,mBAAmB,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAM;gBAEnC,EACV,OAAO,EACP,WAAW,EACX,SAAc,EACd,MAAM,GACP,EAAE,8BAA8B,CAAC,cAAc,CAAC;YAQnC,cAAc;IAS5B;;;;;OAKG;IAEH,OAAO,CAAC,2BAA2B;IAsB7B,SAAS,IAAI,OAAO,CAAC,2BAA2B,CAAC;IA8CjD,kBAAkB;CA0FzB"}
|
|
@@ -25,4 +25,12 @@ export declare const DEFAULT_LAMBDA_TIMEOUT: number;
|
|
|
25
25
|
export declare const HARD_TIMEOUT_MULTIPLIER = 1.3;
|
|
26
26
|
export declare const MEMORY_LOG_INTERVAL: number;
|
|
27
27
|
export declare const DEFAULT_SLEEP_DELAY_MS: number;
|
|
28
|
+
/**
|
|
29
|
+
* Sentinel value representing an unbounded (no limit) extraction timestamp.
|
|
30
|
+
* Used as the resolved value for TimeValueType.UNBOUNDED, stored as workersOldest
|
|
31
|
+
* when the initial import has no lower time bound. The Unix epoch ensures that
|
|
32
|
+
* no real extraction timestamp can be earlier, preventing accidental overwrites
|
|
33
|
+
* of the boundary by subsequent syncs (e.g. reconciliation with absolute dates).
|
|
34
|
+
*/
|
|
35
|
+
export declare const UNBOUNDED_DATE_TIME_VALUE = "1970-01-01T00:00:00.000Z";
|
|
28
36
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,eAAO,MAAM,8BAA8B,aAS1C,CAAC;AAEF,eAAO,MAAM,2BAA2B,aAKvC,CAAC;AAEF,eAAO,MAAM,mBAAmB,aAG/B,CAAC;AAEF,eAAO,MAAM,gCAAgC,aAI5C,CAAC;AAEF,eAAO,MAAM,6BAA6B,aAGzC,CAAC;AAEF,eAAO,MAAM,qBAAqB,aAGjC,CAAC;AAEF,eAAO,MAAM,+BAA+B,aAGzC,CAAC;AAEJ,eAAO,MAAM,4BAA4B,aAExC,CAAC;AAEF,eAAO,MAAM,oBAAoB,aAGhC,CAAC;AAEF,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,wBAAwB,QAAyB,CAAC;AAC/D,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAC9C,eAAO,MAAM,oCAAoC,KAAK,CAAC;AAGvD,eAAO,MAAM,oBAAoB,SAAU,CAAC;AAE5C,eAAO,MAAM,0BAA0B,QAEtC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAA0B,CAAC;AAEzD,oBAAY,uBAAuB;IACjC,wBAAwB,6BAA6B;IACrD,WAAW,gBAAgB;IAC3B,mBAAmB,wBAAwB;CAC5C;AAED,eAAO,MAAM,eAAe,KAAsB,CAAC;AAEnD,eAAO,MAAM,sBAAsB,QAAiB,CAAC;AACrD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,mBAAmB,QAAY,CAAC;AAE7C,eAAO,MAAM,sBAAsB,QAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,eAAO,MAAM,8BAA8B,aAS1C,CAAC;AAEF,eAAO,MAAM,2BAA2B,aAKvC,CAAC;AAEF,eAAO,MAAM,mBAAmB,aAG/B,CAAC;AAEF,eAAO,MAAM,gCAAgC,aAI5C,CAAC;AAEF,eAAO,MAAM,6BAA6B,aAGzC,CAAC;AAEF,eAAO,MAAM,qBAAqB,aAGjC,CAAC;AAEF,eAAO,MAAM,+BAA+B,aAGzC,CAAC;AAEJ,eAAO,MAAM,4BAA4B,aAExC,CAAC;AAEF,eAAO,MAAM,oBAAoB,aAGhC,CAAC;AAEF,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,wBAAwB,QAAyB,CAAC;AAC/D,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAC9C,eAAO,MAAM,oCAAoC,KAAK,CAAC;AAGvD,eAAO,MAAM,oBAAoB,SAAU,CAAC;AAE5C,eAAO,MAAM,0BAA0B,QAEtC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAA0B,CAAC;AAEzD,oBAAY,uBAAuB;IACjC,wBAAwB,6BAA6B;IACrD,WAAW,gBAAgB;IAC3B,mBAAmB,wBAAwB;CAC5C;AAED,eAAO,MAAM,eAAe,KAAsB,CAAC;AAEnD,eAAO,MAAM,sBAAsB,QAAiB,CAAC;AACrD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,mBAAmB,QAAY,CAAC;AAE7C,eAAO,MAAM,sBAAsB,QAAgB,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,6BAA6B,CAAC"}
|
package/dist/common/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_SLEEP_DELAY_MS = exports.MEMORY_LOG_INTERVAL = exports.HARD_TIMEOUT_MULTIPLIER = exports.DEFAULT_LAMBDA_TIMEOUT = exports.LIBRARY_VERSION = exports.AirSyncDefaultItemTypes = exports.SSOR_ATTACHMENT = exports.EVENT_SIZE_THRESHOLD_BYTES = exports.MAX_EVENT_SIZE_BYTES = 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;
|
|
3
|
+
exports.UNBOUNDED_DATE_TIME_VALUE = exports.DEFAULT_SLEEP_DELAY_MS = exports.MEMORY_LOG_INTERVAL = exports.HARD_TIMEOUT_MULTIPLIER = exports.DEFAULT_LAMBDA_TIMEOUT = exports.LIBRARY_VERSION = exports.AirSyncDefaultItemTypes = exports.SSOR_ATTACHMENT = exports.EVENT_SIZE_THRESHOLD_BYTES = exports.MAX_EVENT_SIZE_BYTES = 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
6
|
exports.ALLOWED_EXTRACTION_EVENT_TYPES = [
|
|
@@ -62,3 +62,11 @@ exports.DEFAULT_LAMBDA_TIMEOUT = 10 * 60 * 1000; // 10 minutes
|
|
|
62
62
|
exports.HARD_TIMEOUT_MULTIPLIER = 1.3;
|
|
63
63
|
exports.MEMORY_LOG_INTERVAL = 30 * 1000; // 30 seconds
|
|
64
64
|
exports.DEFAULT_SLEEP_DELAY_MS = 3 * 60 * 1000; // 3 minutes
|
|
65
|
+
/**
|
|
66
|
+
* Sentinel value representing an unbounded (no limit) extraction timestamp.
|
|
67
|
+
* Used as the resolved value for TimeValueType.UNBOUNDED, stored as workersOldest
|
|
68
|
+
* when the initial import has no lower time bound. The Unix epoch ensures that
|
|
69
|
+
* no real extraction timestamp can be earlier, preventing accidental overwrites
|
|
70
|
+
* of the boundary by subsequent syncs (e.g. reconciliation with absolute dates).
|
|
71
|
+
*/
|
|
72
|
+
exports.UNBOUNDED_DATE_TIME_VALUE = '1970-01-01T00:00:00.000Z';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { TimeUnit, TimeValue } from '../types/extraction';
|
|
2
|
+
import { SdkState } from '../state/state.interfaces';
|
|
3
|
+
/**
|
|
4
|
+
* Parses a shorthand duration string into its numeric value and unit.
|
|
5
|
+
* Supported units:
|
|
6
|
+
* - 'ns' for nanoseconds
|
|
7
|
+
* - 'us' or 'µs' for microseconds
|
|
8
|
+
* - 'ms' for milliseconds
|
|
9
|
+
* - 's' for seconds
|
|
10
|
+
* - 'm' for minutes
|
|
11
|
+
* - 'h' for hours
|
|
12
|
+
*
|
|
13
|
+
* @throws Error if the format is invalid
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseDuration(shorthand: string): {
|
|
16
|
+
value: number;
|
|
17
|
+
unit: TimeUnit;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Applies a shorthand duration to a base ISO 8601 timestamp.
|
|
21
|
+
*
|
|
22
|
+
* @param baseTimestamp - ISO 8601 timestamp to apply duration to
|
|
23
|
+
* @param duration - Shorthand duration string (e.g. '100ns', '500ms', '30s', '5m', '2h')
|
|
24
|
+
* @param operation - Whether to 'add' or 'subtract' the duration
|
|
25
|
+
* @returns ISO 8601 timestamp with the duration applied
|
|
26
|
+
*/
|
|
27
|
+
export declare function applyDuration(baseTimestamp: string, duration: string, operation: 'add' | 'subtract'): string;
|
|
28
|
+
/**
|
|
29
|
+
* Resolves a TimeValue into a concrete ISO 8601 timestamp string.
|
|
30
|
+
*
|
|
31
|
+
* Resolution rules:
|
|
32
|
+
* - ABSOLUTE: Returns the value directly (must be an ISO 8601 timestamp)
|
|
33
|
+
* - NOW: Returns the current time as ISO 8601
|
|
34
|
+
* - UNBOUNDED: Returns UNBOUNDED_DATE_TIME_VALUE ('1970-01-01T00:00:00.000Z')
|
|
35
|
+
* - WORKERS_OLDEST: Returns workersOldest from state, or throws if not set
|
|
36
|
+
* - WORKERS_NEWEST: Returns workersNewest from state, or throws if not set
|
|
37
|
+
* - WORKERS_OLDEST_MINUS_WINDOW: Subtracts duration from workersOldest, or throws if not set
|
|
38
|
+
* - WORKERS_NEWEST_PLUS_WINDOW: Adds duration to workersNewest, or throws if not set
|
|
39
|
+
*
|
|
40
|
+
* @param timeValue - The TimeValue to resolve
|
|
41
|
+
* @param state - The current SDK state containing workersOldest and workersNewest
|
|
42
|
+
* @returns Resolved ISO 8601 timestamp string
|
|
43
|
+
* @throws Error if required TimeValue.value is missing for ABSOLUTE or *_WINDOW types
|
|
44
|
+
* @throws Error if workersOldest/workersNewest is not set in state for WORKERS_* types
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveTimeValue(timeValue: TimeValue, state: SdkState): string;
|
|
47
|
+
//# sourceMappingURL=time-value-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-value-resolver.d.ts","sourceRoot":"","sources":["../../src/common/time-value-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAiB,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAGrD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;CAChB,CAcA;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,KAAK,GAAG,UAAU,GAC5B,MAAM,CA6BR;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,QAAQ,GACd,MAAM,CAqFR"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseDuration = parseDuration;
|
|
4
|
+
exports.applyDuration = applyDuration;
|
|
5
|
+
exports.resolveTimeValue = resolveTimeValue;
|
|
6
|
+
const extraction_1 = require("../types/extraction");
|
|
7
|
+
const constants_1 = require("./constants");
|
|
8
|
+
/**
|
|
9
|
+
* Parses a shorthand duration string into its numeric value and unit.
|
|
10
|
+
* Supported units:
|
|
11
|
+
* - 'ns' for nanoseconds
|
|
12
|
+
* - 'us' or 'µs' for microseconds
|
|
13
|
+
* - 'ms' for milliseconds
|
|
14
|
+
* - 's' for seconds
|
|
15
|
+
* - 'm' for minutes
|
|
16
|
+
* - 'h' for hours
|
|
17
|
+
*
|
|
18
|
+
* @throws Error if the format is invalid
|
|
19
|
+
*/
|
|
20
|
+
function parseDuration(shorthand) {
|
|
21
|
+
const validUnits = Object.values(extraction_1.TimeUnit).join('|');
|
|
22
|
+
const match = shorthand.match(new RegExp(`^(\\d+(?:\\.\\d+)?)(${validUnits})$`));
|
|
23
|
+
if (!match) {
|
|
24
|
+
throw new Error(`Invalid duration format: '${shorthand}'. Expected format like '100ns', '500ms', '30s', '5m', or '2h'.`);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
value: parseFloat(match[1]),
|
|
28
|
+
unit: match[2],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Applies a shorthand duration to a base ISO 8601 timestamp.
|
|
33
|
+
*
|
|
34
|
+
* @param baseTimestamp - ISO 8601 timestamp to apply duration to
|
|
35
|
+
* @param duration - Shorthand duration string (e.g. '100ns', '500ms', '30s', '5m', '2h')
|
|
36
|
+
* @param operation - Whether to 'add' or 'subtract' the duration
|
|
37
|
+
* @returns ISO 8601 timestamp with the duration applied
|
|
38
|
+
*/
|
|
39
|
+
function applyDuration(baseTimestamp, duration, operation) {
|
|
40
|
+
const { value, unit } = parseDuration(duration);
|
|
41
|
+
const date = new Date(baseTimestamp);
|
|
42
|
+
const sign = operation === 'add' ? 1 : -1;
|
|
43
|
+
switch (unit) {
|
|
44
|
+
case extraction_1.TimeUnit.NANOSECONDS:
|
|
45
|
+
// JavaScript Date works in milliseconds, so convert nanoseconds
|
|
46
|
+
date.setTime(date.getTime() + sign * value * 0.000001);
|
|
47
|
+
break;
|
|
48
|
+
case extraction_1.TimeUnit.MICROSECONDS:
|
|
49
|
+
case extraction_1.TimeUnit.MICROSECONDS_MU:
|
|
50
|
+
date.setTime(date.getTime() + sign * value * 0.001);
|
|
51
|
+
break;
|
|
52
|
+
case extraction_1.TimeUnit.MILLISECONDS:
|
|
53
|
+
date.setTime(date.getTime() + sign * value);
|
|
54
|
+
break;
|
|
55
|
+
case extraction_1.TimeUnit.SECONDS:
|
|
56
|
+
date.setUTCSeconds(date.getUTCSeconds() + sign * value);
|
|
57
|
+
break;
|
|
58
|
+
case extraction_1.TimeUnit.MINUTES:
|
|
59
|
+
date.setUTCMinutes(date.getUTCMinutes() + sign * value);
|
|
60
|
+
break;
|
|
61
|
+
case extraction_1.TimeUnit.HOURS:
|
|
62
|
+
date.setUTCHours(date.getUTCHours() + sign * value);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
return date.toISOString();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolves a TimeValue into a concrete ISO 8601 timestamp string.
|
|
69
|
+
*
|
|
70
|
+
* Resolution rules:
|
|
71
|
+
* - ABSOLUTE: Returns the value directly (must be an ISO 8601 timestamp)
|
|
72
|
+
* - NOW: Returns the current time as ISO 8601
|
|
73
|
+
* - UNBOUNDED: Returns UNBOUNDED_DATE_TIME_VALUE ('1970-01-01T00:00:00.000Z')
|
|
74
|
+
* - WORKERS_OLDEST: Returns workersOldest from state, or throws if not set
|
|
75
|
+
* - WORKERS_NEWEST: Returns workersNewest from state, or throws if not set
|
|
76
|
+
* - WORKERS_OLDEST_MINUS_WINDOW: Subtracts duration from workersOldest, or throws if not set
|
|
77
|
+
* - WORKERS_NEWEST_PLUS_WINDOW: Adds duration to workersNewest, or throws if not set
|
|
78
|
+
*
|
|
79
|
+
* @param timeValue - The TimeValue to resolve
|
|
80
|
+
* @param state - The current SDK state containing workersOldest and workersNewest
|
|
81
|
+
* @returns Resolved ISO 8601 timestamp string
|
|
82
|
+
* @throws Error if required TimeValue.value is missing for ABSOLUTE or *_WINDOW types
|
|
83
|
+
* @throws Error if workersOldest/workersNewest is not set in state for WORKERS_* types
|
|
84
|
+
*/
|
|
85
|
+
function resolveTimeValue(timeValue, state) {
|
|
86
|
+
switch (timeValue.type) {
|
|
87
|
+
case extraction_1.TimeValueType.ABSOLUTE_TIME: {
|
|
88
|
+
if (!timeValue.value) {
|
|
89
|
+
throw new Error('TimeValue of type ABSOLUTE must have a value (ISO 8601 timestamp).');
|
|
90
|
+
}
|
|
91
|
+
// Normalize to consistent ISO 8601 format (YYYY-MM-DDTHH:mm:ss.sssZ)
|
|
92
|
+
// to ensure string comparisons in boundary expansion are safe.
|
|
93
|
+
const parsed = new Date(timeValue.value);
|
|
94
|
+
if (isNaN(parsed.getTime())) {
|
|
95
|
+
throw new Error(`TimeValue of type ABSOLUTE has an invalid ISO 8601 timestamp: '${timeValue.value}'.`);
|
|
96
|
+
}
|
|
97
|
+
return parsed.toISOString();
|
|
98
|
+
}
|
|
99
|
+
case extraction_1.TimeValueType.CURRENT_TIME: {
|
|
100
|
+
return new Date().toISOString();
|
|
101
|
+
}
|
|
102
|
+
case extraction_1.TimeValueType.UNBOUNDED: {
|
|
103
|
+
return constants_1.UNBOUNDED_DATE_TIME_VALUE;
|
|
104
|
+
}
|
|
105
|
+
case extraction_1.TimeValueType.WORKERS_OLDEST: {
|
|
106
|
+
if (!state.workersOldest) {
|
|
107
|
+
// To support backwards-compatibility for the old state
|
|
108
|
+
return constants_1.UNBOUNDED_DATE_TIME_VALUE;
|
|
109
|
+
}
|
|
110
|
+
return state.workersOldest;
|
|
111
|
+
}
|
|
112
|
+
case extraction_1.TimeValueType.WORKERS_NEWEST: {
|
|
113
|
+
if (!state.workersNewest) {
|
|
114
|
+
// To support backwards-compatibility for the old state
|
|
115
|
+
if (state.lastSuccessfulSyncStarted) {
|
|
116
|
+
return state.lastSuccessfulSyncStarted;
|
|
117
|
+
}
|
|
118
|
+
throw new Error('Field workersNewest is not set in state. Cannot resolve TimeValue of type WORKERS_NEWEST without a prior extraction boundary.');
|
|
119
|
+
}
|
|
120
|
+
return state.workersNewest;
|
|
121
|
+
}
|
|
122
|
+
case extraction_1.TimeValueType.WORKERS_OLDEST_MINUS_WINDOW: {
|
|
123
|
+
if (!timeValue.value) {
|
|
124
|
+
throw new Error("TimeValue of type WORKERS_OLDEST_MINUS_WINDOW must have a value (duration, e.g. '30s', '5m', '2h').");
|
|
125
|
+
}
|
|
126
|
+
if (!state.workersOldest) {
|
|
127
|
+
// To support backwards-compatibility for the old state
|
|
128
|
+
return constants_1.UNBOUNDED_DATE_TIME_VALUE;
|
|
129
|
+
}
|
|
130
|
+
return applyDuration(state.workersOldest, timeValue.value, 'subtract');
|
|
131
|
+
}
|
|
132
|
+
case extraction_1.TimeValueType.WORKERS_NEWEST_PLUS_WINDOW: {
|
|
133
|
+
if (!timeValue.value) {
|
|
134
|
+
throw new Error("TimeValue of type WORKERS_NEWEST_PLUS_WINDOW must have a value (duration, e.g. '30s', '5m', '2h').");
|
|
135
|
+
}
|
|
136
|
+
if (!state.workersNewest) {
|
|
137
|
+
// To support backwards-compatibility for the old state
|
|
138
|
+
if (state.lastSuccessfulSyncStarted) {
|
|
139
|
+
return state.lastSuccessfulSyncStarted;
|
|
140
|
+
}
|
|
141
|
+
throw new Error('Field workersNewest is not set in state. Cannot resolve TimeValue of type WORKERS_NEWEST_PLUS_WINDOW without a prior extraction boundary.');
|
|
142
|
+
}
|
|
143
|
+
return applyDuration(state.workersNewest, timeValue.value, 'add');
|
|
144
|
+
}
|
|
145
|
+
default: {
|
|
146
|
+
throw new Error(`Unknown TimeValueType: '${timeValue.type}'.`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-value-resolver.test.d.ts","sourceRoot":"","sources":["../../src/common/time-value-resolver.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const extraction_1 = require("../types/extraction");
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
const time_value_resolver_1 = require("./time-value-resolver");
|
|
6
|
+
describe('time-value-resolver', () => {
|
|
7
|
+
describe('parseDuration', () => {
|
|
8
|
+
it('should parse nanoseconds', () => {
|
|
9
|
+
expect((0, time_value_resolver_1.parseDuration)('100ns')).toEqual({ value: 100, unit: 'ns' });
|
|
10
|
+
expect((0, time_value_resolver_1.parseDuration)('1ns')).toEqual({ value: 1, unit: 'ns' });
|
|
11
|
+
});
|
|
12
|
+
it('should parse microseconds', () => {
|
|
13
|
+
expect((0, time_value_resolver_1.parseDuration)('500us')).toEqual({ value: 500, unit: 'us' });
|
|
14
|
+
expect((0, time_value_resolver_1.parseDuration)('500µs')).toEqual({ value: 500, unit: 'µs' });
|
|
15
|
+
});
|
|
16
|
+
it('should parse milliseconds', () => {
|
|
17
|
+
expect((0, time_value_resolver_1.parseDuration)('250ms')).toEqual({ value: 250, unit: 'ms' });
|
|
18
|
+
expect((0, time_value_resolver_1.parseDuration)('1ms')).toEqual({ value: 1, unit: 'ms' });
|
|
19
|
+
});
|
|
20
|
+
it('should parse seconds', () => {
|
|
21
|
+
expect((0, time_value_resolver_1.parseDuration)('30s')).toEqual({ value: 30, unit: 's' });
|
|
22
|
+
expect((0, time_value_resolver_1.parseDuration)('1s')).toEqual({ value: 1, unit: 's' });
|
|
23
|
+
expect((0, time_value_resolver_1.parseDuration)('3600s')).toEqual({ value: 3600, unit: 's' });
|
|
24
|
+
});
|
|
25
|
+
it('should parse minutes', () => {
|
|
26
|
+
expect((0, time_value_resolver_1.parseDuration)('5m')).toEqual({ value: 5, unit: 'm' });
|
|
27
|
+
expect((0, time_value_resolver_1.parseDuration)('1m')).toEqual({ value: 1, unit: 'm' });
|
|
28
|
+
expect((0, time_value_resolver_1.parseDuration)('60m')).toEqual({ value: 60, unit: 'm' });
|
|
29
|
+
});
|
|
30
|
+
it('should parse hours', () => {
|
|
31
|
+
expect((0, time_value_resolver_1.parseDuration)('2h')).toEqual({ value: 2, unit: 'h' });
|
|
32
|
+
expect((0, time_value_resolver_1.parseDuration)('24h')).toEqual({ value: 24, unit: 'h' });
|
|
33
|
+
expect((0, time_value_resolver_1.parseDuration)('168h')).toEqual({ value: 168, unit: 'h' });
|
|
34
|
+
});
|
|
35
|
+
it('should parse fractional values', () => {
|
|
36
|
+
expect((0, time_value_resolver_1.parseDuration)('1.5h')).toEqual({ value: 1.5, unit: 'h' });
|
|
37
|
+
expect((0, time_value_resolver_1.parseDuration)('0.5s')).toEqual({ value: 0.5, unit: 's' });
|
|
38
|
+
expect((0, time_value_resolver_1.parseDuration)('2.5m')).toEqual({ value: 2.5, unit: 'm' });
|
|
39
|
+
});
|
|
40
|
+
it('should throw on invalid format', () => {
|
|
41
|
+
expect(() => (0, time_value_resolver_1.parseDuration)('')).toThrow('Invalid duration format');
|
|
42
|
+
expect(() => (0, time_value_resolver_1.parseDuration)('7')).toThrow('Invalid duration format');
|
|
43
|
+
expect(() => (0, time_value_resolver_1.parseDuration)('s')).toThrow('Invalid duration format');
|
|
44
|
+
expect(() => (0, time_value_resolver_1.parseDuration)('7d')).toThrow('Invalid duration format');
|
|
45
|
+
expect(() => (0, time_value_resolver_1.parseDuration)('7y')).toThrow('Invalid duration format');
|
|
46
|
+
expect(() => (0, time_value_resolver_1.parseDuration)('abc')).toThrow('Invalid duration format');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('applyDuration', () => {
|
|
50
|
+
describe('subtract', () => {
|
|
51
|
+
it('should subtract seconds', () => {
|
|
52
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:00:30.000Z', '30s', 'subtract');
|
|
53
|
+
expect(result).toBe('2024-01-15T00:00:00.000Z');
|
|
54
|
+
});
|
|
55
|
+
it('should subtract minutes', () => {
|
|
56
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:05:00.000Z', '5m', 'subtract');
|
|
57
|
+
expect(result).toBe('2024-01-15T00:00:00.000Z');
|
|
58
|
+
});
|
|
59
|
+
it('should subtract hours', () => {
|
|
60
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T02:00:00.000Z', '2h', 'subtract');
|
|
61
|
+
expect(result).toBe('2024-01-15T00:00:00.000Z');
|
|
62
|
+
});
|
|
63
|
+
it('should subtract milliseconds', () => {
|
|
64
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:00:00.500Z', '500ms', 'subtract');
|
|
65
|
+
expect(result).toBe('2024-01-15T00:00:00.000Z');
|
|
66
|
+
});
|
|
67
|
+
it('should handle crossing day boundary', () => {
|
|
68
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T01:00:00.000Z', '2h', 'subtract');
|
|
69
|
+
expect(result).toBe('2024-01-14T23:00:00.000Z');
|
|
70
|
+
});
|
|
71
|
+
it('should subtract 168 hours (7 days equivalent)', () => {
|
|
72
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:00:00.000Z', '168h', 'subtract');
|
|
73
|
+
expect(result).toBe('2024-01-08T00:00:00.000Z');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('add', () => {
|
|
77
|
+
it('should add seconds', () => {
|
|
78
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:00:00.000Z', '30s', 'add');
|
|
79
|
+
expect(result).toBe('2024-01-15T00:00:30.000Z');
|
|
80
|
+
});
|
|
81
|
+
it('should add minutes', () => {
|
|
82
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:00:00.000Z', '5m', 'add');
|
|
83
|
+
expect(result).toBe('2024-01-15T00:05:00.000Z');
|
|
84
|
+
});
|
|
85
|
+
it('should add hours', () => {
|
|
86
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:00:00.000Z', '2h', 'add');
|
|
87
|
+
expect(result).toBe('2024-01-15T02:00:00.000Z');
|
|
88
|
+
});
|
|
89
|
+
it('should add milliseconds', () => {
|
|
90
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:00:00.000Z', '500ms', 'add');
|
|
91
|
+
expect(result).toBe('2024-01-15T00:00:00.500Z');
|
|
92
|
+
});
|
|
93
|
+
it('should handle crossing day boundary', () => {
|
|
94
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T23:00:00.000Z', '2h', 'add');
|
|
95
|
+
expect(result).toBe('2024-01-16T01:00:00.000Z');
|
|
96
|
+
});
|
|
97
|
+
it('should add 168 hours (7 days equivalent)', () => {
|
|
98
|
+
const result = (0, time_value_resolver_1.applyDuration)('2024-01-15T00:00:00.000Z', '168h', 'add');
|
|
99
|
+
expect(result).toBe('2024-01-22T00:00:00.000Z');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('resolveTimeValue', () => {
|
|
104
|
+
const baseState = {
|
|
105
|
+
lastSyncStarted: '',
|
|
106
|
+
lastSuccessfulSyncStarted: '',
|
|
107
|
+
workersOldest: '2024-01-01T00:00:00.000Z',
|
|
108
|
+
workersNewest: '2024-06-01T00:00:00.000Z',
|
|
109
|
+
};
|
|
110
|
+
describe('ABSOLUTE_TIME type', () => {
|
|
111
|
+
it('should return the value normalized to ISO 8601', () => {
|
|
112
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.ABSOLUTE_TIME, value: '2024-03-15T12:00:00Z' }, baseState);
|
|
113
|
+
expect(result).toBe('2024-03-15T12:00:00.000Z');
|
|
114
|
+
});
|
|
115
|
+
it('should normalize timestamps without milliseconds', () => {
|
|
116
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.ABSOLUTE_TIME, value: '2024-01-01T00:00:00Z' }, baseState);
|
|
117
|
+
expect(result).toBe('2024-01-01T00:00:00.000Z');
|
|
118
|
+
});
|
|
119
|
+
it('should preserve timestamps already in normalized format', () => {
|
|
120
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({
|
|
121
|
+
type: extraction_1.TimeValueType.ABSOLUTE_TIME,
|
|
122
|
+
value: '2024-06-15T10:30:00.000Z',
|
|
123
|
+
}, baseState);
|
|
124
|
+
expect(result).toBe('2024-06-15T10:30:00.000Z');
|
|
125
|
+
});
|
|
126
|
+
it('should throw if value is missing', () => {
|
|
127
|
+
expect(() => (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.ABSOLUTE_TIME }, baseState)).toThrow('must have a value');
|
|
128
|
+
});
|
|
129
|
+
it('should throw a descriptive error if value is an invalid timestamp', () => {
|
|
130
|
+
expect(() => (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.ABSOLUTE_TIME, value: 'not-a-date' }, baseState)).toThrow("invalid ISO 8601 timestamp: 'not-a-date'");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('CURRENT_TIME type', () => {
|
|
134
|
+
it('should return current time as ISO string', () => {
|
|
135
|
+
const before = new Date().toISOString();
|
|
136
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.CURRENT_TIME }, baseState);
|
|
137
|
+
const after = new Date().toISOString();
|
|
138
|
+
expect(result).toBeDefined();
|
|
139
|
+
expect(result >= before).toBe(true);
|
|
140
|
+
expect(result <= after).toBe(true);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('UNBOUNDED type', () => {
|
|
144
|
+
it('should return UNBOUNDED_DATE_TIME_VALUE', () => {
|
|
145
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.UNBOUNDED }, baseState);
|
|
146
|
+
expect(result).toBe(constants_1.UNBOUNDED_DATE_TIME_VALUE);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe('WORKERS_OLDEST type', () => {
|
|
150
|
+
it('should return workersOldest from state', () => {
|
|
151
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_OLDEST }, baseState);
|
|
152
|
+
expect(result).toBe('2024-01-01T00:00:00.000Z');
|
|
153
|
+
});
|
|
154
|
+
it('should return UNBOUNDED_DATE_TIME_VALUE if workersOldest is not set', () => {
|
|
155
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_OLDEST }, { workersOldest: '' });
|
|
156
|
+
expect(result).toBe(constants_1.UNBOUNDED_DATE_TIME_VALUE);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
describe('WORKERS_NEWEST type', () => {
|
|
160
|
+
it('should return workersNewest from state', () => {
|
|
161
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_NEWEST }, baseState);
|
|
162
|
+
expect(result).toBe('2024-06-01T00:00:00.000Z');
|
|
163
|
+
});
|
|
164
|
+
it('should throw if workersNewest is not set', () => {
|
|
165
|
+
expect(() => (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_NEWEST }, { workersNewest: '' })).toThrow('workersNewest is not set in state');
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe('WORKERS_OLDEST_MINUS_WINDOW type', () => {
|
|
169
|
+
it('should subtract duration from workersOldest', () => {
|
|
170
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({
|
|
171
|
+
type: extraction_1.TimeValueType.WORKERS_OLDEST_MINUS_WINDOW,
|
|
172
|
+
value: '168h',
|
|
173
|
+
}, baseState);
|
|
174
|
+
expect(result).toBe('2023-12-25T00:00:00.000Z');
|
|
175
|
+
});
|
|
176
|
+
it('should subtract minutes from workersOldest', () => {
|
|
177
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({
|
|
178
|
+
type: extraction_1.TimeValueType.WORKERS_OLDEST_MINUS_WINDOW,
|
|
179
|
+
value: '30m',
|
|
180
|
+
}, baseState);
|
|
181
|
+
expect(result).toBe('2023-12-31T23:30:00.000Z');
|
|
182
|
+
});
|
|
183
|
+
it('should return UNBOUNDED_DATE_TIME_VALUE if workersOldest is not set', () => {
|
|
184
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({
|
|
185
|
+
type: extraction_1.TimeValueType.WORKERS_OLDEST_MINUS_WINDOW,
|
|
186
|
+
value: '2h',
|
|
187
|
+
}, { workersOldest: '' });
|
|
188
|
+
expect(result).toBe(constants_1.UNBOUNDED_DATE_TIME_VALUE);
|
|
189
|
+
});
|
|
190
|
+
it('should throw if value (duration) is missing', () => {
|
|
191
|
+
expect(() => (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_OLDEST_MINUS_WINDOW }, baseState)).toThrow('must have a value');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
describe('WORKERS_NEWEST_PLUS_WINDOW type', () => {
|
|
195
|
+
it('should add duration to workersNewest', () => {
|
|
196
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({
|
|
197
|
+
type: extraction_1.TimeValueType.WORKERS_NEWEST_PLUS_WINDOW,
|
|
198
|
+
value: '168h',
|
|
199
|
+
}, baseState);
|
|
200
|
+
expect(result).toBe('2024-06-08T00:00:00.000Z');
|
|
201
|
+
});
|
|
202
|
+
it('should add minutes to workersNewest', () => {
|
|
203
|
+
const result = (0, time_value_resolver_1.resolveTimeValue)({
|
|
204
|
+
type: extraction_1.TimeValueType.WORKERS_NEWEST_PLUS_WINDOW,
|
|
205
|
+
value: '30m',
|
|
206
|
+
}, baseState);
|
|
207
|
+
expect(result).toBe('2024-06-01T00:30:00.000Z');
|
|
208
|
+
});
|
|
209
|
+
it('should throw if workersNewest is not set', () => {
|
|
210
|
+
expect(() => (0, time_value_resolver_1.resolveTimeValue)({
|
|
211
|
+
type: extraction_1.TimeValueType.WORKERS_NEWEST_PLUS_WINDOW,
|
|
212
|
+
value: '2h',
|
|
213
|
+
}, { workersNewest: '' })).toThrow('workersNewest is not set in state');
|
|
214
|
+
});
|
|
215
|
+
it('should throw if value (duration) is missing', () => {
|
|
216
|
+
expect(() => (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_NEWEST_PLUS_WINDOW }, baseState)).toThrow('must have a value');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
describe('Unknown type', () => {
|
|
220
|
+
it('should throw for unknown type', () => {
|
|
221
|
+
expect(() =>
|
|
222
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
223
|
+
(0, time_value_resolver_1.resolveTimeValue)({ type: 'unknown' }, baseState)).toThrow('Unknown TimeValueType');
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
describe('Real-world scenarios', () => {
|
|
227
|
+
const FIXED_NOW = '2026-02-26T15:30:00.000Z';
|
|
228
|
+
const scenarioState = {
|
|
229
|
+
lastSyncStarted: '',
|
|
230
|
+
lastSuccessfulSyncStarted: '',
|
|
231
|
+
workersOldest: '2024-01-01T00:00:00.000Z',
|
|
232
|
+
workersNewest: '2024-06-01T00:00:00.000Z',
|
|
233
|
+
};
|
|
234
|
+
beforeEach(() => {
|
|
235
|
+
jest.useFakeTimers();
|
|
236
|
+
jest.setSystemTime(new Date(FIXED_NOW));
|
|
237
|
+
});
|
|
238
|
+
afterEach(() => {
|
|
239
|
+
jest.useRealTimers();
|
|
240
|
+
});
|
|
241
|
+
it('Initial Import: UNBOUNDED start, CURRENT_TIME end', () => {
|
|
242
|
+
const start = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.UNBOUNDED }, scenarioState);
|
|
243
|
+
const end = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.CURRENT_TIME }, scenarioState);
|
|
244
|
+
expect(start).toBe(constants_1.UNBOUNDED_DATE_TIME_VALUE);
|
|
245
|
+
expect(end).toBe(FIXED_NOW);
|
|
246
|
+
});
|
|
247
|
+
it('Normal Import: WORKERS_NEWEST start, CURRENT_TIME end', () => {
|
|
248
|
+
const start = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_NEWEST }, scenarioState);
|
|
249
|
+
const end = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.CURRENT_TIME }, scenarioState);
|
|
250
|
+
expect(start).toBe('2024-06-01T00:00:00.000Z');
|
|
251
|
+
expect(end).toBe(FIXED_NOW);
|
|
252
|
+
});
|
|
253
|
+
it('POC Import: ABSOLUTE_TIME start, CURRENT_TIME end', () => {
|
|
254
|
+
const start = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.ABSOLUTE_TIME, value: '2024-01-01T00:00:00Z' }, scenarioState);
|
|
255
|
+
const end = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.CURRENT_TIME }, scenarioState);
|
|
256
|
+
expect(start).toBe('2024-01-01T00:00:00.000Z');
|
|
257
|
+
expect(end).toBe(FIXED_NOW);
|
|
258
|
+
});
|
|
259
|
+
it('Computer Import: WORKERS_OLDEST_MINUS_WINDOW start, WORKERS_OLDEST end', () => {
|
|
260
|
+
const start = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_OLDEST_MINUS_WINDOW, value: '168h' }, scenarioState);
|
|
261
|
+
const end = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.WORKERS_OLDEST }, scenarioState);
|
|
262
|
+
expect(start).toBe('2023-12-25T00:00:00.000Z');
|
|
263
|
+
expect(end).toBe('2024-01-01T00:00:00.000Z');
|
|
264
|
+
});
|
|
265
|
+
it('Reconciliation: ABSOLUTE_TIME start, ABSOLUTE_TIME end', () => {
|
|
266
|
+
const start = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.ABSOLUTE_TIME, value: '2026-01-01T00:00:00Z' }, scenarioState);
|
|
267
|
+
const end = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.ABSOLUTE_TIME, value: '2026-03-31T23:59:59Z' }, scenarioState);
|
|
268
|
+
expect(start).toBe('2026-01-01T00:00:00.000Z');
|
|
269
|
+
expect(end).toBe('2026-03-31T23:59:59.000Z');
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
});
|
|
@@ -5,7 +5,6 @@ import { RequestInfo, RouteConfig } from './mock-server.interfaces';
|
|
|
5
5
|
* Supports per-test route configuration to simulate different response scenarios.
|
|
6
6
|
*/
|
|
7
7
|
export declare class MockServer {
|
|
8
|
-
private app;
|
|
9
8
|
private server;
|
|
10
9
|
private internalPort;
|
|
11
10
|
port: number;
|
|
@@ -16,40 +15,15 @@ export declare class MockServer {
|
|
|
16
15
|
constructor(port?: number);
|
|
17
16
|
start(): Promise<void>;
|
|
18
17
|
stop(): Promise<void>;
|
|
19
|
-
|
|
20
|
-
* Sets up routes for the mock server.
|
|
21
|
-
*/
|
|
22
|
-
private setupRoutes;
|
|
23
|
-
/**
|
|
24
|
-
* Creates a route handler that checks for custom handlers before using the default.
|
|
25
|
-
* @param method - The HTTP method
|
|
26
|
-
* @param path - The route path
|
|
27
|
-
* @returns A route handler function
|
|
28
|
-
*/
|
|
29
|
-
private routeHandler;
|
|
18
|
+
private handleRequest;
|
|
30
19
|
/**
|
|
31
20
|
* Default route handler for the mock server. Returns { success: true } for
|
|
32
21
|
* routes that are not explicitly set.
|
|
33
|
-
* @param req - The request object
|
|
34
|
-
* @param res - The response object
|
|
35
|
-
* @returns void
|
|
36
22
|
*/
|
|
37
23
|
private defaultRouteHandler;
|
|
38
|
-
/**
|
|
39
|
-
* Gets the route key for a given method and path.
|
|
40
|
-
* @param method - The HTTP method
|
|
41
|
-
* @param path - The route path
|
|
42
|
-
* @returns The route key in the format 'METHOD:path'
|
|
43
|
-
*/
|
|
44
24
|
private getRouteKey;
|
|
45
25
|
/**
|
|
46
26
|
* Configures a route to return a specific status code and optional response body.
|
|
47
|
-
* @param config - The route configuration object
|
|
48
|
-
* @param config.path - The path of the route (e.g., '/callback_url')
|
|
49
|
-
* @param config.method - The HTTP method (e.g., 'GET', 'POST')
|
|
50
|
-
* @param config.status - The HTTP status code to return (e.g., 200, 401, 500)
|
|
51
|
-
* @param config.body - Optional response body to send as JSON
|
|
52
|
-
* @param config.retry - Optional retry configuration for simulating failures before success
|
|
53
27
|
*/
|
|
54
28
|
setRoute(config: RouteConfig): void;
|
|
55
29
|
/**
|
|
@@ -59,21 +33,14 @@ export declare class MockServer {
|
|
|
59
33
|
resetRoutes(): void;
|
|
60
34
|
/**
|
|
61
35
|
* Returns the most recent request or undefined if no requests exist.
|
|
62
|
-
* @returns The last RequestInfo object or undefined
|
|
63
36
|
*/
|
|
64
37
|
getLastRequest(): RequestInfo | undefined;
|
|
65
38
|
/**
|
|
66
39
|
* Gets the number of requests made to a specific endpoint.
|
|
67
|
-
* @param method - The HTTP method (e.g., 'GET', 'POST')
|
|
68
|
-
* @param path - The route path (e.g., '/test-endpoint', '/callback_url')
|
|
69
|
-
* @returns The number of requests made to the endpoint
|
|
70
40
|
*/
|
|
71
41
|
getRequestCount(method: string, path: string): number;
|
|
72
42
|
/**
|
|
73
43
|
* Gets all requests made to a specific endpoint.
|
|
74
|
-
* @param method - The HTTP method (e.g., 'GET', 'POST')
|
|
75
|
-
* @param path - The route path (e.g., '/test-endpoint', '/callback_url')
|
|
76
|
-
* @returns An array of RequestInfo objects for the endpoint
|
|
77
44
|
*/
|
|
78
45
|
getRequests(method: string, path: string): RequestInfo[];
|
|
79
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-server.d.ts","sourceRoot":"","sources":["../../src/mock-server/mock-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mock-server.d.ts","sourceRoot":"","sources":["../../src/mock-server/mock-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,WAAW,EACX,WAAW,EAEZ,MAAM,0BAA0B,CAAC;AAuElC;;;;GAIG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAS;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,aAAa,CAA4B;gBAErC,IAAI,GAAE,MAAiC;IAMtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAkBpB,aAAa;IA+B3B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA6B3B,OAAO,CAAC,WAAW;IAInB;;OAEG;IACI,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAyE1C;;;OAGG;IACI,WAAW,IAAI,IAAI;IAM1B;;OAEG;IACI,cAAc,IAAI,WAAW,GAAG,SAAS;IAOhD;;OAEG;IACI,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAI5D;;OAEG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE;CAQhE"}
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
2
2
|
export declare const DEFAULT_MOCK_SERVER_PORT = 3001;
|
|
3
|
+
export interface ParsedRequest extends IncomingMessage {
|
|
4
|
+
/** Parsed URL path (without query string) */
|
|
5
|
+
path: string;
|
|
6
|
+
/** Parsed JSON body (if any) */
|
|
7
|
+
body?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface MockResponse extends ServerResponse {
|
|
10
|
+
/** Set response headers from a record */
|
|
11
|
+
set(headers: Record<string, string>): MockResponse;
|
|
12
|
+
/** Set the HTTP status code */
|
|
13
|
+
status(code: number): MockResponse;
|
|
14
|
+
/** Send a JSON response */
|
|
15
|
+
json(data: unknown): void;
|
|
16
|
+
/** Send an empty response */
|
|
17
|
+
send(): void;
|
|
18
|
+
}
|
|
3
19
|
/**
|
|
4
20
|
* Configuration for retry simulation behavior.
|
|
5
21
|
*/
|
|
@@ -37,7 +53,7 @@ export interface RouteConfig {
|
|
|
37
53
|
/**
|
|
38
54
|
* Type for custom route handler functions.
|
|
39
55
|
*/
|
|
40
|
-
export type RouteHandler = (req:
|
|
56
|
+
export type RouteHandler = (req: ParsedRequest, res: MockResponse) => unknown;
|
|
41
57
|
/**
|
|
42
58
|
* Information about a request received by the mock server.
|
|
43
59
|
*/
|