@chainlink/external-adapter-framework 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/adapter.js +60 -0
  2. package/dist/background-executor.js +45 -0
  3. package/dist/cache/factory.js +57 -0
  4. package/dist/cache/index.js +163 -0
  5. package/dist/cache/local.js +83 -0
  6. package/dist/cache/metrics.js +114 -0
  7. package/dist/cache/redis.js +100 -0
  8. package/dist/config/index.js +364 -0
  9. package/dist/config/provider-limits.js +75 -0
  10. package/dist/examples/coingecko/batch-warming.js +52 -0
  11. package/dist/examples/coingecko/index.js +10 -0
  12. package/dist/examples/coingecko/rest.js +50 -0
  13. package/dist/examples/ncfx/config/index.js +15 -0
  14. package/dist/examples/ncfx/index.js +10 -0
  15. package/dist/examples/ncfx/websocket.js +72 -0
  16. package/dist/index.js +89 -0
  17. package/dist/metrics/constants.js +25 -0
  18. package/dist/metrics/index.js +76 -0
  19. package/dist/metrics/util.js +9 -0
  20. package/dist/rate-limiting/factory.js +33 -0
  21. package/dist/rate-limiting/index.js +36 -0
  22. package/dist/rate-limiting/metrics.js +32 -0
  23. package/dist/rate-limiting/nop-limiter.js +15 -0
  24. package/dist/rate-limiting/simple-counting.js +61 -0
  25. package/dist/src/adapter.js +112 -0
  26. package/dist/src/background-executor.js +45 -0
  27. package/dist/src/cache/factory.js +57 -0
  28. package/dist/src/cache/index.js +165 -0
  29. package/dist/src/cache/local.js +83 -0
  30. package/dist/src/cache/metrics.js +114 -0
  31. package/dist/src/cache/redis.js +100 -0
  32. package/dist/src/config/index.js +366 -0
  33. package/dist/src/config/provider-limits.js +75 -0
  34. package/dist/src/examples/bank-frick/accounts.js +191 -0
  35. package/dist/src/examples/bank-frick/config/index.js +45 -0
  36. package/dist/src/examples/bank-frick/index.js +14 -0
  37. package/dist/src/examples/bank-frick/util.js +39 -0
  38. package/dist/src/examples/coingecko/batch-warming.js +52 -0
  39. package/dist/src/examples/coingecko/index.js +10 -0
  40. package/dist/src/examples/coingecko/rest.js +50 -0
  41. package/dist/src/examples/ncfx/config/index.js +15 -0
  42. package/dist/src/examples/ncfx/index.js +10 -0
  43. package/dist/src/examples/ncfx/websocket.js +72 -0
  44. package/dist/src/index.js +89 -0
  45. package/dist/src/metrics/constants.js +25 -0
  46. package/dist/src/metrics/index.js +76 -0
  47. package/dist/src/metrics/util.js +9 -0
  48. package/dist/src/rate-limiting/background/fixed-frequency.js +37 -0
  49. package/dist/src/rate-limiting/index.js +63 -0
  50. package/dist/src/rate-limiting/metrics.js +32 -0
  51. package/dist/src/rate-limiting/request/simple-counting.js +62 -0
  52. package/dist/src/test.js +6 -0
  53. package/dist/src/transports/batch-warming.js +55 -0
  54. package/dist/src/transports/index.js +85 -0
  55. package/dist/src/transports/metrics.js +119 -0
  56. package/dist/src/transports/rest.js +93 -0
  57. package/dist/src/transports/util.js +85 -0
  58. package/dist/src/transports/websocket.js +175 -0
  59. package/dist/src/util/expiring-sorted-set.js +47 -0
  60. package/dist/src/util/index.js +35 -0
  61. package/dist/src/util/logger.js +62 -0
  62. package/dist/src/util/request.js +2 -0
  63. package/dist/src/validation/error.js +41 -0
  64. package/dist/src/validation/index.js +84 -0
  65. package/dist/src/validation/input-params.js +30 -0
  66. package/dist/src/validation/override-functions.js +40 -0
  67. package/dist/src/validation/preset-tokens.json +23 -0
  68. package/dist/src/validation/validator.js +303 -0
  69. package/dist/test.js +6 -0
  70. package/dist/transports/batch-warming.js +57 -0
  71. package/dist/transports/index.js +76 -0
  72. package/dist/transports/metrics.js +133 -0
  73. package/dist/transports/rest.js +91 -0
  74. package/dist/transports/util.js +85 -0
  75. package/dist/transports/websocket.js +171 -0
  76. package/dist/util/expiring-sorted-set.js +47 -0
  77. package/dist/util/index.js +35 -0
  78. package/dist/util/logger.js +62 -0
  79. package/dist/util/request.js +2 -0
  80. package/dist/validation/error.js +41 -0
  81. package/dist/validation/index.js +82 -0
  82. package/dist/validation/input-params.js +30 -0
  83. package/dist/validation/overrideFunctions.js +42 -0
  84. package/dist/validation/presetTokens.json +23 -0
  85. package/dist/validation/validator.js +303 -0
  86. package/package.json +6 -2
  87. package/.c8rc.json +0 -3
  88. package/.eslintignore +0 -9
  89. package/.eslintrc.js +0 -96
  90. package/.github/README.MD +0 -17
  91. package/.github/actions/setup/action.yaml +0 -13
  92. package/.github/workflows/main.yaml +0 -39
  93. package/.github/workflows/publish.yaml +0 -18
  94. package/.prettierignore +0 -13
  95. package/.yarnrc +0 -0
  96. package/docker-compose.yaml +0 -35
  97. package/src/adapter.ts +0 -236
  98. package/src/background-executor.ts +0 -53
  99. package/src/cache/factory.ts +0 -28
  100. package/src/cache/index.ts +0 -236
  101. package/src/cache/local.ts +0 -73
  102. package/src/cache/metrics.ts +0 -112
  103. package/src/cache/redis.ts +0 -93
  104. package/src/config/index.ts +0 -501
  105. package/src/config/provider-limits.ts +0 -130
  106. package/src/examples/coingecko/batch-warming.ts +0 -79
  107. package/src/examples/coingecko/index.ts +0 -9
  108. package/src/examples/coingecko/rest.ts +0 -77
  109. package/src/examples/ncfx/config/index.ts +0 -12
  110. package/src/examples/ncfx/index.ts +0 -9
  111. package/src/examples/ncfx/websocket.ts +0 -100
  112. package/src/index.ts +0 -106
  113. package/src/metrics/constants.ts +0 -23
  114. package/src/metrics/index.ts +0 -116
  115. package/src/metrics/util.ts +0 -11
  116. package/src/rate-limiting/background/fixed-frequency.ts +0 -47
  117. package/src/rate-limiting/index.ts +0 -100
  118. package/src/rate-limiting/metrics.ts +0 -18
  119. package/src/rate-limiting/request/simple-counting.ts +0 -76
  120. package/src/test.ts +0 -5
  121. package/src/transports/batch-warming.ts +0 -121
  122. package/src/transports/index.ts +0 -173
  123. package/src/transports/metrics.ts +0 -95
  124. package/src/transports/rest.ts +0 -161
  125. package/src/transports/util.ts +0 -63
  126. package/src/transports/websocket.ts +0 -238
  127. package/src/util/expiring-sorted-set.ts +0 -52
  128. package/src/util/index.ts +0 -20
  129. package/src/util/logger.ts +0 -69
  130. package/src/util/request.ts +0 -115
  131. package/src/validation/error.ts +0 -116
  132. package/src/validation/index.ts +0 -101
  133. package/src/validation/input-params.ts +0 -45
  134. package/src/validation/override-functions.ts +0 -44
  135. package/src/validation/preset-tokens.json +0 -23
  136. package/src/validation/validator.ts +0 -384
  137. package/test/adapter.test.ts +0 -27
  138. package/test/background-executor.test.ts +0 -109
  139. package/test/cache/cache-key.test.ts +0 -96
  140. package/test/cache/helper.ts +0 -101
  141. package/test/cache/local.test.ts +0 -54
  142. package/test/cache/redis.test.ts +0 -89
  143. package/test/correlation.test.ts +0 -114
  144. package/test/index.test.ts +0 -37
  145. package/test/metrics/feed-id.test.ts +0 -33
  146. package/test/metrics/helper.ts +0 -14
  147. package/test/metrics/labels.test.ts +0 -36
  148. package/test/metrics/metrics.test.ts +0 -267
  149. package/test/metrics/redis-metrics.test.ts +0 -113
  150. package/test/metrics/warmer-metrics.test.ts +0 -192
  151. package/test/metrics/ws-metrics.test.ts +0 -225
  152. package/test/rate-limit-config.test.ts +0 -243
  153. package/test/transports/batch.test.ts +0 -465
  154. package/test/transports/rest.test.ts +0 -242
  155. package/test/transports/websocket.test.ts +0 -183
  156. package/test/tsconfig.json +0 -5
  157. package/test/util.ts +0 -76
  158. package/test/validation.test.ts +0 -169
  159. package/test.sh +0 -20
  160. package/tsconfig.json +0 -24
  161. package/typedoc.json +0 -6
@@ -1,101 +0,0 @@
1
- import { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from 'fastify'
2
- import { InitializedAdapter } from '../adapter'
3
- import { calculateCacheKey } from '../cache'
4
- import { getMetricsMeta } from '../metrics/util'
5
- import { makeLogger } from '../util'
6
- import { AdapterMiddlewareBuilder, AdapterRequest } from '../util/request'
7
- import { AdapterError, AdapterInputError } from './error'
8
- import { Validator } from './validator'
9
- import { performSymbolOverrides } from './override-functions'
10
- export { InputParameters } from './input-params'
11
-
12
- const errorCatcherLogger = makeLogger('ErrorCatchingMiddleware')
13
-
14
- export const validatorMiddleware: AdapterMiddlewareBuilder =
15
- (adapter: InitializedAdapter) =>
16
- (req: AdapterRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {
17
- if (req.headers['content-type'] !== 'application/json') {
18
- throw new AdapterInputError({
19
- message: 'Content type not "application/json", returning 400',
20
- statusCode: 400,
21
- })
22
- }
23
-
24
- if (!req.body) {
25
- throw new AdapterInputError({
26
- message: 'Body not present in adapter request, returning 400',
27
- statusCode: 400,
28
- })
29
- }
30
-
31
- // Make endpoints case insensitive
32
- const endpointParam = req.body.endpoint?.toLowerCase() || adapter.defaultEndpoint
33
- if (!endpointParam) {
34
- throw new AdapterInputError({
35
- message: `Request body does not specify an endpoint, and there is no default endpoint configured for this adapter.`,
36
- statusCode: 400,
37
- })
38
- }
39
-
40
- const endpoint = adapter.endpointsMap[endpointParam]
41
- if (!endpoint) {
42
- throw new AdapterInputError({
43
- message: `Adapter does not have a "${req.body.endpoint}" endpoint.`,
44
- statusCode: 404,
45
- })
46
- }
47
-
48
- // Validate data using validator from v2
49
- // TODO: See if we want to change this whole thing
50
- const validator = new Validator(req.body, endpoint.inputParameters)
51
-
52
- req.requestContext = {
53
- id: req.body.id || '1',
54
- cacheKey: '',
55
- data: validator.validated.data,
56
- endpointName: endpoint.name,
57
- }
58
-
59
- if (adapter.config.METRICS_ENABLED && adapter.config.EXPERIMENTAL_METRICS_ENABLED) {
60
- // Add metrics meta which includes feedId to the request
61
- // Perform prior to overrides to maintain consistent Feed IDs across adapters
62
- const metrics = getMetricsMeta(endpoint, validator.validated.data)
63
- req.requestContext = { ...req.requestContext, meta: { metrics }}
64
- }
65
-
66
- // TODO: Support `includes` and `tokenOverrides` overrides as needed
67
- const requestParams = req.requestContext.data ?? {}
68
- if (requestParams['tokenOverrides']) {
69
- throw new Error('Token overrides not yet supported')
70
- }
71
- if (requestParams['includes']) {
72
- throw new Error('Includes not yet supported')
73
- }
74
- // Swaps the 'base' parameter if any overrides are found in the request or the adapter configuration
75
- // Supports 'base' input as string or string[]
76
- performSymbolOverrides(adapter, req)
77
-
78
- req.requestContext.cacheKey = calculateCacheKey(
79
- {
80
- adapterEndpoint: endpoint,
81
- adapterConfig: adapter.config,
82
- },
83
- req.requestContext.data,
84
- )
85
-
86
- done()
87
- }
88
-
89
- export const errorCatchingMiddleware = (err: Error, req: FastifyRequest, res: FastifyReply) => {
90
- // Add adapter or generic error to request meta for metrics use
91
- req.requestContext.meta = { ...req.requestContext.meta, error: err }
92
- if (err instanceof AdapterError) {
93
- // We want to log these as warn, because although they are to be expected, NOPs should
94
- // Only use "correct" job specs and therefore not hit adapters with invalid requests.
95
- errorCatcherLogger.warn(err)
96
- res.status(err.statusCode).send(err.toJSONResponse())
97
- } else {
98
- errorCatcherLogger.error(err)
99
- res.status(200).send('There was an unexpected error in the adapter.')
100
- }
101
- }
@@ -1,45 +0,0 @@
1
- /* INPUT TYPE VALIDATIONS */
2
- export type Override = Map<string, Map<string, string>>
3
-
4
- export type InputParameter = {
5
- aliases?: string[]
6
- description?: string
7
- type?: 'bigint' | 'boolean' | 'array' | 'number' | 'object' | 'string'
8
- required?: boolean
9
- options?: unknown[] // Enumerated options, ex. ['ADA', 'BTC', 'ETH']
10
- default?: unknown
11
- dependsOn?: string[] // Other inputs this one depends on
12
- exclusive?: string[] // Other inputs that cannot be present with this one
13
- }
14
-
15
- export type InputParameters = {
16
- [name: string]: InputParameter | boolean | string[]
17
- }
18
- export const baseInputParameters: InputParameters = {
19
- endpoint: {
20
- description: 'The External Adapter "endpoint" name to use.',
21
- required: false,
22
- type: 'string',
23
- },
24
- resultPath: {
25
- description: 'The path to key into the API response the retrieve the result',
26
- required: false,
27
- // Type: 'string', TODO: Once multiple types are supported this could be string or array of strings
28
- },
29
- overrides: {
30
- description: 'Override the mapping of token symbols to another token symbol',
31
- required: false,
32
- // Type: 'string', TODO: Once complex types are supported this could be { [adapter: string]: { [token: string]: string } }
33
- },
34
- tokenOverrides: {
35
- description: 'Override the mapping of token symbols to smart contract address',
36
- required: false,
37
- // Type: 'string', TODO: Once complex types are supported this could be { [network: string]: { [token: string]: string } }
38
- },
39
- includes: {
40
- description:
41
- 'Override the array of includes that holds additional input parameters when matching a pair of symbols',
42
- required: false,
43
- // Type: 'string', TODO: Once complex types are supported this could be { from: string, to: string, includes: [{ from: string, to: string, adapters: string[], inverse: boolean, tokens: boolean }] } }[]
44
- },
45
- }
@@ -1,44 +0,0 @@
1
- import { InitializedAdapter } from '../adapter'
2
- import { AdapterRequest } from '../util/request'
3
-
4
- type Overrides = Record<string, Record<string, string>>
5
-
6
- export const performSymbolOverrides = (adapter: InitializedAdapter, req: AdapterRequest) => {
7
- let adapterOverrides = {} as Record<string, string>
8
- if (
9
- req.requestContext.data &&
10
- req.requestContext.data['overrides'] &&
11
- (req.requestContext.data['overrides'] as Overrides)[adapter.name]
12
- ) {
13
- adapterOverrides = (req.requestContext.data['overrides'] as Overrides)[adapter.name]
14
- }
15
- if (!Array.isArray(req.requestContext.data['base'])) {
16
- // Perform overrides specified in the request payload
17
- req.requestContext.data['base'] =
18
- adapterOverrides[req.requestContext.data['base'] as string] ?? req.requestContext.data['base']
19
- // Perform hardcoded overrides
20
- if (adapter.overrides) {
21
- req.requestContext.data['base'] =
22
- adapter.overrides[req.requestContext.data['base'] as string] ??
23
- req.requestContext.data['base']
24
- }
25
- return
26
- }
27
- let requestedSymbols = req.requestContext.data['base']
28
- for (let i = 0; i < requestedSymbols.length; i++) {
29
- const symbol = requestedSymbols[i]
30
- // Perform overrides specified in the request payload
31
- let overriddenSymbol =
32
- adapterOverrides[symbol.toUpperCase()] ?? adapterOverrides[symbol.toLowerCase()]
33
- // Perform hardcoded overrides
34
- if (adapter.overrides) {
35
- overriddenSymbol =
36
- adapter.overrides[symbol.toUpperCase()] ??
37
- adapter.overrides[symbol.toLowerCase()] ??
38
- overriddenSymbol
39
- }
40
- requestedSymbols[i] = overriddenSymbol ?? requestedSymbols[i]
41
- }
42
- requestedSymbols = requestedSymbols.length > 1 ? requestedSymbols : requestedSymbols[1]
43
- req.requestContext.data['base'] = requestedSymbols
44
- }
@@ -1,23 +0,0 @@
1
- {
2
- "ethereum": {
3
- "LINK": "0x514910771af9ca656af840dff83e8264ecf986ca",
4
- "WETH": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
5
- "ETH": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
6
- "stETH": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84",
7
- "DIGG": "0x798d1be841a82a273720ce31c822c61a67a601c3",
8
- "WBTC": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
9
- "RAI": "0x03ab458634910aad20ef5f1c8ee96f1d6ac54919",
10
- "RGT": "0xD291E7a03283640FDc51b121aC401383A46cC623",
11
- "RARI": "0xFca59Cd816aB1eaD66534D82bc21E7515cE441CF",
12
- "SFI": "0xb753428af26e81097e7fd17f40c88aaa3e04902c",
13
- "LDO": "0x5a98fcbea516cf06857215779fd812ca3bef1b32",
14
- "VSP": "0x1b40183EFB4Dd766f11bDa7A7c3AD8982e998421",
15
- "USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
16
- "USDT": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
17
- "DAI": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
18
- "FRAX": "0x853d955aCEf822Db058eb8505911ED77F175b99e",
19
- "BOND": "0x0391d2021f89dc339f60fff84546ea23e337750f",
20
- "FEI": "0x956f47f50a910163d8bf957cf5846d573e7f87ca",
21
- "TRIBE": "0xc7283b66Eb1EB5FB86327f08e1B5816b0720212B"
22
- }
23
- }
@@ -1,384 +0,0 @@
1
- import { AdapterError, AdapterErrorResponse } from './error'
2
- import { InputParameter, InputParameters, Override, baseInputParameters } from './input-params'
3
- import { isArray, isObject } from '../util'
4
- import presetTokens from './preset-tokens.json'
5
-
6
- export type OverrideType = 'overrides' | 'tokenOverrides' | 'includes'
7
-
8
- type InputType = {
9
- id?: string
10
- data?: any
11
- }
12
-
13
- export interface ValidatorOptions {
14
- shouldThrowError?: boolean
15
- includes?: any[]
16
- overrides?: any
17
- }
18
-
19
- // Includes is an alternative symbol mapping that can be used to represent
20
- // The original request, such as wrapped tokens on DEXes.
21
- export type IncludePair = {
22
- from: string // From symbol
23
- to: string // To symbol
24
- adapters?: string[] // Array of adapters this applies to
25
- inverse?: boolean // If the inverse should be calculated instead
26
- tokens?: boolean // If the token addresses should be used instead
27
- }
28
-
29
- export type Includes = {
30
- from: string
31
- to: string
32
- includes: IncludePair[]
33
- }
34
-
35
- // Don't want to get requester in just yet, only copying the static method 'errored'
36
- const requesterErrored = (
37
- jobRunID = '1',
38
- error: AdapterError | Error | string | undefined = undefined,
39
- statusCode = 500,
40
- feedID: string | undefined = undefined,
41
- ): AdapterErrorResponse => {
42
- if (error instanceof AdapterError) {
43
- error.jobRunID = jobRunID
44
- if (feedID) {
45
- error.feedID = feedID
46
- }
47
- return error.toJSONResponse()
48
- }
49
- if (error instanceof Error) {
50
- return new AdapterError({
51
- jobRunID,
52
- statusCode,
53
- message: error.message,
54
- cause: error,
55
- feedID,
56
- }).toJSONResponse()
57
- }
58
- return new AdapterError({ jobRunID, statusCode, message: error, feedID }).toJSONResponse()
59
- }
60
-
61
- export class Validator {
62
- input: InputType
63
- inputConfigs: InputParameters
64
- inputOptions: Record<string, any[]>
65
- validatorOptions: ValidatorOptions
66
- validated: any
67
- error: AdapterError | undefined
68
- errored: AdapterErrorResponse | undefined
69
- constructor(
70
- input: InputType = { id: '1', data: {} },
71
- inputConfigs = {},
72
- inputOptions = {},
73
- validatorOptions: ValidatorOptions = {},
74
- ) {
75
- this.input = { ...input }
76
- if (!this.input.id) {
77
- this.input.id = '1'
78
- } // TODO Please remove these once "no any" strict typing is enabled
79
- if (!this.input.data) {
80
- this.input.data = {}
81
- }
82
- this.inputConfigs = { ...baseInputParameters, ...inputConfigs }
83
- this.inputOptions = { ...inputOptions }
84
- this.validatorOptions = {
85
- shouldThrowError: true,
86
- includes: [],
87
- overrides: {},
88
- ...validatorOptions,
89
- }
90
- this.validated = { id: this.input.id, data: {} }
91
- this.validateInput()
92
- this.validateOverrides('overrides', this.validatorOptions.overrides)
93
- this.validateOverrides('tokenOverrides', presetTokens)
94
- this.validateIncludeOverrides()
95
- this.checkDuplicateInputParams(inputConfigs)
96
- }
97
-
98
- validateInput(): void {
99
- try {
100
- for (const key in this.inputConfigs) {
101
- this.validateObjectParam(key, this.validatorOptions.shouldThrowError)
102
- }
103
- } catch (e) {
104
- this.parseError(e)
105
- }
106
- }
107
-
108
- validateOverrides(path: 'overrides' | 'tokenOverrides', preset: Record<string, any>): void {
109
- try {
110
- if (!this.input.data?.[path]) {
111
- this.validated[path] = this.formatOverride(preset)
112
- return
113
- }
114
- this.validated[path] = this.formatOverride({ ...preset, ...this.input.data[path] })
115
- } catch (e) {
116
- this.parseError(e)
117
- }
118
- }
119
-
120
- checkDuplicateInputParams(inputConfig: InputParameters): void {
121
- let aliases: string[] = []
122
- for (const key in inputConfig) {
123
- const param = inputConfig[key]
124
- if (Array.isArray(param)) {
125
- aliases = aliases.concat(param)
126
- } else if (typeof inputConfig === 'boolean') {
127
- return
128
- } else {
129
- aliases.push(key)
130
- if (typeof param === 'object' && 'aliases' in param && Array.isArray(param.aliases)) {
131
- aliases = aliases.concat(param.aliases)
132
- }
133
- }
134
- }
135
- if (aliases.length !== new Set(aliases).size) {
136
- this.throwInvalid('Duplicate Input Aliases')
137
- }
138
- }
139
-
140
- validateIncludeOverrides(): void {
141
- try {
142
- this.validated.includes = this.formatIncludeOverrides([
143
- ...(Array.isArray(this.input.data?.includes) ? this.input.data.includes : []),
144
- ...(this.validatorOptions.includes || []),
145
- ])
146
- } catch (e) {
147
- this.parseError(e)
148
- }
149
- }
150
-
151
- parseError(error: unknown): void {
152
- if (!(error instanceof Error)) {
153
- return
154
- }
155
- const message = 'Error validating input.'
156
- if (error instanceof AdapterError) {
157
- this.error = error
158
- } else {
159
- this.error = new AdapterError({
160
- jobRunID: this.validated.id,
161
- statusCode: 400,
162
- message,
163
- cause: error,
164
- })
165
- }
166
- this.errored = requesterErrored(this.validated.id, this.error)
167
- if (this.validatorOptions.shouldThrowError) {
168
- throw this.error
169
- }
170
- }
171
-
172
- // OverrideSymbol = (adapter: string, symbol?: string | string[]): string | string[] => {
173
- // Const defaultSymbol = symbol || this.validated.data.base
174
- // If (!defaultSymbol) this.throwInvalid(`Required parameter not supplied: base`)
175
-
176
- // // TODO: Will never be reached, because the presetSymbols are used as default overrides
177
- // If (!this.validated.overrides) return defaultSymbol
178
-
179
- // If (!Array.isArray(defaultSymbol))
180
- // Return (
181
- // This.validated.overrides.get(adapter.toLowerCase())?.get(defaultSymbol.toLowerCase()) ||
182
- // DefaultSymbol
183
- // )
184
- // Const multiple: string[] = []
185
- // For (const sym of defaultSymbol) {
186
- // Const overrided = this.validated.overrides.get(adapter.toLowerCase())?.get(sym.toLowerCase())
187
- // If (!overrided) multiple.push(sym)
188
- // Else multiple.push(overrided)
189
- // }
190
- // Return multiple
191
- // }
192
-
193
- // OverrideToken = (symbol: string, network = 'ethereum'): string | undefined => {
194
- // Return this.validated.tokenOverrides?.get(network.toLowerCase())?.get(symbol.toLowerCase())
195
- // }
196
-
197
- // OverrideIncludes = (from: string, to: string): IncludePair | undefined => {
198
- // // Search through `presetIncludes` to find matching override for adapter and to/from pairing.
199
- // Const pairs = (
200
- // This.validated.includes?.filter(
201
- // (val: string | Includes) => typeof val !== 'string',
202
- // ) as Includes[]
203
- // ).filter(
204
- // (pair) =>
205
- // Pair.from.toLowerCase() === from.toLowerCase() &&
206
- // Pair.to.toLowerCase() === to.toLowerCase(),
207
- // )
208
- // If (!pairs || !pairs[0] || !pairs[0].includes || !pairs[0].includes[0]) {
209
- // Return
210
- // }
211
- // Return pairs[0].includes[0]
212
- // }
213
-
214
- // OverrideReverseLookup = (adapter: string, type: OverrideType, symbol: string): string => {
215
- // Const overrides: Map<string, string> | undefined = this.validated?.[type]?.get(
216
- // Adapter.toLowerCase(),
217
- // )
218
- // If (!overrides) return symbol
219
- // Let originalSymbol: string | undefined
220
- // Overrides.forEach((overridden, original) => {
221
- // If (overridden.toLowerCase() === symbol.toLowerCase()) originalSymbol = original
222
- // })
223
- // Return originalSymbol || symbol
224
- // }
225
-
226
- formatOverride = (param: any): Override => {
227
- const _throwInvalid = () =>
228
- this.throwInvalid(`Parameter supplied with wrong format: "override"`)
229
-
230
- if (!isObject(param)) {
231
- _throwInvalid()
232
- }
233
-
234
- const _isValid = Object.values(param).every(isObject)
235
- if (!_isValid) {
236
- _throwInvalid()
237
- }
238
-
239
- const _keyToLowerCase = (entry: [string, any]): [string, any] => {
240
- return [entry[0].toLowerCase(), entry[1]]
241
- }
242
- return new Map(
243
- Object.entries(param)
244
- .map(_keyToLowerCase)
245
- .map(([key, value]) => [key, new Map(Object.entries(value).map(_keyToLowerCase))]),
246
- )
247
- }
248
-
249
- formatIncludeOverrides = (param: any): Override => {
250
- const _throwInvalid = () =>
251
- this.throwInvalid(`Parameter supplied with wrong format: "includes"`)
252
- if (!isArray(param)) {
253
- _throwInvalid()
254
- }
255
-
256
- const _isValid = Object.values(param).every((val) => isObject(val) || typeof val === 'string')
257
- if (!_isValid) {
258
- _throwInvalid()
259
- }
260
-
261
- return param
262
- }
263
-
264
- throwInvalid = (message: string): void => {
265
- throw new AdapterError({ jobRunID: this.validated.id, statusCode: 400, message })
266
- }
267
-
268
- validateObjectParam(key: string, shouldThrowError = true): void {
269
- const inputConfig = this.inputConfigs[key] as InputParameter
270
- const usedKey = this.getUsedKey(key, inputConfig.aliases ?? [])
271
-
272
- const param = usedKey
273
- ? this.input.data[usedKey as string] ?? inputConfig.default
274
- : inputConfig.default
275
-
276
- if (shouldThrowError) {
277
- const paramIsDefined = !(param === undefined || param === null || param === '')
278
-
279
- if (inputConfig.required && !paramIsDefined) {
280
- this.throwInvalid(`Required parameter ${key} must be non-null and non-empty`)
281
- }
282
-
283
- if (paramIsDefined) {
284
- if (inputConfig.type) {
285
- const primitiveTypes = ['boolean', 'number', 'bigint', 'string']
286
-
287
- if (![...primitiveTypes, 'array', 'object'].includes(inputConfig.type)) {
288
- this.throwInvalid(`${key} parameter has unrecognized type ${inputConfig.type}`)
289
- }
290
-
291
- if (primitiveTypes.includes(inputConfig.type) && typeof param !== inputConfig.type) {
292
- this.throwInvalid(`${key} parameter must be of type ${inputConfig.type}`)
293
- }
294
-
295
- if (inputConfig.type === 'array' && (!Array.isArray(param) || param.length === 0)) {
296
- this.throwInvalid(`${key} parameter must be a non-empty array`)
297
- }
298
-
299
- if (
300
- inputConfig.type === 'object' &&
301
- (!param ||
302
- Array.isArray(param) ||
303
- typeof param !== inputConfig.type ||
304
- Object.keys(param).length === 0)
305
- ) {
306
- this.throwInvalid(`${key} parameter must be an object with at least one property`)
307
- }
308
- }
309
-
310
- // If (inputConfig.options) {
311
- // Const tolcase = (o: any) => (typeof o === 'string' ? o.toLowerCase() : o)
312
-
313
- // Const formattedOptions = inputConfig.options.map(tolcase)
314
- // Const formattedParam = tolcase(param)
315
-
316
- // If (!formattedOptions.includes(formattedParam))
317
- // This.throwInvalid(
318
- // `${key} parameter '${formattedParam}' is not in the set of available options: ${formattedOptions.join(
319
- // ',',
320
- // )}`,
321
- // )
322
- // }
323
-
324
- // For (const dependency of inputConfig.dependsOn ?? []) {
325
- // Const usedDependencyKey = this.getUsedKey(
326
- // Dependency,
327
- // (this.inputConfigs[dependency] as InputParameter).aliases ?? [],
328
- // )
329
- // If (!usedDependencyKey) this.throwInvalid(`${key} dependency ${dependency} not supplied`)
330
- // }
331
-
332
- // For (const exclusive of inputConfig.exclusive ?? []) {
333
- // Const usedExclusiveKey = this.getUsedKey(
334
- // Exclusive,
335
- // (this.inputConfigs[exclusive] as InputParameter).aliases ?? [],
336
- // )
337
- // If (usedExclusiveKey)
338
- // This.throwInvalid(`${key} cannot be supplied concurrently with ${exclusive}`)
339
- // }
340
- }
341
- }
342
-
343
- this.validated.data[key] = param
344
- }
345
-
346
- validateOptionalParam(param: any, key: string, options: any[]): void {
347
- if (param && options) {
348
- if (!Array.isArray(options)) {
349
- this.throwInvalid(`Parameter options for ${key} must be of an Array type`)
350
- }
351
- if (!options.includes(param)) {
352
- this.throwInvalid(`${param} is not a supported ${key} option. Must be one of ${options}`)
353
- }
354
- }
355
- this.validated.data[key] = param
356
- }
357
-
358
- validateRequiredParam(param: any, key: string, options: any[]): void {
359
- if (typeof param === 'undefined' || param === '') {
360
- this.throwInvalid(`Required parameter not supplied: ${key}`)
361
- }
362
- if (options) {
363
- if (!Array.isArray(options)) {
364
- this.throwInvalid(`Parameter options for ${key} must be of an Array type`)
365
- }
366
- if (!options.includes(param)) {
367
- this.throwInvalid(
368
- `${param} is not a supported ${key} option. Must be one of ${options.join(' || ')}`,
369
- )
370
- }
371
- }
372
- this.validated.data[key] = param
373
- }
374
-
375
- getUsedKey(key: string, keyArray: string[]): string | undefined {
376
- const comparisonArray = [...keyArray]
377
- if (!comparisonArray.includes(key)) {
378
- comparisonArray.push(key)
379
- }
380
-
381
- const inputParamKeys = Object.keys(this.input.data)
382
- return inputParamKeys.find((k) => comparisonArray.includes(k))
383
- }
384
- }
@@ -1,27 +0,0 @@
1
- import test from 'ava'
2
- import { expose } from '../src'
3
- import { Adapter } from '../src/adapter'
4
- import { NopTransport } from './util'
5
-
6
- test('duplicate endpoint names throw error on startup', async (t) => {
7
- const adapter: Adapter = {
8
- name: 'test',
9
- endpoints: [
10
- {
11
- name: 'test',
12
- inputParameters: {},
13
- transport: new NopTransport(),
14
- },
15
- {
16
- name: 'another',
17
- aliases: ['test'],
18
- inputParameters: {},
19
- transport: new NopTransport(),
20
- },
21
- ],
22
- }
23
-
24
- await t.throwsAsync(async () => expose(adapter), {
25
- message: 'Duplicate endpoint / alias: "test"',
26
- })
27
- })