rune-lab 0.4.0 → 0.4.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 (433) hide show
  1. package/.gitignore +12 -0
  2. package/README.md +3 -3
  3. package/deno.json +50 -0
  4. package/justfile +5 -0
  5. package/package.json +2 -79
  6. package/scripts/build_pkg.ts +51 -0
  7. package/scripts/ci.just +26 -0
  8. package/scripts/deploy.just +21 -0
  9. package/scripts/dev.just +4 -0
  10. package/scripts/inject.just +72 -0
  11. package/src/RuneProvider.svelte +105 -0
  12. package/src/i18n/message-resolver.test.ts +103 -0
  13. package/src/i18n/message-resolver.ts +89 -0
  14. package/src/i18n/project.inlang/settings.json +26 -0
  15. package/src/i18n/translations/ar.json +89 -0
  16. package/src/i18n/translations/de.json +89 -0
  17. package/src/i18n/translations/en.json +89 -0
  18. package/src/i18n/translations/es.json +89 -0
  19. package/src/i18n/translations/fr.json +89 -0
  20. package/src/i18n/translations/hi.json +89 -0
  21. package/src/i18n/translations/it.json +89 -0
  22. package/src/i18n/translations/ja.json +89 -0
  23. package/src/i18n/translations/ko.json +89 -0
  24. package/src/i18n/translations/pt.json +89 -0
  25. package/src/i18n/translations/ru.json +89 -0
  26. package/src/i18n/translations/vi.json +89 -0
  27. package/src/i18n/translations/zh.json +89 -0
  28. package/src/kernel/deno.json +5 -0
  29. package/src/kernel/src/actions/portal.ts +41 -0
  30. package/src/kernel/src/actions/shortcut-listener.ts +50 -0
  31. package/src/kernel/src/context/app.svelte.ts +98 -0
  32. package/src/kernel/src/context/context.ts +31 -0
  33. package/src/kernel/src/context/stores.svelte.ts +96 -0
  34. package/src/kernel/src/context/types.ts +110 -0
  35. package/src/kernel/src/context/useRuneLab.ts +38 -0
  36. package/src/kernel/src/mod.ts +13 -0
  37. package/src/kernel/src/persistence/createConfigStore.svelte.ts +120 -0
  38. package/src/kernel/src/persistence/drivers.test.ts +95 -0
  39. package/src/kernel/src/persistence/drivers.ts +77 -0
  40. package/src/kernel/src/persistence/provider.test.ts +58 -0
  41. package/{dist/state/persistence/provider.js → src/kernel/src/persistence/provider.ts} +29 -14
  42. package/src/kernel/src/persistence/types.ts +19 -0
  43. package/src/kernel/src/persistence/usePersistence.ts +9 -0
  44. package/src/kernel/src/registry/mod.ts +221 -0
  45. package/src/kernel/src/registry/registry.test.ts +162 -0
  46. package/src/kernel/src/tokens/props.ts +94 -0
  47. package/src/mod.ts +10 -0
  48. package/src/runes/layout/deno.json +5 -0
  49. package/src/runes/layout/src/APP_CONFIGURATIONS.ts +56 -0
  50. package/{dist/ui/features/config → src/runes/layout/src}/AppSettingSelector.svelte +1 -1
  51. package/{dist/ui/layout → src/runes/layout/src}/ConnectedNavigationPanel.svelte +1 -1
  52. package/{dist/ui/layout → src/runes/layout/src}/ConnectedWorkspaceStrip.svelte +1 -1
  53. package/src/runes/layout/src/Icon.svelte +7 -0
  54. package/{dist/ui/features/config → src/runes/layout/src}/LanguageSelector.svelte +7 -5
  55. package/{dist/ui/layout → src/runes/layout/src}/NavigationPanel.svelte +1 -4
  56. package/{dist/ui/features/config → src/runes/layout/src}/ResourceSelector.svelte +3 -5
  57. package/{dist/ui/features/config → src/runes/layout/src}/ThemeSelector.svelte +2 -2
  58. package/{dist/ui/layout → src/runes/layout/src}/WorkspaceLayout.svelte +6 -4
  59. package/{dist/ui/layout → src/runes/layout/src}/WorkspaceStrip.svelte +1 -1
  60. package/src/runes/layout/src/connection-factory.ts +95 -0
  61. package/src/runes/layout/src/language.svelte.ts +44 -0
  62. package/src/runes/layout/src/mod.ts +71 -0
  63. package/src/runes/layout/src/store.svelte.ts +142 -0
  64. package/src/runes/layout/src/theme.svelte.ts +73 -0
  65. package/src/runes/layout/src/types.ts +11 -0
  66. package/src/runes/palettes/deno.json +8 -0
  67. package/{dist/ui/features/command-palette → src/runes/palettes/src/commands}/CommandPalette.svelte +4 -4
  68. package/src/runes/palettes/src/commands/mod.ts +2 -0
  69. package/src/runes/palettes/src/commands/store.svelte.ts +80 -0
  70. package/src/runes/palettes/src/mod.ts +51 -0
  71. package/{dist/ui/components → src/runes/palettes/src/notifications}/Toaster.svelte +1 -2
  72. package/src/runes/palettes/src/notifications/bridge.ts +56 -0
  73. package/src/runes/palettes/src/notifications/mod.ts +4 -0
  74. package/src/runes/palettes/src/notifications/store.svelte.ts +58 -0
  75. package/{dist/ui/features → src/runes/palettes/src}/shortcuts/ShortcutPalette.svelte +4 -4
  76. package/src/runes/palettes/src/shortcuts/mod.ts +4 -0
  77. package/src/runes/palettes/src/shortcuts/store.svelte.ts +85 -0
  78. package/src/runes/palettes/src/shortcuts/types.ts +4 -0
  79. package/src/runes/palettes/src/shortcuts/useShortcuts.ts +85 -0
  80. package/src/runes/plugins/money/deno.json +8 -0
  81. package/{dist/ui/features/config → src/runes/plugins/money/src}/CurrencySelector.svelte +2 -2
  82. package/{dist/ui/components/money → src/runes/plugins/money/src}/MoneyDisplay.svelte +2 -2
  83. package/{dist/ui/components/money → src/runes/plugins/money/src}/MoneyInput.svelte +4 -8
  84. package/src/runes/plugins/money/src/currency.svelte.ts +95 -0
  85. package/src/runes/plugins/money/src/currency.test.ts +40 -0
  86. package/src/runes/plugins/money/src/exchange-rate.svelte.ts +176 -0
  87. package/src/runes/plugins/money/src/exchange-rate.test.ts +95 -0
  88. package/src/runes/plugins/money/src/mod.ts +79 -0
  89. package/src/runes/plugins/money/src/money-primitive.test.ts +217 -0
  90. package/src/runes/plugins/money/src/money-primitive.ts +220 -0
  91. package/src/runes/plugins/money/src/money.test.ts +183 -0
  92. package/src/runes/plugins/money/src/money.ts +382 -0
  93. package/src/runes/plugins/money/src/strategies.test.ts +143 -0
  94. package/{dist/core/exchange-rate/strategies.js → src/runes/plugins/money/src/strategies.ts} +45 -22
  95. package/src/runes/plugins/money/src/types.ts +27 -0
  96. package/src/runes/plugins/money/src/useMoney.ts +261 -0
  97. package/src/runes/plugins/money/src/useMoneyFilter.ts +132 -0
  98. package/tsconfig.json +41 -0
  99. package/vite.config.ts +44 -0
  100. package/dist/core/design-tokens/props.d.ts +0 -52
  101. package/dist/core/design-tokens/props.d.ts.map +0 -1
  102. package/dist/core/design-tokens/props.js +0 -34
  103. package/dist/core/exchange-rate/strategies.d.ts +0 -52
  104. package/dist/core/exchange-rate/strategies.d.ts.map +0 -1
  105. package/dist/core/index.d.ts +0 -9
  106. package/dist/core/index.d.ts.map +0 -1
  107. package/dist/core/index.js +0 -8
  108. package/dist/core/internal/message-resolver.d.ts +0 -42
  109. package/dist/core/internal/message-resolver.d.ts.map +0 -1
  110. package/dist/core/internal/message-resolver.js +0 -47
  111. package/dist/core/layout/types.d.ts +0 -60
  112. package/dist/core/layout/types.d.ts.map +0 -1
  113. package/dist/core/layout/types.js +0 -4
  114. package/dist/core/money/index.d.ts +0 -2
  115. package/dist/core/money/index.d.ts.map +0 -1
  116. package/dist/core/money/index.js +0 -2
  117. package/dist/core/money/money-primitive.d.ts +0 -101
  118. package/dist/core/money/money-primitive.d.ts.map +0 -1
  119. package/dist/core/money/money-primitive.js +0 -161
  120. package/dist/core/money/money.d.ts +0 -129
  121. package/dist/core/money/money.d.ts.map +0 -1
  122. package/dist/core/money/money.js +0 -250
  123. package/dist/core/persistence/types.d.ts +0 -18
  124. package/dist/core/persistence/types.d.ts.map +0 -1
  125. package/dist/core/persistence/types.js +0 -2
  126. package/dist/core/shortcuts/types.d.ts +0 -60
  127. package/dist/core/shortcuts/types.d.ts.map +0 -1
  128. package/dist/core/shortcuts/types.js +0 -4
  129. package/dist/index.d.ts +0 -6
  130. package/dist/index.js +0 -7
  131. package/dist/state/api.svelte.d.ts +0 -26
  132. package/dist/state/api.svelte.js +0 -65
  133. package/dist/state/app.svelte.d.ts +0 -48
  134. package/dist/state/app.svelte.js +0 -82
  135. package/dist/state/auth/index.d.ts +0 -2
  136. package/dist/state/auth/index.js +0 -2
  137. package/dist/state/auth/session.svelte.d.ts +0 -40
  138. package/dist/state/auth/session.svelte.js +0 -59
  139. package/dist/state/auth/types.d.ts +0 -30
  140. package/dist/state/auth/types.js +0 -3
  141. package/dist/state/cart.svelte.d.ts +0 -64
  142. package/dist/state/cart.svelte.js +0 -122
  143. package/dist/state/commands.svelte.d.ts +0 -46
  144. package/dist/state/commands.svelte.js +0 -62
  145. package/dist/state/composables/useMoney.d.ts +0 -31
  146. package/dist/state/composables/useMoney.js +0 -126
  147. package/dist/state/composables/useMoneyFilter.d.ts +0 -20
  148. package/dist/state/composables/useMoneyFilter.js +0 -81
  149. package/dist/state/composables/usePersistence.d.ts +0 -2
  150. package/dist/state/composables/usePersistence.js +0 -5
  151. package/dist/state/composables/useRuneLab.d.ts +0 -19
  152. package/dist/state/composables/useRuneLab.js +0 -30
  153. package/dist/state/composables/useShortcuts.d.ts +0 -33
  154. package/dist/state/composables/useShortcuts.js +0 -75
  155. package/dist/state/context.d.ts +0 -15
  156. package/dist/state/context.js +0 -16
  157. package/dist/state/createConfigStore.svelte.d.ts +0 -28
  158. package/dist/state/createConfigStore.svelte.js +0 -72
  159. package/dist/state/currency.svelte.d.ts +0 -32
  160. package/dist/state/currency.svelte.js +0 -96
  161. package/dist/state/currency.test.d.ts +0 -1
  162. package/dist/state/currency.test.js +0 -35
  163. package/dist/state/exchange-rate.svelte.d.ts +0 -43
  164. package/dist/state/exchange-rate.svelte.js +0 -145
  165. package/dist/state/exchange-rate.test.d.ts +0 -1
  166. package/dist/state/exchange-rate.test.js +0 -75
  167. package/dist/state/index.d.ts +0 -26
  168. package/dist/state/index.js +0 -32
  169. package/dist/state/language.svelte.d.ts +0 -57
  170. package/dist/state/language.svelte.js +0 -43
  171. package/dist/state/layout.svelte.d.ts +0 -49
  172. package/dist/state/layout.svelte.js +0 -108
  173. package/dist/state/persistence/drivers.d.ts +0 -12
  174. package/dist/state/persistence/drivers.js +0 -75
  175. package/dist/state/persistence/drivers.test.d.ts +0 -1
  176. package/dist/state/persistence/drivers.test.js +0 -79
  177. package/dist/state/persistence/provider.d.ts +0 -23
  178. package/dist/state/persistence/provider.test.d.ts +0 -1
  179. package/dist/state/persistence/provider.test.js +0 -51
  180. package/dist/state/registry/index.d.ts +0 -44
  181. package/dist/state/registry/index.js +0 -58
  182. package/dist/state/registry/registry.test.d.ts +0 -1
  183. package/dist/state/registry/registry.test.js +0 -112
  184. package/dist/state/registry/types.d.ts +0 -20
  185. package/dist/state/registry/types.js +0 -3
  186. package/dist/state/shortcuts.svelte.d.ts +0 -121
  187. package/dist/state/shortcuts.svelte.js +0 -222
  188. package/dist/state/theme.svelte.d.ts +0 -15
  189. package/dist/state/theme.svelte.js +0 -92
  190. package/dist/state/toast-bridge.d.ts +0 -29
  191. package/dist/state/toast-bridge.js +0 -43
  192. package/dist/state/toast.svelte.d.ts +0 -27
  193. package/dist/state/toast.svelte.js +0 -43
  194. package/dist/ui/actions/portal.d.ts +0 -7
  195. package/dist/ui/actions/portal.js +0 -32
  196. package/dist/ui/components/ApiMonitor.svelte +0 -162
  197. package/dist/ui/components/ApiMonitor.svelte.d.ts +0 -3
  198. package/dist/ui/components/Icon.svelte +0 -108
  199. package/dist/ui/components/Icon.svelte.d.ts +0 -14
  200. package/dist/ui/components/Kyntharil.svelte +0 -48
  201. package/dist/ui/components/Kyntharil.svelte.d.ts +0 -6
  202. package/dist/ui/components/RuneProvider.svelte +0 -218
  203. package/dist/ui/components/RuneProvider.svelte.d.ts +0 -49
  204. package/dist/ui/components/Toaster.svelte.d.ts +0 -18
  205. package/dist/ui/components/money/MoneyDisplay.svelte.d.ts +0 -33
  206. package/dist/ui/components/money/MoneyDisplay.svelte.test.d.ts +0 -1
  207. package/dist/ui/components/money/MoneyDisplay.svelte.test.js +0 -117
  208. package/dist/ui/components/money/MoneyInput.svelte.d.ts +0 -34
  209. package/dist/ui/components/money/index.d.ts +0 -2
  210. package/dist/ui/components/money/index.js +0 -3
  211. package/dist/ui/components/user/UserAvatar.svelte +0 -66
  212. package/dist/ui/components/user/UserAvatar.svelte.d.ts +0 -13
  213. package/dist/ui/components/user/UserProfile.svelte +0 -79
  214. package/dist/ui/components/user/UserProfile.svelte.d.ts +0 -17
  215. package/dist/ui/components/user/index.d.ts +0 -2
  216. package/dist/ui/components/user/index.js +0 -3
  217. package/dist/ui/features/command-palette/CommandPalette.svelte.d.ts +0 -6
  218. package/dist/ui/features/config/APP_CONFIGURATIONS.d.ts +0 -29
  219. package/dist/ui/features/config/APP_CONFIGURATIONS.js +0 -38
  220. package/dist/ui/features/config/AppSettingSelector.svelte.d.ts +0 -13
  221. package/dist/ui/features/config/CurrencySelector.svelte.d.ts +0 -8
  222. package/dist/ui/features/config/LanguageSelector.svelte.d.ts +0 -8
  223. package/dist/ui/features/config/ResourceSelector.svelte.d.ts +0 -25
  224. package/dist/ui/features/config/ThemeSelector.svelte.d.ts +0 -8
  225. package/dist/ui/features/notifications/NotificationBell.svelte.d.ts +0 -11
  226. package/dist/ui/features/notifications/index.d.ts +0 -1
  227. package/dist/ui/features/notifications/index.js +0 -2
  228. package/dist/ui/features/shortcuts/ShortcutBinder.svelte +0 -17
  229. package/dist/ui/features/shortcuts/ShortcutBinder.svelte.d.ts +0 -7
  230. package/dist/ui/features/shortcuts/ShortcutPalette.svelte.d.ts +0 -6
  231. package/dist/ui/index.d.ts +0 -30
  232. package/dist/ui/index.js +0 -46
  233. package/dist/ui/layout/ConnectedNavigationPanel.svelte.d.ts +0 -10
  234. package/dist/ui/layout/ConnectedWorkspaceStrip.svelte.d.ts +0 -9
  235. package/dist/ui/layout/ContentArea.svelte.d.ts +0 -8
  236. package/dist/ui/layout/DetailPanel.svelte.d.ts +0 -7
  237. package/dist/ui/layout/NavigationPanel.svelte.d.ts +0 -14
  238. package/dist/ui/layout/WorkspaceLayout.svelte.d.ts +0 -32
  239. package/dist/ui/layout/WorkspaceStrip.svelte.d.ts +0 -11
  240. package/dist/ui/layout/connection-factory.d.ts +0 -50
  241. package/dist/ui/layout/connection-factory.js +0 -58
  242. package/dist/ui/layout/index.d.ts +0 -7
  243. package/dist/ui/layout/index.js +0 -7
  244. package/dist/ui/paraglide/README.md +0 -147
  245. package/dist/ui/paraglide/messages/_index.d.ts +0 -87
  246. package/dist/ui/paraglide/messages/_index.js +0 -88
  247. package/dist/ui/paraglide/messages/abyss.d.ts +0 -16
  248. package/dist/ui/paraglide/messages/abyss.js +0 -84
  249. package/dist/ui/paraglide/messages/acid.d.ts +0 -16
  250. package/dist/ui/paraglide/messages/acid.js +0 -84
  251. package/dist/ui/paraglide/messages/active_toasts.d.ts +0 -16
  252. package/dist/ui/paraglide/messages/active_toasts.js +0 -84
  253. package/dist/ui/paraglide/messages/aed3.d.ts +0 -17
  254. package/dist/ui/paraglide/messages/aed3.js +0 -85
  255. package/dist/ui/paraglide/messages/all_currencies.d.ts +0 -16
  256. package/dist/ui/paraglide/messages/all_currencies.js +0 -84
  257. package/dist/ui/paraglide/messages/all_languages.d.ts +0 -16
  258. package/dist/ui/paraglide/messages/all_languages.js +0 -84
  259. package/dist/ui/paraglide/messages/all_themes.d.ts +0 -16
  260. package/dist/ui/paraglide/messages/all_themes.js +0 -84
  261. package/dist/ui/paraglide/messages/api_status.d.ts +0 -16
  262. package/dist/ui/paraglide/messages/api_status.js +0 -84
  263. package/dist/ui/paraglide/messages/app_info.d.ts +0 -16
  264. package/dist/ui/paraglide/messages/app_info.js +0 -84
  265. package/dist/ui/paraglide/messages/appearance.d.ts +0 -16
  266. package/dist/ui/paraglide/messages/appearance.js +0 -84
  267. package/dist/ui/paraglide/messages/aqua.d.ts +0 -16
  268. package/dist/ui/paraglide/messages/aqua.js +0 -84
  269. package/dist/ui/paraglide/messages/ar.d.ts +0 -16
  270. package/dist/ui/paraglide/messages/ar.js +0 -84
  271. package/dist/ui/paraglide/messages/autumn.d.ts +0 -16
  272. package/dist/ui/paraglide/messages/autumn.js +0 -84
  273. package/dist/ui/paraglide/messages/black.d.ts +0 -16
  274. package/dist/ui/paraglide/messages/black.js +0 -84
  275. package/dist/ui/paraglide/messages/brl3.d.ts +0 -17
  276. package/dist/ui/paraglide/messages/brl3.js +0 -85
  277. package/dist/ui/paraglide/messages/bumblebee.d.ts +0 -16
  278. package/dist/ui/paraglide/messages/bumblebee.js +0 -84
  279. package/dist/ui/paraglide/messages/business.d.ts +0 -16
  280. package/dist/ui/paraglide/messages/business.js +0 -84
  281. package/dist/ui/paraglide/messages/cad3.d.ts +0 -17
  282. package/dist/ui/paraglide/messages/cad3.js +0 -85
  283. package/dist/ui/paraglide/messages/caramellatte.d.ts +0 -16
  284. package/dist/ui/paraglide/messages/caramellatte.js +0 -84
  285. package/dist/ui/paraglide/messages/cmyk.d.ts +0 -16
  286. package/dist/ui/paraglide/messages/cmyk.js +0 -84
  287. package/dist/ui/paraglide/messages/cny3.d.ts +0 -17
  288. package/dist/ui/paraglide/messages/cny3.js +0 -85
  289. package/dist/ui/paraglide/messages/coffee.d.ts +0 -16
  290. package/dist/ui/paraglide/messages/coffee.js +0 -84
  291. package/dist/ui/paraglide/messages/commands_label.d.ts +0 -16
  292. package/dist/ui/paraglide/messages/commands_label.js +0 -84
  293. package/dist/ui/paraglide/messages/corporate.d.ts +0 -16
  294. package/dist/ui/paraglide/messages/corporate.js +0 -84
  295. package/dist/ui/paraglide/messages/cupcake.d.ts +0 -16
  296. package/dist/ui/paraglide/messages/cupcake.js +0 -84
  297. package/dist/ui/paraglide/messages/currency.d.ts +0 -16
  298. package/dist/ui/paraglide/messages/currency.js +0 -84
  299. package/dist/ui/paraglide/messages/current_currency.d.ts +0 -16
  300. package/dist/ui/paraglide/messages/current_currency.js +0 -84
  301. package/dist/ui/paraglide/messages/current_language.d.ts +0 -16
  302. package/dist/ui/paraglide/messages/current_language.js +0 -84
  303. package/dist/ui/paraglide/messages/current_theme.d.ts +0 -16
  304. package/dist/ui/paraglide/messages/current_theme.js +0 -84
  305. package/dist/ui/paraglide/messages/currently_in_queue.d.ts +0 -16
  306. package/dist/ui/paraglide/messages/currently_in_queue.js +0 -84
  307. package/dist/ui/paraglide/messages/cyberpunk.d.ts +0 -16
  308. package/dist/ui/paraglide/messages/cyberpunk.js +0 -84
  309. package/dist/ui/paraglide/messages/dark.d.ts +0 -16
  310. package/dist/ui/paraglide/messages/dark.js +0 -84
  311. package/dist/ui/paraglide/messages/de.d.ts +0 -16
  312. package/dist/ui/paraglide/messages/de.js +0 -84
  313. package/dist/ui/paraglide/messages/dim.d.ts +0 -16
  314. package/dist/ui/paraglide/messages/dim.js +0 -84
  315. package/dist/ui/paraglide/messages/dracula.d.ts +0 -16
  316. package/dist/ui/paraglide/messages/dracula.js +0 -84
  317. package/dist/ui/paraglide/messages/emerald.d.ts +0 -16
  318. package/dist/ui/paraglide/messages/emerald.js +0 -84
  319. package/dist/ui/paraglide/messages/en.d.ts +0 -16
  320. package/dist/ui/paraglide/messages/en.js +0 -84
  321. package/dist/ui/paraglide/messages/es.d.ts +0 -16
  322. package/dist/ui/paraglide/messages/es.js +0 -84
  323. package/dist/ui/paraglide/messages/eur3.d.ts +0 -17
  324. package/dist/ui/paraglide/messages/eur3.js +0 -85
  325. package/dist/ui/paraglide/messages/extended_controls.d.ts +0 -16
  326. package/dist/ui/paraglide/messages/extended_controls.js +0 -84
  327. package/dist/ui/paraglide/messages/fantasy.d.ts +0 -16
  328. package/dist/ui/paraglide/messages/fantasy.js +0 -84
  329. package/dist/ui/paraglide/messages/forest.d.ts +0 -16
  330. package/dist/ui/paraglide/messages/forest.js +0 -84
  331. package/dist/ui/paraglide/messages/fr.d.ts +0 -16
  332. package/dist/ui/paraglide/messages/fr.js +0 -84
  333. package/dist/ui/paraglide/messages/garden.d.ts +0 -16
  334. package/dist/ui/paraglide/messages/garden.js +0 -84
  335. package/dist/ui/paraglide/messages/gbp3.d.ts +0 -17
  336. package/dist/ui/paraglide/messages/gbp3.js +0 -85
  337. package/dist/ui/paraglide/messages/halloween.d.ts +0 -16
  338. package/dist/ui/paraglide/messages/halloween.js +0 -84
  339. package/dist/ui/paraglide/messages/hello_world.d.ts +0 -18
  340. package/dist/ui/paraglide/messages/hello_world.js +0 -84
  341. package/dist/ui/paraglide/messages/hi.d.ts +0 -16
  342. package/dist/ui/paraglide/messages/hi.js +0 -84
  343. package/dist/ui/paraglide/messages/inr3.d.ts +0 -17
  344. package/dist/ui/paraglide/messages/inr3.js +0 -85
  345. package/dist/ui/paraglide/messages/it.d.ts +0 -16
  346. package/dist/ui/paraglide/messages/it.js +0 -84
  347. package/dist/ui/paraglide/messages/ja.d.ts +0 -16
  348. package/dist/ui/paraglide/messages/ja.js +0 -84
  349. package/dist/ui/paraglide/messages/jpy3.d.ts +0 -17
  350. package/dist/ui/paraglide/messages/jpy3.js +0 -85
  351. package/dist/ui/paraglide/messages/ko.d.ts +0 -16
  352. package/dist/ui/paraglide/messages/ko.js +0 -84
  353. package/dist/ui/paraglide/messages/krw3.d.ts +0 -17
  354. package/dist/ui/paraglide/messages/krw3.js +0 -85
  355. package/dist/ui/paraglide/messages/languages.d.ts +0 -16
  356. package/dist/ui/paraglide/messages/languages.js +0 -84
  357. package/dist/ui/paraglide/messages/lemonade.d.ts +0 -16
  358. package/dist/ui/paraglide/messages/lemonade.js +0 -84
  359. package/dist/ui/paraglide/messages/light.d.ts +0 -16
  360. package/dist/ui/paraglide/messages/light.js +0 -84
  361. package/dist/ui/paraglide/messages/live_store_dashboard.d.ts +0 -16
  362. package/dist/ui/paraglide/messages/live_store_dashboard.js +0 -84
  363. package/dist/ui/paraglide/messages/localization.d.ts +0 -16
  364. package/dist/ui/paraglide/messages/localization.js +0 -84
  365. package/dist/ui/paraglide/messages/lofi.d.ts +0 -16
  366. package/dist/ui/paraglide/messages/lofi.js +0 -84
  367. package/dist/ui/paraglide/messages/luxury.d.ts +0 -16
  368. package/dist/ui/paraglide/messages/luxury.js +0 -84
  369. package/dist/ui/paraglide/messages/mxn3.d.ts +0 -17
  370. package/dist/ui/paraglide/messages/mxn3.js +0 -85
  371. package/dist/ui/paraglide/messages/name_label.d.ts +0 -16
  372. package/dist/ui/paraglide/messages/name_label.js +0 -84
  373. package/dist/ui/paraglide/messages/night.d.ts +0 -16
  374. package/dist/ui/paraglide/messages/night.js +0 -84
  375. package/dist/ui/paraglide/messages/nord.d.ts +0 -16
  376. package/dist/ui/paraglide/messages/nord.js +0 -84
  377. package/dist/ui/paraglide/messages/pastel.d.ts +0 -16
  378. package/dist/ui/paraglide/messages/pastel.js +0 -84
  379. package/dist/ui/paraglide/messages/pt.d.ts +0 -16
  380. package/dist/ui/paraglide/messages/pt.js +0 -84
  381. package/dist/ui/paraglide/messages/real_time_monitor_desc.d.ts +0 -16
  382. package/dist/ui/paraglide/messages/real_time_monitor_desc.js +0 -84
  383. package/dist/ui/paraglide/messages/registered_in_registry.d.ts +0 -16
  384. package/dist/ui/paraglide/messages/registered_in_registry.js +0 -84
  385. package/dist/ui/paraglide/messages/retro.d.ts +0 -16
  386. package/dist/ui/paraglide/messages/retro.js +0 -84
  387. package/dist/ui/paraglide/messages/ru.d.ts +0 -16
  388. package/dist/ui/paraglide/messages/ru.js +0 -84
  389. package/dist/ui/paraglide/messages/silk.d.ts +0 -16
  390. package/dist/ui/paraglide/messages/silk.js +0 -84
  391. package/dist/ui/paraglide/messages/state_label.d.ts +0 -16
  392. package/dist/ui/paraglide/messages/state_label.js +0 -84
  393. package/dist/ui/paraglide/messages/sunset.d.ts +0 -16
  394. package/dist/ui/paraglide/messages/sunset.js +0 -84
  395. package/dist/ui/paraglide/messages/synthwave.d.ts +0 -16
  396. package/dist/ui/paraglide/messages/synthwave.js +0 -84
  397. package/dist/ui/paraglide/messages/system.d.ts +0 -16
  398. package/dist/ui/paraglide/messages/system.js +0 -84
  399. package/dist/ui/paraglide/messages/theme.d.ts +0 -16
  400. package/dist/ui/paraglide/messages/theme.js +0 -84
  401. package/dist/ui/paraglide/messages/themes.d.ts +0 -16
  402. package/dist/ui/paraglide/messages/themes.js +0 -84
  403. package/dist/ui/paraglide/messages/url_label.d.ts +0 -16
  404. package/dist/ui/paraglide/messages/url_label.js +0 -84
  405. package/dist/ui/paraglide/messages/usd3.d.ts +0 -17
  406. package/dist/ui/paraglide/messages/usd3.js +0 -85
  407. package/dist/ui/paraglide/messages/valentine.d.ts +0 -16
  408. package/dist/ui/paraglide/messages/valentine.js +0 -84
  409. package/dist/ui/paraglide/messages/version_label.d.ts +0 -16
  410. package/dist/ui/paraglide/messages/version_label.js +0 -84
  411. package/dist/ui/paraglide/messages/vi.d.ts +0 -16
  412. package/dist/ui/paraglide/messages/vi.js +0 -84
  413. package/dist/ui/paraglide/messages/winter.d.ts +0 -16
  414. package/dist/ui/paraglide/messages/winter.js +0 -84
  415. package/dist/ui/paraglide/messages/wireframe.d.ts +0 -16
  416. package/dist/ui/paraglide/messages/wireframe.js +0 -84
  417. package/dist/ui/paraglide/messages/zh.d.ts +0 -16
  418. package/dist/ui/paraglide/messages/zh.js +0 -84
  419. package/dist/ui/paraglide/messages.d.ts +0 -2
  420. package/dist/ui/paraglide/messages.js +0 -4
  421. package/dist/ui/paraglide/registry.d.ts +0 -21
  422. package/dist/ui/paraglide/registry.js +0 -31
  423. package/dist/ui/paraglide/runtime.d.ts +0 -730
  424. package/dist/ui/paraglide/runtime.js +0 -1812
  425. package/dist/ui/paraglide/server.d.ts +0 -92
  426. package/dist/ui/paraglide/server.js +0 -239
  427. package/dist/ui/primitives/DatePicker.svelte +0 -257
  428. package/dist/ui/primitives/DatePicker.svelte.d.ts +0 -17
  429. package/dist/ui/primitives/index.d.ts +0 -1
  430. package/dist/ui/primitives/index.js +0 -3
  431. /package/{dist/ui/layout → src/runes/layout/src}/ContentArea.svelte +0 -0
  432. /package/{dist/ui/layout → src/runes/layout/src}/DetailPanel.svelte +0 -0
  433. /package/{dist/ui/features → src/runes/palettes/src}/notifications/NotificationBell.svelte +0 -0
@@ -0,0 +1,382 @@
1
+ // sdk/core/src/money/money.ts
2
+ // Framework-agnostic money utilities using Dinero.js v2
3
+ // Consumers should never import Dinero directly — these helpers encapsulate it.
4
+
5
+ import {
6
+ add as dineroAdd,
7
+ AED,
8
+ BRL,
9
+ CAD,
10
+ CNY,
11
+ convert as dineroConvert,
12
+ type Dinero,
13
+ dinero,
14
+ type DineroCurrency,
15
+ type DineroSnapshot,
16
+ EUR,
17
+ GBP,
18
+ INR,
19
+ JPY,
20
+ KRW,
21
+ multiply as dineroMultiply,
22
+ MXN,
23
+ subtract as dineroSubtract,
24
+ toDecimal,
25
+ // ISO 4217 currency definitions
26
+ toSnapshot,
27
+ transformScale as dineroTransformScale,
28
+ USD,
29
+ } from "dinero.js";
30
+
31
+ /**
32
+ * Map of ISO 4217 currency codes to Dinero currency objects
33
+ */
34
+ export const CURRENCY_MAP: Record<string, DineroCurrency<number>> = {
35
+ USD,
36
+ EUR,
37
+ MXN,
38
+ JPY,
39
+ KRW,
40
+ CNY,
41
+ AED,
42
+ GBP,
43
+ CAD,
44
+ BRL,
45
+ INR,
46
+ };
47
+
48
+ /**
49
+ * Derived type of all built-in ISO 4217 currency codes.
50
+ * Enables IDE autocomplete while allowing any string for dynamic currencies.
51
+ */
52
+ export type ISO4217Code = keyof typeof CURRENCY_MAP;
53
+
54
+ /**
55
+ * Scaled integer rate for Dinero.js conversion.
56
+ * Avoids floating-point errors by using integer amounts with a scale.
57
+ */
58
+ export type ScaledRate = { amount: number; scale: number };
59
+
60
+ /**
61
+ * Map of currency codes to their exchange rates relative to a base currency.
62
+ * Rates can be plain numbers (integers) or ScaledRate objects.
63
+ */
64
+ export type RateMap = Record<string, ScaledRate | number>;
65
+
66
+ /**
67
+ * Converts a human-readable float rate (e.g., 17.23) into a ScaledRate.
68
+ * Defaults to 4 decimal places of precision if not specified.
69
+ */
70
+ export function scaledRate(float: number, precision: number = 4): ScaledRate {
71
+ const factor = Math.pow(10, precision);
72
+ return {
73
+ amount: Math.round(float * factor),
74
+ scale: precision,
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Register a new currency in CURRENCY_MAP atomically.
80
+ * Ensures the core registry and any store-level registries stay in sync.
81
+ */
82
+ export function registerCurrency(
83
+ code: string,
84
+ currency: DineroCurrency<number>,
85
+ ): void {
86
+ CURRENCY_MAP[code] = currency;
87
+ }
88
+
89
+ /**
90
+ * Normalizes an unknown input into a valid finite number.
91
+ * Handles null, undefined, bigints, and SurrealDB Decimal objects via toString().
92
+ */
93
+ function toNumber(amount: unknown): number {
94
+ if (amount === null || amount === undefined) return 0;
95
+ if (typeof amount === "number") return Number.isFinite(amount) ? amount : 0;
96
+ if (typeof amount === "bigint") return Number(amount);
97
+
98
+ // Handle SurrealDB Decimal (which has a toString method) or other objects
99
+ if (typeof amount === "object") {
100
+ try {
101
+ // SurrealDB Decimal.toString() returns a numeric string
102
+ const str = String(amount);
103
+ const parsed = parseFloat(str);
104
+ return Number.isFinite(parsed) ? parsed : 0;
105
+ } catch {
106
+ return 0;
107
+ }
108
+ }
109
+
110
+ const coerced = Number(amount);
111
+ return Number.isFinite(coerced) ? coerced : 0;
112
+ }
113
+
114
+ /**
115
+ * Normalizes an unknown input into a valid integer for Dinero.js.
116
+ * Exported so consumers can apply the same defensive coercion.
117
+ */
118
+ export function safeAmount(amount: unknown): number {
119
+ return Math.round(toNumber(amount));
120
+ }
121
+
122
+ /**
123
+ * Converts a major-unit amount (e.g., pesos) to a minor-unit integer (e.g., centavos).
124
+ * Uses the currency's exponent from CURRENCY_MAP.
125
+ */
126
+ export function toMinorUnit(
127
+ amount: unknown,
128
+ currencyCode: ISO4217Code | string,
129
+ ): number {
130
+ const currency = CURRENCY_MAP[currencyCode];
131
+ if (!currency) {
132
+ throw new Error(
133
+ `Unknown currency code: ${currencyCode}. Register it first via registerCurrency().`,
134
+ );
135
+ }
136
+ const base = Array.isArray(currency.base) ? currency.base[0] : currency.base;
137
+ const factor = Math.pow(Number(base), Number(currency.exponent));
138
+ return Math.round(toNumber(amount) * factor);
139
+ }
140
+
141
+ /**
142
+ * Create a Dinero monetary value from an amount.
143
+ * @param amount - Amount (normalized internally via safeAmount)
144
+ * @param currencyCode - ISO 4217 currency code (e.g., "USD")
145
+ */
146
+ export function createMoney(
147
+ amount: unknown,
148
+ currencyCode: ISO4217Code | string,
149
+ ): Dinero<number> {
150
+ const currency = CURRENCY_MAP[currencyCode];
151
+ if (!currency) {
152
+ throw new Error(
153
+ `Unknown currency code: ${currencyCode}. Register it first via registerCurrency().`,
154
+ );
155
+ }
156
+ return dinero({ amount: safeAmount(amount), currency });
157
+ }
158
+
159
+ /**
160
+ * Format a Dinero value as a locale-aware string
161
+ * @param money - Dinero monetary value
162
+ * @param locale - BCP 47 locale string (e.g., "en-US", "es-MX")
163
+ * @param currencyCode - ISO 4217 code for Intl.NumberFormat (e.g., "USD")
164
+ */
165
+ export function formatMoney(
166
+ money: Dinero<number>,
167
+ locale: string = "en-US",
168
+ currencyCode?: string,
169
+ ): string {
170
+ return toDecimal(money, ({ value, currency }) => {
171
+ const code = currencyCode ??
172
+ Object.entries(CURRENCY_MAP).find(([, c]) => c.code === currency.code)
173
+ ?.[0] ??
174
+ currency.code;
175
+
176
+ return new Intl.NumberFormat(locale, {
177
+ style: "currency",
178
+ currency: code,
179
+ minimumFractionDigits: currency.exponent,
180
+ maximumFractionDigits: currency.exponent,
181
+ }).format(Number(value));
182
+ });
183
+ }
184
+
185
+ /**
186
+ * Format a raw amount as a locale-aware currency string.
187
+ * Convenience wrapper around createMoney + formatMoney.
188
+ */
189
+ export function formatAmount(
190
+ amount: unknown,
191
+ currencyCode: ISO4217Code | string,
192
+ locale: string = "en-US",
193
+ ): string {
194
+ const money = createMoney(amount, currencyCode);
195
+ return formatMoney(money, locale, currencyCode);
196
+ }
197
+
198
+ /**
199
+ * Add two monetary values (must be same currency)
200
+ */
201
+ export function addMoney(a: Dinero<number>, b: Dinero<number>): Dinero<number> {
202
+ return dineroAdd(a, b);
203
+ }
204
+
205
+ /**
206
+ * Subtract two monetary values (must be same currency)
207
+ */
208
+ export function subtractMoney(
209
+ a: Dinero<number>,
210
+ b: Dinero<number>,
211
+ ): Dinero<number> {
212
+ return dineroSubtract(a, b);
213
+ }
214
+
215
+ /**
216
+ * Multiply a monetary value by a factor
217
+ */
218
+ export function multiplyMoney(
219
+ money: Dinero<number>,
220
+ factor: number,
221
+ ): Dinero<number> {
222
+ return dineroMultiply(money, factor);
223
+ }
224
+
225
+ /**
226
+ * Converts a Dinero object to another currency.
227
+ * Both currencies must share the same base (base 10 for all standard ISO currencies).
228
+ */
229
+ export function convertMoney(
230
+ money: Dinero<number>,
231
+ toCurrencyCode: string,
232
+ rates: RateMap,
233
+ ): Dinero<number> {
234
+ const targetCurrency = CURRENCY_MAP[toCurrencyCode];
235
+ if (!targetCurrency) {
236
+ throw new Error(
237
+ `Unknown target currency: ${toCurrencyCode}. Register it first via registerCurrency().`,
238
+ );
239
+ }
240
+
241
+ const rate = rates[toCurrencyCode];
242
+ if (rate === undefined) {
243
+ throw new Error(`Missing exchange rate for currency: ${toCurrencyCode}`);
244
+ }
245
+
246
+ try {
247
+ return dineroConvert(money, targetCurrency, { [toCurrencyCode]: rate });
248
+ } catch (err) {
249
+ if (err instanceof Error && err.message.includes("base")) {
250
+ throw new Error(
251
+ `Cannot convert between currencies with different bases. Ensure both are base 10.`,
252
+ );
253
+ }
254
+ throw err;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Converts a raw minor-unit amount between currencies.
260
+ * Returns the original amount if from and to currencies are the same.
261
+ */
262
+ export function convertAmount(
263
+ amount: number,
264
+ fromCode: string,
265
+ toCode: string,
266
+ rates: RateMap,
267
+ ): number {
268
+ if (fromCode === toCode) return amount;
269
+ const targetCurrency = CURRENCY_MAP[toCode];
270
+ if (!targetCurrency) {
271
+ throw new Error(`Unknown target currency: ${toCode}`);
272
+ }
273
+
274
+ const sourceMoney = createMoney(amount, fromCode);
275
+ const convertedMoney = convertMoney(sourceMoney, toCode, rates);
276
+
277
+ // Normalize back to the target currency's standard exponent
278
+ const targetMoney = dineroTransformScale(
279
+ convertedMoney,
280
+ targetCurrency.exponent,
281
+ );
282
+ const snapshot = toSnapshot(targetMoney);
283
+
284
+ return snapshot.amount;
285
+ }
286
+
287
+ /**
288
+ * Converts Dinero object to a Stripe-compatible payload.
289
+ */
290
+ export function toStripeMoney(money: Dinero<number>): {
291
+ amount: number;
292
+ currency: string;
293
+ } {
294
+ const snapshot = toSnapshot(money);
295
+ return {
296
+ amount: snapshot.amount,
297
+ currency: snapshot.currency.code.toLowerCase(),
298
+ };
299
+ }
300
+
301
+ /**
302
+ * Converts Dinero object to a PayPal-compatible payload.
303
+ */
304
+ export function toPaypalMoney(money: Dinero<number>): {
305
+ value: string;
306
+ currency_code: string;
307
+ } {
308
+ const value = toDecimal(money);
309
+ const snapshot = toSnapshot(money);
310
+ return {
311
+ value,
312
+ currency_code: snapshot.currency.code,
313
+ };
314
+ }
315
+
316
+ /**
317
+ * Converts Dinero object to an Adyen-compatible payload.
318
+ */
319
+ export function toAdyenMoney(money: Dinero<number>): {
320
+ value: number;
321
+ currency: string;
322
+ } {
323
+ const snapshot = toSnapshot(money);
324
+ return {
325
+ value: snapshot.amount,
326
+ currency: snapshot.currency.code.toUpperCase(),
327
+ };
328
+ }
329
+
330
+ /**
331
+ * Converts Dinero object to a Square-compatible payload (uses BigInt).
332
+ */
333
+ export function toSquareMoney(money: Dinero<number>): {
334
+ amount: bigint;
335
+ currency: string;
336
+ } {
337
+ const snapshot = toSnapshot(money);
338
+ return {
339
+ amount: BigInt(snapshot.amount),
340
+ currency: snapshot.currency.code,
341
+ };
342
+ }
343
+
344
+ /**
345
+ * Serializes a Dinero object into a plain object snapshot.
346
+ */
347
+ export function toMoneySnapshot(money: Dinero<number>): {
348
+ amount: number;
349
+ currency: string;
350
+ scale: number;
351
+ } {
352
+ const snapshot = toSnapshot(money);
353
+ return {
354
+ amount: snapshot.amount,
355
+ currency: snapshot.currency.code,
356
+ scale: snapshot.scale,
357
+ };
358
+ }
359
+
360
+ /**
361
+ * Restores a Dinero object from a snapshot.
362
+ */
363
+ export function fromMoneySnapshot(snapshot: {
364
+ amount: number;
365
+ currency: string;
366
+ scale?: number;
367
+ }): Dinero<number> {
368
+ const currency = CURRENCY_MAP[snapshot.currency];
369
+ if (!currency) {
370
+ throw new Error(
371
+ `Unknown currency: ${snapshot.currency}. Register it first.`,
372
+ );
373
+ }
374
+ return dinero({
375
+ amount: snapshot.amount,
376
+ currency,
377
+ scale: snapshot.scale ?? currency.exponent,
378
+ });
379
+ }
380
+
381
+ // Re-export types
382
+ export type { Dinero, DineroCurrency, DineroSnapshot };
@@ -0,0 +1,143 @@
1
+ import { describe, expect, it } from "vite-plus/test";
2
+ import {
3
+ CONVERSION_STRATEGIES,
4
+ directConversion,
5
+ inverseConversion,
6
+ resolveRate,
7
+ triangularConversion,
8
+ } from "./strategies.ts";
9
+
10
+ describe("ConversionStrategies", () => {
11
+ describe("resolveRate", () => {
12
+ it("should pass through plain numbers", () => {
13
+ expect(resolveRate(20)).toBe(20);
14
+ });
15
+
16
+ it("should resolve ScaledRate to float", () => {
17
+ expect(resolveRate({ amount: 172300, scale: 4 })).toBeCloseTo(17.23);
18
+ });
19
+
20
+ it("should handle zero scale", () => {
21
+ expect(resolveRate({ amount: 1199, scale: 0 })).toBe(1199);
22
+ });
23
+ });
24
+
25
+ describe("directConversion", () => {
26
+ it("should multiply amount by rate", () => {
27
+ // 100 USD cents * 20 = 2000 MXN centavos
28
+ expect(directConversion(100, 20)).toBe(2000);
29
+ });
30
+
31
+ it("should handle fractional rates", () => {
32
+ // 100 * 0.91 = 91
33
+ expect(directConversion(100, 0.91)).toBe(91);
34
+ });
35
+
36
+ it("should handle zero amount", () => {
37
+ expect(directConversion(0, 20)).toBe(0);
38
+ });
39
+
40
+ it("should handle negative amounts", () => {
41
+ expect(directConversion(-100, 20)).toBe(-2000);
42
+ });
43
+
44
+ it("should handle large numbers", () => {
45
+ expect(directConversion(1_000_000, 20)).toBe(20_000_000);
46
+ });
47
+
48
+ it("should round to nearest integer", () => {
49
+ // 100 * 17.23 = 1723
50
+ expect(directConversion(100, 17.23)).toBe(1723);
51
+ });
52
+ });
53
+
54
+ describe("inverseConversion", () => {
55
+ it("should divide amount by rate", () => {
56
+ // 2000 MXN / 20 = 100 USD
57
+ expect(inverseConversion(2000, 20)).toBe(100);
58
+ });
59
+
60
+ it("should handle fractional results (rounded)", () => {
61
+ // 100 / 3 ≈ 33.33 → 33
62
+ expect(inverseConversion(100, 3)).toBe(33);
63
+ });
64
+
65
+ it("should throw on zero rate", () => {
66
+ expect(() => inverseConversion(100, 0)).toThrow("rate of zero");
67
+ });
68
+
69
+ it("should handle negative amounts", () => {
70
+ expect(inverseConversion(-2000, 20)).toBe(-100);
71
+ });
72
+
73
+ it("should handle zero amount", () => {
74
+ expect(inverseConversion(0, 20)).toBe(0);
75
+ });
76
+ });
77
+
78
+ describe("triangularConversion", () => {
79
+ it("should convert through base: MXN → USD → EUR", () => {
80
+ // 2000 MXN, 1 USD = 20 MXN, 1 USD = 0.91 EUR
81
+ // 2000 / 20 = 100 USD → 100 * 0.91 = 91 EUR
82
+ expect(triangularConversion(2000, 20, 0.91)).toBe(91);
83
+ });
84
+
85
+ it("should handle zero amount", () => {
86
+ expect(triangularConversion(0, 20, 0.91)).toBe(0);
87
+ });
88
+
89
+ it("should throw when source-to-base rate is zero", () => {
90
+ expect(() => triangularConversion(100, 0, 0.91)).toThrow(
91
+ "source-to-base rate is zero",
92
+ );
93
+ });
94
+
95
+ it("should handle large cross-rates", () => {
96
+ // 1000 BRL, 1 USD = 5 BRL, 1 USD = 150 JPY
97
+ // 1000 / 5 = 200 USD → 200 * 150 = 30000 JPY
98
+ expect(triangularConversion(1000, 5, 150)).toBe(30000);
99
+ });
100
+
101
+ it("should handle negative amounts", () => {
102
+ expect(triangularConversion(-2000, 20, 0.91)).toBe(-91);
103
+ });
104
+ });
105
+
106
+ describe("CONVERSION_STRATEGIES registry", () => {
107
+ it("should have direct, inverse, and triangular strategies", () => {
108
+ expect(CONVERSION_STRATEGIES).toHaveProperty("direct");
109
+ expect(CONVERSION_STRATEGIES).toHaveProperty("inverse");
110
+ expect(CONVERSION_STRATEGIES).toHaveProperty("triangular");
111
+ });
112
+
113
+ it("direct strategy matches standalone function", () => {
114
+ expect(CONVERSION_STRATEGIES["direct"](100, 20)).toBe(
115
+ directConversion(100, 20),
116
+ );
117
+ });
118
+
119
+ it("inverse strategy matches standalone function", () => {
120
+ expect(CONVERSION_STRATEGIES["inverse"](2000, 20)).toBe(
121
+ inverseConversion(2000, 20),
122
+ );
123
+ });
124
+
125
+ it("triangular strategy matches standalone function", () => {
126
+ expect(CONVERSION_STRATEGIES["triangular"](2000, 20, 0.91)).toBe(
127
+ triangularConversion(2000, 20, 0.91),
128
+ );
129
+ });
130
+
131
+ it("should be extensible", () => {
132
+ CONVERSION_STRATEGIES["custom"] = (
133
+ amount: number,
134
+ rate: number,
135
+ ): number => Math.round(amount * rate * 1.01); // 1% fee
136
+
137
+ expect(CONVERSION_STRATEGIES["custom"](100, 20)).toBe(2020);
138
+
139
+ // Clean up
140
+ delete CONVERSION_STRATEGIES["custom"];
141
+ });
142
+ });
143
+ });
@@ -1,15 +1,27 @@
1
1
  // sdk/core/src/exchange-rate/strategies.ts
2
2
  // Pure conversion strategy functions — no store or context dependencies.
3
3
  // Extracted from ExchangeRateStore to enable independent testing and extensibility.
4
+
5
+ import type { ScaledRate } from "./money.ts";
6
+
7
+ // ── Types ──────────────────────────────────────────────────────────────────────
8
+
9
+ /**
10
+ * A pure function that converts a minor-unit amount using a rate.
11
+ * All strategy functions must be deterministic and side-effect-free.
12
+ */
13
+ export type ConversionFn = (amount: number, ...rates: number[]) => number;
14
+
4
15
  /**
5
16
  * Resolves a ScaledRate or plain number into a float rate value.
6
17
  */
7
- export function resolveRate(rate) {
8
- if (typeof rate === "number")
9
- return rate;
10
- return rate.amount / Math.pow(10, rate.scale);
18
+ export function resolveRate(rate: ScaledRate | number): number {
19
+ if (typeof rate === "number") return rate;
20
+ return rate.amount / Math.pow(10, rate.scale);
11
21
  }
22
+
12
23
  // ── Strategy Functions ─────────────────────────────────────────────────────────
24
+
13
25
  /**
14
26
  * Direct conversion: base currency → target currency.
15
27
  * Multiplies the amount by the rate.
@@ -18,9 +30,10 @@ export function resolveRate(rate) {
18
30
  * @param rate - Conversion rate (1 source = `rate` target)
19
31
  * @returns Minor-unit amount in the target currency
20
32
  */
21
- export function directConversion(amount, rate) {
22
- return Math.round(amount * rate);
33
+ export function directConversion(amount: number, rate: number): number {
34
+ return Math.round(amount * rate);
23
35
  }
36
+
24
37
  /**
25
38
  * Inverse conversion: target currency → base currency.
26
39
  * Divides the amount by the rate.
@@ -29,12 +42,13 @@ export function directConversion(amount, rate) {
29
42
  * @param rate - Conversion rate of source relative to base (1 base = `rate` source)
30
43
  * @returns Minor-unit amount in the base currency
31
44
  */
32
- export function inverseConversion(amount, rate) {
33
- if (rate === 0) {
34
- throw new Error("Cannot perform inverse conversion with a rate of zero.");
35
- }
36
- return Math.round(amount / rate);
45
+ export function inverseConversion(amount: number, rate: number): number {
46
+ if (rate === 0) {
47
+ throw new Error("Cannot perform inverse conversion with a rate of zero.");
48
+ }
49
+ return Math.round(amount / rate);
37
50
  }
51
+
38
52
  /**
39
53
  * Triangular conversion: source → base → target (cross-rate).
40
54
  * First divides by the source-to-base rate, then multiplies by the base-to-target rate.
@@ -44,14 +58,22 @@ export function inverseConversion(amount, rate) {
44
58
  * @param rateBaseToTarget - Rate of base to target (1 base = `rate` target)
45
59
  * @returns Minor-unit amount in the target currency
46
60
  */
47
- export function triangularConversion(amount, rateSourceToBase, rateBaseToTarget) {
48
- if (rateSourceToBase === 0) {
49
- throw new Error("Cannot perform triangular conversion: source-to-base rate is zero.");
50
- }
51
- const amountInBase = amount / rateSourceToBase;
52
- return Math.round(amountInBase * rateBaseToTarget);
61
+ export function triangularConversion(
62
+ amount: number,
63
+ rateSourceToBase: number,
64
+ rateBaseToTarget: number,
65
+ ): number {
66
+ if (rateSourceToBase === 0) {
67
+ throw new Error(
68
+ "Cannot perform triangular conversion: source-to-base rate is zero.",
69
+ );
70
+ }
71
+ const amountInBase = amount / rateSourceToBase;
72
+ return Math.round(amountInBase * rateBaseToTarget);
53
73
  }
74
+
54
75
  // ── Strategy Registry ──────────────────────────────────────────────────────────
76
+
55
77
  /**
56
78
  * Named map of conversion strategies.
57
79
  * Consumer code and the ExchangeRateStore can select a strategy by name.
@@ -64,9 +86,10 @@ export function triangularConversion(amount, rateSourceToBase, rateBaseToTarget)
64
86
  * };
65
87
  * ```
66
88
  */
67
- export const CONVERSION_STRATEGIES = {
68
- direct: directConversion,
69
- inverse: inverseConversion,
70
- // triangularConversion takes 2 rates — wrapped for the registry signature
71
- triangular: (amount, ...rates) => triangularConversion(amount, rates[0], rates[1]),
89
+ export const CONVERSION_STRATEGIES: Record<string, ConversionFn> = {
90
+ direct: directConversion,
91
+ inverse: inverseConversion,
92
+ // triangularConversion takes 2 rates — wrapped for the registry signature
93
+ triangular: (amount: number, ...rates: number[]) =>
94
+ triangularConversion(amount, rates[0], rates[1]),
72
95
  };
@@ -0,0 +1,27 @@
1
+ export {
2
+ addMoney,
3
+ convertAmount,
4
+ convertMoney,
5
+ createMoney,
6
+ CURRENCY_MAP,
7
+ type Dinero,
8
+ type DineroCurrency,
9
+ type DineroSnapshot,
10
+ formatAmount,
11
+ formatMoney,
12
+ fromMoneySnapshot,
13
+ type ISO4217Code,
14
+ multiplyMoney,
15
+ type RateMap,
16
+ registerCurrency,
17
+ safeAmount,
18
+ type ScaledRate,
19
+ scaledRate,
20
+ subtractMoney,
21
+ toAdyenMoney,
22
+ toMinorUnit,
23
+ toMoneySnapshot,
24
+ toPaypalMoney,
25
+ toSquareMoney,
26
+ toStripeMoney,
27
+ } from "./money.ts";