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.
Files changed (113) hide show
  1. package/dist/dts/errors/integration-error.d.ts +11 -11
  2. package/dist/dts/errors/integration-error.d.ts.map +1 -1
  3. package/dist/dts/errors/parse-error-to-readable-json.d.ts +2 -2
  4. package/dist/dts/errors/parse-error-to-readable-json.d.ts.map +1 -1
  5. package/dist/dts/index.d.ts +1 -3
  6. package/dist/dts/index.d.ts.map +1 -1
  7. package/dist/dts/index.docs.d.ts +1 -1
  8. package/dist/dts/lib/errors/integration-error.d.ts +11 -11
  9. package/dist/dts/lib/errors/integration-error.d.ts.map +1 -1
  10. package/dist/dts/lib/errors/parse-error-to-readable-json.d.ts +2 -2
  11. package/dist/dts/lib/errors/parse-error-to-readable-json.d.ts.map +1 -1
  12. package/dist/dts/lib/index.d.ts +1 -3
  13. package/dist/dts/lib/index.d.ts.map +1 -1
  14. package/dist/dts/lib/index.docs.d.ts +1 -1
  15. package/dist/dts/lib/logging/logger.d.ts +1 -12
  16. package/dist/dts/lib/logging/logger.d.ts.map +1 -1
  17. package/dist/dts/lib/requests/polarity-request.d.ts +93 -68
  18. package/dist/dts/lib/requests/polarity-request.d.ts.map +1 -1
  19. package/dist/dts/lib/testing/enhanced-utils/create-entity.d.ts +17 -1
  20. package/dist/dts/lib/testing/enhanced-utils/create-entity.d.ts.map +1 -1
  21. package/dist/dts/lib/testing/enhanced-utils/create-mock-integration-context.d.ts +42 -2
  22. package/dist/dts/lib/testing/enhanced-utils/create-mock-integration-context.d.ts.map +1 -1
  23. package/dist/dts/lib/testing/index.d.ts +0 -3
  24. package/dist/dts/lib/testing/index.d.ts.map +1 -1
  25. package/dist/dts/lib/types.d.ts +89 -84
  26. package/dist/dts/lib/types.d.ts.map +1 -1
  27. package/dist/dts/logging/logger.d.ts +1 -12
  28. package/dist/dts/logging/logger.d.ts.map +1 -1
  29. package/dist/dts/requests/polarity-request.d.ts +93 -68
  30. package/dist/dts/requests/polarity-request.d.ts.map +1 -1
  31. package/dist/dts/testing/enhanced-utils/create-entity.d.ts +17 -1
  32. package/dist/dts/testing/enhanced-utils/create-entity.d.ts.map +1 -1
  33. package/dist/dts/testing/enhanced-utils/create-mock-integration-context.d.ts +42 -2
  34. package/dist/dts/testing/enhanced-utils/create-mock-integration-context.d.ts.map +1 -1
  35. package/dist/dts/testing/index.d.ts +0 -3
  36. package/dist/dts/testing/index.d.ts.map +1 -1
  37. package/dist/dts/tsdoc-metadata.json +1 -1
  38. package/dist/dts/types.d.ts +89 -84
  39. package/dist/dts/types.d.ts.map +1 -1
  40. package/dist/es/lib/errors/integration-error.js +7 -4
  41. package/dist/es/lib/index.docs.js +1 -1
  42. package/dist/es/lib/index.js +1 -5
  43. package/dist/es/lib/logging/logger.js +18 -7
  44. package/dist/es/lib/requests/polarity-request.js +103 -126
  45. package/dist/es/lib/testing/enhanced-utils/create-entity.js +31 -5
  46. package/dist/es/lib/testing/enhanced-utils/create-mock-integration-context.js +54 -27
  47. package/dist/es/lib/testing/index.js +0 -3
  48. package/dist/es/lib/types.js +2 -1
  49. package/dist/lib/errors/integration-error.js +7 -4
  50. package/dist/lib/index.docs.js +1 -1
  51. package/dist/lib/index.js +1 -5
  52. package/dist/lib/logging/logger.js +18 -7
  53. package/dist/lib/requests/polarity-request.js +103 -126
  54. package/dist/lib/testing/enhanced-utils/create-entity.js +31 -5
  55. package/dist/lib/testing/enhanced-utils/create-mock-integration-context.js +54 -27
  56. package/dist/lib/testing/index.js +0 -3
  57. package/dist/lib/types.js +2 -1
  58. package/dist/polarity-integration-utils.d.ts +264 -594
  59. package/package.json +8 -11
  60. package/dist/dts/context/cache.d.ts +0 -149
  61. package/dist/dts/context/cache.d.ts.map +0 -1
  62. package/dist/dts/context/index.d.ts +0 -3
  63. package/dist/dts/context/index.d.ts.map +0 -1
  64. package/dist/dts/context/integration-context.d.ts +0 -16
  65. package/dist/dts/context/integration-context.d.ts.map +0 -1
  66. package/dist/dts/lib/context/cache.d.ts +0 -149
  67. package/dist/dts/lib/context/cache.d.ts.map +0 -1
  68. package/dist/dts/lib/context/index.d.ts +0 -3
  69. package/dist/dts/lib/context/index.d.ts.map +0 -1
  70. package/dist/dts/lib/context/integration-context.d.ts +0 -16
  71. package/dist/dts/lib/context/integration-context.d.ts.map +0 -1
  72. package/dist/dts/lib/testing/enhanced-utils/mock-request.d.ts +0 -14
  73. package/dist/dts/lib/testing/enhanced-utils/mock-request.d.ts.map +0 -1
  74. package/dist/dts/lib/testing/enhanced-utils/validate-integration.d.ts +0 -8
  75. package/dist/dts/lib/testing/enhanced-utils/validate-integration.d.ts.map +0 -1
  76. package/dist/dts/lib/testing/test-factory/create-integration-tests.d.ts +0 -6
  77. package/dist/dts/lib/testing/test-factory/create-integration-tests.d.ts.map +0 -1
  78. package/dist/dts/lib/testing/test-factory/test-do-lookup.d.ts +0 -7
  79. package/dist/dts/lib/testing/test-factory/test-do-lookup.d.ts.map +0 -1
  80. package/dist/dts/lib/testing/test-factory/test-on-message.d.ts +0 -8
  81. package/dist/dts/lib/testing/test-factory/test-on-message.d.ts.map +0 -1
  82. package/dist/dts/lib/zod-types.d.ts +0 -278
  83. package/dist/dts/lib/zod-types.d.ts.map +0 -1
  84. package/dist/dts/testing/enhanced-utils/mock-request.d.ts +0 -14
  85. package/dist/dts/testing/enhanced-utils/mock-request.d.ts.map +0 -1
  86. package/dist/dts/testing/enhanced-utils/validate-integration.d.ts +0 -8
  87. package/dist/dts/testing/enhanced-utils/validate-integration.d.ts.map +0 -1
  88. package/dist/dts/testing/test-factory/create-integration-tests.d.ts +0 -6
  89. package/dist/dts/testing/test-factory/create-integration-tests.d.ts.map +0 -1
  90. package/dist/dts/testing/test-factory/test-do-lookup.d.ts +0 -7
  91. package/dist/dts/testing/test-factory/test-do-lookup.d.ts.map +0 -1
  92. package/dist/dts/testing/test-factory/test-on-message.d.ts +0 -8
  93. package/dist/dts/testing/test-factory/test-on-message.d.ts.map +0 -1
  94. package/dist/dts/zod-types.d.ts +0 -278
  95. package/dist/dts/zod-types.d.ts.map +0 -1
  96. package/dist/es/lib/context/cache.js +0 -2
  97. package/dist/es/lib/context/index.js +0 -18
  98. package/dist/es/lib/context/integration-context.js +0 -2
  99. package/dist/es/lib/testing/enhanced-utils/mock-request.js +0 -22
  100. package/dist/es/lib/testing/enhanced-utils/validate-integration.js +0 -159
  101. package/dist/es/lib/testing/test-factory/create-integration-tests.js +0 -53
  102. package/dist/es/lib/testing/test-factory/test-do-lookup.js +0 -24
  103. package/dist/es/lib/testing/test-factory/test-on-message.js +0 -24
  104. package/dist/es/lib/zod-types.js +0 -206
  105. package/dist/lib/context/cache.js +0 -2
  106. package/dist/lib/context/index.js +0 -18
  107. package/dist/lib/context/integration-context.js +0 -2
  108. package/dist/lib/testing/enhanced-utils/mock-request.js +0 -22
  109. package/dist/lib/testing/enhanced-utils/validate-integration.js +0 -159
  110. package/dist/lib/testing/test-factory/create-integration-tests.js +0 -53
  111. package/dist/lib/testing/test-factory/test-do-lookup.js +0 -24
  112. package/dist/lib/testing/test-factory/test-on-message.js +0 -24
  113. 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: false,
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: 'onDemand',
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 createMockIntegrationContext = () => {
5
- const cache = {
6
- global: {
7
- get: jest.fn(),
8
- set: jest.fn(),
9
- delete: jest.fn()
10
- },
11
- integration: {
12
- get: jest.fn(),
13
- set: jest.fn(),
14
- delete: jest.fn()
15
- },
16
- user: {
17
- get: jest.fn(),
18
- set: jest.fn(),
19
- delete: jest.fn()
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: 'test-user',
26
- logger: {
27
- info: jest.fn(),
28
- debug: jest.fn(),
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);
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IntegrationError = void 0;
4
- const errors_1 = require("./errors");
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 (properties.cause && properties.cause instanceof Error) {
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 = (0, parse_error_to_readable_json_1.parseErrorToReadableJson)(this.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;
@@ -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("./context"), exports);
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.types = exports.context = exports.logging = exports.requests = exports.errors = void 0;
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 loggingLevels = ['info', 'debug', 'trace', 'warn', 'error', 'fatal'];
9
- const writeToDevRunnerResults = (loggingLevel) => (...content) => fs_1.default.appendFileSync('devRunnerResults.json', '\n' + JSON.stringify({ SOURCE: `Logger.${loggingLevel}`, content }, null, 2));
10
- const defaultLogger = loggingLevels.reduce((agg, level) => ({
11
- ...agg,
12
- [level]: writeToDevRunnerResults(level)
13
- }), {});
14
- let _logger = defaultLogger;
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
- * Optional middleware method for modifying {@link HttpRequestOptions} before a request is made
79
- * via the {@link PolarityRequest.run} method or {@link PolarityRequest.runInParallel} method.
80
- * The returned `requestOptions` object will be used for the request. This method is passed
81
- * a copy of the original `requestOptions` object so it can be modified without side effects.
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
- preprocessRequestOptions = async (requestOptions,
96
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
97
- userOptions) => requestOptions;
79
+ limiter = null;
98
80
  /**
99
- * Optional middleware method for modifying the {@link HttpRequestResponse} after a successful request.
100
- * The passed in {@link HttpRequestResponse} object is not a copy but can be safely modified without
101
- * side effects. The returned `HttpRequestResponse` object will be used for the response.
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
- * @param response - The HTTP response from the request.
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
- postprocessRequestSuccess = async (response,
108
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
109
- requestOptions,
110
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
111
- userOptions) => response;
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.postprocessRequestFailure) {
181
- this.postprocessRequestFailure = options.postprocessRequestFailure;
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.postprocessRequestSuccess) {
184
- this.postprocessRequestSuccess = options.postprocessRequestSuccess;
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
- // Note that we specifically pass a copy of requestOptions to `preprocessRequestOptions`
215
- // which lets the user modify the requestOptions object without affecting the original
216
- const postprocessedRequestOptions = await this.preprocessRequestOptions({
217
- ...requestOptions
218
- }, this.userOptions);
219
- let postprocessRequestResults;
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
- this.maybeThrowApiRequestError(httpResponse, postprocessedRequestOptions);
231
- postprocessRequestResults = await this.postprocessRequestSuccess(httpResponse, postprocessedRequestOptions, this.userOptions);
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
- if (!(requestError instanceof errors_1.ApiRequestError)) {
239
- transformedError = new errors_1.NetworkError('Network error encountered during request', {
240
- cause: requestError,
241
- requestOptions: postprocessedRequestOptions,
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
- if (requestError instanceof bottleneck_1.default.BottleneckError) {
246
- transformedError = new errors_1.RetryRequestError('This request has been dropped for going over Integration Configured API Throttling Limits', {
247
- requestOptions: postprocessedRequestOptions,
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
- // Possibly throws an error
252
- await this.postprocessRequestFailure(transformedError, postprocessedRequestOptions, this.userOptions);
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
- return postprocessRequestResults;
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 throws an ApiRequestError if it is.
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 ApiRequestError}
263
- * Throws an error if the response indicates an API error.
234
+ * @throws {@link LibraryUsageError}
235
+ * Throws if the `isApiError` function returns an invalid result.
264
236
  */
265
- maybeThrowApiRequestError(httpResponse, requestOptions) {
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
- throw new errors_1.ApiRequestError(message, {
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. If the `returnErrors` property is set to `true`
384
- * then the response objects will have their `error` property set to the thrown error.
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 (requestOptions.entity) {
400
- response.entity = requestOptions.entity;
401
- }
402
- else if (requestOptions.entities) {
403
- response.entities = requestOptions.entities;
404
- }
405
- else if (requestOptions.requestId) {
406
- response.requestId = requestOptions.requestId;
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: false,
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: 'onDemand',
58
+ requestType: 'OnDemand',
33
59
  isUserInitiated: true
34
60
  }
35
61
  };