coinbase-api 0.3.2 → 0.5.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 (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,13 @@
1
+ interface JWTSignParams {
2
+ algorithm: 'ES256';
3
+ timestampMs: number;
4
+ jwtExpiresSeconds: number;
5
+ apiPubKey: string;
6
+ apiPrivKey: string;
7
+ }
8
+ export declare function signJWT(params: {
9
+ url: string;
10
+ method: string;
11
+ } & JWTSignParams): string;
12
+ export declare function signWSJWT(params: JWTSignParams): string;
13
+ export {};
@@ -0,0 +1,45 @@
1
+ import jwt from 'jsonwebtoken';
2
+ import { nanoid } from 'nanoid';
3
+ export function signJWT(params) {
4
+ const { url, method, algorithm, timestampMs, jwtExpiresSeconds, apiPrivKey, apiPubKey, } = params;
5
+ // Remove https:// but keep the rest
6
+ const urlWithEndpoint = url.slice(8);
7
+ const uri = `${method} ${urlWithEndpoint}`;
8
+ const payload = {
9
+ iss: 'cdp',
10
+ nbf: Math.floor(timestampMs / 1000),
11
+ exp: Math.floor(timestampMs / 1000) + jwtExpiresSeconds,
12
+ sub: apiPubKey,
13
+ uri,
14
+ };
15
+ const header = {
16
+ alg: algorithm,
17
+ kid: apiPubKey,
18
+ nonce: nanoid(16),
19
+ };
20
+ const options = {
21
+ algorithm: algorithm,
22
+ header: header,
23
+ };
24
+ return jwt.sign(payload, apiPrivKey, options);
25
+ }
26
+ export function signWSJWT(params) {
27
+ const { algorithm, timestampMs, jwtExpiresSeconds, apiPrivKey, apiPubKey } = params;
28
+ const payload = {
29
+ iss: 'cdp',
30
+ nbf: Math.floor(timestampMs / 1000),
31
+ exp: Math.floor(timestampMs / 1000) + jwtExpiresSeconds,
32
+ sub: apiPubKey,
33
+ };
34
+ const header = {
35
+ alg: algorithm,
36
+ kid: apiPubKey,
37
+ nonce: nanoid(16),
38
+ };
39
+ const options = {
40
+ algorithm: algorithm,
41
+ header: header,
42
+ };
43
+ return jwt.sign(payload, apiPrivKey, options);
44
+ }
45
+ //# sourceMappingURL=jwtNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwtNode.js","sourceRoot":"","sources":["../../../src/lib/jwtNode.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAUhC,MAAM,UAAU,OAAO,CACrB,MAGiB;IAEjB,MAAM,EACJ,GAAG,EACH,MAAM,EACN,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,SAAS,GACV,GAAG,MAAM,CAAC;IAEX,oCAAoC;IACpC,MAAM,eAAe,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,eAAe,EAAE,CAAC;IAE3C,MAAM,OAAO,GAAG;QACd,GAAG,EAAE,KAAK;QACV,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;QACnC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,iBAAiB;QACvD,GAAG,EAAE,SAAS;QACd,GAAG;KACJ,CAAC;IAEF,MAAM,MAAM,GAAG;QACb,GAAG,EAAE,SAAS;QACd,GAAG,EAAE,SAAS;QACd,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;KAClB,CAAC;IAEF,MAAM,OAAO,GAAoB;QAC/B,SAAS,EAAE,SAA0B;QACrC,MAAM,EAAE,MAAM;KACf,CAAC;IAEF,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAqB;IAC7C,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,SAAS,EAAE,GACxE,MAAM,CAAC;IACT,MAAM,OAAO,GAAG;QACd,GAAG,EAAE,KAAK;QACV,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;QACnC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,iBAAiB;QACvD,GAAG,EAAE,SAAS;KACf,CAAC;IAEF,MAAM,MAAM,GAAG;QACb,GAAG,EAAE,SAAS;QACd,GAAG,EAAE,SAAS;QACd,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;KAClB,CAAC;IAEF,MAAM,OAAO,GAAoB;QAC/B,SAAS,EAAE,SAA0B;QACrC,MAAM,EAAE,MAAM;KACf,CAAC;IAEF,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function neverGuard(x: never, msg: string): Error;
@@ -0,0 +1,4 @@
1
+ export function neverGuard(x, msg) {
2
+ return new Error(`Unhandled value exception "${x}", ${msg}`);
3
+ }
4
+ //# sourceMappingURL=misc-util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"misc-util.js","sourceRoot":"","sources":["../../../src/lib/misc-util.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,CAAQ,EAAE,GAAW;IAC9C,OAAO,IAAI,KAAK,CAAC,8BAA8B,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,98 @@
1
+ import { CustomOrderIdProperty } from '../types/shared.types.js';
2
+ /**
3
+ * Used to switch how authentication/requests work under the hood
4
+ */
5
+ export declare const REST_CLIENT_TYPE_ENUM: {
6
+ /** Coinbase Advanced Trade API */
7
+ readonly advancedTrade: "advancedTrade";
8
+ /** Coinbase App API */
9
+ readonly coinbaseApp: "coinbaseApp";
10
+ /** Coinbase Exchange API */
11
+ readonly exchange: "exchange";
12
+ /** Coinbase Prime API */
13
+ readonly prime: "prime";
14
+ /** Coinbase International API */
15
+ readonly international: "international";
16
+ /** Coinbase Commerce API */
17
+ readonly commerce: "commerce";
18
+ };
19
+ export type RestClientType = (typeof REST_CLIENT_TYPE_ENUM)[keyof typeof REST_CLIENT_TYPE_ENUM];
20
+ export interface RestClientOptions {
21
+ /**
22
+ * Your API key name.
23
+ *
24
+ * - For the Advanced Trade or App APIs, this is your API Key Name.
25
+ */
26
+ apiKey?: string;
27
+ /**
28
+ * Your API key secret.
29
+ *
30
+ * - For the Advanced Trade or App APIs, this is your API private key (including the -----BEGIN EC PRIVATE KEY-----\n etc).
31
+ */
32
+ apiSecret?: string;
33
+ /**
34
+ * Your API passphrase (NOT your account password). Only used for the API groups that use an API passphrase:
35
+ * - Coinbase Exchange API
36
+ * - Coinbase International API
37
+ * - Coinbase Prime API
38
+ */
39
+ apiPassphrase?: string;
40
+ /**
41
+ * For the Advanced Trade or App APIs, instead of passing the key name and
42
+ * private key, you can also parse the exported "cdp_api_key.json" into an object and pass it here.
43
+ *
44
+ * It will automatically get parsed into the apiKey & apiSecret configuration parameters.
45
+ */
46
+ cdpApiKey?: {
47
+ name: string;
48
+ privateKey: string;
49
+ };
50
+ /**
51
+ * https://docs.cdp.coinbase.com/coinbase-app/docs/localization
52
+ *
53
+ * The Coinbase App API supports localization for error messages and other strings.
54
+ * Localization is defined in each request with Accept-Language header.
55
+ *
56
+ * Accepted values are currently as below. Note: this may not work for all coinbase product groups.
57
+ */
58
+ localisation?: 'de' | 'en' | 'es' | 'es-mx' | 'fr' | 'id' | 'it' | 'nl' | 'pt' | 'pt-br';
59
+ /**
60
+ * Connect to the sandbox for supported products
61
+ *
62
+ * - Coinbase Exchange: https://docs.cdp.coinbase.com/exchange/docs/sandbox
63
+ * - Coinbase International: https://docs.cdp.coinbase.com/intx/docs/sandbox
64
+ *
65
+ * - Coinbase App: No sandbox available.
66
+ * - Coinbase Advanced Trade: No sandbox available.
67
+ * - Coinbase Prime: No sandbox available.
68
+ */
69
+ useSandbox?: boolean;
70
+ /**
71
+ * Enable keep alive for REST API requests (via axios).
72
+ * See: https://github.com/tiagosiebler/bybit-api/issues/368
73
+ */
74
+ keepAlive?: boolean;
75
+ /**
76
+ * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000.
77
+ * Only relevant if keepAlive is set to true.
78
+ * Default: 1000 (defaults comes from https agent)
79
+ */
80
+ keepAliveMsecs?: number;
81
+ /**
82
+ * For JWT auth (adv trade & app API), seconds until jwt expires. Defaults to 120 seconds.
83
+ */
84
+ jwtExpiresSeconds?: number;
85
+ /** Default: false. If true, we'll throw errors if any params are undefined */
86
+ strictParamValidation?: boolean;
87
+ /**
88
+ * Optionally override API protocol + domain
89
+ * e.g baseUrl: 'https://api.differentUrl.com'
90
+ **/
91
+ baseUrl?: string;
92
+ /** Default: true. whether to try and post-process request exceptions (and throw them). */
93
+ parseExceptions?: boolean;
94
+ }
95
+ export declare function serializeParams<T extends Record<string, any> | undefined = {}>(params: T, strict_validation: boolean | undefined, encodeValues: boolean, prefixWith: string): string;
96
+ export declare const APIIDPrefix = "cbnode";
97
+ export declare function logInvalidOrderId(orderIdProperty: CustomOrderIdProperty, expectedOrderIdPrefix: string, params: unknown): void;
98
+ export declare function getRestBaseUrl(restClientOptions: RestClientOptions, restClientType: RestClientType): string;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Used to switch how authentication/requests work under the hood
3
+ */
4
+ export const REST_CLIENT_TYPE_ENUM = {
5
+ /** Coinbase Advanced Trade API */
6
+ advancedTrade: 'advancedTrade',
7
+ /** Coinbase App API */
8
+ coinbaseApp: 'coinbaseApp',
9
+ /** Coinbase Exchange API */
10
+ exchange: 'exchange',
11
+ /** Coinbase Prime API */
12
+ prime: 'prime',
13
+ /** Coinbase International API */
14
+ international: 'international',
15
+ /** Coinbase Commerce API */
16
+ commerce: 'commerce',
17
+ };
18
+ const exchangeBaseURLMap = {
19
+ [REST_CLIENT_TYPE_ENUM.advancedTrade]: 'https://api.coinbase.com',
20
+ [REST_CLIENT_TYPE_ENUM.coinbaseApp]: 'https://api.coinbase.com',
21
+ [REST_CLIENT_TYPE_ENUM.exchange]: 'https://api.exchange.coinbase.com',
22
+ [REST_CLIENT_TYPE_ENUM.prime]: 'https://api.prime.coinbase.com',
23
+ [REST_CLIENT_TYPE_ENUM.international]: 'https://api.international.coinbase.com',
24
+ [REST_CLIENT_TYPE_ENUM.commerce]: 'https://api.commerce.coinbase.com',
25
+ };
26
+ const exchangeSandboxURLMap = {
27
+ [REST_CLIENT_TYPE_ENUM.exchange]: 'https://api-public.sandbox.exchange.coinbase.com',
28
+ [REST_CLIENT_TYPE_ENUM.international]: 'https://api-n5e1.coinbase.com',
29
+ [REST_CLIENT_TYPE_ENUM.advancedTrade]: 'NoSandboxAvailable',
30
+ [REST_CLIENT_TYPE_ENUM.coinbaseApp]: 'NoSandboxAvailable',
31
+ [REST_CLIENT_TYPE_ENUM.prime]: 'NoSandboxAvailable',
32
+ [REST_CLIENT_TYPE_ENUM.commerce]: 'NoSandboxAvailable',
33
+ };
34
+ export function serializeParams(params, strict_validation, encodeValues, prefixWith) {
35
+ if (!params) {
36
+ return '';
37
+ }
38
+ const queryString = Object.keys(params)
39
+ .sort()
40
+ .map((key) => {
41
+ const value = params[key];
42
+ if (strict_validation === true && typeof value === 'undefined') {
43
+ throw new Error('Failed to sign API request due to undefined parameter');
44
+ }
45
+ const encodedValue = encodeValues ? encodeURIComponent(value) : value;
46
+ return `${key}=${encodedValue}`;
47
+ })
48
+ .join('&');
49
+ // Only prefix if there's a value
50
+ return queryString ? prefixWith + queryString : queryString;
51
+ }
52
+ export const APIIDPrefix = 'cbnode';
53
+ export function logInvalidOrderId(orderIdProperty, expectedOrderIdPrefix, params) {
54
+ console.error(`'${orderIdProperty}' must be prefixed with ${expectedOrderIdPrefix}. Use the 'client.generateNewOrderId()' REST client utility method to generate a fresh order ID on demand. Original request: ${JSON.stringify(params)}`);
55
+ }
56
+ export function getRestBaseUrl(restClientOptions, restClientType) {
57
+ const exchangeBaseUrls = {
58
+ livenet: exchangeBaseURLMap[restClientType],
59
+ testnet: exchangeSandboxURLMap[restClientType],
60
+ };
61
+ if (restClientOptions.baseUrl) {
62
+ return restClientOptions.baseUrl;
63
+ }
64
+ if (restClientOptions.useSandbox === true) {
65
+ return exchangeBaseUrls.testnet;
66
+ }
67
+ return exchangeBaseUrls.livenet;
68
+ }
69
+ //# sourceMappingURL=requestUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestUtils.js","sourceRoot":"","sources":["../../../src/lib/requestUtils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type SignEncodeMethod = 'hex' | 'base64';
2
+ export type SignAlgorithm = 'SHA-256' | 'SHA-512';
3
+ /**
4
+ * Similar to node crypto's `createHash()` function
5
+ */
6
+ export declare function hashMessage(message: string, method: SignEncodeMethod, algorithm: SignAlgorithm): Promise<string>;
7
+ /**
8
+ * Sign a message, with a secret, using the Web Crypto API
9
+ */
10
+ export declare function signMessage(message: string, secret: string, method: SignEncodeMethod, algorithm: SignAlgorithm, secretEncodeMethod: 'base64:web' | 'utf'): Promise<string>;
@@ -0,0 +1,79 @@
1
+ import { neverGuard } from './misc-util.js';
2
+ function bufferToB64(buffer) {
3
+ let binary = '';
4
+ const bytes = new Uint8Array(buffer);
5
+ const len = bytes.byteLength;
6
+ for (let i = 0; i < len; i++) {
7
+ binary += String.fromCharCode(bytes[i]);
8
+ }
9
+ return globalThis.btoa(binary);
10
+ }
11
+ function b64StringToBuffer(input) {
12
+ const binaryString = atob(input); // Decode base64 string
13
+ const buffer = new Uint8Array(binaryString.length);
14
+ // Convert binary string to a Uint8Array
15
+ for (let i = 0; i < binaryString.length; i++) {
16
+ buffer[i] = binaryString.charCodeAt(i);
17
+ }
18
+ return buffer;
19
+ }
20
+ /**
21
+ * Similar to node crypto's `createHash()` function
22
+ */
23
+ export async function hashMessage(message, method, algorithm) {
24
+ const encoder = new TextEncoder();
25
+ const buffer = await globalThis.crypto.subtle.digest(algorithm, encoder.encode(message));
26
+ switch (method) {
27
+ case 'hex': {
28
+ return Array.from(new Uint8Array(buffer))
29
+ .map((byte) => byte.toString(16).padStart(2, '0'))
30
+ .join('');
31
+ }
32
+ case 'base64': {
33
+ return bufferToB64(buffer);
34
+ }
35
+ default: {
36
+ throw neverGuard(method, `Unhandled sign method: "${method}"`);
37
+ }
38
+ }
39
+ }
40
+ /**
41
+ * Sign a message, with a secret, using the Web Crypto API
42
+ */
43
+ export async function signMessage(message, secret, method, algorithm, secretEncodeMethod) {
44
+ const encoder = new TextEncoder();
45
+ let encodedSecret;
46
+ switch (secretEncodeMethod) {
47
+ // case 'base64:node': {
48
+ // encodedSecret = Buffer.from(secret, 'base64');
49
+ // break;
50
+ // }
51
+ case 'base64:web': {
52
+ encodedSecret = b64StringToBuffer(secret);
53
+ break;
54
+ }
55
+ case 'utf': {
56
+ encodedSecret = encoder.encode(secret);
57
+ break;
58
+ }
59
+ default: {
60
+ throw new Error(`Unhandled encoding: "${secretEncodeMethod}"`);
61
+ }
62
+ }
63
+ const key = await globalThis.crypto.subtle.importKey('raw', encodedSecret, { name: 'HMAC', hash: algorithm }, false, ['sign']);
64
+ const buffer = await globalThis.crypto.subtle.sign('HMAC', key, encoder.encode(message));
65
+ switch (method) {
66
+ case 'hex': {
67
+ return Array.from(new Uint8Array(buffer))
68
+ .map((byte) => byte.toString(16).padStart(2, '0'))
69
+ .join('');
70
+ }
71
+ case 'base64': {
72
+ return bufferToB64(buffer);
73
+ }
74
+ default: {
75
+ throw neverGuard(method, `Unhandled sign method: "${method}"`);
76
+ }
77
+ }
78
+ }
79
+ //# sourceMappingURL=webCryptoAPI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webCryptoAPI.js","sourceRoot":"","sources":["../../../src/lib/webCryptoAPI.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import WebSocket from 'isomorphic-ws';
2
+ import { DefaultLogger } from './logger.js';
3
+ import { DeferredPromise, WSConnectedResult, WsConnectionStateEnum, WsStoredState } from './WsStore.types.js';
4
+ /**
5
+ * Simple comparison of two objects, only checks 1-level deep (nested objects won't match)
6
+ */
7
+ export declare function isDeepObjectMatch(object1: unknown, object2: unknown): boolean;
8
+ declare const DEFERRED_PROMISE_REF: {
9
+ readonly CONNECTION_IN_PROGRESS: "CONNECTION_IN_PROGRESS";
10
+ };
11
+ type DeferredPromiseRef = (typeof DEFERRED_PROMISE_REF)[keyof typeof DEFERRED_PROMISE_REF];
12
+ export declare class WsStore<WsKey extends string, TWSTopicSubscribeEventArgs extends string | object> {
13
+ private wsState;
14
+ private logger;
15
+ constructor(logger: typeof DefaultLogger);
16
+ /** Get WS stored state for key, optionally create if missing */
17
+ get(key: WsKey, createIfMissing?: true): WsStoredState<TWSTopicSubscribeEventArgs>;
18
+ get(key: WsKey, createIfMissing?: false): WsStoredState<TWSTopicSubscribeEventArgs> | undefined;
19
+ getKeys(): WsKey[];
20
+ create(key: WsKey): WsStoredState<TWSTopicSubscribeEventArgs> | undefined;
21
+ delete(key: WsKey): void;
22
+ hasExistingActiveConnection(key: WsKey): boolean;
23
+ getWs(key: WsKey): WebSocket | undefined;
24
+ setWs(key: WsKey, wsConnection: WebSocket): WebSocket;
25
+ getDeferredPromise<TSuccessResult = any>(wsKey: WsKey, promiseRef: string | DeferredPromiseRef): DeferredPromise<TSuccessResult> | undefined;
26
+ createDeferredPromise<TSuccessResult = any>(wsKey: WsKey, promiseRef: string | DeferredPromiseRef, throwIfExists: boolean): DeferredPromise<TSuccessResult>;
27
+ resolveDeferredPromise(wsKey: WsKey, promiseRef: string | DeferredPromiseRef, value: unknown, removeAfter: boolean): void;
28
+ rejectDeferredPromise(wsKey: WsKey, promiseRef: string | DeferredPromiseRef, value: unknown, removeAfter: boolean): void;
29
+ removeDeferredPromise(wsKey: WsKey, promiseRef: string | DeferredPromiseRef): void;
30
+ rejectAllDeferredPromises(wsKey: WsKey, reason: string): void;
31
+ /** Get promise designed to track a connection attempt in progress. Resolves once connected. */
32
+ getConnectionInProgressPromise(wsKey: WsKey): DeferredPromise<WSConnectedResult> | undefined;
33
+ /**
34
+ * Create a deferred promise designed to track a connection attempt in progress.
35
+ *
36
+ * Will throw if existing promise is found.
37
+ */
38
+ createConnectionInProgressPromise(wsKey: WsKey, throwIfExists: boolean): DeferredPromise<WSConnectedResult>;
39
+ /** Remove promise designed to track a connection attempt in progress */
40
+ removeConnectingInProgressPromise(wsKey: WsKey): void;
41
+ isWsOpen(key: WsKey): boolean;
42
+ getConnectionState(key: WsKey): WsConnectionStateEnum;
43
+ setConnectionState(key: WsKey, state: WsConnectionStateEnum): void;
44
+ isConnectionState(key: WsKey, state: WsConnectionStateEnum): boolean;
45
+ /**
46
+ * Check if we're currently in the process of opening a connection for any reason. Safer than only checking "CONNECTING" as the state
47
+ * @param key
48
+ * @returns
49
+ */
50
+ isConnectionAttemptInProgress(key: WsKey): boolean;
51
+ getTopics(key: WsKey): Set<TWSTopicSubscribeEventArgs>;
52
+ getTopicsByKey(): Record<string, Set<TWSTopicSubscribeEventArgs>>;
53
+ /**
54
+ * Find matching "topic" request from the store
55
+ * @param key
56
+ * @param topic
57
+ * @returns
58
+ */
59
+ getMatchingTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs): TWSTopicSubscribeEventArgs | undefined;
60
+ addTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs): Set<TWSTopicSubscribeEventArgs>;
61
+ deleteTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs): Set<TWSTopicSubscribeEventArgs>;
62
+ }
63
+ export {};
@@ -0,0 +1,249 @@
1
+ import { DefaultLogger } from './logger.js';
2
+ import { WsConnectionStateEnum, } from './WsStore.types.js';
3
+ /**
4
+ * Simple comparison of two objects, only checks 1-level deep (nested objects won't match)
5
+ */
6
+ export function isDeepObjectMatch(object1, object2) {
7
+ if (typeof object1 === 'string' && typeof object2 === 'string') {
8
+ return object1 === object2;
9
+ }
10
+ if (typeof object1 !== 'object' || typeof object2 !== 'object') {
11
+ return false;
12
+ }
13
+ for (const key in object1) {
14
+ const value1 = object1[key];
15
+ const value2 = object2[key];
16
+ if (value1 !== value2) {
17
+ return false;
18
+ }
19
+ }
20
+ return true;
21
+ }
22
+ const DEFERRED_PROMISE_REF = {
23
+ CONNECTION_IN_PROGRESS: 'CONNECTION_IN_PROGRESS',
24
+ };
25
+ export class WsStore {
26
+ wsState = {};
27
+ logger;
28
+ constructor(logger) {
29
+ this.logger = logger || DefaultLogger;
30
+ }
31
+ get(key, createIfMissing) {
32
+ if (this.wsState[key]) {
33
+ return this.wsState[key];
34
+ }
35
+ if (createIfMissing) {
36
+ return this.create(key);
37
+ }
38
+ }
39
+ getKeys() {
40
+ return Object.keys(this.wsState);
41
+ }
42
+ create(key) {
43
+ if (this.hasExistingActiveConnection(key)) {
44
+ this.logger.info('WsStore setConnection() overwriting existing open connection: ', this.getWs(key));
45
+ }
46
+ this.wsState[key] = {
47
+ subscribedTopics: new Set(),
48
+ connectionState: WsConnectionStateEnum.INITIAL,
49
+ deferredPromiseStore: {},
50
+ };
51
+ return this.get(key);
52
+ }
53
+ delete(key) {
54
+ // TODO: should we allow this at all? Perhaps block this from happening...
55
+ if (this.hasExistingActiveConnection(key)) {
56
+ const ws = this.getWs(key);
57
+ this.logger.info('WsStore deleting state for connection still open: ', ws);
58
+ ws?.close();
59
+ }
60
+ delete this.wsState[key];
61
+ }
62
+ /* connection websocket */
63
+ hasExistingActiveConnection(key) {
64
+ return this.get(key) && this.isWsOpen(key);
65
+ }
66
+ getWs(key) {
67
+ return this.get(key)?.ws;
68
+ }
69
+ setWs(key, wsConnection) {
70
+ if (this.isWsOpen(key)) {
71
+ this.logger.info('WsStore setConnection() overwriting existing open connection: ', this.getWs(key));
72
+ }
73
+ this.get(key, true).ws = wsConnection;
74
+ return wsConnection;
75
+ }
76
+ getDeferredPromise(wsKey, promiseRef) {
77
+ const storeForKey = this.get(wsKey);
78
+ if (!storeForKey) {
79
+ return;
80
+ }
81
+ const deferredPromiseStore = storeForKey.deferredPromiseStore;
82
+ return deferredPromiseStore[promiseRef];
83
+ }
84
+ createDeferredPromise(wsKey, promiseRef, throwIfExists) {
85
+ const existingPromise = this.getDeferredPromise(wsKey, promiseRef);
86
+ if (existingPromise) {
87
+ if (throwIfExists) {
88
+ throw new Error(`Promise exists for "${wsKey}"`);
89
+ }
90
+ else {
91
+ // console.log('existing promise');
92
+ return existingPromise;
93
+ }
94
+ }
95
+ // console.log('create promise');
96
+ const createIfMissing = true;
97
+ const storeForKey = this.get(wsKey, createIfMissing);
98
+ // TODO: Once stable, use Promise.withResolvers in future
99
+ const deferredPromise = {};
100
+ deferredPromise.promise = new Promise((resolve, reject) => {
101
+ deferredPromise.resolve = resolve;
102
+ deferredPromise.reject = reject;
103
+ });
104
+ const deferredPromiseStore = storeForKey.deferredPromiseStore;
105
+ deferredPromiseStore[promiseRef] = deferredPromise;
106
+ return deferredPromise;
107
+ }
108
+ resolveDeferredPromise(wsKey, promiseRef, value, removeAfter) {
109
+ const promise = this.getDeferredPromise(wsKey, promiseRef);
110
+ if (promise?.resolve) {
111
+ promise.resolve(value);
112
+ }
113
+ if (removeAfter) {
114
+ this.removeDeferredPromise(wsKey, promiseRef);
115
+ }
116
+ }
117
+ rejectDeferredPromise(wsKey, promiseRef, value, removeAfter) {
118
+ const promise = this.getDeferredPromise(wsKey, promiseRef);
119
+ if (promise?.reject) {
120
+ promise.reject(value);
121
+ }
122
+ if (removeAfter) {
123
+ this.removeDeferredPromise(wsKey, promiseRef);
124
+ }
125
+ }
126
+ removeDeferredPromise(wsKey, promiseRef) {
127
+ const storeForKey = this.get(wsKey);
128
+ if (!storeForKey) {
129
+ return;
130
+ }
131
+ const deferredPromise = storeForKey.deferredPromiseStore[promiseRef];
132
+ if (deferredPromise) {
133
+ // Just in case it's pending
134
+ if (deferredPromise.resolve) {
135
+ deferredPromise.resolve('promiseRemoved');
136
+ }
137
+ delete storeForKey.deferredPromiseStore[promiseRef];
138
+ }
139
+ }
140
+ rejectAllDeferredPromises(wsKey, reason) {
141
+ const storeForKey = this.get(wsKey);
142
+ const deferredPromiseStore = storeForKey.deferredPromiseStore;
143
+ if (!storeForKey || !deferredPromiseStore) {
144
+ return;
145
+ }
146
+ const reservedKeys = Object.values(DEFERRED_PROMISE_REF);
147
+ for (const promiseRef in deferredPromiseStore) {
148
+ // Skip reserved keys, such as the connection promise
149
+ if (reservedKeys.includes(promiseRef)) {
150
+ continue;
151
+ }
152
+ try {
153
+ this.rejectDeferredPromise(wsKey, promiseRef, reason, true);
154
+ }
155
+ catch (e) {
156
+ this.logger.error(`rejectAllDeferredPromises(): Exception rejecting deferred promise`, { wsKey: wsKey, reason, promiseRef, exception: e });
157
+ }
158
+ }
159
+ }
160
+ /** Get promise designed to track a connection attempt in progress. Resolves once connected. */
161
+ getConnectionInProgressPromise(wsKey) {
162
+ return this.getDeferredPromise(wsKey, DEFERRED_PROMISE_REF.CONNECTION_IN_PROGRESS);
163
+ }
164
+ /**
165
+ * Create a deferred promise designed to track a connection attempt in progress.
166
+ *
167
+ * Will throw if existing promise is found.
168
+ */
169
+ createConnectionInProgressPromise(wsKey, throwIfExists) {
170
+ return this.createDeferredPromise(wsKey, DEFERRED_PROMISE_REF.CONNECTION_IN_PROGRESS, throwIfExists);
171
+ }
172
+ /** Remove promise designed to track a connection attempt in progress */
173
+ removeConnectingInProgressPromise(wsKey) {
174
+ return this.removeDeferredPromise(wsKey, DEFERRED_PROMISE_REF.CONNECTION_IN_PROGRESS);
175
+ }
176
+ /* connection state */
177
+ isWsOpen(key) {
178
+ const existingConnection = this.getWs(key);
179
+ return (!!existingConnection &&
180
+ existingConnection.readyState === existingConnection.OPEN);
181
+ }
182
+ getConnectionState(key) {
183
+ return this.get(key, true).connectionState;
184
+ }
185
+ setConnectionState(key, state) {
186
+ // console.log(new Date(), `setConnectionState(${key}, ${state})`);
187
+ this.get(key, true).connectionState = state;
188
+ }
189
+ isConnectionState(key, state) {
190
+ return this.getConnectionState(key) === state;
191
+ }
192
+ /**
193
+ * Check if we're currently in the process of opening a connection for any reason. Safer than only checking "CONNECTING" as the state
194
+ * @param key
195
+ * @returns
196
+ */
197
+ isConnectionAttemptInProgress(key) {
198
+ const isConnectionInProgress = this.isConnectionState(key, WsConnectionStateEnum.CONNECTING) ||
199
+ this.isConnectionState(key, WsConnectionStateEnum.RECONNECTING);
200
+ return isConnectionInProgress;
201
+ }
202
+ /* subscribed topics */
203
+ getTopics(key) {
204
+ return this.get(key, true).subscribedTopics;
205
+ }
206
+ getTopicsByKey() {
207
+ const result = {};
208
+ for (const refKey in this.wsState) {
209
+ result[refKey] = this.getTopics(refKey);
210
+ }
211
+ return result;
212
+ }
213
+ // Since topics are objects we can't rely on the set to detect duplicates
214
+ /**
215
+ * Find matching "topic" request from the store
216
+ * @param key
217
+ * @param topic
218
+ * @returns
219
+ */
220
+ getMatchingTopic(key, topic) {
221
+ // if (typeof topic === 'string') {
222
+ // return this.getMatchingTopic(key, { channel: topic });
223
+ // }
224
+ const allTopics = this.getTopics(key).values();
225
+ for (const storedTopic of allTopics) {
226
+ if (isDeepObjectMatch(topic, storedTopic)) {
227
+ return storedTopic;
228
+ }
229
+ }
230
+ }
231
+ addTopic(key, topic) {
232
+ // console.log(`wsStore.addTopic(${key}, ${topic})`);
233
+ // Check for duplicate topic. If already tracked, don't store this one
234
+ const existingTopic = this.getMatchingTopic(key, topic);
235
+ if (existingTopic) {
236
+ return this.getTopics(key);
237
+ }
238
+ return this.getTopics(key).add(topic);
239
+ }
240
+ deleteTopic(key, topic) {
241
+ // Check if we're subscribed to a topic like this
242
+ const storedTopic = this.getMatchingTopic(key, topic);
243
+ if (storedTopic) {
244
+ this.getTopics(key).delete(storedTopic);
245
+ }
246
+ return this.getTopics(key);
247
+ }
248
+ }
249
+ //# sourceMappingURL=WsStore.js.map