current-bitcoin-price 1.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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/dist/index.d.ts +19 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +18 -0
  6. package/dist/price/BitcoinPriceService.d.ts +3 -0
  7. package/dist/price/BitcoinPriceService.d.ts.map +1 -0
  8. package/dist/price/BitcoinPriceService.js +2 -0
  9. package/dist/price/CoinGeckoProvider.d.ts +12 -0
  10. package/dist/price/CoinGeckoProvider.d.ts.map +1 -0
  11. package/dist/price/CoinGeckoProvider.js +35 -0
  12. package/dist/price/PriceProvider.d.ts +80 -0
  13. package/dist/price/PriceProvider.d.ts.map +1 -0
  14. package/dist/price/PriceProvider.js +86 -0
  15. package/dist/price/PriceProviderFactory.d.ts +2 -0
  16. package/dist/price/PriceProviderFactory.d.ts.map +1 -0
  17. package/dist/price/PriceProviderFactory.js +3 -0
  18. package/dist/price/PriceProviders.d.ts +5 -0
  19. package/dist/price/PriceProviders.d.ts.map +1 -0
  20. package/dist/price/PriceProviders.js +5 -0
  21. package/dist/price/__tests__/fetchCurrentPrice.test.d.ts +2 -0
  22. package/dist/price/__tests__/fetchCurrentPrice.test.d.ts.map +1 -0
  23. package/dist/price/__tests__/fetchCurrentPrice.test.js +42 -0
  24. package/dist/price/binance/BinanceProvider.d.ts +23 -0
  25. package/dist/price/binance/BinanceProvider.d.ts.map +1 -0
  26. package/dist/price/binance/BinanceProvider.js +53 -0
  27. package/dist/price/binance/__tests__/BinanceProvider.integration.test.d.ts +2 -0
  28. package/dist/price/binance/__tests__/BinanceProvider.integration.test.d.ts.map +1 -0
  29. package/dist/price/binance/__tests__/BinanceProvider.integration.test.js +19 -0
  30. package/dist/price/binance/__tests__/BinanceProvider.test.d.ts +2 -0
  31. package/dist/price/binance/__tests__/BinanceProvider.test.d.ts.map +1 -0
  32. package/dist/price/binance/__tests__/BinanceProvider.test.js +53 -0
  33. package/dist/price/coinGecko/CoinGeckoProvider.d.ts +18 -0
  34. package/dist/price/coinGecko/CoinGeckoProvider.d.ts.map +1 -0
  35. package/dist/price/coinGecko/CoinGeckoProvider.js +42 -0
  36. package/dist/price/coinGecko/__tests__/CoinGeckoProvider.integration.test.d.ts +2 -0
  37. package/dist/price/coinGecko/__tests__/CoinGeckoProvider.integration.test.d.ts.map +1 -0
  38. package/dist/price/coinGecko/__tests__/CoinGeckoProvider.integration.test.js +18 -0
  39. package/dist/price/coinGecko/__tests__/CoinGeckoProvider.test.d.ts +2 -0
  40. package/dist/price/coinGecko/__tests__/CoinGeckoProvider.test.d.ts.map +1 -0
  41. package/dist/price/coinGecko/__tests__/CoinGeckoProvider.test.js +45 -0
  42. package/dist/price/createPriceProvider.d.ts +5 -0
  43. package/dist/price/createPriceProvider.d.ts.map +1 -0
  44. package/dist/price/createPriceProvider.js +13 -0
  45. package/dist/price/createPriceProvider.test.d.ts +2 -0
  46. package/dist/price/createPriceProvider.test.d.ts.map +1 -0
  47. package/dist/price/createPriceProvider.test.js +25 -0
  48. package/dist/price/fetchCurrentPrice.d.ts +7 -0
  49. package/dist/price/fetchCurrentPrice.d.ts.map +1 -0
  50. package/dist/price/fetchCurrentPrice.js +7 -0
  51. package/dist/types.d.ts +15 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +5 -0
  54. package/dist/utils.d.ts +9 -0
  55. package/dist/utils.d.ts.map +1 -0
  56. package/dist/utils.js +8 -0
  57. package/dist/vitest.config.d.ts +3 -0
  58. package/dist/vitest.config.d.ts.map +1 -0
  59. package/dist/vitest.config.js +10 -0
  60. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 MatΔ›j "Matt" HusΓ‘k
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # πŸš€ current-bitcoin-price
2
+
3
+ A tiny, friendly TypeScript library to get the current Bitcoin price from pluggable providers (CoinGecko, Binance, ...). 🎯
4
+
5
+ **Quick summary** (2 lines)
6
+ - Use `fetchCurrentPrice()` for a one-line price lookup (defaults to CoinGecko). ⚑
7
+ - The library uses a Result pattern (ok / err) β€” no throws for expected failures. βœ…
8
+
9
+ πŸ”” More providers coming soon β€” this is the strength of the package
10
+ - We ship a few providers today (CoinGecko default, Binance support) and will add more exchanges and data sources in upcoming releases. The pluggable provider design makes it easy to add and swap providers without changing your application logic. πŸŒπŸ”Œ
11
+
12
+ ## ✨ Quick example (public usage)
13
+
14
+ ```ts
15
+ import { fetchCurrentPrice } from './src/price/fetchCurrentPrice.js'
16
+
17
+ const res = await fetchCurrentPrice({}) // defaults to CoinGecko, USD (you can override both)
18
+ if (res.success) {
19
+ console.log('BTC (USD):', res.value) // β†’ 12345.67
20
+ } else {
21
+ console.warn('Could not fetch price:', res.error)
22
+ }
23
+ ```
24
+
25
+ ## πŸ“ˆ Get price + trend from a provider (advanced & small extra step)
26
+
27
+ ```ts
28
+ import { createPriceProvider } from './src/price/createPriceProvider.js'
29
+ import { PriceProviders } from './src/price/PriceProviders.js'
30
+
31
+ const provider = createPriceProvider(PriceProviders.COINGECKO)
32
+ // first call will populate the provider's last price
33
+ const res = await provider.getCurrentPrice('usd')
34
+ if (res.success) {
35
+ console.log('BTC (USD):', res.value)
36
+ console.log('trend:', provider.getTrend()) // 'up' | 'down' | 'stable' πŸ”Ί/πŸ”»/➑️
37
+ }
38
+ ```
39
+
40
+ ## 🧩 Result pattern
41
+ - Every call returns either `{ success: true, value }` or `{ success: false, error }`.
42
+ - This makes error handling explicit and composable β€” you check `res.success` and handle both cases. πŸ›‘οΈ
43
+
44
+ ## πŸ”§ Using a provider directly (advanced)
45
+
46
+ ```ts
47
+ import { createPriceProvider } from './src/price/createPriceProvider.js'
48
+ import { PriceProviders } from './src/price/PriceProviders.js'
49
+
50
+ const provider = createPriceProvider(PriceProviders.BINANCE)
51
+ const res = await provider.getCurrentPrice('usd')
52
+ if (res.success) console.log('price:', res.value)
53
+ ```
54
+
55
+ ## πŸ“Š Trend (up / down / stable)
56
+ - Providers internally compute a simple trend when they fetch a new price by comparing to the previous value.
57
+ - The trend is one of: `"up" | "down" | "stable"`.
58
+ - Want the trend? Use `provider.getTrend()` after a successful call. πŸ‘
59
+
60
+ ---
61
+
62
+ ## ❀️ Feel free to support
63
+ Lately, I've been spending a lot of time building open-source libraries like this one. If you find it useful, consider supporting my work: `bc1qh9nvunhut73hqwf9rsd6l6c0dqqlkv9j3a723n`. More cool libraries are coming soon! πŸ™
64
+
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Exporting abstract PriceProvider class in case of custom implementations.
3
+ */
4
+ export { PriceProvider } from './price/PriceProvider.js';
5
+ /**
6
+ * Factory function to create price provider instances.
7
+ */
8
+ export { createPriceProvider } from './price/createPriceProvider.js';
9
+ /**
10
+ * Common types used across the library.
11
+ */
12
+ export { FIAT } from './types.js';
13
+ export { PriceProviders } from './price/PriceProviders.js';
14
+ /**
15
+ * Function to fetch the current price using the default provider.
16
+ * FP approach.
17
+ */
18
+ export { fetchCurrentPrice } from './price/fetchCurrentPrice.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;GAEG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE;;GAEG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D;;;GAGG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Exporting abstract PriceProvider class in case of custom implementations.
3
+ */
4
+ export { PriceProvider } from './price/PriceProvider.js';
5
+ /**
6
+ * Factory function to create price provider instances.
7
+ */
8
+ export { createPriceProvider } from './price/createPriceProvider.js';
9
+ /**
10
+ * Common types used across the library.
11
+ */
12
+ export { FIAT } from './types.js';
13
+ export { PriceProviders } from './price/PriceProviders.js';
14
+ /**
15
+ * Function to fetch the current price using the default provider.
16
+ * FP approach.
17
+ */
18
+ export { fetchCurrentPrice } from './price/fetchCurrentPrice.js';
@@ -0,0 +1,3 @@
1
+ export declare class BitcoinPriceService {
2
+ }
3
+ //# sourceMappingURL=BitcoinPriceService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BitcoinPriceService.d.ts","sourceRoot":"","sources":["../../src/price/BitcoinPriceService.ts"],"names":[],"mappings":"AAAA,qBAAa,mBAAmB;CAE/B"}
@@ -0,0 +1,2 @@
1
+ export class BitcoinPriceService {
2
+ }
@@ -0,0 +1,12 @@
1
+ import { PriceProvider } from "./PriceProvider.js";
2
+ export declare class CoinGeckoProvider extends PriceProvider {
3
+ protected baseApiUrl: string;
4
+ protected price: number;
5
+ protected prepareRequestHeaders(): Record<string, string>;
6
+ /**
7
+ * Fetch the current price for an asset (defaults to bitcoin/usd)
8
+ */
9
+ getCurrentPrice(assetId?: string, fiat?: string): Promise<number>;
10
+ }
11
+ export default CoinGeckoProvider;
12
+ //# sourceMappingURL=CoinGeckoProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CoinGeckoProvider.d.ts","sourceRoot":"","sources":["../../src/price/CoinGeckoProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAEjD,qBAAa,iBAAkB,SAAQ,aAAa;IAEhD,SAAS,CAAC,UAAU,SAAsC;IAG1D,SAAS,CAAC,KAAK,EAAE,MAAM,CAAK;IAG5B,SAAS,CAAC,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAMzD;;OAEG;IACG,eAAe,CAAC,OAAO,SAAY,EAAE,IAAI,SAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;CAqB5E;AAED,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { PriceProvider } from "./PriceProvider.js";
2
+ export class CoinGeckoProvider extends PriceProvider {
3
+ constructor() {
4
+ super(...arguments);
5
+ // Concrete base URL required by the base class
6
+ this.baseApiUrl = 'https://api.coingecko.com/api/v3';
7
+ // Keep last known price; initialized to 0 for definite assignment
8
+ this.price = 0;
9
+ }
10
+ // CoinGecko doesn't need special headers for the public endpoints
11
+ prepareRequestHeaders() {
12
+ return {
13
+ 'Accept': 'application/json'
14
+ };
15
+ }
16
+ /**
17
+ * Fetch the current price for an asset (defaults to bitcoin/usd)
18
+ */
19
+ async getCurrentPrice(assetId = 'bitcoin', fiat = 'usd') {
20
+ const endpoint = `simple/price?ids=${encodeURIComponent(assetId)}&vs_currencies=${encodeURIComponent(fiat)}`;
21
+ const data = await this.queryApi(endpoint);
22
+ if (!data) {
23
+ throw new Error('CoinGecko request failed');
24
+ }
25
+ const price = data[assetId]?.[fiat];
26
+ if (typeof price !== 'number') {
27
+ throw new Error('Unexpected CoinGecko response shape');
28
+ }
29
+ // update trend based on previous price then set new price
30
+ this.setTrend(price);
31
+ this.price = price;
32
+ return price;
33
+ }
34
+ }
35
+ export default CoinGeckoProvider;
@@ -0,0 +1,80 @@
1
+ import { FIAT, type Result, type Trend } from '../types.js';
2
+ export declare abstract class PriceProvider {
3
+ /**
4
+ * Base URL for the price service API.
5
+ * @protected
6
+ */
7
+ protected abstract baseApiUrl: string;
8
+ /**
9
+ * API endpoints for the price service.
10
+ * ROADMAP: consider adding types for endpoints. + support for history rates.
11
+ * @protected
12
+ */
13
+ protected abstract endpoints: Record<string, string>;
14
+ /**
15
+ * Current price of the asset.
16
+ * Used to determine trend.
17
+ *
18
+ * ROADMAP: implement a caching mechanism to store the previous price
19
+ * @protected
20
+ */
21
+ protected price: number;
22
+ /**
23
+ * Current trend of the asset price.
24
+ * Compares to previously fetched price.
25
+ * @protected
26
+ */
27
+ protected trend: Trend;
28
+ /**
29
+ * API key for accessing the price service.
30
+ * NULL by default, since default APIs are free.
31
+ * @protected
32
+ */
33
+ private apiKey;
34
+ /**
35
+ * Provider supported fiat representation of BTC price.
36
+ * @protected
37
+ */
38
+ protected abstract supportedFiat: Partial<FIAT>[];
39
+ /**
40
+ * Constructor for PriceProvider.
41
+ * @param apiKey
42
+ */
43
+ protected constructor(apiKey?: string);
44
+ /**
45
+ * Queries the API endpoint with optional parameters.
46
+ * @param endpoint
47
+ * @protected
48
+ */
49
+ protected queryApi<T>(endpoint: string): Promise<Result<T, string>>;
50
+ /**
51
+ * Updates the trend based on the current price.
52
+ * Has to be called after fetching a new price and before updating the price property.
53
+ * @param currentPrice
54
+ * @protected
55
+ */
56
+ protected setTrend(currentPrice: number): void;
57
+ /**
58
+ * Fetches the current price for Bitcoin.
59
+ * Implementations are asynchronous and should return a Promise<number>.
60
+ * @protected
61
+ */
62
+ protected abstract getCurrentPrice(): Promise<Result<number, string>>;
63
+ /**
64
+ * Constructs the full endpoint URL.
65
+ * @param endpoint
66
+ * @protected
67
+ */
68
+ protected setupUrl(endpoint: string): string;
69
+ /**
70
+ * Prepares the request headers for API calls.
71
+ * Provider-specific implementation required.
72
+ * @protected
73
+ */
74
+ protected abstract prepareRequestHeaders(): Record<string, string>;
75
+ /**
76
+ * Public accessor for the last computed trend ('up'|'down'|'stable').
77
+ */
78
+ getTrend(): Trend;
79
+ }
80
+ //# sourceMappingURL=PriceProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PriceProvider.d.ts","sourceRoot":"","sources":["../../src/price/PriceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAG5D,8BAAsB,aAAa;IACjC;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAEtC;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAErD;;;;;;OAMG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,CAAK;IAE5B;;;;OAIG;IACH,SAAS,CAAC,KAAK,EAAE,KAAK,CAAY;IAElC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAuB;IAErC;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IAElD;;;OAGG;IACH,SAAS,aAAa,MAAM,CAAC,EAAE,MAAM;IAIrC;;;;OAIG;cACa,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAsBzE;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAe9C;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAErE;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI5C;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAElE;;OAEG;IACI,QAAQ,IAAI,KAAK;CAGzB"}
@@ -0,0 +1,86 @@
1
+ import { FIAT } from '../types.js';
2
+ import { ok, err } from '../utils.js';
3
+ export class PriceProvider {
4
+ /**
5
+ * Constructor for PriceProvider.
6
+ * @param apiKey
7
+ */
8
+ constructor(apiKey) {
9
+ /**
10
+ * Current price of the asset.
11
+ * Used to determine trend.
12
+ *
13
+ * ROADMAP: implement a caching mechanism to store the previous price
14
+ * @protected
15
+ */
16
+ this.price = 0;
17
+ /**
18
+ * Current trend of the asset price.
19
+ * Compares to previously fetched price.
20
+ * @protected
21
+ */
22
+ this.trend = 'stable';
23
+ /**
24
+ * API key for accessing the price service.
25
+ * NULL by default, since default APIs are free.
26
+ * @protected
27
+ */
28
+ this.apiKey = null;
29
+ if (apiKey)
30
+ this.apiKey = apiKey;
31
+ }
32
+ /**
33
+ * Queries the API endpoint with optional parameters.
34
+ * @param endpoint
35
+ * @protected
36
+ */
37
+ async queryApi(endpoint) {
38
+ const headers = this.prepareRequestHeaders() || {};
39
+ const url = this.setupUrl(endpoint);
40
+ const result = await fetch(url, {
41
+ method: 'GET',
42
+ headers,
43
+ });
44
+ if (!result.ok) {
45
+ return err(`API request failed with status ${result.status}: ${result.statusText}`);
46
+ }
47
+ // ROADMAP: implement data validation here for T
48
+ const parsed = (await result.json());
49
+ return ok(parsed);
50
+ }
51
+ /**
52
+ * Updates the trend based on the current price.
53
+ * Has to be called after fetching a new price and before updating the price property.
54
+ * @param currentPrice
55
+ * @protected
56
+ */
57
+ setTrend(currentPrice) {
58
+ // if no previous price, cannot determine trend
59
+ if (this.price === 0) {
60
+ return;
61
+ }
62
+ if (currentPrice > this.price) {
63
+ this.trend = 'up';
64
+ }
65
+ else if (currentPrice < this.price) {
66
+ this.trend = 'down';
67
+ }
68
+ else {
69
+ this.trend = 'stable';
70
+ }
71
+ }
72
+ /**
73
+ * Constructs the full endpoint URL.
74
+ * @param endpoint
75
+ * @protected
76
+ */
77
+ setupUrl(endpoint) {
78
+ return `${this.baseApiUrl}/${endpoint}`;
79
+ }
80
+ /**
81
+ * Public accessor for the last computed trend ('up'|'down'|'stable').
82
+ */
83
+ getTrend() {
84
+ return this.trend;
85
+ }
86
+ }
@@ -0,0 +1,2 @@
1
+ export declare const createPriceProviderFactory: () => void;
2
+ //# sourceMappingURL=PriceProviderFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PriceProviderFactory.d.ts","sourceRoot":"","sources":["../../src/price/PriceProviderFactory.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,0BAA0B,YAEtC,CAAA"}
@@ -0,0 +1,3 @@
1
+ export const createPriceProviderFactory = () => {
2
+ // TODO implement factory logic to create and return different price provider instances
3
+ };
@@ -0,0 +1,5 @@
1
+ export declare enum PriceProviders {
2
+ COINGECKO = "coingecko",
3
+ BINANCE = "binance"
4
+ }
5
+ //# sourceMappingURL=PriceProviders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PriceProviders.d.ts","sourceRoot":"","sources":["../../src/price/PriceProviders.ts"],"names":[],"mappings":"AAAA,oBAAY,cAAc;IACxB,SAAS,cAAc;IACvB,OAAO,YAAY;CACpB"}
@@ -0,0 +1,5 @@
1
+ export var PriceProviders;
2
+ (function (PriceProviders) {
3
+ PriceProviders["COINGECKO"] = "coingecko";
4
+ PriceProviders["BINANCE"] = "binance";
5
+ })(PriceProviders || (PriceProviders = {}));
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fetchCurrentPrice.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchCurrentPrice.test.d.ts","sourceRoot":"","sources":["../../../src/price/__tests__/fetchCurrentPrice.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ import { vi, describe, it, expect, beforeEach, afterEach, } from 'vitest';
2
+ // Mock the createPriceProvider module before importing the function under test
3
+ vi.mock('../createPriceProvider.js', () => ({
4
+ createPriceProvider: vi.fn(),
5
+ }));
6
+ import { fetchCurrentPrice } from '../fetchCurrentPrice.js';
7
+ import { PriceProviders } from '../PriceProviders.js';
8
+ import * as cpModule from '../createPriceProvider.js';
9
+ describe(fetchCurrentPrice.name, () => {
10
+ beforeEach(() => {
11
+ vi.restoreAllMocks();
12
+ });
13
+ afterEach(() => {
14
+ vi.resetAllMocks();
15
+ });
16
+ it('uses CoinGecko by default and returns success result', async () => {
17
+ const fakeProvider = {
18
+ getCurrentPrice: vi
19
+ .fn()
20
+ .mockResolvedValue({ success: true, value: 4242 }),
21
+ };
22
+ const mockedCreate = cpModule.createPriceProvider;
23
+ mockedCreate.mockReturnValue(fakeProvider);
24
+ const res = await fetchCurrentPrice({});
25
+ expect(cpModule.createPriceProvider).toHaveBeenCalledWith(PriceProviders.COINGECKO);
26
+ expect(res).toEqual({ success: true, value: 4242 });
27
+ expect(fakeProvider.getCurrentPrice).toHaveBeenCalledWith('usd');
28
+ });
29
+ it('passes provided provider to factory and returns error result', async () => {
30
+ const fakeProvider = {
31
+ getCurrentPrice: vi
32
+ .fn()
33
+ .mockResolvedValue({ success: false, error: 'oops' }),
34
+ };
35
+ const mockedCreate = cpModule.createPriceProvider;
36
+ mockedCreate.mockReturnValue(fakeProvider);
37
+ const res = await fetchCurrentPrice({ provider: PriceProviders.BINANCE });
38
+ expect(cpModule.createPriceProvider).toHaveBeenCalledWith(PriceProviders.BINANCE);
39
+ expect(res).toEqual({ success: false, error: 'oops' });
40
+ expect(fakeProvider.getCurrentPrice).toHaveBeenCalledWith('usd');
41
+ });
42
+ });
@@ -0,0 +1,23 @@
1
+ import { PriceProvider } from '../PriceProvider.js';
2
+ import { FIAT, type Result } from '../../types.js';
3
+ /**
4
+ * Implementation of PriceProvider for Binance public API.
5
+ * Docs: https://api.binance.com
6
+ */
7
+ export declare class BinanceProvider extends PriceProvider {
8
+ protected baseApiUrl: string;
9
+ protected endpoints: {
10
+ currentPrice: string;
11
+ };
12
+ protected supportedFiat: FIAT[];
13
+ protected price: number;
14
+ constructor(apiKey?: string);
15
+ protected prepareRequestHeaders(): Record<string, string>;
16
+ /**
17
+ * Map fiat to Binance symbol suffix. For USD we use USDT as Binance often provides BTCUSDT.
18
+ */
19
+ protected mapFiatToSymbolSuffix(fiat: FIAT): string;
20
+ getCurrentPrice(fiat?: FIAT): Promise<Result<number, string>>;
21
+ }
22
+ export default BinanceProvider;
23
+ //# sourceMappingURL=BinanceProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BinanceProvider.d.ts","sourceRoot":"","sources":["../../../src/price/binance/BinanceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,aAAa;IAChD,SAAS,CAAC,UAAU,SAA6B;IAEjD,SAAS,CAAC,SAAS;;MAEjB;IAGF,SAAS,CAAC,aAAa,SAAwB;IAE/C,SAAS,CAAC,KAAK,EAAE,MAAM,CAAK;gBAEhB,MAAM,CAAC,EAAE,MAAM;IAI3B,SAAS,CAAC,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAMzD;;OAEG;IACH,SAAS,CAAC,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAO7C,eAAe,CAAC,IAAI,OAAW,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAwBxE;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { PriceProvider } from '../PriceProvider.js';
2
+ import { ok, err } from '../../utils.js';
3
+ import { FIAT } from '../../types.js';
4
+ /**
5
+ * Implementation of PriceProvider for Binance public API.
6
+ * Docs: https://api.binance.com
7
+ */
8
+ export class BinanceProvider extends PriceProvider {
9
+ constructor(apiKey) {
10
+ super(apiKey);
11
+ this.baseApiUrl = 'https://api.binance.com';
12
+ this.endpoints = {
13
+ currentPrice: 'api/v3/ticker/price',
14
+ };
15
+ // Support common fiats; map usd to USDT for Binance pairs
16
+ this.supportedFiat = [FIAT.USD, FIAT.EUR];
17
+ this.price = 0;
18
+ }
19
+ prepareRequestHeaders() {
20
+ return {
21
+ Accept: 'application/json',
22
+ };
23
+ }
24
+ /**
25
+ * Map fiat to Binance symbol suffix. For USD we use USDT as Binance often provides BTCUSDT.
26
+ */
27
+ mapFiatToSymbolSuffix(fiat) {
28
+ const f = fiat.toLowerCase();
29
+ if (f === FIAT.USD)
30
+ return 'USDT';
31
+ if (f === FIAT.EUR)
32
+ return 'EUR';
33
+ return f.toUpperCase();
34
+ }
35
+ async getCurrentPrice(fiat = FIAT.USD) {
36
+ const suffix = this.mapFiatToSymbolSuffix(fiat);
37
+ const symbol = `BTC${suffix}`;
38
+ const endpoint = `${this.endpoints.currentPrice}?symbol=${encodeURIComponent(symbol)}`;
39
+ const result = await this.queryApi(endpoint);
40
+ if (!result.success) {
41
+ return err(result.error);
42
+ }
43
+ const priceStr = result.value?.price;
44
+ const price = Number(priceStr);
45
+ if (!price || Number.isNaN(price)) {
46
+ return err('Invalid API response: price not found');
47
+ }
48
+ this.setTrend(price);
49
+ this.price = price;
50
+ return ok(price);
51
+ }
52
+ }
53
+ export default BinanceProvider;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=BinanceProvider.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BinanceProvider.integration.test.d.ts","sourceRoot":"","sources":["../../../../src/price/binance/__tests__/BinanceProvider.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import BinanceProvider from '../BinanceProvider.js';
3
+ import { FIAT } from '../../../types.js';
4
+ const runIntegration = Boolean(process.env.RUN_INTEGRATION);
5
+ describe('BinanceProvider (integration)', () => {
6
+ it('fetches real BTC price from Binance (skip unless RUN_INTEGRATION=true)', async () => {
7
+ if (!runIntegration) {
8
+ console.warn('Skipping integration test - set RUN_INTEGRATION=true to enable');
9
+ return;
10
+ }
11
+ const p = new BinanceProvider();
12
+ const res = await p.getCurrentPrice(FIAT.USD);
13
+ expect(res.success).toBe(true);
14
+ if (res.success) {
15
+ expect(typeof res.value).toBe('number');
16
+ expect(res.value).toBeGreaterThan(0);
17
+ }
18
+ });
19
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=BinanceProvider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BinanceProvider.test.d.ts","sourceRoot":"","sources":["../../../../src/price/binance/__tests__/BinanceProvider.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,53 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import BinanceProvider from '../BinanceProvider.js';
3
+ import { FIAT } from '../../../types.js';
4
+ function makeJsonResponse(obj) {
5
+ // Create a minimal object shaped like a Response and cast it to Response for typing in tests
6
+ const fake = {
7
+ ok: true,
8
+ status: 200,
9
+ statusText: 'OK',
10
+ json: () => Promise.resolve(obj),
11
+ };
12
+ return Promise.resolve(fake);
13
+ }
14
+ describe('BinanceProvider (unit)', () => {
15
+ let originalFetch;
16
+ beforeEach(() => {
17
+ originalFetch = globalThis.fetch;
18
+ vi.restoreAllMocks();
19
+ });
20
+ afterEach(() => {
21
+ if (originalFetch)
22
+ globalThis.fetch = originalFetch;
23
+ });
24
+ it('parses price correctly', async () => {
25
+ globalThis.fetch = vi.fn(() => makeJsonResponse({ symbol: 'BTCUSDT', price: '60000.12' }));
26
+ const p = new BinanceProvider();
27
+ const res = await p.getCurrentPrice(FIAT.USD);
28
+ expect(res.success).toBe(true);
29
+ if (res.success)
30
+ expect(res.value).toBeCloseTo(60000.12);
31
+ });
32
+ it('handles non-ok response', async () => {
33
+ const fakeErrorResponse = Promise.resolve({
34
+ ok: false,
35
+ status: 500,
36
+ statusText: 'err',
37
+ });
38
+ globalThis.fetch = vi.fn(() => fakeErrorResponse);
39
+ const p = new BinanceProvider();
40
+ const res = await p.getCurrentPrice(FIAT.USD);
41
+ expect(res.success).toBe(false);
42
+ if (!res.success)
43
+ expect(res.error).toMatch(/API request failed/);
44
+ });
45
+ it('handles invalid price', async () => {
46
+ globalThis.fetch = vi.fn(() => makeJsonResponse({ symbol: 'BTCUSDT', price: 'NaN' }));
47
+ const p = new BinanceProvider();
48
+ const res = await p.getCurrentPrice(FIAT.USD);
49
+ expect(res.success).toBe(false);
50
+ if (!res.success)
51
+ expect(res.error).toMatch(/Invalid API response/);
52
+ });
53
+ });
@@ -0,0 +1,18 @@
1
+ import { PriceProvider } from '../PriceProvider.js';
2
+ import { FIAT, type Result } from '../../types.js';
3
+ /**
4
+ * Implementation of PriceProvider for CoinGecko API.
5
+ * API Documentation: https://www.coingecko.com/en/api/documentation
6
+ */
7
+ export declare class CoinGeckoProvider extends PriceProvider {
8
+ protected baseApiUrl: string;
9
+ protected endpoints: {
10
+ currentPrice: string;
11
+ };
12
+ protected supportedFiat: FIAT[];
13
+ protected price: number;
14
+ constructor(apiKey?: string);
15
+ protected prepareRequestHeaders(): Record<string, string>;
16
+ getCurrentPrice(fiat?: string): Promise<Result<number, string>>;
17
+ }
18
+ //# sourceMappingURL=CoinGeckoProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CoinGeckoProvider.d.ts","sourceRoot":"","sources":["../../../src/price/coinGecko/CoinGeckoProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,aAAa;IAClD,SAAS,CAAC,UAAU,SAAsC;IAE1D,SAAS,CAAC,SAAS;;MAEjB;IAEF,SAAS,CAAC,aAAa,SAAwB;IAE/C,SAAS,CAAC,KAAK,EAAE,MAAM,CAAK;gBAEhB,MAAM,CAAC,EAAE,MAAM;IAK3B,SAAS,CAAC,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAMnD,eAAe,CAAC,IAAI,SAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAwBrE"}
@@ -0,0 +1,42 @@
1
+ import { PriceProvider } from '../PriceProvider.js';
2
+ import { err, ok } from '../../utils.js';
3
+ import { FIAT } from '../../types.js';
4
+ /**
5
+ * Implementation of PriceProvider for CoinGecko API.
6
+ * API Documentation: https://www.coingecko.com/en/api/documentation
7
+ */
8
+ export class CoinGeckoProvider extends PriceProvider {
9
+ constructor(apiKey) {
10
+ super(apiKey);
11
+ this.baseApiUrl = 'https://api.coingecko.com/api/v3';
12
+ this.endpoints = {
13
+ currentPrice: 'simple/price',
14
+ };
15
+ this.supportedFiat = [FIAT.USD, FIAT.EUR];
16
+ this.price = 0;
17
+ }
18
+ // CoinGecko doesn't need special headers for the public endpoints
19
+ prepareRequestHeaders() {
20
+ return {
21
+ Accept: 'application/json',
22
+ };
23
+ }
24
+ async getCurrentPrice(fiat = 'usd') {
25
+ const url = new URLSearchParams({
26
+ ids: 'bitcoin',
27
+ vs_currencies: fiat,
28
+ });
29
+ const endpoint = `${this.endpoints.currentPrice}?${url.toString()}`;
30
+ const result = await this.queryApi(endpoint);
31
+ if (!result.success) {
32
+ return err(result.error);
33
+ }
34
+ const price = result.value['bitcoin']?.[fiat];
35
+ if (typeof price !== 'number') {
36
+ return err('Invalid API response: price not found');
37
+ }
38
+ this.setTrend(price);
39
+ this.price = price;
40
+ return ok(price);
41
+ }
42
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=CoinGeckoProvider.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CoinGeckoProvider.integration.test.d.ts","sourceRoot":"","sources":["../../../../src/price/coinGecko/__tests__/CoinGeckoProvider.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { CoinGeckoProvider } from '../CoinGeckoProvider.js';
3
+ const runIntegration = Boolean(process.env.RUN_INTEGRATION);
4
+ describe('CoinGeckoProvider (integration)', () => {
5
+ it('fetches real BTC price from CoinGecko (skip unless RUN_INTEGRATION=true)', async () => {
6
+ if (!runIntegration) {
7
+ console.warn('Skipping integration test - set RUN_INTEGRATION=true to enable');
8
+ return;
9
+ }
10
+ const p = new CoinGeckoProvider();
11
+ const res = await p.getCurrentPrice('usd');
12
+ expect(res.success).toBe(true);
13
+ if (res.success) {
14
+ expect(typeof res.value).toBe('number');
15
+ expect(res.value).toBeGreaterThan(0);
16
+ }
17
+ });
18
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=CoinGeckoProvider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CoinGeckoProvider.test.d.ts","sourceRoot":"","sources":["../../../../src/price/coinGecko/__tests__/CoinGeckoProvider.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,45 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { CoinGeckoProvider } from '../CoinGeckoProvider.js';
3
+ function makeJsonResponse(obj, okFlag = true) {
4
+ return Promise.resolve({
5
+ ok: okFlag,
6
+ json: () => Promise.resolve(obj),
7
+ });
8
+ }
9
+ describe(CoinGeckoProvider.name, () => {
10
+ let originalFetch;
11
+ beforeEach(() => {
12
+ originalFetch = globalThis.fetch;
13
+ vi.restoreAllMocks();
14
+ });
15
+ afterEach(() => {
16
+ globalThis.fetch = originalFetch;
17
+ });
18
+ it('returns ok result with numeric price', async () => {
19
+ globalThis.fetch = vi.fn(() => makeJsonResponse({ bitcoin: { usd: 12345 } }));
20
+ const p = new CoinGeckoProvider();
21
+ const res = await p.getCurrentPrice('usd');
22
+ expect(res.success).toBe(true);
23
+ if (res.success) {
24
+ expect(res.value).toBe(12345);
25
+ }
26
+ });
27
+ it('returns error when response not ok', async () => {
28
+ globalThis.fetch = vi.fn(() => Promise.resolve({ ok: false, status: 500, statusText: 'err' }));
29
+ const p = new CoinGeckoProvider();
30
+ const res = await p.getCurrentPrice('usd');
31
+ expect(res.success).toBe(false);
32
+ if (!res.success) {
33
+ expect(res.error).toContain('API request failed');
34
+ }
35
+ });
36
+ it('returns error when price shape is unexpected', async () => {
37
+ globalThis.fetch = vi.fn(() => makeJsonResponse({ btc: { usd: 'NaN' } }));
38
+ const p = new CoinGeckoProvider();
39
+ const res = await p.getCurrentPrice('usd');
40
+ expect(res.success).toBe(false);
41
+ if (!res.success) {
42
+ expect(res.error).toMatch(/Invalid API response/i);
43
+ }
44
+ });
45
+ });
@@ -0,0 +1,5 @@
1
+ import { CoinGeckoProvider } from './coinGecko/CoinGeckoProvider.js';
2
+ import { PriceProviders } from './PriceProviders.js';
3
+ import BinanceProvider from './binance/BinanceProvider.js';
4
+ export declare const createPriceProvider: (provider: PriceProviders) => CoinGeckoProvider | BinanceProvider;
5
+ //# sourceMappingURL=createPriceProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPriceProvider.d.ts","sourceRoot":"","sources":["../../src/price/createPriceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,eAAe,MAAM,8BAA8B,CAAC;AAE3D,eAAO,MAAM,mBAAmB,GAAI,UAAU,cAAc,wCAS3D,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { CoinGeckoProvider } from './coinGecko/CoinGeckoProvider.js';
2
+ import { PriceProviders } from './PriceProviders.js';
3
+ import BinanceProvider from './binance/BinanceProvider.js';
4
+ export const createPriceProvider = (provider) => {
5
+ switch (provider) {
6
+ case PriceProviders.COINGECKO:
7
+ return new CoinGeckoProvider();
8
+ case PriceProviders.BINANCE:
9
+ return new BinanceProvider();
10
+ default:
11
+ throw new Error(`Unsupported price provider: ${provider}`);
12
+ }
13
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=createPriceProvider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPriceProvider.test.d.ts","sourceRoot":"","sources":["../../src/price/createPriceProvider.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ import { describe, it, assert } from 'vitest';
2
+ import { createPriceProvider } from './createPriceProvider.js';
3
+ import { CoinGeckoProvider } from './coinGecko/CoinGeckoProvider.js';
4
+ import { PriceProviders } from './PriceProviders.js';
5
+ import BinanceProvider from './binance/BinanceProvider.js';
6
+ describe(createPriceProvider.name, () => {
7
+ it('should resolve a correct provider (CoinGecko)', () => {
8
+ const provider = createPriceProvider(PriceProviders.COINGECKO);
9
+ assert.equal(provider.constructor.name, CoinGeckoProvider.name);
10
+ });
11
+ it('should resolve a correct provider (Binance)', () => {
12
+ const provider = createPriceProvider(PriceProviders.BINANCE);
13
+ assert.equal(provider.constructor.name, BinanceProvider.name);
14
+ });
15
+ it('should throw an error for unsupported provider', () => {
16
+ try {
17
+ // @ts-expect-error - intentionally passing invalid provider to exercise error path
18
+ createPriceProvider('unsupported_provider');
19
+ assert.fail('Expected error was not thrown');
20
+ }
21
+ catch (e) {
22
+ assert.equal(e.message, 'Unsupported price provider: unsupported_provider');
23
+ }
24
+ });
25
+ });
@@ -0,0 +1,7 @@
1
+ import { PriceProviders } from './PriceProviders.js';
2
+ type FetchCurrentPriceParams = {
3
+ provider?: PriceProviders;
4
+ };
5
+ export declare const fetchCurrentPrice: ({ provider, }: FetchCurrentPriceParams) => Promise<import("../types.js").Result<number, string>>;
6
+ export {};
7
+ //# sourceMappingURL=fetchCurrentPrice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchCurrentPrice.d.ts","sourceRoot":"","sources":["../../src/price/fetchCurrentPrice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAIrD,KAAK,uBAAuB,GAAG;IAC7B,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,eAErC,uBAAuB,0DAMzB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { PriceProviders } from './PriceProviders.js';
2
+ import { createPriceProvider } from './createPriceProvider.js';
3
+ import { FIAT } from '../types.js';
4
+ export const fetchCurrentPrice = async ({ provider, }) => {
5
+ const pricingProvider = createPriceProvider(provider || PriceProviders.COINGECKO);
6
+ return await pricingProvider.getCurrentPrice(FIAT.USD);
7
+ };
@@ -0,0 +1,15 @@
1
+ export type Ok<T> = {
2
+ success: true;
3
+ value: T;
4
+ };
5
+ export type Err<T> = {
6
+ success: false;
7
+ error: T;
8
+ };
9
+ export type Result<T, E> = Ok<T> | Err<E>;
10
+ export type Trend = 'up' | 'down' | 'stable';
11
+ export declare enum FIAT {
12
+ USD = "usd",
13
+ EUR = "eur"
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,EAAE,CAAC,CAAC,IAAI;IAClB,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,CAAC,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI;IACnB,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,CAAC,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAE1C,MAAM,MAAM,KAAK,GAAG,IAAI,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE7C,oBAAY,IAAI;IACd,GAAG,QAAQ;IACX,GAAG,QAAQ;CACZ"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ export var FIAT;
2
+ (function (FIAT) {
3
+ FIAT["USD"] = "usd";
4
+ FIAT["EUR"] = "eur";
5
+ })(FIAT || (FIAT = {}));
@@ -0,0 +1,9 @@
1
+ export declare const ok: <T>(value: T) => {
2
+ success: true;
3
+ value: T;
4
+ };
5
+ export declare const err: <E>(error: E) => {
6
+ success: false;
7
+ error: E;
8
+ };
9
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,GAAI,CAAC,EAAE,OAAO,CAAC;;;CAG5B,CAAC;AAEH,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,OAAO,CAAC;;;CAG7B,CAAC"}
package/dist/utils.js ADDED
@@ -0,0 +1,8 @@
1
+ export const ok = (value) => ({
2
+ success: true,
3
+ value,
4
+ });
5
+ export const err = (error) => ({
6
+ success: false,
7
+ error,
8
+ });
@@ -0,0 +1,3 @@
1
+ declare const _default: import("vite").UserConfig;
2
+ export default _default;
3
+ //# sourceMappingURL=vitest.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest.config.d.ts","sourceRoot":"","sources":["../src/vitest.config.ts"],"names":[],"mappings":";AAEA,wBAQG"}
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ export default defineConfig({
3
+ test: {
4
+ globals: true,
5
+ environment: 'node', // or 'happy-dom' for DOM-like env
6
+ coverage: {
7
+ reporter: ['text', 'html'],
8
+ },
9
+ },
10
+ });
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "current-bitcoin-price",
3
+ "version": "1.0.0",
4
+ "description": "NPM lib that, let's wait for it, has method to get you the current BTC price.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
12
+ "keywords": [
13
+ "bitcoin"
14
+ ],
15
+ "homepage": "https://github.com/OriginalEveres/current-bitcoin-price#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/OriginalEveres/current-bitcoin-price/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/OriginalEveres/current-bitcoin-price.git"
22
+ },
23
+ "license": "MIT",
24
+ "author": "Matthew Husak",
25
+ "types": "./dist/index.d.ts",
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsc -p .",
31
+ "clean": "rm -rf dist",
32
+ "prepublishOnly": "npm run build",
33
+ "test": "vitest",
34
+ "test:watch": "vitest --watch",
35
+ "test:integration": "RUN_INTEGRATION=true vitest --run --include src/price/**/CoinGeckoProvider.integration.test.ts",
36
+ "lint": "eslint 'src/**/*.{ts,tsx,js,jsx}'",
37
+ "format": "prettier --write '**/*.{ts,tsx,js,jsx,json,md}'"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^25.0.3",
41
+ "@typescript-eslint/eslint-plugin": "^8.50.1",
42
+ "@typescript-eslint/parser": "*",
43
+ "eslint": "*",
44
+ "eslint-config-prettier": "*",
45
+ "eslint-plugin-import": "*",
46
+ "eslint-plugin-vitest": "*",
47
+ "prettier": "*",
48
+ "typescript": "^5.9.3",
49
+ "vitest": "^4.0.16"
50
+ }
51
+ }