@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.
Files changed (253) hide show
  1. package/NOTICE +73 -0
  2. package/README.md +479 -62
  3. package/data/cash-rounding.json +123 -2
  4. package/data/cldr-cash.json +101 -0
  5. package/data/historic.json +78 -0
  6. package/data/iso4217-list-three.xml +1185 -0
  7. package/dist/adyen-fx.d.ts.map +1 -1
  8. package/dist/adyen-fx.js +22 -4
  9. package/dist/adyen-fx.js.map +1 -1
  10. package/dist/boc.d.ts +31 -0
  11. package/dist/boc.d.ts.map +1 -0
  12. package/dist/boc.js +114 -0
  13. package/dist/boc.js.map +1 -0
  14. package/dist/boe.d.ts +33 -0
  15. package/dist/boe.d.ts.map +1 -0
  16. package/dist/boe.js +114 -0
  17. package/dist/boe.js.map +1 -0
  18. package/dist/cash.d.ts +30 -1
  19. package/dist/cash.d.ts.map +1 -1
  20. package/dist/cash.js +50 -2
  21. package/dist/cash.js.map +1 -1
  22. package/dist/convert.d.ts +10 -9
  23. package/dist/convert.d.ts.map +1 -1
  24. package/dist/convert.js +13 -3
  25. package/dist/convert.js.map +1 -1
  26. package/dist/drizzle/mysql.d.ts +105 -0
  27. package/dist/drizzle/mysql.d.ts.map +1 -0
  28. package/dist/drizzle/mysql.js +60 -0
  29. package/dist/drizzle/mysql.js.map +1 -0
  30. package/dist/drizzle/pg.d.ts +103 -0
  31. package/dist/drizzle/pg.d.ts.map +1 -0
  32. package/dist/drizzle/pg.js +60 -0
  33. package/dist/drizzle/pg.js.map +1 -0
  34. package/dist/drizzle/sqlite.d.ts +102 -0
  35. package/dist/drizzle/sqlite.d.ts.map +1 -0
  36. package/dist/drizzle/sqlite.js +59 -0
  37. package/dist/drizzle/sqlite.js.map +1 -0
  38. package/dist/ecb.d.ts +37 -2
  39. package/dist/ecb.d.ts.map +1 -1
  40. package/dist/ecb.js +148 -10
  41. package/dist/ecb.js.map +1 -1
  42. package/dist/fed.d.ts +35 -0
  43. package/dist/fed.d.ts.map +1 -0
  44. package/dist/fed.js +134 -0
  45. package/dist/fed.js.map +1 -0
  46. package/dist/fetch.d.ts +45 -0
  47. package/dist/fetch.d.ts.map +1 -1
  48. package/dist/fetch.js +167 -24
  49. package/dist/fetch.js.map +1 -1
  50. package/dist/fn.d.ts +8 -1
  51. package/dist/fn.d.ts.map +1 -1
  52. package/dist/fn.js +8 -1
  53. package/dist/fn.js.map +1 -1
  54. package/dist/generated/cash.d.ts +2 -0
  55. package/dist/generated/cash.d.ts.map +1 -1
  56. package/dist/generated/cash.js +101 -0
  57. package/dist/generated/cash.js.map +1 -1
  58. package/dist/generated/historic.d.ts +337 -0
  59. package/dist/generated/historic.d.ts.map +1 -0
  60. package/dist/generated/historic.js +66 -0
  61. package/dist/generated/historic.js.map +1 -0
  62. package/dist/historic.d.ts +40 -0
  63. package/dist/historic.d.ts.map +1 -0
  64. package/dist/historic.js +43 -0
  65. package/dist/historic.js.map +1 -0
  66. package/dist/history.d.ts +96 -0
  67. package/dist/history.d.ts.map +1 -0
  68. package/dist/history.js +213 -0
  69. package/dist/history.js.map +1 -0
  70. package/dist/hmrc.d.ts +28 -0
  71. package/dist/hmrc.d.ts.map +1 -0
  72. package/dist/hmrc.js +108 -0
  73. package/dist/hmrc.js.map +1 -0
  74. package/dist/index.d.ts +1 -1
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +1 -1
  77. package/dist/index.js.map +1 -1
  78. package/dist/kysely.d.ts +120 -0
  79. package/dist/kysely.d.ts.map +1 -0
  80. package/dist/kysely.js +309 -0
  81. package/dist/kysely.js.map +1 -0
  82. package/dist/money.d.ts +93 -9
  83. package/dist/money.d.ts.map +1 -1
  84. package/dist/money.js +135 -9
  85. package/dist/money.js.map +1 -1
  86. package/dist/parse.d.ts +45 -1
  87. package/dist/parse.d.ts.map +1 -1
  88. package/dist/parse.js +290 -3
  89. package/dist/parse.js.map +1 -1
  90. package/dist/pg.d.ts +100 -0
  91. package/dist/pg.d.ts.map +1 -0
  92. package/dist/pg.js +343 -0
  93. package/dist/pg.js.map +1 -0
  94. package/dist/plugins/adyen.d.ts +1 -1
  95. package/dist/plugins/adyen.d.ts.map +1 -1
  96. package/dist/plugins/adyen.js.map +1 -1
  97. package/dist/plugins/all.d.ts +8 -1
  98. package/dist/plugins/all.d.ts.map +1 -1
  99. package/dist/plugins/all.js +8 -1
  100. package/dist/plugins/all.js.map +1 -1
  101. package/dist/plugins/allocate.d.ts +1 -1
  102. package/dist/plugins/allocate.d.ts.map +1 -1
  103. package/dist/plugins/allocate.js.map +1 -1
  104. package/dist/plugins/braintree.d.ts +1 -1
  105. package/dist/plugins/braintree.d.ts.map +1 -1
  106. package/dist/plugins/braintree.js.map +1 -1
  107. package/dist/plugins/cash.d.ts +1 -1
  108. package/dist/plugins/cash.d.ts.map +1 -1
  109. package/dist/plugins/cash.js.map +1 -1
  110. package/dist/plugins/checkout.d.ts +1 -1
  111. package/dist/plugins/checkout.d.ts.map +1 -1
  112. package/dist/plugins/checkout.js.map +1 -1
  113. package/dist/plugins/convert.d.ts +5 -5
  114. package/dist/plugins/convert.d.ts.map +1 -1
  115. package/dist/plugins/convert.js.map +1 -1
  116. package/dist/plugins/exact.d.ts +1 -1
  117. package/dist/plugins/exact.d.ts.map +1 -1
  118. package/dist/plugins/exact.js.map +1 -1
  119. package/dist/plugins/fixed.d.ts +1 -1
  120. package/dist/plugins/fixed.d.ts.map +1 -1
  121. package/dist/plugins/fixed.js.map +1 -1
  122. package/dist/plugins/format.d.ts +1 -1
  123. package/dist/plugins/format.d.ts.map +1 -1
  124. package/dist/plugins/format.js.map +1 -1
  125. package/dist/plugins/klarna.d.ts +1 -1
  126. package/dist/plugins/klarna.d.ts.map +1 -1
  127. package/dist/plugins/klarna.js.map +1 -1
  128. package/dist/plugins/paypal.d.ts +1 -1
  129. package/dist/plugins/paypal.d.ts.map +1 -1
  130. package/dist/plugins/paypal.js +0 -4
  131. package/dist/plugins/paypal.js.map +1 -1
  132. package/dist/plugins/prisma.d.ts +1 -1
  133. package/dist/plugins/prisma.d.ts.map +1 -1
  134. package/dist/plugins/prisma.js +0 -4
  135. package/dist/plugins/prisma.js.map +1 -1
  136. package/dist/plugins/stripe.d.ts +1 -1
  137. package/dist/plugins/stripe.d.ts.map +1 -1
  138. package/dist/plugins/stripe.js +0 -4
  139. package/dist/plugins/stripe.js.map +1 -1
  140. package/dist/plugins/tax.d.ts +6 -6
  141. package/dist/plugins/tax.d.ts.map +1 -1
  142. package/dist/plugins/tax.js.map +1 -1
  143. package/dist/policy.d.ts +34 -0
  144. package/dist/policy.d.ts.map +1 -0
  145. package/dist/policy.js +90 -0
  146. package/dist/policy.js.map +1 -0
  147. package/dist/prisma.d.ts +25 -14
  148. package/dist/prisma.d.ts.map +1 -1
  149. package/dist/prisma.js +29 -19
  150. package/dist/prisma.js.map +1 -1
  151. package/dist/provider.d.ts +21 -7
  152. package/dist/provider.d.ts.map +1 -1
  153. package/dist/provider.js +51 -11
  154. package/dist/provider.js.map +1 -1
  155. package/dist/rate-text.d.ts +38 -0
  156. package/dist/rate-text.d.ts.map +1 -0
  157. package/dist/rate-text.js +143 -0
  158. package/dist/rate-text.js.map +1 -0
  159. package/dist/rate.d.ts +61 -5
  160. package/dist/rate.d.ts.map +1 -1
  161. package/dist/rate.js +133 -33
  162. package/dist/rate.js.map +1 -1
  163. package/dist/rounding.js +1 -1
  164. package/dist/rounding.js.map +1 -1
  165. package/dist/schema.d.ts +43 -0
  166. package/dist/schema.d.ts.map +1 -0
  167. package/dist/schema.js +77 -0
  168. package/dist/schema.js.map +1 -0
  169. package/dist/sql.d.ts +54 -0
  170. package/dist/sql.d.ts.map +1 -0
  171. package/dist/sql.js +131 -0
  172. package/dist/sql.js.map +1 -0
  173. package/dist/tax.d.ts +13 -9
  174. package/dist/tax.d.ts.map +1 -1
  175. package/dist/tax.js +20 -4
  176. package/dist/tax.js.map +1 -1
  177. package/dist/testing/arbitraries.d.ts +43 -0
  178. package/dist/testing/arbitraries.d.ts.map +1 -0
  179. package/dist/testing/arbitraries.js +98 -0
  180. package/dist/testing/arbitraries.js.map +1 -0
  181. package/dist/testing/index.d.ts +67 -0
  182. package/dist/testing/index.d.ts.map +1 -0
  183. package/dist/testing/index.js +159 -0
  184. package/dist/testing/index.js.map +1 -0
  185. package/dist/testing/jest.d.ts +2 -0
  186. package/dist/testing/jest.d.ts.map +1 -0
  187. package/dist/testing/jest.js +15 -0
  188. package/dist/testing/jest.js.map +1 -0
  189. package/dist/testing/vitest.d.ts +7 -0
  190. package/dist/testing/vitest.d.ts.map +1 -0
  191. package/dist/testing/vitest.js +12 -0
  192. package/dist/testing/vitest.js.map +1 -0
  193. package/dist/valibot.d.ts +33 -0
  194. package/dist/valibot.d.ts.map +1 -0
  195. package/dist/valibot.js +61 -0
  196. package/dist/valibot.js.map +1 -0
  197. package/dist/zod.d.ts +36 -0
  198. package/dist/zod.d.ts.map +1 -0
  199. package/dist/zod.js +58 -0
  200. package/dist/zod.js.map +1 -0
  201. package/package.json +116 -5
  202. package/src/adyen-fx.ts +25 -4
  203. package/src/boc.ts +136 -0
  204. package/src/boe.ts +131 -0
  205. package/src/cash.ts +70 -2
  206. package/src/convert.ts +33 -15
  207. package/src/drizzle/mysql.ts +78 -0
  208. package/src/drizzle/pg.ts +78 -0
  209. package/src/drizzle/sqlite.ts +70 -0
  210. package/src/ecb.ts +179 -13
  211. package/src/fed.ts +146 -0
  212. package/src/fetch.ts +207 -28
  213. package/src/fn.ts +14 -0
  214. package/src/generated/cash.ts +103 -0
  215. package/src/generated/historic.ts +67 -0
  216. package/src/historic.ts +77 -0
  217. package/src/history.ts +333 -0
  218. package/src/hmrc.ts +125 -0
  219. package/src/index.ts +4 -0
  220. package/src/kysely.ts +588 -0
  221. package/src/money.ts +210 -12
  222. package/src/parse.ts +371 -4
  223. package/src/pg.ts +410 -0
  224. package/src/plugins/adyen.ts +3 -2
  225. package/src/plugins/all.ts +10 -0
  226. package/src/plugins/allocate.ts +3 -2
  227. package/src/plugins/braintree.ts +3 -2
  228. package/src/plugins/cash.ts +3 -2
  229. package/src/plugins/checkout.ts +3 -2
  230. package/src/plugins/convert.ts +6 -6
  231. package/src/plugins/exact.ts +3 -2
  232. package/src/plugins/fixed.ts +3 -2
  233. package/src/plugins/format.ts +3 -2
  234. package/src/plugins/klarna.ts +3 -2
  235. package/src/plugins/paypal.ts +3 -2
  236. package/src/plugins/prisma.ts +3 -2
  237. package/src/plugins/stripe.ts +3 -2
  238. package/src/plugins/tax.ts +11 -11
  239. package/src/policy.ts +124 -0
  240. package/src/prisma.ts +91 -10
  241. package/src/provider.ts +81 -16
  242. package/src/rate-text.ts +151 -0
  243. package/src/rate.ts +205 -36
  244. package/src/rounding.ts +1 -1
  245. package/src/schema.ts +119 -0
  246. package/src/sql.ts +178 -0
  247. package/src/tax.ts +40 -9
  248. package/src/testing/arbitraries.ts +134 -0
  249. package/src/testing/index.ts +247 -0
  250. package/src/testing/jest.ts +18 -0
  251. package/src/testing/vitest.ts +18 -0
  252. package/src/valibot.ts +87 -0
  253. 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,2 @@
1
+ export * from './index.js';
2
+ //# sourceMappingURL=jest.d.ts.map
@@ -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,7 @@
1
+ import { type MoneyMatchers } from './index.js';
2
+ export * from './index.js';
3
+ declare module 'vitest' {
4
+ interface Matchers<T = any> extends MoneyMatchers<T> {
5
+ }
6
+ }
7
+ //# sourceMappingURL=vitest.d.ts.map
@@ -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"}
@@ -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
@@ -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.0",
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
- "vitest": "^4.1.12"
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
- /** The offset of an IANA time zone at a UTC instant, in minutes. */
59
- function ianaOffsetMinutes(timeZone: string, utcMs: number): number {
60
- const parts = new Intl.DateTimeFormat('en-US', {
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
- }).formatToParts(new Date(utcMs));
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
+ }