coinbase-api 0.3.2 → 1.0.1

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 (218) hide show
  1. package/README.md +438 -14
  2. package/dist/cjs/CBAdvancedTradeClient.d.ts +559 -0
  3. package/dist/cjs/CBAdvancedTradeClient.js +574 -0
  4. package/dist/cjs/CBAdvancedTradeClient.js.map +1 -0
  5. package/dist/cjs/CBAppClient.d.ts +359 -0
  6. package/dist/cjs/CBAppClient.js +336 -0
  7. package/dist/cjs/CBAppClient.js.map +1 -0
  8. package/dist/cjs/CBCommerceClient.d.ts +110 -0
  9. package/dist/cjs/CBCommerceClient.js +105 -0
  10. package/dist/cjs/CBCommerceClient.js.map +1 -0
  11. package/dist/cjs/CBExchangeClient.d.ts +640 -0
  12. package/dist/cjs/CBExchangeClient.js +751 -0
  13. package/dist/cjs/CBExchangeClient.js.map +1 -0
  14. package/dist/cjs/CBInternationalClient.d.ts +381 -0
  15. package/dist/cjs/CBInternationalClient.js +437 -0
  16. package/dist/cjs/CBInternationalClient.js.map +1 -0
  17. package/dist/cjs/CBPrimeClient.d.ts +363 -0
  18. package/dist/cjs/CBPrimeClient.js +451 -0
  19. package/dist/cjs/CBPrimeClient.js.map +1 -0
  20. package/dist/cjs/WebsocketClient.d.ts +78 -0
  21. package/dist/cjs/WebsocketClient.js +534 -0
  22. package/dist/cjs/WebsocketClient.js.map +1 -0
  23. package/dist/cjs/index.d.ts +13 -0
  24. package/dist/cjs/index.js +30 -0
  25. package/dist/cjs/index.js.map +1 -0
  26. package/dist/cjs/lib/BaseRestClient.d.ts +66 -0
  27. package/dist/cjs/lib/BaseRestClient.js +436 -0
  28. package/dist/cjs/lib/BaseRestClient.js.map +1 -0
  29. package/dist/cjs/lib/BaseWSClient.d.ts +169 -0
  30. package/dist/cjs/lib/BaseWSClient.js +638 -0
  31. package/dist/cjs/lib/BaseWSClient.js.map +1 -0
  32. package/dist/cjs/lib/jwtNode.d.ts +13 -0
  33. package/dist/cjs/lib/jwtNode.js +52 -0
  34. package/dist/cjs/lib/jwtNode.js.map +1 -0
  35. package/dist/cjs/lib/misc-util.d.ts +1 -0
  36. package/dist/cjs/lib/misc-util.js +7 -0
  37. package/dist/cjs/lib/misc-util.js.map +1 -0
  38. package/dist/cjs/lib/requestUtils.d.ts +98 -0
  39. package/dist/cjs/lib/requestUtils.js +75 -0
  40. package/dist/cjs/lib/requestUtils.js.map +1 -0
  41. package/dist/cjs/lib/webCryptoAPI.d.ts +10 -0
  42. package/dist/cjs/lib/webCryptoAPI.js +83 -0
  43. package/dist/cjs/lib/webCryptoAPI.js.map +1 -0
  44. package/dist/cjs/lib/websocket/WsStore.d.ts +63 -0
  45. package/dist/cjs/lib/websocket/WsStore.js +254 -0
  46. package/dist/cjs/lib/websocket/WsStore.js.map +1 -0
  47. package/dist/cjs/lib/websocket/WsStore.types.d.ts +49 -0
  48. package/dist/cjs/lib/websocket/WsStore.types.js +14 -0
  49. package/dist/cjs/lib/websocket/WsStore.types.js.map +1 -0
  50. package/dist/cjs/lib/websocket/logger.d.ts +6 -0
  51. package/dist/cjs/lib/websocket/logger.js +16 -0
  52. package/dist/cjs/lib/websocket/logger.js.map +1 -0
  53. package/dist/cjs/lib/websocket/typeGuards.d.ts +27 -0
  54. package/dist/cjs/lib/websocket/typeGuards.js +86 -0
  55. package/dist/cjs/lib/websocket/typeGuards.js.map +1 -0
  56. package/dist/cjs/lib/websocket/websocket-util.d.ts +120 -0
  57. package/dist/cjs/lib/websocket/websocket-util.js +173 -0
  58. package/dist/cjs/lib/websocket/websocket-util.js.map +1 -0
  59. package/dist/cjs/package.json +3 -0
  60. package/dist/cjs/types/request/advanced-trade-client.d.ts +194 -0
  61. package/dist/cjs/types/request/advanced-trade-client.js +18 -0
  62. package/dist/cjs/types/request/advanced-trade-client.js.map +1 -0
  63. package/dist/cjs/types/request/coinbase-app-client.d.ts +80 -0
  64. package/dist/cjs/types/request/coinbase-app-client.js +28 -0
  65. package/dist/cjs/types/request/coinbase-app-client.js.map +1 -0
  66. package/dist/cjs/types/request/coinbase-exchange.d.ts +332 -0
  67. package/dist/cjs/types/request/coinbase-exchange.js +3 -0
  68. package/dist/cjs/types/request/coinbase-exchange.js.map +1 -0
  69. package/dist/cjs/types/request/coinbase-international.d.ts +160 -0
  70. package/dist/cjs/types/request/coinbase-international.js +13 -0
  71. package/dist/cjs/types/request/coinbase-international.js.map +1 -0
  72. package/dist/cjs/types/request/coinbase-prime.d.ts +298 -0
  73. package/dist/cjs/types/request/coinbase-prime.js +8 -0
  74. package/dist/cjs/types/request/coinbase-prime.js.map +1 -0
  75. package/dist/cjs/types/response/advanced-trade-client.d.ts +759 -0
  76. package/dist/cjs/types/response/advanced-trade-client.js +8 -0
  77. package/dist/cjs/types/response/advanced-trade-client.js.map +1 -0
  78. package/dist/cjs/types/response/coinbase-app-client.d.ts +168 -0
  79. package/dist/cjs/types/response/coinbase-app-client.js +18 -0
  80. package/dist/cjs/types/response/coinbase-app-client.js.map +1 -0
  81. package/dist/cjs/types/response/coinbase-exchange.d.ts +80 -0
  82. package/dist/cjs/types/response/coinbase-exchange.js +82 -0
  83. package/dist/cjs/types/response/coinbase-exchange.js.map +1 -0
  84. package/dist/cjs/types/response/coinbase-international.d.ts +40 -0
  85. package/dist/cjs/types/response/coinbase-international.js +42 -0
  86. package/dist/cjs/types/response/coinbase-international.js.map +1 -0
  87. package/dist/cjs/types/response/coinbase-prime.d.ts +70 -0
  88. package/dist/cjs/types/response/coinbase-prime.js +72 -0
  89. package/dist/cjs/types/response/coinbase-prime.js.map +1 -0
  90. package/dist/cjs/types/response/ws.d.ts +7 -0
  91. package/dist/cjs/types/response/ws.js +3 -0
  92. package/dist/cjs/types/response/ws.js.map +1 -0
  93. package/dist/cjs/types/shared.types.d.ts +60 -0
  94. package/dist/cjs/types/shared.types.js +3 -0
  95. package/dist/cjs/types/shared.types.js.map +1 -0
  96. package/dist/cjs/types/websockets/client.d.ts +73 -0
  97. package/dist/cjs/types/websockets/client.js +3 -0
  98. package/dist/cjs/types/websockets/client.js.map +1 -0
  99. package/dist/cjs/types/websockets/events.d.ts +40 -0
  100. package/dist/cjs/types/websockets/events.js +3 -0
  101. package/dist/cjs/types/websockets/events.js.map +1 -0
  102. package/dist/cjs/types/websockets/requests.d.ts +76 -0
  103. package/dist/cjs/types/websockets/requests.js +3 -0
  104. package/dist/cjs/types/websockets/requests.js.map +1 -0
  105. package/dist/cjs/types/websockets/wsAPI.d.ts +9 -0
  106. package/dist/cjs/types/websockets/wsAPI.js +3 -0
  107. package/dist/cjs/types/websockets/wsAPI.js.map +1 -0
  108. package/dist/mjs/CBAdvancedTradeClient.d.ts +559 -0
  109. package/dist/mjs/CBAdvancedTradeClient.js +570 -0
  110. package/dist/mjs/CBAdvancedTradeClient.js.map +1 -0
  111. package/dist/mjs/CBAppClient.d.ts +359 -0
  112. package/dist/mjs/CBAppClient.js +332 -0
  113. package/dist/mjs/CBAppClient.js.map +1 -0
  114. package/dist/mjs/CBCommerceClient.d.ts +110 -0
  115. package/dist/mjs/CBCommerceClient.js +101 -0
  116. package/dist/mjs/CBCommerceClient.js.map +1 -0
  117. package/dist/mjs/CBExchangeClient.d.ts +640 -0
  118. package/dist/mjs/CBExchangeClient.js +747 -0
  119. package/dist/mjs/CBExchangeClient.js.map +1 -0
  120. package/dist/mjs/CBInternationalClient.d.ts +381 -0
  121. package/dist/mjs/CBInternationalClient.js +433 -0
  122. package/dist/mjs/CBInternationalClient.js.map +1 -0
  123. package/dist/mjs/CBPrimeClient.d.ts +363 -0
  124. package/dist/mjs/CBPrimeClient.js +447 -0
  125. package/dist/mjs/CBPrimeClient.js.map +1 -0
  126. package/dist/mjs/WebsocketClient.d.ts +78 -0
  127. package/dist/mjs/WebsocketClient.js +530 -0
  128. package/dist/mjs/WebsocketClient.js.map +1 -0
  129. package/dist/mjs/index.d.ts +13 -0
  130. package/dist/mjs/index.js +14 -0
  131. package/dist/mjs/index.js.map +1 -0
  132. package/dist/mjs/lib/BaseRestClient.d.ts +66 -0
  133. package/dist/mjs/lib/BaseRestClient.js +429 -0
  134. package/dist/mjs/lib/BaseRestClient.js.map +1 -0
  135. package/dist/mjs/lib/BaseWSClient.d.ts +169 -0
  136. package/dist/mjs/lib/BaseWSClient.js +631 -0
  137. package/dist/mjs/lib/BaseWSClient.js.map +1 -0
  138. package/dist/mjs/lib/jwtNode.d.ts +13 -0
  139. package/dist/mjs/lib/jwtNode.js +45 -0
  140. package/dist/mjs/lib/jwtNode.js.map +1 -0
  141. package/dist/mjs/lib/misc-util.d.ts +1 -0
  142. package/dist/mjs/lib/misc-util.js +4 -0
  143. package/dist/mjs/lib/misc-util.js.map +1 -0
  144. package/dist/mjs/lib/requestUtils.d.ts +98 -0
  145. package/dist/mjs/lib/requestUtils.js +69 -0
  146. package/dist/mjs/lib/requestUtils.js.map +1 -0
  147. package/dist/mjs/lib/webCryptoAPI.d.ts +10 -0
  148. package/dist/mjs/lib/webCryptoAPI.js +79 -0
  149. package/dist/mjs/lib/webCryptoAPI.js.map +1 -0
  150. package/dist/mjs/lib/websocket/WsStore.d.ts +63 -0
  151. package/dist/mjs/lib/websocket/WsStore.js +249 -0
  152. package/dist/mjs/lib/websocket/WsStore.js.map +1 -0
  153. package/dist/mjs/lib/websocket/WsStore.types.d.ts +49 -0
  154. package/dist/mjs/lib/websocket/WsStore.types.js +11 -0
  155. package/dist/mjs/lib/websocket/WsStore.types.js.map +1 -0
  156. package/dist/mjs/lib/websocket/logger.d.ts +6 -0
  157. package/dist/mjs/lib/websocket/logger.js +13 -0
  158. package/dist/mjs/lib/websocket/logger.js.map +1 -0
  159. package/dist/mjs/lib/websocket/typeGuards.d.ts +27 -0
  160. package/dist/mjs/lib/websocket/typeGuards.js +78 -0
  161. package/dist/mjs/lib/websocket/typeGuards.js.map +1 -0
  162. package/dist/mjs/lib/websocket/websocket-util.d.ts +120 -0
  163. package/dist/mjs/lib/websocket/websocket-util.js +164 -0
  164. package/dist/mjs/lib/websocket/websocket-util.js.map +1 -0
  165. package/dist/mjs/package.json +3 -0
  166. package/dist/mjs/types/request/advanced-trade-client.d.ts +194 -0
  167. package/dist/mjs/types/request/advanced-trade-client.js +17 -0
  168. package/dist/mjs/types/request/advanced-trade-client.js.map +1 -0
  169. package/dist/mjs/types/request/coinbase-app-client.d.ts +80 -0
  170. package/dist/mjs/types/request/coinbase-app-client.js +27 -0
  171. package/dist/mjs/types/request/coinbase-app-client.js.map +1 -0
  172. package/dist/mjs/types/request/coinbase-exchange.d.ts +332 -0
  173. package/dist/mjs/types/request/coinbase-exchange.js +2 -0
  174. package/dist/mjs/types/request/coinbase-exchange.js.map +1 -0
  175. package/dist/mjs/types/request/coinbase-international.d.ts +160 -0
  176. package/dist/mjs/types/request/coinbase-international.js +12 -0
  177. package/dist/mjs/types/request/coinbase-international.js.map +1 -0
  178. package/dist/mjs/types/request/coinbase-prime.d.ts +298 -0
  179. package/dist/mjs/types/request/coinbase-prime.js +7 -0
  180. package/dist/mjs/types/request/coinbase-prime.js.map +1 -0
  181. package/dist/mjs/types/response/advanced-trade-client.d.ts +759 -0
  182. package/dist/mjs/types/response/advanced-trade-client.js +7 -0
  183. package/dist/mjs/types/response/advanced-trade-client.js.map +1 -0
  184. package/dist/mjs/types/response/coinbase-app-client.d.ts +168 -0
  185. package/dist/mjs/types/response/coinbase-app-client.js +17 -0
  186. package/dist/mjs/types/response/coinbase-app-client.js.map +1 -0
  187. package/dist/mjs/types/response/coinbase-exchange.d.ts +80 -0
  188. package/dist/mjs/types/response/coinbase-exchange.js +82 -0
  189. package/dist/mjs/types/response/coinbase-exchange.js.map +1 -0
  190. package/dist/mjs/types/response/coinbase-international.d.ts +40 -0
  191. package/dist/mjs/types/response/coinbase-international.js +42 -0
  192. package/dist/mjs/types/response/coinbase-international.js.map +1 -0
  193. package/dist/mjs/types/response/coinbase-prime.d.ts +70 -0
  194. package/dist/mjs/types/response/coinbase-prime.js +72 -0
  195. package/dist/mjs/types/response/coinbase-prime.js.map +1 -0
  196. package/dist/mjs/types/response/ws.d.ts +7 -0
  197. package/dist/mjs/types/response/ws.js +2 -0
  198. package/dist/mjs/types/response/ws.js.map +1 -0
  199. package/dist/mjs/types/shared.types.d.ts +60 -0
  200. package/dist/mjs/types/shared.types.js +2 -0
  201. package/dist/mjs/types/shared.types.js.map +1 -0
  202. package/dist/mjs/types/websockets/client.d.ts +73 -0
  203. package/dist/mjs/types/websockets/client.js +2 -0
  204. package/dist/mjs/types/websockets/client.js.map +1 -0
  205. package/dist/mjs/types/websockets/events.d.ts +40 -0
  206. package/dist/mjs/types/websockets/events.js +2 -0
  207. package/dist/mjs/types/websockets/events.js.map +1 -0
  208. package/dist/mjs/types/websockets/requests.d.ts +76 -0
  209. package/dist/mjs/types/websockets/requests.js +2 -0
  210. package/dist/mjs/types/websockets/requests.js.map +1 -0
  211. package/dist/mjs/types/websockets/wsAPI.d.ts +9 -0
  212. package/dist/mjs/types/websockets/wsAPI.js +2 -0
  213. package/dist/mjs/types/websockets/wsAPI.js.map +1 -0
  214. package/package.json +42 -30
  215. package/index.js +0 -1
  216. package/lib/index.d.ts +0 -1
  217. package/lib/index.js +0 -16
  218. package/lib/index.js.map +0 -1
@@ -0,0 +1,429 @@
1
+ import axios from 'axios';
2
+ import https from 'https';
3
+ import { nanoid } from 'nanoid';
4
+ import { signJWT } from './jwtNode.js';
5
+ import { neverGuard } from './misc-util.js';
6
+ import { APIIDPrefix, getRestBaseUrl, logInvalidOrderId, REST_CLIENT_TYPE_ENUM, serializeParams, } from './requestUtils.js';
7
+ import { signMessage } from './webCryptoAPI.js';
8
+ const MISSING_API_KEYS_ERROR = 'API Key, Secret & API Passphrase are ALL required to use the authenticated REST client';
9
+ const ENABLE_HTTP_TRACE = typeof process === 'object' &&
10
+ typeof process.env === 'object' &&
11
+ process.env.CBTRACE;
12
+ if (ENABLE_HTTP_TRACE) {
13
+ axios.interceptors.request.use((request) => {
14
+ console.log(new Date(), 'Starting Request', JSON.stringify({
15
+ url: request.url,
16
+ method: request.method,
17
+ params: request.params,
18
+ data: request.data,
19
+ }, null, 2));
20
+ return request;
21
+ });
22
+ axios.interceptors.response.use((response) => {
23
+ console.log(new Date(), 'Response:', {
24
+ // request: {
25
+ // url: response.config.url,
26
+ // method: response.config.method,
27
+ // data: response.config.data,
28
+ // headers: response.config.headers,
29
+ // },
30
+ response: {
31
+ status: response.status,
32
+ statusText: response.statusText,
33
+ headers: response.headers,
34
+ data: JSON.stringify(response.data, null, 2),
35
+ },
36
+ });
37
+ return response;
38
+ });
39
+ }
40
+ /**
41
+ * Impure, mutates params to remove any values that have a key but are undefined.
42
+ */
43
+ function deleteUndefinedValues(params) {
44
+ if (!params) {
45
+ return;
46
+ }
47
+ for (const key in params) {
48
+ const value = params[key];
49
+ if (typeof value === 'undefined') {
50
+ delete params[key];
51
+ }
52
+ }
53
+ }
54
+ export class BaseRestClient {
55
+ options;
56
+ baseUrl;
57
+ globalRequestOptions;
58
+ apiKey;
59
+ apiSecret;
60
+ apiPassphrase;
61
+ /**
62
+ * Create an instance of the REST client. Pass API credentials in the object in the first parameter.
63
+ * @param {RestClientOptions} [restClientOptions={}] options to configure REST API connectivity
64
+ * @param {AxiosRequestConfig} [networkOptions={}] HTTP networking options for axios
65
+ */
66
+ constructor(restClientOptions = {}, networkOptions = {}) {
67
+ this.options = {
68
+ /** Throw errors if any request params are empty */
69
+ strictParamValidation: false,
70
+ ...restClientOptions,
71
+ };
72
+ const VERSION = '0.1.0';
73
+ const USER_AGENT = `${APIIDPrefix}/${VERSION}`;
74
+ this.globalRequestOptions = {
75
+ /** in ms == 5 minutes by default */
76
+ timeout: 1000 * 60 * 5,
77
+ /** inject custom rquest options based on axios specs - see axios docs for more guidance on AxiosRequestConfig: https://github.com/axios/axios#request-config */
78
+ ...networkOptions,
79
+ headers: {
80
+ ...networkOptions.headers,
81
+ 'Content-Type': 'application/json',
82
+ locale: 'en-US',
83
+ 'User-Agent': USER_AGENT,
84
+ },
85
+ };
86
+ if (restClientOptions.localisation) {
87
+ if (!this.globalRequestOptions.headers) {
88
+ this.globalRequestOptions.headers = {};
89
+ }
90
+ this.globalRequestOptions.headers['Accept-Language'] =
91
+ restClientOptions.localisation;
92
+ }
93
+ // If enabled, configure a https agent with keepAlive enabled
94
+ if (this.options.keepAlive) {
95
+ // For more advanced configuration, raise an issue on GitHub or use the "networkOptions"
96
+ // parameter to define a custom httpsAgent with the desired properties
97
+ this.globalRequestOptions.httpsAgent = new https.Agent({
98
+ keepAlive: true,
99
+ keepAliveMsecs: this.options.keepAliveMsecs,
100
+ });
101
+ }
102
+ this.baseUrl = getRestBaseUrl(restClientOptions, this.getClientType());
103
+ this.apiKey = this.options.apiKey;
104
+ this.apiSecret = this.options.apiSecret;
105
+ this.apiPassphrase = this.options.apiPassphrase;
106
+ if (restClientOptions.cdpApiKey) {
107
+ this.apiKey = restClientOptions.cdpApiKey.name;
108
+ this.apiSecret = restClientOptions.cdpApiKey.privateKey;
109
+ }
110
+ // Throw if one of these values is missing, and at least one of them is set
111
+ const credentials = [this.apiKey, this.apiSecret];
112
+ if (
113
+ // commerce only needs keys, not key and secret
114
+ this.getClientType() !== REST_CLIENT_TYPE_ENUM.commerce &&
115
+ credentials.includes(undefined) &&
116
+ credentials.some((v) => typeof v === 'string')) {
117
+ throw new Error(MISSING_API_KEYS_ERROR);
118
+ }
119
+ }
120
+ /**
121
+ * Timestamp used to sign the request. Override this method to implement your own timestamp/sync mechanism
122
+ */
123
+ getSignTimestampMs() {
124
+ return Date.now();
125
+ }
126
+ get(endpoint, params) {
127
+ return this._call('GET', endpoint, params, true);
128
+ }
129
+ post(endpoint, params) {
130
+ return this._call('POST', endpoint, params, true);
131
+ }
132
+ getPrivate(endpoint, params) {
133
+ return this._call('GET', endpoint, params, false);
134
+ }
135
+ postPrivate(endpoint, params) {
136
+ return this._call('POST', endpoint, params, false);
137
+ }
138
+ deletePrivate(endpoint, params) {
139
+ return this._call('DELETE', endpoint, params, false);
140
+ }
141
+ putPrivate(endpoint, params) {
142
+ return this._call('PUT', endpoint, params, false);
143
+ }
144
+ patchPrivate(endpoint, params) {
145
+ return this._call('PATCH', endpoint, params, false);
146
+ }
147
+ /**
148
+ * @private Make a HTTP request to a specific endpoint. Private endpoint API calls are automatically signed.
149
+ */
150
+ async _call(method, endpoint, params, isPublicApi) {
151
+ // Sanity check to make sure it's only ever prefixed by one forward slash
152
+ const requestUrl = [this.baseUrl, endpoint].join(endpoint.startsWith('/') ? '' : '/');
153
+ // Build a request and handle signature process
154
+ const options = await this.buildRequest(method, endpoint, requestUrl, params, isPublicApi);
155
+ if (ENABLE_HTTP_TRACE) {
156
+ console.log('full request: ', options);
157
+ }
158
+ // Dispatch request
159
+ return axios(options)
160
+ .then((response) => {
161
+ if (response.status >= 200 && response.status <= 204) {
162
+ // Throw if API returns an error (e.g. insufficient balance)
163
+ if (typeof response.data?.code === 'string' &&
164
+ response.data?.code !== '200000') {
165
+ throw { response };
166
+ }
167
+ return response.data;
168
+ }
169
+ throw { response };
170
+ })
171
+ .catch((e) => this.parseException(e, { method, endpoint, requestUrl, params }));
172
+ }
173
+ generateNewOrderId() {
174
+ return APIIDPrefix + nanoid(14);
175
+ }
176
+ /**
177
+ * Validate syntax meets requirements set by coinbase. Log warning if not.
178
+ */
179
+ validateOrderId(params, orderIdProperty) {
180
+ // Not the cleanest but strict checks aren't quite necessary here either
181
+ const requestParams = params;
182
+ if (!requestParams[orderIdProperty]) {
183
+ requestParams[orderIdProperty] = this.generateNewOrderId();
184
+ return;
185
+ }
186
+ if (!requestParams[orderIdProperty].startsWith(APIIDPrefix)) {
187
+ logInvalidOrderId(orderIdProperty, APIIDPrefix, params);
188
+ const previousValue = requestParams[orderIdProperty];
189
+ const newValue = APIIDPrefix + requestParams[orderIdProperty];
190
+ console.warn(`WARNING: "${orderIdProperty}" was automatically prefixed. Changed from "${previousValue}" to "${newValue}". To avoid this, apply the prefix before submitting an order or use the client.generateNewOrderId() utility method.`);
191
+ requestParams[orderIdProperty] = newValue;
192
+ }
193
+ }
194
+ /**
195
+ * @private generic handler to parse request exceptions
196
+ */
197
+ parseException(e, requestParams) {
198
+ if (this.options.parseExceptions === false) {
199
+ throw e;
200
+ }
201
+ // Something happened in setting up the request that triggered an error
202
+ if (!e.response) {
203
+ if (!e.request) {
204
+ throw e.message;
205
+ }
206
+ // request made but no response received
207
+ throw e;
208
+ }
209
+ // The request was made and the server responded with a status code
210
+ // that falls out of the range of 2xx
211
+ const response = e.response;
212
+ // console.error('err: ', response?.data);
213
+ throw {
214
+ code: response.status,
215
+ message: response.statusText,
216
+ body: response.data,
217
+ headers: response.headers,
218
+ requestOptions: {
219
+ ...this.options,
220
+ // Prevent credentials from leaking into error messages
221
+ apiKey: 'omittedFromError',
222
+ apiSecret: 'omittedFromError',
223
+ apiPassphrase: 'omittedFromError',
224
+ cdpApiKey: 'omittedFromError',
225
+ },
226
+ requestParams,
227
+ };
228
+ }
229
+ /**
230
+ * @private sign request and set recv window
231
+ */
232
+ async signRequest(data, url, endpoint, method, signMethod) {
233
+ const timestampInMs = this.getSignTimestampMs();
234
+ const res = {
235
+ originalParams: {
236
+ ...data,
237
+ },
238
+ sign: '',
239
+ timestamp: timestampInMs,
240
+ recvWindow: 0,
241
+ serializedParams: '',
242
+ queryParamsWithSign: '',
243
+ headers: {},
244
+ };
245
+ const apiKey = this.apiKey;
246
+ const apiSecret = this.apiSecret;
247
+ const apiPassphrase = this.apiPassphrase;
248
+ const jwtExpiresSeconds = this.options.jwtExpiresSeconds || 120;
249
+ if (!apiKey) {
250
+ return res;
251
+ }
252
+ const strictParamValidation = this.options.strictParamValidation;
253
+ const encodeQueryStringValues = true;
254
+ const requestBody = data?.body || data;
255
+ const requestBodyString = requestBody ? JSON.stringify(requestBody) : '';
256
+ if (signMethod === 'coinbase') {
257
+ const clientType = this.getClientType();
258
+ const signRequestParams = method === 'GET'
259
+ ? serializeParams(data?.query || data, strictParamValidation, encodeQueryStringValues, '?')
260
+ : requestBodyString;
261
+ // https://docs.cdp.coinbase.com/product-apis/docs/welcome
262
+ switch (clientType) {
263
+ case REST_CLIENT_TYPE_ENUM.advancedTrade:
264
+ case REST_CLIENT_TYPE_ENUM.coinbaseApp: {
265
+ // Both adv trade & app API use the same JWT auth mechanism
266
+ // Advanced Trade: https://docs.cdp.coinbase.com/advanced-trade/docs/rest-api-auth
267
+ // App: https://docs.cdp.coinbase.com/coinbase-app/docs/api-key-authentication
268
+ if (!apiSecret) {
269
+ throw new Error(`No API secret provided, cannot prepare JWT.`);
270
+ }
271
+ const sign = signJWT({
272
+ url,
273
+ method,
274
+ algorithm: 'ES256',
275
+ timestampMs: timestampInMs,
276
+ jwtExpiresSeconds,
277
+ apiPubKey: apiKey,
278
+ apiPrivKey: apiSecret,
279
+ });
280
+ return {
281
+ ...res,
282
+ sign: sign,
283
+ queryParamsWithSign: signRequestParams,
284
+ headers: {
285
+ Authorization: `Bearer ${sign}`,
286
+ },
287
+ };
288
+ // TODO: is there demand for oauth support?
289
+ // Docs: https://docs.cdp.coinbase.com/coinbase-app/docs/coinbase-app-integration
290
+ // See: https://github.com/tiagosiebler/coinbase-api/issues/24
291
+ }
292
+ // Docs: https://docs.cdp.coinbase.com/exchange/docs/rest-auth
293
+ case REST_CLIENT_TYPE_ENUM.exchange:
294
+ // Docs: https://docs.cdp.coinbase.com/intx/docs/rest-auth
295
+ case REST_CLIENT_TYPE_ENUM.international: {
296
+ const timestampInSeconds = timestampInMs / 1000; // decimals are OK
297
+ if (!apiSecret) {
298
+ throw new Error(`No API secret provided, cannot sign request.`);
299
+ }
300
+ if (!apiPassphrase) {
301
+ throw new Error(`No API passphrase provided, cannot sign request.`);
302
+ }
303
+ const signInput = timestampInSeconds + method + endpoint + signRequestParams;
304
+ const sign = await signMessage(signInput, apiSecret, 'base64', 'SHA-256', 'base64:web');
305
+ const headers = {
306
+ 'CB-ACCESS-KEY': apiKey,
307
+ 'CB-ACCESS-SIGN': sign,
308
+ 'CB-ACCESS-TIMESTAMP': timestampInSeconds,
309
+ 'CB-ACCESS-PASSPHRASE': apiPassphrase,
310
+ };
311
+ // console.log('sign res: ', { signInput, ...headers });
312
+ return {
313
+ ...res,
314
+ sign: sign,
315
+ queryParamsWithSign: signRequestParams,
316
+ headers: {
317
+ ...headers,
318
+ },
319
+ };
320
+ // For CB Exchange, is there demand for FIX
321
+ // Docs, FIX: https://docs.cdp.coinbase.com/exchange/docs/fix-connectivity
322
+ // For CB International, is there demand for FIX
323
+ // Docs, FIX: https://docs.cdp.coinbase.com/intx/docs/fix-overview
324
+ }
325
+ // Docs: https://docs.cdp.coinbase.com/prime/docs/rest-authentication
326
+ case REST_CLIENT_TYPE_ENUM.prime: {
327
+ const timestampInSeconds = Math.floor(timestampInMs / 1000); // decimal not allowed
328
+ const signInput = timestampInSeconds + method + endpoint + requestBodyString;
329
+ if (!apiSecret) {
330
+ throw new Error(`No API secret provided, cannot sign request.`);
331
+ }
332
+ if (!apiPassphrase) {
333
+ throw new Error(`No API passphrase provided, cannot sign request.`);
334
+ }
335
+ const sign = await signMessage(signInput, apiSecret, 'base64', 'SHA-256', 'base64:web');
336
+ const headers = {
337
+ 'X-CB-ACCESS-KEY': apiKey,
338
+ 'X-CB-ACCESS-PASSPHRASE': apiPassphrase,
339
+ 'X-CB-ACCESS-SIGNATURE': sign,
340
+ 'X-CB-ACCESS-TIMESTAMP': timestampInSeconds,
341
+ };
342
+ // For CB Prime, is there demand for FIX
343
+ // Docs, FIX: https://docs.cdp.coinbase.com/prime/docs/fix-connectivity
344
+ return {
345
+ ...res,
346
+ sign: sign,
347
+ queryParamsWithSign: signRequestParams,
348
+ headers: {
349
+ ...headers,
350
+ },
351
+ };
352
+ }
353
+ case REST_CLIENT_TYPE_ENUM.commerce: {
354
+ // https://docs.cdp.coinbase.com/commerce-onchain/docs/getting-started
355
+ // No auth?
356
+ return {
357
+ ...res,
358
+ headers: {
359
+ 'X-CC-Api-Key': apiKey,
360
+ },
361
+ };
362
+ }
363
+ default: {
364
+ console.error(new Date(), neverGuard(clientType, `Unhandled sign client type : "${clientType}"`));
365
+ throw new Error(`Unhandled request sign for client : "${clientType}"`);
366
+ }
367
+ }
368
+ }
369
+ console.error(new Date(), neverGuard(signMethod, `Unhandled sign method: "${signMessage}"`));
370
+ return res;
371
+ }
372
+ async prepareSignParams(method, url, endpoint, signMethod, params, isPublicApi) {
373
+ if (isPublicApi) {
374
+ return {
375
+ originalParams: params,
376
+ paramsWithSign: params,
377
+ };
378
+ }
379
+ if (!this.apiKey || !this.apiSecret) {
380
+ throw new Error(MISSING_API_KEYS_ERROR);
381
+ }
382
+ return this.signRequest(params, url, endpoint, method, signMethod);
383
+ }
384
+ /** Returns an axios request object. Handles signing process automatically if this is a private API call */
385
+ async buildRequest(method, endpoint, url, params, isPublicApi) {
386
+ const options = {
387
+ ...this.globalRequestOptions,
388
+ url: url,
389
+ method: method,
390
+ };
391
+ deleteUndefinedValues(params);
392
+ deleteUndefinedValues(params?.body);
393
+ deleteUndefinedValues(params?.query);
394
+ deleteUndefinedValues(params?.headers);
395
+ if (isPublicApi || !this.apiKey || !this.apiSecret) {
396
+ return {
397
+ ...options,
398
+ params: params,
399
+ };
400
+ }
401
+ const signResult = await this.prepareSignParams(method, url, endpoint, 'coinbase', params, isPublicApi);
402
+ const requestHeaders = {
403
+ // request parameter headers for this request
404
+ ...params?.headers,
405
+ // auth headers for this request
406
+ ...signResult.headers,
407
+ // global headers for every request
408
+ ...options.headers,
409
+ };
410
+ let urlWithQueryParams = options.url;
411
+ if (method === 'GET') {
412
+ if (signResult.queryParamsWithSign) {
413
+ urlWithQueryParams += signResult.queryParamsWithSign;
414
+ }
415
+ return {
416
+ ...options,
417
+ headers: requestHeaders,
418
+ url: urlWithQueryParams,
419
+ };
420
+ }
421
+ return {
422
+ ...options,
423
+ headers: requestHeaders,
424
+ url: params?.query ? urlWithQueryParams : options.url,
425
+ data: signResult.originalParams.body,
426
+ };
427
+ }
428
+ }
429
+ //# sourceMappingURL=BaseRestClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseRestClient.js","sourceRoot":"","sources":["../../../src/lib/BaseRestClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,169 @@
1
+ import EventEmitter from 'events';
2
+ import WebSocket from 'isomorphic-ws';
3
+ import { WebsocketClientOptions, WSClientConfigurableOptions } from '../types/websockets/client.js';
4
+ import { WsOperation } from '../types/websockets/requests.js';
5
+ import { DefaultLogger } from './websocket/logger.js';
6
+ import { MessageEventLike, WsTopicRequest, WsTopicRequestOrStringTopic } from './websocket/websocket-util.js';
7
+ import { WsStore } from './websocket/WsStore.js';
8
+ import { WSConnectedResult } from './websocket/WsStore.types.js';
9
+ interface WSClientEventMap<WsKey extends string> {
10
+ /** Connection opened. If this connection was previously opened and reconnected, expect the reconnected event instead */
11
+ open: (evt: {
12
+ wsKey: WsKey;
13
+ event: any;
14
+ }) => void;
15
+ /** Reconnecting a dropped connection */
16
+ reconnect: (evt: {
17
+ wsKey: WsKey;
18
+ event: any;
19
+ }) => void;
20
+ /** Successfully reconnected a connection that dropped */
21
+ reconnected: (evt: {
22
+ wsKey: WsKey;
23
+ event: any;
24
+ }) => void;
25
+ /** Connection closed */
26
+ close: (evt: {
27
+ wsKey: WsKey;
28
+ event: any;
29
+ }) => void;
30
+ /** Received reply to websocket command (e.g. after subscribing to topics) */
31
+ response: (response: any & {
32
+ wsKey: WsKey;
33
+ }) => void;
34
+ /** Received data for topic */
35
+ update: (response: any & {
36
+ wsKey: WsKey;
37
+ }) => void;
38
+ /** Exception from ws client OR custom listeners (e.g. if you throw inside your event handler) */
39
+ exception: (response: any & {
40
+ wsKey: WsKey;
41
+ }) => void;
42
+ error: (response: any & {
43
+ wsKey: WsKey;
44
+ }) => void;
45
+ /** Confirmation that a connection successfully authenticated */
46
+ authenticated: (event: {
47
+ wsKey: WsKey;
48
+ event: any;
49
+ }) => void;
50
+ }
51
+ export interface EmittableEvent<TEvent = any> {
52
+ eventType: 'response' | 'update' | 'exception' | 'authenticated' | 'connectionReady';
53
+ event: TEvent;
54
+ }
55
+ export interface BaseWebsocketClient<TWSKey extends string> {
56
+ on<U extends keyof WSClientEventMap<TWSKey>>(event: U, listener: WSClientEventMap<TWSKey>[U]): this;
57
+ emit<U extends keyof WSClientEventMap<TWSKey>>(event: U, ...args: Parameters<WSClientEventMap<TWSKey>[U]>): boolean;
58
+ }
59
+ type WSTopic = string;
60
+ export declare abstract class BaseWebsocketClient<TWSKey extends string> extends EventEmitter {
61
+ private wsStore;
62
+ protected logger: typeof DefaultLogger;
63
+ protected options: WebsocketClientOptions;
64
+ private wsApiRequestId;
65
+ constructor(options?: WSClientConfigurableOptions, logger?: typeof DefaultLogger);
66
+ protected abstract sendPingEvent(wsKey: TWSKey, ws: WebSocket): void;
67
+ protected abstract sendPongEvent(wsKey: TWSKey, ws: WebSocket): void;
68
+ protected abstract isWsPong(data: any): boolean;
69
+ protected abstract isWsPing(data: any): boolean;
70
+ protected abstract getWsAuthRequestEvent(wsKey: TWSKey): Promise<object>;
71
+ protected abstract isPrivateTopicRequest(request: WsTopicRequest<WSTopic>, wsKey: TWSKey): boolean;
72
+ /**
73
+ * Returns a list of string events that can be individually sent upstream to complete subscribing/unsubscribing/etc to these topics
74
+ */
75
+ protected abstract getWsOperationEventsForTopics(topics: WsTopicRequest<WSTopic>[], wsKey: TWSKey, operation: WsOperation): Promise<string[]>;
76
+ protected abstract getPrivateWSKeys(): TWSKey[];
77
+ protected abstract getWsUrl(wsKey: TWSKey): Promise<string>;
78
+ protected abstract getMaxTopicsPerSubscribeEvent(wsKey: TWSKey): number | null;
79
+ /**
80
+ * Abstraction called to sort ws events into emittable event types (response to a request, data update, etc)
81
+ */
82
+ protected abstract resolveEmittableEvents(wsKey: TWSKey, event: MessageEventLike): EmittableEvent[];
83
+ /**
84
+ * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library
85
+ */
86
+ protected abstract connectAll(): Promise<(WSConnectedResult | undefined)[]>;
87
+ protected isPrivateWsKey(wsKey: TWSKey): boolean;
88
+ /** Returns auto-incrementing request ID, used to track promise references for async requests */
89
+ protected getNewRequestId(): string;
90
+ protected abstract sendWSAPIRequest(wsKey: TWSKey, channel: WSTopic, params?: any): Promise<unknown>;
91
+ protected abstract sendWSAPIRequest(wsKey: TWSKey, channel: WSTopic, params: any): Promise<unknown>;
92
+ /**
93
+ * Subscribe to one or more topics on a WS connection (identified by WS Key).
94
+ *
95
+ * - Topics are automatically cached
96
+ * - Connections are automatically opened, if not yet connected
97
+ * - Authentication is automatically handled
98
+ * - Topics are automatically resubscribed to, if something happens to the connection, unless you call unsubsribeTopicsForWsKey(topics, key).
99
+ *
100
+ * @param wsTopicRequests array of topics to subscribe to
101
+ * @param wsKey ws key referring to the ws connection these topics should be subscribed on
102
+ */
103
+ subscribeTopicsForWsKey(wsTopicRequests: WsTopicRequestOrStringTopic<WSTopic>[], wsKey: TWSKey): false | Promise<WSConnectedResult | undefined> | undefined;
104
+ protected unsubscribeTopicsForWsKey(wsTopicRequests: WsTopicRequestOrStringTopic<string>[], wsKey: TWSKey): void;
105
+ /**
106
+ * Splits topic requests into two groups, public & private topic requests
107
+ */
108
+ private sortTopicRequestsIntoPublicPrivate;
109
+ /** Get the WsStore that tracks websockets & topics */
110
+ getWsStore(): WsStore<TWSKey, WsTopicRequest<string>>;
111
+ close(wsKey: TWSKey, force?: boolean): void;
112
+ closeAll(force?: boolean): void;
113
+ isConnected(wsKey: TWSKey): boolean;
114
+ /**
115
+ * Request connection to a specific websocket, instead of waiting for automatic connection.
116
+ */
117
+ connect(wsKey: TWSKey): Promise<WSConnectedResult | undefined>;
118
+ private connectToWsUrl;
119
+ private parseWsError;
120
+ /** Get a signature, build the auth request and send it */
121
+ private sendAuthRequest;
122
+ private reconnectWithDelay;
123
+ private ping;
124
+ private clearTimers;
125
+ private clearPingTimer;
126
+ private clearPongTimer;
127
+ /**
128
+ * Simply builds and sends subscribe events for a list of topics for a ws key
129
+ *
130
+ * @private Use the `subscribe(topics)` or `subscribeTopicsForWsKey(topics, wsKey)` method to subscribe to topics. Send WS message to subscribe to topics.
131
+ */
132
+ private requestSubscribeTopics;
133
+ /**
134
+ * Simply builds and sends unsubscribe events for a list of topics for a ws key
135
+ *
136
+ * @private Use the `unsubscribe(topics)` method to unsubscribe from topics. Send WS message to unsubscribe from topics.
137
+ */
138
+ private requestUnsubscribeTopics;
139
+ /**
140
+ * Try sending a string event on a WS connection (identified by the WS Key)
141
+ */
142
+ tryWsSend(wsKey: TWSKey, wsMessage: string): void;
143
+ private onWsOpen;
144
+ private onWsPing;
145
+ private onWsPong;
146
+ /**
147
+ * Called automatically once a connection is ready.
148
+ * - Some exchanges are ready immediately after the connections open.
149
+ * - Some exchanges send an event to confirm the connection is ready for us.
150
+ *
151
+ * This method is called to act when the connection is ready. Use `requireConnectionReadyConfirmation` to control how this is called.
152
+ */
153
+ private onWsReadyForEvents;
154
+ /**
155
+ * Handle subscription to private topics _after_ authentication successfully completes asynchronously.
156
+ *
157
+ * Only used for exchanges that require auth before sending private topic subscription requests
158
+ */
159
+ private onWsAuthenticated;
160
+ private onWsMessage;
161
+ private onWsClose;
162
+ private getWs;
163
+ private setWsState;
164
+ /**
165
+ * Promise-driven method to assert that a ws has successfully connected (will await until connection is open)
166
+ */
167
+ protected assertIsConnected(wsKey: TWSKey): Promise<unknown>;
168
+ }
169
+ export {};