@chainlink/external-adapter-framework 0.0.7 → 0.0.10

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 (127) hide show
  1. package/adapter.d.ts +88 -0
  2. package/{dist/src/adapter.js → adapter.js} +0 -0
  3. package/background-executor.d.ts +11 -0
  4. package/{dist/background-executor.js → background-executor.js} +0 -0
  5. package/cache/factory.d.ts +6 -0
  6. package/{dist/cache → cache}/factory.js +0 -0
  7. package/cache/index.d.ts +90 -0
  8. package/{dist/src/cache → cache}/index.js +6 -2
  9. package/cache/local.d.ts +23 -0
  10. package/{dist/cache → cache}/local.js +1 -1
  11. package/cache/metrics.d.ts +27 -0
  12. package/{dist/cache → cache}/metrics.js +7 -1
  13. package/cache/redis.d.ts +16 -0
  14. package/{dist/cache → cache}/redis.js +2 -2
  15. package/config/index.d.ts +195 -0
  16. package/{dist/src/config → config}/index.js +5 -6
  17. package/config/provider-limits.d.ts +31 -0
  18. package/{dist/src/config → config}/provider-limits.js +1 -1
  19. package/examples/coingecko/batch-warming.d.ts +2 -0
  20. package/{dist/examples → examples}/coingecko/batch-warming.js +0 -0
  21. package/examples/coingecko/index.d.ts +2 -0
  22. package/{dist/examples → examples}/coingecko/index.js +0 -0
  23. package/examples/coingecko/rest.d.ts +2 -0
  24. package/{dist/examples → examples}/coingecko/rest.js +0 -0
  25. package/examples/ncfx/config/index.d.ts +12 -0
  26. package/{dist/examples → examples}/ncfx/config/index.js +0 -0
  27. package/examples/ncfx/index.d.ts +2 -0
  28. package/{dist/examples → examples}/ncfx/index.js +0 -0
  29. package/examples/ncfx/websocket.d.ts +36 -0
  30. package/{dist/examples → examples}/ncfx/websocket.js +0 -0
  31. package/index.d.ts +12 -0
  32. package/{dist/index.js → index.js} +3 -0
  33. package/metrics/constants.d.ts +16 -0
  34. package/{dist/src/metrics → metrics}/constants.js +1 -1
  35. package/metrics/index.d.ts +15 -0
  36. package/{dist/metrics → metrics}/index.js +48 -1
  37. package/metrics/util.d.ts +3 -0
  38. package/{dist/metrics → metrics}/util.js +0 -0
  39. package/package.json +2 -6
  40. package/rate-limiting/background/fixed-frequency.d.ts +10 -0
  41. package/{dist/src/rate-limiting → rate-limiting}/background/fixed-frequency.js +0 -0
  42. package/rate-limiting/index.d.ts +54 -0
  43. package/{dist/src/rate-limiting → rate-limiting}/index.js +0 -0
  44. package/rate-limiting/metrics.d.ts +3 -0
  45. package/{dist/src/rate-limiting → rate-limiting}/metrics.js +14 -2
  46. package/rate-limiting/request/simple-counting.d.ts +20 -0
  47. package/{dist/src/rate-limiting → rate-limiting}/request/simple-counting.js +0 -0
  48. package/test.d.ts +1 -0
  49. package/{dist/test.js → test.js} +0 -0
  50. package/transports/batch-warming.d.ts +34 -0
  51. package/{dist/src/transports → transports}/batch-warming.js +47 -1
  52. package/transports/index.d.ts +87 -0
  53. package/{dist/src/transports → transports}/index.js +5 -3
  54. package/transports/metrics.d.ts +21 -0
  55. package/{dist/src/transports → transports}/metrics.js +28 -42
  56. package/transports/rest.d.ts +43 -0
  57. package/{dist/src/transports → transports}/rest.js +38 -2
  58. package/transports/util.d.ts +8 -0
  59. package/{dist/src/transports → transports}/util.js +16 -16
  60. package/transports/websocket.d.ts +80 -0
  61. package/{dist/src/transports → transports}/websocket.js +8 -14
  62. package/util/expiring-sorted-set.d.ts +21 -0
  63. package/{dist/src/util → util}/expiring-sorted-set.js +0 -0
  64. package/util/index.d.ts +11 -0
  65. package/{dist/src/util → util}/index.js +0 -0
  66. package/util/logger.d.ts +42 -0
  67. package/{dist/src/util → util}/logger.js +0 -0
  68. package/util/request.d.ts +55 -0
  69. package/{dist/src/util → util}/request.js +0 -0
  70. package/validation/error.d.ts +50 -0
  71. package/validation/error.js +79 -0
  72. package/validation/index.d.ts +5 -0
  73. package/{dist/src/validation → validation}/index.js +8 -6
  74. package/validation/input-params.d.ts +15 -0
  75. package/{dist/src/validation → validation}/input-params.js +0 -0
  76. package/validation/override-functions.d.ts +3 -0
  77. package/{dist/src/validation → validation}/override-functions.js +0 -0
  78. package/{dist/src/validation → validation}/preset-tokens.json +0 -0
  79. package/validation/validator.d.ts +47 -0
  80. package/{dist/src/validation → validation}/validator.js +0 -0
  81. package/README.md +0 -103
  82. package/dist/adapter.js +0 -60
  83. package/dist/cache/index.js +0 -163
  84. package/dist/config/index.js +0 -364
  85. package/dist/config/provider-limits.js +0 -75
  86. package/dist/metrics/constants.js +0 -25
  87. package/dist/rate-limiting/factory.js +0 -33
  88. package/dist/rate-limiting/index.js +0 -36
  89. package/dist/rate-limiting/metrics.js +0 -32
  90. package/dist/rate-limiting/nop-limiter.js +0 -15
  91. package/dist/rate-limiting/simple-counting.js +0 -61
  92. package/dist/src/background-executor.js +0 -45
  93. package/dist/src/cache/factory.js +0 -57
  94. package/dist/src/cache/local.js +0 -83
  95. package/dist/src/cache/metrics.js +0 -114
  96. package/dist/src/cache/redis.js +0 -100
  97. package/dist/src/examples/bank-frick/accounts.js +0 -191
  98. package/dist/src/examples/bank-frick/config/index.js +0 -45
  99. package/dist/src/examples/bank-frick/index.js +0 -14
  100. package/dist/src/examples/bank-frick/util.js +0 -39
  101. package/dist/src/examples/coingecko/batch-warming.js +0 -52
  102. package/dist/src/examples/coingecko/index.js +0 -10
  103. package/dist/src/examples/coingecko/rest.js +0 -50
  104. package/dist/src/examples/ncfx/config/index.js +0 -15
  105. package/dist/src/examples/ncfx/index.js +0 -10
  106. package/dist/src/examples/ncfx/websocket.js +0 -72
  107. package/dist/src/index.js +0 -89
  108. package/dist/src/metrics/index.js +0 -76
  109. package/dist/src/metrics/util.js +0 -9
  110. package/dist/src/test.js +0 -6
  111. package/dist/src/validation/error.js +0 -41
  112. package/dist/transports/batch-warming.js +0 -57
  113. package/dist/transports/index.js +0 -76
  114. package/dist/transports/metrics.js +0 -133
  115. package/dist/transports/rest.js +0 -91
  116. package/dist/transports/util.js +0 -85
  117. package/dist/transports/websocket.js +0 -171
  118. package/dist/util/expiring-sorted-set.js +0 -47
  119. package/dist/util/index.js +0 -35
  120. package/dist/util/logger.js +0 -62
  121. package/dist/util/request.js +0 -2
  122. package/dist/validation/error.js +0 -41
  123. package/dist/validation/index.js +0 -82
  124. package/dist/validation/input-params.js +0 -30
  125. package/dist/validation/overrideFunctions.js +0 -42
  126. package/dist/validation/presetTokens.json +0 -23
  127. package/dist/validation/validator.js +0 -303
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AdapterCustomError = exports.AdapterConnectionError = exports.AdapterDataProviderError = exports.AdapterTimeoutError = exports.AdapterRateLimitError = exports.AdapterInputError = exports.AdapterError = void 0;
4
+ const constants_1 = require("../metrics/constants");
5
+ class AdapterError extends Error {
6
+ constructor({ jobRunID = '1', status = 'errored', statusCode = 500, name = 'AdapterError', message = 'An error occurred.', cause, url, errorResponse, feedID, providerStatusCode, metricsLabel = constants_1.HttpRequestType.ADAPTER_ERROR }) {
7
+ super(message);
8
+ this.jobRunID = jobRunID;
9
+ this.status = status;
10
+ this.statusCode = statusCode;
11
+ this.name = name;
12
+ this.message = message;
13
+ this.cause = cause;
14
+ if (url) {
15
+ this.url = url;
16
+ }
17
+ if (feedID) {
18
+ this.feedID = feedID;
19
+ }
20
+ this.errorResponse = errorResponse;
21
+ this.providerStatusCode = providerStatusCode;
22
+ this.metricsLabel = metricsLabel;
23
+ }
24
+ toJSONResponse() {
25
+ const showDebugInfo = process.env['NODE_ENV'] === 'development' || process.env['DEBUG'] === 'true';
26
+ const errorBasic = {
27
+ name: this.name,
28
+ message: this.message,
29
+ url: this.url,
30
+ errorResponse: this.errorResponse,
31
+ feedID: this.feedID,
32
+ };
33
+ const errorFull = { ...errorBasic, stack: this.stack, cause: this.cause };
34
+ return {
35
+ jobRunID: this.jobRunID,
36
+ status: this.status,
37
+ statusCode: this.statusCode,
38
+ providerStatusCode: this.providerStatusCode,
39
+ error: showDebugInfo ? errorFull : errorBasic,
40
+ };
41
+ }
42
+ }
43
+ exports.AdapterError = AdapterError;
44
+ class AdapterInputError extends AdapterError {
45
+ constructor(input) {
46
+ super({ ...input, metricsLabel: constants_1.HttpRequestType.INPUT_ERROR });
47
+ }
48
+ }
49
+ exports.AdapterInputError = AdapterInputError;
50
+ class AdapterRateLimitError extends AdapterError {
51
+ constructor(input) {
52
+ super({ ...input, metricsLabel: constants_1.HttpRequestType.RATE_LIMIT_ERROR });
53
+ }
54
+ }
55
+ exports.AdapterRateLimitError = AdapterRateLimitError;
56
+ class AdapterTimeoutError extends AdapterError {
57
+ constructor(input) {
58
+ super({ ...input, metricsLabel: constants_1.HttpRequestType.TIMEOUT_ERROR });
59
+ }
60
+ }
61
+ exports.AdapterTimeoutError = AdapterTimeoutError;
62
+ class AdapterDataProviderError extends AdapterError {
63
+ constructor(input) {
64
+ super({ ...input, metricsLabel: constants_1.HttpRequestType.DP_ERROR });
65
+ }
66
+ }
67
+ exports.AdapterDataProviderError = AdapterDataProviderError;
68
+ class AdapterConnectionError extends AdapterError {
69
+ constructor(input) {
70
+ super({ ...input, metricsLabel: constants_1.HttpRequestType.CONNECTION_ERROR });
71
+ }
72
+ }
73
+ exports.AdapterConnectionError = AdapterConnectionError;
74
+ class AdapterCustomError extends AdapterError {
75
+ constructor(input) {
76
+ super({ ...input, metricsLabel: constants_1.HttpRequestType.CUSTOM_ERROR });
77
+ }
78
+ }
79
+ exports.AdapterCustomError = AdapterCustomError;
@@ -0,0 +1,5 @@
1
+ import { FastifyReply, FastifyRequest } from 'fastify';
2
+ import { AdapterMiddlewareBuilder } from '../util/request';
3
+ export { InputParameters } from './input-params';
4
+ export declare const validatorMiddleware: AdapterMiddlewareBuilder;
5
+ export declare const errorCatchingMiddleware: (err: Error, req: FastifyRequest, res: FastifyReply) => void;
@@ -10,13 +10,13 @@ const override_functions_1 = require("./override-functions");
10
10
  const errorCatcherLogger = (0, util_2.makeLogger)('ErrorCatchingMiddleware');
11
11
  const validatorMiddleware = (adapter) => (req, reply, done) => {
12
12
  if (req.headers['content-type'] !== 'application/json') {
13
- throw new error_1.AdapterError({
13
+ throw new error_1.AdapterInputError({
14
14
  message: 'Content type not "application/json", returning 400',
15
15
  statusCode: 400,
16
16
  });
17
17
  }
18
18
  if (!req.body) {
19
- throw new error_1.AdapterError({
19
+ throw new error_1.AdapterInputError({
20
20
  message: 'Body not present in adapter request, returning 400',
21
21
  statusCode: 400,
22
22
  });
@@ -24,14 +24,14 @@ const validatorMiddleware = (adapter) => (req, reply, done) => {
24
24
  // Make endpoints case insensitive
25
25
  const endpointParam = req.body.endpoint?.toLowerCase() || adapter.defaultEndpoint;
26
26
  if (!endpointParam) {
27
- throw new error_1.AdapterError({
27
+ throw new error_1.AdapterInputError({
28
28
  message: `Request body does not specify an endpoint, and there is no default endpoint configured for this adapter.`,
29
29
  statusCode: 400,
30
30
  });
31
31
  }
32
32
  const endpoint = adapter.endpointsMap[endpointParam];
33
33
  if (!endpoint) {
34
- throw new error_1.AdapterError({
34
+ throw new error_1.AdapterInputError({
35
35
  message: `Adapter does not have a "${req.body.endpoint}" endpoint.`,
36
36
  statusCode: 404,
37
37
  });
@@ -48,8 +48,8 @@ const validatorMiddleware = (adapter) => (req, reply, done) => {
48
48
  if (adapter.config.METRICS_ENABLED && adapter.config.EXPERIMENTAL_METRICS_ENABLED) {
49
49
  // Add metrics meta which includes feedId to the request
50
50
  // Perform prior to overrides to maintain consistent Feed IDs across adapters
51
- const metricsMeta = (0, util_1.getMetricsMeta)(endpoint, validator.validated.data);
52
- req.requestContext = { ...req.requestContext, metricsMeta };
51
+ const metrics = (0, util_1.getMetricsMeta)(endpoint, validator.validated.data);
52
+ req.requestContext = { ...req.requestContext, meta: { metrics } };
53
53
  }
54
54
  // TODO: Support `includes` and `tokenOverrides` overrides as needed
55
55
  const requestParams = req.requestContext.data ?? {};
@@ -70,6 +70,8 @@ const validatorMiddleware = (adapter) => (req, reply, done) => {
70
70
  };
71
71
  exports.validatorMiddleware = validatorMiddleware;
72
72
  const errorCatchingMiddleware = (err, req, res) => {
73
+ // Add adapter or generic error to request meta for metrics use
74
+ req.requestContext.meta = { ...req.requestContext.meta, error: err };
73
75
  if (err instanceof error_1.AdapterError) {
74
76
  // We want to log these as warn, because although they are to be expected, NOPs should
75
77
  // Only use "correct" job specs and therefore not hit adapters with invalid requests.
@@ -0,0 +1,15 @@
1
+ export declare type Override = Map<string, Map<string, string>>;
2
+ export declare type InputParameter = {
3
+ aliases?: string[];
4
+ description?: string;
5
+ type?: 'bigint' | 'boolean' | 'array' | 'number' | 'object' | 'string';
6
+ required?: boolean;
7
+ options?: unknown[];
8
+ default?: unknown;
9
+ dependsOn?: string[];
10
+ exclusive?: string[];
11
+ };
12
+ export declare type InputParameters = {
13
+ [name: string]: InputParameter | boolean | string[];
14
+ };
15
+ export declare const baseInputParameters: InputParameters;
@@ -0,0 +1,3 @@
1
+ import { InitializedAdapter } from '../adapter';
2
+ import { AdapterRequest } from '../util/request';
3
+ export declare const performSymbolOverrides: (adapter: InitializedAdapter, req: AdapterRequest) => void;
@@ -0,0 +1,47 @@
1
+ import { AdapterError, AdapterErrorResponse } from './error';
2
+ import { InputParameters, Override } from './input-params';
3
+ export declare type OverrideType = 'overrides' | 'tokenOverrides' | 'includes';
4
+ declare type InputType = {
5
+ id?: string;
6
+ data?: any;
7
+ };
8
+ export interface ValidatorOptions {
9
+ shouldThrowError?: boolean;
10
+ includes?: any[];
11
+ overrides?: any;
12
+ }
13
+ export declare type IncludePair = {
14
+ from: string;
15
+ to: string;
16
+ adapters?: string[];
17
+ inverse?: boolean;
18
+ tokens?: boolean;
19
+ };
20
+ export declare type Includes = {
21
+ from: string;
22
+ to: string;
23
+ includes: IncludePair[];
24
+ };
25
+ export declare class Validator {
26
+ input: InputType;
27
+ inputConfigs: InputParameters;
28
+ inputOptions: Record<string, any[]>;
29
+ validatorOptions: ValidatorOptions;
30
+ validated: any;
31
+ error: AdapterError | undefined;
32
+ errored: AdapterErrorResponse | undefined;
33
+ constructor(input?: InputType, inputConfigs?: {}, inputOptions?: {}, validatorOptions?: ValidatorOptions);
34
+ validateInput(): void;
35
+ validateOverrides(path: 'overrides' | 'tokenOverrides', preset: Record<string, any>): void;
36
+ checkDuplicateInputParams(inputConfig: InputParameters): void;
37
+ validateIncludeOverrides(): void;
38
+ parseError(error: unknown): void;
39
+ formatOverride: (param: any) => Override;
40
+ formatIncludeOverrides: (param: any) => Override;
41
+ throwInvalid: (message: string) => void;
42
+ validateObjectParam(key: string, shouldThrowError?: boolean): void;
43
+ validateOptionalParam(param: any, key: string, options: any[]): void;
44
+ validateRequiredParam(param: any, key: string, options: any[]): void;
45
+ getUsedKey(key: string, keyArray: string[]): string | undefined;
46
+ }
47
+ export {};
File without changes
package/README.md DELETED
@@ -1,103 +0,0 @@
1
- # EA Framework v3
2
-
3
- External adapters and its core framework serve as middleware to facilitate connections between Chainlink Nodes and Data Providers (DP). Their main purpose is threefold:
4
-
5
- - Abstract provider specific details, specifically:
6
- - Transport (REST, WebSockets, RPC, SSE, etc.)
7
- - Authentication (login flows, keys)
8
- - Accept normalized request payloads and translate into the provider's interface (this also includes things like symbols/tickers)
9
- - Parse provider responses into the desired data points (e.g. price from crypto endpoint)
10
- - Make the overall system more efficient by using as few resources (e.g. API credits, networking traffic, CPU usage) as possible to fetch data, achieved by features like:
11
- - Caching: since DPs update data at various times and a request to their API incurs a certain latency, EAs keep a cache of values to
12
- - Provide responses to the Chainlink Nodes as quickly as possible
13
- - Communicate with DPs only when necessary
14
- - Cache Warming: in order to make as many of the requests to EAs be fulfilled from the cache, EAs fetch values from DPs asynchronously to keep the local ones fresh.
15
- - Batching: the CL Node requests feeds individually, but it's common for DPs to provide batch endpoints to get many data points at once. With Batching, EAs keep track of incoming requests and consolidate them into one batched request.
16
- - Rate limiting: the EA framework additionally checks request rates (frequency) to make sure they fall within acceptable limits (like quotas for the DP's API, or adjusting based on the NOP's API tier).
17
- - Perform off chain computations (think aggregations, indexing, or any sort of data processing)
18
-
19
- By providing a framework that gives users easy access to those features, we reduce the complexity required for Nodes to communicate with DPs since by using EAs there is only one standardized way to do so, while at the same time optimizing said communication so it's as resource efficient as possible. It also makes internal and external development easier and faster, by serving as a strict guideline to implement and add new providers.
20
-
21
- ## Qs
22
-
23
- - Store entire response in cache?
24
- - Check for valid result in adapter response?
25
-
26
- ## Env vars
27
-
28
- These are all existing env vars, marked DONE if they have been ported to this version, or N/A if the new version disregards them altogether.
29
-
30
- | Name | State | Comments |
31
- | :----------------------------------------- | :---: | :----------------------------------------------------------- |
32
- | API_TIMEOUT | N/A | Only used for WS with handler.noHTtp = true |
33
- | BASE_URL | √ | |
34
- | CACHE_ENABLED | N/A | Cache is integral to this fw, not including this for now |
35
- | CACHE_KEY_IGNORED_PROPS | ?? | Do we want this to be available in v3. Used for feed id |
36
- | CACHE_KEY_GROUP | ?? | Dunno if this applies to this fw |
37
- | CACHE_MAX_AGE | √ | |
38
- | CACHE_MAX_ITEMS | - | Should add when replacing obj in local impl with LRU package |
39
- | CACHE_MIN_AGE | - | Used for rate limiting |
40
- | CACHE_REDIS_CONNECTION_TIMEOUT | - | TODO: Redis |
41
- | CACHE_REDIS_HOST | - | TODO: Redis |
42
- | CACHE_REDIS_MAX_QUEUED_ITEMS | - | TODO: Redis |
43
- | CACHE_REDIS_MAX_RECONNECT_COOLDOWN | - | TODO: Redis |
44
- | CACHE_REDIS_PASSWORD | - | TODO: Redis |
45
- | CACHE_REDIS_PATH | - | TODO: Redis |
46
- | CACHE_REDIS_PORT | - | TODO: Redis |
47
- | CACHE_REDIS_TIMEOUT | - | TODO: Redis |
48
- | CACHE_REDIS_URL | - | TODO: Redis |
49
- | CACHE_TYPE | - | TODO: Cache factory |
50
- | CACHE_UPDATE_AGE_ON_GET | N/A | No longer used in EA currently, apparently |
51
- | DEBUG | | |
52
- | DEFAULT_WS_HEARTBEAT_INTERVAL | | |
53
- | EA_HOST | | |
54
- | EA_PORT | √ | |
55
- | ENV_ADAPTER_URL | | |
56
- | ENV_API_ENDPOINT | | |
57
- | ENV_API_KEY | | |
58
- | ENV_API_TIMEOUT | | |
59
- | ENV_API_VERBOSE | | |
60
- | ENV_WS_API_ENDPOINT | | |
61
- | ENV_WS_API_KEY | | |
62
- | ERROR_CAPACITY | | |
63
- | EXPERIMENTAL_METRICS_ENABLED | √ | Maintaining for backwards compatibility. Defaults to true |
64
- | LEGACY_ENV_ADAPTER_URL | | |
65
- | LOG_LEVEL | | |
66
- | METRICS_ENABLED | √ | Defaults to true |
67
- | METRICS_NAME | √ | |
68
- | METRICS_PORT | √ | |
69
- | METRICS_USE_BASE_URL | √ | |
70
- | NODE_ENV | | |
71
- | npm_package_version | | |
72
- | RATE_LIMIT_API_TIER | | |
73
- | RATE_LIMIT_CAPACITY | | |
74
- | RATE_LIMIT_CAPACITY_MINUTE | | |
75
- | RATE_LIMIT_CAPACITY_SECOND | | |
76
- | RATE_LIMIT_ENABLED | | |
77
- | RECORD | | |
78
- | REQUEST_COALESCING_ENABLED | | |
79
- | REQUEST_COALESCING_ENTROPY_MAX | | |
80
- | REQUEST_COALESCING_INTERVAL | | |
81
- | REQUEST_COALESCING_INTERVAL_COEFFICIENT | | |
82
- | REQUEST_COALESCING_INTERVAL_MAX | | |
83
- | REQUEST_COALESCING_MAX_RETRIES | | |
84
- | RETRY | | |
85
- | SERVER_RATE_LIMIT_MAX | | |
86
- | SERVER_SLOW_DOWN_AFTER_FACTOR | | |
87
- | SERVER_SLOW_DOWN_DELAY_MS | | |
88
- | TIMEOUT | | |
89
- | WARMUP_ENABLED | | |
90
- | WARMUP_INTERVAL | | |
91
- | WARMUP_SUBSCRIPTION_TTL | | |
92
- | WARMUP_UNHEALTHY_THRESHOLD | | |
93
- | WS_CONNECTION_KEY | | |
94
- | WS_CONNECTION_LIMIT | | |
95
- | WS_CONNECTION_RETRY_DELAY | | |
96
- | WS_CONNECTION_RETRY_LIMIT | | |
97
- | WS_CONNECTION_TTL | | |
98
- | WS_ENABLED | N/A | Shouldn't be part of this fw |
99
- | WS_SUBSCRIPTION_LIMIT | | |
100
- | WS_SUBSCRIPTION_PRIORITY_LIST | | |
101
- | WS_SUBSCRIPTION_TTL | | |
102
- | WS_SUBSCRIPTION_UNRESPONSIVE_TTL | | |
103
- | WS_TIME_UNTIL_HANDLE_NEXT_MESSAGE_OVERRIDE | | |
package/dist/adapter.js DELETED
@@ -1,60 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.initializeAdapter = exports.initializeDependencies = void 0;
4
- const factory_1 = require("./cache/factory");
5
- const rate_limiting_1 = require("./rate-limiting");
6
- const util_1 = require("./util");
7
- const logger = (0, util_1.makeLogger)('Adapter');
8
- /**
9
- * This function will process dependencies for an adapter, such as caches or rate limiters,
10
- * in order to inject them into transports and other relevant places later in the lifecycle.
11
- *
12
- * @param config - the configuration for this adapter
13
- * @param inputDependencies - a partial obj of initialized dependencies to override the created ones
14
- * @param rateLimitingConfig - details from the adapter regarding rate limiting
15
- * @returns a set of AdapterDependencies all initialized
16
- */
17
- const initializeDependencies = (config, inputDependencies, rateLimitingConfig) => {
18
- const dependencies = inputDependencies || {};
19
- if (!dependencies.cache) {
20
- dependencies.cache = factory_1.CacheFactory.buildCache(config);
21
- }
22
- if (!dependencies.rateLimiter) {
23
- const rateLimiter = rate_limiting_1.RateLimiterFactory.buildRateLimiter(rateLimitingConfig?.tiers, config['RATE_LIMIT_API_TIER'], rateLimitingConfig?.strategy);
24
- dependencies.rateLimiter = rateLimiter;
25
- }
26
- return dependencies;
27
- };
28
- exports.initializeDependencies = initializeDependencies;
29
- /**
30
- * Initializes all of the [[Transport]]s in the adapter, passing along any [[AdapterDependencies]] and [[AdapterConfig]].
31
- * Additionally, it builds a map out of all the endpoint names and aliases (checking for duplicates).
32
- *
33
- * @param adapter - an instance of an Adapter
34
- * @param dependencies - dependencies that the adapter will need at initialization
35
- * @param config - configuration variables already processed and validated
36
- * @returns - the adapter with all transports initialized and aliases map built
37
- */
38
- const initializeAdapter = async (adapter, config, dependencies) => {
39
- const initializedDependencies = (0, exports.initializeDependencies)(config, dependencies, adapter.rateLimiting);
40
- const endpointsMap = {};
41
- for (const endpoint of adapter.endpoints) {
42
- // Add aliases to map to use in validation
43
- const aliases = [endpoint.name, ...(endpoint.aliases || [])];
44
- for (const alias of aliases) {
45
- if (endpointsMap[alias]) {
46
- throw new Error(`Duplicate endpoint / alias: "${alias}"`);
47
- }
48
- endpointsMap[alias] = endpoint;
49
- }
50
- logger.debug(`Initializing transport for endpoint "${endpoint.name}"...`);
51
- await endpoint.transport.initialize(initializedDependencies);
52
- }
53
- return {
54
- ...adapter,
55
- endpointsMap,
56
- dependencies: initializedDependencies,
57
- config,
58
- };
59
- };
60
- exports.initializeAdapter = initializeAdapter;
@@ -1,163 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
26
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.buildCacheMiddleware = exports.pollResponseFromCache = exports.calculateKey = exports.calculateFeedId = exports.calculateCacheKey = void 0;
30
- const util_1 = require("../util");
31
- const cacheMetrics = __importStar(require("./metrics"));
32
- __exportStar(require("./local"), exports);
33
- __exportStar(require("./redis"), exports);
34
- const logger = (0, util_1.makeLogger)('Cache');
35
- // Uses calculateKey to generate a unique key from the endpoint name, data, and input parameters
36
- const calculateCacheKey = ({ adapterEndpoint, adapterConfig, }, data) => {
37
- const paramNames = Object.keys(adapterEndpoint.inputParameters);
38
- if (paramNames.length === 0) {
39
- logger.trace(`Using default cache key ${adapterConfig.DEFAULT_CACHE_KEY}`);
40
- return adapterConfig.DEFAULT_CACHE_KEY;
41
- }
42
- return `${adapterEndpoint.name}-${(0, exports.calculateKey)(data, paramNames)}`;
43
- };
44
- exports.calculateCacheKey = calculateCacheKey;
45
- const calculateFeedId = (adapterEndpoint, data) => {
46
- const paramNames = Object.keys(adapterEndpoint.inputParameters);
47
- if (paramNames.length === 0) {
48
- logger.trace(`Cannot generate Feed ID without input parameters`);
49
- return 'N/A';
50
- }
51
- return (0, exports.calculateKey)(data, paramNames);
52
- };
53
- exports.calculateFeedId = calculateFeedId;
54
- /**
55
- * Calculates a unique key from the provided data.
56
- *
57
- * @param data - the request data/body, i.e. the adapter input params
58
- * @param paramNames - the keys from adapter endpoint input parameters
59
- * @returns the calculated unique key
60
- *
61
- * @example
62
- * ```
63
- * calculateKey({ base: 'ETH', quote: 'BTC' }, ['base','quote'])
64
- * // equals `|base:eth|quote:btc`
65
- * ```
66
- */
67
- const calculateKey = (data, paramNames) => {
68
- if (data && typeof data !== 'object') {
69
- throw new Error('Data to calculate cache key should be an object');
70
- }
71
- const params = data;
72
- let cacheKey = ''; // TODO: Maybe there's a faster String Builder
73
- for (const paramName of paramNames) {
74
- // Ignore overrides param when generating cache keys
75
- // TODO: expand support for ignoring `includes` and `tokenOverrides` params when generating keys
76
- if (paramName === 'overrides') {
77
- continue;
78
- }
79
- const param = params[paramName];
80
- if (param === undefined) {
81
- continue;
82
- }
83
- cacheKey += `|${paramName}:`;
84
- switch (typeof param) {
85
- case 'string':
86
- cacheKey += param.toLowerCase();
87
- break;
88
- case 'number':
89
- case 'boolean':
90
- cacheKey += param.toString();
91
- break;
92
- case 'object':
93
- // TODO: Implement object sorting for deterministic cache key generation
94
- cacheKey += JSON.stringify(param);
95
- }
96
- }
97
- // TODO: Check max size, potential issue
98
- logger.trace(`Generated cache key for request: "${cacheKey}"`);
99
- return cacheKey;
100
- };
101
- exports.calculateKey = calculateKey;
102
- // Calculate the amount of time the non-expired entry has been in the cache
103
- const calculateStaleness = (expirationTimestamp, ttl) => {
104
- if (expirationTimestamp) {
105
- const createTimestamp = expirationTimestamp - ttl;
106
- return (Date.now() - createTimestamp) / 1000;
107
- }
108
- else {
109
- // If expirationTimestamp is not available, staleness cannot be calculated
110
- // Defaults to ttl for metrics purposes
111
- return ttl;
112
- }
113
- };
114
- /**
115
- * Polls the provided Cache for an AdapterResponse set in the provided key. If the maximum
116
- * amount of retries is exceeded, it returns undefined instead.
117
- *
118
- * @param cache - a Cache instance
119
- * @param key - the key generated from an AdapterRequest that corresponds to the desired AdapterResponse
120
- * @param retry - current retry, only for internal use
121
- * @returns the AdapterResponse if found, else undefined
122
- */
123
- const pollResponseFromCache = async (cache, key, options, retry = 0) => {
124
- if (retry > options.maxRetries) {
125
- // Ideally this shouldn't happen often (p99 of reqs should be found in the cache)
126
- logger.info('Exceeded max cache polling retries');
127
- return undefined;
128
- }
129
- logger.trace('Getting response from cache...');
130
- const response = await cache.get(key);
131
- if (response) {
132
- logger.trace('Got response from cache');
133
- return response;
134
- }
135
- if (options.maxRetries === 0) {
136
- logger.debug(`Response not found, retries disabled`);
137
- return undefined;
138
- }
139
- logger.debug(`Response not found, sleeping ${options.sleep} milliseconds...`);
140
- await (0, util_1.sleep)(options.sleep);
141
- return (0, exports.pollResponseFromCache)(cache, key, options, retry + 1);
142
- };
143
- exports.pollResponseFromCache = pollResponseFromCache;
144
- /**
145
- * Given a Cache instance in the adapter dependencies, builds a middleware function that will perform
146
- * a get from said Cache and return that if found; otherwise it'll continue the middleware chain.
147
- *
148
- * @param adapter - an initialized adapter
149
- * @returns the cache middleware function
150
- */
151
- const buildCacheMiddleware = (adapter) => async (req, res) => {
152
- const response = await adapter.dependencies.cache.get(req.requestContext.cacheKey);
153
- if (response) {
154
- logger.debug('Found response from cache, sending that');
155
- const label = cacheMetrics.cacheMetricsLabel(req.requestContext.cacheKey, req.requestContext.metricsMeta?.feedId || 'N/A', adapter.config.CACHE_TYPE);
156
- // Record cache staleness and cache get count and value
157
- const staleness = calculateStaleness(response.maxAge, adapter.config.CACHE_MAX_AGE);
158
- cacheMetrics.cacheGet(label, response.result, staleness);
159
- return res.send(response);
160
- }
161
- logger.debug('Did not find response in cache, moving to next middleware');
162
- };
163
- exports.buildCacheMiddleware = buildCacheMiddleware;