easy-currencies 1.10.2 → 2.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.
- package/dist/converter.d.ts +78 -9
- package/dist/converter.js +305 -74
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -2
- package/dist/parts/chainer.js +2 -3
- package/dist/parts/client.d.ts +39 -0
- package/dist/parts/client.js +78 -0
- package/dist/parts/config.d.ts +17 -14
- package/dist/parts/config.js +40 -14
- package/dist/parts/providers.d.ts +2 -4
- package/dist/parts/providers.js +22 -25
- package/dist/parts/requester.d.ts +37 -3
- package/dist/parts/requester.js +308 -44
- package/dist/parts/utils.js +14 -8
- package/package.json +12 -8
- package/readme.md +92 -17
package/dist/converter.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { RetryOptions } from "./parts/requester";
|
|
1
2
|
import { Provider, ProviderReference } from "./parts/providers";
|
|
2
|
-
import { Config
|
|
3
|
+
import { Config } from "./parts/config";
|
|
3
4
|
export { Chainer as Convert } from "./parts/chainer";
|
|
5
|
+
import { HttpClient } from "./parts/client";
|
|
4
6
|
/**
|
|
5
7
|
* A simple map object for rates
|
|
6
8
|
*
|
|
@@ -18,6 +20,17 @@ export interface rateObject {
|
|
|
18
20
|
* as before.
|
|
19
21
|
*/
|
|
20
22
|
export declare const RATES_BASE: unique symbol;
|
|
23
|
+
/**
|
|
24
|
+
* The enumerable twin of `RATES_BASE`.
|
|
25
|
+
*
|
|
26
|
+
* A symbol is invisible to `JSON.stringify`, spread, `Object.assign` and
|
|
27
|
+
* `structuredClone`, so a table that has been through a cache loses the marker
|
|
28
|
+
* and a conversion against the wrong base is then accepted silently. That is
|
|
29
|
+
* the caching workflow this guard exists for, so the base also travels as an
|
|
30
|
+
* ordinary key. Underscores are not valid in a currency code, see
|
|
31
|
+
* `CURRENCY_CODE`, so this can never collide with a rate.
|
|
32
|
+
*/
|
|
33
|
+
export declare const RATES_BASE_KEY = "__base";
|
|
21
34
|
/**
|
|
22
35
|
* Regular converter class definition.
|
|
23
36
|
*
|
|
@@ -32,6 +45,22 @@ export declare class Converter {
|
|
|
32
45
|
* @memberof Converter
|
|
33
46
|
*/
|
|
34
47
|
config: Config;
|
|
48
|
+
/**
|
|
49
|
+
* Called with each handled provider error before the next provider is tried.
|
|
50
|
+
*
|
|
51
|
+
* A library does not own the consumer's stderr, so this is the single point
|
|
52
|
+
* where that reporting happens. It defaults to the previous behaviour;
|
|
53
|
+
* assign your own to route the errors elsewhere, or assign a no-op to
|
|
54
|
+
* silence them entirely.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const converter = new Converter();
|
|
58
|
+
* converter.onError = () => {}; // silence
|
|
59
|
+
* converter.onError = (e) => logger.warn(e); // or route
|
|
60
|
+
*
|
|
61
|
+
* @memberof Converter
|
|
62
|
+
*/
|
|
63
|
+
onError: (error: unknown) => void;
|
|
35
64
|
/**
|
|
36
65
|
* Creates an instance of Converter.
|
|
37
66
|
* @param {(...ProviderReference[] | undefined[] | string[])} config
|
|
@@ -48,15 +77,43 @@ export declare class Converter {
|
|
|
48
77
|
get providers(): Provider[];
|
|
49
78
|
get active(): Provider[];
|
|
50
79
|
add: Config["add"];
|
|
51
|
-
addProvider: Config["add"];
|
|
52
80
|
addMultiple: Config["addMultiple"];
|
|
53
|
-
addMultipleProviders: Config["addMultiple"];
|
|
54
81
|
remove: Config["remove"];
|
|
55
82
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
83
|
+
* Replaces the HTTP client.
|
|
84
|
+
*
|
|
85
|
+
* The default client uses the global fetch, which has no proxy option, so
|
|
86
|
+
* proxying (or a custom agent, or instrumentation) means supplying your own.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* import { ProxyAgent } from "undici";
|
|
90
|
+
* const dispatcher = new ProxyAgent("http://proxy:8080");
|
|
91
|
+
* converter.setClient({
|
|
92
|
+
* get: (url) =>
|
|
93
|
+
* fetch(url, { dispatcher } as any).then(async (r) => ({
|
|
94
|
+
* status: r.status,
|
|
95
|
+
* data: await r.json()
|
|
96
|
+
* }))
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* @param {HttpClient} client - the client to use
|
|
100
|
+
*/
|
|
101
|
+
setClient: (client: HttpClient) => void;
|
|
102
|
+
/**
|
|
103
|
+
* Tunes retries and the time a conversion may take.
|
|
104
|
+
*
|
|
105
|
+
* `budgetMs` is wall clock for the whole call, spent across every provider
|
|
106
|
+
* rather than reset for each one, and it covers the requests themselves: a
|
|
107
|
+
* client that never settles cannot hold a conversion open past it. Fields
|
|
108
|
+
* merge, so one can be set without restating the rest.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* converter.setRetryOptions({ budgetMs: 5000 }); // an HTTP handler
|
|
112
|
+
* converter.setRetryOptions({ maxRetries: 0 }); // never retry a 429
|
|
113
|
+
*
|
|
114
|
+
* @param {RetryOptions} options - the tuning to apply
|
|
58
115
|
*/
|
|
59
|
-
|
|
116
|
+
setRetryOptions: (options: RetryOptions) => void;
|
|
60
117
|
/**
|
|
61
118
|
* Conversion function (non chainable).
|
|
62
119
|
*
|
|
@@ -69,23 +126,35 @@ export declare class Converter {
|
|
|
69
126
|
* @param {string} from - base currency
|
|
70
127
|
* @param {string} to - conversion currency
|
|
71
128
|
* @param {any} rates - conversion rates, if they were pre-fetched
|
|
129
|
+
* @throws {Error} - if the amount is not finite, or a currency is missing
|
|
72
130
|
* @returns {Promise<number>} - converted amount
|
|
73
131
|
*/
|
|
74
132
|
convert: (amount: number, from: string, to: string, rates?: any) => Promise<number>;
|
|
75
133
|
/**
|
|
76
134
|
* Performs safe multiplication to get the result amount.
|
|
135
|
+
*
|
|
136
|
+
* A usable rate is finite and greater than zero; anything else multiplies
|
|
137
|
+
* into a plausible-looking wrong amount.
|
|
138
|
+
*
|
|
77
139
|
* @param {number} amount - amount to be converted
|
|
78
140
|
* @param {string} to - conversion currency
|
|
79
141
|
* @param {any} rates - conversion rates, if they were pre-fetched
|
|
80
|
-
* @
|
|
142
|
+
* @throws {Error} - if the amount, the currency, the rates or the rate is invalid
|
|
143
|
+
* @returns {number} - converted amount
|
|
81
144
|
*/
|
|
82
145
|
convertRate: (amount: number, to: string, rates?: any) => number;
|
|
83
146
|
/**
|
|
84
|
-
* Rate fetch function
|
|
147
|
+
* Rate fetch function.
|
|
148
|
+
*
|
|
149
|
+
* Walks a snapshot of the chain, so concurrent calls do not shrink each
|
|
150
|
+
* other's list. A failure applies to the call, not the chain: no provider is
|
|
151
|
+
* removed, so one unknown currency cannot degrade a long-lived converter.
|
|
152
|
+
*
|
|
85
153
|
* @param {string} from - base currency
|
|
86
154
|
* @param {string} to - conversion currency
|
|
87
155
|
* @param {boolean} multiple - determines conversion mode
|
|
88
|
-
* @
|
|
156
|
+
* @throws {Error} - if a currency is missing, or every provider failed
|
|
157
|
+
* @returns {Promise<rateObject>} - the fetched rates
|
|
89
158
|
*/
|
|
90
159
|
getRates: (from: string, to: string, multiple?: boolean) => Promise<rateObject>;
|
|
91
160
|
}
|
package/dist/converter.js
CHANGED
|
@@ -8,17 +8,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.Converter = exports.RATES_BASE = exports.Convert = void 0;
|
|
12
|
+
exports.Converter = exports.RATES_BASE_KEY = exports.RATES_BASE = exports.Convert = void 0;
|
|
16
13
|
const requester_1 = require("./parts/requester");
|
|
17
14
|
const config_1 = require("./parts/config");
|
|
18
15
|
var chainer_1 = require("./parts/chainer");
|
|
19
16
|
Object.defineProperty(exports, "Convert", { enumerable: true, get: function () { return chainer_1.Chainer; } });
|
|
20
17
|
const utils_1 = require("./parts/utils");
|
|
21
|
-
const axios_1 = __importDefault(require("axios"));
|
|
22
18
|
/**
|
|
23
19
|
* Marks a rate map with the base currency it was fetched for.
|
|
24
20
|
*
|
|
@@ -27,6 +23,149 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
27
23
|
* as before.
|
|
28
24
|
*/
|
|
29
25
|
exports.RATES_BASE = Symbol.for("easy-currencies.ratesBase");
|
|
26
|
+
/**
|
|
27
|
+
* The enumerable twin of `RATES_BASE`.
|
|
28
|
+
*
|
|
29
|
+
* A symbol is invisible to `JSON.stringify`, spread, `Object.assign` and
|
|
30
|
+
* `structuredClone`, so a table that has been through a cache loses the marker
|
|
31
|
+
* and a conversion against the wrong base is then accepted silently. That is
|
|
32
|
+
* the caching workflow this guard exists for, so the base also travels as an
|
|
33
|
+
* ordinary key. Underscores are not valid in a currency code, see
|
|
34
|
+
* `CURRENCY_CODE`, so this can never collide with a rate.
|
|
35
|
+
*/
|
|
36
|
+
exports.RATES_BASE_KEY = "__base";
|
|
37
|
+
/** The base a table was fetched for, or undefined for one built by hand. */
|
|
38
|
+
function baseOf(rates) {
|
|
39
|
+
var _a;
|
|
40
|
+
const marked = (_a = rates[exports.RATES_BASE]) !== null && _a !== void 0 ? _a : rates[exports.RATES_BASE_KEY];
|
|
41
|
+
return typeof marked === "string" ? marked : undefined;
|
|
42
|
+
}
|
|
43
|
+
/** A rejection that is not contract-shaped is a bug, not a provider failure, and must not trigger fallback. */
|
|
44
|
+
function isProviderFailure(value) {
|
|
45
|
+
return (typeof value === "object" &&
|
|
46
|
+
value !== null &&
|
|
47
|
+
typeof value.handled === "boolean");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Providers describe failures with strings and numeric codes; consumers write
|
|
51
|
+
* `catch (e) { log(e.message) }`. Wrap so that reads something, keeping the
|
|
52
|
+
* original on `cause`.
|
|
53
|
+
*/
|
|
54
|
+
function asError(value) {
|
|
55
|
+
if (value instanceof Error) {
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
const message = typeof value === "string" && value.length > 0
|
|
59
|
+
? value
|
|
60
|
+
: `Rate provider failed: ${String(value)}`;
|
|
61
|
+
const error = new Error(message);
|
|
62
|
+
error.cause = value;
|
|
63
|
+
return error;
|
|
64
|
+
}
|
|
65
|
+
/** Describes a rejected rate without dumping the whole object into the message. */
|
|
66
|
+
function describeRate(value) {
|
|
67
|
+
if (typeof value === "string") {
|
|
68
|
+
return JSON.stringify(value);
|
|
69
|
+
}
|
|
70
|
+
if (value === null || typeof value !== "object") {
|
|
71
|
+
return String(value);
|
|
72
|
+
}
|
|
73
|
+
return Array.isArray(value) ? "an array" : "an object";
|
|
74
|
+
}
|
|
75
|
+
/** A currency library must never hand back NaN. */
|
|
76
|
+
function requireAmount(amount) {
|
|
77
|
+
if (typeof amount !== "number" || !Number.isFinite(amount)) {
|
|
78
|
+
throw new Error(`Conversion amount must be a finite number, received ${describeRate(amount)}.`);
|
|
79
|
+
}
|
|
80
|
+
return amount;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Asserts that a currency argument is a non-empty string.
|
|
84
|
+
*
|
|
85
|
+
* Without this, a missing currency reached the vendor as the literal
|
|
86
|
+
* `undefined` and came back as a confusing "Currency not found".
|
|
87
|
+
*
|
|
88
|
+
* @param {unknown} currency - the value to check
|
|
89
|
+
* @param {string} label - the parameter name, so the error says which is missing
|
|
90
|
+
* @returns {string} - the validated currency
|
|
91
|
+
*/
|
|
92
|
+
/**
|
|
93
|
+
* Every code the configured providers accept is alphanumeric: ISO 4217 is three
|
|
94
|
+
* letters, and the crypto tickers they carry include `USDT`, `1INCH`, `0G` and
|
|
95
|
+
* `00`, so neither "starts with a letter" nor "letters only" holds. AlphaVantage
|
|
96
|
+
* publishes `SBDf`, so the check is case-insensitive.
|
|
97
|
+
*/
|
|
98
|
+
const CURRENCY_CODE = /^[A-Za-z0-9]{1,16}$/;
|
|
99
|
+
function requireCurrency(currency, label) {
|
|
100
|
+
if (typeof currency !== "string" || currency.trim().length === 0) {
|
|
101
|
+
throw new Error(`The '${label}' currency must be a non-empty string, received ${describeRate(currency)}.`);
|
|
102
|
+
}
|
|
103
|
+
// Encoding alone does not close this: `.` is unreserved in RFC 3986, so
|
|
104
|
+
// encodeURIComponent("..") is "..", and the URL parser then resolves the dot
|
|
105
|
+
// segment and climbs the path. Rejecting the value is what actually stops it.
|
|
106
|
+
if (!CURRENCY_CODE.test(currency)) {
|
|
107
|
+
throw new Error(`The '${label}' currency must be alphanumeric, received ${describeRate(currency)}.`);
|
|
108
|
+
}
|
|
109
|
+
return currency;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Whether a table holds at least one entry that will actually convert.
|
|
113
|
+
*
|
|
114
|
+
* Uses the same coercion as `convertRate`, so a table that passes here cannot
|
|
115
|
+
* fail every lookup for want of a usable value.
|
|
116
|
+
*/
|
|
117
|
+
function hasUsableRate(rates) {
|
|
118
|
+
return Object.keys(rates).some((key) => {
|
|
119
|
+
const raw = rates[key];
|
|
120
|
+
const value = typeof raw === "number" || typeof raw === "string" ? Number(raw) : NaN;
|
|
121
|
+
return Number.isFinite(value) && value > 0;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Reads the rates out of a successful response.
|
|
126
|
+
*
|
|
127
|
+
* Returns the failure rather than throwing, so the caller can move to the next
|
|
128
|
+
* provider: a vendor answering for a different base, or a handler that trips on
|
|
129
|
+
* an unexpected shape, says nothing about the providers behind it.
|
|
130
|
+
*/
|
|
131
|
+
function readRates(provider, data, from) {
|
|
132
|
+
// Some vendors truncate an unrecognised code to a valid prefix and answer for
|
|
133
|
+
// that instead: exchangerate-api turns "CNYqqqwwC" into "CNY".
|
|
134
|
+
const echoed = data && (data.base || data.source);
|
|
135
|
+
if (typeof echoed === "string" && echoed.toLowerCase() !== from.toLowerCase()) {
|
|
136
|
+
return [
|
|
137
|
+
new Error(`Provider answered for base '${echoed}', not the requested '${from}'.`),
|
|
138
|
+
{}
|
|
139
|
+
];
|
|
140
|
+
}
|
|
141
|
+
let rates;
|
|
142
|
+
try {
|
|
143
|
+
rates = provider.handler(data);
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
return [asError(e), {}];
|
|
147
|
+
}
|
|
148
|
+
if (!rates || typeof rates !== "object") {
|
|
149
|
+
return [new Error("Provider returned no usable rates."), {}];
|
|
150
|
+
}
|
|
151
|
+
// Three of the built-in handlers return {} by design when the body is not the
|
|
152
|
+
// shape they expect, and FloatRates turns a junk 200 into {undefined: NaN}.
|
|
153
|
+
// Treating that as a successful fetch of zero rates stops the chain with
|
|
154
|
+
// healthy providers still behind it, and hands raw mode a garbage table.
|
|
155
|
+
if (!hasUsableRate(rates)) {
|
|
156
|
+
return [new Error("Provider returned a rate table with no usable rates."), {}];
|
|
157
|
+
}
|
|
158
|
+
// Stamp a copy, not the handler's own object. A handler may return a frozen
|
|
159
|
+
// table, where writing throws, or a memoised one, where a later fetch for a
|
|
160
|
+
// different base rewrites the marker under a caller still holding it.
|
|
161
|
+
const marked = Object.assign(Object.assign({}, rates), { [exports.RATES_BASE_KEY]: from });
|
|
162
|
+
Object.defineProperty(marked, exports.RATES_BASE, {
|
|
163
|
+
value: from,
|
|
164
|
+
enumerable: false,
|
|
165
|
+
configurable: true
|
|
166
|
+
});
|
|
167
|
+
return [null, marked];
|
|
168
|
+
}
|
|
30
169
|
/**
|
|
31
170
|
* Regular converter class definition.
|
|
32
171
|
*
|
|
@@ -41,11 +180,61 @@ class Converter {
|
|
|
41
180
|
*/
|
|
42
181
|
constructor(...config) {
|
|
43
182
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
183
|
+
* Called with each handled provider error before the next provider is tried.
|
|
184
|
+
*
|
|
185
|
+
* A library does not own the consumer's stderr, so this is the single point
|
|
186
|
+
* where that reporting happens. It defaults to the previous behaviour;
|
|
187
|
+
* assign your own to route the errors elsewhere, or assign a no-op to
|
|
188
|
+
* silence them entirely.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* const converter = new Converter();
|
|
192
|
+
* converter.onError = () => {}; // silence
|
|
193
|
+
* converter.onError = (e) => logger.warn(e); // or route
|
|
194
|
+
*
|
|
195
|
+
* @memberof Converter
|
|
196
|
+
*/
|
|
197
|
+
this.onError = (error) => {
|
|
198
|
+
console.error(error);
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Replaces the HTTP client.
|
|
202
|
+
*
|
|
203
|
+
* The default client uses the global fetch, which has no proxy option, so
|
|
204
|
+
* proxying (or a custom agent, or instrumentation) means supplying your own.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* import { ProxyAgent } from "undici";
|
|
208
|
+
* const dispatcher = new ProxyAgent("http://proxy:8080");
|
|
209
|
+
* converter.setClient({
|
|
210
|
+
* get: (url) =>
|
|
211
|
+
* fetch(url, { dispatcher } as any).then(async (r) => ({
|
|
212
|
+
* status: r.status,
|
|
213
|
+
* data: await r.json()
|
|
214
|
+
* }))
|
|
215
|
+
* });
|
|
216
|
+
*
|
|
217
|
+
* @param {HttpClient} client - the client to use
|
|
218
|
+
*/
|
|
219
|
+
this.setClient = (client) => {
|
|
220
|
+
this.config.setClient(client);
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* Tunes retries and the time a conversion may take.
|
|
224
|
+
*
|
|
225
|
+
* `budgetMs` is wall clock for the whole call, spent across every provider
|
|
226
|
+
* rather than reset for each one, and it covers the requests themselves: a
|
|
227
|
+
* client that never settles cannot hold a conversion open past it. Fields
|
|
228
|
+
* merge, so one can be set without restating the rest.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* converter.setRetryOptions({ budgetMs: 5000 }); // an HTTP handler
|
|
232
|
+
* converter.setRetryOptions({ maxRetries: 0 }); // never retry a 429
|
|
233
|
+
*
|
|
234
|
+
* @param {RetryOptions} options - the tuning to apply
|
|
46
235
|
*/
|
|
47
|
-
this.
|
|
48
|
-
this.config.
|
|
236
|
+
this.setRetryOptions = (options) => {
|
|
237
|
+
this.config.setRetryOptions(options);
|
|
49
238
|
};
|
|
50
239
|
/**
|
|
51
240
|
* Conversion function (non chainable).
|
|
@@ -59,13 +248,19 @@ class Converter {
|
|
|
59
248
|
* @param {string} from - base currency
|
|
60
249
|
* @param {string} to - conversion currency
|
|
61
250
|
* @param {any} rates - conversion rates, if they were pre-fetched
|
|
251
|
+
* @throws {Error} - if the amount is not finite, or a currency is missing
|
|
62
252
|
* @returns {Promise<number>} - converted amount
|
|
63
253
|
*/
|
|
64
254
|
this.convert = (amount_1, from_1, to_1, ...args_1) => __awaiter(this, [amount_1, from_1, to_1, ...args_1], void 0, function* (amount, from, to, rates = undefined) {
|
|
255
|
+
// Validating before anything is requested: an unset amount used to come
|
|
256
|
+
// back as NaN, and an unset currency reached the vendor as "undefined".
|
|
257
|
+
requireAmount(amount);
|
|
258
|
+
requireCurrency(from, "from");
|
|
259
|
+
requireCurrency(to, "to");
|
|
65
260
|
// Returining conversion from provided rates
|
|
66
|
-
if (
|
|
67
|
-
const base = rates
|
|
68
|
-
if (
|
|
261
|
+
if (rates !== undefined && rates !== null) {
|
|
262
|
+
const base = baseOf(rates);
|
|
263
|
+
if (base !== undefined &&
|
|
69
264
|
typeof from === "string" &&
|
|
70
265
|
base.toLowerCase() !== from.toLowerCase()) {
|
|
71
266
|
throw new Error(`Rates were fetched for base '${base}', but conversion asked for '${from}'.`);
|
|
@@ -75,7 +270,7 @@ class Converter {
|
|
|
75
270
|
//Fetching conversion rates from the active provider
|
|
76
271
|
const [err, data] = yield (0, utils_1._to)(this.getRates(from, to, false));
|
|
77
272
|
if (err) {
|
|
78
|
-
throw err;
|
|
273
|
+
throw asError(err);
|
|
79
274
|
}
|
|
80
275
|
if (!data || Object.keys(data).length == 0) {
|
|
81
276
|
throw new Error("No data returned for rate fetch.");
|
|
@@ -85,86 +280,120 @@ class Converter {
|
|
|
85
280
|
});
|
|
86
281
|
/**
|
|
87
282
|
* Performs safe multiplication to get the result amount.
|
|
283
|
+
*
|
|
284
|
+
* A usable rate is finite and greater than zero; anything else multiplies
|
|
285
|
+
* into a plausible-looking wrong amount.
|
|
286
|
+
*
|
|
88
287
|
* @param {number} amount - amount to be converted
|
|
89
288
|
* @param {string} to - conversion currency
|
|
90
289
|
* @param {any} rates - conversion rates, if they were pre-fetched
|
|
91
|
-
* @
|
|
290
|
+
* @throws {Error} - if the amount, the currency, the rates or the rate is invalid
|
|
291
|
+
* @returns {number} - converted amount
|
|
92
292
|
*/
|
|
93
293
|
this.convertRate = (amount, to, rates = undefined) => {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (
|
|
98
|
-
throw new Error(`
|
|
294
|
+
var _a;
|
|
295
|
+
requireAmount(amount);
|
|
296
|
+
requireCurrency(to, "to");
|
|
297
|
+
if (typeof rates !== "object" || rates === null) {
|
|
298
|
+
throw new Error(`Rates must be an object mapping currency to rate, received ${describeRate(rates)}.`);
|
|
299
|
+
}
|
|
300
|
+
// The base marker rides along as an ordinary key; it is not a rate, so it
|
|
301
|
+
// is neither a lookup candidate nor part of the "N rates available" count.
|
|
302
|
+
const keys = Object.keys(rates).filter((key) => key !== exports.RATES_BASE_KEY);
|
|
303
|
+
// Exact match wins, so a response carrying both "EUR" and "eur" does not
|
|
304
|
+
// resolve differently depending on JSON key order.
|
|
305
|
+
const rateKey = (_a = keys.find((key) => key === to)) !== null && _a !== void 0 ? _a : keys.find((key) => key.toLowerCase() === to.toLowerCase());
|
|
306
|
+
// Truthiness would report a present-but-zero rate as missing.
|
|
307
|
+
if (rateKey === undefined) {
|
|
308
|
+
// The full table is ~4KB in production.
|
|
309
|
+
throw new Error(`No '${to}' present in rates (${keys.length} rate${keys.length === 1 ? "" : "s"} available).`);
|
|
310
|
+
}
|
|
311
|
+
const raw = rates[rateKey];
|
|
312
|
+
// Number(["0.9"]) === 0.9, so check the type before the value.
|
|
313
|
+
const numericRate = typeof raw === "number" || typeof raw === "string" ? Number(raw) : NaN;
|
|
314
|
+
if (!Number.isFinite(numericRate) || numericRate <= 0) {
|
|
315
|
+
throw new Error(`Invalid rate value for '${to}': expected a finite number greater than zero, received ${describeRate(raw)}.`);
|
|
99
316
|
}
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
317
|
+
const converted = amount * numericRate;
|
|
318
|
+
// Both operands are already finite and the rate is positive, so a result
|
|
319
|
+
// that is not finite overflowed and a result of zero from a non-zero amount
|
|
320
|
+
// underflowed. Either way the product is not the answer, and returning it
|
|
321
|
+
// hands back a wrong number that looks like a right one.
|
|
322
|
+
if (!Number.isFinite(converted) || (converted === 0 && amount !== 0)) {
|
|
323
|
+
throw new Error(`Converting ${amount} at rate ${numericRate} is not representable as a number.`);
|
|
103
324
|
}
|
|
104
|
-
return
|
|
325
|
+
return converted;
|
|
105
326
|
};
|
|
106
327
|
/**
|
|
107
|
-
* Rate fetch function
|
|
328
|
+
* Rate fetch function.
|
|
329
|
+
*
|
|
330
|
+
* Walks a snapshot of the chain, so concurrent calls do not shrink each
|
|
331
|
+
* other's list. A failure applies to the call, not the chain: no provider is
|
|
332
|
+
* removed, so one unknown currency cannot degrade a long-lived converter.
|
|
333
|
+
*
|
|
108
334
|
* @param {string} from - base currency
|
|
109
335
|
* @param {string} to - conversion currency
|
|
110
336
|
* @param {boolean} multiple - determines conversion mode
|
|
111
|
-
* @
|
|
337
|
+
* @throws {Error} - if a currency is missing, or every provider failed
|
|
338
|
+
* @returns {Promise<rateObject>} - the fetched rates
|
|
112
339
|
*/
|
|
113
|
-
this.getRates = (
|
|
114
|
-
|
|
115
|
-
|
|
340
|
+
this.getRates = (from_1, to_1, ...args_1) => __awaiter(this, [from_1, to_1, ...args_1], void 0, function* (from, to, multiple = false) {
|
|
341
|
+
requireCurrency(from, "from");
|
|
342
|
+
// In multiple mode the whole table is fetched for the base currency, so
|
|
343
|
+
// there is no target currency to validate.
|
|
344
|
+
if (!multiple) {
|
|
345
|
+
requireCurrency(to, "to");
|
|
346
|
+
}
|
|
347
|
+
// Per-call snapshot of the fallback chain.
|
|
348
|
+
const chain = [...this.config.providers];
|
|
349
|
+
if (chain.length === 0) {
|
|
350
|
+
throw new Error("No rate providers are configured.");
|
|
351
|
+
}
|
|
116
352
|
// Getting the client
|
|
117
353
|
const client = this.config.getClient();
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
typeof from === "string" &&
|
|
134
|
-
echoed.toLowerCase() !== from.toLowerCase()) {
|
|
135
|
-
throw new Error(`Provider answered for base '${echoed}', not the requested '${from}'.`);
|
|
354
|
+
// One deadline for the whole chain. Per provider it would let a
|
|
355
|
+
// three-provider chain spend three budgets, which is how a rate-limited
|
|
356
|
+
// conversion reached 102 seconds.
|
|
357
|
+
const retry = this.config.getRetryOptions();
|
|
358
|
+
const deadline = (0, requester_1.deadlineFrom)(retry);
|
|
359
|
+
let lastError = new Error("No rate providers were tried.");
|
|
360
|
+
for (let index = 0; index < chain.length; index++) {
|
|
361
|
+
const provider = chain[index];
|
|
362
|
+
// A whole-table fetch has no target currency, so a provider whose template
|
|
363
|
+
// needs one cannot serve it: the request would go out asking for an empty
|
|
364
|
+
// symbol list. That is this provider's limitation, so move to the next.
|
|
365
|
+
if (multiple && provider.endpoint.single.includes("%TO%")) {
|
|
366
|
+
lastError = new Error("Provider cannot fetch a whole rate table; it requires a target currency.");
|
|
367
|
+
this.onError(lastError);
|
|
368
|
+
continue;
|
|
136
369
|
}
|
|
137
|
-
const
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
370
|
+
const [err, data] = yield (0, utils_1._to)((0, requester_1.fetchRates)(client, provider, { FROM: from, TO: to, multiple: multiple }, Object.assign(Object.assign({}, retry), { deadline })));
|
|
371
|
+
if (!err) {
|
|
372
|
+
// A provider answering wrongly, or a handler throwing on a shape it did
|
|
373
|
+
// not expect, is that provider's failure. Aborting here would give up on
|
|
374
|
+
// the healthy providers behind it.
|
|
375
|
+
const [failure, rates] = readRates(provider, data, from);
|
|
376
|
+
if (!failure) {
|
|
377
|
+
return rates;
|
|
378
|
+
}
|
|
379
|
+
this.onError(failure);
|
|
380
|
+
lastError = failure;
|
|
381
|
+
continue;
|
|
144
382
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
console.error(err.error);
|
|
153
|
-
if (this.config.providers.length <= 1) {
|
|
154
|
-
throw err.error;
|
|
383
|
+
// A rejection that does not follow the failure contract was not
|
|
384
|
+
// classified by the requester, so there is nothing to fall back for.
|
|
385
|
+
if (!isProviderFailure(err) || !err.handled) {
|
|
386
|
+
throw asError(isProviderFailure(err) ? err.error : err);
|
|
387
|
+
}
|
|
388
|
+
this.onError(err.error);
|
|
389
|
+
lastError = asError(err.error);
|
|
155
390
|
}
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
// Retrying...
|
|
159
|
-
return this.getRates(from, to, multiple);
|
|
391
|
+
// Every provider in the snapshot failed.
|
|
392
|
+
throw lastError;
|
|
160
393
|
});
|
|
161
394
|
this.config = new config_1.Config(...config);
|
|
162
|
-
// Forwarding config adder function (with the alternative handle)
|
|
163
395
|
this.add = this.config.add;
|
|
164
|
-
this.addProvider = this.config.add;
|
|
165
|
-
// Forwarding config multiple adder function (with the alternative handle)
|
|
166
396
|
this.addMultiple = this.config.addMultiple;
|
|
167
|
-
this.addMultipleProviders = this.config.addMultiple;
|
|
168
397
|
this.remove = this.config.remove;
|
|
169
398
|
}
|
|
170
399
|
/**
|
|
@@ -175,11 +404,13 @@ class Converter {
|
|
|
175
404
|
* @memberof Converter
|
|
176
405
|
*/
|
|
177
406
|
get providers() {
|
|
178
|
-
|
|
407
|
+
// A copy: the readme tells callers to read this, and handing back the live
|
|
408
|
+
// array lets `providers.length = 0` empty the chain.
|
|
409
|
+
return [...this.config.providers];
|
|
179
410
|
}
|
|
180
411
|
get active() {
|
|
181
|
-
return this.config.providers;
|
|
412
|
+
return [...this.config.providers];
|
|
182
413
|
}
|
|
183
414
|
}
|
|
184
415
|
exports.Converter = Converter;
|
|
185
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udmVydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBQSxpREFBK0M7QUFFL0MsMkNBQTREO0FBQzVELDJDQUFxRDtBQUE1QyxrR0FBQSxPQUFPLE9BQVc7QUFDM0IseUNBQW9DO0FBQ3BDLGtEQUEwQjtBQVkxQjs7Ozs7O0dBTUc7QUFDVSxRQUFBLFVBQVUsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLDJCQUEyQixDQUFDLENBQUM7QUFFbEU7Ozs7O0dBS0c7QUFDSCxNQUFhLFNBQVM7SUFTcEI7Ozs7T0FJRztJQUNILFlBQVksR0FBRyxNQUFvRDtRQXFDbkU7OztXQUdHO1FBQ0gsMEJBQXFCLEdBQUcsQ0FBQyxrQkFBc0MsRUFBRSxFQUFFO1lBQ2pFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGVBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDckUsQ0FBQyxDQUFDO1FBRUY7Ozs7Ozs7Ozs7Ozs7V0FhRztRQUNILFlBQU8sR0FBRyxvQ0FLUyxFQUFFLHlFQUpuQixNQUFjLEVBQ2QsSUFBWSxFQUNaLEVBQVUsRUFDVixRQUFhLFNBQVM7WUFFdEIsNENBQTRDO1lBQzVDLElBQUksT0FBTyxLQUFLLEtBQUssV0FBVyxFQUFFLENBQUM7Z0JBQ2pDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxrQkFBVSxDQUFDLENBQUM7Z0JBQy9CLElBQ0UsT0FBTyxJQUFJLEtBQUssUUFBUTtvQkFDeEIsT0FBTyxJQUFJLEtBQUssUUFBUTtvQkFDeEIsSUFBSSxDQUFDLFdBQVcsRUFBRSxLQUFLLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFDekMsQ0FBQztvQkFDRCxNQUFNLElBQUksS0FBSyxDQUNiLGdDQUFnQyxJQUFJLGdDQUFnQyxJQUFJLElBQUksQ0FDN0UsQ0FBQztnQkFDSixDQUFDO2dCQUNELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzdDLENBQUM7WUFFRCxvREFBb0Q7WUFDcEQsTUFBTSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxNQUFNLElBQUEsV0FBRyxFQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBRTlELElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ1IsTUFBTSxHQUFHLENBQUM7WUFDWixDQUFDO1lBRUQsSUFBSSxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDM0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1lBQ3RELENBQUM7WUFFRCxtQ0FBbUM7WUFDbkMsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDNUMsQ0FBQyxDQUFBLENBQUM7UUFFRjs7Ozs7O1dBTUc7UUFDSCxnQkFBVyxHQUFHLENBQ1osTUFBYyxFQUNkLEVBQVUsRUFDVixRQUFhLFNBQVMsRUFDZCxFQUFFO1lBQ1YsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNoQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxLQUFLLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1lBQ3pFLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7WUFFbEQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNWLE1BQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLHVCQUF1QixJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3BGLENBQUM7WUFFRCxNQUFNLFdBQVcsR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDckMsSUFBSSxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztnQkFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsRUFBRSxNQUFNLElBQUksRUFBRSxDQUFDLENBQUM7WUFDN0QsQ0FBQztZQUVELE9BQU8sTUFBTSxHQUFHLFdBQVcsQ0FBQztRQUM5QixDQUFDLENBQUM7UUFFRjs7Ozs7O1dBTUc7UUFDSCxhQUFRLEdBQUcsMEJBSVksRUFBRSwrREFIdkIsSUFBWSxFQUNaLEVBQVUsRUFDVixXQUFvQixLQUFLO1lBRXpCLHNDQUFzQztZQUN0QyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBRTlDLHFCQUFxQjtZQUNyQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBRXZDLHNEQUFzRDtZQUN0RCxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLE1BQVksSUFBQSxXQUFHLEVBQ2pDLElBQUEsc0JBQVUsRUFBQyxNQUFNLEVBQUUsUUFBUSxFQUFFO2dCQUMzQixJQUFJLEVBQUUsSUFBSTtnQkFDVixFQUFFLEVBQUUsRUFBRTtnQkFDTixRQUFRLEVBQUUsUUFBUTthQUNuQixDQUFDLENBQ0YsQ0FBQztZQUVILGtCQUFrQjtZQUNsQixtRkFBbUY7WUFDbkYsOEVBQThFO1lBQzlFLGlGQUFpRjtZQUNqRixJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ1QsMEVBQTBFO2dCQUMxRSxtRUFBbUU7Z0JBQ25FLE1BQU0sTUFBTSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUNsRCxJQUNFLE9BQU8sTUFBTSxLQUFLLFFBQVE7b0JBQzFCLE9BQU8sSUFBSSxLQUFLLFFBQVE7b0JBQ3hCLE1BQU0sQ0FBQyxXQUFXLEVBQUUsS0FBSyxJQUFJLENBQUMsV0FBVyxFQUFFLEVBQzNDLENBQUM7b0JBQ0QsTUFBTSxJQUFJLEtBQUssQ0FDYiwrQkFBK0IsTUFBTSx5QkFBeUIsSUFBSSxJQUFJLENBQ3ZFLENBQUM7Z0JBQ0osQ0FBQztnQkFFRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNyQyxJQUFJLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztvQkFDdkMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsa0JBQVUsRUFBRTt3QkFDdkMsS0FBSyxFQUFFLElBQUk7d0JBQ1gsVUFBVSxFQUFFLEtBQUs7d0JBQ2pCLFlBQVksRUFBRSxJQUFJO3FCQUNuQixDQUFDLENBQUM7Z0JBQ0wsQ0FBQztnQkFDRCxPQUFPLEtBQUssQ0FBQztZQUNmLENBQUM7WUFFRCxxQkFBcUI7WUFDckIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDakIsTUFBTSxHQUFHLENBQUMsS0FBSyxDQUFDO1lBQ2xCLENBQUM7WUFFRCx5QkFBeUI7WUFDekIsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7WUFFekIsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ3RDLE1BQU0sR0FBRyxDQUFDLEtBQUssQ0FBQztZQUNsQixDQUFDO1lBRUQsNkNBQTZDO1lBQzdDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRTdCLGNBQWM7WUFDZCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUMzQyxDQUFDLENBQUEsQ0FBQztRQW5NQSxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksZUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUM7UUFFcEMsaUVBQWlFO1FBQ2pFLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7UUFDM0IsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztRQUVuQywwRUFBMEU7UUFDMUUsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQztRQUMzQyxJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUM7UUFFcEQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUNuQyxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQztJQUMvQixDQUFDO0lBQ0QsSUFBSSxNQUFNO1FBQ1IsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQztJQUMvQixDQUFDO0NBMktGO0FBbk5ELDhCQW1OQyJ9
|
|
416
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udmVydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSxpREFBMkU7QUFFM0UsMkNBQXdDO0FBQ3hDLDJDQUFxRDtBQUE1QyxrR0FBQSxPQUFPLE9BQVc7QUFDM0IseUNBQW9DO0FBYXBDOzs7Ozs7R0FNRztBQUNVLFFBQUEsVUFBVSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUMsQ0FBQztBQUVsRTs7Ozs7Ozs7O0dBU0c7QUFDVSxRQUFBLGNBQWMsR0FBRyxRQUFRLENBQUM7QUFFdkMsNEVBQTRFO0FBQzVFLFNBQVMsTUFBTSxDQUFDLEtBQVU7O0lBQ3hCLE1BQU0sTUFBTSxHQUFHLE1BQUEsS0FBSyxDQUFDLGtCQUFVLENBQUMsbUNBQUksS0FBSyxDQUFDLHNCQUFjLENBQUMsQ0FBQztJQUMxRCxPQUFPLE9BQU8sTUFBTSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDekQsQ0FBQztBQVlELCtHQUErRztBQUMvRyxTQUFTLGlCQUFpQixDQUFDLEtBQWM7SUFDdkMsT0FBTyxDQUNMLE9BQU8sS0FBSyxLQUFLLFFBQVE7UUFDekIsS0FBSyxLQUFLLElBQUk7UUFDZCxPQUFRLEtBQXlCLENBQUMsT0FBTyxLQUFLLFNBQVMsQ0FDeEQsQ0FBQztBQUNKLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxPQUFPLENBQUMsS0FBYztJQUM3QixJQUFJLEtBQUssWUFBWSxLQUFLLEVBQUUsQ0FBQztRQUMzQixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FDWCxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDO1FBQzNDLENBQUMsQ0FBQyxLQUFLO1FBQ1AsQ0FBQyxDQUFDLHlCQUF5QixNQUFNLENB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
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export { Converter, Convert } from "./converter";
|
|
1
|
+
export { Converter, Convert, RATES_BASE_KEY } from "./converter";
|
|
2
2
|
export { providers } from "./parts/providers";
|
|
3
3
|
export type { rateObject } from "./converter";
|
|
4
4
|
export type { Provider, ProviderErrors, ProviderReference, Providers, UserDefinedProvider } from "./parts/providers";
|
|
5
|
-
export type { Config
|
|
5
|
+
export type { Config } from "./parts/config";
|
|
6
|
+
export type { HttpClient, HttpResponse, HttpError, ClientOptions } from "./parts/client";
|
|
7
|
+
export { createClient } from "./parts/client";
|
|
6
8
|
export type { chainableConverter } from "./parts/chainer";
|
|
9
|
+
export type { RetryOptions } from "./parts/requester";
|