@ducatjs/money 0.0.0 → 0.2.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/LICENSE +21 -0
- package/NOTICE +51 -0
- package/README.md +1034 -3
- package/assets/CREDITS.md +12 -0
- package/data/adyen-fx.json +19 -0
- package/data/adyen.json +171 -0
- package/data/braintree.json +223 -0
- package/data/cash-rounding.json +520 -0
- package/data/checkout.json +230 -0
- package/data/cldr-cash.json +101 -0
- package/data/historic.json +78 -0
- package/data/iso4217-list-one.xml +1956 -0
- package/data/iso4217-list-three.xml +1185 -0
- package/data/klarna.json +95 -0
- package/data/paypal.json +65 -0
- package/data/stripe-fx.json +17 -0
- package/data/stripe.json +285 -0
- package/dist/adyen-fx.d.ts +25 -0
- package/dist/adyen-fx.d.ts.map +1 -0
- package/dist/adyen-fx.js +140 -0
- package/dist/adyen-fx.js.map +1 -0
- package/dist/adyen.d.ts +25 -0
- package/dist/adyen.d.ts.map +1 -0
- package/dist/adyen.js +34 -0
- package/dist/adyen.js.map +1 -0
- package/dist/allocate.d.ts +72 -0
- package/dist/allocate.d.ts.map +1 -0
- package/dist/allocate.js +314 -0
- package/dist/allocate.js.map +1 -0
- package/dist/bag.d.ts +58 -0
- package/dist/bag.d.ts.map +1 -0
- package/dist/bag.js +122 -0
- package/dist/bag.js.map +1 -0
- package/dist/boc.d.ts +31 -0
- package/dist/boc.d.ts.map +1 -0
- package/dist/boc.js +114 -0
- package/dist/boc.js.map +1 -0
- package/dist/boe.d.ts +33 -0
- package/dist/boe.d.ts.map +1 -0
- package/dist/boe.js +114 -0
- package/dist/boe.js.map +1 -0
- package/dist/braintree.d.ts +34 -0
- package/dist/braintree.d.ts.map +1 -0
- package/dist/braintree.js +45 -0
- package/dist/braintree.js.map +1 -0
- package/dist/cash.d.ts +64 -0
- package/dist/cash.d.ts.map +1 -0
- package/dist/cash.js +134 -0
- package/dist/cash.js.map +1 -0
- package/dist/checkout.d.ts +42 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +52 -0
- package/dist/checkout.js.map +1 -0
- package/dist/convert.d.ts +52 -0
- package/dist/convert.d.ts.map +1 -0
- package/dist/convert.js +65 -0
- package/dist/convert.js.map +1 -0
- package/dist/currency.d.ts +22 -0
- package/dist/currency.d.ts.map +1 -0
- package/dist/currency.js +38 -0
- package/dist/currency.js.map +1 -0
- package/dist/decimal.d.ts +52 -0
- package/dist/decimal.d.ts.map +1 -0
- package/dist/decimal.js +251 -0
- package/dist/decimal.js.map +1 -0
- package/dist/drizzle/mysql.d.ts +105 -0
- package/dist/drizzle/mysql.d.ts.map +1 -0
- package/dist/drizzle/mysql.js +60 -0
- package/dist/drizzle/mysql.js.map +1 -0
- package/dist/drizzle/pg.d.ts +103 -0
- package/dist/drizzle/pg.d.ts.map +1 -0
- package/dist/drizzle/pg.js +60 -0
- package/dist/drizzle/pg.js.map +1 -0
- package/dist/drizzle/sqlite.d.ts +102 -0
- package/dist/drizzle/sqlite.d.ts.map +1 -0
- package/dist/drizzle/sqlite.js +59 -0
- package/dist/drizzle/sqlite.js.map +1 -0
- package/dist/ecb.d.ts +52 -0
- package/dist/ecb.d.ts.map +1 -0
- package/dist/ecb.js +285 -0
- package/dist/ecb.js.map +1 -0
- package/dist/exact.d.ts +62 -0
- package/dist/exact.d.ts.map +1 -0
- package/dist/exact.js +147 -0
- package/dist/exact.js.map +1 -0
- package/dist/fed.d.ts +35 -0
- package/dist/fed.d.ts.map +1 -0
- package/dist/fed.js +134 -0
- package/dist/fed.js.map +1 -0
- package/dist/fetch.d.ts +103 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +222 -0
- package/dist/fetch.js.map +1 -0
- package/dist/fixed.d.ts +121 -0
- package/dist/fixed.d.ts.map +1 -0
- package/dist/fixed.js +420 -0
- package/dist/fixed.js.map +1 -0
- package/dist/fn.d.ts +34 -0
- package/dist/fn.d.ts.map +1 -0
- package/dist/fn.js +37 -0
- package/dist/fn.js.map +1 -0
- package/dist/format.d.ts +13 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +90 -0
- package/dist/format.js.map +1 -0
- package/dist/generated/adyen.d.ts +3 -0
- package/dist/generated/adyen.d.ts.map +1 -0
- package/dist/generated/adyen.js +144 -0
- package/dist/generated/adyen.js.map +1 -0
- package/dist/generated/braintree.d.ts +3 -0
- package/dist/generated/braintree.d.ts.map +1 -0
- package/dist/generated/braintree.js +140 -0
- package/dist/generated/braintree.js.map +1 -0
- package/dist/generated/cash.d.ts +14 -0
- package/dist/generated/cash.d.ts.map +1 -0
- package/dist/generated/cash.js +465 -0
- package/dist/generated/cash.js.map +1 -0
- package/dist/generated/checkout.d.ts +3 -0
- package/dist/generated/checkout.d.ts.map +1 -0
- package/dist/generated/checkout.js +151 -0
- package/dist/generated/checkout.js.map +1 -0
- package/dist/generated/historic.d.ts +337 -0
- package/dist/generated/historic.d.ts.map +1 -0
- package/dist/generated/historic.js +66 -0
- package/dist/generated/historic.js.map +1 -0
- package/dist/generated/iso4217.d.ts +174 -0
- package/dist/generated/iso4217.d.ts.map +1 -0
- package/dist/generated/iso4217.js +175 -0
- package/dist/generated/iso4217.js.map +1 -0
- package/dist/generated/kernel.d.ts +17 -0
- package/dist/generated/kernel.d.ts.map +1 -0
- package/dist/generated/kernel.js +208 -0
- package/dist/generated/kernel.js.map +1 -0
- package/dist/generated/klarna.d.ts +3 -0
- package/dist/generated/klarna.d.ts.map +1 -0
- package/dist/generated/klarna.js +21 -0
- package/dist/generated/klarna.js.map +1 -0
- package/dist/generated/paypal.d.ts +3 -0
- package/dist/generated/paypal.d.ts.map +1 -0
- package/dist/generated/paypal.js +31 -0
- package/dist/generated/paypal.js.map +1 -0
- package/dist/generated/stripe.d.ts +8 -0
- package/dist/generated/stripe.d.ts.map +1 -0
- package/dist/generated/stripe.js +150 -0
- package/dist/generated/stripe.js.map +1 -0
- package/dist/historic.d.ts +40 -0
- package/dist/historic.d.ts.map +1 -0
- package/dist/historic.js +43 -0
- package/dist/historic.js.map +1 -0
- package/dist/history.d.ts +96 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +213 -0
- package/dist/history.js.map +1 -0
- package/dist/hmrc.d.ts +28 -0
- package/dist/hmrc.d.ts.map +1 -0
- package/dist/hmrc.js +108 -0
- package/dist/hmrc.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/klarna.d.ts +31 -0
- package/dist/klarna.d.ts.map +1 -0
- package/dist/klarna.js +38 -0
- package/dist/klarna.js.map +1 -0
- package/dist/kysely.d.ts +120 -0
- package/dist/kysely.d.ts.map +1 -0
- package/dist/kysely.js +309 -0
- package/dist/kysely.js.map +1 -0
- package/dist/money.d.ts +302 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/money.js +703 -0
- package/dist/money.js.map +1 -0
- package/dist/parse.d.ts +55 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +419 -0
- package/dist/parse.js.map +1 -0
- package/dist/paypal.d.ts +41 -0
- package/dist/paypal.d.ts.map +1 -0
- package/dist/paypal.js +58 -0
- package/dist/paypal.js.map +1 -0
- package/dist/pg.d.ts +100 -0
- package/dist/pg.d.ts.map +1 -0
- package/dist/pg.js +343 -0
- package/dist/pg.js.map +1 -0
- package/dist/plugins/adyen.d.ts +15 -0
- package/dist/plugins/adyen.d.ts.map +1 -0
- package/dist/plugins/adyen.js +10 -0
- package/dist/plugins/adyen.js.map +1 -0
- package/dist/plugins/all.d.ts +29 -0
- package/dist/plugins/all.d.ts.map +1 -0
- package/dist/plugins/all.js +30 -0
- package/dist/plugins/all.js.map +1 -0
- package/dist/plugins/allocate.d.ts +20 -0
- package/dist/plugins/allocate.d.ts.map +1 -0
- package/dist/plugins/allocate.js +26 -0
- package/dist/plugins/allocate.js.map +1 -0
- package/dist/plugins/braintree.d.ts +12 -0
- package/dist/plugins/braintree.d.ts.map +1 -0
- package/dist/plugins/braintree.js +12 -0
- package/dist/plugins/braintree.js.map +1 -0
- package/dist/plugins/cash.d.ts +19 -0
- package/dist/plugins/cash.d.ts.map +1 -0
- package/dist/plugins/cash.js +16 -0
- package/dist/plugins/cash.js.map +1 -0
- package/dist/plugins/checkout.d.ts +21 -0
- package/dist/plugins/checkout.d.ts.map +1 -0
- package/dist/plugins/checkout.js +16 -0
- package/dist/plugins/checkout.js.map +1 -0
- package/dist/plugins/convert.d.ts +19 -0
- package/dist/plugins/convert.d.ts.map +1 -0
- package/dist/plugins/convert.js +13 -0
- package/dist/plugins/convert.js.map +1 -0
- package/dist/plugins/exact.d.ts +15 -0
- package/dist/plugins/exact.d.ts.map +1 -0
- package/dist/plugins/exact.js +13 -0
- package/dist/plugins/exact.js.map +1 -0
- package/dist/plugins/fixed.d.ts +17 -0
- package/dist/plugins/fixed.d.ts.map +1 -0
- package/dist/plugins/fixed.js +13 -0
- package/dist/plugins/fixed.js.map +1 -0
- package/dist/plugins/format.d.ts +9 -0
- package/dist/plugins/format.d.ts.map +1 -0
- package/dist/plugins/format.js +16 -0
- package/dist/plugins/format.js.map +1 -0
- package/dist/plugins/klarna.d.ts +10 -0
- package/dist/plugins/klarna.d.ts.map +1 -0
- package/dist/plugins/klarna.js +10 -0
- package/dist/plugins/klarna.js.map +1 -0
- package/dist/plugins/paypal.d.ts +14 -0
- package/dist/plugins/paypal.d.ts.map +1 -0
- package/dist/plugins/paypal.js +16 -0
- package/dist/plugins/paypal.js.map +1 -0
- package/dist/plugins/prisma.d.ts +8 -0
- package/dist/plugins/prisma.d.ts.map +1 -0
- package/dist/plugins/prisma.js +13 -0
- package/dist/plugins/prisma.js.map +1 -0
- package/dist/plugins/stripe.d.ts +14 -0
- package/dist/plugins/stripe.d.ts.map +1 -0
- package/dist/plugins/stripe.js +16 -0
- package/dist/plugins/stripe.js.map +1 -0
- package/dist/plugins/tax.d.ts +20 -0
- package/dist/plugins/tax.d.ts.map +1 -0
- package/dist/plugins/tax.js +18 -0
- package/dist/plugins/tax.js.map +1 -0
- package/dist/policy.d.ts +34 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +90 -0
- package/dist/policy.js.map +1 -0
- package/dist/prisma.d.ts +77 -0
- package/dist/prisma.d.ts.map +1 -0
- package/dist/prisma.js +76 -0
- package/dist/prisma.js.map +1 -0
- package/dist/processor.d.ts +28 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +118 -0
- package/dist/processor.js.map +1 -0
- package/dist/provider.d.ts +103 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +280 -0
- package/dist/provider.js.map +1 -0
- package/dist/rate-text.d.ts +38 -0
- package/dist/rate-text.d.ts.map +1 -0
- package/dist/rate-text.js +143 -0
- package/dist/rate-text.js.map +1 -0
- package/dist/rate.d.ts +175 -0
- package/dist/rate.d.ts.map +1 -0
- package/dist/rate.js +371 -0
- package/dist/rate.js.map +1 -0
- package/dist/rounding-error.d.ts +9 -0
- package/dist/rounding-error.d.ts.map +1 -0
- package/dist/rounding-error.js +9 -0
- package/dist/rounding-error.js.map +1 -0
- package/dist/rounding.d.ts +50 -0
- package/dist/rounding.d.ts.map +1 -0
- package/dist/rounding.js +87 -0
- package/dist/rounding.js.map +1 -0
- package/dist/schema.d.ts +43 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +77 -0
- package/dist/schema.js.map +1 -0
- package/dist/sql.d.ts +54 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +131 -0
- package/dist/sql.js.map +1 -0
- package/dist/stripe-fx.d.ts +22 -0
- package/dist/stripe-fx.d.ts.map +1 -0
- package/dist/stripe-fx.js +30 -0
- package/dist/stripe-fx.js.map +1 -0
- package/dist/stripe.d.ts +36 -0
- package/dist/stripe.d.ts.map +1 -0
- package/dist/stripe.js +39 -0
- package/dist/stripe.js.map +1 -0
- package/dist/tax.d.ts +33 -0
- package/dist/tax.d.ts.map +1 -0
- package/dist/tax.js +55 -0
- package/dist/tax.js.map +1 -0
- package/dist/testing/arbitraries.d.ts +43 -0
- package/dist/testing/arbitraries.d.ts.map +1 -0
- package/dist/testing/arbitraries.js +98 -0
- package/dist/testing/arbitraries.js.map +1 -0
- package/dist/testing/index.d.ts +67 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +159 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/jest.d.ts +2 -0
- package/dist/testing/jest.d.ts.map +1 -0
- package/dist/testing/jest.js +15 -0
- package/dist/testing/jest.js.map +1 -0
- package/dist/testing/vitest.d.ts +7 -0
- package/dist/testing/vitest.d.ts.map +1 -0
- package/dist/testing/vitest.js +12 -0
- package/dist/testing/vitest.js.map +1 -0
- package/dist/valibot.d.ts +33 -0
- package/dist/valibot.d.ts.map +1 -0
- package/dist/valibot.js +61 -0
- package/dist/valibot.js.map +1 -0
- package/dist/zod.d.ts +36 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +58 -0
- package/dist/zod.js.map +1 -0
- package/package.json +280 -5
- package/src/adyen-fx.ts +175 -0
- package/src/adyen.ts +46 -0
- package/src/allocate.ts +393 -0
- package/src/bag.ts +170 -0
- package/src/boc.ts +136 -0
- package/src/boe.ts +131 -0
- package/src/braintree.ts +71 -0
- package/src/cash.ts +183 -0
- package/src/checkout.ts +77 -0
- package/src/convert.ts +177 -0
- package/src/currency.ts +61 -0
- package/src/decimal.ts +283 -0
- package/src/drizzle/mysql.ts +78 -0
- package/src/drizzle/pg.ts +78 -0
- package/src/drizzle/sqlite.ts +70 -0
- package/src/ecb.ts +328 -0
- package/src/exact.ts +182 -0
- package/src/fed.ts +146 -0
- package/src/fetch.ts +306 -0
- package/src/fixed.ts +558 -0
- package/src/fn.ts +94 -0
- package/src/format.ts +106 -0
- package/src/generated/adyen.ts +144 -0
- package/src/generated/braintree.ts +140 -0
- package/src/generated/cash.ts +478 -0
- package/src/generated/checkout.ts +151 -0
- package/src/generated/historic.ts +67 -0
- package/src/generated/iso4217.ts +179 -0
- package/src/generated/kernel.ts +230 -0
- package/src/generated/klarna.ts +21 -0
- package/src/generated/paypal.ts +31 -0
- package/src/generated/stripe.ts +150 -0
- package/src/historic.ts +77 -0
- package/src/history.ts +333 -0
- package/src/hmrc.ts +125 -0
- package/src/index.ts +41 -0
- package/src/klarna.ts +54 -0
- package/src/kysely.ts +588 -0
- package/src/money.ts +979 -0
- package/src/parse.ts +511 -0
- package/src/paypal.ts +93 -0
- package/src/pg.ts +410 -0
- package/src/plugins/adyen.ts +25 -0
- package/src/plugins/all.ts +57 -0
- package/src/plugins/allocate.ts +53 -0
- package/src/plugins/braintree.ts +23 -0
- package/src/plugins/cash.ts +33 -0
- package/src/plugins/checkout.ts +32 -0
- package/src/plugins/convert.ts +49 -0
- package/src/plugins/exact.ts +23 -0
- package/src/plugins/fixed.ts +28 -0
- package/src/plugins/format.ts +28 -0
- package/src/plugins/klarna.ts +21 -0
- package/src/plugins/paypal.ts +29 -0
- package/src/plugins/prisma.ts +24 -0
- package/src/plugins/stripe.ts +29 -0
- package/src/plugins/tax.ts +40 -0
- package/src/policy.ts +124 -0
- package/src/prisma.ts +199 -0
- package/src/processor.ts +181 -0
- package/src/provider.ts +389 -0
- package/src/rate-text.ts +151 -0
- package/src/rate.ts +546 -0
- package/src/rounding-error.ts +8 -0
- package/src/rounding.ts +122 -0
- package/src/schema.ts +119 -0
- package/src/sql.ts +178 -0
- package/src/stripe-fx.ts +49 -0
- package/src/stripe.ts +69 -0
- package/src/tax.ts +102 -0
- package/src/testing/arbitraries.ts +134 -0
- package/src/testing/index.ts +247 -0
- package/src/testing/jest.ts +18 -0
- package/src/testing/vitest.ts +18 -0
- package/src/valibot.ts +87 -0
- package/src/zod.ts +78 -0
package/dist/fetch.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// Network fetchers for published reference rates, using the platform fetch. Opt-in: nothing else in
|
|
2
|
+
// the library imports this module, so core and @ducatjs/money/convert never touch the
|
|
3
|
+
// network. You decide when to call it and how to cache.
|
|
4
|
+
import { parseBankOfCanadaJson } from './boc.js';
|
|
5
|
+
import { parseEcbSdmxCsv, parseEcbSdmxDecimals, parseEcbXml } from './ecb.js';
|
|
6
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
7
|
+
/** The ECB's eurofxref files: the latest day, the last 90 days, and the full history since 1999. */
|
|
8
|
+
export const ECB_URLS = {
|
|
9
|
+
daily: 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml',
|
|
10
|
+
'90d': 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml',
|
|
11
|
+
all: 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml',
|
|
12
|
+
};
|
|
13
|
+
/** Thrown when the HTTP request completes without a 2xx status. */
|
|
14
|
+
export class FetchRatesError extends Error {
|
|
15
|
+
status;
|
|
16
|
+
url;
|
|
17
|
+
constructor(url, status) {
|
|
18
|
+
super(`GET ${url} failed with HTTP ${status}`);
|
|
19
|
+
this.name = 'FetchRatesError';
|
|
20
|
+
this.status = status;
|
|
21
|
+
this.url = url;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Fetches the ECB euro reference rates and parses them with parseEcbXml: EUR-based tables,
|
|
26
|
+
* newest first. The ECB publishes once per TARGET working day at about 16:00 CET and states
|
|
27
|
+
* that its rates are for information purposes only.
|
|
28
|
+
*
|
|
29
|
+
* const [latest] = await fetchEcb(); // the RateTable for the last published day
|
|
30
|
+
* const hist = snapshotsFrom(await fetchEcb({ history: '90d' }));
|
|
31
|
+
*/
|
|
32
|
+
export async function fetchEcb(options) {
|
|
33
|
+
const url = ECB_URLS[options?.history ?? 'daily'];
|
|
34
|
+
const body = await getText(url, 'application/xml', options);
|
|
35
|
+
return parsedFrom(url, () => parseEcbXml(body));
|
|
36
|
+
}
|
|
37
|
+
/** The caller's signal, a timeout signal, or both combined. */
|
|
38
|
+
function requestSignal(signal, timeout) {
|
|
39
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
40
|
+
throw new RangeError(`timeout must be a non-negative number of milliseconds, got ${timeout}`);
|
|
41
|
+
}
|
|
42
|
+
const statics = globalThis.AbortSignal;
|
|
43
|
+
if (timeout === 0 || statics?.timeout === undefined) {
|
|
44
|
+
return signal;
|
|
45
|
+
}
|
|
46
|
+
const timeoutSignal = statics.timeout(timeout);
|
|
47
|
+
if (signal === undefined) {
|
|
48
|
+
return timeoutSignal;
|
|
49
|
+
}
|
|
50
|
+
if (statics.any === undefined) {
|
|
51
|
+
// Without AbortSignal.any the caller's signal wins: it is the one they can control.
|
|
52
|
+
return signal;
|
|
53
|
+
}
|
|
54
|
+
return statics.any([signal, timeoutSignal]);
|
|
55
|
+
}
|
|
56
|
+
/** The ECB Data Portal's SDMX REST API (no key, and CORS-enabled, so it works in browsers). */
|
|
57
|
+
export const ECB_DATA_API = 'https://data-api.ecb.europa.eu/service/data/EXR';
|
|
58
|
+
/**
|
|
59
|
+
* A request's UTC day: a 'YYYY-MM-DD' string that is a real calendar day, or a Date (any
|
|
60
|
+
* offset) as its UTC day. Anything else is a RangeError, before any request is made.
|
|
61
|
+
*/
|
|
62
|
+
function requestDay(time, name) {
|
|
63
|
+
let day;
|
|
64
|
+
if (typeof time === 'string') {
|
|
65
|
+
day = time;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
day = Number.isNaN(time.getTime()) ? '' : time.toISOString().slice(0, 10);
|
|
69
|
+
}
|
|
70
|
+
const match = /^(\d{4})-(\d\d)-(\d\d)$/.exec(day);
|
|
71
|
+
const date = match === null ? undefined : new Date(Date.UTC(+match[1], +match[2] - 1, +match[3]));
|
|
72
|
+
// Date.UTC rolls 30 February over into March, so a real day must come back unchanged.
|
|
73
|
+
if (date === undefined || date.toISOString().slice(0, 10) !== day) {
|
|
74
|
+
throw new RangeError(`${name} must be a date, got ${String(time)}`);
|
|
75
|
+
}
|
|
76
|
+
return day;
|
|
77
|
+
}
|
|
78
|
+
/** Wraps a parser's SyntaxError with the URL the bad file came from (an error page, usually). */
|
|
79
|
+
function parsedFrom(url, parse) {
|
|
80
|
+
try {
|
|
81
|
+
return parse();
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error instanceof SyntaxError) {
|
|
85
|
+
throw new SyntaxError(`${error.message} (from ${url})`, { cause: error });
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** GETs `url` as text, with the timeout and signal handling every fetcher here shares. */
|
|
91
|
+
async function getText(url, accept, options) {
|
|
92
|
+
return (await getTextOrNotFound(url, accept, options, false));
|
|
93
|
+
}
|
|
94
|
+
/** getText, or undefined for HTTP 404 when `notFoundIsEmpty` (an API's "no results"). */
|
|
95
|
+
async function getTextOrNotFound(url, accept, options, notFoundIsEmpty) {
|
|
96
|
+
const fetchFunction = options?.fetch ?? globalThis.fetch;
|
|
97
|
+
if (fetchFunction === undefined) {
|
|
98
|
+
throw new TypeError('No fetch available: pass options.fetch');
|
|
99
|
+
}
|
|
100
|
+
const init = {
|
|
101
|
+
headers: { accept },
|
|
102
|
+
};
|
|
103
|
+
const signal = requestSignal(options?.signal, options?.timeout ?? DEFAULT_TIMEOUT_MS);
|
|
104
|
+
if (signal !== undefined) {
|
|
105
|
+
init.signal = signal;
|
|
106
|
+
}
|
|
107
|
+
const response = await fetchFunction(url, init);
|
|
108
|
+
if (notFoundIsEmpty && response.status === 404) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
throw new FetchRatesError(url, response.status);
|
|
113
|
+
}
|
|
114
|
+
return response.text();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Fetches a date range of ECB euro reference rates from the ECB Data Portal and parses them with
|
|
118
|
+
* parseEcbSdmxCsv: EUR-based tables, one per TARGET working day, newest first, with the published
|
|
119
|
+
* digits. It makes two requests: the series' DECIMALS (small) and the observations without
|
|
120
|
+
* attributes, which keeps the full history since 1999 to about 15 MB. Give a few days before the
|
|
121
|
+
* first day you need, so that a lookback from it has a table to fall back on. A range with no
|
|
122
|
+
* rates (a weekend, or after the latest day) gives []. Both requests share one timeout and are
|
|
123
|
+
* cancelled together: if one fails, the other is aborted. The ECB states that its rates are for
|
|
124
|
+
* information purposes only.
|
|
125
|
+
*
|
|
126
|
+
* const tables = await fetchEcbRange({ start: '2026-01-01', currencies: ['USD', 'JPY'] });
|
|
127
|
+
* const history = rateHistory(tables); // from @ducatjs/money/convert/history
|
|
128
|
+
*/
|
|
129
|
+
export async function fetchEcbRange(options) {
|
|
130
|
+
const currencies = options.currencies ?? [];
|
|
131
|
+
for (const currency of currencies) {
|
|
132
|
+
if (!/^[A-Z]{3}$/.test(currency)) {
|
|
133
|
+
throw new RangeError(`Not an ISO currency code: ${currency}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const start = requestDay(options.start, 'start');
|
|
137
|
+
if (start < '1999-01-04') {
|
|
138
|
+
throw new RangeError(`The ECB's rates start on 1999-01-04, not ${start}`);
|
|
139
|
+
}
|
|
140
|
+
let query = `?format=csvdata&startPeriod=${start}`;
|
|
141
|
+
if (options.end !== undefined) {
|
|
142
|
+
const end = requestDay(options.end, 'end');
|
|
143
|
+
if (end < start) {
|
|
144
|
+
throw new RangeError(`end ${end} is before start ${start}`);
|
|
145
|
+
}
|
|
146
|
+
query += `&endPeriod=${end}`;
|
|
147
|
+
}
|
|
148
|
+
const url = `${ECB_DATA_API}/D.${currencies.join('+')}.EUR.SP00.A`;
|
|
149
|
+
const seriesUrl = `${url}?format=csvdata&detail=nodata`;
|
|
150
|
+
const dataUrl = `${url}${query}&detail=dataonly`;
|
|
151
|
+
// One controller for both requests, tied to the caller's signal and the timeout, so that a
|
|
152
|
+
// failure of either cancels the other (the data can be ~15 MB) instead of letting it run on.
|
|
153
|
+
let shared = options;
|
|
154
|
+
let controller;
|
|
155
|
+
const Controller = globalThis
|
|
156
|
+
.AbortController;
|
|
157
|
+
if (Controller !== undefined) {
|
|
158
|
+
const own = new Controller();
|
|
159
|
+
controller = own;
|
|
160
|
+
const outer = requestSignal(options.signal, options.timeout ?? DEFAULT_TIMEOUT_MS);
|
|
161
|
+
if (outer?.aborted === true) {
|
|
162
|
+
own.abort(outer.reason);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
outer?.addEventListener('abort', () => own.abort(outer.reason), { once: true });
|
|
166
|
+
}
|
|
167
|
+
shared = { ...options, signal: own.signal, timeout: 0 };
|
|
168
|
+
}
|
|
169
|
+
let series;
|
|
170
|
+
let data;
|
|
171
|
+
try {
|
|
172
|
+
[series, data] = await Promise.all([
|
|
173
|
+
getText(seriesUrl, 'text/csv', shared),
|
|
174
|
+
getTextOrNotFound(dataUrl, 'text/csv', shared, true),
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
controller?.abort(error);
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
if (data === undefined) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
const decimals = parsedFrom(seriesUrl, () => parseEcbSdmxDecimals(series));
|
|
185
|
+
return parsedFrom(dataUrl, () => parseEcbSdmxCsv(data, { decimals }));
|
|
186
|
+
}
|
|
187
|
+
/** The Bank of Canada's Valet API for its daily exchange rates (no key; CORS-enabled). */
|
|
188
|
+
export const BANK_OF_CANADA_URL = 'https://www.bankofcanada.ca/valet/observations/group/FX_RATES_DAILY/json';
|
|
189
|
+
/**
|
|
190
|
+
* Fetches the Bank of Canada's daily exchange rates from its Valet API and parses them with
|
|
191
|
+
* parseBankOfCanadaJson: CAD-based tables, newest first. Without `start`, only the latest day;
|
|
192
|
+
* without `end`, up to the latest. A range with no business days in it gives [].
|
|
193
|
+
* The Bank asks users to keep within its request limits, which it doesn't publish, and its rates
|
|
194
|
+
* are "released for statistical and analytical purposes only", not for transactions.
|
|
195
|
+
*
|
|
196
|
+
* const [latest] = await fetchBankOfCanada();
|
|
197
|
+
* const year = await fetchBankOfCanada({ start: '2026-01-01' });
|
|
198
|
+
*/
|
|
199
|
+
export async function fetchBankOfCanada(options) {
|
|
200
|
+
let query = '?recent=1';
|
|
201
|
+
if (options?.start !== undefined) {
|
|
202
|
+
const start = requestDay(options.start, 'start');
|
|
203
|
+
if (start < '2017-01-03') {
|
|
204
|
+
throw new RangeError(`Valet's daily rates start on 2017-01-03, not ${start}`);
|
|
205
|
+
}
|
|
206
|
+
query = `?start_date=${start}`;
|
|
207
|
+
if (options.end !== undefined) {
|
|
208
|
+
const end = requestDay(options.end, 'end');
|
|
209
|
+
if (end < start) {
|
|
210
|
+
throw new RangeError(`end ${end} is before start ${start}`);
|
|
211
|
+
}
|
|
212
|
+
query += `&end_date=${end}`;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else if (options?.end !== undefined) {
|
|
216
|
+
throw new RangeError('end needs a start');
|
|
217
|
+
}
|
|
218
|
+
const url = `${BANK_OF_CANADA_URL}${query}`;
|
|
219
|
+
const body = await getText(url, 'application/json', options);
|
|
220
|
+
return parsedFrom(url, () => parseBankOfCanadaJson(body));
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"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"}
|
package/dist/fixed.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { type Factor } from './decimal.js';
|
|
2
|
+
import { type CurrencyInput, type Money } from './money.js';
|
|
3
|
+
import { type RoundingMode } from './rounding.js';
|
|
4
|
+
declare const INTERNAL: unique symbol;
|
|
5
|
+
/** What `fixed()` accepts: a decimal string, a number, a bigint or a Fixed. */
|
|
6
|
+
export type FixedInput = string | number | bigint | Fixed;
|
|
7
|
+
/** Options for `fixed()`. */
|
|
8
|
+
export interface FixedOptions {
|
|
9
|
+
/** Decimal places to keep (default: as many as the input has; 0 for integers). */
|
|
10
|
+
readonly scale?: number;
|
|
11
|
+
/** How to round input with more decimals than `scale` (default 'unnecessary': throw). */
|
|
12
|
+
readonly rounding?: RoundingMode;
|
|
13
|
+
}
|
|
14
|
+
/** Options for multiply and divide. */
|
|
15
|
+
export interface ArithmeticOptions {
|
|
16
|
+
/** The result's scale (default: the scale of the value being multiplied or divided). */
|
|
17
|
+
readonly scale?: number;
|
|
18
|
+
}
|
|
19
|
+
/** The integer-and-scale form of a Fixed: `value / 10^scale`. */
|
|
20
|
+
export interface ScaledInteger {
|
|
21
|
+
readonly value: number | bigint;
|
|
22
|
+
readonly scale: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* An exact fixed-point decimal: `value / 10^scale`. Immutable. Create one with `fixed()` or
|
|
26
|
+
* `fromScaled()`. Mixed scales work as for Money: add, subtract and compare align to the larger
|
|
27
|
+
* scale exactly, and multiply and divide keep this value's scale.
|
|
28
|
+
*/
|
|
29
|
+
export declare class Fixed {
|
|
30
|
+
/** The scaled integer: a number while it is a safe integer, a bigint beyond. */
|
|
31
|
+
readonly value: number | bigint;
|
|
32
|
+
/** Decimal places. */
|
|
33
|
+
readonly scale: number;
|
|
34
|
+
/** @internal use fixed() or fromScaled() */
|
|
35
|
+
constructor(token: typeof INTERNAL, value: number | bigint, scale: number);
|
|
36
|
+
/** this + other, exactly, at the larger of the two scales. */
|
|
37
|
+
add(other: FixedInput): Fixed;
|
|
38
|
+
/** this − other, exactly, at the larger of the two scales. */
|
|
39
|
+
subtract(other: FixedInput): Fixed;
|
|
40
|
+
/**
|
|
41
|
+
* this × factor, rounded once to this value's scale or `options.scale` (default 'halfExpand').
|
|
42
|
+
* The factor is exact: an integer, a decimal string ('1.075'), a bigint, a `ratio()` or another
|
|
43
|
+
* Fixed. Give `scale` rather than calling toScale afterwards, which would round twice.
|
|
44
|
+
*/
|
|
45
|
+
multiply(factor: Factor | Fixed, rounding?: RoundingMode, options?: ArithmeticOptions): Fixed;
|
|
46
|
+
/**
|
|
47
|
+
* this ÷ divisor, rounded once to this value's scale or `options.scale` (default 'halfExpand'):
|
|
48
|
+
* `fixed('9.990').divide('1.2', 'halfEven', { scale: 2 })` is 8.32.
|
|
49
|
+
*/
|
|
50
|
+
divide(divisor: Factor | Fixed, rounding?: RoundingMode, options?: ArithmeticOptions): Fixed;
|
|
51
|
+
/** −this */
|
|
52
|
+
negate(): Fixed;
|
|
53
|
+
/** |this| */
|
|
54
|
+
abs(): Fixed;
|
|
55
|
+
/**
|
|
56
|
+
* Rounds to `scale` decimal places (default 0, an integer): `fixed('2.5').round('halfEven')` is
|
|
57
|
+
* 2. Money's round() defaults to the currency's exponent; a Fixed has none, so the default is 0.
|
|
58
|
+
*/
|
|
59
|
+
round(rounding: RoundingMode, scale?: number): Fixed;
|
|
60
|
+
/**
|
|
61
|
+
* Changes the scale: increasing it is always exact, decreasing it rounds (default 'halfExpand').
|
|
62
|
+
*/
|
|
63
|
+
toScale(scale: number, rounding?: RoundingMode): Fixed;
|
|
64
|
+
/** −1, 0 or 1, exactly, across scales and number/bigint. */
|
|
65
|
+
compare(other: FixedInput): -1 | 0 | 1;
|
|
66
|
+
/** The same value, at any scale: 1.0 equals 1.00. */
|
|
67
|
+
equals(other: FixedInput): boolean;
|
|
68
|
+
/** this < other */
|
|
69
|
+
lessThan(other: FixedInput): boolean;
|
|
70
|
+
/** this ≤ other */
|
|
71
|
+
lessThanOrEqual(other: FixedInput): boolean;
|
|
72
|
+
/** this > other */
|
|
73
|
+
greaterThan(other: FixedInput): boolean;
|
|
74
|
+
/** this ≥ other */
|
|
75
|
+
greaterThanOrEqual(other: FixedInput): boolean;
|
|
76
|
+
/** this = 0 */
|
|
77
|
+
isZero(): boolean;
|
|
78
|
+
/** this > 0 */
|
|
79
|
+
isPositive(): boolean;
|
|
80
|
+
/** this < 0 */
|
|
81
|
+
isNegative(): boolean;
|
|
82
|
+
/** −1, 0 or 1 */
|
|
83
|
+
sign(): -1 | 0 | 1;
|
|
84
|
+
/** The plain decimal string, with every decimal place of the scale: '12.340'. */
|
|
85
|
+
toString(): string;
|
|
86
|
+
/** The decimal string, as toString(), so JSON round-trips exactly through `fixed()`. */
|
|
87
|
+
toJSON(): string;
|
|
88
|
+
/** `{ value, scale }`, the exact integer form: value / 10^scale. */
|
|
89
|
+
toScaled(): ScaledInteger;
|
|
90
|
+
/**
|
|
91
|
+
* Money in `currency`, at its exponent. Throws RoundingError when that would drop digits, unless
|
|
92
|
+
* `rounding` is given: `fixed('1.005').toMoney('EUR', 'halfEven')` is 1.00 EUR.
|
|
93
|
+
*/
|
|
94
|
+
toMoney<C extends CurrencyInput>(currency: C, rounding?: RoundingMode): Money<C>;
|
|
95
|
+
/** Blocks `a + b`, `a > b` and `+a`: arithmetic and comparison go through the methods. */
|
|
96
|
+
[Symbol.toPrimitive](hint: string): string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Creates an exact fixed-point decimal.
|
|
100
|
+
*
|
|
101
|
+
* fixed('12.340') // 12.340: a string keeps its scale (3)
|
|
102
|
+
* fixed('1.005', { scale: 2, rounding: 'halfEven' }) // 1.00
|
|
103
|
+
* fixed(12) // 12, scale 0
|
|
104
|
+
* fixed(0.25) // 0.25: read at its shortest decimal form
|
|
105
|
+
* fixed(10n ** 30n)
|
|
106
|
+
*
|
|
107
|
+
* Numbers are taken at their shortest decimal form, and only when that has at most 15 significant
|
|
108
|
+
* digits, which a double always holds faithfully. So `fixed(0.1 + 0.2)` throws rather than becoming
|
|
109
|
+
* 0.30000000000000004; pass the decimal as a string, or give `scale` and `rounding`. Input with
|
|
110
|
+
* more decimals than `scale` throws unless `rounding` is given, and `rounding` needs a `scale`.
|
|
111
|
+
* Scales run from 0 to 1000.
|
|
112
|
+
*/
|
|
113
|
+
export declare function fixed(value: FixedInput, options?: FixedOptions): Fixed;
|
|
114
|
+
/** The Fixed `value / 10^scale`: `fromScaled(12345, 3)` is 12.345. `value` must be an integer. */
|
|
115
|
+
export declare function fromScaled(value: number | bigint, scale: number): Fixed;
|
|
116
|
+
/** Whether `value` is a Fixed. */
|
|
117
|
+
export declare function isFixed(value: unknown): value is Fixed;
|
|
118
|
+
/** The exact Fixed of a Money amount, at the money's scale: `money('12.34', 'EUR')` → 12.34. */
|
|
119
|
+
export declare function moneyToFixed(money: Money): Fixed;
|
|
120
|
+
export {};
|
|
121
|
+
//# sourceMappingURL=fixed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixed.d.ts","sourceRoot":"","sources":["../src/fixed.ts"],"names":[],"mappings":"AAKA,OAAO,EAOL,KAAK,MAAM,EAEZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,KAAK,EACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAiBvB,QAAA,MAAM,QAAQ,EAAE,OAAO,MAAwB,CAAC;AAEhD,+EAA+E;AAC/E,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1D,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;CAClC;AAED,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAChC,wFAAwF;IACxF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAkCD;;;;GAIG;AACH,qBAAa,KAAK;IAChB,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,sBAAsB;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,4CAA4C;gBAChC,KAAK,EAAE,OAAO,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM;IAWzE,8DAA8D;IAC9D,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK;IAI7B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK;IAIlC;;;;OAIG;IACH,QAAQ,CACN,MAAM,EAAE,MAAM,GAAG,KAAK,EACtB,QAAQ,GAAE,YAA+B,EACzC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,KAAK;IAoBR;;;OAGG;IACH,MAAM,CACJ,OAAO,EAAE,MAAM,GAAG,KAAK,EACvB,QAAQ,GAAE,YAA+B,EACzC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,KAAK;IASR,YAAY;IACZ,MAAM,IAAI,KAAK;IAQf,aAAa;IACb,GAAG,IAAI,KAAK;IAIZ;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,SAAI,GAAG,KAAK;IAI/C;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAE,YAA+B,GAAG,KAAK;IAaxE,4DAA4D;IAC5D,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAoBtC,qDAAqD;IACrD,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IASlC,mBAAmB;IACnB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAIpC,mBAAmB;IACnB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAI3C,mBAAmB;IACnB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAIvC,mBAAmB;IACnB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAI9C,eAAe;IACf,MAAM,IAAI,OAAO;IAIjB,eAAe;IACf,UAAU,IAAI,OAAO;IAIrB,eAAe;IACf,UAAU,IAAI,OAAO;IAIrB,iBAAiB;IACjB,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAYlB,iFAAiF;IACjF,QAAQ,IAAI,MAAM;IAIlB,wFAAwF;IACxF,MAAM,IAAI,MAAM;IAIhB,oEAAoE;IACpE,QAAQ,IAAI,aAAa;IAIzB;;;OAGG;IACH,OAAO,CAAC,CAAC,SAAS,aAAa,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAE,YAA4B,GAAG,KAAK,CAAC,CAAC,CAAC;IAkB/F,0FAA0F;IAC1F,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAQ3C;AA8HD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CA8CtE;AAED,kGAAkG;AAClG,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAYvE;AAED,kCAAkC;AAClC,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,CAEtD;AAED,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAEhD"}
|