polarity-integration-utils 3.1.7 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dts/errors/integration-error.d.ts +11 -11
- package/dist/dts/errors/integration-error.d.ts.map +1 -1
- package/dist/dts/errors/parse-error-to-readable-json.d.ts +2 -2
- package/dist/dts/errors/parse-error-to-readable-json.d.ts.map +1 -1
- package/dist/dts/index.d.ts +1 -3
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/index.docs.d.ts +1 -1
- package/dist/dts/lib/errors/integration-error.d.ts +11 -11
- package/dist/dts/lib/errors/integration-error.d.ts.map +1 -1
- package/dist/dts/lib/errors/parse-error-to-readable-json.d.ts +2 -2
- package/dist/dts/lib/errors/parse-error-to-readable-json.d.ts.map +1 -1
- package/dist/dts/lib/index.d.ts +1 -3
- package/dist/dts/lib/index.d.ts.map +1 -1
- package/dist/dts/lib/index.docs.d.ts +1 -1
- package/dist/dts/lib/logging/logger.d.ts +1 -12
- package/dist/dts/lib/logging/logger.d.ts.map +1 -1
- package/dist/dts/lib/requests/polarity-request.d.ts +93 -68
- package/dist/dts/lib/requests/polarity-request.d.ts.map +1 -1
- package/dist/dts/lib/testing/enhanced-utils/create-entity.d.ts +17 -1
- package/dist/dts/lib/testing/enhanced-utils/create-entity.d.ts.map +1 -1
- package/dist/dts/lib/testing/enhanced-utils/create-mock-integration-context.d.ts +42 -2
- package/dist/dts/lib/testing/enhanced-utils/create-mock-integration-context.d.ts.map +1 -1
- package/dist/dts/lib/testing/index.d.ts +0 -3
- package/dist/dts/lib/testing/index.d.ts.map +1 -1
- package/dist/dts/lib/types.d.ts +89 -84
- package/dist/dts/lib/types.d.ts.map +1 -1
- package/dist/dts/logging/logger.d.ts +1 -12
- package/dist/dts/logging/logger.d.ts.map +1 -1
- package/dist/dts/requests/polarity-request.d.ts +93 -68
- package/dist/dts/requests/polarity-request.d.ts.map +1 -1
- package/dist/dts/testing/enhanced-utils/create-entity.d.ts +17 -1
- package/dist/dts/testing/enhanced-utils/create-entity.d.ts.map +1 -1
- package/dist/dts/testing/enhanced-utils/create-mock-integration-context.d.ts +42 -2
- package/dist/dts/testing/enhanced-utils/create-mock-integration-context.d.ts.map +1 -1
- package/dist/dts/testing/index.d.ts +0 -3
- package/dist/dts/testing/index.d.ts.map +1 -1
- package/dist/dts/tsdoc-metadata.json +1 -1
- package/dist/dts/types.d.ts +89 -84
- package/dist/dts/types.d.ts.map +1 -1
- package/dist/es/lib/errors/integration-error.js +7 -4
- package/dist/es/lib/index.docs.js +1 -1
- package/dist/es/lib/index.js +1 -5
- package/dist/es/lib/logging/logger.js +18 -7
- package/dist/es/lib/requests/polarity-request.js +103 -126
- package/dist/es/lib/testing/enhanced-utils/create-entity.js +31 -5
- package/dist/es/lib/testing/enhanced-utils/create-mock-integration-context.js +54 -27
- package/dist/es/lib/testing/index.js +0 -3
- package/dist/es/lib/types.js +2 -1
- package/dist/lib/errors/integration-error.js +7 -4
- package/dist/lib/index.docs.js +1 -1
- package/dist/lib/index.js +1 -5
- package/dist/lib/logging/logger.js +18 -7
- package/dist/lib/requests/polarity-request.js +103 -126
- package/dist/lib/testing/enhanced-utils/create-entity.js +31 -5
- package/dist/lib/testing/enhanced-utils/create-mock-integration-context.js +54 -27
- package/dist/lib/testing/index.js +0 -3
- package/dist/lib/types.js +2 -1
- package/dist/polarity-integration-utils.d.ts +264 -594
- package/package.json +8 -11
- package/dist/dts/context/cache.d.ts +0 -149
- package/dist/dts/context/cache.d.ts.map +0 -1
- package/dist/dts/context/index.d.ts +0 -3
- package/dist/dts/context/index.d.ts.map +0 -1
- package/dist/dts/context/integration-context.d.ts +0 -16
- package/dist/dts/context/integration-context.d.ts.map +0 -1
- package/dist/dts/lib/context/cache.d.ts +0 -149
- package/dist/dts/lib/context/cache.d.ts.map +0 -1
- package/dist/dts/lib/context/index.d.ts +0 -3
- package/dist/dts/lib/context/index.d.ts.map +0 -1
- package/dist/dts/lib/context/integration-context.d.ts +0 -16
- package/dist/dts/lib/context/integration-context.d.ts.map +0 -1
- package/dist/dts/lib/testing/enhanced-utils/mock-request.d.ts +0 -14
- package/dist/dts/lib/testing/enhanced-utils/mock-request.d.ts.map +0 -1
- package/dist/dts/lib/testing/enhanced-utils/validate-integration.d.ts +0 -8
- package/dist/dts/lib/testing/enhanced-utils/validate-integration.d.ts.map +0 -1
- package/dist/dts/lib/testing/test-factory/create-integration-tests.d.ts +0 -6
- package/dist/dts/lib/testing/test-factory/create-integration-tests.d.ts.map +0 -1
- package/dist/dts/lib/testing/test-factory/test-do-lookup.d.ts +0 -7
- package/dist/dts/lib/testing/test-factory/test-do-lookup.d.ts.map +0 -1
- package/dist/dts/lib/testing/test-factory/test-on-message.d.ts +0 -8
- package/dist/dts/lib/testing/test-factory/test-on-message.d.ts.map +0 -1
- package/dist/dts/lib/zod-types.d.ts +0 -278
- package/dist/dts/lib/zod-types.d.ts.map +0 -1
- package/dist/dts/testing/enhanced-utils/mock-request.d.ts +0 -14
- package/dist/dts/testing/enhanced-utils/mock-request.d.ts.map +0 -1
- package/dist/dts/testing/enhanced-utils/validate-integration.d.ts +0 -8
- package/dist/dts/testing/enhanced-utils/validate-integration.d.ts.map +0 -1
- package/dist/dts/testing/test-factory/create-integration-tests.d.ts +0 -6
- package/dist/dts/testing/test-factory/create-integration-tests.d.ts.map +0 -1
- package/dist/dts/testing/test-factory/test-do-lookup.d.ts +0 -7
- package/dist/dts/testing/test-factory/test-do-lookup.d.ts.map +0 -1
- package/dist/dts/testing/test-factory/test-on-message.d.ts +0 -8
- package/dist/dts/testing/test-factory/test-on-message.d.ts.map +0 -1
- package/dist/dts/zod-types.d.ts +0 -278
- package/dist/dts/zod-types.d.ts.map +0 -1
- package/dist/es/lib/context/cache.js +0 -2
- package/dist/es/lib/context/index.js +0 -18
- package/dist/es/lib/context/integration-context.js +0 -2
- package/dist/es/lib/testing/enhanced-utils/mock-request.js +0 -22
- package/dist/es/lib/testing/enhanced-utils/validate-integration.js +0 -159
- package/dist/es/lib/testing/test-factory/create-integration-tests.js +0 -53
- package/dist/es/lib/testing/test-factory/test-do-lookup.js +0 -24
- package/dist/es/lib/testing/test-factory/test-on-message.js +0 -24
- package/dist/es/lib/zod-types.js +0 -206
- package/dist/lib/context/cache.js +0 -2
- package/dist/lib/context/index.js +0 -18
- package/dist/lib/context/integration-context.js +0 -2
- package/dist/lib/testing/enhanced-utils/mock-request.js +0 -22
- package/dist/lib/testing/enhanced-utils/validate-integration.js +0 -159
- package/dist/lib/testing/test-factory/create-integration-tests.js +0 -53
- package/dist/lib/testing/test-factory/test-do-lookup.js +0 -24
- package/dist/lib/testing/test-factory/test-on-message.js +0 -24
- package/dist/lib/zod-types.js +0 -206
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createEntity = void 0;
|
|
4
|
+
function toEntityTypeIdentifier(type) {
|
|
5
|
+
if (type === 'IP')
|
|
6
|
+
return 'IPv4';
|
|
7
|
+
if (type.startsWith('custom.'))
|
|
8
|
+
return 'custom';
|
|
9
|
+
return type;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates a mock `Entity` for use in tests.
|
|
13
|
+
*
|
|
14
|
+
* Automatically detects whether the value is a domain or IPv4 address and sets
|
|
15
|
+
* the corresponding boolean flags. All other flags default to `false`.
|
|
16
|
+
*
|
|
17
|
+
* @param type - An `EntityType` string (e.g., `'IPv4'`, `'domain'`, `'MD5'`)
|
|
18
|
+
* @param value - The entity value string
|
|
19
|
+
* @returns A fully populated `Entity` object
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const ip = createEntity('IPv4', '8.8.8.8');
|
|
24
|
+
* const domain = createEntity('domain', 'example.com');
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
4
27
|
const createEntity = (type, value) => {
|
|
5
28
|
const isDomain = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/.test(value);
|
|
6
29
|
const isIPv4 = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(value);
|
|
30
|
+
const isIPv6 = /^[\da-fA-F:]+$/.test(value) && value.includes(':');
|
|
7
31
|
return {
|
|
8
32
|
value,
|
|
33
|
+
rawValue: value,
|
|
9
34
|
displayValue: value,
|
|
10
|
-
type,
|
|
35
|
+
type: toEntityTypeIdentifier(type),
|
|
11
36
|
types: [type],
|
|
12
37
|
isDomain,
|
|
13
38
|
isIPv4,
|
|
14
|
-
isIP: isIPv4,
|
|
39
|
+
isIP: isIPv4 || isIPv6,
|
|
15
40
|
isEmail: false,
|
|
16
41
|
isHash: false,
|
|
17
42
|
isHex: false,
|
|
18
43
|
isHTMLTag: false,
|
|
19
|
-
isIPv6
|
|
44
|
+
isIPv6,
|
|
20
45
|
isMD5: false,
|
|
21
46
|
isPrivateIP: false,
|
|
22
47
|
isSHA1: false,
|
|
@@ -25,11 +50,12 @@ const createEntity = (type, value) => {
|
|
|
25
50
|
isURL: false,
|
|
26
51
|
latitude: 0,
|
|
27
52
|
longitude: 0,
|
|
53
|
+
IPLong: 0,
|
|
28
54
|
hashType: '',
|
|
29
|
-
IPType: isIPv4 ? 'IPv4' : '',
|
|
55
|
+
IPType: isIPv4 ? 'IPv4' : isIPv6 ? 'IPv6' : '',
|
|
30
56
|
channels: [],
|
|
31
57
|
requestContext: {
|
|
32
|
-
requestType: '
|
|
58
|
+
requestType: 'OnDemand',
|
|
33
59
|
isUserInitiated: true
|
|
34
60
|
}
|
|
35
61
|
};
|
|
@@ -1,36 +1,63 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createMockIntegrationContext = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
4
|
+
const noOp = () => () => undefined;
|
|
5
|
+
/**
|
|
6
|
+
* Creates a mock `IntegrationContext`
|
|
7
|
+
* with stubbed logger, cache, and polling methods.
|
|
8
|
+
*
|
|
9
|
+
* Pass your testing framework's mock function factory to enable spy capabilities
|
|
10
|
+
* (e.g., `toHaveBeenCalledWith()`). When omitted, plain no-op stubs are used.
|
|
11
|
+
*
|
|
12
|
+
* @param createMockFn - A factory that creates mock functions (e.g., `vi.fn` or `jest.fn`)
|
|
13
|
+
* @returns A fully populated `IntegrationContext` with stubbed methods
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Vitest
|
|
18
|
+
* const ctx = createMockIntegrationContext(vi.fn);
|
|
19
|
+
*
|
|
20
|
+
* // Jest
|
|
21
|
+
* const ctx = createMockIntegrationContext(jest.fn);
|
|
22
|
+
*
|
|
23
|
+
* // No framework — plain no-ops
|
|
24
|
+
* const ctx = createMockIntegrationContext();
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
const createMockIntegrationContext = (createMockFn = noOp) => {
|
|
28
|
+
const createCacheScope = () => ({
|
|
29
|
+
get: createMockFn(),
|
|
30
|
+
set: createMockFn(),
|
|
31
|
+
delete: createMockFn()
|
|
32
|
+
});
|
|
33
|
+
const childFn = createMockFn();
|
|
34
|
+
const logger = {
|
|
35
|
+
child: childFn,
|
|
36
|
+
info: createMockFn(),
|
|
37
|
+
debug: createMockFn(),
|
|
38
|
+
trace: createMockFn(),
|
|
39
|
+
warn: createMockFn(),
|
|
40
|
+
error: createMockFn(),
|
|
41
|
+
fatal: createMockFn()
|
|
21
42
|
};
|
|
43
|
+
// Make child() return the logger for method chaining
|
|
44
|
+
if (typeof childFn.mockReturnValue === 'function') {
|
|
45
|
+
childFn.mockReturnValue(logger);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
logger.child = () => logger;
|
|
49
|
+
}
|
|
22
50
|
return {
|
|
23
|
-
cache
|
|
51
|
+
cache: {
|
|
52
|
+
global: createCacheScope(),
|
|
53
|
+
integration: createCacheScope(),
|
|
54
|
+
user: createCacheScope()
|
|
55
|
+
},
|
|
24
56
|
integrationId: 'test-integration',
|
|
25
|
-
userId:
|
|
26
|
-
logger
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
trace: jest.fn(),
|
|
30
|
-
warn: jest.fn(),
|
|
31
|
-
error: jest.fn(),
|
|
32
|
-
fatal: jest.fn()
|
|
33
|
-
}
|
|
57
|
+
userId: 1,
|
|
58
|
+
logger,
|
|
59
|
+
startPolling: createMockFn(),
|
|
60
|
+
stopPolling: createMockFn()
|
|
34
61
|
};
|
|
35
62
|
};
|
|
36
63
|
exports.createMockIntegrationContext = createMockIntegrationContext;
|
|
@@ -14,8 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./test-factory/create-integration-tests"), exports);
|
|
18
17
|
__exportStar(require("./enhanced-utils/create-entity"), exports);
|
|
19
18
|
__exportStar(require("./enhanced-utils/create-mock-integration-context"), exports);
|
|
20
|
-
__exportStar(require("./enhanced-utils/mock-request"), exports);
|
|
21
|
-
__exportStar(require("./enhanced-utils/validate-integration"), exports);
|
package/dist/es/lib/types.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.IntegrationError = void 0;
|
|
4
|
-
|
|
4
|
+
// Re-export utils-specific types
|
|
5
|
+
var errors_1 = require("./errors");
|
|
5
6
|
Object.defineProperty(exports, "IntegrationError", { enumerable: true, get: function () { return errors_1.IntegrationError; } });
|
|
@@ -31,7 +31,7 @@ class IntegrationError extends Error {
|
|
|
31
31
|
code;
|
|
32
32
|
/**
|
|
33
33
|
* The `cause` property is used to specify the `cause` of the error. Typically,
|
|
34
|
-
* this property is used to pass through a related Error instance.
|
|
34
|
+
* this property is used to pass through a related Error instance but can be any value.
|
|
35
35
|
*/
|
|
36
36
|
cause;
|
|
37
37
|
/**
|
|
@@ -63,7 +63,7 @@ class IntegrationError extends Error {
|
|
|
63
63
|
if (typeof properties.status !== 'undefined') {
|
|
64
64
|
this.status = properties.status;
|
|
65
65
|
}
|
|
66
|
-
if (
|
|
66
|
+
if (typeof properties.cause !== 'undefined') {
|
|
67
67
|
this.cause = properties.cause;
|
|
68
68
|
}
|
|
69
69
|
if (typeof properties.requestOptions !== 'undefined') {
|
|
@@ -101,8 +101,11 @@ class IntegrationError extends Error {
|
|
|
101
101
|
if (this.help) {
|
|
102
102
|
props.help = this.help;
|
|
103
103
|
}
|
|
104
|
-
if (this.cause) {
|
|
105
|
-
props.cause =
|
|
104
|
+
if (this.cause !== undefined) {
|
|
105
|
+
props.cause =
|
|
106
|
+
this.cause instanceof Error
|
|
107
|
+
? (0, parse_error_to_readable_json_1.parseErrorToReadableJson)(this.cause)
|
|
108
|
+
: this.cause;
|
|
106
109
|
}
|
|
107
110
|
if (this.requestOptions) {
|
|
108
111
|
props.requestOptions = this.requestOptions;
|
package/dist/lib/index.docs.js
CHANGED
|
@@ -22,4 +22,4 @@ __exportStar(require("./errors"), exports);
|
|
|
22
22
|
__exportStar(require("./requests"), exports);
|
|
23
23
|
__exportStar(require("./logging"), exports);
|
|
24
24
|
__exportStar(require("./types"), exports);
|
|
25
|
-
__exportStar(require("./
|
|
25
|
+
__exportStar(require("./testing"), exports);
|
package/dist/lib/index.js
CHANGED
|
@@ -36,15 +36,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
36
36
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
39
|
+
exports.logging = exports.requests = exports.errors = void 0;
|
|
40
40
|
const errors = __importStar(require("./errors"));
|
|
41
41
|
exports.errors = errors;
|
|
42
42
|
const requests = __importStar(require("./requests"));
|
|
43
43
|
exports.requests = requests;
|
|
44
44
|
const logging = __importStar(require("./logging"));
|
|
45
45
|
exports.logging = logging;
|
|
46
|
-
const context = __importStar(require("./context"));
|
|
47
|
-
exports.context = context;
|
|
48
|
-
const types = __importStar(require("./types"));
|
|
49
|
-
exports.types = types;
|
|
50
46
|
__exportStar(require("./types"), exports);
|
|
@@ -5,13 +5,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getLogger = exports.setLogger = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const createLogMethod = (loggingLevel) => (...content) => {
|
|
9
|
+
if (content.length === 0)
|
|
10
|
+
return true;
|
|
11
|
+
fs_1.default.appendFileSync('devRunnerResults.json', '\n' + JSON.stringify({ SOURCE: `Logger.${loggingLevel}`, content }, null, 2));
|
|
12
|
+
};
|
|
13
|
+
function createDefaultLogger() {
|
|
14
|
+
const logger = {
|
|
15
|
+
child: () => logger,
|
|
16
|
+
trace: createLogMethod('trace'),
|
|
17
|
+
debug: createLogMethod('debug'),
|
|
18
|
+
info: createLogMethod('info'),
|
|
19
|
+
warn: createLogMethod('warn'),
|
|
20
|
+
error: createLogMethod('error'),
|
|
21
|
+
fatal: createLogMethod('fatal')
|
|
22
|
+
};
|
|
23
|
+
return logger;
|
|
24
|
+
}
|
|
25
|
+
let _logger = createDefaultLogger();
|
|
15
26
|
/**
|
|
16
27
|
* Set the logger object used by the integration.
|
|
17
28
|
*
|
|
@@ -6,10 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.PolarityRequest = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const util_1 = require("util");
|
|
9
|
-
const bottleneck_1 = __importDefault(require("bottleneck"));
|
|
10
9
|
const postman_request_1 = __importDefault(require("postman-request"));
|
|
11
10
|
const parallel_limit_1 = require("../internal/helpers/parallel-limit");
|
|
12
|
-
const node_util_1 = require("node:util");
|
|
13
11
|
const get_js_1 = __importDefault(require("lodash/get.js"));
|
|
14
12
|
const has_js_1 = __importDefault(require("lodash/has.js"));
|
|
15
13
|
const errors_1 = require("../errors");
|
|
@@ -20,12 +18,10 @@ const sanitize_request_options_1 = require("./sanitize-request-options");
|
|
|
20
18
|
* @public
|
|
21
19
|
*/
|
|
22
20
|
class PolarityRequest {
|
|
23
|
-
bottleneckLimiter;
|
|
24
21
|
/**
|
|
25
22
|
* Instance of a Bunyan logger
|
|
26
23
|
*/
|
|
27
24
|
logger;
|
|
28
|
-
internalThrottlingOptions;
|
|
29
25
|
/**
|
|
30
26
|
* postman-request library request object with default values set. Used internally for
|
|
31
27
|
* making HTTP requests directly via the postman-request library
|
|
@@ -75,80 +71,25 @@ class PolarityRequest {
|
|
|
75
71
|
requestOptionsToSanitize = [];
|
|
76
72
|
userOptions = null;
|
|
77
73
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* This method is typically used for adding authentication (e.g., auth headers, or basic auth) to every request.
|
|
84
|
-
* It can also be used to add headers that are required on every request or conditionally add headers based
|
|
85
|
-
* on the passed in `userOptions`.
|
|
86
|
-
*
|
|
87
|
-
* This method can be set as part of the {@link PolarityRequestOptions} when creating a new instance of the
|
|
88
|
-
* {@link PolarityRequest} class or can be set after the fact.
|
|
89
|
-
*
|
|
90
|
-
* @param requestOptions - A copy of the request options used for the request. This object can be modified
|
|
91
|
-
* without side effects.
|
|
92
|
-
* @param userOptions - The user options passed into the `doLookup` method.
|
|
93
|
-
* @returns The modified request options to use for the request.
|
|
74
|
+
* An optional rate limiter instance used to throttle HTTP requests.
|
|
75
|
+
* When set, all requests made via {@link PolarityRequest.run} are scheduled
|
|
76
|
+
* through this limiter. Typically provided by the Polarity server via the
|
|
77
|
+
* integration context.
|
|
94
78
|
*/
|
|
95
|
-
|
|
96
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
97
|
-
userOptions) => requestOptions;
|
|
79
|
+
limiter = null;
|
|
98
80
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
81
|
+
* Lifecycle hooks for customizing request behavior. Hooks are configured via the
|
|
82
|
+
* {@link PolarityRequestOptions.hooks} property when creating a new instance of the
|
|
83
|
+
* {@link PolarityRequest} class.
|
|
102
84
|
*
|
|
103
|
-
* @
|
|
104
|
-
* @param requestOptions - The request options used for the request.
|
|
105
|
-
* @param userOptions - The user options passed into the `doLookup` method.
|
|
85
|
+
* @see {@link PolarityRequestHooks} for hook type details.
|
|
106
86
|
*/
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Method that can be implemented to post-process the HTTP response after a failed request.
|
|
114
|
-
* This method is typically used to inspect the error thrown and either alter the error
|
|
115
|
-
* object (e.g., to change the error message property to something more specific), to ignore
|
|
116
|
-
* the error (by not rethrowing it), or to take a specific action based on the error (e.g.,
|
|
117
|
-
* in the case of a RetryRequestError you may want to retry the request or return a special
|
|
118
|
-
* payload to the integration front end).
|
|
119
|
-
*
|
|
120
|
-
* @param error - The error thrown during the request.
|
|
121
|
-
* @param requestOptions - The request options used for the request.
|
|
122
|
-
* @param userOptions - The user options passed into the `doLookup` method.
|
|
123
|
-
*/
|
|
124
|
-
postprocessRequestFailure = (error,
|
|
125
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
126
|
-
requestOptions,
|
|
127
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
128
|
-
userOptions) => {
|
|
129
|
-
throw error;
|
|
87
|
+
hooks = {
|
|
88
|
+
beforeRequest: [],
|
|
89
|
+
afterResponse: [],
|
|
90
|
+
onApiError: [],
|
|
91
|
+
onNetworkError: []
|
|
130
92
|
};
|
|
131
|
-
get throttlingOptions() {
|
|
132
|
-
return this.internalThrottlingOptions;
|
|
133
|
-
}
|
|
134
|
-
// REVIEW: Do we want to tie our throttling specifically to Bottleneck or do we want to make
|
|
135
|
-
// it more generic and independent of Bottleneck?
|
|
136
|
-
set throttlingOptions(throttlingOptions) {
|
|
137
|
-
if ((0, node_util_1.isDeepStrictEqual)(this.internalThrottlingOptions, throttlingOptions))
|
|
138
|
-
return;
|
|
139
|
-
this.bottleneckLimiter = new bottleneck_1.default({
|
|
140
|
-
...throttlingOptions,
|
|
141
|
-
maxConcurrent: typeof throttlingOptions.maxConcurrent === 'string'
|
|
142
|
-
? Number.parseInt(throttlingOptions.maxConcurrent, 10)
|
|
143
|
-
: throttlingOptions.maxConcurrent,
|
|
144
|
-
minTime: typeof throttlingOptions.minTime === 'string'
|
|
145
|
-
? Number.parseInt(throttlingOptions.minTime, 10)
|
|
146
|
-
: throttlingOptions.minTime,
|
|
147
|
-
highWater: throttlingOptions.highWater || 50,
|
|
148
|
-
strategy: throttlingOptions.strategy || bottleneck_1.default.strategy.OVERFLOW
|
|
149
|
-
});
|
|
150
|
-
this.internalThrottlingOptions = throttlingOptions;
|
|
151
|
-
}
|
|
152
93
|
constructor(options = {}) {
|
|
153
94
|
const defaults = options.defaults || {};
|
|
154
95
|
const { ca, cert, key, passphrase, proxy, rejectUnauthorized = true, json = true } = defaults;
|
|
@@ -177,17 +118,19 @@ class PolarityRequest {
|
|
|
177
118
|
if (options.requestOptionsToSanitize) {
|
|
178
119
|
this.requestOptionsToSanitize = options.requestOptionsToSanitize;
|
|
179
120
|
}
|
|
180
|
-
if (options.
|
|
181
|
-
|
|
121
|
+
if (options.hooks) {
|
|
122
|
+
const h = options.hooks;
|
|
123
|
+
if (h.beforeRequest)
|
|
124
|
+
this.hooks.beforeRequest = h.beforeRequest;
|
|
125
|
+
if (h.afterResponse)
|
|
126
|
+
this.hooks.afterResponse = h.afterResponse;
|
|
127
|
+
if (h.onApiError)
|
|
128
|
+
this.hooks.onApiError = h.onApiError;
|
|
129
|
+
if (h.onNetworkError)
|
|
130
|
+
this.hooks.onNetworkError = h.onNetworkError;
|
|
182
131
|
}
|
|
183
|
-
if (options.
|
|
184
|
-
this.
|
|
185
|
-
}
|
|
186
|
-
if (options.preprocessRequestOptions) {
|
|
187
|
-
this.preprocessRequestOptions = options.preprocessRequestOptions;
|
|
188
|
-
}
|
|
189
|
-
if (options.throttlingOptions) {
|
|
190
|
-
this.throttlingOptions = options.throttlingOptions;
|
|
132
|
+
if (options.limiter) {
|
|
133
|
+
this.limiter = options.limiter;
|
|
191
134
|
}
|
|
192
135
|
const defaultRequestOptions = {
|
|
193
136
|
...(this.configFieldIsValid(ca) && { ca: fs_1.default.readFileSync(ca) }),
|
|
@@ -211,58 +154,87 @@ class PolarityRequest {
|
|
|
211
154
|
if (!this.userOptions) {
|
|
212
155
|
throw new errors_1.LibraryUsageError('PolarityRequest property `userOptions` must be set before calling `run` method');
|
|
213
156
|
}
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
const httpResponse = await (this.bottleneckLimiter
|
|
222
|
-
? this.bottleneckLimiter.schedule(this.requestWithDefaults, postprocessedRequestOptions)
|
|
223
|
-
: this.requestWithDefaults(postprocessedRequestOptions));
|
|
224
|
-
if (this.bottleneckLimiter) {
|
|
225
|
-
this.logger.trace({ httpResponse }, 'HTTP Response via Bottleneck');
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
this.logger.trace({ httpResponse }, 'HTTP Response');
|
|
157
|
+
// Run beforeRequest hooks — each receives previous hook's output
|
|
158
|
+
let processedOptions = { ...requestOptions };
|
|
159
|
+
for (const hook of this.hooks.beforeRequest) {
|
|
160
|
+
const hookResult = await hook(processedOptions, this.userOptions);
|
|
161
|
+
if (!hookResult || typeof hookResult !== 'object' || Array.isArray(hookResult)) {
|
|
162
|
+
throw new errors_1.LibraryUsageError('Each `beforeRequest` hook must return an `HttpRequestOptions` object.');
|
|
229
163
|
}
|
|
230
|
-
|
|
231
|
-
|
|
164
|
+
processedOptions = hookResult;
|
|
165
|
+
}
|
|
166
|
+
let httpResponse;
|
|
167
|
+
try {
|
|
168
|
+
httpResponse = await (this.limiter
|
|
169
|
+
? this.limiter.schedule(this.requestWithDefaults, processedOptions)
|
|
170
|
+
: this.requestWithDefaults(processedOptions));
|
|
232
171
|
}
|
|
233
172
|
catch (requestError) {
|
|
234
|
-
let transformedError = requestError;
|
|
235
173
|
if (requestError instanceof errors_1.LibraryUsageError) {
|
|
236
174
|
throw requestError;
|
|
237
175
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
176
|
+
let transformedError;
|
|
177
|
+
if (requestError instanceof Error &&
|
|
178
|
+
requestError.constructor.name === 'BottleneckError') {
|
|
179
|
+
transformedError = new errors_1.RetryRequestError('This request has been dropped for going over Integration Configured API Throttling Limits', {
|
|
180
|
+
requestOptions: processedOptions,
|
|
242
181
|
requestOptionsToSanitize: this.requestOptionsToSanitize
|
|
243
182
|
});
|
|
244
183
|
}
|
|
245
|
-
|
|
246
|
-
transformedError = new errors_1.
|
|
247
|
-
|
|
184
|
+
else {
|
|
185
|
+
transformedError = new errors_1.NetworkError('Network error encountered during request', {
|
|
186
|
+
cause: requestError,
|
|
187
|
+
requestOptions: processedOptions,
|
|
248
188
|
requestOptionsToSanitize: this.requestOptionsToSanitize
|
|
249
189
|
});
|
|
250
190
|
}
|
|
251
|
-
|
|
252
|
-
|
|
191
|
+
if (this.hooks.onNetworkError.length > 0) {
|
|
192
|
+
for (const hook of this.hooks.onNetworkError) {
|
|
193
|
+
await hook(transformedError, processedOptions, this.userOptions);
|
|
194
|
+
}
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
throw transformedError;
|
|
253
198
|
}
|
|
254
|
-
|
|
199
|
+
if (this.limiter) {
|
|
200
|
+
this.logger.trace({ httpResponse }, 'HTTP Response via limiter');
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
this.logger.trace({ httpResponse }, 'HTTP Response');
|
|
204
|
+
}
|
|
205
|
+
// Check for API-level errors
|
|
206
|
+
const apiError = this.detectApiError(httpResponse, processedOptions);
|
|
207
|
+
if (apiError) {
|
|
208
|
+
if (this.hooks.onApiError.length > 0) {
|
|
209
|
+
for (const hook of this.hooks.onApiError) {
|
|
210
|
+
await hook(apiError, httpResponse, processedOptions, this.userOptions);
|
|
211
|
+
}
|
|
212
|
+
return httpResponse;
|
|
213
|
+
}
|
|
214
|
+
throw apiError;
|
|
215
|
+
}
|
|
216
|
+
// Run afterResponse hooks — each receives previous hook's output
|
|
217
|
+
let result = httpResponse;
|
|
218
|
+
for (const hook of this.hooks.afterResponse) {
|
|
219
|
+
const hookResult = await hook(result, processedOptions, this.userOptions);
|
|
220
|
+
if (!hookResult || typeof hookResult !== 'object' || Array.isArray(hookResult)) {
|
|
221
|
+
throw new errors_1.LibraryUsageError('Each `afterResponse` hook must return an `HttpRequestResponse` object.');
|
|
222
|
+
}
|
|
223
|
+
result = hookResult;
|
|
224
|
+
}
|
|
225
|
+
return result;
|
|
255
226
|
}
|
|
256
227
|
/**
|
|
257
|
-
* Checks whether the HTTP response is an API error and
|
|
228
|
+
* Checks whether the HTTP response is an API error and returns an ApiRequestError if it is.
|
|
258
229
|
*
|
|
259
230
|
* @param httpResponse - The HTTP response from the Postman request.
|
|
260
231
|
* @param requestOptions - The options used for the request.
|
|
232
|
+
* @returns An ApiRequestError if the response indicates an API error, undefined otherwise.
|
|
261
233
|
*
|
|
262
|
-
* @throws {@link
|
|
263
|
-
* Throws
|
|
234
|
+
* @throws {@link LibraryUsageError}
|
|
235
|
+
* Throws if the `isApiError` function returns an invalid result.
|
|
264
236
|
*/
|
|
265
|
-
|
|
237
|
+
detectApiError(httpResponse, requestOptions) {
|
|
266
238
|
const { statusCode, body } = httpResponse;
|
|
267
239
|
const requestOptionsWithoutSensitiveData = (0, sanitize_request_options_1.sanitizeRequestOptions)(requestOptions, this.requestOptionsToSanitize);
|
|
268
240
|
this.logger.trace({
|
|
@@ -291,7 +263,7 @@ class PolarityRequest {
|
|
|
291
263
|
message = this.getErrorMessageFromHttpResponse(body, 'Unexpected Error HTTP Response Received');
|
|
292
264
|
}
|
|
293
265
|
if (hasApiError) {
|
|
294
|
-
|
|
266
|
+
return new errors_1.ApiRequestError(message, {
|
|
295
267
|
status: statusCode.toString(),
|
|
296
268
|
requestOptions: requestOptionsWithoutSensitiveData,
|
|
297
269
|
requestOptionsToSanitize: this.requestOptionsToSanitize,
|
|
@@ -300,6 +272,7 @@ class PolarityRequest {
|
|
|
300
272
|
}
|
|
301
273
|
});
|
|
302
274
|
}
|
|
275
|
+
return undefined;
|
|
303
276
|
}
|
|
304
277
|
/**
|
|
305
278
|
* Returns true if the `httpStatusCode` is not one of the rounded HTTP status codes
|
|
@@ -380,8 +353,10 @@ class PolarityRequest {
|
|
|
380
353
|
* `requestId` property.
|
|
381
354
|
*
|
|
382
355
|
* @param options - An array of request options for running requests in parallel.
|
|
383
|
-
* @returns A promise that resolves to an array of responses
|
|
384
|
-
*
|
|
356
|
+
* @returns A promise that resolves to an array of responses in the same order as the input
|
|
357
|
+
* request options. If the `returnErrors` property is set to `true`, the response objects will
|
|
358
|
+
* have their `error` property set to the thrown error. If `onNetworkError` hooks are configured
|
|
359
|
+
* and suppress an error (return without throwing), the corresponding entry will be `undefined`.
|
|
385
360
|
*/
|
|
386
361
|
async runInParallel(options) {
|
|
387
362
|
const allRequestOptions = options.allRequestOptions;
|
|
@@ -396,14 +371,16 @@ class PolarityRequest {
|
|
|
396
371
|
return async () => {
|
|
397
372
|
try {
|
|
398
373
|
const response = await this.run(requestOptions);
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
374
|
+
if (response) {
|
|
375
|
+
if (requestOptions.entity) {
|
|
376
|
+
response.entity = requestOptions.entity;
|
|
377
|
+
}
|
|
378
|
+
else if (requestOptions.entities) {
|
|
379
|
+
response.entities = requestOptions.entities;
|
|
380
|
+
}
|
|
381
|
+
else if (requestOptions.requestId) {
|
|
382
|
+
response.requestId = requestOptions.requestId;
|
|
383
|
+
}
|
|
407
384
|
}
|
|
408
385
|
return response;
|
|
409
386
|
}
|
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createEntity = void 0;
|
|
4
|
+
function toEntityTypeIdentifier(type) {
|
|
5
|
+
if (type === 'IP')
|
|
6
|
+
return 'IPv4';
|
|
7
|
+
if (type.startsWith('custom.'))
|
|
8
|
+
return 'custom';
|
|
9
|
+
return type;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates a mock `Entity` for use in tests.
|
|
13
|
+
*
|
|
14
|
+
* Automatically detects whether the value is a domain or IPv4 address and sets
|
|
15
|
+
* the corresponding boolean flags. All other flags default to `false`.
|
|
16
|
+
*
|
|
17
|
+
* @param type - An `EntityType` string (e.g., `'IPv4'`, `'domain'`, `'MD5'`)
|
|
18
|
+
* @param value - The entity value string
|
|
19
|
+
* @returns A fully populated `Entity` object
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const ip = createEntity('IPv4', '8.8.8.8');
|
|
24
|
+
* const domain = createEntity('domain', 'example.com');
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
4
27
|
const createEntity = (type, value) => {
|
|
5
28
|
const isDomain = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/.test(value);
|
|
6
29
|
const isIPv4 = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(value);
|
|
30
|
+
const isIPv6 = /^[\da-fA-F:]+$/.test(value) && value.includes(':');
|
|
7
31
|
return {
|
|
8
32
|
value,
|
|
33
|
+
rawValue: value,
|
|
9
34
|
displayValue: value,
|
|
10
|
-
type,
|
|
35
|
+
type: toEntityTypeIdentifier(type),
|
|
11
36
|
types: [type],
|
|
12
37
|
isDomain,
|
|
13
38
|
isIPv4,
|
|
14
|
-
isIP: isIPv4,
|
|
39
|
+
isIP: isIPv4 || isIPv6,
|
|
15
40
|
isEmail: false,
|
|
16
41
|
isHash: false,
|
|
17
42
|
isHex: false,
|
|
18
43
|
isHTMLTag: false,
|
|
19
|
-
isIPv6
|
|
44
|
+
isIPv6,
|
|
20
45
|
isMD5: false,
|
|
21
46
|
isPrivateIP: false,
|
|
22
47
|
isSHA1: false,
|
|
@@ -25,11 +50,12 @@ const createEntity = (type, value) => {
|
|
|
25
50
|
isURL: false,
|
|
26
51
|
latitude: 0,
|
|
27
52
|
longitude: 0,
|
|
53
|
+
IPLong: 0,
|
|
28
54
|
hashType: '',
|
|
29
|
-
IPType: isIPv4 ? 'IPv4' : '',
|
|
55
|
+
IPType: isIPv4 ? 'IPv4' : isIPv6 ? 'IPv6' : '',
|
|
30
56
|
channels: [],
|
|
31
57
|
requestContext: {
|
|
32
|
-
requestType: '
|
|
58
|
+
requestType: 'OnDemand',
|
|
33
59
|
isUserInitiated: true
|
|
34
60
|
}
|
|
35
61
|
};
|