@ducatjs/money 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +73 -0
- package/README.md +479 -62
- package/data/cash-rounding.json +123 -2
- package/data/cldr-cash.json +101 -0
- package/data/historic.json +78 -0
- package/data/iso4217-list-three.xml +1185 -0
- package/dist/adyen-fx.d.ts.map +1 -1
- package/dist/adyen-fx.js +22 -4
- package/dist/adyen-fx.js.map +1 -1
- 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/cash.d.ts +30 -1
- package/dist/cash.d.ts.map +1 -1
- package/dist/cash.js +50 -2
- package/dist/cash.js.map +1 -1
- package/dist/convert.d.ts +10 -9
- package/dist/convert.d.ts.map +1 -1
- package/dist/convert.js +13 -3
- package/dist/convert.js.map +1 -1
- 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 +37 -2
- package/dist/ecb.d.ts.map +1 -1
- package/dist/ecb.js +148 -10
- package/dist/ecb.js.map +1 -1
- 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 +45 -0
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +167 -24
- package/dist/fetch.js.map +1 -1
- package/dist/fn.d.ts +8 -1
- package/dist/fn.d.ts.map +1 -1
- package/dist/fn.js +8 -1
- package/dist/fn.js.map +1 -1
- package/dist/generated/cash.d.ts +2 -0
- package/dist/generated/cash.d.ts.map +1 -1
- package/dist/generated/cash.js +101 -0
- package/dist/generated/cash.js.map +1 -1
- 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/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 +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- 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 +93 -9
- package/dist/money.d.ts.map +1 -1
- package/dist/money.js +135 -9
- package/dist/money.js.map +1 -1
- package/dist/parse.d.ts +45 -1
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +290 -3
- package/dist/parse.js.map +1 -1
- 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 +1 -1
- package/dist/plugins/adyen.d.ts.map +1 -1
- package/dist/plugins/adyen.js.map +1 -1
- package/dist/plugins/all.d.ts +8 -1
- package/dist/plugins/all.d.ts.map +1 -1
- package/dist/plugins/all.js +8 -1
- package/dist/plugins/all.js.map +1 -1
- package/dist/plugins/allocate.d.ts +1 -1
- package/dist/plugins/allocate.d.ts.map +1 -1
- package/dist/plugins/allocate.js.map +1 -1
- package/dist/plugins/braintree.d.ts +1 -1
- package/dist/plugins/braintree.d.ts.map +1 -1
- package/dist/plugins/braintree.js.map +1 -1
- package/dist/plugins/cash.d.ts +1 -1
- package/dist/plugins/cash.d.ts.map +1 -1
- package/dist/plugins/cash.js.map +1 -1
- package/dist/plugins/checkout.d.ts +1 -1
- package/dist/plugins/checkout.d.ts.map +1 -1
- package/dist/plugins/checkout.js.map +1 -1
- package/dist/plugins/convert.d.ts +5 -5
- package/dist/plugins/convert.d.ts.map +1 -1
- package/dist/plugins/convert.js.map +1 -1
- package/dist/plugins/exact.d.ts +1 -1
- package/dist/plugins/exact.d.ts.map +1 -1
- package/dist/plugins/exact.js.map +1 -1
- package/dist/plugins/fixed.d.ts +1 -1
- package/dist/plugins/fixed.d.ts.map +1 -1
- package/dist/plugins/fixed.js.map +1 -1
- package/dist/plugins/format.d.ts +1 -1
- package/dist/plugins/format.d.ts.map +1 -1
- package/dist/plugins/format.js.map +1 -1
- package/dist/plugins/klarna.d.ts +1 -1
- package/dist/plugins/klarna.d.ts.map +1 -1
- package/dist/plugins/klarna.js.map +1 -1
- package/dist/plugins/paypal.d.ts +1 -1
- package/dist/plugins/paypal.d.ts.map +1 -1
- package/dist/plugins/paypal.js +0 -4
- package/dist/plugins/paypal.js.map +1 -1
- package/dist/plugins/prisma.d.ts +1 -1
- package/dist/plugins/prisma.d.ts.map +1 -1
- package/dist/plugins/prisma.js +0 -4
- package/dist/plugins/prisma.js.map +1 -1
- package/dist/plugins/stripe.d.ts +1 -1
- package/dist/plugins/stripe.d.ts.map +1 -1
- package/dist/plugins/stripe.js +0 -4
- package/dist/plugins/stripe.js.map +1 -1
- package/dist/plugins/tax.d.ts +6 -6
- package/dist/plugins/tax.d.ts.map +1 -1
- package/dist/plugins/tax.js.map +1 -1
- 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 +25 -14
- package/dist/prisma.d.ts.map +1 -1
- package/dist/prisma.js +29 -19
- package/dist/prisma.js.map +1 -1
- package/dist/provider.d.ts +21 -7
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +51 -11
- package/dist/provider.js.map +1 -1
- 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 +61 -5
- package/dist/rate.d.ts.map +1 -1
- package/dist/rate.js +133 -33
- package/dist/rate.js.map +1 -1
- package/dist/rounding.js +1 -1
- package/dist/rounding.js.map +1 -1
- 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/tax.d.ts +13 -9
- package/dist/tax.d.ts.map +1 -1
- package/dist/tax.js +20 -4
- package/dist/tax.js.map +1 -1
- 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 +116 -5
- package/src/adyen-fx.ts +25 -4
- package/src/boc.ts +136 -0
- package/src/boe.ts +131 -0
- package/src/cash.ts +70 -2
- package/src/convert.ts +33 -15
- 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 +179 -13
- package/src/fed.ts +146 -0
- package/src/fetch.ts +207 -28
- package/src/fn.ts +14 -0
- package/src/generated/cash.ts +103 -0
- package/src/generated/historic.ts +67 -0
- package/src/historic.ts +77 -0
- package/src/history.ts +333 -0
- package/src/hmrc.ts +125 -0
- package/src/index.ts +4 -0
- package/src/kysely.ts +588 -0
- package/src/money.ts +210 -12
- package/src/parse.ts +371 -4
- package/src/pg.ts +410 -0
- package/src/plugins/adyen.ts +3 -2
- package/src/plugins/all.ts +10 -0
- package/src/plugins/allocate.ts +3 -2
- package/src/plugins/braintree.ts +3 -2
- package/src/plugins/cash.ts +3 -2
- package/src/plugins/checkout.ts +3 -2
- package/src/plugins/convert.ts +6 -6
- package/src/plugins/exact.ts +3 -2
- package/src/plugins/fixed.ts +3 -2
- package/src/plugins/format.ts +3 -2
- package/src/plugins/klarna.ts +3 -2
- package/src/plugins/paypal.ts +3 -2
- package/src/plugins/prisma.ts +3 -2
- package/src/plugins/stripe.ts +3 -2
- package/src/plugins/tax.ts +11 -11
- package/src/policy.ts +124 -0
- package/src/prisma.ts +91 -10
- package/src/provider.ts +81 -16
- package/src/rate-text.ts +151 -0
- package/src/rate.ts +205 -36
- package/src/rounding.ts +1 -1
- package/src/schema.ts +119 -0
- package/src/sql.ts +178 -0
- package/src/tax.ts +40 -9
- 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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jest.d.ts","sourceRoot":"","sources":["../../src/testing/jest.ts"],"names":[],"mappings":"AASA,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ducatjs/money/testing/jest`: one import in a Jest setup file (`setupFilesAfterEnv`) installs
|
|
3
|
+
* the money matchers, value equality and the snapshot serializer on Jest's global `expect`. It
|
|
4
|
+
* needs no Jest package of its own. For the types, add `MoneyMatchers` to Jest's `Matchers` in a
|
|
5
|
+
* declaration file (see the README): augmenting Jest's global namespace from here would clash
|
|
6
|
+
* with Vitest's types in projects that have both.
|
|
7
|
+
*/
|
|
8
|
+
import { installMoneyMatchers } from './index.js';
|
|
9
|
+
export * from './index.js';
|
|
10
|
+
const globalExpect = globalThis.expect;
|
|
11
|
+
if (globalExpect === undefined) {
|
|
12
|
+
throw new Error('@ducatjs/money/testing/jest needs Jest’s global expect; import it from a setup file, or call installMoneyMatchers(expect)');
|
|
13
|
+
}
|
|
14
|
+
installMoneyMatchers(globalExpect);
|
|
15
|
+
//# sourceMappingURL=jest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jest.js","sourceRoot":"","sources":["../../src/testing/jest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,oBAAoB,EAA6B,MAAM,YAAY,CAAC;AAE7E,cAAc,YAAY,CAAC;AAE3B,MAAM,YAAY,GAAI,UAAgD,CAAC,MAAM,CAAC;AAC9E,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;IAC/B,MAAM,IAAI,KAAK,CACb,2HAA2H,CAC5H,CAAC;AACJ,CAAC;AACD,oBAAoB,CAAC,YAAY,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../../src/testing/vitest.ts"],"names":[],"mappings":"AAQA,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtE,cAAc,YAAY,CAAC;AAE3B,OAAO,QAAQ,QAAQ,CAAC;IAEtB,UAAU,QAAQ,CAAC,CAAC,GAAG,GAAG,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;KAAG;CACxD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ducatjs/money/testing/vitest`: one import in a Vitest setup file installs the money matchers,
|
|
3
|
+
* value equality and the snapshot serializer, and types the matchers on `expect`:
|
|
4
|
+
*
|
|
5
|
+
* // vitest.config.ts: test: { setupFiles: ['./test/setup.ts'] }
|
|
6
|
+
* import '@ducatjs/money/testing/vitest';
|
|
7
|
+
*/
|
|
8
|
+
import { expect } from 'vitest';
|
|
9
|
+
import { installMoneyMatchers } from './index.js';
|
|
10
|
+
export * from './index.js';
|
|
11
|
+
installMoneyMatchers(expect);
|
|
12
|
+
//# sourceMappingURL=vitest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../../src/testing/vitest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAsB,MAAM,YAAY,CAAC;AAEtE,cAAc,YAAY,CAAC;AAO3B,oBAAoB,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ducatjs/money/valibot`: Valibot schemas for the JSON form of Money, `{ "amount": "12.34",
|
|
3
|
+
* "currency": "EUR" }`, for API boundaries. Valibot is an optional peer dependency: only this entry
|
|
4
|
+
* imports it.
|
|
5
|
+
*/
|
|
6
|
+
import * as valibot from 'valibot';
|
|
7
|
+
import { type MoneyJSON } from './money.js';
|
|
8
|
+
import { type MoneyFor, type MoneySchemaOptions } from './schema.js';
|
|
9
|
+
export type { MoneyFor, MoneySchemaOptions } from './schema.js';
|
|
10
|
+
declare const jsonShape: valibot.ObjectSchema<{
|
|
11
|
+
readonly amount: valibot.StringSchema<undefined>;
|
|
12
|
+
readonly currency: valibot.StringSchema<undefined>;
|
|
13
|
+
}, undefined>;
|
|
14
|
+
/** The schema type both functions return: the JSON shape, then a transformation. */
|
|
15
|
+
export type MoneySchema<TOutput> = valibot.SchemaWithPipe<readonly [typeof jsonShape, valibot.RawTransformAction<MoneyJSON, TOutput>]>;
|
|
16
|
+
/**
|
|
17
|
+
* Parses `{ amount, currency }` into Money, accepting exactly what the Zod entry accepts (see its
|
|
18
|
+
* `moneySchema`): an exact decimal string with no more decimals than the scale and at most
|
|
19
|
+
* `maxDigits` digits, padded to the scale, and a listed or known currency. Problems are Valibot
|
|
20
|
+
* issues on `amount` or `currency`; other keys are dropped. Bad options throw when the schema is
|
|
21
|
+
* built. Valibot has no codecs, so encode with `money.toJSON()` (or `JSON.stringify`), which this
|
|
22
|
+
* schema reads back.
|
|
23
|
+
*
|
|
24
|
+
* const Order = valibot.object({ total: moneySchema({ currency: 'EUR' }) })
|
|
25
|
+
* v.parse(Order, { total: { amount: '12.34', currency: 'EUR' } }).total // Money<'EUR'>
|
|
26
|
+
*/
|
|
27
|
+
export declare function moneySchema<C extends string = string>(options?: MoneySchemaOptions<C>): MoneySchema<MoneyFor<C>>;
|
|
28
|
+
/**
|
|
29
|
+
* Like `moneySchema`, but the output stays the JSON object: it checks that the input would parse,
|
|
30
|
+
* for code that passes the JSON on rather than computing with it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function moneyJSONSchema<C extends string = string>(options?: MoneySchemaOptions<C>): MoneySchema<MoneyJSON<C>>;
|
|
33
|
+
//# sourceMappingURL=valibot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"valibot.d.ts","sourceRoot":"","sources":["../src/valibot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAGL,KAAK,QAAQ,EAEb,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEhE,QAAA,MAAM,SAAS;;;aAA2E,CAAC;AAE3F,oFAAoF;AACpF,MAAM,MAAM,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC,cAAc,CACvD,SAAS,CAAC,OAAO,SAAS,EAAE,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAC5E,CAAC;AAeF;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACnD,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAc1B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACvD,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAc3B"}
|
package/dist/valibot.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ducatjs/money/valibot`: Valibot schemas for the JSON form of Money, `{ "amount": "12.34",
|
|
3
|
+
* "currency": "EUR" }`, for API boundaries. Valibot is an optional peer dependency: only this entry
|
|
4
|
+
* imports it.
|
|
5
|
+
*/
|
|
6
|
+
import * as valibot from 'valibot';
|
|
7
|
+
import { isMoney } from './money.js';
|
|
8
|
+
import { checkSchemaOptions, readMoneyJSON, } from './schema.js';
|
|
9
|
+
const jsonShape = valibot.object({ amount: valibot.string(), currency: valibot.string() });
|
|
10
|
+
/** A Valibot issue path pointing at the field that is wrong. */
|
|
11
|
+
function pathTo(json, issue) {
|
|
12
|
+
return [
|
|
13
|
+
{
|
|
14
|
+
type: 'object',
|
|
15
|
+
origin: 'value',
|
|
16
|
+
input: json,
|
|
17
|
+
key: issue.field,
|
|
18
|
+
value: json[issue.field],
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parses `{ amount, currency }` into Money, accepting exactly what the Zod entry accepts (see its
|
|
24
|
+
* `moneySchema`): an exact decimal string with no more decimals than the scale and at most
|
|
25
|
+
* `maxDigits` digits, padded to the scale, and a listed or known currency. Problems are Valibot
|
|
26
|
+
* issues on `amount` or `currency`; other keys are dropped. Bad options throw when the schema is
|
|
27
|
+
* built. Valibot has no codecs, so encode with `money.toJSON()` (or `JSON.stringify`), which this
|
|
28
|
+
* schema reads back.
|
|
29
|
+
*
|
|
30
|
+
* const Order = valibot.object({ total: moneySchema({ currency: 'EUR' }) })
|
|
31
|
+
* v.parse(Order, { total: { amount: '12.34', currency: 'EUR' } }).total // Money<'EUR'>
|
|
32
|
+
*/
|
|
33
|
+
export function moneySchema(options) {
|
|
34
|
+
checkSchemaOptions(options);
|
|
35
|
+
return valibot.pipe(jsonShape, valibot.rawTransform(({ dataset, addIssue, NEVER }) => {
|
|
36
|
+
const json = dataset.value;
|
|
37
|
+
const result = readMoneyJSON(json, options);
|
|
38
|
+
if (isMoney(result)) {
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
addIssue({ message: result.message, path: pathTo(json, result) });
|
|
42
|
+
return NEVER;
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Like `moneySchema`, but the output stays the JSON object: it checks that the input would parse,
|
|
47
|
+
* for code that passes the JSON on rather than computing with it.
|
|
48
|
+
*/
|
|
49
|
+
export function moneyJSONSchema(options) {
|
|
50
|
+
checkSchemaOptions(options);
|
|
51
|
+
return valibot.pipe(jsonShape, valibot.rawTransform(({ dataset, addIssue, NEVER }) => {
|
|
52
|
+
const json = dataset.value;
|
|
53
|
+
const result = readMoneyJSON(json, options);
|
|
54
|
+
if (isMoney(result)) {
|
|
55
|
+
return json;
|
|
56
|
+
}
|
|
57
|
+
addIssue({ message: result.message, path: pathTo(json, result) });
|
|
58
|
+
return NEVER;
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=valibot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"valibot.js","sourceRoot":"","sources":["../src/valibot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,OAAO,EAA8B,MAAM,YAAY,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,aAAa,GAId,MAAM,aAAa,CAAC;AAIrB,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAO3F,gEAAgE;AAChE,SAAS,MAAM,CAAC,IAAe,EAAE,KAAiB;IAChD,OAAO;QACL;YACE,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,IAA0C;YACjD,GAAG,EAAE,KAAK,CAAC,KAAK;YAChB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;SACzB;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,OAA+B;IAE/B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,OAAO,CAAC,IAAI,CACjB,SAAS,EACT,OAAO,CAAC,YAAY,CAAyB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACpB,OAAO,MAA8B,CAAC;QACxC,CAAC;QACD,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAClE,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA+B;IAE/B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,OAAO,CAAC,IAAI,CACjB,SAAS,EACT,OAAO,CAAC,YAAY,CAA0B,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QAC7E,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACpB,OAAO,IAAoB,CAAC;QAC9B,CAAC;QACD,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAClE,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
package/dist/zod.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ducatjs/money/zod`: Zod schemas for the JSON form of Money, `{ "amount": "12.34", "currency":
|
|
3
|
+
* "EUR" }`, for API boundaries. Zod is an optional peer dependency: only this entry imports it.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { type MoneyJSON } from './money.js';
|
|
7
|
+
import { type MoneyFor, type MoneySchemaOptions } from './schema.js';
|
|
8
|
+
export type { MoneyFor, MoneySchemaOptions } from './schema.js';
|
|
9
|
+
declare const jsonShape: z.ZodObject<{
|
|
10
|
+
amount: z.ZodString;
|
|
11
|
+
currency: z.ZodString;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
/** The schema `moneySchema` returns: a Zod codec between the JSON form and Money. */
|
|
14
|
+
export type MoneyCodec<C extends string> = z.ZodCodec<typeof jsonShape, z.ZodCustom<MoneyFor<C>>>;
|
|
15
|
+
/**
|
|
16
|
+
* Parses `{ amount, currency }` into Money, and encodes Money back to that JSON form. It is a Zod
|
|
17
|
+
* codec, so `schema.parse(json)` (or `z.decode`) gives Money and `z.encode(schema, money)` gives
|
|
18
|
+
* `{ amount, currency }`, written at the amount's own scale.
|
|
19
|
+
*
|
|
20
|
+
* The amount must be an exact decimal string with no more decimals than the scale (the
|
|
21
|
+
* currency's exponent unless `scale` is given; `rounding` allows more), and at most `maxDigits`
|
|
22
|
+
* digits. The currency must be one of `currency`, or any known code. Shorter amounts are padded to
|
|
23
|
+
* the scale ("1.5" EUR gives 1.50 EUR). Problems are Zod issues on `amount` or `currency`; keys
|
|
24
|
+
* other than those two are dropped. Bad options throw when the schema is built.
|
|
25
|
+
*
|
|
26
|
+
* const Order = z.object({ total: moneySchema({ currency: 'EUR' }) })
|
|
27
|
+
* Order.parse({ total: { amount: '12.34', currency: 'EUR' } }).total // Money<'EUR'>
|
|
28
|
+
*/
|
|
29
|
+
export declare function moneySchema<C extends string = string>(options?: MoneySchemaOptions<C>): MoneyCodec<C>;
|
|
30
|
+
/**
|
|
31
|
+
* Like `moneySchema`, but the output stays the JSON object (with only `amount` and `currency`): it
|
|
32
|
+
* checks that the input would parse, for code that passes the JSON on rather than computing with
|
|
33
|
+
* it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function moneyJSONSchema<C extends string = string>(options?: MoneySchemaOptions<C>): z.ZodType<MoneyJSON<C>, MoneyJSON>;
|
|
36
|
+
//# sourceMappingURL=zod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.d.ts","sourceRoot":"","sources":["../src/zod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEhE,QAAA,MAAM,SAAS;;;iBAAyD,CAAC;AAEzE,qFAAqF;AACrF,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAElG;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACnD,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,UAAU,CAAC,CAAC,CAAC,CAsBf;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACvD,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAUpC"}
|
package/dist/zod.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ducatjs/money/zod`: Zod schemas for the JSON form of Money, `{ "amount": "12.34", "currency":
|
|
3
|
+
* "EUR" }`, for API boundaries. Zod is an optional peer dependency: only this entry imports it.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { isMoney } from './money.js';
|
|
7
|
+
import { checkSchemaOptions, readMoneyJSON, } from './schema.js';
|
|
8
|
+
const jsonShape = z.object({ amount: z.string(), currency: z.string() });
|
|
9
|
+
/**
|
|
10
|
+
* Parses `{ amount, currency }` into Money, and encodes Money back to that JSON form. It is a Zod
|
|
11
|
+
* codec, so `schema.parse(json)` (or `z.decode`) gives Money and `z.encode(schema, money)` gives
|
|
12
|
+
* `{ amount, currency }`, written at the amount's own scale.
|
|
13
|
+
*
|
|
14
|
+
* The amount must be an exact decimal string with no more decimals than the scale (the
|
|
15
|
+
* currency's exponent unless `scale` is given; `rounding` allows more), and at most `maxDigits`
|
|
16
|
+
* digits. The currency must be one of `currency`, or any known code. Shorter amounts are padded to
|
|
17
|
+
* the scale ("1.5" EUR gives 1.50 EUR). Problems are Zod issues on `amount` or `currency`; keys
|
|
18
|
+
* other than those two are dropped. Bad options throw when the schema is built.
|
|
19
|
+
*
|
|
20
|
+
* const Order = z.object({ total: moneySchema({ currency: 'EUR' }) })
|
|
21
|
+
* Order.parse({ total: { amount: '12.34', currency: 'EUR' } }).total // Money<'EUR'>
|
|
22
|
+
*/
|
|
23
|
+
export function moneySchema(options) {
|
|
24
|
+
checkSchemaOptions(options);
|
|
25
|
+
return z.codec(jsonShape, z.custom((value) => isMoney(value)), {
|
|
26
|
+
decode: (json, payload) => {
|
|
27
|
+
const result = readMoneyJSON(json, options);
|
|
28
|
+
if (isMoney(result)) {
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
payload.issues.push({
|
|
32
|
+
code: 'custom',
|
|
33
|
+
message: result.message,
|
|
34
|
+
input: json,
|
|
35
|
+
path: [result.field],
|
|
36
|
+
});
|
|
37
|
+
return z.NEVER;
|
|
38
|
+
},
|
|
39
|
+
encode: (value) => value.toJSON(),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Like `moneySchema`, but the output stays the JSON object (with only `amount` and `currency`): it
|
|
44
|
+
* checks that the input would parse, for code that passes the JSON on rather than computing with
|
|
45
|
+
* it.
|
|
46
|
+
*/
|
|
47
|
+
export function moneyJSONSchema(options) {
|
|
48
|
+
checkSchemaOptions(options);
|
|
49
|
+
return jsonShape.transform((json, context) => {
|
|
50
|
+
const result = readMoneyJSON(json, options);
|
|
51
|
+
if (isMoney(result)) {
|
|
52
|
+
return json;
|
|
53
|
+
}
|
|
54
|
+
context.addIssue({ code: 'custom', message: result.message, path: [result.field] });
|
|
55
|
+
return z.NEVER;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=zod.js.map
|
package/dist/zod.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.js","sourceRoot":"","sources":["../src/zod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAA8B,MAAM,YAAY,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,aAAa,GAGd,MAAM,aAAa,CAAC;AAIrB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAKzE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CACzB,OAA+B;IAE/B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,CAAC,KAAK,CACZ,SAAS,EACT,CAAC,CAAC,MAAM,CAAc,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAChD;QACE,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE;YACxB,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC5C,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBACpB,OAAO,MAA8B,CAAC;YACxC,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;gBAClB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,KAAK,EAAE,IAAI;gBACX,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;aACrB,CAAC,CAAC;YACH,OAAO,CAAC,CAAC,KAAK,CAAC;QACjB,CAAC;QACD,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAE,KAAe,CAAC,MAAM,EAAE;KAC7C,CACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA+B;IAE/B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACpB,OAAO,IAAoB,CAAC;QAC9B,CAAC;QACD,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACpF,OAAO,CAAC,CAAC,KAAK,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ducatjs/money",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Exact, fast, typed Money for TypeScript: integer minor units, bigint fallback, Stripe/Adyen views, allocation, cash rounding, Prisma helpers.",
|
|
5
5
|
"homepage": "https://github.com/public/ducat#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -23,7 +23,11 @@
|
|
|
23
23
|
"type": "module",
|
|
24
24
|
"sideEffects": [
|
|
25
25
|
"./dist/plugins/*.js",
|
|
26
|
-
"./src/plugins/*.ts"
|
|
26
|
+
"./src/plugins/*.ts",
|
|
27
|
+
"./dist/testing/vitest.js",
|
|
28
|
+
"./dist/testing/jest.js",
|
|
29
|
+
"./src/testing/vitest.ts",
|
|
30
|
+
"./src/testing/jest.ts"
|
|
27
31
|
],
|
|
28
32
|
"exports": {
|
|
29
33
|
".": {
|
|
@@ -50,6 +54,30 @@
|
|
|
50
54
|
"types": "./dist/ecb.d.ts",
|
|
51
55
|
"default": "./dist/ecb.js"
|
|
52
56
|
},
|
|
57
|
+
"./convert/history": {
|
|
58
|
+
"types": "./dist/history.d.ts",
|
|
59
|
+
"default": "./dist/history.js"
|
|
60
|
+
},
|
|
61
|
+
"./convert/boc": {
|
|
62
|
+
"types": "./dist/boc.d.ts",
|
|
63
|
+
"default": "./dist/boc.js"
|
|
64
|
+
},
|
|
65
|
+
"./convert/fed": {
|
|
66
|
+
"types": "./dist/fed.d.ts",
|
|
67
|
+
"default": "./dist/fed.js"
|
|
68
|
+
},
|
|
69
|
+
"./historic": {
|
|
70
|
+
"types": "./dist/historic.d.ts",
|
|
71
|
+
"default": "./dist/historic.js"
|
|
72
|
+
},
|
|
73
|
+
"./convert/boe": {
|
|
74
|
+
"types": "./dist/boe.d.ts",
|
|
75
|
+
"default": "./dist/boe.js"
|
|
76
|
+
},
|
|
77
|
+
"./convert/hmrc": {
|
|
78
|
+
"types": "./dist/hmrc.d.ts",
|
|
79
|
+
"default": "./dist/hmrc.js"
|
|
80
|
+
},
|
|
53
81
|
"./convert/fetch": {
|
|
54
82
|
"types": "./dist/fetch.d.ts",
|
|
55
83
|
"default": "./dist/fetch.js"
|
|
@@ -58,6 +86,10 @@
|
|
|
58
86
|
"types": "./dist/plugins/exact.d.ts",
|
|
59
87
|
"default": "./dist/plugins/exact.js"
|
|
60
88
|
},
|
|
89
|
+
"./policy": {
|
|
90
|
+
"types": "./dist/policy.d.ts",
|
|
91
|
+
"default": "./dist/policy.js"
|
|
92
|
+
},
|
|
61
93
|
"./cash": {
|
|
62
94
|
"types": "./dist/plugins/cash.d.ts",
|
|
63
95
|
"default": "./dist/plugins/cash.js"
|
|
@@ -110,6 +142,50 @@
|
|
|
110
142
|
"types": "./dist/plugins/prisma.d.ts",
|
|
111
143
|
"default": "./dist/plugins/prisma.js"
|
|
112
144
|
},
|
|
145
|
+
"./drizzle/pg": {
|
|
146
|
+
"types": "./dist/drizzle/pg.d.ts",
|
|
147
|
+
"default": "./dist/drizzle/pg.js"
|
|
148
|
+
},
|
|
149
|
+
"./drizzle/mysql": {
|
|
150
|
+
"types": "./dist/drizzle/mysql.d.ts",
|
|
151
|
+
"default": "./dist/drizzle/mysql.js"
|
|
152
|
+
},
|
|
153
|
+
"./drizzle/sqlite": {
|
|
154
|
+
"types": "./dist/drizzle/sqlite.d.ts",
|
|
155
|
+
"default": "./dist/drizzle/sqlite.js"
|
|
156
|
+
},
|
|
157
|
+
"./zod": {
|
|
158
|
+
"types": "./dist/zod.d.ts",
|
|
159
|
+
"default": "./dist/zod.js"
|
|
160
|
+
},
|
|
161
|
+
"./valibot": {
|
|
162
|
+
"types": "./dist/valibot.d.ts",
|
|
163
|
+
"default": "./dist/valibot.js"
|
|
164
|
+
},
|
|
165
|
+
"./pg": {
|
|
166
|
+
"types": "./dist/pg.d.ts",
|
|
167
|
+
"default": "./dist/pg.js"
|
|
168
|
+
},
|
|
169
|
+
"./testing": {
|
|
170
|
+
"types": "./dist/testing/index.d.ts",
|
|
171
|
+
"default": "./dist/testing/index.js"
|
|
172
|
+
},
|
|
173
|
+
"./testing/vitest": {
|
|
174
|
+
"types": "./dist/testing/vitest.d.ts",
|
|
175
|
+
"default": "./dist/testing/vitest.js"
|
|
176
|
+
},
|
|
177
|
+
"./testing/jest": {
|
|
178
|
+
"types": "./dist/testing/jest.d.ts",
|
|
179
|
+
"default": "./dist/testing/jest.js"
|
|
180
|
+
},
|
|
181
|
+
"./testing/arbitraries": {
|
|
182
|
+
"types": "./dist/testing/arbitraries.d.ts",
|
|
183
|
+
"default": "./dist/testing/arbitraries.js"
|
|
184
|
+
},
|
|
185
|
+
"./kysely": {
|
|
186
|
+
"types": "./dist/kysely.d.ts",
|
|
187
|
+
"default": "./dist/kysely.js"
|
|
188
|
+
},
|
|
113
189
|
"./all": {
|
|
114
190
|
"types": "./dist/plugins/all.d.ts",
|
|
115
191
|
"default": "./dist/plugins/all.js"
|
|
@@ -117,8 +193,8 @@
|
|
|
117
193
|
"./package.json": "./package.json"
|
|
118
194
|
},
|
|
119
195
|
"scripts": {
|
|
120
|
-
"build": "tsc -p tsconfig.json",
|
|
121
|
-
"typecheck": "tsc -p tsconfig.test.json && tsc -p test/core-only/tsconfig.json && tsc -p test/browser/tsconfig.json",
|
|
196
|
+
"build": "tsc -p tsconfig.json && tsc -p tsconfig.drizzle.json && tsc -p tsconfig.kysely.json && tsc -p tsconfig.peers.json",
|
|
197
|
+
"typecheck": "tsc -p tsconfig.test.json && tsc -p tsconfig.test-drizzle.json && tsc -p test/core-only/tsconfig.json && tsc -p test/browser/tsconfig.json && tsc -p test/jest-types/tsconfig.json",
|
|
122
198
|
"test": "vitest run",
|
|
123
199
|
"test:deep": "DUCAT_DEEP=1 vitest run",
|
|
124
200
|
"compare": "pnpm --dir compare battery && pnpm --dir compare tables",
|
|
@@ -149,22 +225,57 @@
|
|
|
149
225
|
"@prisma/client": "^6.19.3",
|
|
150
226
|
"@stryker-mutator/core": "10.1.1",
|
|
151
227
|
"@stryker-mutator/vitest-runner": "10.1.1",
|
|
228
|
+
"@types/better-sqlite3": "9.6.0",
|
|
152
229
|
"@types/big.js": "^7.0.0",
|
|
153
230
|
"@types/node": "^26.6.6",
|
|
154
231
|
"@types/pg": "8.23.1",
|
|
232
|
+
"better-sqlite3": "13.0.3",
|
|
155
233
|
"big.js": "^7.0.1",
|
|
156
234
|
"currency.js": "^2.0.4",
|
|
157
235
|
"decimal.js": "^10.6.0",
|
|
158
236
|
"dinero.js": "^2.0.2",
|
|
237
|
+
"drizzle-orm": "0.45.4",
|
|
159
238
|
"esbuild": "^0.28.2",
|
|
160
239
|
"fast-check": "^4.10.2",
|
|
240
|
+
"kysely": "0.29.8",
|
|
161
241
|
"mysql2": "3.24.6",
|
|
162
242
|
"oxfmt": "0.77.0",
|
|
163
243
|
"oxlint": "1.92.0",
|
|
164
244
|
"pg": "8.23.1",
|
|
245
|
+
"pg-cursor": "2.22.1",
|
|
165
246
|
"ts-money": "^0.4.8",
|
|
166
247
|
"typescript": "^5.9.3",
|
|
167
|
-
"
|
|
248
|
+
"valibot": "1.5.0",
|
|
249
|
+
"vitest": "^4.1.12",
|
|
250
|
+
"zod": "4.6.7"
|
|
251
|
+
},
|
|
252
|
+
"peerDependencies": {
|
|
253
|
+
"drizzle-orm": ">=0.45.0 <1",
|
|
254
|
+
"fast-check": "^4.0.0",
|
|
255
|
+
"kysely": ">=0.28.0 <1",
|
|
256
|
+
"valibot": "^1.0.0",
|
|
257
|
+
"vitest": ">=3.2.0 <5",
|
|
258
|
+
"zod": "^4.0.0"
|
|
259
|
+
},
|
|
260
|
+
"peerDependenciesMeta": {
|
|
261
|
+
"drizzle-orm": {
|
|
262
|
+
"optional": true
|
|
263
|
+
},
|
|
264
|
+
"fast-check": {
|
|
265
|
+
"optional": true
|
|
266
|
+
},
|
|
267
|
+
"kysely": {
|
|
268
|
+
"optional": true
|
|
269
|
+
},
|
|
270
|
+
"valibot": {
|
|
271
|
+
"optional": true
|
|
272
|
+
},
|
|
273
|
+
"vitest": {
|
|
274
|
+
"optional": true
|
|
275
|
+
},
|
|
276
|
+
"zod": {
|
|
277
|
+
"optional": true
|
|
278
|
+
}
|
|
168
279
|
},
|
|
169
280
|
"engines": {
|
|
170
281
|
"node": ">=24"
|
package/src/adyen-fx.ts
CHANGED
|
@@ -55,9 +55,20 @@ function offsetMinutes(zone: string): number | undefined {
|
|
|
55
55
|
return numeric[1] === '-' ? -total : total;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
// Building an Intl.DateTimeFormat is far slower than using one, and a report has thousands of rows
|
|
59
|
+
// in one zone, so keep one formatter per zone. The bound stops a stream of distinct zone names
|
|
60
|
+
// (case variants are accepted by Intl) from growing the cache without limit.
|
|
61
|
+
const MAX_CACHED_FORMATTERS = 32;
|
|
62
|
+
const formatters = new Map<string, Intl.DateTimeFormat>();
|
|
63
|
+
|
|
64
|
+
/** The cached wall-clock formatter for an IANA time zone. */
|
|
65
|
+
function wallClockFormatter(timeZone: string): Intl.DateTimeFormat {
|
|
66
|
+
let formatter = formatters.get(timeZone);
|
|
67
|
+
if (formatter !== undefined) {
|
|
68
|
+
return formatter;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
formatter = new Intl.DateTimeFormat('en-US', {
|
|
61
72
|
timeZone,
|
|
62
73
|
hourCycle: 'h23',
|
|
63
74
|
year: 'numeric',
|
|
@@ -66,7 +77,17 @@ function ianaOffsetMinutes(timeZone: string, utcMs: number): number {
|
|
|
66
77
|
hour: 'numeric',
|
|
67
78
|
minute: 'numeric',
|
|
68
79
|
second: 'numeric',
|
|
69
|
-
})
|
|
80
|
+
});
|
|
81
|
+
if (formatters.size >= MAX_CACHED_FORMATTERS) {
|
|
82
|
+
formatters.clear();
|
|
83
|
+
}
|
|
84
|
+
formatters.set(timeZone, formatter);
|
|
85
|
+
return formatter;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** The offset of an IANA time zone at a UTC instant, in minutes. */
|
|
89
|
+
function ianaOffsetMinutes(timeZone: string, utcMs: number): number {
|
|
90
|
+
const parts = wallClockFormatter(timeZone).formatToParts(new Date(utcMs));
|
|
70
91
|
const field = (type: string): number => Number(parts.find((part) => part.type === type)!.value);
|
|
71
92
|
const wallClockAsUtc = Date.UTC(
|
|
72
93
|
field('year'),
|
package/src/boc.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// `@ducatjs/money/convert/boc`: an offline parser for the Bank of Canada's daily exchange rates
|
|
2
|
+
// (the Valet API). No I/O: fetch the JSON yourself, or use fetchBankOfCanada from
|
|
3
|
+
// @ducatjs/money/convert/fetch. Rates are kept exactly as published.
|
|
4
|
+
import { quotedTable } from './history.js';
|
|
5
|
+
import type { RateTable } from './provider.js';
|
|
6
|
+
import { addDayRate, isCalendarDay, newestFirst, readRateCell } from './rate-text.js';
|
|
7
|
+
|
|
8
|
+
const SERIES = /^FX([A-Z]{3})CAD$/;
|
|
9
|
+
const ZERO = /^0+(?:\.0+)?$/;
|
|
10
|
+
|
|
11
|
+
// The Bank publishes "once each business day by 16:30 (ET)". One formatter for the zone, built on
|
|
12
|
+
// first use, gives the Toronto offset on any day, summer time included.
|
|
13
|
+
let torontoFormatter: Intl.DateTimeFormat | undefined;
|
|
14
|
+
|
|
15
|
+
/** 16:30 in Toronto on `day`, as a UTC instant. */
|
|
16
|
+
function publishedBy(day: string): string {
|
|
17
|
+
torontoFormatter ??= new Intl.DateTimeFormat('en-US', {
|
|
18
|
+
timeZone: 'America/Toronto',
|
|
19
|
+
timeZoneName: 'shortOffset',
|
|
20
|
+
});
|
|
21
|
+
// Noon UTC is 07:00 or 08:00 in Toronto, after any clock change that day (they happen at 02:00).
|
|
22
|
+
const noon = new Date(`${day}T12:00:00Z`);
|
|
23
|
+
const zone = torontoFormatter.formatToParts(noon).find((part) => part.type === 'timeZoneName');
|
|
24
|
+
const offset = /^GMT([+-]\d+)$/.exec(zone?.value ?? '');
|
|
25
|
+
if (offset === null) {
|
|
26
|
+
throw new RangeError(`Can't tell Toronto's UTC offset on ${day} (${zone?.value})`);
|
|
27
|
+
}
|
|
28
|
+
const utcMs = Date.parse(`${day}T16:30:00Z`) - Number(offset[1]) * 3_600_000;
|
|
29
|
+
return new Date(utcMs).toISOString();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function notValet(why: string): never {
|
|
33
|
+
throw new SyntaxError(`Not a Bank of Canada Valet daily FX file: ${why}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Options for parseBankOfCanadaJson. */
|
|
37
|
+
export interface BankOfCanadaOptions {
|
|
38
|
+
/**
|
|
39
|
+
* When each day's rates were published, or false for none. Default: 16:30 Toronto time that day,
|
|
40
|
+
* when the Bank says it publishes them.
|
|
41
|
+
*/
|
|
42
|
+
readonly availableAt?: false | ((day: string) => string | Date);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Parses the Bank of Canada's daily exchange rates from the Valet API's JSON (the
|
|
47
|
+
* `FX_RATES_DAILY` group, or single `FX…CAD` series) into one CAD-based table per business day,
|
|
48
|
+
* newest first. The Bank quotes CAD per unit of each currency (FXUSDCAD 1.3748), so each table
|
|
49
|
+
* holds the exact inverse, CAD → currency, and keeps the published quote: `rate.inverse()` prints
|
|
50
|
+
* '1.3748' again. Rates have `source: 'BoC'`, `type: 'average'` (an average of a day's quotes, not
|
|
51
|
+
* a market rate) and `availableAt` 16:30 Toronto time, when the Bank says it publishes them (a late
|
|
52
|
+
* rate can come later; pass `availableAt` to change it). Valet leaves a series out of a day
|
|
53
|
+
* without a value, so a series listed in `seriesDetail` but absent on a day, an empty value or a
|
|
54
|
+
* null one, is in that day's `missing`. Anything but daily `FX…CAD` series (monthly or annual
|
|
55
|
+
* groups, other data) throws SyntaxError, as do two different values for one series on one day.
|
|
56
|
+
*
|
|
57
|
+
* Precision: the Bank quotes four decimals, up to six for small rates, so a small rate has only
|
|
58
|
+
* about four significant digits (JPY 0.008760, KRW 0.000929, and IDR 0.000082 with two). Its
|
|
59
|
+
* inverse is exact, but only as precise as that. For such currencies, prefer a source that quotes
|
|
60
|
+
* them the other way round.
|
|
61
|
+
*
|
|
62
|
+
* const tables = parseBankOfCanadaJson(await (await fetch(url)).text());
|
|
63
|
+
* tables[0].rate('CAD', 'USD')?.inverse().toString(); // '1.3748'
|
|
64
|
+
*/
|
|
65
|
+
export function parseBankOfCanadaJson(json: string, options?: BankOfCanadaOptions): RateTable[] {
|
|
66
|
+
const parsed = JSON.parse(json) as {
|
|
67
|
+
observations?: unknown;
|
|
68
|
+
seriesDetail?: Record<string, unknown>;
|
|
69
|
+
} | null;
|
|
70
|
+
const observations = parsed?.observations;
|
|
71
|
+
if (!Array.isArray(observations)) {
|
|
72
|
+
notValet('no observations');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// The series the file says it has; each must be a daily FX…CAD series.
|
|
76
|
+
const expected = new Set<string>();
|
|
77
|
+
for (const series of Object.keys(parsed?.seriesDetail ?? {})) {
|
|
78
|
+
if (!SERIES.test(series)) {
|
|
79
|
+
notValet(`series ${series} isn't a daily FX…CAD rate`);
|
|
80
|
+
}
|
|
81
|
+
expected.add(series);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const days = new Map<string, Record<string, string | null>>();
|
|
85
|
+
for (const observation of observations as readonly Record<string, unknown>[]) {
|
|
86
|
+
const day = observation?.['d'];
|
|
87
|
+
if (typeof day !== 'string' || !isCalendarDay(day)) {
|
|
88
|
+
notValet(`bad date ${JSON.stringify(day)}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const [series, cell] of Object.entries(observation)) {
|
|
92
|
+
if (series === 'd') {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const currency = SERIES.exec(series)?.[1];
|
|
96
|
+
if (currency === undefined) {
|
|
97
|
+
notValet(`series ${series} isn't a daily FX…CAD rate`);
|
|
98
|
+
}
|
|
99
|
+
const where = `${series} on ${day}`;
|
|
100
|
+
const value = (cell as { v?: unknown } | null)?.v;
|
|
101
|
+
if (value !== null && typeof value !== 'string') {
|
|
102
|
+
throw new SyntaxError(`Malformed Valet value for ${where}`);
|
|
103
|
+
}
|
|
104
|
+
const rate = value === null ? null : readRateCell(value, where);
|
|
105
|
+
if (rate !== null && ZERO.test(rate)) {
|
|
106
|
+
throw new SyntaxError(`A zero rate for ${where}`);
|
|
107
|
+
}
|
|
108
|
+
addDayRate(days, day, currency, rate);
|
|
109
|
+
}
|
|
110
|
+
// Valet leaves out a series without a value that day.
|
|
111
|
+
for (const series of expected) {
|
|
112
|
+
const currency = SERIES.exec(series)![1]!;
|
|
113
|
+
if (days.get(day)?.[currency] === undefined) {
|
|
114
|
+
addDayRate(days, day, currency, null);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const tables: RateTable[] = [];
|
|
120
|
+
for (const [day, rates] of days) {
|
|
121
|
+
if (!Object.values(rates).some((rate) => rate !== null)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
let availableAt: string | Date | undefined;
|
|
125
|
+
if (options?.availableAt === undefined) {
|
|
126
|
+
availableAt = publishedBy(day);
|
|
127
|
+
} else if (options.availableAt !== false) {
|
|
128
|
+
availableAt = options.availableAt(day);
|
|
129
|
+
}
|
|
130
|
+
const info = { base: 'CAD', inverted: true, source: 'BoC', type: 'average', asOf: day };
|
|
131
|
+
tables.push(
|
|
132
|
+
quotedTable({ ...info, ...(availableAt === undefined ? {} : { availableAt }), rates }),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return newestFirst(tables);
|
|
136
|
+
}
|