@chainlink/external-adapter-framework 0.0.15 → 0.0.16

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 (183) hide show
  1. package/adapter.js +128 -0
  2. package/background-executor.js +45 -0
  3. package/cache/factory.js +58 -0
  4. package/cache/index.js +173 -0
  5. package/cache/local.js +83 -0
  6. package/cache/metrics.js +120 -0
  7. package/cache/redis.js +100 -0
  8. package/chainlink-external-adapter-framework-v0.0.6.tgz +0 -0
  9. package/config/index.js +366 -0
  10. package/config/provider-limits.js +74 -0
  11. package/examples/bank-frick/accounts.js +192 -0
  12. package/examples/bank-frick/config/index.js +54 -0
  13. package/examples/bank-frick/index.js +15 -0
  14. package/examples/bank-frick/util.js +39 -0
  15. package/examples/coingecko/src/config/index.js +13 -0
  16. package/examples/coingecko/src/config/overrides.json +10826 -0
  17. package/examples/coingecko/src/cryptoUtils.js +41 -0
  18. package/examples/coingecko/src/endpoint/coins.js +33 -0
  19. package/examples/coingecko/src/endpoint/crypto-marketcap.js +46 -0
  20. package/examples/coingecko/src/endpoint/crypto-volume.js +46 -0
  21. package/examples/coingecko/src/endpoint/crypto.js +47 -0
  22. package/examples/coingecko/src/endpoint/dominance.js +26 -0
  23. package/examples/coingecko/src/endpoint/global-marketcap.js +26 -0
  24. package/examples/coingecko/src/endpoint/index.js +15 -0
  25. package/examples/coingecko/src/globalUtils.js +48 -0
  26. package/examples/coingecko/src/index.js +14 -0
  27. package/examples/coingecko/test/e2e/adapter.test.js +262 -0
  28. package/examples/coingecko/test/integration/adapter.test.js +264 -0
  29. package/examples/coingecko/test/integration/capturedRequests.json +1 -0
  30. package/examples/coingecko/test/integration/fixtures.js +41 -0
  31. package/examples/coingecko-old/batch-warming.js +53 -0
  32. package/examples/coingecko-old/index.js +11 -0
  33. package/examples/coingecko-old/rest.js +51 -0
  34. package/examples/ncfx/config/index.js +15 -0
  35. package/examples/ncfx/index.js +11 -0
  36. package/examples/ncfx/websocket.js +73 -0
  37. package/index.js +127 -0
  38. package/metrics/constants.js +25 -0
  39. package/metrics/index.js +122 -0
  40. package/metrics/util.js +9 -0
  41. package/package.json +5 -15
  42. package/rate-limiting/background/fixed-frequency.js +35 -0
  43. package/rate-limiting/index.js +84 -0
  44. package/rate-limiting/metrics.js +44 -0
  45. package/rate-limiting/request/simple-counting.js +62 -0
  46. package/test.js +6 -0
  47. package/transports/batch-warming.js +101 -0
  48. package/transports/index.js +87 -0
  49. package/transports/metrics.js +105 -0
  50. package/transports/rest.js +138 -0
  51. package/transports/util.js +86 -0
  52. package/transports/websocket.js +166 -0
  53. package/util/index.js +35 -0
  54. package/util/logger.js +62 -0
  55. package/util/recordRequests.js +45 -0
  56. package/util/request.js +2 -0
  57. package/util/subscription-set/expiring-sorted-set.js +47 -0
  58. package/util/subscription-set/subscription-set.js +19 -0
  59. package/util/test-payload-loader.js +83 -0
  60. package/validation/error.js +79 -0
  61. package/validation/index.js +91 -0
  62. package/validation/input-params.js +30 -0
  63. package/validation/override-functions.js +40 -0
  64. package/validation/overrideFunctions.js +40 -0
  65. package/validation/preset-tokens.json +23 -0
  66. package/validation/validator.js +303 -0
  67. package/.c8rc.json +0 -3
  68. package/.eslintignore +0 -10
  69. package/.eslintrc.js +0 -96
  70. package/.github/README.MD +0 -42
  71. package/.github/actions/setup/action.yaml +0 -13
  72. package/.github/workflows/label.yaml +0 -39
  73. package/.github/workflows/main.yaml +0 -39
  74. package/.github/workflows/publish.yaml +0 -17
  75. package/.prettierignore +0 -13
  76. package/.yarnrc +0 -0
  77. package/README.md +0 -103
  78. package/dist/examples/coingecko/test/e2e/adapter.test.ts.js +0 -82953
  79. package/dist/examples/coingecko/test/integration/adapter.test.ts.js +0 -91672
  80. package/dist/main.js +0 -72703
  81. package/docker-compose.yaml +0 -35
  82. package/env.sh +0 -54
  83. package/env2.sh +0 -55
  84. package/jest.config.js +0 -5
  85. package/publish.sh +0 -0
  86. package/src/adapter.ts +0 -263
  87. package/src/background-executor.ts +0 -52
  88. package/src/cache/factory.ts +0 -26
  89. package/src/cache/index.ts +0 -258
  90. package/src/cache/local.ts +0 -73
  91. package/src/cache/metrics.ts +0 -112
  92. package/src/cache/redis.ts +0 -93
  93. package/src/config/index.ts +0 -517
  94. package/src/config/provider-limits.ts +0 -127
  95. package/src/examples/bank-frick/README.MD +0 -10
  96. package/src/examples/bank-frick/accounts.ts +0 -246
  97. package/src/examples/bank-frick/config/index.ts +0 -53
  98. package/src/examples/bank-frick/index.ts +0 -13
  99. package/src/examples/bank-frick/types.d.ts +0 -38
  100. package/src/examples/bank-frick/util.ts +0 -55
  101. package/src/examples/coingecko/src/config/index.ts +0 -12
  102. package/src/examples/coingecko/src/config/overrides.json +0 -10826
  103. package/src/examples/coingecko/src/cryptoUtils.ts +0 -88
  104. package/src/examples/coingecko/src/endpoint/coins.ts +0 -54
  105. package/src/examples/coingecko/src/endpoint/crypto-marketcap.ts +0 -66
  106. package/src/examples/coingecko/src/endpoint/crypto-volume.ts +0 -66
  107. package/src/examples/coingecko/src/endpoint/crypto.ts +0 -63
  108. package/src/examples/coingecko/src/endpoint/dominance.ts +0 -40
  109. package/src/examples/coingecko/src/endpoint/global-marketcap.ts +0 -40
  110. package/src/examples/coingecko/src/endpoint/index.ts +0 -6
  111. package/src/examples/coingecko/src/globalUtils.ts +0 -78
  112. package/src/examples/coingecko/src/index.ts +0 -17
  113. package/src/examples/coingecko/test/e2e/adapter.test.ts +0 -278
  114. package/src/examples/coingecko/test/integration/__snapshots__/adapter.test.ts.snap +0 -15
  115. package/src/examples/coingecko/test/integration/adapter.test.ts +0 -281
  116. package/src/examples/coingecko/test/integration/capturedRequests.json +0 -1
  117. package/src/examples/coingecko/test/integration/fixtures.ts +0 -42
  118. package/src/examples/coingecko-old/batch-warming.ts +0 -79
  119. package/src/examples/coingecko-old/index.ts +0 -9
  120. package/src/examples/coingecko-old/rest.ts +0 -77
  121. package/src/examples/ncfx/config/index.ts +0 -12
  122. package/src/examples/ncfx/index.ts +0 -9
  123. package/src/examples/ncfx/websocket.ts +0 -99
  124. package/src/index.ts +0 -149
  125. package/src/metrics/constants.ts +0 -23
  126. package/src/metrics/index.ts +0 -115
  127. package/src/metrics/util.ts +0 -18
  128. package/src/rate-limiting/background/fixed-frequency.ts +0 -45
  129. package/src/rate-limiting/index.ts +0 -100
  130. package/src/rate-limiting/metrics.ts +0 -18
  131. package/src/rate-limiting/request/simple-counting.ts +0 -76
  132. package/src/transports/batch-warming.ts +0 -127
  133. package/src/transports/index.ts +0 -152
  134. package/src/transports/metrics.ts +0 -95
  135. package/src/transports/rest.ts +0 -168
  136. package/src/transports/util.ts +0 -63
  137. package/src/transports/websocket.ts +0 -245
  138. package/src/util/index.ts +0 -23
  139. package/src/util/logger.ts +0 -69
  140. package/src/util/recordRequests.ts +0 -47
  141. package/src/util/request.ts +0 -117
  142. package/src/util/subscription-set/expiring-sorted-set.ts +0 -54
  143. package/src/util/subscription-set/subscription-set.ts +0 -35
  144. package/src/util/test-payload-loader.ts +0 -87
  145. package/src/validation/error.ts +0 -116
  146. package/src/validation/index.ts +0 -110
  147. package/src/validation/input-params.ts +0 -45
  148. package/src/validation/override-functions.ts +0 -44
  149. package/src/validation/overrideFunctions.ts +0 -44
  150. package/src/validation/preset-tokens.json +0 -23
  151. package/src/validation/validator.ts +0 -384
  152. package/test/adapter.test.ts +0 -27
  153. package/test/background-executor.test.ts +0 -108
  154. package/test/cache/cache-key.test.ts +0 -114
  155. package/test/cache/helper.ts +0 -100
  156. package/test/cache/local.test.ts +0 -54
  157. package/test/cache/redis.test.ts +0 -89
  158. package/test/correlation.test.ts +0 -114
  159. package/test/index.test.ts +0 -37
  160. package/test/metrics/feed-id.test.ts +0 -38
  161. package/test/metrics/helper.ts +0 -14
  162. package/test/metrics/labels.test.ts +0 -36
  163. package/test/metrics/metrics.test.ts +0 -267
  164. package/test/metrics/redis-metrics.test.ts +0 -113
  165. package/test/metrics/warmer-metrics.test.ts +0 -193
  166. package/test/metrics/ws-metrics.test.ts +0 -225
  167. package/test/rate-limit-config.test.ts +0 -242
  168. package/test/smoke/smoke.test.ts +0 -166
  169. package/test/smoke/test-payload-fail.json +0 -3
  170. package/test/smoke/test-payload.js +0 -22
  171. package/test/smoke/test-payload.json +0 -7
  172. package/test/transports/batch.test.ts +0 -466
  173. package/test/transports/rest.test.ts +0 -242
  174. package/test/transports/websocket.test.ts +0 -183
  175. package/test/tsconfig.json +0 -5
  176. package/test/util.ts +0 -77
  177. package/test/validation.test.ts +0 -178
  178. package/test.sh +0 -20
  179. package/test2.sh +0 -2
  180. package/tsconfig.json +0 -28
  181. package/typedoc.json +0 -6
  182. package/webpack.config.js +0 -57
  183. package/yarn-error.log +0 -3778
@@ -1,517 +0,0 @@
1
- // Import { getRandomRequiredEnv, getRandomEnv, getEnv } from '../util'
2
-
3
- export const BaseSettings = {
4
- // V2 compat
5
- // TODO: Remove non used in v3 ones
6
- API_ENDPOINT: {
7
- description: 'The URL that the certain transports use to retrieve data',
8
- type: 'string',
9
- },
10
- API_KEY: {
11
- description: 'Default setting for an EA key',
12
- type: 'string',
13
- },
14
- // API_TIMEOUT: {
15
- // type: 'number',
16
- // default: 30000,
17
- // },
18
- // API_VERBOSE: {
19
- // type: 'boolean',
20
- // },
21
- BASE_URL: {
22
- description: 'Starting path for the EA handler endpoint',
23
- type: 'string',
24
- default: '/',
25
- },
26
- // CACHE_ENABLED: {
27
- // type: 'boolean',
28
- // default: true,
29
- // },
30
- // CACHE_KEY_GROUP: {
31
- // type: 'string',
32
- // },
33
- CACHE_MAX_AGE: {
34
- description: 'Maximum amount of time (in ms) that a response will stay cached',
35
- type: 'number',
36
- default: 90000,
37
- },
38
- // CACHE_MAX_ITEMS: {
39
- // type: 'number',
40
- // default: 1000,
41
- // },
42
- // CACHE_MIN_AGE: {
43
- // type: 'number',
44
- // default: 30000,
45
- // },
46
- // CACHE_REDIS_CONNECTION_TIMEOUT: {
47
- // type: 'number',
48
- // default: 15000,
49
- // },
50
- CACHE_REDIS_HOST: {
51
- description: 'Hostname for the Redis instance to be used',
52
- type: 'string',
53
- default: '127.0.0.1',
54
- },
55
- // CACHE_REDIS_MAX_QUEUED_ITEMS: {
56
- // type: 'number',
57
- // default: 100,
58
- // },
59
- // CACHE_REDIS_MAX_RECONNECT_COOLDOWN: {
60
- // type: 'number',
61
- // default: 3000,
62
- // },
63
- // CACHE_REDIS_PASSWORD: {
64
- // type: 'string',
65
- // },
66
- // CACHE_REDIS_PATH: {
67
- // type: 'string',
68
- // },
69
- CACHE_REDIS_PORT: {
70
- description: 'Port for the Redis instance to be used',
71
- type: 'number',
72
- default: 6379,
73
- },
74
- // CACHE_REDIS_TIMEOUT: {
75
- // type: 'number',
76
- // default: 500,
77
- // },
78
- // CACHE_REDIS_URL: {
79
- // type: 'string',
80
- // },
81
- CACHE_TYPE: {
82
- description: 'The type of cache to use throughout the EA',
83
- type: 'enum',
84
- default: 'local',
85
- options: ['local', 'redis'],
86
- },
87
- // CACHE_UPDATE_AGE_ON_GET: {
88
- // type: 'boolean',
89
- // default: false,
90
- // },
91
- CORRELATION_ID_ENABLED: {
92
- description: 'Flag to enable correlation IDs for sent requests in logging',
93
- type: 'boolean',
94
- default: true,
95
- },
96
- // DEBUG: {
97
- // type: 'boolean',
98
- // },
99
- // DEFAULT_WS_HEARTBEAT_INTERVAL: {
100
- // type: 'number',
101
- // default: 30000,
102
- // },
103
- EA_PORT: {
104
- description:
105
- 'Port through which the EA will listen for REST requests (if mode is set to "reader" or "reader-writer")',
106
- type: 'number',
107
- default: 8080,
108
- },
109
- // ENV_ADAPTER_URL: {
110
- // type: 'string',
111
- // },
112
- // ERROR_CAPACITY: {
113
- // type: 'number',
114
- // },
115
- EXPERIMENTAL_METRICS_ENABLED: {
116
- description:
117
- 'Flag to specify whether or not to collect metrics. Used as fallback for METRICS_ENABLED',
118
- type: 'boolean',
119
- default: true,
120
- },
121
- // LEGACY_ENV_ADAPTER_URL: {
122
- // type: 'string',
123
- // },
124
- LOG_LEVEL: {
125
- description: 'Minimum level required for logs to be output',
126
- type: 'string',
127
- default: 'info',
128
- },
129
- METRICS_ENABLED: {
130
- description: 'Flag to specify whether or not to startup the metrics server',
131
- type: 'boolean',
132
- default: true,
133
- },
134
- METRICS_NAME: {
135
- description: 'Metrics name',
136
- type: 'string',
137
- },
138
- METRICS_PORT: {
139
- description: 'Port metrics will be exposed to',
140
- type: 'number',
141
- default: 9080,
142
- },
143
- METRICS_USE_BASE_URL: {
144
- description: 'Flag to specify whether or not to prepend the BASE_URL to the metrics endpoint',
145
- type: 'boolean',
146
- },
147
- RATE_LIMIT_API_TIER: {
148
- description:
149
- 'Rate limiting tier to use from the available options for the adapter. If not present, the adapter will run using the first tier on the list.',
150
- type: 'string',
151
- },
152
- // RATE_LIMIT_CAPACITY_MINUTE: {
153
- // type: 'number',
154
- // },
155
- // RATE_LIMIT_CAPACITY_SECOND: {
156
- // type: 'number',
157
- // },
158
- // RATE_LIMIT_CAPACITY: {
159
- // type: 'number',
160
- // },
161
- // RATE_LIMIT_ENABLED: {
162
- // type: 'boolean',
163
- // default: true,
164
- // },
165
- // RECORD: {
166
- // type: 'boolean',
167
- // },
168
- // REQUEST_COALESCING_ENABLED: {
169
- // type: 'boolean',
170
- // },
171
- // REQUEST_COALESCING_ENTROPY_MAX: {
172
- // type: 'number',
173
- // default: 0,
174
- // },
175
- // REQUEST_COALESCING_INTERVAL_COEFFICIENT: {
176
- // type: 'number',
177
- // default: 2,
178
- // },
179
- // REQUEST_COALESCING_INTERVAL_MAX: {
180
- // type: 'number',
181
- // default: 1000,
182
- // },
183
- // REQUEST_COALESCING_INTERVAL: {
184
- // type: 'number',
185
- // default: 100,
186
- // },
187
- // REQUEST_COALESCING_MAX_RETRIES: {
188
- // type: 'number',
189
- // default: 5,
190
- // },
191
- // RETRY: {
192
- // type: 'boolean',
193
- // default: 1,
194
- // },
195
- // SERVER_RATE_LIMIT_MAX: {
196
- // type: 'number',
197
- // default: 250,
198
- // },
199
- // SERVER_SLOW_DOWN_AFTER_FACTOR: {
200
- // type: 'number',
201
- // default: 0.8,
202
- // },
203
- // SERVER_SLOW_DOWN_DELAY_MS: {
204
- // type: 'number',
205
- // default: 500,
206
- // },
207
- // TIMEOUT: {
208
- // type: 'number',
209
- // },
210
- // WARMUP_ENABLED: {
211
- // type: 'boolean',
212
- // default: true,
213
- // },
214
- // WARMUP_INTERVAL: {
215
- // type: 'number',
216
- // },
217
- WARMUP_SUBSCRIPTION_TTL: {
218
- type: 'number',
219
- description: 'TTL for batch warmer subscriptions',
220
- default: 10000,
221
- },
222
- // WARMUP_UNHEALTHY_THRESHOLD: {
223
- // type: 'number',
224
- // default: 3,
225
- // },
226
- // WS_API_ENDPOINT: {
227
- // type: 'string',
228
- // },
229
- // WS_API_KEY: {
230
- // type: 'string',
231
- // },
232
- // WS_CONNECTION_KEY: {
233
- // type: 'string',
234
- // default: 1,
235
- // },
236
- // WS_CONNECTION_LIMIT: {
237
- // type: 'number',
238
- // default: 1,
239
- // },
240
- // WS_CONNECTION_RETRY_DELAY: {
241
- // type: 'number',
242
- // default: 1000,
243
- // },
244
- // WS_CONNECTION_RETRY_LIMIT: {
245
- // type: 'number',
246
- // default: 3,
247
- // },
248
- // WS_CONNECTION_TTL: {
249
- // type: 'number',
250
- // default: 70000,
251
- // },
252
- // WS_ENABLED: {
253
- // type: 'boolean',
254
- // default: false,
255
- // },
256
- // WS_SUBSCRIPTION_LIMIT: {
257
- // type: 'number',
258
- // default: 10,
259
- // },
260
- // WS_SUBSCRIPTION_PRIORITY_LIST: {
261
- // type: 'string',
262
- // },
263
- // WS_SUBSCRIPTION_TTL: {
264
- // type: 'number',
265
- // default: 120000,
266
- // },
267
- // WS_SUBSCRIPTION_UNRESPONSIVE_TTL: {
268
- // type: 'number',
269
- // default: false,
270
- // },
271
- // WS_TIME_UNTIL_HANDLE_NEXT_MESSAGE_OVERRIDE: {
272
- // type: 'number',
273
- // },
274
-
275
- // V3
276
- CACHE_POLLING_MAX_RETRIES: {
277
- description:
278
- 'Max amount of times to attempt to find EA response in the cache after the Transport has been set up',
279
- type: 'number',
280
- default: 10,
281
- },
282
- CACHE_POLLING_SLEEP_MS: {
283
- description:
284
- 'The number of ms to sleep between each retry to fetch the EA response in the cache',
285
- type: 'number',
286
- default: 200,
287
- },
288
- DEFAULT_CACHE_KEY: {
289
- description: 'Default key to be used when one cannot be determined from request parameters',
290
- type: 'string',
291
- default: 'DEFAULT_CACHE_KEY',
292
- },
293
- EA_HOST: {
294
- description:
295
- 'Host this EA will listen for REST requests on (if mode is set to "reader" or "reader-writer")',
296
- type: 'string',
297
- default: '::',
298
- },
299
- EA_MODE: {
300
- description:
301
- 'Port this EA will listen for REST requests on (if mode is set to "reader" or "reader-writer")',
302
- type: 'enum',
303
- default: 'reader-writer',
304
- options: ['reader', 'writer', 'reader-writer'],
305
- },
306
- REST_TRANSPORT_MAX_RATE_LIMIT_RETRIES: {
307
- description:
308
- 'Maximum amount of times the Rest Transport will attempt to set up a request when blocked by the rate limiter',
309
- type: 'number',
310
- default: 3,
311
- },
312
- REST_TRANSPORT_MS_BETWEEN_RATE_LIMIT_RETRIES: {
313
- description:
314
- 'Time that the Rest Transport will wait between retries when blocked by the rate limiter',
315
- type: 'number',
316
- default: 400,
317
- },
318
- MAX_COMMON_KEY_SIZE: {
319
- description:
320
- 'Maximum amount of characters that the common part of the cache key or feed ID can have',
321
- type: 'number',
322
- default: 300,
323
- validate: (value?: number) => {
324
- if (!(value && value >= 150 && value <= 500)) {
325
- return 'MAX_COMMON_KEY_SIZE must be a number between 150 and 500'
326
- }
327
- },
328
- },
329
- // CACHE_KEY_IGNORED_PROPS : {
330
- // description: 'Properties to ignore when generating a feed ID for requests',
331
- // type: 'string'
332
- // }
333
- SMOKE_TEST_PAYLOAD_FILE_NAME: {
334
- description: 'Name of the test payload file used for the smoke endpoint',
335
- type: 'string',
336
- },
337
- } as const
338
-
339
- export const buildAdapterConfig = <
340
- CustomSettings extends CustomSettingsType<CustomSettings> = EmptySettings,
341
- >({
342
- overrides = {} as Partial<BaseAdapterConfig>,
343
- customSettings = {} as SettingsMap,
344
- }): AdapterConfig<CustomSettings> => {
345
- const validationErrors = [] as string[]
346
- const vars = {} as Record<string, SettingValueType | undefined>
347
-
348
- // Iterate base adapter env vars
349
- for (const [key, config] of Object.entries(BaseSettings) as Array<
350
- [keyof BaseAdapterConfig, Setting]
351
- >) {
352
- const value = getEnv(key as string, config) ?? overrides?.[key] ?? config.default
353
- vars[key] = value
354
- }
355
-
356
- // Iterate custom vars
357
- for (const [key, config] of Object.entries(customSettings) as Array<[string, Setting]>) {
358
- if ((BaseSettings as Record<string, unknown>)[key as string]) {
359
- throw new Error(
360
- `Custom env var "${key}" declared, but a base framework env var with that name already exists.`,
361
- )
362
- }
363
-
364
- const value = getEnv(key as string, config) ?? config.default
365
-
366
- // Check if a required setting has been provided
367
- if (config.required && value === null) {
368
- validationErrors.push(`${key}: Value is required, but none was provided`)
369
- } else if (config.validate) {
370
- // Cast validate to unknown because TS can't select one of multiple variants of the validate function signature
371
- const validationRes = (
372
- config.validate as unknown as (value?: SettingValueType) => ValidationErrorMessage
373
- )(value)
374
- if (validationRes) {
375
- validationErrors.push(`${key}: ${validationRes}`)
376
- }
377
- }
378
- vars[key] = value
379
- }
380
-
381
- if (validationErrors.length > 0) {
382
- throw new Error(
383
- `Validation failed for the following variables:\n ${validationErrors.join('\n')}`,
384
- )
385
- }
386
-
387
- return vars as AdapterConfig<CustomSettings>
388
- }
389
-
390
- const getEnv = (name: string, config: Setting): SettingValueType | null => {
391
- const value = process.env[name]
392
- if (!value) {
393
- return null
394
- }
395
-
396
- switch (config.type) {
397
- case 'string':
398
- return value
399
- case 'number':
400
- return parseInt(value)
401
- case 'boolean':
402
- return value === 'true'
403
- case 'enum':
404
- if (!config.options?.includes(value)) {
405
- throw new Error(
406
- `Env var "${name}" has value "${value}" which is not included in the valid options (${config.options})`,
407
- )
408
- }
409
- return value
410
- }
411
- }
412
-
413
- type SettingValueType = string | number | boolean
414
- type SettingType<C extends Setting> = C['type'] extends 'string'
415
- ? string
416
- : C['type'] extends 'number'
417
- ? number
418
- : C['type'] extends 'boolean'
419
- ? boolean
420
- : C['type'] extends 'enum'
421
- ? C['options'] extends readonly string[]
422
- ? C['options'][number]
423
- : never
424
- : never
425
- type BaseSettingsType = typeof BaseSettings
426
- export type Setting =
427
- | {
428
- type: 'string'
429
- description: string
430
- options?: never
431
- default?: string
432
- validate?: (value?: string) => ValidationErrorMessage
433
- required?: false
434
- }
435
- | {
436
- type: 'string'
437
- description: string
438
- options?: never
439
- default?: string
440
- validate?: (value: string) => ValidationErrorMessage
441
- required: true
442
- }
443
- | {
444
- type: 'number'
445
- description: string
446
- options?: never
447
- default?: number
448
- validate?: (value?: number) => ValidationErrorMessage
449
- required?: false
450
- }
451
- | {
452
- type: 'number'
453
- description: string
454
- options?: never
455
- default?: number
456
- validate?: (value: number) => ValidationErrorMessage
457
- required: true
458
- }
459
- | {
460
- type: 'boolean'
461
- description: string
462
- options?: never
463
- default?: boolean
464
- validate?: (value?: boolean) => ValidationErrorMessage
465
- required?: false
466
- }
467
- | {
468
- type: 'boolean'
469
- description: string
470
- options?: never
471
- default?: boolean
472
- validate?: (value: boolean) => ValidationErrorMessage
473
- required: true
474
- }
475
- | {
476
- type: 'enum'
477
- description: string
478
- default?: string
479
- options: readonly string[]
480
- validate?: (value?: string) => ValidationErrorMessage
481
- required?: false
482
- }
483
- | {
484
- type: 'enum'
485
- description: string
486
- default?: string
487
- options: readonly string[]
488
- validate?: (value: string) => ValidationErrorMessage
489
- required: true
490
- }
491
-
492
- export type AdapterConfigFromSettings<T extends SettingsMap> = {
493
- -readonly [K in keyof T as T[K] extends {
494
- default: SettingValueType
495
- }
496
- ? K
497
- : T[K]['required'] extends true
498
- ? K
499
- : never]: SettingType<T[K]>
500
- } & {
501
- -readonly [K in keyof T as T[K] extends {
502
- default: SettingValueType
503
- }
504
- ? never
505
- : T[K]['required'] extends true
506
- ? never
507
- : K]?: SettingType<T[K]> | undefined
508
- }
509
-
510
- export type BaseAdapterConfig = AdapterConfigFromSettings<BaseSettingsType>
511
- export type AdapterConfig<T extends CustomSettingsType<T> = SettingsMap> =
512
- AdapterConfigFromSettings<T> & BaseAdapterConfig
513
-
514
- export type CustomSettingsType<T = SettingsMap> = Record<keyof T, Setting>
515
- export type EmptySettings = Record<string, never>
516
- export type SettingsMap = Record<string, Setting>
517
- export type ValidationErrorMessage = string | undefined
@@ -1,127 +0,0 @@
1
- import { makeLogger } from '../util'
2
-
3
- export const DEFAULT_MINUTE_RATE_LIMIT = 60
4
- export const BURST_UNDEFINED_QUOTA_MULTIPLE = 2
5
-
6
- export const DEFAULT_WS_CONNECTIONS = 2
7
- export const DEFAULT_WS_SUBSCRIPTIONS = 10
8
-
9
- type RateLimitTimeFrame = 'rateLimit1s' | 'rateLimit1m' | 'rateLimit1h'
10
-
11
- type HTTPTier = {
12
- rateLimit1s?: number
13
- rateLimit1m?: number
14
- rateLimit1h?: number
15
- note?: string
16
- }
17
-
18
- type WSTier = {
19
- connections: number
20
- subscriptions: number
21
- }
22
-
23
- export interface Limits {
24
- http: Record<string, HTTPTier>
25
- ws: Record<string, WSTier>
26
- }
27
-
28
- interface ProviderRateLimit {
29
- second: number
30
- minute: number
31
- }
32
-
33
- const logger = makeLogger('ProviderLimits')
34
-
35
- export const getHTTPLimit = (
36
- provider: string,
37
- limits: Limits,
38
- tier: string,
39
- timeframe: RateLimitTimeFrame,
40
- ): number => {
41
- const providerLimit = getProviderLimits(provider, limits, tier, 'http')
42
- return (providerLimit as HTTPTier)?.[timeframe] || 0
43
- }
44
-
45
- export const getRateLimit = (provider: string, limits: Limits, tier: string): ProviderRateLimit => {
46
- const providerLimit = getProviderLimits(provider, limits, tier, 'http')
47
- return calculateRateLimit(providerLimit as HTTPTier)
48
- }
49
-
50
- export const getWSLimits = (provider: string, limits: Limits, tier: string): WSTier => {
51
- const providerLimit = getProviderLimits(provider, limits, tier, 'ws')
52
- return calculateWSLimits(providerLimit as WSTier)
53
- }
54
-
55
- const getProviderLimits = (
56
- provider: string,
57
- limits: Limits,
58
- tier: string,
59
- protocol: 'ws' | 'http',
60
- ): HTTPTier | WSTier | undefined => {
61
- const providerConfig = parseLimits(limits)
62
- if (!providerConfig) {
63
- throw new Error(
64
- `Rate Limit: Provider: "${provider}" doesn't match any provider spec in limits.json`,
65
- )
66
- }
67
-
68
- const protocolConfig = providerConfig[protocol]
69
- if (!protocolConfig) {
70
- throw new Error(
71
- `Rate Limit: "${provider}" doesn't have any configuration for ${protocol} in limits.json`,
72
- )
73
- }
74
-
75
- let limitsConfig = protocolConfig[tier.toLowerCase()]
76
-
77
- if (!limitsConfig) {
78
- logger.debug(
79
- `Rate Limit: "${provider} does not have tier ${tier} defined. Falling back to lowest tier"`,
80
- )
81
- limitsConfig = Object.values(protocolConfig)?.[0]
82
- }
83
-
84
- if (!limitsConfig) {
85
- throw new Error(
86
- `Rate Limit: Provider: "${provider}" has no tiers defined for ${protocol} in limits.json`,
87
- )
88
- }
89
-
90
- return limitsConfig
91
- }
92
-
93
- const objectKeysToLowercase = <T>(obj: Record<string, T>): Record<string, T> => {
94
- const lower: Record<string, T> = {}
95
-
96
- for (const key in obj) {
97
- lower[key.toLowerCase()] = obj[key]
98
- }
99
-
100
- return lower
101
- }
102
-
103
- const parseLimits = (limits: Limits): Limits => {
104
- limits.http = objectKeysToLowercase(limits.http)
105
- limits.ws = objectKeysToLowercase(limits.ws)
106
- return limits
107
- }
108
-
109
- const calculateWSLimits = (providerLimit: WSTier): WSTier => {
110
- return {
111
- connections: providerLimit.connections,
112
- subscriptions: providerLimit.subscriptions,
113
- }
114
- }
115
-
116
- const calculateRateLimit = (providerLimit: HTTPTier): ProviderRateLimit => {
117
- let quota = providerLimit.rateLimit1m
118
- if (!quota && providerLimit?.rateLimit1h) {
119
- quota = providerLimit?.rateLimit1h / 60
120
- } else if (!quota && providerLimit?.rateLimit1s) {
121
- quota = providerLimit?.rateLimit1s * 60
122
- }
123
- return {
124
- second: providerLimit?.rateLimit1s || ((quota as number) / 60) * BURST_UNDEFINED_QUOTA_MULTIPLE,
125
- minute: quota as number,
126
- }
127
- }
@@ -1,10 +0,0 @@
1
- See: https://github.com/smartcontractkit/external-adapters-js/tree/develop/packages/sources/bank-frick for the original V2 adapter
2
-
3
- The Bank Frick adapter is a complex REST-based EA that consists of mostly non-transferrable code purpose build to run against Bank Frick. Due to limitations of the API, this adapter has to interact with the API multiple times to fetch pages of data. This behavior is unique to the Bank Frick EA specifically, so no transport has been created to accomodate this pattern (nor is there the need to create one currently since it's only the Bank Frick EA so far). Instead, this EA leverages the frameworks interfaces for its own, EA specific transport.
4
-
5
- What this example demonstrates is the V3 framework's features can be leveraged by complex implementations, and that complex implementations plug into the framework seamlessly when implementing the framework's patterns and interfacts.
6
-
7
- In this example, you will find:
8
- * A custom Transport implementation
9
- * Custom validation for configuration
10
- * (Non-V3) JWT authentication workflow