@audius/sdk 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/.eslintrc +38 -0
  2. package/.prettierrc.js +1 -0
  3. package/.python-version +1 -0
  4. package/Dockerfile +15 -0
  5. package/README.md +3 -0
  6. package/babel.config.js +3 -0
  7. package/data-contracts/ABIs/AdminUpgradeabilityProxy.json +132 -0
  8. package/data-contracts/ABIs/BaseAdminUpgradeabilityProxy.json +113 -0
  9. package/data-contracts/ABIs/BaseUpgradeabilityProxy.json +22 -0
  10. package/data-contracts/ABIs/DiscoveryProviderFactory.json +189 -0
  11. package/data-contracts/ABIs/DiscoveryProviderFactoryInterface.json +61 -0
  12. package/data-contracts/ABIs/DiscoveryProviderStorage.json +205 -0
  13. package/data-contracts/ABIs/DiscoveryProviderStorageInterface.json +65 -0
  14. package/data-contracts/ABIs/ECDSA.json +4 -0
  15. package/data-contracts/ABIs/IPLDBlacklistFactory.json +168 -0
  16. package/data-contracts/ABIs/Initializable.json +4 -0
  17. package/data-contracts/ABIs/Migrations.json +67 -0
  18. package/data-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
  19. package/data-contracts/ABIs/Ownable.json +79 -0
  20. package/data-contracts/ABIs/PlaylistFactory.json +669 -0
  21. package/data-contracts/ABIs/PlaylistFactoryInterface.json +42 -0
  22. package/data-contracts/ABIs/PlaylistStorage.json +250 -0
  23. package/data-contracts/ABIs/PlaylistStorageInterface.json +129 -0
  24. package/data-contracts/ABIs/Proxy.json +10 -0
  25. package/data-contracts/ABIs/Registry.json +240 -0
  26. package/data-contracts/ABIs/RegistryContract.json +102 -0
  27. package/data-contracts/ABIs/RegistryContractInterface.json +28 -0
  28. package/data-contracts/ABIs/RegistryInterface.json +66 -0
  29. package/data-contracts/ABIs/SigningLogic.json +43 -0
  30. package/data-contracts/ABIs/SigningLogicInitializable.json +46 -0
  31. package/data-contracts/ABIs/SocialFeatureFactory.json +460 -0
  32. package/data-contracts/ABIs/SocialFeatureStorage.json +225 -0
  33. package/data-contracts/ABIs/SocialFeatureStorageInterface.json +123 -0
  34. package/data-contracts/ABIs/TestContract.json +135 -0
  35. package/data-contracts/ABIs/TestContractInterface.json +19 -0
  36. package/data-contracts/ABIs/TestContractWithStorage.json +165 -0
  37. package/data-contracts/ABIs/TestContractWithStorageInterface.json +24 -0
  38. package/data-contracts/ABIs/TestStorage.json +144 -0
  39. package/data-contracts/ABIs/TestStorageInterface.json +42 -0
  40. package/data-contracts/ABIs/TestUserReplicaSetManager.json +432 -0
  41. package/data-contracts/ABIs/TrackFactory.json +391 -0
  42. package/data-contracts/ABIs/TrackFactoryInterface.json +73 -0
  43. package/data-contracts/ABIs/TrackStorage.json +223 -0
  44. package/data-contracts/ABIs/TrackStorageInterface.json +121 -0
  45. package/data-contracts/ABIs/UpgradeabilityProxy.json +37 -0
  46. package/data-contracts/ABIs/UserFactory.json +657 -0
  47. package/data-contracts/ABIs/UserFactoryInterface.json +65 -0
  48. package/data-contracts/ABIs/UserLibraryFactory.json +334 -0
  49. package/data-contracts/ABIs/UserReplicaSetManager.json +418 -0
  50. package/data-contracts/ABIs/UserStorage.json +233 -0
  51. package/data-contracts/ABIs/UserStorageInterface.json +93 -0
  52. package/data-contracts/signatureSchemas.ts +1236 -0
  53. package/dist/core.d.ts +446 -0
  54. package/dist/core.js +769 -0
  55. package/dist/core.js.map +1 -0
  56. package/dist/index.d.ts +689 -0
  57. package/dist/index.js +72850 -0
  58. package/dist/index.js.map +1 -0
  59. package/eth-contracts/ABIs/Address.json +4 -0
  60. package/eth-contracts/ABIs/AudiusAdminUpgradeabilityProxy.json +105 -0
  61. package/eth-contracts/ABIs/AudiusClaimDistributor.json +4968 -0
  62. package/eth-contracts/ABIs/AudiusToken.json +724 -0
  63. package/eth-contracts/ABIs/BaseUpgradeabilityProxy.json +23 -0
  64. package/eth-contracts/ABIs/Checkpointing.json +4 -0
  65. package/eth-contracts/ABIs/ClaimsManager.json +539 -0
  66. package/eth-contracts/ABIs/Context.json +11 -0
  67. package/eth-contracts/ABIs/DelegateManager.json +989 -0
  68. package/eth-contracts/ABIs/DelegateManagerV2.json +1049 -0
  69. package/eth-contracts/ABIs/DelegateManagerV2Bad.json +1049 -0
  70. package/eth-contracts/ABIs/ERC20.json +252 -0
  71. package/eth-contracts/ABIs/ERC20Burnable.json +287 -0
  72. package/eth-contracts/ABIs/ERC20Detailed.json +270 -0
  73. package/eth-contracts/ABIs/ERC20Mintable.json +364 -0
  74. package/eth-contracts/ABIs/ERC20Pausable.json +397 -0
  75. package/eth-contracts/ABIs/EthRewardsManager.json +174 -0
  76. package/eth-contracts/ABIs/Governance.json +938 -0
  77. package/eth-contracts/ABIs/GovernanceUpgraded.json +953 -0
  78. package/eth-contracts/ABIs/GovernanceV2.json +938 -0
  79. package/eth-contracts/ABIs/IERC20.json +200 -0
  80. package/eth-contracts/ABIs/Initializable.json +4 -0
  81. package/eth-contracts/ABIs/InitializableV2.json +14 -0
  82. package/eth-contracts/ABIs/Migrations.json +71 -0
  83. package/eth-contracts/ABIs/MinterRole.json +91 -0
  84. package/eth-contracts/ABIs/MockAccount.json +62 -0
  85. package/eth-contracts/ABIs/MockDelegateManager.json +55 -0
  86. package/eth-contracts/ABIs/MockStakingCaller.json +259 -0
  87. package/eth-contracts/ABIs/MockWormhole.json +106 -0
  88. package/eth-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
  89. package/eth-contracts/ABIs/Ownable.json +93 -0
  90. package/eth-contracts/ABIs/Pausable.json +150 -0
  91. package/eth-contracts/ABIs/PauserRole.json +91 -0
  92. package/eth-contracts/ABIs/Proxy.json +10 -0
  93. package/eth-contracts/ABIs/Registry.json +288 -0
  94. package/eth-contracts/ABIs/Roles.json +4 -0
  95. package/eth-contracts/ABIs/SafeERC20.json +4 -0
  96. package/eth-contracts/ABIs/SafeMath.json +4 -0
  97. package/eth-contracts/ABIs/ServiceProviderFactory.json +1153 -0
  98. package/eth-contracts/ABIs/ServiceTypeManager.json +337 -0
  99. package/eth-contracts/ABIs/Staking.json +555 -0
  100. package/eth-contracts/ABIs/StakingUpgraded.json +570 -0
  101. package/eth-contracts/ABIs/TestContract.json +44 -0
  102. package/eth-contracts/ABIs/TrustedNotifierManager.json +265 -0
  103. package/eth-contracts/ABIs/Uint256Helpers.json +4 -0
  104. package/eth-contracts/ABIs/UpgradeabilityProxy.json +40 -0
  105. package/eth-contracts/ABIs/Wormhole.json +45 -0
  106. package/eth-contracts/ABIs/WormholeClient.json +155 -0
  107. package/examples/file.mp3 +0 -0
  108. package/examples/initAudiusLibs.js +86 -0
  109. package/examples/initializeVersions.js +95 -0
  110. package/examples/pic.jpg +0 -0
  111. package/initScripts/configureLocalDiscProv.js +167 -0
  112. package/initScripts/helpers/claim.js +43 -0
  113. package/initScripts/helpers/distributeTokens.js +24 -0
  114. package/initScripts/helpers/spRegistration.js +138 -0
  115. package/initScripts/helpers/utils.js +34 -0
  116. package/initScripts/helpers/version.js +93 -0
  117. package/initScripts/local.js +617 -0
  118. package/initScripts/mainnet.js +131 -0
  119. package/initScripts/manageProdRelayerWallets.js +191 -0
  120. package/package.json +125 -0
  121. package/rollup.config.js +164 -0
  122. package/scripts/AudiusClaimDistributor.json +4968 -0
  123. package/scripts/Wormhole.json +155 -0
  124. package/scripts/addCIDToIpldBlacklist.js +124 -0
  125. package/scripts/circleci-test.sh +53 -0
  126. package/scripts/communityRewards/transferCommunityRewardsToSolana.js +222 -0
  127. package/scripts/ipfs.sh +58 -0
  128. package/scripts/migrate_contracts.sh +25 -0
  129. package/scripts/reset.sh +65 -0
  130. package/scripts/test.sh +77 -0
  131. package/src/api/account.js +670 -0
  132. package/src/api/base.js +122 -0
  133. package/src/api/file.js +168 -0
  134. package/src/api/playlist.js +328 -0
  135. package/src/api/rewards.d.ts +4 -0
  136. package/src/api/rewards.js +682 -0
  137. package/src/api/serviceProvider.js +154 -0
  138. package/src/api/track.js +604 -0
  139. package/src/api/user.js +888 -0
  140. package/src/api/user.test.js +172 -0
  141. package/src/constants.ts +7 -0
  142. package/src/core.ts +3 -0
  143. package/src/index.js +6 -0
  144. package/src/libs.d.ts +3 -0
  145. package/src/libs.js +619 -0
  146. package/src/sanityChecks/addSecondaries.js +40 -0
  147. package/src/sanityChecks/assignReplicaSetIfNecessary.js +10 -0
  148. package/src/sanityChecks/index.d.ts +9 -0
  149. package/src/sanityChecks/index.js +31 -0
  150. package/src/sanityChecks/isCreator.js +73 -0
  151. package/src/sanityChecks/needsRecoveryEmail.js +20 -0
  152. package/src/sanityChecks/rolloverNodes.js +74 -0
  153. package/src/sanityChecks/sanitizeNodes.js +24 -0
  154. package/src/sanityChecks/syncNodes.js +28 -0
  155. package/src/sdk/constants.ts +10 -0
  156. package/src/sdk/index.ts +1 -0
  157. package/src/sdk/oauth/Oauth.ts +265 -0
  158. package/src/sdk/oauth/index.ts +1 -0
  159. package/src/sdk/sdk.ts +102 -0
  160. package/src/service-selection/ServiceSelection.test.ts +320 -0
  161. package/src/service-selection/ServiceSelection.ts +460 -0
  162. package/src/service-selection/constants.ts +14 -0
  163. package/src/service-selection/index.ts +1 -0
  164. package/src/services/ABIDecoder/AudiusABIDecoder.ts +71 -0
  165. package/src/services/ABIDecoder/index.ts +1 -0
  166. package/src/services/comstock/Comstock.ts +39 -0
  167. package/src/services/comstock/index.ts +1 -0
  168. package/src/services/contracts/ContractClient.ts +227 -0
  169. package/src/services/contracts/GovernedContractClient.ts +53 -0
  170. package/src/services/contracts/ProviderSelection.ts +42 -0
  171. package/src/services/creatorNode/CreatorNode.ts +1065 -0
  172. package/src/services/creatorNode/CreatorNodeSelection.test.ts +997 -0
  173. package/src/services/creatorNode/CreatorNodeSelection.ts +488 -0
  174. package/src/services/creatorNode/constants.ts +10 -0
  175. package/src/services/creatorNode/index.ts +2 -0
  176. package/src/services/dataContracts/AudiusContracts.ts +234 -0
  177. package/src/services/dataContracts/IPLDBlacklistFactoryClient.ts +73 -0
  178. package/src/services/dataContracts/PlaylistFactoryClient.ts +370 -0
  179. package/src/services/dataContracts/RegistryClient.ts +95 -0
  180. package/src/services/dataContracts/SocialFeatureFactoryClient.ts +196 -0
  181. package/src/services/dataContracts/TrackFactoryClient.ts +131 -0
  182. package/src/services/dataContracts/UserFactoryClient.ts +351 -0
  183. package/src/services/dataContracts/UserLibraryFactoryClient.ts +115 -0
  184. package/src/services/dataContracts/UserReplicaSetManagerClient.ts +206 -0
  185. package/src/services/dataContracts/index.ts +1 -0
  186. package/src/services/discoveryProvider/DiscoveryProvider.ts +1168 -0
  187. package/src/services/discoveryProvider/DiscoveryProviderSelection.test.ts +536 -0
  188. package/src/services/discoveryProvider/DiscoveryProviderSelection.ts +383 -0
  189. package/src/services/discoveryProvider/constants.ts +13 -0
  190. package/src/services/discoveryProvider/index.ts +1 -0
  191. package/src/services/discoveryProvider/requests.ts +629 -0
  192. package/src/services/ethContracts/AudiusTokenClient.ts +163 -0
  193. package/src/services/ethContracts/ClaimDistributionClient.ts +45 -0
  194. package/src/services/ethContracts/ClaimsManagerClient.ts +102 -0
  195. package/src/services/ethContracts/DelegateManagerClient.ts +480 -0
  196. package/src/services/ethContracts/EthContracts.ts +359 -0
  197. package/src/services/ethContracts/EthRewardsManagerClient.ts +33 -0
  198. package/src/services/ethContracts/GovernanceClient.ts +451 -0
  199. package/src/services/ethContracts/RegistryClient.ts +33 -0
  200. package/src/services/ethContracts/ServiceProviderFactoryClient.ts +691 -0
  201. package/src/services/ethContracts/ServiceTypeManagerClient.ts +112 -0
  202. package/src/services/ethContracts/StakingProxyClient.ts +97 -0
  203. package/src/services/ethContracts/TrustedNotifierManagerClient.ts +101 -0
  204. package/src/services/ethContracts/WormholeClient.ts +97 -0
  205. package/src/services/ethContracts/index.ts +1 -0
  206. package/src/services/ethWeb3Manager/EthWeb3Manager.ts +239 -0
  207. package/src/services/ethWeb3Manager/index.ts +1 -0
  208. package/src/services/hedgehog/Hedgehog.ts +96 -0
  209. package/src/services/hedgehog/index.ts +1 -0
  210. package/src/services/identity/IdentityService.ts +551 -0
  211. package/src/services/identity/index.ts +1 -0
  212. package/src/services/identity/requests.ts +65 -0
  213. package/src/services/schemaValidator/SchemaValidator.ts +105 -0
  214. package/src/services/schemaValidator/index.ts +1 -0
  215. package/src/services/schemaValidator/schemas/trackSchema.json +267 -0
  216. package/src/services/schemaValidator/schemas/userSchema.json +230 -0
  217. package/src/services/solanaAudiusData/errors.ts +20 -0
  218. package/src/services/solanaAudiusData/index.ts +1189 -0
  219. package/src/services/solanaWeb3Manager/errors.js +101 -0
  220. package/src/services/solanaWeb3Manager/index.d.ts +46 -0
  221. package/src/services/solanaWeb3Manager/index.js +655 -0
  222. package/src/services/solanaWeb3Manager/padBNToUint8Array.ts +7 -0
  223. package/src/services/solanaWeb3Manager/rewards.js +941 -0
  224. package/src/services/solanaWeb3Manager/rewardsAttester.ts +1093 -0
  225. package/src/services/solanaWeb3Manager/tokenAccount.js +149 -0
  226. package/src/services/solanaWeb3Manager/transactionHandler.js +345 -0
  227. package/src/services/solanaWeb3Manager/transfer.js +272 -0
  228. package/src/services/solanaWeb3Manager/userBank.js +160 -0
  229. package/src/services/solanaWeb3Manager/utils.d.ts +31 -0
  230. package/src/services/solanaWeb3Manager/utils.js +163 -0
  231. package/src/services/solanaWeb3Manager/wAudio.js +28 -0
  232. package/src/services/solanaWeb3Manager/wAudio.test.js +30 -0
  233. package/src/services/web3Manager/Web3Config.ts +14 -0
  234. package/src/services/web3Manager/Web3Manager.ts +360 -0
  235. package/src/services/web3Manager/XMLHttpRequest.ts +11 -0
  236. package/src/services/web3Manager/index.ts +2 -0
  237. package/src/services/wormhole/index.js +424 -0
  238. package/src/types.ts +8 -0
  239. package/src/userStateManager.ts +53 -0
  240. package/src/utils/apiSigning.ts +51 -0
  241. package/src/utils/captcha.ts +97 -0
  242. package/src/utils/estimateGas.ts +64 -0
  243. package/src/utils/fileHasher.ts +278 -0
  244. package/src/utils/importContractABI.d.ts +9 -0
  245. package/src/utils/importContractABI.js +19 -0
  246. package/src/utils/index.ts +11 -0
  247. package/src/utils/multiProvider.ts +72 -0
  248. package/src/utils/network.test.ts +127 -0
  249. package/src/utils/network.ts +308 -0
  250. package/src/utils/promiseFight.test.ts +87 -0
  251. package/src/utils/promiseFight.ts +36 -0
  252. package/src/utils/signatures.ts +139 -0
  253. package/src/utils/types.ts +34 -0
  254. package/src/utils/utils.test.ts +36 -0
  255. package/src/utils/utils.ts +235 -0
  256. package/src/utils/uuid.ts +14 -0
  257. package/src/web3.d.ts +9 -0
  258. package/src/web3.js +8 -0
  259. package/tests/assets/static_image.png +0 -0
  260. package/tests/assets/static_text.txt +1 -0
  261. package/tests/audiusTokenClientTest.js +37 -0
  262. package/tests/creatorNodeTest.js +19 -0
  263. package/tests/fileHasherTest.js +125 -0
  264. package/tests/governanceTest.js +382 -0
  265. package/tests/helpers.js +105 -0
  266. package/tests/index.js +14 -0
  267. package/tests/playlistClientTest.js +157 -0
  268. package/tests/providerSelectionTest.js +241 -0
  269. package/tests/registryClientTest.js +19 -0
  270. package/tests/rewardsAttesterTest.js +373 -0
  271. package/tests/serviceTypeManagerClientTest.js +33 -0
  272. package/tests/socialFeatureClientTest.js +79 -0
  273. package/tests/stakingTest.js +302 -0
  274. package/tests/trackClientTest.js +86 -0
  275. package/tests/userClientTest.js +121 -0
  276. package/tsconfig.json +10 -0
  277. package/types/@audius-hedgehog/index.d.ts +39 -0
  278. package/types/abi-decoder/index.d.ts +41 -0
@@ -0,0 +1,320 @@
1
+ import { ServiceSelection } from './ServiceSelection'
2
+ import nock from 'nock'
3
+ import assert from 'assert'
4
+ import { Utils } from '../utils'
5
+ import type { AxiosResponse } from 'axios'
6
+
7
+ describe('ServiceSelection', () => {
8
+ it('prefers a healthy service', async () => {
9
+ const good = 'https://good.audius.co'
10
+ nock(good).get('/health_check').reply(200)
11
+
12
+ const bad = 'https://bad.audius.co'
13
+ nock(bad).get('/health_check').reply(400)
14
+
15
+ const getServices = async () => [good, bad] as string[]
16
+
17
+ const s = new ServiceSelection({
18
+ getServices
19
+ })
20
+ const service = await s.select()
21
+ assert.strictEqual(service, good)
22
+ })
23
+
24
+ it('prefers a faster service', async () => {
25
+ const fast = 'https://fast.audius.co'
26
+ nock(fast).get('/health_check').reply(200)
27
+
28
+ const slow = 'https://slow.audius.co'
29
+ nock(slow).get('/health_check').delay(200).reply(400)
30
+
31
+ const s = new ServiceSelection({
32
+ getServices: async () => [fast, slow]
33
+ })
34
+ const service = await s.select()
35
+ assert.strictEqual(service, fast)
36
+ })
37
+
38
+ it('prefers a slower healthy service', async () => {
39
+ const fast = 'https://fast.audius.co'
40
+ nock(fast).get('/health_check').reply(400)
41
+
42
+ const slow = 'https://slow.audius.co'
43
+ nock(slow).get('/health_check').delay(200).reply(200)
44
+
45
+ const s = new ServiceSelection({
46
+ getServices: async () => [fast, slow]
47
+ })
48
+ const service = await s.select()
49
+ assert.strictEqual(service, slow)
50
+ assert.deepStrictEqual(s.unhealthy, new Set([fast]))
51
+ })
52
+
53
+ it('should find the needle in the haystack', async () => {
54
+ // Single good service
55
+ const needle = 'https://needle.audius.co'
56
+ nock(needle).get('/health_check').reply(200)
57
+ // Many bad services
58
+ const haystack = Array.from(
59
+ { length: 20 },
60
+ (_, i) => `https://${i}.audius.co`
61
+ )
62
+ haystack.forEach((hay) => {
63
+ nock(hay).get('/health_check').reply(400)
64
+ })
65
+
66
+ const s = new ServiceSelection({
67
+ getServices: async () => [...haystack, needle],
68
+ maxConcurrentRequests: 2,
69
+ requestTimeout: 100
70
+ })
71
+ const service = await s.select()
72
+ assert.strictEqual(service, needle)
73
+ })
74
+
75
+ it('should pick null if there is no healthy service', async () => {
76
+ const bad1 = 'https://bad1.audius.co'
77
+ nock(bad1).get('/health_check').reply(400)
78
+
79
+ const bad2 = 'https://bad2.audius.co'
80
+ nock(bad2).get('/health_check').reply(400)
81
+
82
+ const s = new ServiceSelection({
83
+ getServices: async () => [bad1, bad2],
84
+ // Short timeout otherwise, we'll wait for a long time for some request to succeed
85
+ // TODO: consider ammending promiseFight to early exit
86
+ requestTimeout: 100
87
+ })
88
+ const service = await s.select()
89
+ assert.strictEqual(service, null)
90
+ })
91
+
92
+ it('respects a whitelist', async () => {
93
+ const fast = 'https://fast.audius.co'
94
+ nock(fast).get('/health_check').reply(200)
95
+
96
+ const slow = 'https://slow.audius.co'
97
+ nock(slow).get('/health_check').delay(200).reply(200)
98
+
99
+ const s = new ServiceSelection({
100
+ getServices: async () => [fast, slow],
101
+ whitelist: new Set([slow])
102
+ })
103
+ const service = await s.select()
104
+ assert.strictEqual(service, slow)
105
+ })
106
+
107
+ it('respects a blacklist', async () => {
108
+ const fast = 'https://fast.audius.co'
109
+ nock(fast).get('/health_check').reply(200)
110
+
111
+ const slow = 'https://slow.audius.co'
112
+ nock(slow).get('/health_check').delay(200).reply(200)
113
+
114
+ const s = new ServiceSelection({
115
+ getServices: async () => [fast, slow],
116
+ blacklist: new Set([fast])
117
+ })
118
+ const service = await s.select()
119
+ assert.strictEqual(service, slow)
120
+ })
121
+
122
+ it('will recheck unhealthy ones', async () => {
123
+ const atFirstHealthy = 'https://atFirstHealthy.audius.co'
124
+ nock(atFirstHealthy).get('/health_check').reply(200)
125
+ nock(atFirstHealthy).get('/health_check').reply(400)
126
+
127
+ const atFirstUnhealthy = 'https://atFirstUnhealthy.audius.co'
128
+ nock(atFirstUnhealthy).get('/health_check').reply(400)
129
+ nock(atFirstUnhealthy).get('/health_check').reply(200)
130
+
131
+ const s = new ServiceSelection({
132
+ getServices: async () => [atFirstHealthy, atFirstUnhealthy],
133
+ unhealthyTTL: 0
134
+ })
135
+ const firstService = await s.select()
136
+ assert.strictEqual(firstService, atFirstHealthy)
137
+
138
+ // Push the event loop just to let the unhealthy list get cleared
139
+ await Utils.wait(0)
140
+ const secondService = await s.select()
141
+ assert.strictEqual(secondService, atFirstUnhealthy)
142
+ })
143
+ })
144
+
145
+ describe('ServiceSelection withBackupCriteria', () => {
146
+ class ServiceSelectionWithBackupCriteria extends ServiceSelection {
147
+ override isHealthy(
148
+ response: AxiosResponse,
149
+ urlMap: Record<string, string>
150
+ ) {
151
+ if (response.status === 200) {
152
+ if (response.data.behind) {
153
+ const service = urlMap[response.config.url ?? '']
154
+ if (service) {
155
+ this.addBackup(service, response.data)
156
+ return false
157
+ } else {
158
+ return true
159
+ }
160
+ }
161
+ return true
162
+ }
163
+ return false
164
+ }
165
+ }
166
+
167
+ // Crude example of how backups can be used
168
+ it('adds backups', async () => {
169
+ const behind1 = 'https://behind1.audius.co'
170
+ nock(behind1).get('/health_check').reply(200, {
171
+ behind: true
172
+ })
173
+
174
+ const behind2 = 'https://behind2.audius.co'
175
+ nock(behind2).get('/health_check').reply(200, {
176
+ behind: true
177
+ })
178
+
179
+ const ok = 'https://ok.audius.co'
180
+ nock(ok).get('/health_check').delay(100).reply(200, {
181
+ behind: false
182
+ })
183
+
184
+ const s = new ServiceSelectionWithBackupCriteria({
185
+ getServices: async () => [behind1, behind2, ok]
186
+ })
187
+ const service = await s.select()
188
+ assert.strictEqual(service, ok)
189
+ assert.deepStrictEqual(s.backups, {
190
+ [behind1]: { behind: true },
191
+ [behind2]: { behind: true }
192
+ })
193
+ })
194
+
195
+ it('should use a backup if there is no better option', async () => {
196
+ // Single service that's behind
197
+ const needle = 'https://needle.audius.co'
198
+ nock(needle).get('/health_check').reply(200, {
199
+ behind: true
200
+ })
201
+ // Many bad services
202
+ const haystack = Array.from(
203
+ { length: 20 },
204
+ (_, i) => `https://${i}.audius.co`
205
+ )
206
+ haystack.forEach((hay) => {
207
+ nock(hay).get('/health_check').reply(400)
208
+ })
209
+
210
+ const s = new ServiceSelectionWithBackupCriteria({
211
+ getServices: async () => [...haystack, needle],
212
+ maxConcurrentRequests: 2,
213
+ requestTimeout: 100
214
+ })
215
+ const service = await s.select()
216
+ assert.strictEqual(service, needle)
217
+ // It should have tried everything before falling back to the "needle"
218
+ assert.strictEqual(s.getTotalAttempts(), 21)
219
+ })
220
+
221
+ it('should skip over a backup if a better service can be found', async () => {
222
+ // Single good service
223
+ const needle = 'https://needle.audius.co'
224
+ nock(needle).get('/health_check').reply(200)
225
+ // Single service that's behind
226
+ const behind = 'https://behind.audius.co'
227
+ nock(behind).get('/health_check').reply(200, {
228
+ behind: true
229
+ })
230
+ // Many bad services
231
+ const haystack = Array.from(
232
+ { length: 20 },
233
+ (_, i) => `https://${i}.audius.co`
234
+ )
235
+ haystack.forEach((hay) => {
236
+ nock(hay).get('/health_check').reply(400)
237
+ })
238
+
239
+ const s = new ServiceSelectionWithBackupCriteria({
240
+ getServices: async () => [behind, ...haystack, needle],
241
+ maxConcurrentRequests: 2,
242
+ requestTimeout: 100
243
+ })
244
+ const service = await s.select()
245
+ assert.strictEqual(service, needle)
246
+ })
247
+ })
248
+
249
+ describe('ServiceSelection withShortCircuit', () => {
250
+ const shortcircuit = 'https://shortcircuit.audius.co'
251
+ class ServiceSelectionWithShortCircuit extends ServiceSelection {
252
+ override shortcircuit() {
253
+ return shortcircuit
254
+ }
255
+ }
256
+
257
+ it('uses a short circuit', async () => {
258
+ const other = 'https://other.audius.co'
259
+ nock(other).get('/health_check').reply(200, {
260
+ behind: true
261
+ })
262
+
263
+ const s = new ServiceSelectionWithShortCircuit({
264
+ getServices: async () => [other]
265
+ })
266
+ const service = await s.select()
267
+ assert.strictEqual(service, shortcircuit)
268
+ })
269
+
270
+ it('does not use a short circuit when a blacklist is present', async () => {
271
+ const other = 'https://other.audius.co'
272
+ nock(other).get('/health_check').reply(200, {
273
+ behind: true
274
+ })
275
+
276
+ const s = new ServiceSelectionWithShortCircuit({
277
+ getServices: async () => [other],
278
+ blacklist: new Set([shortcircuit])
279
+ })
280
+ const service = await s.select()
281
+ assert.strictEqual(service, other)
282
+ })
283
+ })
284
+
285
+ describe('ServiceSelection findAll', () => {
286
+ it('can find all the healthy services', async () => {
287
+ const a = 'https://a.audius.co'
288
+ nock(a).get('/health_check').reply(200)
289
+
290
+ const b = 'https://b.audius.co'
291
+ nock(b).get('/health_check').reply(200)
292
+
293
+ const c = 'https://c.audius.co'
294
+ nock(c).get('/health_check').reply(400)
295
+
296
+ const s = new ServiceSelection({
297
+ getServices: async () => [a, b, c]
298
+ })
299
+ const all = await s.findAll()
300
+ assert.deepStrictEqual(all, [a, b])
301
+ })
302
+
303
+ it('will drop slow services', async () => {
304
+ const a = 'https://a.audius.co'
305
+ nock(a).get('/health_check').delay(200).reply(200)
306
+
307
+ const b = 'https://b.audius.co'
308
+ nock(b).get('/health_check').reply(200)
309
+
310
+ const c = 'https://c.audius.co'
311
+ nock(c).get('/health_check').reply(200)
312
+
313
+ const s = new ServiceSelection({
314
+ getServices: async () => [a, b, c],
315
+ requestTimeout: 100
316
+ })
317
+ const all = await s.findAll()
318
+ assert.deepStrictEqual(all, [b, c])
319
+ })
320
+ })