@supercmd/calculator 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,2627 @@
1
+ // src/data/currencies.ts
2
+ var FIAT_CURRENCIES = {
3
+ // Major
4
+ USD: "US Dollar",
5
+ EUR: "Euro",
6
+ GBP: "British Pound",
7
+ JPY: "Japanese Yen",
8
+ CHF: "Swiss Franc",
9
+ CAD: "Canadian Dollar",
10
+ AUD: "Australian Dollar",
11
+ NZD: "New Zealand Dollar",
12
+ CNY: "Chinese Yuan",
13
+ HKD: "Hong Kong Dollar",
14
+ SGD: "Singapore Dollar",
15
+ SEK: "Swedish Krona",
16
+ NOK: "Norwegian Krone",
17
+ DKK: "Danish Krone",
18
+ KRW: "South Korean Won",
19
+ TWD: "Taiwan Dollar",
20
+ // Asia
21
+ INR: "Indian Rupee",
22
+ PKR: "Pakistani Rupee",
23
+ BDT: "Bangladeshi Taka",
24
+ LKR: "Sri Lankan Rupee",
25
+ NPR: "Nepalese Rupee",
26
+ IDR: "Indonesian Rupiah",
27
+ MYR: "Malaysian Ringgit",
28
+ THB: "Thai Baht",
29
+ VND: "Vietnamese Dong",
30
+ PHP: "Philippine Peso",
31
+ MMK: "Myanmar Kyat",
32
+ KHR: "Cambodian Riel",
33
+ LAK: "Lao Kip",
34
+ MNT: "Mongolian Tugrik",
35
+ KZT: "Kazakh Tenge",
36
+ UZS: "Uzbekistani Som",
37
+ GEL: "Georgian Lari",
38
+ AZN: "Azerbaijani Manat",
39
+ AMD: "Armenian Dram",
40
+ // Middle East
41
+ AED: "UAE Dirham",
42
+ SAR: "Saudi Riyal",
43
+ QAR: "Qatari Riyal",
44
+ OMR: "Omani Rial",
45
+ KWD: "Kuwaiti Dinar",
46
+ BHD: "Bahraini Dinar",
47
+ ILS: "Israeli Shekel",
48
+ JOD: "Jordanian Dinar",
49
+ LBP: "Lebanese Pound",
50
+ IQD: "Iraqi Dinar",
51
+ IRR: "Iranian Rial",
52
+ TRY: "Turkish Lira",
53
+ // Africa
54
+ ZAR: "South African Rand",
55
+ NGN: "Nigerian Naira",
56
+ EGP: "Egyptian Pound",
57
+ KES: "Kenyan Shilling",
58
+ GHS: "Ghanaian Cedi",
59
+ TZS: "Tanzanian Shilling",
60
+ UGX: "Ugandan Shilling",
61
+ MAD: "Moroccan Dirham",
62
+ TND: "Tunisian Dinar",
63
+ DZD: "Algerian Dinar",
64
+ XOF: "West African CFA",
65
+ XAF: "Central African CFA",
66
+ ETB: "Ethiopian Birr",
67
+ RWF: "Rwandan Franc",
68
+ MUR: "Mauritian Rupee",
69
+ // Americas
70
+ MXN: "Mexican Peso",
71
+ BRL: "Brazilian Real",
72
+ ARS: "Argentine Peso",
73
+ CLP: "Chilean Peso",
74
+ COP: "Colombian Peso",
75
+ PEN: "Peruvian Sol",
76
+ UYU: "Uruguayan Peso",
77
+ BOB: "Bolivian Boliviano",
78
+ PYG: "Paraguayan Guarani",
79
+ VES: "Venezuelan Bolivar",
80
+ CRC: "Costa Rican Colon",
81
+ GTQ: "Guatemalan Quetzal",
82
+ HNL: "Honduran Lempira",
83
+ NIO: "Nicaraguan Cordoba",
84
+ PAB: "Panamanian Balboa",
85
+ DOP: "Dominican Peso",
86
+ TTD: "Trinidad Dollar",
87
+ JMD: "Jamaican Dollar",
88
+ HTG: "Haitian Gourde",
89
+ BSD: "Bahamian Dollar",
90
+ BBD: "Barbadian Dollar",
91
+ BZD: "Belizean Dollar",
92
+ // Europe
93
+ PLN: "Polish Zloty",
94
+ CZK: "Czech Koruna",
95
+ HUF: "Hungarian Forint",
96
+ RON: "Romanian Leu",
97
+ BGN: "Bulgarian Lev",
98
+ HRK: "Croatian Kuna",
99
+ RSD: "Serbian Dinar",
100
+ UAH: "Ukrainian Hryvnia",
101
+ RUB: "Russian Ruble",
102
+ BYN: "Belarusian Ruble",
103
+ MDL: "Moldovan Leu",
104
+ MKD: "Macedonian Denar",
105
+ ALL: "Albanian Lek",
106
+ BAM: "Bosnian Mark",
107
+ ISK: "Icelandic Krona",
108
+ // Oceania / Pacific
109
+ FJD: "Fijian Dollar",
110
+ PGK: "Papua New Guinean Kina",
111
+ WST: "Samoan Tala",
112
+ TOP: "Tongan Paanga",
113
+ VUV: "Vanuatu Vatu",
114
+ SBD: "Solomon Islands Dollar",
115
+ // Caribbean / Other
116
+ XCD: "East Caribbean Dollar",
117
+ AWG: "Aruban Florin",
118
+ ANG: "Netherlands Antillean Guilder",
119
+ CUP: "Cuban Peso",
120
+ KYD: "Cayman Islands Dollar",
121
+ BMD: "Bermudian Dollar",
122
+ // Precious metals (often in currency APIs)
123
+ XAU: "Gold (troy oz)",
124
+ XAG: "Silver (troy oz)",
125
+ XPT: "Platinum (troy oz)"
126
+ };
127
+ var FIAT_ALIASES = {
128
+ dollar: "USD",
129
+ dollars: "USD",
130
+ usd: "USD",
131
+ "$": "USD",
132
+ "us dollar": "USD",
133
+ "us dollars": "USD",
134
+ euro: "EUR",
135
+ euros: "EUR",
136
+ eur: "EUR",
137
+ "\u20AC": "EUR",
138
+ pound: "GBP",
139
+ pounds: "GBP",
140
+ gbp: "GBP",
141
+ sterling: "GBP",
142
+ "\xA3": "GBP",
143
+ yen: "JPY",
144
+ jpy: "JPY",
145
+ "\xA5": "JPY",
146
+ rupee: "INR",
147
+ rupees: "INR",
148
+ inr: "INR",
149
+ "\u20B9": "INR",
150
+ yuan: "CNY",
151
+ renminbi: "CNY",
152
+ rmb: "CNY",
153
+ cny: "CNY",
154
+ won: "KRW",
155
+ krw: "KRW",
156
+ "\u20A9": "KRW",
157
+ franc: "CHF",
158
+ chf: "CHF",
159
+ real: "BRL",
160
+ reais: "BRL",
161
+ brl: "BRL",
162
+ peso: "MXN",
163
+ mxn: "MXN",
164
+ lira: "TRY",
165
+ try: "TRY",
166
+ "\u20BA": "TRY",
167
+ baht: "THB",
168
+ thb: "THB",
169
+ "\u0E3F": "THB",
170
+ ringgit: "MYR",
171
+ myr: "MYR",
172
+ rand: "ZAR",
173
+ zar: "ZAR",
174
+ dirham: "AED",
175
+ aed: "AED",
176
+ riyal: "SAR",
177
+ sar: "SAR",
178
+ shekel: "ILS",
179
+ shekels: "ILS",
180
+ ils: "ILS",
181
+ "\u20AA": "ILS",
182
+ ruble: "RUB",
183
+ rubles: "RUB",
184
+ rub: "RUB",
185
+ "\u20BD": "RUB",
186
+ zloty: "PLN",
187
+ pln: "PLN",
188
+ krona: "SEK",
189
+ sek: "SEK",
190
+ krone: "NOK",
191
+ nok: "NOK",
192
+ dinar: "KWD",
193
+ kwd: "KWD",
194
+ naira: "NGN",
195
+ ngn: "NGN",
196
+ "\u20A6": "NGN",
197
+ cedi: "GHS",
198
+ ghs: "GHS",
199
+ "\u20B5": "GHS",
200
+ birr: "ETB",
201
+ etb: "ETB"
202
+ };
203
+ var CRYPTO_CURRENCIES = {
204
+ BTC: "Bitcoin",
205
+ ETH: "Ethereum",
206
+ SOL: "Solana",
207
+ XRP: "Ripple",
208
+ USDT: "Tether",
209
+ USDC: "USD Coin",
210
+ BNB: "BNB",
211
+ DOGE: "Dogecoin",
212
+ ADA: "Cardano",
213
+ MATIC: "Polygon",
214
+ DOT: "Polkadot",
215
+ LTC: "Litecoin",
216
+ AVAX: "Avalanche",
217
+ LINK: "Chainlink",
218
+ UNI: "Uniswap",
219
+ ATOM: "Cosmos",
220
+ XLM: "Stellar",
221
+ ALGO: "Algorand",
222
+ FIL: "Filecoin",
223
+ NEAR: "NEAR Protocol",
224
+ APT: "Aptos",
225
+ ARB: "Arbitrum",
226
+ OP: "Optimism",
227
+ SUI: "Sui",
228
+ SHIB: "Shiba Inu",
229
+ PEPE: "Pepe",
230
+ TRX: "TRON",
231
+ TON: "Toncoin",
232
+ HBAR: "Hedera",
233
+ ICP: "Internet Computer",
234
+ VET: "VeChain",
235
+ AAVE: "Aave",
236
+ MKR: "Maker",
237
+ CRV: "Curve",
238
+ SNX: "Synthetix",
239
+ COMP: "Compound",
240
+ SAND: "The Sandbox",
241
+ MANA: "Decentraland",
242
+ AXS: "Axie Infinity",
243
+ GMT: "STEPN",
244
+ APE: "ApeCoin",
245
+ FTM: "Fantom",
246
+ ONE: "Harmony",
247
+ KAVA: "Kava",
248
+ ROSE: "Oasis",
249
+ ZEC: "Zcash",
250
+ XMR: "Monero",
251
+ DASH: "Dash",
252
+ ETC: "Ethereum Classic",
253
+ BCH: "Bitcoin Cash",
254
+ BSV: "Bitcoin SV"
255
+ };
256
+ var CRYPTO_ALIASES = {
257
+ bitcoin: "BTC",
258
+ btc: "BTC",
259
+ satoshi: "BTC",
260
+ sats: "BTC",
261
+ ethereum: "ETH",
262
+ eth: "ETH",
263
+ ether: "ETH",
264
+ solana: "SOL",
265
+ sol: "SOL",
266
+ ripple: "XRP",
267
+ xrp: "XRP",
268
+ tether: "USDT",
269
+ usdt: "USDT",
270
+ "usd coin": "USDC",
271
+ usdc: "USDC",
272
+ bnb: "BNB",
273
+ binance: "BNB",
274
+ dogecoin: "DOGE",
275
+ doge: "DOGE",
276
+ cardano: "ADA",
277
+ ada: "ADA",
278
+ polygon: "MATIC",
279
+ matic: "MATIC",
280
+ polkadot: "DOT",
281
+ dot: "DOT",
282
+ litecoin: "LTC",
283
+ ltc: "LTC",
284
+ avalanche: "AVAX",
285
+ avax: "AVAX",
286
+ chainlink: "LINK",
287
+ link: "LINK",
288
+ uniswap: "UNI",
289
+ uni: "UNI",
290
+ cosmos: "ATOM",
291
+ atom: "ATOM",
292
+ stellar: "XLM",
293
+ xlm: "XLM",
294
+ monero: "XMR",
295
+ xmr: "XMR",
296
+ zcash: "ZEC",
297
+ zec: "ZEC",
298
+ tron: "TRX",
299
+ trx: "TRX",
300
+ toncoin: "TON",
301
+ ton: "TON",
302
+ "bitcoin cash": "BCH",
303
+ bch: "BCH",
304
+ "ethereum classic": "ETC",
305
+ etc: "ETC"
306
+ };
307
+ function resolveFiat(token) {
308
+ const upper = token.toUpperCase();
309
+ if (FIAT_CURRENCIES[upper]) return upper;
310
+ const lower = token.toLowerCase();
311
+ if (FIAT_ALIASES[lower]) return FIAT_ALIASES[lower];
312
+ return null;
313
+ }
314
+ function resolveCrypto(token) {
315
+ const upper = token.toUpperCase();
316
+ if (CRYPTO_CURRENCIES[upper]) return upper;
317
+ const lower = token.toLowerCase();
318
+ if (CRYPTO_ALIASES[lower]) return CRYPTO_ALIASES[lower];
319
+ return null;
320
+ }
321
+
322
+ // src/data/units.ts
323
+ function u(factor, name, offset) {
324
+ return offset !== void 0 ? { factor, name, offset } : { factor, name };
325
+ }
326
+ var length = {
327
+ name: "length",
328
+ base: "meter",
329
+ units: {
330
+ // Metric
331
+ nm: u(1e-9, "nanometer"),
332
+ nanometer: u(1e-9, "nanometer"),
333
+ nanometers: u(1e-9, "nanometer"),
334
+ um: u(1e-6, "micrometer"),
335
+ micrometer: u(1e-6, "micrometer"),
336
+ micrometers: u(1e-6, "micrometer"),
337
+ micron: u(1e-6, "micrometer"),
338
+ microns: u(1e-6, "micrometer"),
339
+ mm: u(1e-3, "millimeter"),
340
+ millimeter: u(1e-3, "millimeter"),
341
+ millimeters: u(1e-3, "millimeter"),
342
+ millimetre: u(1e-3, "millimeter"),
343
+ millimetres: u(1e-3, "millimeter"),
344
+ cm: u(0.01, "centimeter"),
345
+ centimeter: u(0.01, "centimeter"),
346
+ centimeters: u(0.01, "centimeter"),
347
+ centimetre: u(0.01, "centimeter"),
348
+ centimetres: u(0.01, "centimeter"),
349
+ dm: u(0.1, "decimeter"),
350
+ decimeter: u(0.1, "decimeter"),
351
+ decimeters: u(0.1, "decimeter"),
352
+ m: u(1, "meter"),
353
+ meter: u(1, "meter"),
354
+ meters: u(1, "meter"),
355
+ metre: u(1, "meter"),
356
+ metres: u(1, "meter"),
357
+ km: u(1e3, "kilometer"),
358
+ kilometer: u(1e3, "kilometer"),
359
+ kilometers: u(1e3, "kilometer"),
360
+ kilometre: u(1e3, "kilometer"),
361
+ kilometres: u(1e3, "kilometer"),
362
+ // Imperial
363
+ in: u(0.0254, "inch"),
364
+ inch: u(0.0254, "inch"),
365
+ inches: u(0.0254, "inch"),
366
+ '"': u(0.0254, "inch"),
367
+ ft: u(0.3048, "foot"),
368
+ foot: u(0.3048, "foot"),
369
+ feet: u(0.3048, "foot"),
370
+ "'": u(0.3048, "foot"),
371
+ yd: u(0.9144, "yard"),
372
+ yard: u(0.9144, "yard"),
373
+ yards: u(0.9144, "yard"),
374
+ mi: u(1609.344, "mile"),
375
+ mile: u(1609.344, "mile"),
376
+ miles: u(1609.344, "mile"),
377
+ nmi: u(1852, "nautical mile"),
378
+ "nautical mile": u(1852, "nautical mile"),
379
+ "nautical miles": u(1852, "nautical mile"),
380
+ // Astronomical
381
+ au: u(149597870700, "astronomical unit"),
382
+ "astronomical unit": u(149597870700, "astronomical unit"),
383
+ ly: u(94607e11, "light year"),
384
+ "light year": u(94607e11, "light year"),
385
+ "light years": u(94607e11, "light year"),
386
+ lightyear: u(94607e11, "light year"),
387
+ lightyears: u(94607e11, "light year"),
388
+ pc: u(30857e12, "parsec"),
389
+ parsec: u(30857e12, "parsec"),
390
+ parsecs: u(30857e12, "parsec")
391
+ }
392
+ };
393
+ var mass = {
394
+ name: "mass",
395
+ base: "kilogram",
396
+ units: {
397
+ ug: u(1e-9, "microgram"),
398
+ microgram: u(1e-9, "microgram"),
399
+ micrograms: u(1e-9, "microgram"),
400
+ mcg: u(1e-9, "microgram"),
401
+ mg: u(1e-6, "milligram"),
402
+ milligram: u(1e-6, "milligram"),
403
+ milligrams: u(1e-6, "milligram"),
404
+ g: u(1e-3, "gram"),
405
+ gram: u(1e-3, "gram"),
406
+ grams: u(1e-3, "gram"),
407
+ kg: u(1, "kilogram"),
408
+ kilogram: u(1, "kilogram"),
409
+ kilograms: u(1, "kilogram"),
410
+ kilo: u(1, "kilogram"),
411
+ kilos: u(1, "kilogram"),
412
+ tonne: u(1e3, "metric ton"),
413
+ tonnes: u(1e3, "metric ton"),
414
+ "metric ton": u(1e3, "metric ton"),
415
+ "metric tons": u(1e3, "metric ton"),
416
+ t: u(1e3, "metric ton"),
417
+ oz: u(0.028349523125, "ounce"),
418
+ ounce: u(0.028349523125, "ounce"),
419
+ ounces: u(0.028349523125, "ounce"),
420
+ lb: u(0.45359237, "pound"),
421
+ lbs: u(0.45359237, "pound"),
422
+ pound: u(0.45359237, "pound"),
423
+ pounds: u(0.45359237, "pound"),
424
+ st: u(6.35029318, "stone"),
425
+ stone: u(6.35029318, "stone"),
426
+ stones: u(6.35029318, "stone"),
427
+ "short ton": u(907.18474, "short ton"),
428
+ "short tons": u(907.18474, "short ton"),
429
+ "long ton": u(1016.0469088, "long ton"),
430
+ "long tons": u(1016.0469088, "long ton"),
431
+ grain: u(6479891e-11, "grain"),
432
+ grains: u(6479891e-11, "grain"),
433
+ gr: u(6479891e-11, "grain"),
434
+ carat: u(2e-4, "carat"),
435
+ carats: u(2e-4, "carat"),
436
+ ct: u(2e-4, "carat")
437
+ }
438
+ };
439
+ var volume = {
440
+ name: "volume",
441
+ base: "liter",
442
+ units: {
443
+ ml: u(1e-3, "milliliter"),
444
+ milliliter: u(1e-3, "milliliter"),
445
+ milliliters: u(1e-3, "milliliter"),
446
+ millilitre: u(1e-3, "milliliter"),
447
+ millilitres: u(1e-3, "milliliter"),
448
+ cl: u(0.01, "centiliter"),
449
+ centiliter: u(0.01, "centiliter"),
450
+ centiliters: u(0.01, "centiliter"),
451
+ dl: u(0.1, "deciliter"),
452
+ deciliter: u(0.1, "deciliter"),
453
+ deciliters: u(0.1, "deciliter"),
454
+ l: u(1, "liter"),
455
+ liter: u(1, "liter"),
456
+ liters: u(1, "liter"),
457
+ litre: u(1, "liter"),
458
+ litres: u(1, "liter"),
459
+ kl: u(1e3, "kiloliter"),
460
+ kiloliter: u(1e3, "kiloliter"),
461
+ kiloliters: u(1e3, "kiloliter"),
462
+ "m3": u(1e3, "cubic meter"),
463
+ "cubic meter": u(1e3, "cubic meter"),
464
+ "cubic meters": u(1e3, "cubic meter"),
465
+ "cubic metre": u(1e3, "cubic meter"),
466
+ "cm3": u(1e-3, "cubic centimeter"),
467
+ "cubic centimeter": u(1e-3, "cubic centimeter"),
468
+ "cubic centimeters": u(1e-3, "cubic centimeter"),
469
+ cc: u(1e-3, "cubic centimeter"),
470
+ tsp: u(492892e-8, "teaspoon"),
471
+ teaspoon: u(492892e-8, "teaspoon"),
472
+ teaspoons: u(492892e-8, "teaspoon"),
473
+ tbsp: u(0.0147868, "tablespoon"),
474
+ tablespoon: u(0.0147868, "tablespoon"),
475
+ tablespoons: u(0.0147868, "tablespoon"),
476
+ "fl oz": u(0.0295735, "fluid ounce"),
477
+ "fluid ounce": u(0.0295735, "fluid ounce"),
478
+ "fluid ounces": u(0.0295735, "fluid ounce"),
479
+ floz: u(0.0295735, "fluid ounce"),
480
+ cup: u(0.236588, "cup"),
481
+ cups: u(0.236588, "cup"),
482
+ pt: u(0.473176, "pint"),
483
+ pint: u(0.473176, "pint"),
484
+ pints: u(0.473176, "pint"),
485
+ qt: u(0.946353, "quart"),
486
+ quart: u(0.946353, "quart"),
487
+ quarts: u(0.946353, "quart"),
488
+ gal: u(3.78541, "gallon"),
489
+ gallon: u(3.78541, "gallon"),
490
+ gallons: u(3.78541, "gallon"),
491
+ "imp gal": u(4.54609, "imperial gallon"),
492
+ "imperial gallon": u(4.54609, "imperial gallon"),
493
+ "imperial gallons": u(4.54609, "imperial gallon"),
494
+ "imp pt": u(0.568261, "imperial pint"),
495
+ "imperial pint": u(0.568261, "imperial pint"),
496
+ bbl: u(158.987, "barrel"),
497
+ barrel: u(158.987, "barrel"),
498
+ barrels: u(158.987, "barrel")
499
+ }
500
+ };
501
+ var area = {
502
+ name: "area",
503
+ base: "square meter",
504
+ units: {
505
+ "mm2": u(1e-6, "square millimeter"),
506
+ "sq mm": u(1e-6, "square millimeter"),
507
+ "square millimeter": u(1e-6, "square millimeter"),
508
+ "square millimeters": u(1e-6, "square millimeter"),
509
+ "cm2": u(1e-4, "square centimeter"),
510
+ "sq cm": u(1e-4, "square centimeter"),
511
+ "square centimeter": u(1e-4, "square centimeter"),
512
+ "square centimeters": u(1e-4, "square centimeter"),
513
+ "m2": u(1, "square meter"),
514
+ "sq m": u(1, "square meter"),
515
+ "square meter": u(1, "square meter"),
516
+ "square meters": u(1, "square meter"),
517
+ "square metre": u(1, "square meter"),
518
+ "km2": u(1e6, "square kilometer"),
519
+ "sq km": u(1e6, "square kilometer"),
520
+ "square kilometer": u(1e6, "square kilometer"),
521
+ "square kilometers": u(1e6, "square kilometer"),
522
+ "in2": u(64516e-8, "square inch"),
523
+ "sq in": u(64516e-8, "square inch"),
524
+ "square inch": u(64516e-8, "square inch"),
525
+ "square inches": u(64516e-8, "square inch"),
526
+ "ft2": u(0.092903, "square foot"),
527
+ "sq ft": u(0.092903, "square foot"),
528
+ "square foot": u(0.092903, "square foot"),
529
+ "square feet": u(0.092903, "square foot"),
530
+ sqft: u(0.092903, "square foot"),
531
+ "yd2": u(0.836127, "square yard"),
532
+ "sq yd": u(0.836127, "square yard"),
533
+ "square yard": u(0.836127, "square yard"),
534
+ "square yards": u(0.836127, "square yard"),
535
+ "mi2": u(258998811e-2, "square mile"),
536
+ "sq mi": u(258998811e-2, "square mile"),
537
+ "square mile": u(258998811e-2, "square mile"),
538
+ "square miles": u(258998811e-2, "square mile"),
539
+ acre: u(4046.8564224, "acre"),
540
+ acres: u(4046.8564224, "acre"),
541
+ ac: u(4046.8564224, "acre"),
542
+ hectare: u(1e4, "hectare"),
543
+ hectares: u(1e4, "hectare"),
544
+ ha: u(1e4, "hectare")
545
+ }
546
+ };
547
+ var temperature = {
548
+ name: "temperature",
549
+ base: "kelvin",
550
+ units: {
551
+ // factor=1 offset=0 for kelvin (base)
552
+ k: u(1, "kelvin", 0),
553
+ kelvin: u(1, "kelvin", 0),
554
+ // Celsius: K = C + 273.15
555
+ c: u(1, "celsius", 273.15),
556
+ celsius: u(1, "celsius", 273.15),
557
+ "\xB0c": u(1, "celsius", 273.15),
558
+ centigrade: u(1, "celsius", 273.15),
559
+ // Fahrenheit: K = (F + 459.67) * 5/9
560
+ f: u(5 / 9, "fahrenheit", 459.67),
561
+ fahrenheit: u(5 / 9, "fahrenheit", 459.67),
562
+ "\xB0f": u(5 / 9, "fahrenheit", 459.67)
563
+ }
564
+ };
565
+ var speed = {
566
+ name: "speed",
567
+ base: "meter per second",
568
+ units: {
569
+ "mps": u(1, "meter per second"),
570
+ "m/s": u(1, "meter per second"),
571
+ "meter per second": u(1, "meter per second"),
572
+ "meters per second": u(1, "meter per second"),
573
+ "km/h": u(1 / 3.6, "kilometer per hour"),
574
+ kmh: u(1 / 3.6, "kilometer per hour"),
575
+ kph: u(1 / 3.6, "kilometer per hour"),
576
+ kmph: u(1 / 3.6, "kilometer per hour"),
577
+ "kilometer per hour": u(1 / 3.6, "kilometer per hour"),
578
+ "kilometers per hour": u(1 / 3.6, "kilometer per hour"),
579
+ mph: u(0.44704, "mile per hour"),
580
+ "mile per hour": u(0.44704, "mile per hour"),
581
+ "miles per hour": u(0.44704, "mile per hour"),
582
+ fps: u(0.3048, "foot per second"),
583
+ "ft/s": u(0.3048, "foot per second"),
584
+ "feet per second": u(0.3048, "foot per second"),
585
+ knot: u(0.514444, "knot"),
586
+ knots: u(0.514444, "knot"),
587
+ kn: u(0.514444, "knot"),
588
+ kt: u(0.514444, "knot"),
589
+ mach: u(343, "mach")
590
+ }
591
+ };
592
+ var timeDuration = {
593
+ name: "time",
594
+ base: "second",
595
+ units: {
596
+ ns: u(1e-9, "nanosecond"),
597
+ nanosecond: u(1e-9, "nanosecond"),
598
+ nanoseconds: u(1e-9, "nanosecond"),
599
+ us: u(1e-6, "microsecond"),
600
+ microsecond: u(1e-6, "microsecond"),
601
+ microseconds: u(1e-6, "microsecond"),
602
+ \u03BCs: u(1e-6, "microsecond"),
603
+ ms: u(1e-3, "millisecond"),
604
+ millisecond: u(1e-3, "millisecond"),
605
+ milliseconds: u(1e-3, "millisecond"),
606
+ s: u(1, "second"),
607
+ sec: u(1, "second"),
608
+ second: u(1, "second"),
609
+ seconds: u(1, "second"),
610
+ min: u(60, "minute"),
611
+ minute: u(60, "minute"),
612
+ minutes: u(60, "minute"),
613
+ mins: u(60, "minute"),
614
+ h: u(3600, "hour"),
615
+ hr: u(3600, "hour"),
616
+ hrs: u(3600, "hour"),
617
+ hour: u(3600, "hour"),
618
+ hours: u(3600, "hour"),
619
+ d: u(86400, "day"),
620
+ day: u(86400, "day"),
621
+ days: u(86400, "day"),
622
+ wk: u(604800, "week"),
623
+ week: u(604800, "week"),
624
+ weeks: u(604800, "week"),
625
+ mo: u(2629746, "month"),
626
+ month: u(2629746, "month"),
627
+ months: u(2629746, "month"),
628
+ yr: u(31556952, "year"),
629
+ year: u(31556952, "year"),
630
+ years: u(31556952, "year"),
631
+ decade: u(315569520, "decade"),
632
+ decades: u(315569520, "decade"),
633
+ century: u(3155695200, "century"),
634
+ centuries: u(3155695200, "century")
635
+ }
636
+ };
637
+ var dataSize = {
638
+ name: "data",
639
+ base: "byte",
640
+ units: {
641
+ b: u(1, "byte"),
642
+ byte: u(1, "byte"),
643
+ bytes: u(1, "byte"),
644
+ kb: u(1e3, "kilobyte"),
645
+ kilobyte: u(1e3, "kilobyte"),
646
+ kilobytes: u(1e3, "kilobyte"),
647
+ mb: u(1e6, "megabyte"),
648
+ megabyte: u(1e6, "megabyte"),
649
+ megabytes: u(1e6, "megabyte"),
650
+ gb: u(1e9, "gigabyte"),
651
+ gigabyte: u(1e9, "gigabyte"),
652
+ gigabytes: u(1e9, "gigabyte"),
653
+ tb: u(1e12, "terabyte"),
654
+ terabyte: u(1e12, "terabyte"),
655
+ terabytes: u(1e12, "terabyte"),
656
+ pb: u(1e15, "petabyte"),
657
+ petabyte: u(1e15, "petabyte"),
658
+ petabytes: u(1e15, "petabyte"),
659
+ eb: u(1e18, "exabyte"),
660
+ exabyte: u(1e18, "exabyte"),
661
+ exabytes: u(1e18, "exabyte"),
662
+ kib: u(1024, "kibibyte"),
663
+ kibibyte: u(1024, "kibibyte"),
664
+ kibibytes: u(1024, "kibibyte"),
665
+ mib: u(1048576, "mebibyte"),
666
+ mebibyte: u(1048576, "mebibyte"),
667
+ mebibytes: u(1048576, "mebibyte"),
668
+ gib: u(1073741824, "gibibyte"),
669
+ gibibyte: u(1073741824, "gibibyte"),
670
+ gibibytes: u(1073741824, "gibibyte"),
671
+ tib: u(1099511627776, "tebibyte"),
672
+ tebibyte: u(1099511627776, "tebibyte"),
673
+ tebibytes: u(1099511627776, "tebibyte"),
674
+ bit: u(0.125, "bit"),
675
+ bits: u(0.125, "bit"),
676
+ kbit: u(125, "kilobit"),
677
+ kilobit: u(125, "kilobit"),
678
+ kilobits: u(125, "kilobit"),
679
+ mbit: u(125e3, "megabit"),
680
+ megabit: u(125e3, "megabit"),
681
+ megabits: u(125e3, "megabit"),
682
+ gbit: u(125e6, "gigabit"),
683
+ gigabit: u(125e6, "gigabit"),
684
+ gigabits: u(125e6, "gigabit")
685
+ }
686
+ };
687
+ var pressure = {
688
+ name: "pressure",
689
+ base: "pascal",
690
+ units: {
691
+ pa: u(1, "pascal"),
692
+ pascal: u(1, "pascal"),
693
+ pascals: u(1, "pascal"),
694
+ hpa: u(100, "hectopascal"),
695
+ hectopascal: u(100, "hectopascal"),
696
+ kpa: u(1e3, "kilopascal"),
697
+ kilopascal: u(1e3, "kilopascal"),
698
+ mpa: u(1e6, "megapascal"),
699
+ megapascal: u(1e6, "megapascal"),
700
+ bar: u(1e5, "bar"),
701
+ bars: u(1e5, "bar"),
702
+ mbar: u(100, "millibar"),
703
+ millibar: u(100, "millibar"),
704
+ atm: u(101325, "atmosphere"),
705
+ atmosphere: u(101325, "atmosphere"),
706
+ atmospheres: u(101325, "atmosphere"),
707
+ psi: u(6894.757, "psi"),
708
+ torr: u(133.322, "torr"),
709
+ mmhg: u(133.322, "mmHg"),
710
+ inhg: u(3386.39, "inHg")
711
+ }
712
+ };
713
+ var energy = {
714
+ name: "energy",
715
+ base: "joule",
716
+ units: {
717
+ j: u(1, "joule"),
718
+ joule: u(1, "joule"),
719
+ joules: u(1, "joule"),
720
+ kj: u(1e3, "kilojoule"),
721
+ kilojoule: u(1e3, "kilojoule"),
722
+ kilojoules: u(1e3, "kilojoule"),
723
+ mj: u(1e6, "megajoule"),
724
+ megajoule: u(1e6, "megajoule"),
725
+ cal: u(4.184, "calorie"),
726
+ calorie: u(4.184, "calorie"),
727
+ calories: u(4.184, "calorie"),
728
+ kcal: u(4184, "kilocalorie"),
729
+ kilocalorie: u(4184, "kilocalorie"),
730
+ kilocalories: u(4184, "kilocalorie"),
731
+ wh: u(3600, "watt-hour"),
732
+ "watt-hour": u(3600, "watt-hour"),
733
+ "watt hour": u(3600, "watt-hour"),
734
+ kwh: u(36e5, "kilowatt-hour"),
735
+ "kilowatt-hour": u(36e5, "kilowatt-hour"),
736
+ "kilowatt hour": u(36e5, "kilowatt-hour"),
737
+ btu: u(1055.06, "BTU"),
738
+ "british thermal unit": u(1055.06, "BTU"),
739
+ ev: u(1602176634e-28, "electronvolt"),
740
+ electronvolt: u(1602176634e-28, "electronvolt"),
741
+ erg: u(1e-7, "erg"),
742
+ ergs: u(1e-7, "erg"),
743
+ therm: u(1055e5, "therm"),
744
+ therms: u(1055e5, "therm")
745
+ }
746
+ };
747
+ var power = {
748
+ name: "power",
749
+ base: "watt",
750
+ units: {
751
+ w: u(1, "watt"),
752
+ watt: u(1, "watt"),
753
+ watts: u(1, "watt"),
754
+ mw: u(1e-3, "milliwatt"),
755
+ milliwatt: u(1e-3, "milliwatt"),
756
+ kw: u(1e3, "kilowatt"),
757
+ kilowatt: u(1e3, "kilowatt"),
758
+ kilowatts: u(1e3, "kilowatt"),
759
+ megawatt: u(1e6, "megawatt"),
760
+ megawatts: u(1e6, "megawatt"),
761
+ gw: u(1e9, "gigawatt"),
762
+ gigawatt: u(1e9, "gigawatt"),
763
+ gigawatts: u(1e9, "gigawatt"),
764
+ hp: u(745.7, "horsepower"),
765
+ horsepower: u(745.7, "horsepower"),
766
+ "metric hp": u(735.499, "metric horsepower"),
767
+ ps: u(735.499, "metric horsepower"),
768
+ "btu/h": u(0.293071, "BTU per hour")
769
+ }
770
+ };
771
+ var angle = {
772
+ name: "angle",
773
+ base: "radian",
774
+ units: {
775
+ rad: u(1, "radian"),
776
+ radian: u(1, "radian"),
777
+ radians: u(1, "radian"),
778
+ deg: u(Math.PI / 180, "degree"),
779
+ degree: u(Math.PI / 180, "degree"),
780
+ degrees: u(Math.PI / 180, "degree"),
781
+ "\xB0": u(Math.PI / 180, "degree"),
782
+ grad: u(Math.PI / 200, "gradian"),
783
+ gradian: u(Math.PI / 200, "gradian"),
784
+ gradians: u(Math.PI / 200, "gradian"),
785
+ gon: u(Math.PI / 200, "gradian"),
786
+ arcmin: u(Math.PI / 10800, "arcminute"),
787
+ arcminute: u(Math.PI / 10800, "arcminute"),
788
+ arcminutes: u(Math.PI / 10800, "arcminute"),
789
+ "'": u(Math.PI / 10800, "arcminute"),
790
+ arcsec: u(Math.PI / 648e3, "arcsecond"),
791
+ arcsecond: u(Math.PI / 648e3, "arcsecond"),
792
+ arcseconds: u(Math.PI / 648e3, "arcsecond"),
793
+ rev: u(2 * Math.PI, "revolution"),
794
+ revolution: u(2 * Math.PI, "revolution"),
795
+ revolutions: u(2 * Math.PI, "revolution"),
796
+ turn: u(2 * Math.PI, "revolution"),
797
+ turns: u(2 * Math.PI, "revolution")
798
+ }
799
+ };
800
+ var frequency = {
801
+ name: "frequency",
802
+ base: "hertz",
803
+ units: {
804
+ hz: u(1, "hertz"),
805
+ hertz: u(1, "hertz"),
806
+ khz: u(1e3, "kilohertz"),
807
+ kilohertz: u(1e3, "kilohertz"),
808
+ mhz: u(1e6, "megahertz"),
809
+ megahertz: u(1e6, "megahertz"),
810
+ ghz: u(1e9, "gigahertz"),
811
+ gigahertz: u(1e9, "gigahertz"),
812
+ thz: u(1e12, "terahertz"),
813
+ terahertz: u(1e12, "terahertz"),
814
+ rpm: u(1 / 60, "RPM")
815
+ }
816
+ };
817
+ var electricCurrent = {
818
+ name: "electric current",
819
+ base: "ampere",
820
+ units: {
821
+ a: u(1, "ampere"),
822
+ amp: u(1, "ampere"),
823
+ amps: u(1, "ampere"),
824
+ ampere: u(1, "ampere"),
825
+ amperes: u(1, "ampere"),
826
+ ma: u(1e-3, "milliampere"),
827
+ milliamp: u(1e-3, "milliampere"),
828
+ milliamps: u(1e-3, "milliampere"),
829
+ milliampere: u(1e-3, "milliampere"),
830
+ ka: u(1e3, "kiloampere"),
831
+ kiloamp: u(1e3, "kiloampere"),
832
+ kiloampere: u(1e3, "kiloampere"),
833
+ \u03BCa: u(1e-6, "microampere"),
834
+ microamp: u(1e-6, "microampere"),
835
+ microampere: u(1e-6, "microampere")
836
+ }
837
+ };
838
+ var voltage = {
839
+ name: "voltage",
840
+ base: "volt",
841
+ units: {
842
+ v: u(1, "volt"),
843
+ volt: u(1, "volt"),
844
+ volts: u(1, "volt"),
845
+ mv: u(1e-3, "millivolt"),
846
+ millivolt: u(1e-3, "millivolt"),
847
+ millivolts: u(1e-3, "millivolt"),
848
+ kv: u(1e3, "kilovolt"),
849
+ kilovolt: u(1e3, "kilovolt"),
850
+ kilovolts: u(1e3, "kilovolt"),
851
+ \u03BCv: u(1e-6, "microvolt"),
852
+ microvolt: u(1e-6, "microvolt"),
853
+ microvolts: u(1e-6, "microvolt")
854
+ }
855
+ };
856
+ var fuelEconomy = {
857
+ name: "fuel economy",
858
+ base: "km per liter",
859
+ units: {
860
+ "km/l": u(1, "km per liter"),
861
+ "kmpl": u(1, "km per liter"),
862
+ "km per liter": u(1, "km per liter"),
863
+ // mpg (US) → km/l: 1 mpg ≈ 0.425144 km/l
864
+ mpg: u(0.425144, "miles per gallon"),
865
+ "miles per gallon": u(0.425144, "miles per gallon"),
866
+ // mpg (UK) → km/l: 1 UK mpg ≈ 0.354006 km/l
867
+ "mpg uk": u(0.354006, "miles per gallon (UK)"),
868
+ "uk mpg": u(0.354006, "miles per gallon (UK)")
869
+ // l/100km is inverse — we handle specially
870
+ }
871
+ };
872
+ var UNIT_CATEGORIES = [
873
+ length,
874
+ mass,
875
+ volume,
876
+ area,
877
+ temperature,
878
+ speed,
879
+ timeDuration,
880
+ dataSize,
881
+ pressure,
882
+ energy,
883
+ power,
884
+ angle,
885
+ frequency,
886
+ electricCurrent,
887
+ voltage,
888
+ fuelEconomy
889
+ ];
890
+ var _unitIndex = /* @__PURE__ */ new Map();
891
+ for (const cat of UNIT_CATEGORIES) {
892
+ for (const [key, def] of Object.entries(cat.units)) {
893
+ _unitIndex.set(key.toLowerCase(), { category: cat, key, def });
894
+ }
895
+ }
896
+ function lookupUnit(token) {
897
+ return _unitIndex.get(token.toLowerCase());
898
+ }
899
+ function convertUnit(value, from, to) {
900
+ if (from.category !== to.category) {
901
+ throw new Error(`Cannot convert between ${from.category.name} and ${to.category.name}`);
902
+ }
903
+ if (from.category.name === "temperature") {
904
+ const fromDef = from.def;
905
+ const toDef = to.def;
906
+ const kelvin = (value + (fromDef.offset ?? 0)) * fromDef.factor;
907
+ return kelvin / toDef.factor - (toDef.offset ?? 0);
908
+ }
909
+ const baseValue = value * from.def.factor;
910
+ return baseValue / to.def.factor;
911
+ }
912
+
913
+ // src/data/timezones.ts
914
+ var TIMEZONE_MAP = {
915
+ // ─── Americas ─────────────────────────────────────────
916
+ "new york": "America/New_York",
917
+ nyc: "America/New_York",
918
+ "new york city": "America/New_York",
919
+ manhattan: "America/New_York",
920
+ boston: "America/New_York",
921
+ philadelphia: "America/New_York",
922
+ miami: "America/New_York",
923
+ atlanta: "America/New_York",
924
+ washington: "America/New_York",
925
+ "washington dc": "America/New_York",
926
+ dc: "America/New_York",
927
+ detroit: "America/New_York",
928
+ orlando: "America/New_York",
929
+ charlotte: "America/New_York",
930
+ pittsburgh: "America/New_York",
931
+ raleigh: "America/New_York",
932
+ chicago: "America/Chicago",
933
+ dallas: "America/Chicago",
934
+ houston: "America/Chicago",
935
+ austin: "America/Chicago",
936
+ "san antonio": "America/Chicago",
937
+ nashville: "America/Chicago",
938
+ memphis: "America/Chicago",
939
+ milwaukee: "America/Chicago",
940
+ minneapolis: "America/Chicago",
941
+ "kansas city": "America/Chicago",
942
+ "new orleans": "America/Chicago",
943
+ "oklahoma city": "America/Chicago",
944
+ madison: "America/Chicago",
945
+ indianapolis: "America/Indiana/Indianapolis",
946
+ denver: "America/Denver",
947
+ phoenix: "America/Phoenix",
948
+ "salt lake city": "America/Denver",
949
+ albuquerque: "America/Denver",
950
+ "las vegas": "America/Los_Angeles",
951
+ "los angeles": "America/Los_Angeles",
952
+ la: "America/Los_Angeles",
953
+ "san francisco": "America/Los_Angeles",
954
+ sf: "America/Los_Angeles",
955
+ seattle: "America/Los_Angeles",
956
+ portland: "America/Los_Angeles",
957
+ "san diego": "America/Los_Angeles",
958
+ "san jose": "America/Los_Angeles",
959
+ sacramento: "America/Los_Angeles",
960
+ oakland: "America/Los_Angeles",
961
+ anchorage: "America/Anchorage",
962
+ alaska: "America/Anchorage",
963
+ honolulu: "Pacific/Honolulu",
964
+ hawaii: "Pacific/Honolulu",
965
+ toronto: "America/Toronto",
966
+ montreal: "America/Toronto",
967
+ ottawa: "America/Toronto",
968
+ vancouver: "America/Vancouver",
969
+ calgary: "America/Edmonton",
970
+ edmonton: "America/Edmonton",
971
+ winnipeg: "America/Winnipeg",
972
+ halifax: "America/Halifax",
973
+ "mexico city": "America/Mexico_City",
974
+ guadalajara: "America/Mexico_City",
975
+ monterrey: "America/Monterrey",
976
+ "sao paulo": "America/Sao_Paulo",
977
+ "s\xE3o paulo": "America/Sao_Paulo",
978
+ rio: "America/Sao_Paulo",
979
+ "rio de janeiro": "America/Sao_Paulo",
980
+ brasilia: "America/Sao_Paulo",
981
+ "buenos aires": "America/Argentina/Buenos_Aires",
982
+ argentina: "America/Argentina/Buenos_Aires",
983
+ lima: "America/Lima",
984
+ bogota: "America/Bogota",
985
+ santiago: "America/Santiago",
986
+ caracas: "America/Caracas",
987
+ quito: "America/Guayaquil",
988
+ // ─── Europe ───────────────────────────────────────────
989
+ london: "Europe/London",
990
+ uk: "Europe/London",
991
+ "united kingdom": "Europe/London",
992
+ england: "Europe/London",
993
+ britain: "Europe/London",
994
+ edinburgh: "Europe/London",
995
+ manchester: "Europe/London",
996
+ birmingham: "Europe/London",
997
+ glasgow: "Europe/London",
998
+ paris: "Europe/Paris",
999
+ france: "Europe/Paris",
1000
+ lyon: "Europe/Paris",
1001
+ marseille: "Europe/Paris",
1002
+ berlin: "Europe/Berlin",
1003
+ germany: "Europe/Berlin",
1004
+ munich: "Europe/Berlin",
1005
+ frankfurt: "Europe/Berlin",
1006
+ hamburg: "Europe/Berlin",
1007
+ amsterdam: "Europe/Amsterdam",
1008
+ netherlands: "Europe/Amsterdam",
1009
+ brussels: "Europe/Brussels",
1010
+ belgium: "Europe/Brussels",
1011
+ madrid: "Europe/Madrid",
1012
+ spain: "Europe/Madrid",
1013
+ barcelona: "Europe/Madrid",
1014
+ rome: "Europe/Rome",
1015
+ italy: "Europe/Rome",
1016
+ milan: "Europe/Rome",
1017
+ vienna: "Europe/Vienna",
1018
+ austria: "Europe/Vienna",
1019
+ zurich: "Europe/Zurich",
1020
+ geneva: "Europe/Zurich",
1021
+ switzerland: "Europe/Zurich",
1022
+ lisbon: "Europe/Lisbon",
1023
+ portugal: "Europe/Lisbon",
1024
+ dublin: "Europe/Dublin",
1025
+ ireland: "Europe/Dublin",
1026
+ copenhagen: "Europe/Copenhagen",
1027
+ denmark: "Europe/Copenhagen",
1028
+ stockholm: "Europe/Stockholm",
1029
+ sweden: "Europe/Stockholm",
1030
+ oslo: "Europe/Oslo",
1031
+ norway: "Europe/Oslo",
1032
+ helsinki: "Europe/Helsinki",
1033
+ finland: "Europe/Helsinki",
1034
+ warsaw: "Europe/Warsaw",
1035
+ poland: "Europe/Warsaw",
1036
+ krakow: "Europe/Warsaw",
1037
+ prague: "Europe/Prague",
1038
+ "czech republic": "Europe/Prague",
1039
+ czechia: "Europe/Prague",
1040
+ budapest: "Europe/Budapest",
1041
+ hungary: "Europe/Budapest",
1042
+ bucharest: "Europe/Bucharest",
1043
+ romania: "Europe/Bucharest",
1044
+ athens: "Europe/Athens",
1045
+ greece: "Europe/Athens",
1046
+ istanbul: "Europe/Istanbul",
1047
+ turkey: "Europe/Istanbul",
1048
+ ankara: "Europe/Istanbul",
1049
+ moscow: "Europe/Moscow",
1050
+ russia: "Europe/Moscow",
1051
+ "st petersburg": "Europe/Moscow",
1052
+ "saint petersburg": "Europe/Moscow",
1053
+ kyiv: "Europe/Kyiv",
1054
+ kiev: "Europe/Kyiv",
1055
+ ukraine: "Europe/Kyiv",
1056
+ belgrade: "Europe/Belgrade",
1057
+ serbia: "Europe/Belgrade",
1058
+ sofia: "Europe/Sofia",
1059
+ bulgaria: "Europe/Sofia",
1060
+ zagreb: "Europe/Zagreb",
1061
+ croatia: "Europe/Zagreb",
1062
+ bratislava: "Europe/Bratislava",
1063
+ slovakia: "Europe/Bratislava",
1064
+ tallinn: "Europe/Tallinn",
1065
+ estonia: "Europe/Tallinn",
1066
+ riga: "Europe/Riga",
1067
+ latvia: "Europe/Riga",
1068
+ vilnius: "Europe/Vilnius",
1069
+ lithuania: "Europe/Vilnius",
1070
+ luxembourg: "Europe/Luxembourg",
1071
+ // ─── Asia ─────────────────────────────────────────────
1072
+ tokyo: "Asia/Tokyo",
1073
+ japan: "Asia/Tokyo",
1074
+ osaka: "Asia/Tokyo",
1075
+ seoul: "Asia/Seoul",
1076
+ "south korea": "Asia/Seoul",
1077
+ korea: "Asia/Seoul",
1078
+ beijing: "Asia/Shanghai",
1079
+ shanghai: "Asia/Shanghai",
1080
+ china: "Asia/Shanghai",
1081
+ guangzhou: "Asia/Shanghai",
1082
+ shenzhen: "Asia/Shanghai",
1083
+ "hong kong": "Asia/Hong_Kong",
1084
+ hongkong: "Asia/Hong_Kong",
1085
+ taipei: "Asia/Taipei",
1086
+ taiwan: "Asia/Taipei",
1087
+ singapore: "Asia/Singapore",
1088
+ bangkok: "Asia/Bangkok",
1089
+ thailand: "Asia/Bangkok",
1090
+ "kuala lumpur": "Asia/Kuala_Lumpur",
1091
+ kl: "Asia/Kuala_Lumpur",
1092
+ malaysia: "Asia/Kuala_Lumpur",
1093
+ jakarta: "Asia/Jakarta",
1094
+ indonesia: "Asia/Jakarta",
1095
+ manila: "Asia/Manila",
1096
+ philippines: "Asia/Manila",
1097
+ hanoi: "Asia/Ho_Chi_Minh",
1098
+ "ho chi minh": "Asia/Ho_Chi_Minh",
1099
+ vietnam: "Asia/Ho_Chi_Minh",
1100
+ saigon: "Asia/Ho_Chi_Minh",
1101
+ mumbai: "Asia/Kolkata",
1102
+ delhi: "Asia/Kolkata",
1103
+ "new delhi": "Asia/Kolkata",
1104
+ india: "Asia/Kolkata",
1105
+ bangalore: "Asia/Kolkata",
1106
+ bengaluru: "Asia/Kolkata",
1107
+ hyderabad: "Asia/Kolkata",
1108
+ chennai: "Asia/Kolkata",
1109
+ kolkata: "Asia/Kolkata",
1110
+ pune: "Asia/Kolkata",
1111
+ ahmedabad: "Asia/Kolkata",
1112
+ karachi: "Asia/Karachi",
1113
+ lahore: "Asia/Karachi",
1114
+ islamabad: "Asia/Karachi",
1115
+ pakistan: "Asia/Karachi",
1116
+ dhaka: "Asia/Dhaka",
1117
+ bangladesh: "Asia/Dhaka",
1118
+ colombo: "Asia/Colombo",
1119
+ "sri lanka": "Asia/Colombo",
1120
+ kathmandu: "Asia/Kathmandu",
1121
+ nepal: "Asia/Kathmandu",
1122
+ dubai: "Asia/Dubai",
1123
+ "abu dhabi": "Asia/Dubai",
1124
+ uae: "Asia/Dubai",
1125
+ riyadh: "Asia/Riyadh",
1126
+ "saudi arabia": "Asia/Riyadh",
1127
+ jeddah: "Asia/Riyadh",
1128
+ doha: "Asia/Qatar",
1129
+ qatar: "Asia/Qatar",
1130
+ muscat: "Asia/Muscat",
1131
+ oman: "Asia/Muscat",
1132
+ kuwait: "Asia/Kuwait",
1133
+ bahrain: "Asia/Bahrain",
1134
+ tehran: "Asia/Tehran",
1135
+ iran: "Asia/Tehran",
1136
+ baghdad: "Asia/Baghdad",
1137
+ iraq: "Asia/Baghdad",
1138
+ jerusalem: "Asia/Jerusalem",
1139
+ "tel aviv": "Asia/Jerusalem",
1140
+ israel: "Asia/Jerusalem",
1141
+ amman: "Asia/Amman",
1142
+ jordan: "Asia/Amman",
1143
+ beirut: "Asia/Beirut",
1144
+ lebanon: "Asia/Beirut",
1145
+ kabul: "Asia/Kabul",
1146
+ afghanistan: "Asia/Kabul",
1147
+ tashkent: "Asia/Tashkent",
1148
+ uzbekistan: "Asia/Tashkent",
1149
+ almaty: "Asia/Almaty",
1150
+ kazakhstan: "Asia/Almaty",
1151
+ yangon: "Asia/Yangon",
1152
+ myanmar: "Asia/Yangon",
1153
+ phnom_penh: "Asia/Phnom_Penh",
1154
+ cambodia: "Asia/Phnom_Penh",
1155
+ // ─── Africa ───────────────────────────────────────────
1156
+ cairo: "Africa/Cairo",
1157
+ egypt: "Africa/Cairo",
1158
+ lagos: "Africa/Lagos",
1159
+ nigeria: "Africa/Lagos",
1160
+ nairobi: "Africa/Nairobi",
1161
+ kenya: "Africa/Nairobi",
1162
+ johannesburg: "Africa/Johannesburg",
1163
+ "south africa": "Africa/Johannesburg",
1164
+ "cape town": "Africa/Johannesburg",
1165
+ accra: "Africa/Accra",
1166
+ ghana: "Africa/Accra",
1167
+ addis_ababa: "Africa/Addis_Ababa",
1168
+ ethiopia: "Africa/Addis_Ababa",
1169
+ "addis ababa": "Africa/Addis_Ababa",
1170
+ casablanca: "Africa/Casablanca",
1171
+ morocco: "Africa/Casablanca",
1172
+ tunis: "Africa/Tunis",
1173
+ tunisia: "Africa/Tunis",
1174
+ algiers: "Africa/Algiers",
1175
+ algeria: "Africa/Algiers",
1176
+ "dar es salaam": "Africa/Dar_es_Salaam",
1177
+ tanzania: "Africa/Dar_es_Salaam",
1178
+ kampala: "Africa/Kampala",
1179
+ uganda: "Africa/Kampala",
1180
+ kigali: "Africa/Kigali",
1181
+ rwanda: "Africa/Kigali",
1182
+ // ─── Oceania ──────────────────────────────────────────
1183
+ sydney: "Australia/Sydney",
1184
+ australia: "Australia/Sydney",
1185
+ melbourne: "Australia/Melbourne",
1186
+ brisbane: "Australia/Brisbane",
1187
+ perth: "Australia/Perth",
1188
+ adelaide: "Australia/Adelaide",
1189
+ auckland: "Pacific/Auckland",
1190
+ "new zealand": "Pacific/Auckland",
1191
+ wellington: "Pacific/Auckland",
1192
+ fiji: "Pacific/Fiji",
1193
+ suva: "Pacific/Fiji"
1194
+ };
1195
+ var TZ_ABBREVIATIONS = {
1196
+ utc: "UTC",
1197
+ gmt: "UTC",
1198
+ est: "America/New_York",
1199
+ edt: "America/New_York",
1200
+ et: "America/New_York",
1201
+ cst: "America/Chicago",
1202
+ cdt: "America/Chicago",
1203
+ ct: "America/Chicago",
1204
+ mst: "America/Denver",
1205
+ mdt: "America/Denver",
1206
+ mt: "America/Denver",
1207
+ pst: "America/Los_Angeles",
1208
+ pdt: "America/Los_Angeles",
1209
+ pt: "America/Los_Angeles",
1210
+ akst: "America/Anchorage",
1211
+ akdt: "America/Anchorage",
1212
+ hst: "Pacific/Honolulu",
1213
+ ist: "Asia/Kolkata",
1214
+ // Indian Standard Time (most common usage)
1215
+ cet: "Europe/Paris",
1216
+ cest: "Europe/Paris",
1217
+ eet: "Europe/Athens",
1218
+ eest: "Europe/Athens",
1219
+ wet: "Europe/Lisbon",
1220
+ west: "Europe/Lisbon",
1221
+ bst: "Europe/London",
1222
+ // British Summer Time
1223
+ gst: "Asia/Dubai",
1224
+ // Gulf Standard Time
1225
+ jst: "Asia/Tokyo",
1226
+ kst: "Asia/Seoul",
1227
+ cst_china: "Asia/Shanghai",
1228
+ // Disambiguated
1229
+ hkt: "Asia/Hong_Kong",
1230
+ sgt: "Asia/Singapore",
1231
+ ict: "Asia/Bangkok",
1232
+ wib: "Asia/Jakarta",
1233
+ pht: "Asia/Manila",
1234
+ nzst: "Pacific/Auckland",
1235
+ nzdt: "Pacific/Auckland",
1236
+ aest: "Australia/Sydney",
1237
+ aedt: "Australia/Sydney",
1238
+ acst: "Australia/Adelaide",
1239
+ acdt: "Australia/Adelaide",
1240
+ awst: "Australia/Perth",
1241
+ ast: "America/Halifax",
1242
+ // Atlantic Standard Time
1243
+ nst: "America/St_Johns",
1244
+ // Newfoundland
1245
+ brt: "America/Sao_Paulo",
1246
+ art: "America/Argentina/Buenos_Aires",
1247
+ msk: "Europe/Moscow",
1248
+ irst: "Asia/Tehran",
1249
+ pkt: "Asia/Karachi",
1250
+ npt: "Asia/Kathmandu",
1251
+ bdt: "Asia/Dhaka",
1252
+ mmt: "Asia/Yangon",
1253
+ cat: "Africa/Nairobi",
1254
+ // Central Africa Time
1255
+ eat: "Africa/Nairobi",
1256
+ // East Africa Time
1257
+ wat: "Africa/Lagos",
1258
+ // West Africa Time
1259
+ sast: "Africa/Johannesburg"
1260
+ };
1261
+ var COUNTRY_TZ = {
1262
+ us: "America/New_York",
1263
+ usa: "America/New_York",
1264
+ "united states": "America/New_York",
1265
+ america: "America/New_York",
1266
+ canada: "America/Toronto",
1267
+ mexico: "America/Mexico_City",
1268
+ brazil: "America/Sao_Paulo",
1269
+ uk: "Europe/London",
1270
+ "united kingdom": "Europe/London",
1271
+ britain: "Europe/London",
1272
+ england: "Europe/London",
1273
+ france: "Europe/Paris",
1274
+ germany: "Europe/Berlin",
1275
+ italy: "Europe/Rome",
1276
+ spain: "Europe/Madrid",
1277
+ netherlands: "Europe/Amsterdam",
1278
+ belgium: "Europe/Brussels",
1279
+ switzerland: "Europe/Zurich",
1280
+ portugal: "Europe/Lisbon",
1281
+ ireland: "Europe/Dublin",
1282
+ austria: "Europe/Vienna",
1283
+ sweden: "Europe/Stockholm",
1284
+ norway: "Europe/Oslo",
1285
+ denmark: "Europe/Copenhagen",
1286
+ finland: "Europe/Helsinki",
1287
+ poland: "Europe/Warsaw",
1288
+ czechia: "Europe/Prague",
1289
+ hungary: "Europe/Budapest",
1290
+ romania: "Europe/Bucharest",
1291
+ greece: "Europe/Athens",
1292
+ turkey: "Europe/Istanbul",
1293
+ russia: "Europe/Moscow",
1294
+ ukraine: "Europe/Kyiv",
1295
+ india: "Asia/Kolkata",
1296
+ pakistan: "Asia/Karachi",
1297
+ bangladesh: "Asia/Dhaka",
1298
+ china: "Asia/Shanghai",
1299
+ japan: "Asia/Tokyo",
1300
+ "south korea": "Asia/Seoul",
1301
+ korea: "Asia/Seoul",
1302
+ indonesia: "Asia/Jakarta",
1303
+ malaysia: "Asia/Kuala_Lumpur",
1304
+ singapore: "Asia/Singapore",
1305
+ thailand: "Asia/Bangkok",
1306
+ vietnam: "Asia/Ho_Chi_Minh",
1307
+ philippines: "Asia/Manila",
1308
+ uae: "Asia/Dubai",
1309
+ "saudi arabia": "Asia/Riyadh",
1310
+ qatar: "Asia/Qatar",
1311
+ israel: "Asia/Jerusalem",
1312
+ iran: "Asia/Tehran",
1313
+ iraq: "Asia/Baghdad",
1314
+ australia: "Australia/Sydney",
1315
+ "new zealand": "Pacific/Auckland",
1316
+ egypt: "Africa/Cairo",
1317
+ nigeria: "Africa/Lagos",
1318
+ kenya: "Africa/Nairobi",
1319
+ "south africa": "Africa/Johannesburg",
1320
+ ghana: "Africa/Accra",
1321
+ ethiopia: "Africa/Addis_Ababa"
1322
+ };
1323
+ function resolveTimezone(name) {
1324
+ const lower = name.toLowerCase().trim();
1325
+ if (lower.includes("/")) {
1326
+ try {
1327
+ Intl.DateTimeFormat(void 0, { timeZone: name });
1328
+ return name;
1329
+ } catch {
1330
+ }
1331
+ }
1332
+ if (TZ_ABBREVIATIONS[lower]) return TZ_ABBREVIATIONS[lower];
1333
+ if (TIMEZONE_MAP[lower]) return TIMEZONE_MAP[lower];
1334
+ if (COUNTRY_TZ[lower]) return COUNTRY_TZ[lower];
1335
+ return null;
1336
+ }
1337
+
1338
+ // src/providers/default.ts
1339
+ async function fetchJSON(url, timeoutMs = 8e3) {
1340
+ const controller = new AbortController();
1341
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
1342
+ try {
1343
+ const res = await fetch(url, { signal: controller.signal });
1344
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
1345
+ return await res.json();
1346
+ } finally {
1347
+ clearTimeout(timer);
1348
+ }
1349
+ }
1350
+ async function withFallback(fns) {
1351
+ let lastError;
1352
+ for (const fn of fns) {
1353
+ try {
1354
+ return await fn();
1355
+ } catch (err) {
1356
+ lastError = err instanceof Error ? err : new Error(String(err));
1357
+ }
1358
+ }
1359
+ throw lastError ?? new Error("All providers failed");
1360
+ }
1361
+ async function frankfurterRate(base, target) {
1362
+ const data = await fetchJSON(
1363
+ `https://api.frankfurter.dev/v1/latest?base=${base}&symbols=${target}`
1364
+ );
1365
+ const rate = data?.rates?.[target];
1366
+ if (typeof rate !== "number") throw new Error("Rate not found");
1367
+ return rate;
1368
+ }
1369
+ async function exchangeRateApiRate(base, target) {
1370
+ const data = await fetchJSON(
1371
+ `https://open.er-api.com/v6/latest/${base}`
1372
+ );
1373
+ const rate = data?.rates?.[target];
1374
+ if (typeof rate !== "number") throw new Error("Rate not found");
1375
+ return rate;
1376
+ }
1377
+ async function fawazCurrencyRate(base, target) {
1378
+ const b = base.toLowerCase();
1379
+ const t = target.toLowerCase();
1380
+ const data = await fetchJSON(
1381
+ `https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/${b}.json`
1382
+ );
1383
+ const rate = data?.[b]?.[t];
1384
+ if (typeof rate !== "number") throw new Error("Rate not found");
1385
+ return rate;
1386
+ }
1387
+ var COINGECKO_IDS = {
1388
+ BTC: "bitcoin",
1389
+ ETH: "ethereum",
1390
+ SOL: "solana",
1391
+ XRP: "ripple",
1392
+ USDT: "tether",
1393
+ USDC: "usd-coin",
1394
+ BNB: "binancecoin",
1395
+ DOGE: "dogecoin",
1396
+ ADA: "cardano",
1397
+ MATIC: "matic-network",
1398
+ DOT: "polkadot",
1399
+ LTC: "litecoin",
1400
+ AVAX: "avalanche-2",
1401
+ LINK: "chainlink",
1402
+ UNI: "uniswap",
1403
+ ATOM: "cosmos",
1404
+ XLM: "stellar",
1405
+ ALGO: "algorand",
1406
+ FIL: "filecoin",
1407
+ NEAR: "near",
1408
+ APT: "aptos",
1409
+ ARB: "arbitrum",
1410
+ OP: "optimism",
1411
+ SUI: "sui",
1412
+ SHIB: "shiba-inu",
1413
+ PEPE: "pepe",
1414
+ TRX: "tron",
1415
+ TON: "the-open-network",
1416
+ HBAR: "hedera-hashgraph",
1417
+ ICP: "internet-computer",
1418
+ VET: "vechain",
1419
+ AAVE: "aave",
1420
+ MKR: "maker",
1421
+ CRV: "curve-dao-token",
1422
+ SNX: "havven",
1423
+ COMP: "compound-governance-token",
1424
+ SAND: "the-sandbox",
1425
+ MANA: "decentraland",
1426
+ AXS: "axie-infinity",
1427
+ APE: "apecoin",
1428
+ FTM: "fantom",
1429
+ ONE: "harmony",
1430
+ KAVA: "kava",
1431
+ ROSE: "oasis-network",
1432
+ ZEC: "zcash",
1433
+ XMR: "monero",
1434
+ DASH: "dash",
1435
+ ETC: "ethereum-classic",
1436
+ BCH: "bitcoin-cash",
1437
+ BSV: "bitcoin-cash-sv"
1438
+ };
1439
+ var COINGECKO_FIATS = /* @__PURE__ */ new Set([
1440
+ "usd",
1441
+ "eur",
1442
+ "gbp",
1443
+ "jpy",
1444
+ "aud",
1445
+ "cad",
1446
+ "chf",
1447
+ "cny",
1448
+ "hkd",
1449
+ "nzd",
1450
+ "sek",
1451
+ "krw",
1452
+ "sgd",
1453
+ "nok",
1454
+ "mxn",
1455
+ "inr",
1456
+ "rub",
1457
+ "zar",
1458
+ "try",
1459
+ "brl",
1460
+ "twd",
1461
+ "dkk",
1462
+ "pln",
1463
+ "thb",
1464
+ "idr",
1465
+ "huf",
1466
+ "czk",
1467
+ "ils",
1468
+ "clp",
1469
+ "php",
1470
+ "aed",
1471
+ "sar",
1472
+ "myr",
1473
+ "ars",
1474
+ "ngn",
1475
+ "pkr",
1476
+ "bdt",
1477
+ "vnd",
1478
+ "egp",
1479
+ "uah",
1480
+ "btc",
1481
+ "eth",
1482
+ "bnb",
1483
+ "xrp",
1484
+ "sol",
1485
+ "dot",
1486
+ "ltc"
1487
+ ]);
1488
+ async function coingeckoRate(from, to) {
1489
+ const fromId = COINGECKO_IDS[from];
1490
+ const toId = COINGECKO_IDS[to];
1491
+ if (fromId) {
1492
+ const vsCurrency = toId ? to.toLowerCase() : to.toLowerCase();
1493
+ if (!COINGECKO_FIATS.has(vsCurrency) && !toId) {
1494
+ throw new Error(`CoinGecko: unsupported target ${to}`);
1495
+ }
1496
+ const target = toId ? to.toLowerCase() : to.toLowerCase();
1497
+ const data = await fetchJSON(
1498
+ `https://api.coingecko.com/api/v3/simple/price?ids=${fromId}&vs_currencies=${target}`
1499
+ );
1500
+ const rate = data?.[fromId]?.[target];
1501
+ if (typeof rate !== "number") throw new Error("CoinGecko: rate not found");
1502
+ return rate;
1503
+ }
1504
+ if (toId) {
1505
+ const fiat = from.toLowerCase();
1506
+ if (!COINGECKO_FIATS.has(fiat)) {
1507
+ throw new Error(`CoinGecko: unsupported source ${from}`);
1508
+ }
1509
+ const data = await fetchJSON(
1510
+ `https://api.coingecko.com/api/v3/simple/price?ids=${toId}&vs_currencies=${fiat}`
1511
+ );
1512
+ const priceInFiat = data?.[toId]?.[fiat];
1513
+ if (typeof priceInFiat !== "number" || priceInFiat === 0) throw new Error("CoinGecko: rate not found");
1514
+ return 1 / priceInFiat;
1515
+ }
1516
+ throw new Error(`CoinGecko: unknown pair ${from}/${to}`);
1517
+ }
1518
+ function binanceSymbol(from, to) {
1519
+ return `${from}${to}`;
1520
+ }
1521
+ async function binanceRate(from, to) {
1522
+ const tryDirect = async (a, b) => {
1523
+ try {
1524
+ const data = await fetchJSON(
1525
+ `https://api.binance.com/api/v3/ticker/price?symbol=${binanceSymbol(a, b)}`
1526
+ );
1527
+ const p = parseFloat(data?.price);
1528
+ return isNaN(p) ? null : p;
1529
+ } catch {
1530
+ return null;
1531
+ }
1532
+ };
1533
+ let rate = await tryDirect(from, to);
1534
+ if (rate !== null) return rate;
1535
+ rate = await tryDirect(to, from);
1536
+ if (rate !== null && rate !== 0) return 1 / rate;
1537
+ if (from !== "USDT" && to !== "USDT") {
1538
+ const fromUsdt = await tryDirect(from, "USDT");
1539
+ const toUsdt = await tryDirect(to, "USDT");
1540
+ if (fromUsdt !== null && toUsdt !== null && toUsdt !== 0) {
1541
+ return fromUsdt / toUsdt;
1542
+ }
1543
+ }
1544
+ throw new Error(`Binance: no pair found for ${from}/${to}`);
1545
+ }
1546
+ async function coincapRate(from, to) {
1547
+ const COINCAP_IDS = {
1548
+ BTC: "bitcoin",
1549
+ ETH: "ethereum",
1550
+ SOL: "solana",
1551
+ XRP: "xrp",
1552
+ USDT: "tether",
1553
+ USDC: "usd-coin",
1554
+ BNB: "binance-coin",
1555
+ DOGE: "dogecoin",
1556
+ ADA: "cardano",
1557
+ DOT: "polkadot",
1558
+ LTC: "litecoin",
1559
+ AVAX: "avalanche",
1560
+ LINK: "chainlink",
1561
+ UNI: "uniswap",
1562
+ ATOM: "cosmos",
1563
+ XLM: "stellar",
1564
+ MATIC: "polygon",
1565
+ SHIB: "shiba-inu",
1566
+ TRX: "tron",
1567
+ TON: "toncoin",
1568
+ BCH: "bitcoin-cash",
1569
+ ETC: "ethereum-classic",
1570
+ XMR: "monero",
1571
+ ZEC: "zcash"
1572
+ };
1573
+ const getUsdPrice = async (ticker) => {
1574
+ if (ticker === "USD") return 1;
1575
+ const id = COINCAP_IDS[ticker];
1576
+ if (!id) throw new Error(`CoinCap: unknown ${ticker}`);
1577
+ const data = await fetchJSON(
1578
+ `https://api.coincap.io/v2/assets/${id}`
1579
+ );
1580
+ const price = parseFloat(data?.data?.priceUsd);
1581
+ if (isNaN(price)) throw new Error(`CoinCap: no price for ${ticker}`);
1582
+ return price;
1583
+ };
1584
+ const isFiat = (t) => !COINCAP_IDS[t] && t !== "USD";
1585
+ if (to === "USD") {
1586
+ return getUsdPrice(from);
1587
+ }
1588
+ if (isFiat(to)) {
1589
+ throw new Error("CoinCap: fiat target not directly supported");
1590
+ }
1591
+ if (from === "USD") {
1592
+ const price = await getUsdPrice(to);
1593
+ return price === 0 ? 0 : 1 / price;
1594
+ }
1595
+ const fromUsd = await getUsdPrice(from);
1596
+ const toUsd = await getUsdPrice(to);
1597
+ if (toUsd === 0) throw new Error("CoinCap: zero price");
1598
+ return fromUsd / toUsd;
1599
+ }
1600
+ async function getCryptoRateWithFiatFallback(from, to, getFiat) {
1601
+ const CRYPTO_SET = new Set(Object.keys(COINGECKO_IDS));
1602
+ const fromIsCrypto = CRYPTO_SET.has(from);
1603
+ const toIsCrypto = CRYPTO_SET.has(to);
1604
+ const toIsFiat = !toIsCrypto;
1605
+ const fromIsFiat = !fromIsCrypto;
1606
+ try {
1607
+ return await withFallback([
1608
+ () => coingeckoRate(from, to),
1609
+ () => binanceRate(from, to),
1610
+ () => coincapRate(from, to)
1611
+ ]);
1612
+ } catch {
1613
+ }
1614
+ if (fromIsCrypto && toIsFiat) {
1615
+ const cryptoToUsd = await withFallback([
1616
+ () => coingeckoRate(from, "USD"),
1617
+ () => binanceRate(from, "USDT"),
1618
+ () => coincapRate(from, "USD")
1619
+ ]);
1620
+ if (to === "USD" || to === "USDT" || to === "USDC") return cryptoToUsd;
1621
+ const usdToFiat = await getFiat("USD", to);
1622
+ return cryptoToUsd * usdToFiat;
1623
+ }
1624
+ if (fromIsFiat && toIsCrypto) {
1625
+ const fiatToUsd = from === "USD" ? 1 : await getFiat(from, "USD");
1626
+ const usdToCrypto = await withFallback([
1627
+ () => coingeckoRate("USD", to).then((r) => r === 0 ? Promise.reject() : r),
1628
+ async () => {
1629
+ const p = await coingeckoRate(to, "USD");
1630
+ return p === 0 ? Promise.reject("zero") : 1 / p;
1631
+ },
1632
+ async () => {
1633
+ const p = await coincapRate(to, "USD");
1634
+ return p === 0 ? Promise.reject("zero") : 1 / p;
1635
+ }
1636
+ ]);
1637
+ return fiatToUsd * usdToCrypto;
1638
+ }
1639
+ throw new Error(`Could not resolve rate for ${from} \u2192 ${to}`);
1640
+ }
1641
+ function createDefaultProvider() {
1642
+ return {
1643
+ async getFiatRate(base, target) {
1644
+ return withFallback([
1645
+ () => frankfurterRate(base, target),
1646
+ () => exchangeRateApiRate(base, target),
1647
+ () => fawazCurrencyRate(base, target)
1648
+ ]);
1649
+ },
1650
+ async getCryptoRate(base, target) {
1651
+ const getFiat = (b, t) => withFallback([
1652
+ () => frankfurterRate(b, t),
1653
+ () => exchangeRateApiRate(b, t),
1654
+ () => fawazCurrencyRate(b, t)
1655
+ ]);
1656
+ return getCryptoRateWithFiatFallback(base, target, getFiat);
1657
+ }
1658
+ };
1659
+ }
1660
+
1661
+ // src/parser/intent.ts
1662
+ function detectIntent(input) {
1663
+ const trimmed = input.trim();
1664
+ if (!trimmed) {
1665
+ return { kind: "math", expression: "0" };
1666
+ }
1667
+ return tryTimeIntent(trimmed) ?? tryDateIntent(trimmed) ?? tryCurrencyOrCryptoIntent(trimmed) ?? tryUnitIntent(trimmed) ?? { kind: "math", expression: trimmed };
1668
+ }
1669
+ var TIME_IN_PATTERN = /^(?:what(?:'s| is) )?(?:the )?(?:current )?time (?:in|at) (.+)$/i;
1670
+ var TIME_CONVERT_PATTERN = /^(.+?) to (.+?) time$/i;
1671
+ var TIME_NOW_PATTERN = /^(?:what(?:'s| is) )?(?:the )?(?:current )?time(?: now)?$/i;
1672
+ function tryTimeIntent(input) {
1673
+ let match;
1674
+ match = input.match(TIME_IN_PATTERN);
1675
+ if (match) {
1676
+ const place = match[1].trim();
1677
+ const tz2 = resolveTimezone(place);
1678
+ if (tz2) return { kind: "time", query: place, to: tz2 };
1679
+ return { kind: "time", query: place, to: place };
1680
+ }
1681
+ match = input.match(TIME_CONVERT_PATTERN);
1682
+ if (match) {
1683
+ const from = match[1].trim();
1684
+ const to = match[2].trim();
1685
+ const fromTz = resolveTimezone(from);
1686
+ const toTz = resolveTimezone(to);
1687
+ if (fromTz || toTz) {
1688
+ return { kind: "time", query: input, from: fromTz ?? from, to: toTz ?? to };
1689
+ }
1690
+ }
1691
+ match = input.match(TIME_NOW_PATTERN);
1692
+ if (match) {
1693
+ return { kind: "time", query: input };
1694
+ }
1695
+ if (/^time\s/i.test(input)) {
1696
+ return { kind: "time", query: input };
1697
+ }
1698
+ const placeSuffixMatch = input.match(/^(.+?)\s+(?:time|now|time now)$/i);
1699
+ if (placeSuffixMatch) {
1700
+ const place = placeSuffixMatch[1].trim();
1701
+ const tz2 = resolveTimezone(place);
1702
+ if (tz2) return { kind: "time", query: place, to: tz2 };
1703
+ }
1704
+ const tz = resolveTimezone(input);
1705
+ if (tz) {
1706
+ return { kind: "time", query: input, to: tz };
1707
+ }
1708
+ return null;
1709
+ }
1710
+ var DATE_PATTERNS = [
1711
+ // Relative dates
1712
+ /^(today|now|tomorrow|yesterday)$/i,
1713
+ /^(next|last|this)\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday|week|month|year)$/i,
1714
+ /^(\d+)\s+(days?|weeks?|months?|years?|hours?|minutes?|seconds?)\s+(from now|ago|from today|from tomorrow)$/i,
1715
+ /^in\s+(\d+)\s+(days?|weeks?|months?|years?|hours?|minutes?|seconds?)$/i,
1716
+ // Unix timestamp
1717
+ /^(?:unix\s+)?(?:timestamp\s+)?(\d{10,13})$/i,
1718
+ /^(?:unix|timestamp|epoch)\s+(\d{10,13})$/i,
1719
+ // "to unix" / "to timestamp"
1720
+ /^.+\s+(?:to|in)\s+(?:unix|timestamp|epoch)$/i,
1721
+ // ISO / date strings
1722
+ /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2})?/,
1723
+ // "date" queries
1724
+ /^(?:what(?:'s| is) )?(?:the )?(?:current )?date(?: today)?$/i,
1725
+ // Days between dates
1726
+ /^(?:days?\s+)?(?:between|from)\s+.+\s+(?:to|and|until)\s+.+$/i
1727
+ ];
1728
+ function tryDateIntent(input) {
1729
+ for (const pattern of DATE_PATTERNS) {
1730
+ if (pattern.test(input)) {
1731
+ return { kind: "date", query: input };
1732
+ }
1733
+ }
1734
+ return null;
1735
+ }
1736
+ var CONVERSION_PATTERN = /^([\d.,]+)?\s*([a-zA-Z$€£¥₹₩₽₺₦₵₪฿]+(?:\s+[a-zA-Z]+)?)\s+(?:to|in|into|as|=)\s+([a-zA-Z$€£¥₹₩₽₺₦₵₪฿]+(?:\s+[a-zA-Z]+)?)$/i;
1737
+ function tryCurrencyOrCryptoIntent(input) {
1738
+ const match = input.match(CONVERSION_PATTERN);
1739
+ if (!match) return null;
1740
+ const amount = match[1] ? parseFloat(match[1].replace(/,/g, "")) : 1;
1741
+ const fromToken = match[2].trim();
1742
+ const toToken = match[3].trim();
1743
+ const fromCrypto = resolveCrypto(fromToken);
1744
+ const toCrypto = resolveCrypto(toToken);
1745
+ const fromFiat = resolveFiat(fromToken);
1746
+ const toFiat = resolveFiat(toToken);
1747
+ if (fromCrypto && (toCrypto || toFiat)) {
1748
+ return { kind: "crypto", amount, from: fromCrypto, to: toCrypto ?? toFiat };
1749
+ }
1750
+ if (fromFiat && toCrypto) {
1751
+ return { kind: "crypto", amount, from: fromFiat, to: toCrypto };
1752
+ }
1753
+ if (fromFiat && toFiat) {
1754
+ return { kind: "currency", amount, from: fromFiat, to: toFiat };
1755
+ }
1756
+ return null;
1757
+ }
1758
+ var UNIT_PATTERN = /^(-?[\d.,]+)\s*([a-zA-Z°/µμ'"²³]+(?:\s+[a-zA-Z]+(?:\s+[a-zA-Z]+)?)?)\s+(?:to|in|into|as|=)\s+([a-zA-Z°/µμ'"²³]+(?:\s+[a-zA-Z]+(?:\s+[a-zA-Z]+)?)?)$/i;
1759
+ var UNIT_PATTERN_NO_SPACE = /^(-?[\d.,]+)([a-zA-Z°]+)\s+(?:to|in|into|as)\s+([a-zA-Z°]+(?:\s+[a-zA-Z]+)?)$/i;
1760
+ function tryUnitIntent(input) {
1761
+ const match = input.match(UNIT_PATTERN) || input.match(UNIT_PATTERN_NO_SPACE);
1762
+ if (!match) return null;
1763
+ const amount = parseFloat(match[1].replace(/,/g, ""));
1764
+ const fromToken = match[2].trim().toLowerCase();
1765
+ const toToken = match[3].trim().toLowerCase();
1766
+ if (resolveFiat(fromToken) || resolveCrypto(fromToken)) return null;
1767
+ if (resolveFiat(toToken) || resolveCrypto(toToken)) return null;
1768
+ const fromUnit = lookupUnit(fromToken);
1769
+ const toUnit = lookupUnit(toToken);
1770
+ if (fromUnit && toUnit && fromUnit.category === toUnit.category) {
1771
+ return {
1772
+ kind: "unit",
1773
+ amount,
1774
+ from: fromToken,
1775
+ to: toToken,
1776
+ category: fromUnit.category.name
1777
+ };
1778
+ }
1779
+ return null;
1780
+ }
1781
+
1782
+ // src/evaluators/math.ts
1783
+ var CONSTANTS = {
1784
+ pi: Math.PI,
1785
+ \u03C0: Math.PI,
1786
+ e: Math.E,
1787
+ tau: Math.PI * 2,
1788
+ \u03C4: Math.PI * 2,
1789
+ phi: (1 + Math.sqrt(5)) / 2,
1790
+ \u03C6: (1 + Math.sqrt(5)) / 2,
1791
+ inf: Infinity,
1792
+ infinity: Infinity
1793
+ };
1794
+ var FUNCTIONS = {
1795
+ sqrt: Math.sqrt,
1796
+ cbrt: Math.cbrt,
1797
+ abs: Math.abs,
1798
+ ceil: Math.ceil,
1799
+ floor: Math.floor,
1800
+ round: Math.round,
1801
+ trunc: Math.trunc,
1802
+ sign: Math.sign,
1803
+ log: Math.log10,
1804
+ log2: Math.log2,
1805
+ log10: Math.log10,
1806
+ ln: Math.log,
1807
+ exp: Math.exp,
1808
+ sin: Math.sin,
1809
+ cos: Math.cos,
1810
+ tan: Math.tan,
1811
+ asin: Math.asin,
1812
+ acos: Math.acos,
1813
+ atan: Math.atan,
1814
+ sinh: Math.sinh,
1815
+ cosh: Math.cosh,
1816
+ tanh: Math.tanh,
1817
+ asinh: Math.asinh,
1818
+ acosh: Math.acosh,
1819
+ atanh: Math.atanh
1820
+ };
1821
+ var FUNCTIONS2 = {
1822
+ pow: Math.pow,
1823
+ max: Math.max,
1824
+ min: Math.min,
1825
+ atan2: Math.atan2,
1826
+ mod: (a, b) => (a % b + b) % b
1827
+ };
1828
+ var Parser = class {
1829
+ pos = 0;
1830
+ expr;
1831
+ constructor(expression) {
1832
+ this.expr = expression.replace(/×/g, "*").replace(/÷/g, "/").replace(/—/g, "-").replace(/\*\*/g, "^");
1833
+ }
1834
+ parse() {
1835
+ const result = this.parseBitwiseOr();
1836
+ this.skipWhitespace();
1837
+ if (this.pos < this.expr.length) {
1838
+ throw new Error(`Unexpected character: '${this.expr[this.pos]}' at position ${this.pos}`);
1839
+ }
1840
+ return result;
1841
+ }
1842
+ skipWhitespace() {
1843
+ while (this.pos < this.expr.length && /\s/.test(this.expr[this.pos])) {
1844
+ this.pos++;
1845
+ }
1846
+ }
1847
+ peek() {
1848
+ this.skipWhitespace();
1849
+ return this.expr[this.pos] ?? "";
1850
+ }
1851
+ consume(expected) {
1852
+ this.skipWhitespace();
1853
+ const ch = this.expr[this.pos];
1854
+ if (expected && ch !== expected) {
1855
+ throw new Error(`Expected '${expected}' at position ${this.pos}, got '${ch ?? "end"}'`);
1856
+ }
1857
+ this.pos++;
1858
+ return ch;
1859
+ }
1860
+ // Bitwise OR: expr | expr
1861
+ parseBitwiseOr() {
1862
+ let left = this.parseBitwiseXor();
1863
+ while (this.peek() === "|") {
1864
+ this.consume();
1865
+ left = left | this.parseBitwiseXor();
1866
+ }
1867
+ return left;
1868
+ }
1869
+ // Bitwise XOR (not used commonly, but supported)
1870
+ parseBitwiseXor() {
1871
+ let left = this.parseBitwiseAnd();
1872
+ return left;
1873
+ }
1874
+ // Bitwise AND: expr & expr
1875
+ parseBitwiseAnd() {
1876
+ let left = this.parseBitwiseShift();
1877
+ while (this.peek() === "&") {
1878
+ this.consume();
1879
+ left = left & this.parseBitwiseShift();
1880
+ }
1881
+ return left;
1882
+ }
1883
+ // Bitwise shift: << >>
1884
+ parseBitwiseShift() {
1885
+ let left = this.parseAddition();
1886
+ while (true) {
1887
+ this.skipWhitespace();
1888
+ if (this.expr[this.pos] === "<" && this.expr[this.pos + 1] === "<") {
1889
+ this.pos += 2;
1890
+ left = left << this.parseAddition();
1891
+ } else if (this.expr[this.pos] === ">" && this.expr[this.pos + 1] === ">") {
1892
+ this.pos += 2;
1893
+ left = left >> this.parseAddition();
1894
+ } else {
1895
+ break;
1896
+ }
1897
+ }
1898
+ return left;
1899
+ }
1900
+ // Addition / subtraction
1901
+ parseAddition() {
1902
+ let left = this.parseMultiplication();
1903
+ while (true) {
1904
+ const op = this.peek();
1905
+ if (op === "+") {
1906
+ this.consume();
1907
+ left += this.parseMultiplication();
1908
+ } else if (op === "-") {
1909
+ this.consume();
1910
+ left -= this.parseMultiplication();
1911
+ } else {
1912
+ break;
1913
+ }
1914
+ }
1915
+ return left;
1916
+ }
1917
+ // Multiplication / division / modulo
1918
+ parseMultiplication() {
1919
+ let left = this.parseExponentiation();
1920
+ while (true) {
1921
+ const op = this.peek();
1922
+ if (op === "*") {
1923
+ this.consume();
1924
+ left *= this.parseExponentiation();
1925
+ } else if (op === "/") {
1926
+ this.consume();
1927
+ const right = this.parseExponentiation();
1928
+ if (right === 0) throw new Error("Division by zero");
1929
+ left /= right;
1930
+ } else if (op === "%") {
1931
+ const savedPos = this.pos;
1932
+ this.skipWhitespace();
1933
+ this.pos++;
1934
+ this.skipWhitespace();
1935
+ const next = this.expr[this.pos];
1936
+ if (next === void 0 || /[+\-*/^)|&<>]/.test(next)) {
1937
+ this.pos = savedPos;
1938
+ break;
1939
+ } else {
1940
+ this.pos = savedPos;
1941
+ this.consume();
1942
+ left = left % this.parseExponentiation();
1943
+ }
1944
+ } else {
1945
+ break;
1946
+ }
1947
+ }
1948
+ return left;
1949
+ }
1950
+ // Exponentiation (right-associative)
1951
+ parseExponentiation() {
1952
+ const base = this.parseUnary();
1953
+ if (this.peek() === "^") {
1954
+ this.consume();
1955
+ const exp = this.parseExponentiation();
1956
+ return Math.pow(base, exp);
1957
+ }
1958
+ return base;
1959
+ }
1960
+ // Unary: + - ~
1961
+ parseUnary() {
1962
+ const op = this.peek();
1963
+ if (op === "-") {
1964
+ this.consume();
1965
+ return -this.parseUnary();
1966
+ }
1967
+ if (op === "+") {
1968
+ this.consume();
1969
+ return this.parseUnary();
1970
+ }
1971
+ if (op === "~") {
1972
+ this.consume();
1973
+ return ~this.parseUnary();
1974
+ }
1975
+ return this.parsePostfix();
1976
+ }
1977
+ // Postfix: factorial (!), percentage (%)
1978
+ parsePostfix() {
1979
+ let value = this.parsePrimary();
1980
+ while (true) {
1981
+ this.skipWhitespace();
1982
+ if (this.expr[this.pos] === "!") {
1983
+ this.pos++;
1984
+ value = factorial(value);
1985
+ } else if (this.expr[this.pos] === "%") {
1986
+ this.pos++;
1987
+ value = value / 100;
1988
+ } else {
1989
+ break;
1990
+ }
1991
+ }
1992
+ return value;
1993
+ }
1994
+ // Primary: number, constant, function, parenthesized expr
1995
+ parsePrimary() {
1996
+ this.skipWhitespace();
1997
+ if (this.expr[this.pos] === "(") {
1998
+ this.consume("(");
1999
+ const value = this.parseBitwiseOr();
2000
+ this.consume(")");
2001
+ return value;
2002
+ }
2003
+ if (/[0-9.]/.test(this.expr[this.pos]) || this.expr[this.pos] === "0" && /[xXbBoO]/.test(this.expr[this.pos + 1])) {
2004
+ return this.parseNumber();
2005
+ }
2006
+ if (/[a-zA-Zπτφ_]/.test(this.expr[this.pos])) {
2007
+ return this.parseIdentifier();
2008
+ }
2009
+ throw new Error(`Unexpected character: '${this.expr[this.pos]}' at position ${this.pos}`);
2010
+ }
2011
+ charAt(i) {
2012
+ return i < this.expr.length ? this.expr[i] : "";
2013
+ }
2014
+ parseNumber() {
2015
+ const start = this.pos;
2016
+ if (this.charAt(this.pos) === "0" && /[xX]/.test(this.charAt(this.pos + 1))) {
2017
+ this.pos += 2;
2018
+ while (this.pos < this.expr.length && /[0-9a-fA-F]/.test(this.expr[this.pos])) this.pos++;
2019
+ return parseInt(this.expr.slice(start, this.pos), 16);
2020
+ }
2021
+ if (this.charAt(this.pos) === "0" && /[bB]/.test(this.charAt(this.pos + 1))) {
2022
+ this.pos += 2;
2023
+ while (this.pos < this.expr.length && /[01]/.test(this.expr[this.pos])) this.pos++;
2024
+ return parseInt(this.expr.slice(start + 2, this.pos), 2);
2025
+ }
2026
+ if (this.charAt(this.pos) === "0" && /[oO]/.test(this.charAt(this.pos + 1))) {
2027
+ this.pos += 2;
2028
+ while (this.pos < this.expr.length && /[0-7]/.test(this.expr[this.pos])) this.pos++;
2029
+ return parseInt(this.expr.slice(start + 2, this.pos), 8);
2030
+ }
2031
+ while (this.pos < this.expr.length && /[0-9]/.test(this.expr[this.pos])) this.pos++;
2032
+ if (this.charAt(this.pos) === ".") {
2033
+ this.pos++;
2034
+ while (this.pos < this.expr.length && /[0-9]/.test(this.expr[this.pos])) this.pos++;
2035
+ }
2036
+ if (this.pos < this.expr.length && /[eE]/.test(this.expr[this.pos])) {
2037
+ this.pos++;
2038
+ if (this.pos < this.expr.length && /[+-]/.test(this.expr[this.pos])) this.pos++;
2039
+ while (this.pos < this.expr.length && /[0-9]/.test(this.expr[this.pos])) this.pos++;
2040
+ }
2041
+ const numStr = this.expr.slice(start, this.pos);
2042
+ const num = parseFloat(numStr);
2043
+ if (isNaN(num)) throw new Error(`Invalid number: '${numStr}'`);
2044
+ return num;
2045
+ }
2046
+ parseIdentifier() {
2047
+ const start = this.pos;
2048
+ while (this.pos < this.expr.length && /[a-zA-Zπτφ_0-9]/.test(this.expr[this.pos])) {
2049
+ this.pos++;
2050
+ }
2051
+ const name = this.expr.slice(start, this.pos).toLowerCase();
2052
+ this.skipWhitespace();
2053
+ if (this.expr[this.pos] === "(") {
2054
+ if (FUNCTIONS2[name]) {
2055
+ this.consume("(");
2056
+ const a = this.parseBitwiseOr();
2057
+ this.consume(",");
2058
+ const b = this.parseBitwiseOr();
2059
+ this.consume(")");
2060
+ return FUNCTIONS2[name](a, b);
2061
+ }
2062
+ if (FUNCTIONS[name]) {
2063
+ this.consume("(");
2064
+ const arg = this.parseBitwiseOr();
2065
+ this.consume(")");
2066
+ return FUNCTIONS[name](arg);
2067
+ }
2068
+ throw new Error(`Unknown function: '${name}'`);
2069
+ }
2070
+ if (CONSTANTS[name] !== void 0) return CONSTANTS[name];
2071
+ throw new Error(`Unknown identifier: '${name}'`);
2072
+ }
2073
+ };
2074
+ function factorial(n) {
2075
+ if (n < 0) throw new Error("Factorial of negative number");
2076
+ if (!Number.isInteger(n)) throw new Error("Factorial of non-integer");
2077
+ if (n > 170) return Infinity;
2078
+ let result = 1;
2079
+ for (let i = 2; i <= n; i++) result *= i;
2080
+ return result;
2081
+ }
2082
+ function evaluateMath(expression, locale = "en-US", precision = 10) {
2083
+ try {
2084
+ const parser = new Parser(expression);
2085
+ const result = parser.parse();
2086
+ let formatted;
2087
+ if (Number.isInteger(result) && Math.abs(result) < Number.MAX_SAFE_INTEGER) {
2088
+ formatted = new Intl.NumberFormat(locale).format(result);
2089
+ } else if (!isFinite(result)) {
2090
+ formatted = result.toString();
2091
+ } else {
2092
+ const rounded = parseFloat(result.toPrecision(precision));
2093
+ formatted = new Intl.NumberFormat(locale, {
2094
+ maximumSignificantDigits: precision
2095
+ }).format(rounded);
2096
+ }
2097
+ const metadata = {};
2098
+ if (Number.isInteger(result) && isFinite(result)) {
2099
+ const int = Math.trunc(result);
2100
+ metadata.hex = "0x" + int.toString(16).toUpperCase();
2101
+ metadata.binary = "0b" + int.toString(2);
2102
+ metadata.octal = "0o" + int.toString(8);
2103
+ }
2104
+ return {
2105
+ type: "math",
2106
+ input: expression,
2107
+ result,
2108
+ formatted,
2109
+ metadata
2110
+ };
2111
+ } catch (err) {
2112
+ return {
2113
+ type: "error",
2114
+ input: expression,
2115
+ error: err instanceof Error ? err.message : "Invalid expression"
2116
+ };
2117
+ }
2118
+ }
2119
+
2120
+ // src/evaluators/unit.ts
2121
+ function evaluateUnit(amount, fromToken, toToken, locale = "en-US", precision = 10) {
2122
+ const from = lookupUnit(fromToken);
2123
+ const to = lookupUnit(toToken);
2124
+ if (!from) {
2125
+ return { type: "error", input: `${amount} ${fromToken} to ${toToken}`, error: `Unknown unit: '${fromToken}'` };
2126
+ }
2127
+ if (!to) {
2128
+ return { type: "error", input: `${amount} ${fromToken} to ${toToken}`, error: `Unknown unit: '${toToken}'` };
2129
+ }
2130
+ if (from.category !== to.category) {
2131
+ return {
2132
+ type: "error",
2133
+ input: `${amount} ${fromToken} to ${toToken}`,
2134
+ error: `Cannot convert ${from.category.name} to ${to.category.name}`
2135
+ };
2136
+ }
2137
+ const result = convertUnit(amount, from, to);
2138
+ const inputStr = `${amount} ${fromToken} to ${toToken}`;
2139
+ const rounded = parseFloat(result.toPrecision(precision));
2140
+ const formatted = `${new Intl.NumberFormat(locale, { maximumSignificantDigits: precision }).format(rounded)} ${to.def.name}`;
2141
+ return {
2142
+ type: "unit",
2143
+ input: inputStr,
2144
+ result: rounded,
2145
+ formatted,
2146
+ metadata: {
2147
+ fromUnit: from.def.name,
2148
+ toUnit: to.def.name,
2149
+ category: from.category.name,
2150
+ amount
2151
+ }
2152
+ };
2153
+ }
2154
+
2155
+ // src/evaluators/time.ts
2156
+ function evaluateTime(query, fromTz, toTz, localTz) {
2157
+ const now = /* @__PURE__ */ new Date();
2158
+ const userTz = localTz ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
2159
+ try {
2160
+ if (!fromTz && !toTz) {
2161
+ const formatted = formatTimeInZone(now, userTz);
2162
+ return {
2163
+ type: "time",
2164
+ input: query,
2165
+ result: formatted,
2166
+ formatted,
2167
+ metadata: { timezone: userTz, iso: now.toISOString() }
2168
+ };
2169
+ }
2170
+ if (toTz && !fromTz) {
2171
+ const resolvedTo = resolveTimezone(toTz) ?? toTz;
2172
+ try {
2173
+ const formatted = formatTimeInZone(now, resolvedTo);
2174
+ return {
2175
+ type: "time",
2176
+ input: query,
2177
+ result: formatted,
2178
+ formatted,
2179
+ metadata: { timezone: resolvedTo, iso: now.toISOString() }
2180
+ };
2181
+ } catch {
2182
+ return { type: "error", input: query, error: `Unknown timezone: '${toTz}'` };
2183
+ }
2184
+ }
2185
+ if (fromTz && toTz) {
2186
+ const resolvedFrom = resolveTimezone(fromTz) ?? fromTz;
2187
+ const resolvedTo = resolveTimezone(toTz) ?? toTz;
2188
+ try {
2189
+ const fromTime = formatTimeInZone(now, resolvedFrom);
2190
+ const toTime = formatTimeInZone(now, resolvedTo);
2191
+ const formatted = `${fromTime} \u2192 ${toTime}`;
2192
+ return {
2193
+ type: "time",
2194
+ input: query,
2195
+ result: formatted,
2196
+ formatted,
2197
+ metadata: {
2198
+ from: { timezone: resolvedFrom, time: fromTime },
2199
+ to: { timezone: resolvedTo, time: toTime },
2200
+ iso: now.toISOString()
2201
+ }
2202
+ };
2203
+ } catch {
2204
+ return {
2205
+ type: "error",
2206
+ input: query,
2207
+ error: `Cannot resolve timezone conversion: '${fromTz}' \u2192 '${toTz}'`
2208
+ };
2209
+ }
2210
+ }
2211
+ return { type: "error", input: query, error: "Could not parse time query" };
2212
+ } catch (err) {
2213
+ return {
2214
+ type: "error",
2215
+ input: query,
2216
+ error: err instanceof Error ? err.message : "Time evaluation failed"
2217
+ };
2218
+ }
2219
+ }
2220
+ function formatTimeInZone(date, timezone) {
2221
+ const timePart = new Intl.DateTimeFormat("en-US", {
2222
+ timeZone: timezone,
2223
+ hour: "numeric",
2224
+ minute: "2-digit",
2225
+ second: "2-digit",
2226
+ hour12: true
2227
+ }).format(date);
2228
+ const datePart = new Intl.DateTimeFormat("en-US", {
2229
+ timeZone: timezone,
2230
+ weekday: "short",
2231
+ month: "short",
2232
+ day: "numeric",
2233
+ year: "numeric"
2234
+ }).format(date);
2235
+ const tzAbbrev = getShortTzName(timezone);
2236
+ return `${timePart}, ${datePart} (${tzAbbrev})`;
2237
+ }
2238
+ function getShortTzName(timezone) {
2239
+ try {
2240
+ const parts = new Intl.DateTimeFormat("en-US", {
2241
+ timeZone: timezone,
2242
+ timeZoneName: "short"
2243
+ }).formatToParts(/* @__PURE__ */ new Date());
2244
+ const name = parts.find((p) => p.type === "timeZoneName")?.value ?? timezone;
2245
+ return name;
2246
+ } catch {
2247
+ return timezone;
2248
+ }
2249
+ }
2250
+
2251
+ // src/evaluators/date.ts
2252
+ var DAY_NAMES = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
2253
+ function evaluateDate(query) {
2254
+ const lower = query.toLowerCase().trim();
2255
+ try {
2256
+ if (lower === "today" || lower === "now" || /^(?:what(?:'s| is) )?(?:the )?(?:current )?date(?: today)?$/.test(lower)) {
2257
+ return formatDateResult(query, /* @__PURE__ */ new Date());
2258
+ }
2259
+ if (lower === "tomorrow") {
2260
+ const d = /* @__PURE__ */ new Date();
2261
+ d.setDate(d.getDate() + 1);
2262
+ return formatDateResult(query, d);
2263
+ }
2264
+ if (lower === "yesterday") {
2265
+ const d = /* @__PURE__ */ new Date();
2266
+ d.setDate(d.getDate() - 1);
2267
+ return formatDateResult(query, d);
2268
+ }
2269
+ const nextLastMatch = lower.match(/^(next|last|this)\s+(.+)$/);
2270
+ if (nextLastMatch) {
2271
+ const direction = nextLastMatch[1];
2272
+ const target = nextLastMatch[2];
2273
+ const dayIndex = DAY_NAMES.indexOf(target);
2274
+ if (dayIndex !== -1) {
2275
+ const d = getRelativeDay(dayIndex, direction);
2276
+ return formatDateResult(query, d);
2277
+ }
2278
+ const now = /* @__PURE__ */ new Date();
2279
+ if (target === "week") {
2280
+ const offset = direction === "next" ? 7 : direction === "last" ? -7 : 0;
2281
+ now.setDate(now.getDate() + offset);
2282
+ return formatDateResult(query, now);
2283
+ }
2284
+ if (target === "month") {
2285
+ const offset = direction === "next" ? 1 : direction === "last" ? -1 : 0;
2286
+ now.setMonth(now.getMonth() + offset);
2287
+ return formatDateResult(query, now);
2288
+ }
2289
+ if (target === "year") {
2290
+ const offset = direction === "next" ? 1 : direction === "last" ? -1 : 0;
2291
+ now.setFullYear(now.getFullYear() + offset);
2292
+ return formatDateResult(query, now);
2293
+ }
2294
+ }
2295
+ const relativeMatch = lower.match(/^(\d+)\s+(days?|weeks?|months?|years?|hours?|minutes?|seconds?)\s+(from now|ago|from today|from tomorrow)$/);
2296
+ if (relativeMatch) {
2297
+ const amount = parseInt(relativeMatch[1]);
2298
+ const unit = relativeMatch[2].replace(/s$/, "");
2299
+ const direction = relativeMatch[3];
2300
+ const isAgo = direction === "ago";
2301
+ const base = direction === "from tomorrow" ? (() => {
2302
+ const d2 = /* @__PURE__ */ new Date();
2303
+ d2.setDate(d2.getDate() + 1);
2304
+ return d2;
2305
+ })() : /* @__PURE__ */ new Date();
2306
+ const d = applyOffset(base, amount * (isAgo ? -1 : 1), unit);
2307
+ return formatDateResult(query, d);
2308
+ }
2309
+ const inMatch = lower.match(/^in\s+(\d+)\s+(days?|weeks?|months?|years?|hours?|minutes?|seconds?)$/);
2310
+ if (inMatch) {
2311
+ const amount = parseInt(inMatch[1]);
2312
+ const unit = inMatch[2].replace(/s$/, "");
2313
+ const d = applyOffset(/* @__PURE__ */ new Date(), amount, unit);
2314
+ return formatDateResult(query, d);
2315
+ }
2316
+ const unixMatch = lower.match(/^(?:unix\s+)?(?:timestamp\s+)?(\d{10,13})$/);
2317
+ if (unixMatch) {
2318
+ const ts = parseInt(unixMatch[1]);
2319
+ const ms = ts > 9999999999 ? ts : ts * 1e3;
2320
+ const d = new Date(ms);
2321
+ if (isNaN(d.getTime())) {
2322
+ return { type: "error", input: query, error: "Invalid timestamp" };
2323
+ }
2324
+ return {
2325
+ type: "date",
2326
+ input: query,
2327
+ result: d.toISOString(),
2328
+ formatted: `${formatDate(d)} (${d.toISOString()})`,
2329
+ metadata: { unix: Math.floor(ms / 1e3), iso: d.toISOString(), date: d }
2330
+ };
2331
+ }
2332
+ const toUnixMatch = lower.match(/^(.+)\s+(?:to|in)\s+(?:unix|timestamp|epoch)$/);
2333
+ if (toUnixMatch) {
2334
+ const dateStr = toUnixMatch[1].trim();
2335
+ let d;
2336
+ if (dateStr === "now" || dateStr === "today") {
2337
+ d = /* @__PURE__ */ new Date();
2338
+ } else {
2339
+ d = new Date(dateStr);
2340
+ }
2341
+ if (isNaN(d.getTime())) {
2342
+ return { type: "error", input: query, error: `Cannot parse date: '${dateStr}'` };
2343
+ }
2344
+ const unix = Math.floor(d.getTime() / 1e3);
2345
+ return {
2346
+ type: "date",
2347
+ input: query,
2348
+ result: unix,
2349
+ formatted: unix.toString(),
2350
+ metadata: { iso: d.toISOString(), date: d }
2351
+ };
2352
+ }
2353
+ if (/^\d{4}-\d{2}-\d{2}/.test(lower)) {
2354
+ const d = new Date(query.trim());
2355
+ if (!isNaN(d.getTime())) {
2356
+ return formatDateResult(query, d, { iso: d.toISOString(), unix: Math.floor(d.getTime() / 1e3) });
2357
+ }
2358
+ }
2359
+ const betweenMatch = lower.match(/^(?:days?\s+)?(?:between|from)\s+(.+)\s+(?:to|and|until)\s+(.+)$/);
2360
+ if (betweenMatch) {
2361
+ const d1 = parseFlexibleDate(betweenMatch[1].trim());
2362
+ const d2 = parseFlexibleDate(betweenMatch[2].trim());
2363
+ if (d1 && d2) {
2364
+ const diffMs = Math.abs(d2.getTime() - d1.getTime());
2365
+ const diffDays = Math.round(diffMs / (1e3 * 60 * 60 * 24));
2366
+ return {
2367
+ type: "date",
2368
+ input: query,
2369
+ result: diffDays,
2370
+ formatted: `${diffDays} days`,
2371
+ metadata: { from: d1.toISOString(), to: d2.toISOString() }
2372
+ };
2373
+ }
2374
+ }
2375
+ return { type: "error", input: query, error: "Could not parse date query" };
2376
+ } catch (err) {
2377
+ return {
2378
+ type: "error",
2379
+ input: query,
2380
+ error: err instanceof Error ? err.message : "Date evaluation failed"
2381
+ };
2382
+ }
2383
+ }
2384
+ function getRelativeDay(targetDay, direction) {
2385
+ const now = /* @__PURE__ */ new Date();
2386
+ const currentDay = now.getDay();
2387
+ let diff;
2388
+ if (direction === "next") {
2389
+ diff = (targetDay - currentDay + 7) % 7 || 7;
2390
+ } else if (direction === "last") {
2391
+ diff = -((currentDay - targetDay + 7) % 7 || 7);
2392
+ } else {
2393
+ diff = targetDay - currentDay;
2394
+ }
2395
+ now.setDate(now.getDate() + diff);
2396
+ return now;
2397
+ }
2398
+ function applyOffset(base, amount, unit) {
2399
+ const d = new Date(base);
2400
+ switch (unit) {
2401
+ case "second":
2402
+ d.setSeconds(d.getSeconds() + amount);
2403
+ break;
2404
+ case "minute":
2405
+ d.setMinutes(d.getMinutes() + amount);
2406
+ break;
2407
+ case "hour":
2408
+ d.setHours(d.getHours() + amount);
2409
+ break;
2410
+ case "day":
2411
+ d.setDate(d.getDate() + amount);
2412
+ break;
2413
+ case "week":
2414
+ d.setDate(d.getDate() + amount * 7);
2415
+ break;
2416
+ case "month":
2417
+ d.setMonth(d.getMonth() + amount);
2418
+ break;
2419
+ case "year":
2420
+ d.setFullYear(d.getFullYear() + amount);
2421
+ break;
2422
+ }
2423
+ return d;
2424
+ }
2425
+ function formatDate(d) {
2426
+ return new Intl.DateTimeFormat("en-US", {
2427
+ weekday: "long",
2428
+ year: "numeric",
2429
+ month: "long",
2430
+ day: "numeric",
2431
+ hour: "2-digit",
2432
+ minute: "2-digit",
2433
+ hour12: true
2434
+ }).format(d);
2435
+ }
2436
+ function formatDateResult(input, d, extraMeta) {
2437
+ const formatted = formatDate(d);
2438
+ return {
2439
+ type: "date",
2440
+ input,
2441
+ result: d.toISOString(),
2442
+ formatted,
2443
+ metadata: {
2444
+ iso: d.toISOString(),
2445
+ unix: Math.floor(d.getTime() / 1e3),
2446
+ dayOfWeek: DAY_NAMES[d.getDay()],
2447
+ ...extraMeta
2448
+ }
2449
+ };
2450
+ }
2451
+ function parseFlexibleDate(str) {
2452
+ if (str === "today" || str === "now") return /* @__PURE__ */ new Date();
2453
+ if (str === "tomorrow") {
2454
+ const d2 = /* @__PURE__ */ new Date();
2455
+ d2.setDate(d2.getDate() + 1);
2456
+ return d2;
2457
+ }
2458
+ if (str === "yesterday") {
2459
+ const d2 = /* @__PURE__ */ new Date();
2460
+ d2.setDate(d2.getDate() - 1);
2461
+ return d2;
2462
+ }
2463
+ const d = new Date(str);
2464
+ return isNaN(d.getTime()) ? null : d;
2465
+ }
2466
+
2467
+ // src/evaluators/currency.ts
2468
+ async function evaluateCurrency(amount, from, to, provider, locale = "en-US", precision = 10) {
2469
+ const inputStr = `${amount} ${from} to ${to}`;
2470
+ if (!provider) {
2471
+ return {
2472
+ type: "error",
2473
+ input: inputStr,
2474
+ error: "No rate provider configured. Pass a rateProvider in options to enable currency conversion."
2475
+ };
2476
+ }
2477
+ try {
2478
+ const rate = await provider.getFiatRate(from, to);
2479
+ const result = amount * rate;
2480
+ const rounded = parseFloat(result.toPrecision(precision));
2481
+ let formatted;
2482
+ try {
2483
+ formatted = new Intl.NumberFormat(locale, {
2484
+ style: "currency",
2485
+ currency: to,
2486
+ maximumSignificantDigits: precision
2487
+ }).format(rounded);
2488
+ } catch {
2489
+ formatted = `${new Intl.NumberFormat(locale, { maximumSignificantDigits: precision }).format(rounded)} ${to}`;
2490
+ }
2491
+ return {
2492
+ type: "currency",
2493
+ input: inputStr,
2494
+ result: rounded,
2495
+ formatted,
2496
+ metadata: {
2497
+ from: { code: from, name: FIAT_CURRENCIES[from] ?? from },
2498
+ to: { code: to, name: FIAT_CURRENCIES[to] ?? to },
2499
+ rate,
2500
+ amount
2501
+ }
2502
+ };
2503
+ } catch (err) {
2504
+ return {
2505
+ type: "error",
2506
+ input: inputStr,
2507
+ error: err instanceof Error ? err.message : "Currency conversion failed"
2508
+ };
2509
+ }
2510
+ }
2511
+ async function evaluateCrypto(amount, from, to, provider, locale = "en-US", precision = 10) {
2512
+ const inputStr = `${amount} ${from} to ${to}`;
2513
+ if (!provider) {
2514
+ return {
2515
+ type: "error",
2516
+ input: inputStr,
2517
+ error: "No rate provider configured. Pass a rateProvider in options to enable crypto conversion."
2518
+ };
2519
+ }
2520
+ try {
2521
+ const rate = await provider.getCryptoRate(from, to);
2522
+ const result = amount * rate;
2523
+ const rounded = parseFloat(result.toPrecision(precision));
2524
+ let formatted;
2525
+ if (FIAT_CURRENCIES[to]) {
2526
+ try {
2527
+ formatted = new Intl.NumberFormat(locale, {
2528
+ style: "currency",
2529
+ currency: to,
2530
+ maximumSignificantDigits: precision
2531
+ }).format(rounded);
2532
+ } catch {
2533
+ formatted = `${new Intl.NumberFormat(locale, { maximumSignificantDigits: precision }).format(rounded)} ${to}`;
2534
+ }
2535
+ } else {
2536
+ formatted = `${new Intl.NumberFormat(locale, { maximumSignificantDigits: precision }).format(rounded)} ${CRYPTO_CURRENCIES[to] ?? to}`;
2537
+ }
2538
+ return {
2539
+ type: "crypto",
2540
+ input: inputStr,
2541
+ result: rounded,
2542
+ formatted,
2543
+ metadata: {
2544
+ from: { code: from, name: CRYPTO_CURRENCIES[from] ?? FIAT_CURRENCIES[from] ?? from },
2545
+ to: { code: to, name: CRYPTO_CURRENCIES[to] ?? FIAT_CURRENCIES[to] ?? to },
2546
+ rate,
2547
+ amount
2548
+ }
2549
+ };
2550
+ } catch (err) {
2551
+ return {
2552
+ type: "error",
2553
+ input: inputStr,
2554
+ error: err instanceof Error ? err.message : "Crypto conversion failed"
2555
+ };
2556
+ }
2557
+ }
2558
+
2559
+ // src/index.ts
2560
+ var _defaultProvider = null;
2561
+ function getDefaultProvider() {
2562
+ if (!_defaultProvider) _defaultProvider = createDefaultProvider();
2563
+ return _defaultProvider;
2564
+ }
2565
+ async function calculate(input, options) {
2566
+ const trimmed = input.trim();
2567
+ if (!trimmed) {
2568
+ return { type: "error", input, error: "Empty input" };
2569
+ }
2570
+ const locale = options?.locale ?? "en-US";
2571
+ const precision = options?.precision ?? 10;
2572
+ const rateProvider = options?.rateProvider ?? getDefaultProvider();
2573
+ const intent = detectIntent(trimmed);
2574
+ switch (intent.kind) {
2575
+ case "time":
2576
+ return evaluateTime(
2577
+ intent.query,
2578
+ intent.from,
2579
+ intent.to,
2580
+ options?.timezone
2581
+ );
2582
+ case "date":
2583
+ return evaluateDate(intent.query);
2584
+ case "currency":
2585
+ return evaluateCurrency(
2586
+ intent.amount,
2587
+ intent.from,
2588
+ intent.to,
2589
+ rateProvider,
2590
+ locale,
2591
+ precision
2592
+ );
2593
+ case "crypto":
2594
+ return evaluateCrypto(
2595
+ intent.amount,
2596
+ intent.from,
2597
+ intent.to,
2598
+ rateProvider,
2599
+ locale,
2600
+ precision
2601
+ );
2602
+ case "unit":
2603
+ return evaluateUnit(
2604
+ intent.amount,
2605
+ intent.from,
2606
+ intent.to,
2607
+ locale,
2608
+ precision
2609
+ );
2610
+ case "math":
2611
+ return evaluateMath(intent.expression, locale, precision);
2612
+ }
2613
+ }
2614
+ export {
2615
+ CRYPTO_CURRENCIES,
2616
+ FIAT_CURRENCIES,
2617
+ TIMEZONE_MAP,
2618
+ TZ_ABBREVIATIONS,
2619
+ UNIT_CATEGORIES,
2620
+ calculate,
2621
+ convertUnit,
2622
+ createDefaultProvider,
2623
+ lookupUnit,
2624
+ resolveCrypto,
2625
+ resolveFiat,
2626
+ resolveTimezone
2627
+ };