mongoose-currency-convert 0.2.4 → 0.2.5

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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # mongoose-currency-convert
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/mongoose-currency-convert.svg)](https://www.npmjs.com/package/mongoose-currency-convert)
4
- [![Release](https://github.com/maku85/mongoose-currency-convert/actions/workflows/release.yml/badge.svg?branch=main)](https://github.com/maku85/mongoose-currency-convert/actions/workflows/release.yml)
4
+ [![CI](https://github.com/maku85/mongoose-currency-convert/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/maku85/mongoose-currency-convert/actions/workflows/ci.yml)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
7
  A lightweight Mongoose plugin for automatic currency conversion at save and update time — flexible, extensible, and service-agnostic.
@@ -116,19 +116,19 @@ The target path must point to a schema object with `amount`, `currency`, and `da
116
116
  | `round` | `(value: number) => number` | Round to 2 decimals | Custom rounding function |
117
117
  | `cache` | `CurrencyRateCache<number>` | — | Cache for exchange rates |
118
118
  | `allowedCurrencyCodes` | `string[]` | Full ISO 4217 list | Restrict accepted currency codes |
119
- | `fallbackRate` | `number` | — | Rate to use when `getRate` throws or returns an invalid value |
119
+ | `fallbackRate` | `number` (≥ 0) | — | Rate to use when `getRate` throws or returns an invalid value |
120
120
  | `onError` | `(ctx: CurrencyPluginErrorContext) => void` | `console.error` | Called on rate fetch failure |
121
121
  | `onSuccess` | `(ctx: CurrencyPluginSuccessContext) => void` | — | Called after each successful conversion |
122
122
  | `rollbackOnError` | `boolean` | `false` | If `true`, clears already-converted fields when a field fails |
123
123
  | `dateTransform` | `(date: Date) => Date` | — | Transform the conversion date before passing it to `getRate` |
124
- | `concurrency` | `number` | `Infinity` | Max parallel `getRate` calls per document |
125
- | `rateValidation` | `{ min?: number; max?: number }` | — | Reject rates outside this range (throws, triggers `onError`/fallback) |
124
+ | `concurrency` | `number` | `5` | Max parallel `getRate` calls per document |
125
+ | `rateValidation` | `{ min?: number; max?: number }` | — | Reject rates outside this range (throws, triggers `onError`/fallback). `min` defaults to `0` when not specified |
126
126
 
127
127
  ## Caching
128
128
 
129
129
  ### Built-in `SimpleCache`
130
130
 
131
- An in-memory LRU cache with TTL-based eviction is included. The cache key is `{from}_{to}_{YYYY-MM-DD}`.
131
+ An in-memory TTL cache with active eviction is included. The cache key is `{from}_{to}_{YYYY-MM-DD}`.
132
132
 
133
133
  ```ts
134
134
  import { SimpleCache } from 'mongoose-currency-convert/cache';
@@ -354,32 +354,27 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
354
354
 
355
355
  ## Releasing
356
356
 
357
- This project uses [Conventional Commits](https://www.conventionalcommits.org/) and [`commit-and-tag-version`](https://github.com/absolute-version/commit-and-tag-version) for versioning.
357
+ Releases are cut manually using the `scripts/release.sh` script, which runs typecheck, tests, and build before bumping the version, pushing the tag, and publishing to npm.
358
358
 
359
359
  ```bash
360
- # preview what would change without modifying anything
361
- pnpm release:dry
362
-
363
- # release (auto-detects patch/minor/major from commits)
360
+ # patch release (0.2.4 0.2.5)
364
361
  pnpm release
365
362
 
366
- # or force a specific bump
363
+ # minor release (0.2.4 0.3.0)
367
364
  pnpm release:minor
368
- pnpm release:major
369
365
 
370
- # push commit + tag triggers the GitHub Action
371
- git push --follow-tags
366
+ # major release (0.2.41.0.0)
367
+ pnpm release:major
372
368
  ```
373
369
 
374
- The version bump is determined by commit types:
375
-
376
- | Commit type | Release |
377
- |-------------|---------|
378
- | `fix:`, `perf:`, `revert:` | patch |
379
- | `feat:` | minor |
380
- | `feat!:` / `BREAKING CHANGE` | major |
370
+ Each command runs the following steps in order:
381
371
 
382
- The GitHub Action will automatically create a GitHub Release and publish to npm.
372
+ 1. `pnpm typecheck`
373
+ 2. `pnpm test`
374
+ 3. `pnpm build`
375
+ 4. `npm version <type>` — bumps `package.json` and creates a git tag
376
+ 5. `git push --follow-tags`
377
+ 6. `npm publish --access public`
383
378
 
384
379
  ## Changelog
385
380
 
package/dist/index.d.mts CHANGED
@@ -18,6 +18,7 @@ interface CurrencyPluginOptions {
18
18
  fallbackRate?: number;
19
19
  rollbackOnError?: boolean;
20
20
  dateTransform?: (date: Date) => Date;
21
+ /** Maximum number of concurrent `getRate` calls. Defaults to `5`. */
21
22
  concurrency?: number;
22
23
  rateValidation?: {
23
24
  min?: number;
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ interface CurrencyPluginOptions {
18
18
  fallbackRate?: number;
19
19
  rollbackOnError?: boolean;
20
20
  dateTransform?: (date: Date) => Date;
21
+ /** Maximum number of concurrent `getRate` calls. Defaults to `5`. */
21
22
  concurrency?: number;
22
23
  rateValidation?: {
23
24
  min?: number;
package/dist/index.js CHANGED
@@ -42,7 +42,6 @@ var ISO_4217_CODES = [
42
42
  "COP",
43
43
  "COU",
44
44
  "CRC",
45
- "CUC",
46
45
  "CUP",
47
46
  "CVE",
48
47
  "CZK",
@@ -71,7 +70,6 @@ var ISO_4217_CODES = [
71
70
  // H
72
71
  "HKD",
73
72
  "HNL",
74
- "HRK",
75
73
  "HTG",
76
74
  "HUF",
77
75
  // I
@@ -279,7 +277,7 @@ function currencyConversionPlugin(schema, options) {
279
277
  rollbackOnError,
280
278
  cache,
281
279
  dateTransform,
282
- concurrency = Infinity,
280
+ concurrency = 5,
283
281
  rateValidation
284
282
  } = options;
285
283
  if (!fields || !Array.isArray(fields) || fields.length === 0) {
@@ -300,12 +298,19 @@ function currencyConversionPlugin(schema, options) {
300
298
  if (options.dateTransform !== void 0 && typeof options.dateTransform !== "function") {
301
299
  throw new Error('[mongoose-currency-convert] option "dateTransform" must be a function');
302
300
  }
301
+ const targetPaths = /* @__PURE__ */ new Set();
303
302
  for (const field of fields) {
304
303
  if (!isValidCurrencyCode(field.toCurrency, allowedCurrencyCodes)) {
305
304
  throw new Error(
306
305
  `[mongoose-currency-convert] invalid toCurrency "${field.toCurrency}" in field config`
307
306
  );
308
307
  }
308
+ if (targetPaths.has(field.targetPath)) {
309
+ throw new Error(
310
+ `[mongoose-currency-convert] duplicate targetPath "${field.targetPath}" in field config`
311
+ );
312
+ }
313
+ targetPaths.add(field.targetPath);
309
314
  }
310
315
  if (options.fallbackRate !== void 0 && (typeof options.fallbackRate !== "number" || options.fallbackRate < 0)) {
311
316
  throw new Error(
@@ -378,7 +383,14 @@ function currencyConversionPlugin(schema, options) {
378
383
  }
379
384
  if (dateTransform) {
380
385
  try {
381
- conversionDate = dateTransform(conversionDate);
386
+ const transformed = dateTransform(conversionDate);
387
+ if (transformed instanceof Date && !Number.isNaN(transformed.getTime())) {
388
+ conversionDate = transformed;
389
+ } else {
390
+ console.warn(
391
+ `[mongoose-currency-convert] dateTransform returned an invalid Date for field '${sourcePath}', using original date`
392
+ );
393
+ }
382
394
  } catch (transformErr) {
383
395
  console.warn(
384
396
  `[mongoose-currency-convert] dateTransform threw for field '${sourcePath}', using original date:`,
@@ -407,7 +419,7 @@ function currencyConversionPlugin(schema, options) {
407
419
  }
408
420
  if (rate === void 0) {
409
421
  rate = await getRate(fromCurrency, field.toCurrency, conversionDate);
410
- if (cache && rate !== void 0 && !Number.isNaN(rate)) {
422
+ if (cache && rate !== void 0 && Number.isFinite(rate)) {
411
423
  try {
412
424
  await cache.set(cacheKey, rate);
413
425
  } catch (cacheErr) {
@@ -415,7 +427,7 @@ function currencyConversionPlugin(schema, options) {
415
427
  }
416
428
  }
417
429
  }
418
- if (rate == null || Number.isNaN(rate)) {
430
+ if (rate == null || !Number.isFinite(rate) || rate < 0) {
419
431
  if (typeof fallbackRate === "number") {
420
432
  rate = fallbackRate;
421
433
  usedFallback = true;
@@ -424,7 +436,7 @@ function currencyConversionPlugin(schema, options) {
424
436
  }
425
437
  }
426
438
  if (rateValidation) {
427
- const { min = Number.EPSILON, max } = rateValidation;
439
+ const { min = 0, max } = rateValidation;
428
440
  if (rate < min || max !== void 0 && rate > max) {
429
441
  throw new Error(
430
442
  `Rate ${rate} is out of bounds [${min}, ${max ?? "\u221E"}] for ${fromCurrency}\u2192${field.toCurrency}`
@@ -435,7 +447,7 @@ function currencyConversionPlugin(schema, options) {
435
447
  } catch (error) {
436
448
  if (typeof fallbackRate === "number") {
437
449
  if (rateValidation) {
438
- const { min = Number.EPSILON, max } = rateValidation;
450
+ const { min = 0, max } = rateValidation;
439
451
  if (fallbackRate < min || max !== void 0 && fallbackRate > max) {
440
452
  return {
441
453
  success: false,
@@ -489,8 +501,15 @@ function currencyConversionPlugin(schema, options) {
489
501
  }
490
502
  continue;
491
503
  }
504
+ const rawAmount = Number(amount) * rateResult.rate;
505
+ const roundedAmount = round(rawAmount);
506
+ if (!Number.isFinite(roundedAmount)) {
507
+ console.warn(
508
+ `[mongoose-currency-convert] WARNING: round() returned a non-finite value for field '${sourcePath}', using unrounded amount`
509
+ );
510
+ }
492
511
  const convertedValue = {
493
- amount: round(Number(amount) * rateResult.rate),
512
+ amount: Number.isFinite(roundedAmount) ? roundedAmount : rawAmount,
494
513
  currency: toCurrency,
495
514
  date: conversionDate
496
515
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/helpers.ts","../src/index.ts"],"names":[],"mappings":";;;AACA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAErB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,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","file":"index.js","sourcesContent":["// Complete ISO 4217 active currency codes\nconst ISO_4217_CODES = [\n // A\n \"AED\",\n \"AFN\",\n \"ALL\",\n \"AMD\",\n \"ANG\",\n \"AOA\",\n \"ARS\",\n \"AUD\",\n \"AWG\",\n \"AZN\",\n // B\n \"BAM\",\n \"BBD\",\n \"BDT\",\n \"BGN\",\n \"BHD\",\n \"BIF\",\n \"BMD\",\n \"BND\",\n \"BOB\",\n \"BOV\",\n \"BRL\",\n \"BSD\",\n \"BTN\",\n \"BWP\",\n \"BYN\",\n \"BZD\",\n // C\n \"CAD\",\n \"CDF\",\n \"CHE\",\n \"CHF\",\n \"CHW\",\n \"CLF\",\n \"CLP\",\n \"CNY\",\n \"COP\",\n \"COU\",\n \"CRC\",\n \"CUC\",\n \"CUP\",\n \"CVE\",\n \"CZK\",\n // D\n \"DJF\",\n \"DKK\",\n \"DOP\",\n \"DZD\",\n // E\n \"EGP\",\n \"ERN\",\n \"ETB\",\n \"EUR\",\n // F\n \"FJD\",\n \"FKP\",\n // G\n \"GBP\",\n \"GEL\",\n \"GHS\",\n \"GIP\",\n \"GMD\",\n \"GNF\",\n \"GTQ\",\n \"GYD\",\n // H\n \"HKD\",\n \"HNL\",\n \"HRK\",\n \"HTG\",\n \"HUF\",\n // I\n \"IDR\",\n \"ILS\",\n \"INR\",\n \"IQD\",\n \"IRR\",\n \"ISK\",\n // J\n \"JMD\",\n \"JOD\",\n \"JPY\",\n // K\n \"KES\",\n \"KGS\",\n \"KHR\",\n \"KMF\",\n \"KPW\",\n \"KRW\",\n \"KWD\",\n \"KYD\",\n \"KZT\",\n // L\n \"LAK\",\n \"LBP\",\n \"LRD\",\n \"LSL\",\n \"LYD\",\n // M\n \"MAD\",\n \"MDL\",\n \"MGA\",\n \"MKD\",\n \"MMK\",\n \"MNT\",\n \"MOP\",\n \"MRU\",\n \"MUR\",\n \"MVR\",\n \"MWK\",\n \"MXN\",\n \"MXV\",\n \"MYR\",\n \"MZN\",\n // N\n \"NAD\",\n \"NGN\",\n \"NIO\",\n \"NOK\",\n \"NPR\",\n \"NZD\",\n // O\n \"OMR\",\n // P\n \"PAB\",\n \"PEN\",\n \"PGK\",\n \"PHP\",\n \"PKR\",\n \"PLN\",\n \"PYG\",\n // Q\n \"QAR\",\n // R\n \"RON\",\n \"RSD\",\n \"RUB\",\n \"RWF\",\n // S\n \"SAR\",\n \"SBD\",\n \"SCR\",\n \"SDG\",\n \"SEK\",\n \"SGD\",\n \"SHP\",\n \"SLE\",\n \"SOS\",\n \"SRD\",\n \"SSP\",\n \"STN\",\n \"SVC\",\n \"SYP\",\n \"SZL\",\n // T\n \"THB\",\n \"TJS\",\n \"TMT\",\n \"TND\",\n \"TOP\",\n \"TRY\",\n \"TTD\",\n \"TWD\",\n \"TZS\",\n // U\n \"UAH\",\n \"UGX\",\n \"USD\",\n \"USN\",\n \"UYI\",\n \"UYU\",\n \"UZS\",\n // V\n \"VES\",\n \"VND\",\n \"VUV\",\n // W\n \"WST\",\n // X (special / supra-national)\n \"XAF\",\n \"XAG\",\n \"XAU\",\n \"XBA\",\n \"XBB\",\n \"XBC\",\n \"XBD\",\n \"XCD\",\n \"XDR\",\n \"XOF\",\n \"XPD\",\n \"XPF\",\n \"XPT\",\n \"XSU\",\n \"XTS\",\n \"XUA\",\n \"XXX\",\n // Y\n \"YER\",\n // Z\n \"ZAR\",\n \"ZMW\",\n \"ZWL\",\n];\nconst PATH_CACHE_MAX_SIZE = 500;\nconst pathCache = new Map<string, string[]>();\n\nexport function getPathArray(path: string): string[] {\n const cached = pathCache.get(path);\n if (cached) {\n // Refresh insertion order so least-recently-used entries are evicted first\n pathCache.delete(path);\n pathCache.set(path, cached);\n return cached;\n }\n\n const arr = path.split(\".\");\n if (pathCache.size >= PATH_CACHE_MAX_SIZE) {\n pathCache.delete(pathCache.keys().next().value as string);\n }\n pathCache.set(path, arr);\n return arr;\n}\n\nexport function getNestedValue(obj: unknown, path: string | string[]): unknown {\n const keys = Array.isArray(path) ? path : getPathArray(path);\n return keys.reduce((acc, key) => {\n if (acc && typeof acc === \"object\") {\n if (!Number.isNaN(Number(key)) && Array.isArray(acc)) {\n return acc[Number(key)];\n }\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\nexport function setNestedValue(obj: unknown, path: string | string[], value: unknown): void {\n const parts = Array.isArray(path) ? [...path] : [...getPathArray(path)];\n const last = parts.pop();\n if (!last) return;\n\n let target = obj as Record<string, unknown>;\n for (const key of parts) {\n if (!Number.isNaN(Number(key)) && Array.isArray(target)) {\n if (!target[Number(key)]) target[Number(key)] = {};\n target = target[Number(key)] as Record<string, unknown>;\n } else {\n if (typeof target[key] !== \"object\" || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n }\n if (!Number.isNaN(Number(last)) && Array.isArray(target)) {\n target[Number(last)] = value;\n } else {\n target[last] = value;\n }\n}\n\nexport function defaultRound(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nexport function isValidCurrencyCode(code: string, allowedCodes?: string[]): boolean {\n const list = allowedCodes || ISO_4217_CODES;\n if (typeof code !== \"string\") return false;\n const normalized = code.toUpperCase();\n return list.some((c) => c.toUpperCase() === normalized);\n}\n","import type { Schema, Document } from \"mongoose\";\n\nimport type { CurrencyPluginOptions } from \"./types\";\nimport { defaultRound, getNestedValue, isValidCurrencyCode, setNestedValue } from \"./utils/helpers\";\n\n/**\n * Mongoose plugin that automatically converts currency fields on save and update operations.\n *\n * ## Error handling policy\n *\n * The plugin uses a three-tier strategy depending on when and where an error occurs:\n *\n * 1. **Initialization errors** (`throw`): Missing or invalid required options (`fields`, `getRate`)\n * cause an immediate `Error` to be thrown when the plugin is registered. These are\n * programmer errors and must be fixed before the application starts.\n *\n * 2. **Field validation warnings** (`console.warn` + skip): Invalid field configurations\n * detected at conversion time (missing `targetPath`, invalid currency code, non-numeric\n * `amount`, invalid date) are logged as warnings and the field is silently skipped.\n * The document is still saved with the remaining conversions applied.\n *\n * 3. **Rate fetch errors** (`onError` callback or `console.error`): Errors thrown by `getRate`\n * or invalid rates returned by it are passed to the `onError` callback if provided,\n * otherwise logged via `console.error`. If `fallbackRate` is set it is used instead.\n * If `rollbackOnError` is `true`, all previously converted fields in that document are\n * reverted before the save continues.\n */\nexport function currencyConversionPlugin(schema: Schema, options: CurrencyPluginOptions) {\n const {\n fields,\n getRate,\n round = defaultRound,\n allowedCurrencyCodes,\n onError,\n onSuccess,\n fallbackRate,\n rollbackOnError,\n cache,\n dateTransform,\n concurrency = Infinity,\n rateValidation,\n } = options;\n\n if (!fields || !Array.isArray(fields) || fields.length === 0) {\n throw new Error('[mongoose-currency-convert] option \"fields\" must be a non-empty array');\n }\n\n if (typeof getRate !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"getRate\" must be a function');\n }\n\n if (options.round !== undefined && typeof options.round !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"round\" must be a function');\n }\n\n if (options.onError !== undefined && typeof options.onError !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"onError\" must be a function');\n }\n\n if (options.onSuccess !== undefined && typeof options.onSuccess !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"onSuccess\" must be a function');\n }\n\n if (options.dateTransform !== undefined && typeof options.dateTransform !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"dateTransform\" must be a function');\n }\n\n for (const field of fields) {\n if (!isValidCurrencyCode(field.toCurrency, allowedCurrencyCodes)) {\n throw new Error(\n `[mongoose-currency-convert] invalid toCurrency \"${field.toCurrency}\" in field config`,\n );\n }\n }\n\n if (\n options.fallbackRate !== undefined &&\n (typeof options.fallbackRate !== \"number\" || options.fallbackRate < 0)\n ) {\n throw new Error(\n '[mongoose-currency-convert] option \"fallbackRate\" must be a non-negative number',\n );\n }\n\n if (\n options.concurrency !== undefined &&\n (typeof options.concurrency !== \"number\" || options.concurrency < 1)\n ) {\n throw new Error('[mongoose-currency-convert] option \"concurrency\" must be a number >= 1');\n }\n\n if (rateValidation !== undefined) {\n if (typeof rateValidation !== \"object\" || rateValidation === null) {\n throw new Error('[mongoose-currency-convert] option \"rateValidation\" must be an object');\n }\n if (rateValidation.min !== undefined && typeof rateValidation.min !== \"number\") {\n throw new Error('[mongoose-currency-convert] option \"rateValidation.min\" must be a number');\n }\n if (rateValidation.max !== undefined && typeof rateValidation.max !== \"number\") {\n throw new Error('[mongoose-currency-convert] option \"rateValidation.max\" must be a number');\n }\n if (\n rateValidation.min !== undefined &&\n rateValidation.max !== undefined &&\n rateValidation.min > rateValidation.max\n ) {\n throw new Error(\n '[mongoose-currency-convert] option \"rateValidation.min\" must be <= \"rateValidation.max\"',\n );\n }\n }\n\n async function applyCurrencyConversion(\n doc: Record<string, unknown>,\n ): Promise<Map<string, unknown>> {\n const results = new Map<string, unknown>();\n\n type WorkItem = {\n field: (typeof fields)[number];\n amount: number;\n fromCurrency: string;\n conversionDate: Date;\n cacheKey: string;\n };\n const workItems: WorkItem[] = [];\n\n for (const field of fields) {\n const { sourcePath, currencyPath, datePath, targetPath, toCurrency } = field;\n\n if (!targetPath) {\n console.warn(\n `[mongoose-currency-convert] WARNING: 'targetPath' is required in field config`,\n );\n continue;\n }\n\n if (!schema.path(`${targetPath}.amount`)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: targetPath '${targetPath}' does not exist in schema`,\n );\n continue;\n }\n\n const amount = getNestedValue(doc, sourcePath);\n if (amount == null) continue;\n if (typeof amount !== \"number\" || Number.isNaN(amount)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: non-numeric amount at path '${sourcePath}': (${typeof amount})`,\n );\n continue;\n }\n\n const fromCurrency = getNestedValue(doc, currencyPath);\n if (typeof fromCurrency !== \"string\" || !fromCurrency) {\n console.warn(\n `[mongoose-currency-convert] Missing or invalid source currency at path: ${currencyPath}`,\n );\n continue;\n }\n\n if (!isValidCurrencyCode(fromCurrency, allowedCurrencyCodes)) {\n console.warn(`[mongoose-currency-convert] Invalid source currency code: ${fromCurrency}`);\n continue;\n }\n\n if (fromCurrency.toUpperCase() === toCurrency.toUpperCase()) continue;\n\n const dateValue = datePath ? getNestedValue(doc, datePath) : undefined;\n let conversionDate =\n dateValue &&\n (typeof dateValue === \"string\" ||\n typeof dateValue === \"number\" ||\n dateValue instanceof Date)\n ? new Date(dateValue)\n : new Date();\n if (Number.isNaN(conversionDate.getTime())) {\n console.warn(\n `[mongoose-currency-convert] Invalid date value at path '${datePath}', using current date`,\n );\n conversionDate = new Date();\n }\n\n if (dateTransform) {\n try {\n conversionDate = dateTransform(conversionDate);\n } catch (transformErr) {\n console.warn(\n `[mongoose-currency-convert] dateTransform threw for field '${sourcePath}', using original date:`,\n transformErr,\n );\n }\n }\n\n const cacheKey = `${fromCurrency.toUpperCase()}_${toCurrency.toUpperCase()}_${conversionDate.toISOString().slice(0, 10)}`;\n workItems.push({ field, amount, fromCurrency, conversionDate, cacheKey });\n }\n\n type RateResult =\n | { success: true; rate: number; usedFallback: boolean }\n | { success: false; error: unknown };\n\n async function fetchRate({\n field,\n fromCurrency,\n conversionDate,\n cacheKey,\n }: WorkItem): Promise<RateResult> {\n try {\n let rate: number | undefined;\n let usedFallback = false;\n if (cache) {\n try {\n rate = await cache.get(cacheKey);\n } catch (cacheErr) {\n console.warn(\"[mongoose-currency-convert] cache.get() failed:\", cacheErr);\n }\n }\n\n if (rate === undefined) {\n rate = await getRate(fromCurrency, field.toCurrency, conversionDate);\n if (cache && rate !== undefined && !Number.isNaN(rate)) {\n try {\n await cache.set(cacheKey, rate);\n } catch (cacheErr) {\n console.warn(\"[mongoose-currency-convert] cache.set() failed:\", cacheErr);\n }\n }\n }\n\n if (rate == null || Number.isNaN(rate)) {\n if (typeof fallbackRate === \"number\") {\n rate = fallbackRate;\n usedFallback = true;\n } else {\n throw new Error(\"Invalid rate\");\n }\n }\n\n if (rateValidation) {\n const { min = Number.EPSILON, max } = rateValidation;\n if (rate < min || (max !== undefined && rate > max)) {\n throw new Error(\n `Rate ${rate} is out of bounds [${min}, ${max ?? \"∞\"}] for ${fromCurrency}→${field.toCurrency}`,\n );\n }\n }\n\n return { success: true, rate, usedFallback };\n } catch (error) {\n if (typeof fallbackRate === \"number\") {\n if (rateValidation) {\n const { min = Number.EPSILON, max } = rateValidation;\n if (fallbackRate < min || (max !== undefined && fallbackRate > max)) {\n return {\n success: false,\n error: new Error(\n `Fallback rate ${fallbackRate} is also out of bounds [${min}, ${max ?? \"∞\"}] for ${fromCurrency}→${field.toCurrency}`,\n ),\n };\n }\n }\n return { success: true, rate: fallbackRate, usedFallback: true };\n }\n return { success: false, error };\n }\n }\n\n const limit = Math.max(1, concurrency);\n const rateResults: RateResult[] = [];\n for (let i = 0; i < workItems.length; i += limit) {\n const batch = workItems.slice(i, i + limit);\n rateResults.push(...(await Promise.all(batch.map(fetchRate))));\n }\n\n const convertedFields: string[] = [];\n for (let i = 0; i < workItems.length; i++) {\n const { field, amount, fromCurrency, conversionDate } = workItems[i];\n const { sourcePath, targetPath, toCurrency } = field;\n const rateResult = rateResults[i];\n\n if (!rateResult.success) {\n if (onError) {\n try {\n await onError({\n field: sourcePath,\n fromCurrency,\n toCurrency,\n date: conversionDate,\n error: rateResult.error,\n });\n } catch (callbackErr) {\n console.error(\"[mongoose-currency-convert] onError callback threw:\", callbackErr);\n }\n } else {\n console.error(\n `[mongoose-currency-convert] Error converting ${sourcePath}:`,\n rateResult.error,\n );\n }\n if (rollbackOnError) {\n for (const convertedField of convertedFields) {\n setNestedValue(doc, convertedField, undefined);\n results.delete(convertedField);\n }\n break;\n }\n continue;\n }\n\n const convertedValue = {\n amount: round(Number(amount) * rateResult.rate),\n currency: toCurrency,\n date: conversionDate,\n };\n setNestedValue(doc, targetPath, convertedValue);\n results.set(targetPath, convertedValue);\n convertedFields.push(targetPath);\n if (onSuccess) {\n try {\n await onSuccess({\n field: sourcePath,\n fromCurrency,\n toCurrency,\n originalAmount: amount,\n convertedAmount: convertedValue.amount,\n rate: rateResult.rate,\n date: conversionDate,\n usedFallback: rateResult.usedFallback,\n });\n } catch (callbackErr) {\n console.error(\"[mongoose-currency-convert] onSuccess callback threw:\", callbackErr);\n }\n }\n }\n\n return results;\n }\n\n schema.pre(\"save\", async function (this: Document) {\n if (this.$locals.skipCurrencyConversion) return;\n const conversions = await applyCurrencyConversion(this as unknown as Record<string, unknown>);\n for (const [path, value] of conversions) {\n this.set(path, value);\n }\n });\n\n async function handleUpdateMiddleware(\n this: import(\"mongoose\").Query<unknown, unknown>,\n next: (err?: Error) => void,\n ) {\n const queryOptions = this.getOptions() as Record<string, unknown>;\n if (queryOptions.skipCurrencyConversion) return next();\n\n const update = this.getUpdate();\n if (!update) return next();\n\n const updateAny = update as Record<string, unknown>;\n let doc: Record<string, unknown>;\n try {\n if (typeof updateAny.$set === \"object\" && updateAny.$set !== null) {\n doc = { ...updateAny.$set };\n await applyCurrencyConversion(doc);\n updateAny.$set = doc;\n } else {\n doc = { ...updateAny };\n await applyCurrencyConversion(doc);\n Object.assign(updateAny, doc);\n }\n\n if (typeof updateAny.$setOnInsert === \"object\" && updateAny.$setOnInsert !== null) {\n const insertDoc = { ...updateAny.$setOnInsert } as Record<string, unknown>;\n await applyCurrencyConversion(insertDoc);\n updateAny.$setOnInsert = insertDoc;\n }\n } catch (err) {\n return next(err instanceof Error ? err : new Error(String(err)));\n }\n next();\n }\n\n schema.pre(\"findOneAndUpdate\", handleUpdateMiddleware);\n schema.pre(\"updateOne\", handleUpdateMiddleware);\n schema.pre(\"updateMany\", handleUpdateMiddleware);\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/helpers.ts","../src/index.ts"],"names":[],"mappings":";;;AACA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAErB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;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","file":"index.js","sourcesContent":["// Complete ISO 4217 active currency codes\nconst ISO_4217_CODES = [\n // A\n \"AED\",\n \"AFN\",\n \"ALL\",\n \"AMD\",\n \"ANG\",\n \"AOA\",\n \"ARS\",\n \"AUD\",\n \"AWG\",\n \"AZN\",\n // B\n \"BAM\",\n \"BBD\",\n \"BDT\",\n \"BGN\",\n \"BHD\",\n \"BIF\",\n \"BMD\",\n \"BND\",\n \"BOB\",\n \"BOV\",\n \"BRL\",\n \"BSD\",\n \"BTN\",\n \"BWP\",\n \"BYN\",\n \"BZD\",\n // C\n \"CAD\",\n \"CDF\",\n \"CHE\",\n \"CHF\",\n \"CHW\",\n \"CLF\",\n \"CLP\",\n \"CNY\",\n \"COP\",\n \"COU\",\n \"CRC\",\n \"CUP\",\n \"CVE\",\n \"CZK\",\n // D\n \"DJF\",\n \"DKK\",\n \"DOP\",\n \"DZD\",\n // E\n \"EGP\",\n \"ERN\",\n \"ETB\",\n \"EUR\",\n // F\n \"FJD\",\n \"FKP\",\n // G\n \"GBP\",\n \"GEL\",\n \"GHS\",\n \"GIP\",\n \"GMD\",\n \"GNF\",\n \"GTQ\",\n \"GYD\",\n // H\n \"HKD\",\n \"HNL\",\n \"HTG\",\n \"HUF\",\n // I\n \"IDR\",\n \"ILS\",\n \"INR\",\n \"IQD\",\n \"IRR\",\n \"ISK\",\n // J\n \"JMD\",\n \"JOD\",\n \"JPY\",\n // K\n \"KES\",\n \"KGS\",\n \"KHR\",\n \"KMF\",\n \"KPW\",\n \"KRW\",\n \"KWD\",\n \"KYD\",\n \"KZT\",\n // L\n \"LAK\",\n \"LBP\",\n \"LRD\",\n \"LSL\",\n \"LYD\",\n // M\n \"MAD\",\n \"MDL\",\n \"MGA\",\n \"MKD\",\n \"MMK\",\n \"MNT\",\n \"MOP\",\n \"MRU\",\n \"MUR\",\n \"MVR\",\n \"MWK\",\n \"MXN\",\n \"MXV\",\n \"MYR\",\n \"MZN\",\n // N\n \"NAD\",\n \"NGN\",\n \"NIO\",\n \"NOK\",\n \"NPR\",\n \"NZD\",\n // O\n \"OMR\",\n // P\n \"PAB\",\n \"PEN\",\n \"PGK\",\n \"PHP\",\n \"PKR\",\n \"PLN\",\n \"PYG\",\n // Q\n \"QAR\",\n // R\n \"RON\",\n \"RSD\",\n \"RUB\",\n \"RWF\",\n // S\n \"SAR\",\n \"SBD\",\n \"SCR\",\n \"SDG\",\n \"SEK\",\n \"SGD\",\n \"SHP\",\n \"SLE\",\n \"SOS\",\n \"SRD\",\n \"SSP\",\n \"STN\",\n \"SVC\",\n \"SYP\",\n \"SZL\",\n // T\n \"THB\",\n \"TJS\",\n \"TMT\",\n \"TND\",\n \"TOP\",\n \"TRY\",\n \"TTD\",\n \"TWD\",\n \"TZS\",\n // U\n \"UAH\",\n \"UGX\",\n \"USD\",\n \"USN\",\n \"UYI\",\n \"UYU\",\n \"UZS\",\n // V\n \"VES\",\n \"VND\",\n \"VUV\",\n // W\n \"WST\",\n // X (special / supra-national)\n \"XAF\",\n \"XAG\",\n \"XAU\",\n \"XBA\",\n \"XBB\",\n \"XBC\",\n \"XBD\",\n \"XCD\",\n \"XDR\",\n \"XOF\",\n \"XPD\",\n \"XPF\",\n \"XPT\",\n \"XSU\",\n \"XTS\",\n \"XUA\",\n \"XXX\",\n // Y\n \"YER\",\n // Z\n \"ZAR\",\n \"ZMW\",\n \"ZWL\",\n];\nconst PATH_CACHE_MAX_SIZE = 500;\nconst pathCache = new Map<string, string[]>();\n\nexport function getPathArray(path: string): string[] {\n const cached = pathCache.get(path);\n if (cached) {\n // Refresh insertion order so least-recently-used entries are evicted first\n pathCache.delete(path);\n pathCache.set(path, cached);\n return cached;\n }\n\n const arr = path.split(\".\");\n if (pathCache.size >= PATH_CACHE_MAX_SIZE) {\n pathCache.delete(pathCache.keys().next().value as string);\n }\n pathCache.set(path, arr);\n return arr;\n}\n\nexport function getNestedValue(obj: unknown, path: string | string[]): unknown {\n const keys = Array.isArray(path) ? path : getPathArray(path);\n return keys.reduce((acc, key) => {\n if (acc && typeof acc === \"object\") {\n if (!Number.isNaN(Number(key)) && Array.isArray(acc)) {\n return acc[Number(key)];\n }\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\nexport function setNestedValue(obj: unknown, path: string | string[], value: unknown): void {\n const parts = Array.isArray(path) ? [...path] : [...getPathArray(path)];\n const last = parts.pop();\n if (!last) return;\n\n let target = obj as Record<string, unknown>;\n for (const key of parts) {\n if (!Number.isNaN(Number(key)) && Array.isArray(target)) {\n if (!target[Number(key)]) target[Number(key)] = {};\n target = target[Number(key)] as Record<string, unknown>;\n } else {\n if (typeof target[key] !== \"object\" || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n }\n if (!Number.isNaN(Number(last)) && Array.isArray(target)) {\n target[Number(last)] = value;\n } else {\n target[last] = value;\n }\n}\n\nexport function defaultRound(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nexport function isValidCurrencyCode(code: string, allowedCodes?: string[]): boolean {\n const list = allowedCodes || ISO_4217_CODES;\n if (typeof code !== \"string\") return false;\n const normalized = code.toUpperCase();\n return list.some((c) => c.toUpperCase() === normalized);\n}\n","import type { Schema, Document } from \"mongoose\";\n\nimport type { CurrencyPluginOptions } from \"./types\";\nimport { defaultRound, getNestedValue, isValidCurrencyCode, setNestedValue } from \"./utils/helpers\";\n\n/**\n * Mongoose plugin that automatically converts currency fields on save and update operations.\n *\n * ## Error handling policy\n *\n * The plugin uses a three-tier strategy depending on when and where an error occurs:\n *\n * 1. **Initialization errors** (`throw`): Missing or invalid required options (`fields`, `getRate`)\n * cause an immediate `Error` to be thrown when the plugin is registered. These are\n * programmer errors and must be fixed before the application starts.\n *\n * 2. **Field validation warnings** (`console.warn` + skip): Invalid field configurations\n * detected at conversion time (missing `targetPath`, invalid currency code, non-numeric\n * `amount`, invalid date) are logged as warnings and the field is silently skipped.\n * The document is still saved with the remaining conversions applied.\n *\n * 3. **Rate fetch errors** (`onError` callback or `console.error`): Errors thrown by `getRate`\n * or invalid rates returned by it are passed to the `onError` callback if provided,\n * otherwise logged via `console.error`. If `fallbackRate` is set it is used instead.\n * If `rollbackOnError` is `true`, all previously converted fields in that document are\n * reverted before the save continues.\n */\nexport function currencyConversionPlugin(schema: Schema, options: CurrencyPluginOptions) {\n const {\n fields,\n getRate,\n round = defaultRound,\n allowedCurrencyCodes,\n onError,\n onSuccess,\n fallbackRate,\n rollbackOnError,\n cache,\n dateTransform,\n concurrency = 5,\n rateValidation,\n } = options;\n\n if (!fields || !Array.isArray(fields) || fields.length === 0) {\n throw new Error('[mongoose-currency-convert] option \"fields\" must be a non-empty array');\n }\n\n if (typeof getRate !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"getRate\" must be a function');\n }\n\n if (options.round !== undefined && typeof options.round !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"round\" must be a function');\n }\n\n if (options.onError !== undefined && typeof options.onError !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"onError\" must be a function');\n }\n\n if (options.onSuccess !== undefined && typeof options.onSuccess !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"onSuccess\" must be a function');\n }\n\n if (options.dateTransform !== undefined && typeof options.dateTransform !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"dateTransform\" must be a function');\n }\n\n const targetPaths = new Set<string>();\n for (const field of fields) {\n if (!isValidCurrencyCode(field.toCurrency, allowedCurrencyCodes)) {\n throw new Error(\n `[mongoose-currency-convert] invalid toCurrency \"${field.toCurrency}\" in field config`,\n );\n }\n if (targetPaths.has(field.targetPath)) {\n throw new Error(\n `[mongoose-currency-convert] duplicate targetPath \"${field.targetPath}\" in field config`,\n );\n }\n targetPaths.add(field.targetPath);\n }\n\n if (\n options.fallbackRate !== undefined &&\n (typeof options.fallbackRate !== \"number\" || options.fallbackRate < 0)\n ) {\n throw new Error(\n '[mongoose-currency-convert] option \"fallbackRate\" must be a non-negative number',\n );\n }\n\n if (\n options.concurrency !== undefined &&\n (typeof options.concurrency !== \"number\" || options.concurrency < 1)\n ) {\n throw new Error('[mongoose-currency-convert] option \"concurrency\" must be a number >= 1');\n }\n\n if (rateValidation !== undefined) {\n if (typeof rateValidation !== \"object\" || rateValidation === null) {\n throw new Error('[mongoose-currency-convert] option \"rateValidation\" must be an object');\n }\n if (rateValidation.min !== undefined && typeof rateValidation.min !== \"number\") {\n throw new Error('[mongoose-currency-convert] option \"rateValidation.min\" must be a number');\n }\n if (rateValidation.max !== undefined && typeof rateValidation.max !== \"number\") {\n throw new Error('[mongoose-currency-convert] option \"rateValidation.max\" must be a number');\n }\n if (\n rateValidation.min !== undefined &&\n rateValidation.max !== undefined &&\n rateValidation.min > rateValidation.max\n ) {\n throw new Error(\n '[mongoose-currency-convert] option \"rateValidation.min\" must be <= \"rateValidation.max\"',\n );\n }\n }\n\n async function applyCurrencyConversion(\n doc: Record<string, unknown>,\n ): Promise<Map<string, unknown>> {\n const results = new Map<string, unknown>();\n\n type WorkItem = {\n field: (typeof fields)[number];\n amount: number;\n fromCurrency: string;\n conversionDate: Date;\n cacheKey: string;\n };\n const workItems: WorkItem[] = [];\n\n for (const field of fields) {\n const { sourcePath, currencyPath, datePath, targetPath, toCurrency } = field;\n\n if (!targetPath) {\n console.warn(\n `[mongoose-currency-convert] WARNING: 'targetPath' is required in field config`,\n );\n continue;\n }\n\n if (!schema.path(`${targetPath}.amount`)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: targetPath '${targetPath}' does not exist in schema`,\n );\n continue;\n }\n\n const amount = getNestedValue(doc, sourcePath);\n if (amount == null) continue;\n if (typeof amount !== \"number\" || Number.isNaN(amount)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: non-numeric amount at path '${sourcePath}': (${typeof amount})`,\n );\n continue;\n }\n\n const fromCurrency = getNestedValue(doc, currencyPath);\n if (typeof fromCurrency !== \"string\" || !fromCurrency) {\n console.warn(\n `[mongoose-currency-convert] Missing or invalid source currency at path: ${currencyPath}`,\n );\n continue;\n }\n\n if (!isValidCurrencyCode(fromCurrency, allowedCurrencyCodes)) {\n console.warn(`[mongoose-currency-convert] Invalid source currency code: ${fromCurrency}`);\n continue;\n }\n\n if (fromCurrency.toUpperCase() === toCurrency.toUpperCase()) continue;\n\n const dateValue = datePath ? getNestedValue(doc, datePath) : undefined;\n let conversionDate =\n dateValue &&\n (typeof dateValue === \"string\" ||\n typeof dateValue === \"number\" ||\n dateValue instanceof Date)\n ? new Date(dateValue)\n : new Date();\n if (Number.isNaN(conversionDate.getTime())) {\n console.warn(\n `[mongoose-currency-convert] Invalid date value at path '${datePath}', using current date`,\n );\n conversionDate = new Date();\n }\n\n if (dateTransform) {\n try {\n const transformed = dateTransform(conversionDate);\n if (transformed instanceof Date && !Number.isNaN(transformed.getTime())) {\n conversionDate = transformed;\n } else {\n console.warn(\n `[mongoose-currency-convert] dateTransform returned an invalid Date for field '${sourcePath}', using original date`,\n );\n }\n } catch (transformErr) {\n console.warn(\n `[mongoose-currency-convert] dateTransform threw for field '${sourcePath}', using original date:`,\n transformErr,\n );\n }\n }\n\n const cacheKey = `${fromCurrency.toUpperCase()}_${toCurrency.toUpperCase()}_${conversionDate.toISOString().slice(0, 10)}`;\n workItems.push({ field, amount, fromCurrency, conversionDate, cacheKey });\n }\n\n type RateResult =\n | { success: true; rate: number; usedFallback: boolean }\n | { success: false; error: unknown };\n\n async function fetchRate({\n field,\n fromCurrency,\n conversionDate,\n cacheKey,\n }: WorkItem): Promise<RateResult> {\n try {\n let rate: number | undefined;\n let usedFallback = false;\n if (cache) {\n try {\n rate = await cache.get(cacheKey);\n } catch (cacheErr) {\n console.warn(\"[mongoose-currency-convert] cache.get() failed:\", cacheErr);\n }\n }\n\n if (rate === undefined) {\n rate = await getRate(fromCurrency, field.toCurrency, conversionDate);\n if (cache && rate !== undefined && Number.isFinite(rate)) {\n try {\n await cache.set(cacheKey, rate);\n } catch (cacheErr) {\n console.warn(\"[mongoose-currency-convert] cache.set() failed:\", cacheErr);\n }\n }\n }\n\n if (rate == null || !Number.isFinite(rate) || rate < 0) {\n if (typeof fallbackRate === \"number\") {\n rate = fallbackRate;\n usedFallback = true;\n } else {\n throw new Error(\"Invalid rate\");\n }\n }\n\n if (rateValidation) {\n const { min = 0, max } = rateValidation;\n if (rate < min || (max !== undefined && rate > max)) {\n throw new Error(\n `Rate ${rate} is out of bounds [${min}, ${max ?? \"∞\"}] for ${fromCurrency}→${field.toCurrency}`,\n );\n }\n }\n\n return { success: true, rate, usedFallback };\n } catch (error) {\n if (typeof fallbackRate === \"number\") {\n if (rateValidation) {\n const { min = 0, max } = rateValidation;\n if (fallbackRate < min || (max !== undefined && fallbackRate > max)) {\n return {\n success: false,\n error: new Error(\n `Fallback rate ${fallbackRate} is also out of bounds [${min}, ${max ?? \"∞\"}] for ${fromCurrency}→${field.toCurrency}`,\n ),\n };\n }\n }\n return { success: true, rate: fallbackRate, usedFallback: true };\n }\n return { success: false, error };\n }\n }\n\n const limit = Math.max(1, concurrency);\n const rateResults: RateResult[] = [];\n for (let i = 0; i < workItems.length; i += limit) {\n const batch = workItems.slice(i, i + limit);\n rateResults.push(...(await Promise.all(batch.map(fetchRate))));\n }\n\n const convertedFields: string[] = [];\n for (let i = 0; i < workItems.length; i++) {\n const { field, amount, fromCurrency, conversionDate } = workItems[i];\n const { sourcePath, targetPath, toCurrency } = field;\n const rateResult = rateResults[i];\n\n if (!rateResult.success) {\n if (onError) {\n try {\n await onError({\n field: sourcePath,\n fromCurrency,\n toCurrency,\n date: conversionDate,\n error: rateResult.error,\n });\n } catch (callbackErr) {\n console.error(\"[mongoose-currency-convert] onError callback threw:\", callbackErr);\n }\n } else {\n console.error(\n `[mongoose-currency-convert] Error converting ${sourcePath}:`,\n rateResult.error,\n );\n }\n if (rollbackOnError) {\n for (const convertedField of convertedFields) {\n setNestedValue(doc, convertedField, undefined);\n results.delete(convertedField);\n }\n break;\n }\n continue;\n }\n\n const rawAmount = Number(amount) * rateResult.rate;\n const roundedAmount = round(rawAmount);\n if (!Number.isFinite(roundedAmount)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: round() returned a non-finite value for field '${sourcePath}', using unrounded amount`,\n );\n }\n const convertedValue = {\n amount: Number.isFinite(roundedAmount) ? roundedAmount : rawAmount,\n currency: toCurrency,\n date: conversionDate,\n };\n setNestedValue(doc, targetPath, convertedValue);\n results.set(targetPath, convertedValue);\n convertedFields.push(targetPath);\n if (onSuccess) {\n try {\n await onSuccess({\n field: sourcePath,\n fromCurrency,\n toCurrency,\n originalAmount: amount,\n convertedAmount: convertedValue.amount,\n rate: rateResult.rate,\n date: conversionDate,\n usedFallback: rateResult.usedFallback,\n });\n } catch (callbackErr) {\n console.error(\"[mongoose-currency-convert] onSuccess callback threw:\", callbackErr);\n }\n }\n }\n\n return results;\n }\n\n schema.pre(\"save\", async function (this: Document) {\n if (this.$locals.skipCurrencyConversion) return;\n const conversions = await applyCurrencyConversion(this as unknown as Record<string, unknown>);\n for (const [path, value] of conversions) {\n this.set(path, value);\n }\n });\n\n async function handleUpdateMiddleware(\n this: import(\"mongoose\").Query<unknown, unknown>,\n next: (err?: Error) => void,\n ) {\n const queryOptions = this.getOptions() as Record<string, unknown>;\n if (queryOptions.skipCurrencyConversion) return next();\n\n const update = this.getUpdate();\n if (!update) return next();\n\n const updateAny = update as Record<string, unknown>;\n let doc: Record<string, unknown>;\n try {\n if (typeof updateAny.$set === \"object\" && updateAny.$set !== null) {\n doc = { ...updateAny.$set };\n await applyCurrencyConversion(doc);\n updateAny.$set = doc;\n } else {\n doc = { ...updateAny };\n await applyCurrencyConversion(doc);\n Object.assign(updateAny, doc);\n }\n\n if (typeof updateAny.$setOnInsert === \"object\" && updateAny.$setOnInsert !== null) {\n const insertDoc = { ...updateAny.$setOnInsert } as Record<string, unknown>;\n await applyCurrencyConversion(insertDoc);\n updateAny.$setOnInsert = insertDoc;\n }\n } catch (err) {\n return next(err instanceof Error ? err : new Error(String(err)));\n }\n next();\n }\n\n schema.pre(\"findOneAndUpdate\", handleUpdateMiddleware);\n schema.pre(\"updateOne\", handleUpdateMiddleware);\n schema.pre(\"updateMany\", handleUpdateMiddleware);\n}\n"]}
package/dist/index.mjs CHANGED
@@ -40,7 +40,6 @@ var ISO_4217_CODES = [
40
40
  "COP",
41
41
  "COU",
42
42
  "CRC",
43
- "CUC",
44
43
  "CUP",
45
44
  "CVE",
46
45
  "CZK",
@@ -69,7 +68,6 @@ var ISO_4217_CODES = [
69
68
  // H
70
69
  "HKD",
71
70
  "HNL",
72
- "HRK",
73
71
  "HTG",
74
72
  "HUF",
75
73
  // I
@@ -277,7 +275,7 @@ function currencyConversionPlugin(schema, options) {
277
275
  rollbackOnError,
278
276
  cache,
279
277
  dateTransform,
280
- concurrency = Infinity,
278
+ concurrency = 5,
281
279
  rateValidation
282
280
  } = options;
283
281
  if (!fields || !Array.isArray(fields) || fields.length === 0) {
@@ -298,12 +296,19 @@ function currencyConversionPlugin(schema, options) {
298
296
  if (options.dateTransform !== void 0 && typeof options.dateTransform !== "function") {
299
297
  throw new Error('[mongoose-currency-convert] option "dateTransform" must be a function');
300
298
  }
299
+ const targetPaths = /* @__PURE__ */ new Set();
301
300
  for (const field of fields) {
302
301
  if (!isValidCurrencyCode(field.toCurrency, allowedCurrencyCodes)) {
303
302
  throw new Error(
304
303
  `[mongoose-currency-convert] invalid toCurrency "${field.toCurrency}" in field config`
305
304
  );
306
305
  }
306
+ if (targetPaths.has(field.targetPath)) {
307
+ throw new Error(
308
+ `[mongoose-currency-convert] duplicate targetPath "${field.targetPath}" in field config`
309
+ );
310
+ }
311
+ targetPaths.add(field.targetPath);
307
312
  }
308
313
  if (options.fallbackRate !== void 0 && (typeof options.fallbackRate !== "number" || options.fallbackRate < 0)) {
309
314
  throw new Error(
@@ -376,7 +381,14 @@ function currencyConversionPlugin(schema, options) {
376
381
  }
377
382
  if (dateTransform) {
378
383
  try {
379
- conversionDate = dateTransform(conversionDate);
384
+ const transformed = dateTransform(conversionDate);
385
+ if (transformed instanceof Date && !Number.isNaN(transformed.getTime())) {
386
+ conversionDate = transformed;
387
+ } else {
388
+ console.warn(
389
+ `[mongoose-currency-convert] dateTransform returned an invalid Date for field '${sourcePath}', using original date`
390
+ );
391
+ }
380
392
  } catch (transformErr) {
381
393
  console.warn(
382
394
  `[mongoose-currency-convert] dateTransform threw for field '${sourcePath}', using original date:`,
@@ -405,7 +417,7 @@ function currencyConversionPlugin(schema, options) {
405
417
  }
406
418
  if (rate === void 0) {
407
419
  rate = await getRate(fromCurrency, field.toCurrency, conversionDate);
408
- if (cache && rate !== void 0 && !Number.isNaN(rate)) {
420
+ if (cache && rate !== void 0 && Number.isFinite(rate)) {
409
421
  try {
410
422
  await cache.set(cacheKey, rate);
411
423
  } catch (cacheErr) {
@@ -413,7 +425,7 @@ function currencyConversionPlugin(schema, options) {
413
425
  }
414
426
  }
415
427
  }
416
- if (rate == null || Number.isNaN(rate)) {
428
+ if (rate == null || !Number.isFinite(rate) || rate < 0) {
417
429
  if (typeof fallbackRate === "number") {
418
430
  rate = fallbackRate;
419
431
  usedFallback = true;
@@ -422,7 +434,7 @@ function currencyConversionPlugin(schema, options) {
422
434
  }
423
435
  }
424
436
  if (rateValidation) {
425
- const { min = Number.EPSILON, max } = rateValidation;
437
+ const { min = 0, max } = rateValidation;
426
438
  if (rate < min || max !== void 0 && rate > max) {
427
439
  throw new Error(
428
440
  `Rate ${rate} is out of bounds [${min}, ${max ?? "\u221E"}] for ${fromCurrency}\u2192${field.toCurrency}`
@@ -433,7 +445,7 @@ function currencyConversionPlugin(schema, options) {
433
445
  } catch (error) {
434
446
  if (typeof fallbackRate === "number") {
435
447
  if (rateValidation) {
436
- const { min = Number.EPSILON, max } = rateValidation;
448
+ const { min = 0, max } = rateValidation;
437
449
  if (fallbackRate < min || max !== void 0 && fallbackRate > max) {
438
450
  return {
439
451
  success: false,
@@ -487,8 +499,15 @@ function currencyConversionPlugin(schema, options) {
487
499
  }
488
500
  continue;
489
501
  }
502
+ const rawAmount = Number(amount) * rateResult.rate;
503
+ const roundedAmount = round(rawAmount);
504
+ if (!Number.isFinite(roundedAmount)) {
505
+ console.warn(
506
+ `[mongoose-currency-convert] WARNING: round() returned a non-finite value for field '${sourcePath}', using unrounded amount`
507
+ );
508
+ }
490
509
  const convertedValue = {
491
- amount: round(Number(amount) * rateResult.rate),
510
+ amount: Number.isFinite(roundedAmount) ? roundedAmount : rawAmount,
492
511
  currency: toCurrency,
493
512
  date: conversionDate
494
513
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/helpers.ts","../src/index.ts"],"names":[],"mappings":";AACA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAErB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EA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","file":"index.mjs","sourcesContent":["// Complete ISO 4217 active currency codes\nconst ISO_4217_CODES = [\n // A\n \"AED\",\n \"AFN\",\n \"ALL\",\n \"AMD\",\n \"ANG\",\n \"AOA\",\n \"ARS\",\n \"AUD\",\n \"AWG\",\n \"AZN\",\n // B\n \"BAM\",\n \"BBD\",\n \"BDT\",\n \"BGN\",\n \"BHD\",\n \"BIF\",\n \"BMD\",\n \"BND\",\n \"BOB\",\n \"BOV\",\n \"BRL\",\n \"BSD\",\n \"BTN\",\n \"BWP\",\n \"BYN\",\n \"BZD\",\n // C\n \"CAD\",\n \"CDF\",\n \"CHE\",\n \"CHF\",\n \"CHW\",\n \"CLF\",\n \"CLP\",\n \"CNY\",\n \"COP\",\n \"COU\",\n \"CRC\",\n \"CUC\",\n \"CUP\",\n \"CVE\",\n \"CZK\",\n // D\n \"DJF\",\n \"DKK\",\n \"DOP\",\n \"DZD\",\n // E\n \"EGP\",\n \"ERN\",\n \"ETB\",\n \"EUR\",\n // F\n \"FJD\",\n \"FKP\",\n // G\n \"GBP\",\n \"GEL\",\n \"GHS\",\n \"GIP\",\n \"GMD\",\n \"GNF\",\n \"GTQ\",\n \"GYD\",\n // H\n \"HKD\",\n \"HNL\",\n \"HRK\",\n \"HTG\",\n \"HUF\",\n // I\n \"IDR\",\n \"ILS\",\n \"INR\",\n \"IQD\",\n \"IRR\",\n \"ISK\",\n // J\n \"JMD\",\n \"JOD\",\n \"JPY\",\n // K\n \"KES\",\n \"KGS\",\n \"KHR\",\n \"KMF\",\n \"KPW\",\n \"KRW\",\n \"KWD\",\n \"KYD\",\n \"KZT\",\n // L\n \"LAK\",\n \"LBP\",\n \"LRD\",\n \"LSL\",\n \"LYD\",\n // M\n \"MAD\",\n \"MDL\",\n \"MGA\",\n \"MKD\",\n \"MMK\",\n \"MNT\",\n \"MOP\",\n \"MRU\",\n \"MUR\",\n \"MVR\",\n \"MWK\",\n \"MXN\",\n \"MXV\",\n \"MYR\",\n \"MZN\",\n // N\n \"NAD\",\n \"NGN\",\n \"NIO\",\n \"NOK\",\n \"NPR\",\n \"NZD\",\n // O\n \"OMR\",\n // P\n \"PAB\",\n \"PEN\",\n \"PGK\",\n \"PHP\",\n \"PKR\",\n \"PLN\",\n \"PYG\",\n // Q\n \"QAR\",\n // R\n \"RON\",\n \"RSD\",\n \"RUB\",\n \"RWF\",\n // S\n \"SAR\",\n \"SBD\",\n \"SCR\",\n \"SDG\",\n \"SEK\",\n \"SGD\",\n \"SHP\",\n \"SLE\",\n \"SOS\",\n \"SRD\",\n \"SSP\",\n \"STN\",\n \"SVC\",\n \"SYP\",\n \"SZL\",\n // T\n \"THB\",\n \"TJS\",\n \"TMT\",\n \"TND\",\n \"TOP\",\n \"TRY\",\n \"TTD\",\n \"TWD\",\n \"TZS\",\n // U\n \"UAH\",\n \"UGX\",\n \"USD\",\n \"USN\",\n \"UYI\",\n \"UYU\",\n \"UZS\",\n // V\n \"VES\",\n \"VND\",\n \"VUV\",\n // W\n \"WST\",\n // X (special / supra-national)\n \"XAF\",\n \"XAG\",\n \"XAU\",\n \"XBA\",\n \"XBB\",\n \"XBC\",\n \"XBD\",\n \"XCD\",\n \"XDR\",\n \"XOF\",\n \"XPD\",\n \"XPF\",\n \"XPT\",\n \"XSU\",\n \"XTS\",\n \"XUA\",\n \"XXX\",\n // Y\n \"YER\",\n // Z\n \"ZAR\",\n \"ZMW\",\n \"ZWL\",\n];\nconst PATH_CACHE_MAX_SIZE = 500;\nconst pathCache = new Map<string, string[]>();\n\nexport function getPathArray(path: string): string[] {\n const cached = pathCache.get(path);\n if (cached) {\n // Refresh insertion order so least-recently-used entries are evicted first\n pathCache.delete(path);\n pathCache.set(path, cached);\n return cached;\n }\n\n const arr = path.split(\".\");\n if (pathCache.size >= PATH_CACHE_MAX_SIZE) {\n pathCache.delete(pathCache.keys().next().value as string);\n }\n pathCache.set(path, arr);\n return arr;\n}\n\nexport function getNestedValue(obj: unknown, path: string | string[]): unknown {\n const keys = Array.isArray(path) ? path : getPathArray(path);\n return keys.reduce((acc, key) => {\n if (acc && typeof acc === \"object\") {\n if (!Number.isNaN(Number(key)) && Array.isArray(acc)) {\n return acc[Number(key)];\n }\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\nexport function setNestedValue(obj: unknown, path: string | string[], value: unknown): void {\n const parts = Array.isArray(path) ? [...path] : [...getPathArray(path)];\n const last = parts.pop();\n if (!last) return;\n\n let target = obj as Record<string, unknown>;\n for (const key of parts) {\n if (!Number.isNaN(Number(key)) && Array.isArray(target)) {\n if (!target[Number(key)]) target[Number(key)] = {};\n target = target[Number(key)] as Record<string, unknown>;\n } else {\n if (typeof target[key] !== \"object\" || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n }\n if (!Number.isNaN(Number(last)) && Array.isArray(target)) {\n target[Number(last)] = value;\n } else {\n target[last] = value;\n }\n}\n\nexport function defaultRound(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nexport function isValidCurrencyCode(code: string, allowedCodes?: string[]): boolean {\n const list = allowedCodes || ISO_4217_CODES;\n if (typeof code !== \"string\") return false;\n const normalized = code.toUpperCase();\n return list.some((c) => c.toUpperCase() === normalized);\n}\n","import type { Schema, Document } from \"mongoose\";\n\nimport type { CurrencyPluginOptions } from \"./types\";\nimport { defaultRound, getNestedValue, isValidCurrencyCode, setNestedValue } from \"./utils/helpers\";\n\n/**\n * Mongoose plugin that automatically converts currency fields on save and update operations.\n *\n * ## Error handling policy\n *\n * The plugin uses a three-tier strategy depending on when and where an error occurs:\n *\n * 1. **Initialization errors** (`throw`): Missing or invalid required options (`fields`, `getRate`)\n * cause an immediate `Error` to be thrown when the plugin is registered. These are\n * programmer errors and must be fixed before the application starts.\n *\n * 2. **Field validation warnings** (`console.warn` + skip): Invalid field configurations\n * detected at conversion time (missing `targetPath`, invalid currency code, non-numeric\n * `amount`, invalid date) are logged as warnings and the field is silently skipped.\n * The document is still saved with the remaining conversions applied.\n *\n * 3. **Rate fetch errors** (`onError` callback or `console.error`): Errors thrown by `getRate`\n * or invalid rates returned by it are passed to the `onError` callback if provided,\n * otherwise logged via `console.error`. If `fallbackRate` is set it is used instead.\n * If `rollbackOnError` is `true`, all previously converted fields in that document are\n * reverted before the save continues.\n */\nexport function currencyConversionPlugin(schema: Schema, options: CurrencyPluginOptions) {\n const {\n fields,\n getRate,\n round = defaultRound,\n allowedCurrencyCodes,\n onError,\n onSuccess,\n fallbackRate,\n rollbackOnError,\n cache,\n dateTransform,\n concurrency = Infinity,\n rateValidation,\n } = options;\n\n if (!fields || !Array.isArray(fields) || fields.length === 0) {\n throw new Error('[mongoose-currency-convert] option \"fields\" must be a non-empty array');\n }\n\n if (typeof getRate !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"getRate\" must be a function');\n }\n\n if (options.round !== undefined && typeof options.round !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"round\" must be a function');\n }\n\n if (options.onError !== undefined && typeof options.onError !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"onError\" must be a function');\n }\n\n if (options.onSuccess !== undefined && typeof options.onSuccess !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"onSuccess\" must be a function');\n }\n\n if (options.dateTransform !== undefined && typeof options.dateTransform !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"dateTransform\" must be a function');\n }\n\n for (const field of fields) {\n if (!isValidCurrencyCode(field.toCurrency, allowedCurrencyCodes)) {\n throw new Error(\n `[mongoose-currency-convert] invalid toCurrency \"${field.toCurrency}\" in field config`,\n );\n }\n }\n\n if (\n options.fallbackRate !== undefined &&\n (typeof options.fallbackRate !== \"number\" || options.fallbackRate < 0)\n ) {\n throw new Error(\n '[mongoose-currency-convert] option \"fallbackRate\" must be a non-negative number',\n );\n }\n\n if (\n options.concurrency !== undefined &&\n (typeof options.concurrency !== \"number\" || options.concurrency < 1)\n ) {\n throw new Error('[mongoose-currency-convert] option \"concurrency\" must be a number >= 1');\n }\n\n if (rateValidation !== undefined) {\n if (typeof rateValidation !== \"object\" || rateValidation === null) {\n throw new Error('[mongoose-currency-convert] option \"rateValidation\" must be an object');\n }\n if (rateValidation.min !== undefined && typeof rateValidation.min !== \"number\") {\n throw new Error('[mongoose-currency-convert] option \"rateValidation.min\" must be a number');\n }\n if (rateValidation.max !== undefined && typeof rateValidation.max !== \"number\") {\n throw new Error('[mongoose-currency-convert] option \"rateValidation.max\" must be a number');\n }\n if (\n rateValidation.min !== undefined &&\n rateValidation.max !== undefined &&\n rateValidation.min > rateValidation.max\n ) {\n throw new Error(\n '[mongoose-currency-convert] option \"rateValidation.min\" must be <= \"rateValidation.max\"',\n );\n }\n }\n\n async function applyCurrencyConversion(\n doc: Record<string, unknown>,\n ): Promise<Map<string, unknown>> {\n const results = new Map<string, unknown>();\n\n type WorkItem = {\n field: (typeof fields)[number];\n amount: number;\n fromCurrency: string;\n conversionDate: Date;\n cacheKey: string;\n };\n const workItems: WorkItem[] = [];\n\n for (const field of fields) {\n const { sourcePath, currencyPath, datePath, targetPath, toCurrency } = field;\n\n if (!targetPath) {\n console.warn(\n `[mongoose-currency-convert] WARNING: 'targetPath' is required in field config`,\n );\n continue;\n }\n\n if (!schema.path(`${targetPath}.amount`)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: targetPath '${targetPath}' does not exist in schema`,\n );\n continue;\n }\n\n const amount = getNestedValue(doc, sourcePath);\n if (amount == null) continue;\n if (typeof amount !== \"number\" || Number.isNaN(amount)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: non-numeric amount at path '${sourcePath}': (${typeof amount})`,\n );\n continue;\n }\n\n const fromCurrency = getNestedValue(doc, currencyPath);\n if (typeof fromCurrency !== \"string\" || !fromCurrency) {\n console.warn(\n `[mongoose-currency-convert] Missing or invalid source currency at path: ${currencyPath}`,\n );\n continue;\n }\n\n if (!isValidCurrencyCode(fromCurrency, allowedCurrencyCodes)) {\n console.warn(`[mongoose-currency-convert] Invalid source currency code: ${fromCurrency}`);\n continue;\n }\n\n if (fromCurrency.toUpperCase() === toCurrency.toUpperCase()) continue;\n\n const dateValue = datePath ? getNestedValue(doc, datePath) : undefined;\n let conversionDate =\n dateValue &&\n (typeof dateValue === \"string\" ||\n typeof dateValue === \"number\" ||\n dateValue instanceof Date)\n ? new Date(dateValue)\n : new Date();\n if (Number.isNaN(conversionDate.getTime())) {\n console.warn(\n `[mongoose-currency-convert] Invalid date value at path '${datePath}', using current date`,\n );\n conversionDate = new Date();\n }\n\n if (dateTransform) {\n try {\n conversionDate = dateTransform(conversionDate);\n } catch (transformErr) {\n console.warn(\n `[mongoose-currency-convert] dateTransform threw for field '${sourcePath}', using original date:`,\n transformErr,\n );\n }\n }\n\n const cacheKey = `${fromCurrency.toUpperCase()}_${toCurrency.toUpperCase()}_${conversionDate.toISOString().slice(0, 10)}`;\n workItems.push({ field, amount, fromCurrency, conversionDate, cacheKey });\n }\n\n type RateResult =\n | { success: true; rate: number; usedFallback: boolean }\n | { success: false; error: unknown };\n\n async function fetchRate({\n field,\n fromCurrency,\n conversionDate,\n cacheKey,\n }: WorkItem): Promise<RateResult> {\n try {\n let rate: number | undefined;\n let usedFallback = false;\n if (cache) {\n try {\n rate = await cache.get(cacheKey);\n } catch (cacheErr) {\n console.warn(\"[mongoose-currency-convert] cache.get() failed:\", cacheErr);\n }\n }\n\n if (rate === undefined) {\n rate = await getRate(fromCurrency, field.toCurrency, conversionDate);\n if (cache && rate !== undefined && !Number.isNaN(rate)) {\n try {\n await cache.set(cacheKey, rate);\n } catch (cacheErr) {\n console.warn(\"[mongoose-currency-convert] cache.set() failed:\", cacheErr);\n }\n }\n }\n\n if (rate == null || Number.isNaN(rate)) {\n if (typeof fallbackRate === \"number\") {\n rate = fallbackRate;\n usedFallback = true;\n } else {\n throw new Error(\"Invalid rate\");\n }\n }\n\n if (rateValidation) {\n const { min = Number.EPSILON, max } = rateValidation;\n if (rate < min || (max !== undefined && rate > max)) {\n throw new Error(\n `Rate ${rate} is out of bounds [${min}, ${max ?? \"∞\"}] for ${fromCurrency}→${field.toCurrency}`,\n );\n }\n }\n\n return { success: true, rate, usedFallback };\n } catch (error) {\n if (typeof fallbackRate === \"number\") {\n if (rateValidation) {\n const { min = Number.EPSILON, max } = rateValidation;\n if (fallbackRate < min || (max !== undefined && fallbackRate > max)) {\n return {\n success: false,\n error: new Error(\n `Fallback rate ${fallbackRate} is also out of bounds [${min}, ${max ?? \"∞\"}] for ${fromCurrency}→${field.toCurrency}`,\n ),\n };\n }\n }\n return { success: true, rate: fallbackRate, usedFallback: true };\n }\n return { success: false, error };\n }\n }\n\n const limit = Math.max(1, concurrency);\n const rateResults: RateResult[] = [];\n for (let i = 0; i < workItems.length; i += limit) {\n const batch = workItems.slice(i, i + limit);\n rateResults.push(...(await Promise.all(batch.map(fetchRate))));\n }\n\n const convertedFields: string[] = [];\n for (let i = 0; i < workItems.length; i++) {\n const { field, amount, fromCurrency, conversionDate } = workItems[i];\n const { sourcePath, targetPath, toCurrency } = field;\n const rateResult = rateResults[i];\n\n if (!rateResult.success) {\n if (onError) {\n try {\n await onError({\n field: sourcePath,\n fromCurrency,\n toCurrency,\n date: conversionDate,\n error: rateResult.error,\n });\n } catch (callbackErr) {\n console.error(\"[mongoose-currency-convert] onError callback threw:\", callbackErr);\n }\n } else {\n console.error(\n `[mongoose-currency-convert] Error converting ${sourcePath}:`,\n rateResult.error,\n );\n }\n if (rollbackOnError) {\n for (const convertedField of convertedFields) {\n setNestedValue(doc, convertedField, undefined);\n results.delete(convertedField);\n }\n break;\n }\n continue;\n }\n\n const convertedValue = {\n amount: round(Number(amount) * rateResult.rate),\n currency: toCurrency,\n date: conversionDate,\n };\n setNestedValue(doc, targetPath, convertedValue);\n results.set(targetPath, convertedValue);\n convertedFields.push(targetPath);\n if (onSuccess) {\n try {\n await onSuccess({\n field: sourcePath,\n fromCurrency,\n toCurrency,\n originalAmount: amount,\n convertedAmount: convertedValue.amount,\n rate: rateResult.rate,\n date: conversionDate,\n usedFallback: rateResult.usedFallback,\n });\n } catch (callbackErr) {\n console.error(\"[mongoose-currency-convert] onSuccess callback threw:\", callbackErr);\n }\n }\n }\n\n return results;\n }\n\n schema.pre(\"save\", async function (this: Document) {\n if (this.$locals.skipCurrencyConversion) return;\n const conversions = await applyCurrencyConversion(this as unknown as Record<string, unknown>);\n for (const [path, value] of conversions) {\n this.set(path, value);\n }\n });\n\n async function handleUpdateMiddleware(\n this: import(\"mongoose\").Query<unknown, unknown>,\n next: (err?: Error) => void,\n ) {\n const queryOptions = this.getOptions() as Record<string, unknown>;\n if (queryOptions.skipCurrencyConversion) return next();\n\n const update = this.getUpdate();\n if (!update) return next();\n\n const updateAny = update as Record<string, unknown>;\n let doc: Record<string, unknown>;\n try {\n if (typeof updateAny.$set === \"object\" && updateAny.$set !== null) {\n doc = { ...updateAny.$set };\n await applyCurrencyConversion(doc);\n updateAny.$set = doc;\n } else {\n doc = { ...updateAny };\n await applyCurrencyConversion(doc);\n Object.assign(updateAny, doc);\n }\n\n if (typeof updateAny.$setOnInsert === \"object\" && updateAny.$setOnInsert !== null) {\n const insertDoc = { ...updateAny.$setOnInsert } as Record<string, unknown>;\n await applyCurrencyConversion(insertDoc);\n updateAny.$setOnInsert = insertDoc;\n }\n } catch (err) {\n return next(err instanceof Error ? err : new Error(String(err)));\n }\n next();\n }\n\n schema.pre(\"findOneAndUpdate\", handleUpdateMiddleware);\n schema.pre(\"updateOne\", handleUpdateMiddleware);\n schema.pre(\"updateMany\", handleUpdateMiddleware);\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/helpers.ts","../src/index.ts"],"names":[],"mappings":";AACA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAErB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA;AACA,IAAM,mBAAA,GAAsB,GAAA;AAC5B,IAAM,SAAA,uBAAgB,GAAA,EAAsB;AAErC,SAAS,aAAa,IAAA,EAAwB;AACnD,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,GAAA,CAAI,IAAI,CAAA;AACjC,EAAA,IAAI,MAAA,EAAQ;AAEV,IAAA,SAAA,CAAU,OAAO,IAAI,CAAA;AACrB,IAAA,SAAA,CAAU,GAAA,CAAI,MAAM,MAAM,CAAA;AAC1B,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC1B,EAAA,IAAI,SAAA,CAAU,QAAQ,mBAAA,EAAqB;AACzC,IAAA,SAAA,CAAU,OAAO,SAAA,CAAU,IAAA,EAAK,CAAE,IAAA,GAAO,KAAe,CAAA;AAAA,EAC1D;AACA,EAAA,SAAA,CAAU,GAAA,CAAI,MAAM,GAAG,CAAA;AACvB,EAAA,OAAO,GAAA;AACT;AAEO,SAAS,cAAA,CAAe,KAAc,IAAA,EAAkC;AAC7E,EAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,IAAA,GAAO,aAAa,IAAI,CAAA;AAC3D,EAAA,OAAO,IAAA,CAAK,MAAA,CAAO,CAAC,GAAA,EAAK,GAAA,KAAQ;AAC/B,IAAA,IAAI,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,EAAU;AAClC,MAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC,CAAA,IAAK,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACpD,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MACxB;AACA,MAAA,OAAQ,IAAgC,GAAG,CAAA;AAAA,IAC7C;AACA,IAAA,OAAO,MAAA;AAAA,EACT,GAAG,GAAG,CAAA;AACR;AAEO,SAAS,cAAA,CAAe,GAAA,EAAc,IAAA,EAAyB,KAAA,EAAsB;AAC1F,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,CAAC,GAAG,IAAI,CAAA,GAAI,CAAC,GAAG,YAAA,CAAa,IAAI,CAAC,CAAA;AACtE,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,EAAI;AACvB,EAAA,IAAI,CAAC,IAAA,EAAM;AAEX,EAAA,IAAI,MAAA,GAAS,GAAA;AACb,EAAA,KAAA,MAAW,OAAO,KAAA,EAAO;AACvB,IAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC,CAAA,IAAK,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AACvD,MAAA,IAAI,CAAC,MAAA,CAAO,MAAA,CAAO,GAAG,CAAC,CAAA,EAAG,MAAA,CAAO,MAAA,CAAO,GAAG,CAAC,CAAA,GAAI,EAAC;AACjD,MAAA,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,IAC7B,CAAA,MAAO;AACL,MAAA,IAAI,OAAO,OAAO,GAAG,CAAA,KAAM,YAAY,MAAA,CAAO,GAAG,MAAM,IAAA,EAAM;AAC3D,QAAA,MAAA,CAAO,GAAG,IAAI,EAAC;AAAA,MACjB;AACA,MAAA,MAAA,GAAS,OAAO,GAAG,CAAA;AAAA,IACrB;AAAA,EACF;AACA,EAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,IAAI,CAAC,CAAA,IAAK,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AACxD,IAAA,MAAA,CAAO,MAAA,CAAO,IAAI,CAAC,CAAA,GAAI,KAAA;AAAA,EACzB,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAI,CAAA,GAAI,KAAA;AAAA,EACjB;AACF;AAEO,SAAS,aAAa,KAAA,EAAuB;AAClD,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,GAAG,CAAA,GAAI,GAAA;AACnC;AAEO,SAAS,mBAAA,CAAoB,MAAc,YAAA,EAAkC;AAClF,EAAA,MAAM,OAAO,YAAA,IAAgB,cAAA;AAC7B,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,KAAA;AACrC,EAAA,MAAM,UAAA,GAAa,KAAK,WAAA,EAAY;AACpC,EAAA,OAAO,KAAK,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,WAAA,OAAkB,UAAU,CAAA;AACxD;;;ACnPO,SAAS,wBAAA,CAAyB,QAAgB,OAAA,EAAgC;AACvF,EAAA,MAAM;AAAA,IACJ,MAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA,GAAQ,YAAA;AAAA,IACR,oBAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,eAAA;AAAA,IACA,KAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA,GAAc,CAAA;AAAA,IACd;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,IAAI,CAAC,UAAU,CAAC,KAAA,CAAM,QAAQ,MAAM,CAAA,IAAK,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG;AAC5D,IAAA,MAAM,IAAI,MAAM,uEAAuE,CAAA;AAAA,EACzF;AAEA,EAAA,IAAI,OAAO,YAAY,UAAA,EAAY;AACjC,IAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,EACnF;AAEA,EAAA,IAAI,QAAQ,KAAA,KAAU,MAAA,IAAa,OAAO,OAAA,CAAQ,UAAU,UAAA,EAAY;AACtE,IAAA,MAAM,IAAI,MAAM,+DAA+D,CAAA;AAAA,EACjF;AAEA,EAAA,IAAI,QAAQ,OAAA,KAAY,MAAA,IAAa,OAAO,OAAA,CAAQ,YAAY,UAAA,EAAY;AAC1E,IAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,EACnF;AAEA,EAAA,IAAI,QAAQ,SAAA,KAAc,MAAA,IAAa,OAAO,OAAA,CAAQ,cAAc,UAAA,EAAY;AAC9E,IAAA,MAAM,IAAI,MAAM,mEAAmE,CAAA;AAAA,EACrF;AAEA,EAAA,IAAI,QAAQ,aAAA,KAAkB,MAAA,IAAa,OAAO,OAAA,CAAQ,kBAAkB,UAAA,EAAY;AACtF,IAAA,MAAM,IAAI,MAAM,uEAAuE,CAAA;AAAA,EACzF;AAEA,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAI,CAAC,mBAAA,CAAoB,KAAA,CAAM,UAAA,EAAY,oBAAoB,CAAA,EAAG;AAChE,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,gDAAA,EAAmD,MAAM,UAAU,CAAA,iBAAA;AAAA,OACrE;AAAA,IACF;AACA,IAAA,IAAI,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,UAAU,CAAA,EAAG;AACrC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,kDAAA,EAAqD,MAAM,UAAU,CAAA,iBAAA;AAAA,OACvE;AAAA,IACF;AACA,IAAA,WAAA,CAAY,GAAA,CAAI,MAAM,UAAU,CAAA;AAAA,EAClC;AAEA,EAAA,IACE,OAAA,CAAQ,iBAAiB,MAAA,KACxB,OAAO,QAAQ,YAAA,KAAiB,QAAA,IAAY,OAAA,CAAQ,YAAA,GAAe,CAAA,CAAA,EACpE;AACA,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IACE,OAAA,CAAQ,gBAAgB,MAAA,KACvB,OAAO,QAAQ,WAAA,KAAgB,QAAA,IAAY,OAAA,CAAQ,WAAA,GAAc,CAAA,CAAA,EAClE;AACA,IAAA,MAAM,IAAI,MAAM,wEAAwE,CAAA;AAAA,EAC1F;AAEA,EAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,IAAA,IAAI,OAAO,cAAA,KAAmB,QAAA,IAAY,cAAA,KAAmB,IAAA,EAAM;AACjE,MAAA,MAAM,IAAI,MAAM,uEAAuE,CAAA;AAAA,IACzF;AACA,IAAA,IAAI,eAAe,GAAA,KAAQ,MAAA,IAAa,OAAO,cAAA,CAAe,QAAQ,QAAA,EAAU;AAC9E,MAAA,MAAM,IAAI,MAAM,0EAA0E,CAAA;AAAA,IAC5F;AACA,IAAA,IAAI,eAAe,GAAA,KAAQ,MAAA,IAAa,OAAO,cAAA,CAAe,QAAQ,QAAA,EAAU;AAC9E,MAAA,MAAM,IAAI,MAAM,0EAA0E,CAAA;AAAA,IAC5F;AACA,IAAA,IACE,cAAA,CAAe,QAAQ,MAAA,IACvB,cAAA,CAAe,QAAQ,MAAA,IACvB,cAAA,CAAe,GAAA,GAAM,cAAA,CAAe,GAAA,EACpC;AACA,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,eAAe,wBACb,GAAA,EAC+B;AAC/B,IAAA,MAAM,OAAA,uBAAc,GAAA,EAAqB;AASzC,IAAA,MAAM,YAAwB,EAAC;AAE/B,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,MAAM,EAAE,UAAA,EAAY,YAAA,EAAc,QAAA,EAAU,UAAA,EAAY,YAAW,GAAI,KAAA;AAEvE,MAAA,IAAI,CAAC,UAAA,EAAY;AACf,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,CAAA,6EAAA;AAAA,SACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,MAAA,CAAO,IAAA,CAAK,CAAA,EAAG,UAAU,SAAS,CAAA,EAAG;AACxC,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,oDAAoD,UAAU,CAAA,0BAAA;AAAA,SAChE;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,GAAS,cAAA,CAAe,GAAA,EAAK,UAAU,CAAA;AAC7C,MAAA,IAAI,UAAU,IAAA,EAAM;AACpB,MAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA,EAAG;AACtD,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,CAAA,iEAAA,EAAoE,UAAU,CAAA,IAAA,EAAO,OAAO,MAAM,CAAA,CAAA;AAAA,SACpG;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,YAAA,GAAe,cAAA,CAAe,GAAA,EAAK,YAAY,CAAA;AACrD,MAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,CAAC,YAAA,EAAc;AACrD,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,2EAA2E,YAAY,CAAA;AAAA,SACzF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,mBAAA,CAAoB,YAAA,EAAc,oBAAoB,CAAA,EAAG;AAC5D,QAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,0DAAA,EAA6D,YAAY,CAAA,CAAE,CAAA;AACxF,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,YAAA,CAAa,WAAA,EAAY,KAAM,UAAA,CAAW,aAAY,EAAG;AAE7D,MAAA,MAAM,SAAA,GAAY,QAAA,GAAW,cAAA,CAAe,GAAA,EAAK,QAAQ,CAAA,GAAI,MAAA;AAC7D,MAAA,IAAI,cAAA,GACF,SAAA,KACC,OAAO,SAAA,KAAc,YACpB,OAAO,SAAA,KAAc,QAAA,IACrB,SAAA,YAAqB,QACnB,IAAI,IAAA,CAAK,SAAS,CAAA,uBACd,IAAA,EAAK;AACf,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,cAAA,CAAe,OAAA,EAAS,CAAA,EAAG;AAC1C,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,2DAA2D,QAAQ,CAAA,qBAAA;AAAA,SACrE;AACA,QAAA,cAAA,uBAAqB,IAAA,EAAK;AAAA,MAC5B;AAEA,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,IAAI;AACF,UAAA,MAAM,WAAA,GAAc,cAAc,cAAc,CAAA;AAChD,UAAA,IAAI,WAAA,YAAuB,QAAQ,CAAC,MAAA,CAAO,MAAM,WAAA,CAAY,OAAA,EAAS,CAAA,EAAG;AACvE,YAAA,cAAA,GAAiB,WAAA;AAAA,UACnB,CAAA,MAAO;AACL,YAAA,OAAA,CAAQ,IAAA;AAAA,cACN,iFAAiF,UAAU,CAAA,sBAAA;AAAA,aAC7F;AAAA,UACF;AAAA,QACF,SAAS,YAAA,EAAc;AACrB,UAAA,OAAA,CAAQ,IAAA;AAAA,YACN,8DAA8D,UAAU,CAAA,uBAAA,CAAA;AAAA,YACxE;AAAA,WACF;AAAA,QACF;AAAA,MACF;AAEA,MAAA,MAAM,WAAW,CAAA,EAAG,YAAA,CAAa,WAAA,EAAa,IAAI,UAAA,CAAW,WAAA,EAAa,CAAA,CAAA,EAAI,eAAe,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AACvH,MAAA,SAAA,CAAU,KAAK,EAAE,KAAA,EAAO,QAAQ,YAAA,EAAc,cAAA,EAAgB,UAAU,CAAA;AAAA,IAC1E;AAMA,IAAA,eAAe,SAAA,CAAU;AAAA,MACvB,KAAA;AAAA,MACA,YAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACF,EAAkC;AAChC,MAAA,IAAI;AACF,QAAA,IAAI,IAAA;AACJ,QAAA,IAAI,YAAA,GAAe,KAAA;AACnB,QAAA,IAAI,KAAA,EAAO;AACT,UAAA,IAAI;AACF,YAAA,IAAA,GAAO,MAAM,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA;AAAA,UACjC,SAAS,QAAA,EAAU;AACjB,YAAA,OAAA,CAAQ,IAAA,CAAK,mDAAmD,QAAQ,CAAA;AAAA,UAC1E;AAAA,QACF;AAEA,QAAA,IAAI,SAAS,KAAA,CAAA,EAAW;AACtB,UAAA,IAAA,GAAO,MAAM,OAAA,CAAQ,YAAA,EAAc,KAAA,CAAM,YAAY,cAAc,CAAA;AACnE,UAAA,IAAI,SAAS,IAAA,KAAS,KAAA,CAAA,IAAa,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA,EAAG;AACxD,YAAA,IAAI;AACF,cAAA,MAAM,KAAA,CAAM,GAAA,CAAI,QAAA,EAAU,IAAI,CAAA;AAAA,YAChC,SAAS,QAAA,EAAU;AACjB,cAAA,OAAA,CAAQ,IAAA,CAAK,mDAAmD,QAAQ,CAAA;AAAA,YAC1E;AAAA,UACF;AAAA,QACF;AAEA,QAAA,IAAI,IAAA,IAAQ,QAAQ,CAAC,MAAA,CAAO,SAAS,IAAI,CAAA,IAAK,OAAO,CAAA,EAAG;AACtD,UAAA,IAAI,OAAO,iBAAiB,QAAA,EAAU;AACpC,YAAA,IAAA,GAAO,YAAA;AACP,YAAA,YAAA,GAAe,IAAA;AAAA,UACjB,CAAA,MAAO;AACL,YAAA,MAAM,IAAI,MAAM,cAAc,CAAA;AAAA,UAChC;AAAA,QACF;AAEA,QAAA,IAAI,cAAA,EAAgB;AAClB,UAAA,MAAM,EAAE,GAAA,GAAM,CAAA,EAAG,GAAA,EAAI,GAAI,cAAA;AACzB,UAAA,IAAI,IAAA,GAAO,GAAA,IAAQ,GAAA,KAAQ,KAAA,CAAA,IAAa,OAAO,GAAA,EAAM;AACnD,YAAA,MAAM,IAAI,KAAA;AAAA,cACR,CAAA,KAAA,EAAQ,IAAI,CAAA,mBAAA,EAAsB,GAAG,CAAA,EAAA,EAAK,GAAA,IAAO,QAAG,CAAA,MAAA,EAAS,YAAY,CAAA,MAAA,EAAI,KAAA,CAAM,UAAU,CAAA;AAAA,aAC/F;AAAA,UACF;AAAA,QACF;AAEA,QAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,YAAA,EAAa;AAAA,MAC7C,SAAS,KAAA,EAAO;AACd,QAAA,IAAI,OAAO,iBAAiB,QAAA,EAAU;AACpC,UAAA,IAAI,cAAA,EAAgB;AAClB,YAAA,MAAM,EAAE,GAAA,GAAM,CAAA,EAAG,GAAA,EAAI,GAAI,cAAA;AACzB,YAAA,IAAI,YAAA,GAAe,GAAA,IAAQ,GAAA,KAAQ,MAAA,IAAa,eAAe,GAAA,EAAM;AACnE,cAAA,OAAO;AAAA,gBACL,OAAA,EAAS,KAAA;AAAA,gBACT,OAAO,IAAI,KAAA;AAAA,kBACT,CAAA,cAAA,EAAiB,YAAY,CAAA,wBAAA,EAA2B,GAAG,CAAA,EAAA,EAAK,GAAA,IAAO,QAAG,CAAA,MAAA,EAAS,YAAY,CAAA,MAAA,EAAI,KAAA,CAAM,UAAU,CAAA;AAAA;AACrH,eACF;AAAA,YACF;AAAA,UACF;AACA,UAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,YAAA,EAAc,cAAc,IAAA,EAAK;AAAA,QACjE;AACA,QAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,KAAA,EAAM;AAAA,MACjC;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,WAAW,CAAA;AACrC,IAAA,MAAM,cAA4B,EAAC;AACnC,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,MAAA,EAAQ,KAAK,KAAA,EAAO;AAChD,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,KAAA,CAAM,CAAA,EAAG,IAAI,KAAK,CAAA;AAC1C,MAAA,WAAA,CAAY,IAAA,CAAK,GAAI,MAAM,OAAA,CAAQ,IAAI,KAAA,CAAM,GAAA,CAAI,SAAS,CAAC,CAAE,CAAA;AAAA,IAC/D;AAEA,IAAA,MAAM,kBAA4B,EAAC;AACnC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,QAAQ,CAAA,EAAA,EAAK;AACzC,MAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,cAAc,cAAA,EAAe,GAAI,UAAU,CAAC,CAAA;AACnE,MAAA,MAAM,EAAE,UAAA,EAAY,UAAA,EAAY,UAAA,EAAW,GAAI,KAAA;AAC/C,MAAA,MAAM,UAAA,GAAa,YAAY,CAAC,CAAA;AAEhC,MAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACvB,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,IAAI;AACF,YAAA,MAAM,OAAA,CAAQ;AAAA,cACZ,KAAA,EAAO,UAAA;AAAA,cACP,YAAA;AAAA,cACA,UAAA;AAAA,cACA,IAAA,EAAM,cAAA;AAAA,cACN,OAAO,UAAA,CAAW;AAAA,aACnB,CAAA;AAAA,UACH,SAAS,WAAA,EAAa;AACpB,YAAA,OAAA,CAAQ,KAAA,CAAM,uDAAuD,WAAW,CAAA;AAAA,UAClF;AAAA,QACF,CAAA,MAAO;AACL,UAAA,OAAA,CAAQ,KAAA;AAAA,YACN,gDAAgD,UAAU,CAAA,CAAA,CAAA;AAAA,YAC1D,UAAA,CAAW;AAAA,WACb;AAAA,QACF;AACA,QAAA,IAAI,eAAA,EAAiB;AACnB,UAAA,KAAA,MAAW,kBAAkB,eAAA,EAAiB;AAC5C,YAAA,cAAA,CAAe,GAAA,EAAK,gBAAgB,MAAS,CAAA;AAC7C,YAAA,OAAA,CAAQ,OAAO,cAAc,CAAA;AAAA,UAC/B;AACA,UAAA;AAAA,QACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,SAAA,GAAY,MAAA,CAAO,MAAM,CAAA,GAAI,UAAA,CAAW,IAAA;AAC9C,MAAA,MAAM,aAAA,GAAgB,MAAM,SAAS,CAAA;AACrC,MAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,aAAa,CAAA,EAAG;AACnC,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,uFAAuF,UAAU,CAAA,yBAAA;AAAA,SACnG;AAAA,MACF;AACA,MAAA,MAAM,cAAA,GAAiB;AAAA,QACrB,MAAA,EAAQ,MAAA,CAAO,QAAA,CAAS,aAAa,IAAI,aAAA,GAAgB,SAAA;AAAA,QACzD,QAAA,EAAU,UAAA;AAAA,QACV,IAAA,EAAM;AAAA,OACR;AACA,MAAA,cAAA,CAAe,GAAA,EAAK,YAAY,cAAc,CAAA;AAC9C,MAAA,OAAA,CAAQ,GAAA,CAAI,YAAY,cAAc,CAAA;AACtC,MAAA,eAAA,CAAgB,KAAK,UAAU,CAAA;AAC/B,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,IAAI;AACF,UAAA,MAAM,SAAA,CAAU;AAAA,YACd,KAAA,EAAO,UAAA;AAAA,YACP,YAAA;AAAA,YACA,UAAA;AAAA,YACA,cAAA,EAAgB,MAAA;AAAA,YAChB,iBAAiB,cAAA,CAAe,MAAA;AAAA,YAChC,MAAM,UAAA,CAAW,IAAA;AAAA,YACjB,IAAA,EAAM,cAAA;AAAA,YACN,cAAc,UAAA,CAAW;AAAA,WAC1B,CAAA;AAAA,QACH,SAAS,WAAA,EAAa;AACpB,UAAA,OAAA,CAAQ,KAAA,CAAM,yDAAyD,WAAW,CAAA;AAAA,QACpF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,MAAA,CAAO,GAAA,CAAI,QAAQ,iBAAgC;AACjD,IAAA,IAAI,IAAA,CAAK,QAAQ,sBAAA,EAAwB;AACzC,IAAA,MAAM,WAAA,GAAc,MAAM,uBAAA,CAAwB,IAA0C,CAAA;AAC5F,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,KAAK,CAAA,IAAK,WAAA,EAAa;AACvC,MAAA,IAAA,CAAK,GAAA,CAAI,MAAM,KAAK,CAAA;AAAA,IACtB;AAAA,EACF,CAAC,CAAA;AAED,EAAA,eAAe,uBAEb,IAAA,EACA;AACA,IAAA,MAAM,YAAA,GAAe,KAAK,UAAA,EAAW;AACrC,IAAA,IAAI,YAAA,CAAa,sBAAA,EAAwB,OAAO,IAAA,EAAK;AAErD,IAAA,MAAM,MAAA,GAAS,KAAK,SAAA,EAAU;AAC9B,IAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,IAAA,EAAK;AAEzB,IAAA,MAAM,SAAA,GAAY,MAAA;AAClB,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,IAAI,OAAO,SAAA,CAAU,IAAA,KAAS,QAAA,IAAY,SAAA,CAAU,SAAS,IAAA,EAAM;AACjE,QAAA,GAAA,GAAM,EAAE,GAAG,SAAA,CAAU,IAAA,EAAK;AAC1B,QAAA,MAAM,wBAAwB,GAAG,CAAA;AACjC,QAAA,SAAA,CAAU,IAAA,GAAO,GAAA;AAAA,MACnB,CAAA,MAAO;AACL,QAAA,GAAA,GAAM,EAAE,GAAG,SAAA,EAAU;AACrB,QAAA,MAAM,wBAAwB,GAAG,CAAA;AACjC,QAAA,MAAA,CAAO,MAAA,CAAO,WAAW,GAAG,CAAA;AAAA,MAC9B;AAEA,MAAA,IAAI,OAAO,SAAA,CAAU,YAAA,KAAiB,QAAA,IAAY,SAAA,CAAU,iBAAiB,IAAA,EAAM;AACjF,QAAA,MAAM,SAAA,GAAY,EAAE,GAAG,SAAA,CAAU,YAAA,EAAa;AAC9C,QAAA,MAAM,wBAAwB,SAAS,CAAA;AACvC,QAAA,SAAA,CAAU,YAAA,GAAe,SAAA;AAAA,MAC3B;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,OAAO,IAAA,CAAK,eAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAAA,IACjE;AACA,IAAA,IAAA,EAAK;AAAA,EACP;AAEA,EAAA,MAAA,CAAO,GAAA,CAAI,oBAAoB,sBAAsB,CAAA;AACrD,EAAA,MAAA,CAAO,GAAA,CAAI,aAAa,sBAAsB,CAAA;AAC9C,EAAA,MAAA,CAAO,GAAA,CAAI,cAAc,sBAAsB,CAAA;AACjD","file":"index.mjs","sourcesContent":["// Complete ISO 4217 active currency codes\nconst ISO_4217_CODES = [\n // A\n \"AED\",\n \"AFN\",\n \"ALL\",\n \"AMD\",\n \"ANG\",\n \"AOA\",\n \"ARS\",\n \"AUD\",\n \"AWG\",\n \"AZN\",\n // B\n \"BAM\",\n \"BBD\",\n \"BDT\",\n \"BGN\",\n \"BHD\",\n \"BIF\",\n \"BMD\",\n \"BND\",\n \"BOB\",\n \"BOV\",\n \"BRL\",\n \"BSD\",\n \"BTN\",\n \"BWP\",\n \"BYN\",\n \"BZD\",\n // C\n \"CAD\",\n \"CDF\",\n \"CHE\",\n \"CHF\",\n \"CHW\",\n \"CLF\",\n \"CLP\",\n \"CNY\",\n \"COP\",\n \"COU\",\n \"CRC\",\n \"CUP\",\n \"CVE\",\n \"CZK\",\n // D\n \"DJF\",\n \"DKK\",\n \"DOP\",\n \"DZD\",\n // E\n \"EGP\",\n \"ERN\",\n \"ETB\",\n \"EUR\",\n // F\n \"FJD\",\n \"FKP\",\n // G\n \"GBP\",\n \"GEL\",\n \"GHS\",\n \"GIP\",\n \"GMD\",\n \"GNF\",\n \"GTQ\",\n \"GYD\",\n // H\n \"HKD\",\n \"HNL\",\n \"HTG\",\n \"HUF\",\n // I\n \"IDR\",\n \"ILS\",\n \"INR\",\n \"IQD\",\n \"IRR\",\n \"ISK\",\n // J\n \"JMD\",\n \"JOD\",\n \"JPY\",\n // K\n \"KES\",\n \"KGS\",\n \"KHR\",\n \"KMF\",\n \"KPW\",\n \"KRW\",\n \"KWD\",\n \"KYD\",\n \"KZT\",\n // L\n \"LAK\",\n \"LBP\",\n \"LRD\",\n \"LSL\",\n \"LYD\",\n // M\n \"MAD\",\n \"MDL\",\n \"MGA\",\n \"MKD\",\n \"MMK\",\n \"MNT\",\n \"MOP\",\n \"MRU\",\n \"MUR\",\n \"MVR\",\n \"MWK\",\n \"MXN\",\n \"MXV\",\n \"MYR\",\n \"MZN\",\n // N\n \"NAD\",\n \"NGN\",\n \"NIO\",\n \"NOK\",\n \"NPR\",\n \"NZD\",\n // O\n \"OMR\",\n // P\n \"PAB\",\n \"PEN\",\n \"PGK\",\n \"PHP\",\n \"PKR\",\n \"PLN\",\n \"PYG\",\n // Q\n \"QAR\",\n // R\n \"RON\",\n \"RSD\",\n \"RUB\",\n \"RWF\",\n // S\n \"SAR\",\n \"SBD\",\n \"SCR\",\n \"SDG\",\n \"SEK\",\n \"SGD\",\n \"SHP\",\n \"SLE\",\n \"SOS\",\n \"SRD\",\n \"SSP\",\n \"STN\",\n \"SVC\",\n \"SYP\",\n \"SZL\",\n // T\n \"THB\",\n \"TJS\",\n \"TMT\",\n \"TND\",\n \"TOP\",\n \"TRY\",\n \"TTD\",\n \"TWD\",\n \"TZS\",\n // U\n \"UAH\",\n \"UGX\",\n \"USD\",\n \"USN\",\n \"UYI\",\n \"UYU\",\n \"UZS\",\n // V\n \"VES\",\n \"VND\",\n \"VUV\",\n // W\n \"WST\",\n // X (special / supra-national)\n \"XAF\",\n \"XAG\",\n \"XAU\",\n \"XBA\",\n \"XBB\",\n \"XBC\",\n \"XBD\",\n \"XCD\",\n \"XDR\",\n \"XOF\",\n \"XPD\",\n \"XPF\",\n \"XPT\",\n \"XSU\",\n \"XTS\",\n \"XUA\",\n \"XXX\",\n // Y\n \"YER\",\n // Z\n \"ZAR\",\n \"ZMW\",\n \"ZWL\",\n];\nconst PATH_CACHE_MAX_SIZE = 500;\nconst pathCache = new Map<string, string[]>();\n\nexport function getPathArray(path: string): string[] {\n const cached = pathCache.get(path);\n if (cached) {\n // Refresh insertion order so least-recently-used entries are evicted first\n pathCache.delete(path);\n pathCache.set(path, cached);\n return cached;\n }\n\n const arr = path.split(\".\");\n if (pathCache.size >= PATH_CACHE_MAX_SIZE) {\n pathCache.delete(pathCache.keys().next().value as string);\n }\n pathCache.set(path, arr);\n return arr;\n}\n\nexport function getNestedValue(obj: unknown, path: string | string[]): unknown {\n const keys = Array.isArray(path) ? path : getPathArray(path);\n return keys.reduce((acc, key) => {\n if (acc && typeof acc === \"object\") {\n if (!Number.isNaN(Number(key)) && Array.isArray(acc)) {\n return acc[Number(key)];\n }\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\nexport function setNestedValue(obj: unknown, path: string | string[], value: unknown): void {\n const parts = Array.isArray(path) ? [...path] : [...getPathArray(path)];\n const last = parts.pop();\n if (!last) return;\n\n let target = obj as Record<string, unknown>;\n for (const key of parts) {\n if (!Number.isNaN(Number(key)) && Array.isArray(target)) {\n if (!target[Number(key)]) target[Number(key)] = {};\n target = target[Number(key)] as Record<string, unknown>;\n } else {\n if (typeof target[key] !== \"object\" || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n }\n if (!Number.isNaN(Number(last)) && Array.isArray(target)) {\n target[Number(last)] = value;\n } else {\n target[last] = value;\n }\n}\n\nexport function defaultRound(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nexport function isValidCurrencyCode(code: string, allowedCodes?: string[]): boolean {\n const list = allowedCodes || ISO_4217_CODES;\n if (typeof code !== \"string\") return false;\n const normalized = code.toUpperCase();\n return list.some((c) => c.toUpperCase() === normalized);\n}\n","import type { Schema, Document } from \"mongoose\";\n\nimport type { CurrencyPluginOptions } from \"./types\";\nimport { defaultRound, getNestedValue, isValidCurrencyCode, setNestedValue } from \"./utils/helpers\";\n\n/**\n * Mongoose plugin that automatically converts currency fields on save and update operations.\n *\n * ## Error handling policy\n *\n * The plugin uses a three-tier strategy depending on when and where an error occurs:\n *\n * 1. **Initialization errors** (`throw`): Missing or invalid required options (`fields`, `getRate`)\n * cause an immediate `Error` to be thrown when the plugin is registered. These are\n * programmer errors and must be fixed before the application starts.\n *\n * 2. **Field validation warnings** (`console.warn` + skip): Invalid field configurations\n * detected at conversion time (missing `targetPath`, invalid currency code, non-numeric\n * `amount`, invalid date) are logged as warnings and the field is silently skipped.\n * The document is still saved with the remaining conversions applied.\n *\n * 3. **Rate fetch errors** (`onError` callback or `console.error`): Errors thrown by `getRate`\n * or invalid rates returned by it are passed to the `onError` callback if provided,\n * otherwise logged via `console.error`. If `fallbackRate` is set it is used instead.\n * If `rollbackOnError` is `true`, all previously converted fields in that document are\n * reverted before the save continues.\n */\nexport function currencyConversionPlugin(schema: Schema, options: CurrencyPluginOptions) {\n const {\n fields,\n getRate,\n round = defaultRound,\n allowedCurrencyCodes,\n onError,\n onSuccess,\n fallbackRate,\n rollbackOnError,\n cache,\n dateTransform,\n concurrency = 5,\n rateValidation,\n } = options;\n\n if (!fields || !Array.isArray(fields) || fields.length === 0) {\n throw new Error('[mongoose-currency-convert] option \"fields\" must be a non-empty array');\n }\n\n if (typeof getRate !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"getRate\" must be a function');\n }\n\n if (options.round !== undefined && typeof options.round !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"round\" must be a function');\n }\n\n if (options.onError !== undefined && typeof options.onError !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"onError\" must be a function');\n }\n\n if (options.onSuccess !== undefined && typeof options.onSuccess !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"onSuccess\" must be a function');\n }\n\n if (options.dateTransform !== undefined && typeof options.dateTransform !== \"function\") {\n throw new Error('[mongoose-currency-convert] option \"dateTransform\" must be a function');\n }\n\n const targetPaths = new Set<string>();\n for (const field of fields) {\n if (!isValidCurrencyCode(field.toCurrency, allowedCurrencyCodes)) {\n throw new Error(\n `[mongoose-currency-convert] invalid toCurrency \"${field.toCurrency}\" in field config`,\n );\n }\n if (targetPaths.has(field.targetPath)) {\n throw new Error(\n `[mongoose-currency-convert] duplicate targetPath \"${field.targetPath}\" in field config`,\n );\n }\n targetPaths.add(field.targetPath);\n }\n\n if (\n options.fallbackRate !== undefined &&\n (typeof options.fallbackRate !== \"number\" || options.fallbackRate < 0)\n ) {\n throw new Error(\n '[mongoose-currency-convert] option \"fallbackRate\" must be a non-negative number',\n );\n }\n\n if (\n options.concurrency !== undefined &&\n (typeof options.concurrency !== \"number\" || options.concurrency < 1)\n ) {\n throw new Error('[mongoose-currency-convert] option \"concurrency\" must be a number >= 1');\n }\n\n if (rateValidation !== undefined) {\n if (typeof rateValidation !== \"object\" || rateValidation === null) {\n throw new Error('[mongoose-currency-convert] option \"rateValidation\" must be an object');\n }\n if (rateValidation.min !== undefined && typeof rateValidation.min !== \"number\") {\n throw new Error('[mongoose-currency-convert] option \"rateValidation.min\" must be a number');\n }\n if (rateValidation.max !== undefined && typeof rateValidation.max !== \"number\") {\n throw new Error('[mongoose-currency-convert] option \"rateValidation.max\" must be a number');\n }\n if (\n rateValidation.min !== undefined &&\n rateValidation.max !== undefined &&\n rateValidation.min > rateValidation.max\n ) {\n throw new Error(\n '[mongoose-currency-convert] option \"rateValidation.min\" must be <= \"rateValidation.max\"',\n );\n }\n }\n\n async function applyCurrencyConversion(\n doc: Record<string, unknown>,\n ): Promise<Map<string, unknown>> {\n const results = new Map<string, unknown>();\n\n type WorkItem = {\n field: (typeof fields)[number];\n amount: number;\n fromCurrency: string;\n conversionDate: Date;\n cacheKey: string;\n };\n const workItems: WorkItem[] = [];\n\n for (const field of fields) {\n const { sourcePath, currencyPath, datePath, targetPath, toCurrency } = field;\n\n if (!targetPath) {\n console.warn(\n `[mongoose-currency-convert] WARNING: 'targetPath' is required in field config`,\n );\n continue;\n }\n\n if (!schema.path(`${targetPath}.amount`)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: targetPath '${targetPath}' does not exist in schema`,\n );\n continue;\n }\n\n const amount = getNestedValue(doc, sourcePath);\n if (amount == null) continue;\n if (typeof amount !== \"number\" || Number.isNaN(amount)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: non-numeric amount at path '${sourcePath}': (${typeof amount})`,\n );\n continue;\n }\n\n const fromCurrency = getNestedValue(doc, currencyPath);\n if (typeof fromCurrency !== \"string\" || !fromCurrency) {\n console.warn(\n `[mongoose-currency-convert] Missing or invalid source currency at path: ${currencyPath}`,\n );\n continue;\n }\n\n if (!isValidCurrencyCode(fromCurrency, allowedCurrencyCodes)) {\n console.warn(`[mongoose-currency-convert] Invalid source currency code: ${fromCurrency}`);\n continue;\n }\n\n if (fromCurrency.toUpperCase() === toCurrency.toUpperCase()) continue;\n\n const dateValue = datePath ? getNestedValue(doc, datePath) : undefined;\n let conversionDate =\n dateValue &&\n (typeof dateValue === \"string\" ||\n typeof dateValue === \"number\" ||\n dateValue instanceof Date)\n ? new Date(dateValue)\n : new Date();\n if (Number.isNaN(conversionDate.getTime())) {\n console.warn(\n `[mongoose-currency-convert] Invalid date value at path '${datePath}', using current date`,\n );\n conversionDate = new Date();\n }\n\n if (dateTransform) {\n try {\n const transformed = dateTransform(conversionDate);\n if (transformed instanceof Date && !Number.isNaN(transformed.getTime())) {\n conversionDate = transformed;\n } else {\n console.warn(\n `[mongoose-currency-convert] dateTransform returned an invalid Date for field '${sourcePath}', using original date`,\n );\n }\n } catch (transformErr) {\n console.warn(\n `[mongoose-currency-convert] dateTransform threw for field '${sourcePath}', using original date:`,\n transformErr,\n );\n }\n }\n\n const cacheKey = `${fromCurrency.toUpperCase()}_${toCurrency.toUpperCase()}_${conversionDate.toISOString().slice(0, 10)}`;\n workItems.push({ field, amount, fromCurrency, conversionDate, cacheKey });\n }\n\n type RateResult =\n | { success: true; rate: number; usedFallback: boolean }\n | { success: false; error: unknown };\n\n async function fetchRate({\n field,\n fromCurrency,\n conversionDate,\n cacheKey,\n }: WorkItem): Promise<RateResult> {\n try {\n let rate: number | undefined;\n let usedFallback = false;\n if (cache) {\n try {\n rate = await cache.get(cacheKey);\n } catch (cacheErr) {\n console.warn(\"[mongoose-currency-convert] cache.get() failed:\", cacheErr);\n }\n }\n\n if (rate === undefined) {\n rate = await getRate(fromCurrency, field.toCurrency, conversionDate);\n if (cache && rate !== undefined && Number.isFinite(rate)) {\n try {\n await cache.set(cacheKey, rate);\n } catch (cacheErr) {\n console.warn(\"[mongoose-currency-convert] cache.set() failed:\", cacheErr);\n }\n }\n }\n\n if (rate == null || !Number.isFinite(rate) || rate < 0) {\n if (typeof fallbackRate === \"number\") {\n rate = fallbackRate;\n usedFallback = true;\n } else {\n throw new Error(\"Invalid rate\");\n }\n }\n\n if (rateValidation) {\n const { min = 0, max } = rateValidation;\n if (rate < min || (max !== undefined && rate > max)) {\n throw new Error(\n `Rate ${rate} is out of bounds [${min}, ${max ?? \"∞\"}] for ${fromCurrency}→${field.toCurrency}`,\n );\n }\n }\n\n return { success: true, rate, usedFallback };\n } catch (error) {\n if (typeof fallbackRate === \"number\") {\n if (rateValidation) {\n const { min = 0, max } = rateValidation;\n if (fallbackRate < min || (max !== undefined && fallbackRate > max)) {\n return {\n success: false,\n error: new Error(\n `Fallback rate ${fallbackRate} is also out of bounds [${min}, ${max ?? \"∞\"}] for ${fromCurrency}→${field.toCurrency}`,\n ),\n };\n }\n }\n return { success: true, rate: fallbackRate, usedFallback: true };\n }\n return { success: false, error };\n }\n }\n\n const limit = Math.max(1, concurrency);\n const rateResults: RateResult[] = [];\n for (let i = 0; i < workItems.length; i += limit) {\n const batch = workItems.slice(i, i + limit);\n rateResults.push(...(await Promise.all(batch.map(fetchRate))));\n }\n\n const convertedFields: string[] = [];\n for (let i = 0; i < workItems.length; i++) {\n const { field, amount, fromCurrency, conversionDate } = workItems[i];\n const { sourcePath, targetPath, toCurrency } = field;\n const rateResult = rateResults[i];\n\n if (!rateResult.success) {\n if (onError) {\n try {\n await onError({\n field: sourcePath,\n fromCurrency,\n toCurrency,\n date: conversionDate,\n error: rateResult.error,\n });\n } catch (callbackErr) {\n console.error(\"[mongoose-currency-convert] onError callback threw:\", callbackErr);\n }\n } else {\n console.error(\n `[mongoose-currency-convert] Error converting ${sourcePath}:`,\n rateResult.error,\n );\n }\n if (rollbackOnError) {\n for (const convertedField of convertedFields) {\n setNestedValue(doc, convertedField, undefined);\n results.delete(convertedField);\n }\n break;\n }\n continue;\n }\n\n const rawAmount = Number(amount) * rateResult.rate;\n const roundedAmount = round(rawAmount);\n if (!Number.isFinite(roundedAmount)) {\n console.warn(\n `[mongoose-currency-convert] WARNING: round() returned a non-finite value for field '${sourcePath}', using unrounded amount`,\n );\n }\n const convertedValue = {\n amount: Number.isFinite(roundedAmount) ? roundedAmount : rawAmount,\n currency: toCurrency,\n date: conversionDate,\n };\n setNestedValue(doc, targetPath, convertedValue);\n results.set(targetPath, convertedValue);\n convertedFields.push(targetPath);\n if (onSuccess) {\n try {\n await onSuccess({\n field: sourcePath,\n fromCurrency,\n toCurrency,\n originalAmount: amount,\n convertedAmount: convertedValue.amount,\n rate: rateResult.rate,\n date: conversionDate,\n usedFallback: rateResult.usedFallback,\n });\n } catch (callbackErr) {\n console.error(\"[mongoose-currency-convert] onSuccess callback threw:\", callbackErr);\n }\n }\n }\n\n return results;\n }\n\n schema.pre(\"save\", async function (this: Document) {\n if (this.$locals.skipCurrencyConversion) return;\n const conversions = await applyCurrencyConversion(this as unknown as Record<string, unknown>);\n for (const [path, value] of conversions) {\n this.set(path, value);\n }\n });\n\n async function handleUpdateMiddleware(\n this: import(\"mongoose\").Query<unknown, unknown>,\n next: (err?: Error) => void,\n ) {\n const queryOptions = this.getOptions() as Record<string, unknown>;\n if (queryOptions.skipCurrencyConversion) return next();\n\n const update = this.getUpdate();\n if (!update) return next();\n\n const updateAny = update as Record<string, unknown>;\n let doc: Record<string, unknown>;\n try {\n if (typeof updateAny.$set === \"object\" && updateAny.$set !== null) {\n doc = { ...updateAny.$set };\n await applyCurrencyConversion(doc);\n updateAny.$set = doc;\n } else {\n doc = { ...updateAny };\n await applyCurrencyConversion(doc);\n Object.assign(updateAny, doc);\n }\n\n if (typeof updateAny.$setOnInsert === \"object\" && updateAny.$setOnInsert !== null) {\n const insertDoc = { ...updateAny.$setOnInsert } as Record<string, unknown>;\n await applyCurrencyConversion(insertDoc);\n updateAny.$setOnInsert = insertDoc;\n }\n } catch (err) {\n return next(err instanceof Error ? err : new Error(String(err)));\n }\n next();\n }\n\n schema.pre(\"findOneAndUpdate\", handleUpdateMiddleware);\n schema.pre(\"updateOne\", handleUpdateMiddleware);\n schema.pre(\"updateMany\", handleUpdateMiddleware);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/cache.ts"],"names":[],"mappings":";;;AAEO,IAAM,cAAN,MAA+B;AAAA,EAC5B,KAAA,uBAAY,GAAA,EAA2B;AAAA,EACvC,GAAA;AAAA,EACA,UAAA;AAAA,EAER,WAAA,CAAY,aAAqB,EAAA,EAAI;AACnC,IAAA,IAAI,cAAc,CAAA,EAAG;AACnB,MAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,IACnF;AACA,IAAA,IAAA,CAAK,GAAA,GAAM,aAAa,EAAA,GAAK,GAAA;AAC7B,IAAA,IAAA,CAAK,aAAa,WAAA,CAAY,MAAM,KAAK,KAAA,EAAM,EAAG,KAAK,GAAG,CAAA;AAC1D,IAAA,IAAA,CAAK,WAAW,KAAA,EAAM;AAAA,EACxB;AAAA,EAEQ,UAAU,KAAA,EAA+B;AAC/C,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA,CAAM,SAAA;AAAA,EAC5B;AAAA,EAEQ,KAAA,GAAc;AACpB,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,KAAK,KAAA,EAAO;AACrC,MAAA,IAAI,KAAK,SAAA,CAAU,KAAK,GAAG,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,IAAI,GAAA,EAA4B;AAC9B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AACrB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,OAAO,KAAA,CAAM,KAAA;AAAA,EACf;AAAA,EAEA,GAAA,CAAI,KAAa,KAAA,EAAgB;AAC/B,IAAA,IAAA,CAAK,KAAA,CAAM,IAAI,GAAA,EAAK;AAAA,MAClB,KAAA;AAAA,MACA,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK;AAAA,KAC9B,CAAA;AAAA,EACH;AAAA,EAEA,OAAO,GAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,EACvB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA,EAEA,OAAA,GAAgB;AACd,IAAA,aAAA,CAAc,KAAK,UAAU,CAAA;AAC7B,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AACF","file":"cache.js","sourcesContent":["import type { CacheEntry } from \"../types.js\";\n\nexport class SimpleCache<T = unknown> {\n private store = new Map<string, CacheEntry<T>>();\n private ttl: number;\n private sweepTimer: ReturnType<typeof setInterval>;\n\n constructor(ttlMinutes: number = 60) {\n if (ttlMinutes <= 0) {\n throw new Error(\"[mongoose-currency-convert] SimpleCache: ttlMinutes must be > 0\");\n }\n this.ttl = ttlMinutes * 60 * 1000;\n this.sweepTimer = setInterval(() => this.sweep(), this.ttl);\n this.sweepTimer.unref();\n }\n\n private isExpired(entry: CacheEntry<T>): boolean {\n return Date.now() > entry.expiresAt;\n }\n\n private sweep(): void {\n for (const [key, entry] of this.store) {\n if (this.isExpired(entry)) this.store.delete(key);\n }\n }\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n\n if (this.isExpired(entry)) {\n this.store.delete(key);\n return undefined;\n }\n\n return entry.value;\n }\n\n set(key: string, value: T): void {\n this.store.set(key, {\n value,\n expiresAt: Date.now() + this.ttl,\n });\n }\n\n delete(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n destroy(): void {\n clearInterval(this.sweepTimer);\n this.store.clear();\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/cache.ts"],"names":[],"mappings":";;;AAEO,IAAM,cAAN,MAA+B;AAAA,EAC5B,KAAA,uBAAY,GAAA,EAA2B;AAAA,EACvC,GAAA;AAAA,EACA,UAAA;AAAA,EAER,WAAA,CAAY,aAAqB,EAAA,EAAI;AACnC,IAAA,IAAI,cAAc,CAAA,EAAG;AACnB,MAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,IACnF;AACA,IAAA,IAAA,CAAK,GAAA,GAAM,aAAa,EAAA,GAAK,GAAA;AAC7B,IAAA,IAAA,CAAK,aAAa,WAAA,CAAY,MAAM,KAAK,KAAA,EAAM,EAAG,KAAK,GAAG,CAAA;AAC1D,IAAA,IAAA,CAAK,WAAW,KAAA,EAAM;AAAA,EACxB;AAAA,EAEQ,UAAU,KAAA,EAA+B;AAC/C,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA,CAAM,SAAA;AAAA,EAC5B;AAAA,EAEQ,KAAA,GAAc;AACpB,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,KAAK,KAAA,EAAO;AACrC,MAAA,IAAI,KAAK,SAAA,CAAU,KAAK,GAAG,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,IAAI,GAAA,EAA4B;AAC9B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AACrB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,OAAO,KAAA,CAAM,KAAA;AAAA,EACf;AAAA,EAEA,GAAA,CAAI,KAAa,KAAA,EAAgB;AAC/B,IAAA,IAAA,CAAK,KAAA,CAAM,IAAI,GAAA,EAAK;AAAA,MAClB,KAAA;AAAA,MACA,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK;AAAA,KAC9B,CAAA;AAAA,EACH;AAAA,EAEA,OAAO,GAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,EACvB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA,EAEA,OAAA,GAAgB;AACd,IAAA,aAAA,CAAc,KAAK,UAAU,CAAA;AAC7B,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AACF","file":"cache.js","sourcesContent":["import type { CacheEntry } from \"../types.js\";\n\nexport class SimpleCache<T = unknown> {\n private store = new Map<string, CacheEntry<T>>();\n private ttl: number;\n private sweepTimer: NodeJS.Timeout;\n\n constructor(ttlMinutes: number = 60) {\n if (ttlMinutes <= 0) {\n throw new Error(\"[mongoose-currency-convert] SimpleCache: ttlMinutes must be > 0\");\n }\n this.ttl = ttlMinutes * 60 * 1000;\n this.sweepTimer = setInterval(() => this.sweep(), this.ttl);\n this.sweepTimer.unref();\n }\n\n private isExpired(entry: CacheEntry<T>): boolean {\n return Date.now() > entry.expiresAt;\n }\n\n private sweep(): void {\n for (const [key, entry] of this.store) {\n if (this.isExpired(entry)) this.store.delete(key);\n }\n }\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n\n if (this.isExpired(entry)) {\n this.store.delete(key);\n return undefined;\n }\n\n return entry.value;\n }\n\n set(key: string, value: T): void {\n this.store.set(key, {\n value,\n expiresAt: Date.now() + this.ttl,\n });\n }\n\n delete(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n destroy(): void {\n clearInterval(this.sweepTimer);\n this.store.clear();\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/cache.ts"],"names":[],"mappings":";AAEO,IAAM,cAAN,MAA+B;AAAA,EAC5B,KAAA,uBAAY,GAAA,EAA2B;AAAA,EACvC,GAAA;AAAA,EACA,UAAA;AAAA,EAER,WAAA,CAAY,aAAqB,EAAA,EAAI;AACnC,IAAA,IAAI,cAAc,CAAA,EAAG;AACnB,MAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,IACnF;AACA,IAAA,IAAA,CAAK,GAAA,GAAM,aAAa,EAAA,GAAK,GAAA;AAC7B,IAAA,IAAA,CAAK,aAAa,WAAA,CAAY,MAAM,KAAK,KAAA,EAAM,EAAG,KAAK,GAAG,CAAA;AAC1D,IAAA,IAAA,CAAK,WAAW,KAAA,EAAM;AAAA,EACxB;AAAA,EAEQ,UAAU,KAAA,EAA+B;AAC/C,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA,CAAM,SAAA;AAAA,EAC5B;AAAA,EAEQ,KAAA,GAAc;AACpB,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,KAAK,KAAA,EAAO;AACrC,MAAA,IAAI,KAAK,SAAA,CAAU,KAAK,GAAG,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,IAAI,GAAA,EAA4B;AAC9B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AACrB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,OAAO,KAAA,CAAM,KAAA;AAAA,EACf;AAAA,EAEA,GAAA,CAAI,KAAa,KAAA,EAAgB;AAC/B,IAAA,IAAA,CAAK,KAAA,CAAM,IAAI,GAAA,EAAK;AAAA,MAClB,KAAA;AAAA,MACA,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK;AAAA,KAC9B,CAAA;AAAA,EACH;AAAA,EAEA,OAAO,GAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,EACvB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA,EAEA,OAAA,GAAgB;AACd,IAAA,aAAA,CAAc,KAAK,UAAU,CAAA;AAC7B,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AACF","file":"cache.mjs","sourcesContent":["import type { CacheEntry } from \"../types.js\";\n\nexport class SimpleCache<T = unknown> {\n private store = new Map<string, CacheEntry<T>>();\n private ttl: number;\n private sweepTimer: ReturnType<typeof setInterval>;\n\n constructor(ttlMinutes: number = 60) {\n if (ttlMinutes <= 0) {\n throw new Error(\"[mongoose-currency-convert] SimpleCache: ttlMinutes must be > 0\");\n }\n this.ttl = ttlMinutes * 60 * 1000;\n this.sweepTimer = setInterval(() => this.sweep(), this.ttl);\n this.sweepTimer.unref();\n }\n\n private isExpired(entry: CacheEntry<T>): boolean {\n return Date.now() > entry.expiresAt;\n }\n\n private sweep(): void {\n for (const [key, entry] of this.store) {\n if (this.isExpired(entry)) this.store.delete(key);\n }\n }\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n\n if (this.isExpired(entry)) {\n this.store.delete(key);\n return undefined;\n }\n\n return entry.value;\n }\n\n set(key: string, value: T): void {\n this.store.set(key, {\n value,\n expiresAt: Date.now() + this.ttl,\n });\n }\n\n delete(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n destroy(): void {\n clearInterval(this.sweepTimer);\n this.store.clear();\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/cache.ts"],"names":[],"mappings":";AAEO,IAAM,cAAN,MAA+B;AAAA,EAC5B,KAAA,uBAAY,GAAA,EAA2B;AAAA,EACvC,GAAA;AAAA,EACA,UAAA;AAAA,EAER,WAAA,CAAY,aAAqB,EAAA,EAAI;AACnC,IAAA,IAAI,cAAc,CAAA,EAAG;AACnB,MAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,IACnF;AACA,IAAA,IAAA,CAAK,GAAA,GAAM,aAAa,EAAA,GAAK,GAAA;AAC7B,IAAA,IAAA,CAAK,aAAa,WAAA,CAAY,MAAM,KAAK,KAAA,EAAM,EAAG,KAAK,GAAG,CAAA;AAC1D,IAAA,IAAA,CAAK,WAAW,KAAA,EAAM;AAAA,EACxB;AAAA,EAEQ,UAAU,KAAA,EAA+B;AAC/C,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA,CAAM,SAAA;AAAA,EAC5B;AAAA,EAEQ,KAAA,GAAc;AACpB,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,KAAK,KAAA,EAAO;AACrC,MAAA,IAAI,KAAK,SAAA,CAAU,KAAK,GAAG,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,IAAI,GAAA,EAA4B;AAC9B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AACrB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,OAAO,KAAA,CAAM,KAAA;AAAA,EACf;AAAA,EAEA,GAAA,CAAI,KAAa,KAAA,EAAgB;AAC/B,IAAA,IAAA,CAAK,KAAA,CAAM,IAAI,GAAA,EAAK;AAAA,MAClB,KAAA;AAAA,MACA,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK;AAAA,KAC9B,CAAA;AAAA,EACH;AAAA,EAEA,OAAO,GAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,EACvB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA,EAEA,OAAA,GAAgB;AACd,IAAA,aAAA,CAAc,KAAK,UAAU,CAAA;AAC7B,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AACF","file":"cache.mjs","sourcesContent":["import type { CacheEntry } from \"../types.js\";\n\nexport class SimpleCache<T = unknown> {\n private store = new Map<string, CacheEntry<T>>();\n private ttl: number;\n private sweepTimer: NodeJS.Timeout;\n\n constructor(ttlMinutes: number = 60) {\n if (ttlMinutes <= 0) {\n throw new Error(\"[mongoose-currency-convert] SimpleCache: ttlMinutes must be > 0\");\n }\n this.ttl = ttlMinutes * 60 * 1000;\n this.sweepTimer = setInterval(() => this.sweep(), this.ttl);\n this.sweepTimer.unref();\n }\n\n private isExpired(entry: CacheEntry<T>): boolean {\n return Date.now() > entry.expiresAt;\n }\n\n private sweep(): void {\n for (const [key, entry] of this.store) {\n if (this.isExpired(entry)) this.store.delete(key);\n }\n }\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n\n if (this.isExpired(entry)) {\n this.store.delete(key);\n return undefined;\n }\n\n return entry.value;\n }\n\n set(key: string, value: T): void {\n this.store.set(key, {\n value,\n expiresAt: Date.now() + this.ttl,\n });\n }\n\n delete(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n destroy(): void {\n clearInterval(this.sweepTimer);\n this.store.clear();\n }\n}\n"]}
package/dist/validate.js CHANGED
@@ -42,7 +42,6 @@ var ISO_4217_CODES = [
42
42
  "COP",
43
43
  "COU",
44
44
  "CRC",
45
- "CUC",
46
45
  "CUP",
47
46
  "CVE",
48
47
  "CZK",
@@ -71,7 +70,6 @@ var ISO_4217_CODES = [
71
70
  // H
72
71
  "HKD",
73
72
  "HNL",
74
- "HRK",
75
73
  "HTG",
76
74
  "HUF",
77
75
  // I
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/helpers.ts"],"names":[],"mappings":";;;AACA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAErB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA;AA8DO,SAAS,mBAAA,CAAoB,MAAc,YAAA,EAAkC;AAClF,EAAA,MAAM,OAAO,YAAA,IAAgB,cAAA;AAC7B,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,KAAA;AACrC,EAAA,MAAM,UAAA,GAAa,KAAK,WAAA,EAAY;AACpC,EAAA,OAAO,KAAK,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,WAAA,OAAkB,UAAU,CAAA;AACxD","file":"validate.js","sourcesContent":["// Complete ISO 4217 active currency codes\nconst ISO_4217_CODES = [\n // A\n \"AED\",\n \"AFN\",\n \"ALL\",\n \"AMD\",\n \"ANG\",\n \"AOA\",\n \"ARS\",\n \"AUD\",\n \"AWG\",\n \"AZN\",\n // B\n \"BAM\",\n \"BBD\",\n \"BDT\",\n \"BGN\",\n \"BHD\",\n \"BIF\",\n \"BMD\",\n \"BND\",\n \"BOB\",\n \"BOV\",\n \"BRL\",\n \"BSD\",\n \"BTN\",\n \"BWP\",\n \"BYN\",\n \"BZD\",\n // C\n \"CAD\",\n \"CDF\",\n \"CHE\",\n \"CHF\",\n \"CHW\",\n \"CLF\",\n \"CLP\",\n \"CNY\",\n \"COP\",\n \"COU\",\n \"CRC\",\n \"CUC\",\n \"CUP\",\n \"CVE\",\n \"CZK\",\n // D\n \"DJF\",\n \"DKK\",\n \"DOP\",\n \"DZD\",\n // E\n \"EGP\",\n \"ERN\",\n \"ETB\",\n \"EUR\",\n // F\n \"FJD\",\n \"FKP\",\n // G\n \"GBP\",\n \"GEL\",\n \"GHS\",\n \"GIP\",\n \"GMD\",\n \"GNF\",\n \"GTQ\",\n \"GYD\",\n // H\n \"HKD\",\n \"HNL\",\n \"HRK\",\n \"HTG\",\n \"HUF\",\n // I\n \"IDR\",\n \"ILS\",\n \"INR\",\n \"IQD\",\n \"IRR\",\n \"ISK\",\n // J\n \"JMD\",\n \"JOD\",\n \"JPY\",\n // K\n \"KES\",\n \"KGS\",\n \"KHR\",\n \"KMF\",\n \"KPW\",\n \"KRW\",\n \"KWD\",\n \"KYD\",\n \"KZT\",\n // L\n \"LAK\",\n \"LBP\",\n \"LRD\",\n \"LSL\",\n \"LYD\",\n // M\n \"MAD\",\n \"MDL\",\n \"MGA\",\n \"MKD\",\n \"MMK\",\n \"MNT\",\n \"MOP\",\n \"MRU\",\n \"MUR\",\n \"MVR\",\n \"MWK\",\n \"MXN\",\n \"MXV\",\n \"MYR\",\n \"MZN\",\n // N\n \"NAD\",\n \"NGN\",\n \"NIO\",\n \"NOK\",\n \"NPR\",\n \"NZD\",\n // O\n \"OMR\",\n // P\n \"PAB\",\n \"PEN\",\n \"PGK\",\n \"PHP\",\n \"PKR\",\n \"PLN\",\n \"PYG\",\n // Q\n \"QAR\",\n // R\n \"RON\",\n \"RSD\",\n \"RUB\",\n \"RWF\",\n // S\n \"SAR\",\n \"SBD\",\n \"SCR\",\n \"SDG\",\n \"SEK\",\n \"SGD\",\n \"SHP\",\n \"SLE\",\n \"SOS\",\n \"SRD\",\n \"SSP\",\n \"STN\",\n \"SVC\",\n \"SYP\",\n \"SZL\",\n // T\n \"THB\",\n \"TJS\",\n \"TMT\",\n \"TND\",\n \"TOP\",\n \"TRY\",\n \"TTD\",\n \"TWD\",\n \"TZS\",\n // U\n \"UAH\",\n \"UGX\",\n \"USD\",\n \"USN\",\n \"UYI\",\n \"UYU\",\n \"UZS\",\n // V\n \"VES\",\n \"VND\",\n \"VUV\",\n // W\n \"WST\",\n // X (special / supra-national)\n \"XAF\",\n \"XAG\",\n \"XAU\",\n \"XBA\",\n \"XBB\",\n \"XBC\",\n \"XBD\",\n \"XCD\",\n \"XDR\",\n \"XOF\",\n \"XPD\",\n \"XPF\",\n \"XPT\",\n \"XSU\",\n \"XTS\",\n \"XUA\",\n \"XXX\",\n // Y\n \"YER\",\n // Z\n \"ZAR\",\n \"ZMW\",\n \"ZWL\",\n];\nconst PATH_CACHE_MAX_SIZE = 500;\nconst pathCache = new Map<string, string[]>();\n\nexport function getPathArray(path: string): string[] {\n const cached = pathCache.get(path);\n if (cached) {\n // Refresh insertion order so least-recently-used entries are evicted first\n pathCache.delete(path);\n pathCache.set(path, cached);\n return cached;\n }\n\n const arr = path.split(\".\");\n if (pathCache.size >= PATH_CACHE_MAX_SIZE) {\n pathCache.delete(pathCache.keys().next().value as string);\n }\n pathCache.set(path, arr);\n return arr;\n}\n\nexport function getNestedValue(obj: unknown, path: string | string[]): unknown {\n const keys = Array.isArray(path) ? path : getPathArray(path);\n return keys.reduce((acc, key) => {\n if (acc && typeof acc === \"object\") {\n if (!Number.isNaN(Number(key)) && Array.isArray(acc)) {\n return acc[Number(key)];\n }\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\nexport function setNestedValue(obj: unknown, path: string | string[], value: unknown): void {\n const parts = Array.isArray(path) ? [...path] : [...getPathArray(path)];\n const last = parts.pop();\n if (!last) return;\n\n let target = obj as Record<string, unknown>;\n for (const key of parts) {\n if (!Number.isNaN(Number(key)) && Array.isArray(target)) {\n if (!target[Number(key)]) target[Number(key)] = {};\n target = target[Number(key)] as Record<string, unknown>;\n } else {\n if (typeof target[key] !== \"object\" || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n }\n if (!Number.isNaN(Number(last)) && Array.isArray(target)) {\n target[Number(last)] = value;\n } else {\n target[last] = value;\n }\n}\n\nexport function defaultRound(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nexport function isValidCurrencyCode(code: string, allowedCodes?: string[]): boolean {\n const list = allowedCodes || ISO_4217_CODES;\n if (typeof code !== \"string\") return false;\n const normalized = code.toUpperCase();\n return list.some((c) => c.toUpperCase() === normalized);\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/helpers.ts"],"names":[],"mappings":";;;AACA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAErB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA;AA8DO,SAAS,mBAAA,CAAoB,MAAc,YAAA,EAAkC;AAClF,EAAA,MAAM,OAAO,YAAA,IAAgB,cAAA;AAC7B,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,KAAA;AACrC,EAAA,MAAM,UAAA,GAAa,KAAK,WAAA,EAAY;AACpC,EAAA,OAAO,KAAK,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,WAAA,OAAkB,UAAU,CAAA;AACxD","file":"validate.js","sourcesContent":["// Complete ISO 4217 active currency codes\nconst ISO_4217_CODES = [\n // A\n \"AED\",\n \"AFN\",\n \"ALL\",\n \"AMD\",\n \"ANG\",\n \"AOA\",\n \"ARS\",\n \"AUD\",\n \"AWG\",\n \"AZN\",\n // B\n \"BAM\",\n \"BBD\",\n \"BDT\",\n \"BGN\",\n \"BHD\",\n \"BIF\",\n \"BMD\",\n \"BND\",\n \"BOB\",\n \"BOV\",\n \"BRL\",\n \"BSD\",\n \"BTN\",\n \"BWP\",\n \"BYN\",\n \"BZD\",\n // C\n \"CAD\",\n \"CDF\",\n \"CHE\",\n \"CHF\",\n \"CHW\",\n \"CLF\",\n \"CLP\",\n \"CNY\",\n \"COP\",\n \"COU\",\n \"CRC\",\n \"CUP\",\n \"CVE\",\n \"CZK\",\n // D\n \"DJF\",\n \"DKK\",\n \"DOP\",\n \"DZD\",\n // E\n \"EGP\",\n \"ERN\",\n \"ETB\",\n \"EUR\",\n // F\n \"FJD\",\n \"FKP\",\n // G\n \"GBP\",\n \"GEL\",\n \"GHS\",\n \"GIP\",\n \"GMD\",\n \"GNF\",\n \"GTQ\",\n \"GYD\",\n // H\n \"HKD\",\n \"HNL\",\n \"HTG\",\n \"HUF\",\n // I\n \"IDR\",\n \"ILS\",\n \"INR\",\n \"IQD\",\n \"IRR\",\n \"ISK\",\n // J\n \"JMD\",\n \"JOD\",\n \"JPY\",\n // K\n \"KES\",\n \"KGS\",\n \"KHR\",\n \"KMF\",\n \"KPW\",\n \"KRW\",\n \"KWD\",\n \"KYD\",\n \"KZT\",\n // L\n \"LAK\",\n \"LBP\",\n \"LRD\",\n \"LSL\",\n \"LYD\",\n // M\n \"MAD\",\n \"MDL\",\n \"MGA\",\n \"MKD\",\n \"MMK\",\n \"MNT\",\n \"MOP\",\n \"MRU\",\n \"MUR\",\n \"MVR\",\n \"MWK\",\n \"MXN\",\n \"MXV\",\n \"MYR\",\n \"MZN\",\n // N\n \"NAD\",\n \"NGN\",\n \"NIO\",\n \"NOK\",\n \"NPR\",\n \"NZD\",\n // O\n \"OMR\",\n // P\n \"PAB\",\n \"PEN\",\n \"PGK\",\n \"PHP\",\n \"PKR\",\n \"PLN\",\n \"PYG\",\n // Q\n \"QAR\",\n // R\n \"RON\",\n \"RSD\",\n \"RUB\",\n \"RWF\",\n // S\n \"SAR\",\n \"SBD\",\n \"SCR\",\n \"SDG\",\n \"SEK\",\n \"SGD\",\n \"SHP\",\n \"SLE\",\n \"SOS\",\n \"SRD\",\n \"SSP\",\n \"STN\",\n \"SVC\",\n \"SYP\",\n \"SZL\",\n // T\n \"THB\",\n \"TJS\",\n \"TMT\",\n \"TND\",\n \"TOP\",\n \"TRY\",\n \"TTD\",\n \"TWD\",\n \"TZS\",\n // U\n \"UAH\",\n \"UGX\",\n \"USD\",\n \"USN\",\n \"UYI\",\n \"UYU\",\n \"UZS\",\n // V\n \"VES\",\n \"VND\",\n \"VUV\",\n // W\n \"WST\",\n // X (special / supra-national)\n \"XAF\",\n \"XAG\",\n \"XAU\",\n \"XBA\",\n \"XBB\",\n \"XBC\",\n \"XBD\",\n \"XCD\",\n \"XDR\",\n \"XOF\",\n \"XPD\",\n \"XPF\",\n \"XPT\",\n \"XSU\",\n \"XTS\",\n \"XUA\",\n \"XXX\",\n // Y\n \"YER\",\n // Z\n \"ZAR\",\n \"ZMW\",\n \"ZWL\",\n];\nconst PATH_CACHE_MAX_SIZE = 500;\nconst pathCache = new Map<string, string[]>();\n\nexport function getPathArray(path: string): string[] {\n const cached = pathCache.get(path);\n if (cached) {\n // Refresh insertion order so least-recently-used entries are evicted first\n pathCache.delete(path);\n pathCache.set(path, cached);\n return cached;\n }\n\n const arr = path.split(\".\");\n if (pathCache.size >= PATH_CACHE_MAX_SIZE) {\n pathCache.delete(pathCache.keys().next().value as string);\n }\n pathCache.set(path, arr);\n return arr;\n}\n\nexport function getNestedValue(obj: unknown, path: string | string[]): unknown {\n const keys = Array.isArray(path) ? path : getPathArray(path);\n return keys.reduce((acc, key) => {\n if (acc && typeof acc === \"object\") {\n if (!Number.isNaN(Number(key)) && Array.isArray(acc)) {\n return acc[Number(key)];\n }\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\nexport function setNestedValue(obj: unknown, path: string | string[], value: unknown): void {\n const parts = Array.isArray(path) ? [...path] : [...getPathArray(path)];\n const last = parts.pop();\n if (!last) return;\n\n let target = obj as Record<string, unknown>;\n for (const key of parts) {\n if (!Number.isNaN(Number(key)) && Array.isArray(target)) {\n if (!target[Number(key)]) target[Number(key)] = {};\n target = target[Number(key)] as Record<string, unknown>;\n } else {\n if (typeof target[key] !== \"object\" || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n }\n if (!Number.isNaN(Number(last)) && Array.isArray(target)) {\n target[Number(last)] = value;\n } else {\n target[last] = value;\n }\n}\n\nexport function defaultRound(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nexport function isValidCurrencyCode(code: string, allowedCodes?: string[]): boolean {\n const list = allowedCodes || ISO_4217_CODES;\n if (typeof code !== \"string\") return false;\n const normalized = code.toUpperCase();\n return list.some((c) => c.toUpperCase() === normalized);\n}\n"]}
package/dist/validate.mjs CHANGED
@@ -40,7 +40,6 @@ var ISO_4217_CODES = [
40
40
  "COP",
41
41
  "COU",
42
42
  "CRC",
43
- "CUC",
44
43
  "CUP",
45
44
  "CVE",
46
45
  "CZK",
@@ -69,7 +68,6 @@ var ISO_4217_CODES = [
69
68
  // H
70
69
  "HKD",
71
70
  "HNL",
72
- "HRK",
73
71
  "HTG",
74
72
  "HUF",
75
73
  // I
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/helpers.ts"],"names":[],"mappings":";AACA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAErB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA;AA8DO,SAAS,mBAAA,CAAoB,MAAc,YAAA,EAAkC;AAClF,EAAA,MAAM,OAAO,YAAA,IAAgB,cAAA;AAC7B,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,KAAA;AACrC,EAAA,MAAM,UAAA,GAAa,KAAK,WAAA,EAAY;AACpC,EAAA,OAAO,KAAK,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,WAAA,OAAkB,UAAU,CAAA;AACxD","file":"validate.mjs","sourcesContent":["// Complete ISO 4217 active currency codes\nconst ISO_4217_CODES = [\n // A\n \"AED\",\n \"AFN\",\n \"ALL\",\n \"AMD\",\n \"ANG\",\n \"AOA\",\n \"ARS\",\n \"AUD\",\n \"AWG\",\n \"AZN\",\n // B\n \"BAM\",\n \"BBD\",\n \"BDT\",\n \"BGN\",\n \"BHD\",\n \"BIF\",\n \"BMD\",\n \"BND\",\n \"BOB\",\n \"BOV\",\n \"BRL\",\n \"BSD\",\n \"BTN\",\n \"BWP\",\n \"BYN\",\n \"BZD\",\n // C\n \"CAD\",\n \"CDF\",\n \"CHE\",\n \"CHF\",\n \"CHW\",\n \"CLF\",\n \"CLP\",\n \"CNY\",\n \"COP\",\n \"COU\",\n \"CRC\",\n \"CUC\",\n \"CUP\",\n \"CVE\",\n \"CZK\",\n // D\n \"DJF\",\n \"DKK\",\n \"DOP\",\n \"DZD\",\n // E\n \"EGP\",\n \"ERN\",\n \"ETB\",\n \"EUR\",\n // F\n \"FJD\",\n \"FKP\",\n // G\n \"GBP\",\n \"GEL\",\n \"GHS\",\n \"GIP\",\n \"GMD\",\n \"GNF\",\n \"GTQ\",\n \"GYD\",\n // H\n \"HKD\",\n \"HNL\",\n \"HRK\",\n \"HTG\",\n \"HUF\",\n // I\n \"IDR\",\n \"ILS\",\n \"INR\",\n \"IQD\",\n \"IRR\",\n \"ISK\",\n // J\n \"JMD\",\n \"JOD\",\n \"JPY\",\n // K\n \"KES\",\n \"KGS\",\n \"KHR\",\n \"KMF\",\n \"KPW\",\n \"KRW\",\n \"KWD\",\n \"KYD\",\n \"KZT\",\n // L\n \"LAK\",\n \"LBP\",\n \"LRD\",\n \"LSL\",\n \"LYD\",\n // M\n \"MAD\",\n \"MDL\",\n \"MGA\",\n \"MKD\",\n \"MMK\",\n \"MNT\",\n \"MOP\",\n \"MRU\",\n \"MUR\",\n \"MVR\",\n \"MWK\",\n \"MXN\",\n \"MXV\",\n \"MYR\",\n \"MZN\",\n // N\n \"NAD\",\n \"NGN\",\n \"NIO\",\n \"NOK\",\n \"NPR\",\n \"NZD\",\n // O\n \"OMR\",\n // P\n \"PAB\",\n \"PEN\",\n \"PGK\",\n \"PHP\",\n \"PKR\",\n \"PLN\",\n \"PYG\",\n // Q\n \"QAR\",\n // R\n \"RON\",\n \"RSD\",\n \"RUB\",\n \"RWF\",\n // S\n \"SAR\",\n \"SBD\",\n \"SCR\",\n \"SDG\",\n \"SEK\",\n \"SGD\",\n \"SHP\",\n \"SLE\",\n \"SOS\",\n \"SRD\",\n \"SSP\",\n \"STN\",\n \"SVC\",\n \"SYP\",\n \"SZL\",\n // T\n \"THB\",\n \"TJS\",\n \"TMT\",\n \"TND\",\n \"TOP\",\n \"TRY\",\n \"TTD\",\n \"TWD\",\n \"TZS\",\n // U\n \"UAH\",\n \"UGX\",\n \"USD\",\n \"USN\",\n \"UYI\",\n \"UYU\",\n \"UZS\",\n // V\n \"VES\",\n \"VND\",\n \"VUV\",\n // W\n \"WST\",\n // X (special / supra-national)\n \"XAF\",\n \"XAG\",\n \"XAU\",\n \"XBA\",\n \"XBB\",\n \"XBC\",\n \"XBD\",\n \"XCD\",\n \"XDR\",\n \"XOF\",\n \"XPD\",\n \"XPF\",\n \"XPT\",\n \"XSU\",\n \"XTS\",\n \"XUA\",\n \"XXX\",\n // Y\n \"YER\",\n // Z\n \"ZAR\",\n \"ZMW\",\n \"ZWL\",\n];\nconst PATH_CACHE_MAX_SIZE = 500;\nconst pathCache = new Map<string, string[]>();\n\nexport function getPathArray(path: string): string[] {\n const cached = pathCache.get(path);\n if (cached) {\n // Refresh insertion order so least-recently-used entries are evicted first\n pathCache.delete(path);\n pathCache.set(path, cached);\n return cached;\n }\n\n const arr = path.split(\".\");\n if (pathCache.size >= PATH_CACHE_MAX_SIZE) {\n pathCache.delete(pathCache.keys().next().value as string);\n }\n pathCache.set(path, arr);\n return arr;\n}\n\nexport function getNestedValue(obj: unknown, path: string | string[]): unknown {\n const keys = Array.isArray(path) ? path : getPathArray(path);\n return keys.reduce((acc, key) => {\n if (acc && typeof acc === \"object\") {\n if (!Number.isNaN(Number(key)) && Array.isArray(acc)) {\n return acc[Number(key)];\n }\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\nexport function setNestedValue(obj: unknown, path: string | string[], value: unknown): void {\n const parts = Array.isArray(path) ? [...path] : [...getPathArray(path)];\n const last = parts.pop();\n if (!last) return;\n\n let target = obj as Record<string, unknown>;\n for (const key of parts) {\n if (!Number.isNaN(Number(key)) && Array.isArray(target)) {\n if (!target[Number(key)]) target[Number(key)] = {};\n target = target[Number(key)] as Record<string, unknown>;\n } else {\n if (typeof target[key] !== \"object\" || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n }\n if (!Number.isNaN(Number(last)) && Array.isArray(target)) {\n target[Number(last)] = value;\n } else {\n target[last] = value;\n }\n}\n\nexport function defaultRound(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nexport function isValidCurrencyCode(code: string, allowedCodes?: string[]): boolean {\n const list = allowedCodes || ISO_4217_CODES;\n if (typeof code !== \"string\") return false;\n const normalized = code.toUpperCase();\n return list.some((c) => c.toUpperCase() === normalized);\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/helpers.ts"],"names":[],"mappings":";AACA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAErB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA;AA8DO,SAAS,mBAAA,CAAoB,MAAc,YAAA,EAAkC;AAClF,EAAA,MAAM,OAAO,YAAA,IAAgB,cAAA;AAC7B,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,KAAA;AACrC,EAAA,MAAM,UAAA,GAAa,KAAK,WAAA,EAAY;AACpC,EAAA,OAAO,KAAK,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,WAAA,OAAkB,UAAU,CAAA;AACxD","file":"validate.mjs","sourcesContent":["// Complete ISO 4217 active currency codes\nconst ISO_4217_CODES = [\n // A\n \"AED\",\n \"AFN\",\n \"ALL\",\n \"AMD\",\n \"ANG\",\n \"AOA\",\n \"ARS\",\n \"AUD\",\n \"AWG\",\n \"AZN\",\n // B\n \"BAM\",\n \"BBD\",\n \"BDT\",\n \"BGN\",\n \"BHD\",\n \"BIF\",\n \"BMD\",\n \"BND\",\n \"BOB\",\n \"BOV\",\n \"BRL\",\n \"BSD\",\n \"BTN\",\n \"BWP\",\n \"BYN\",\n \"BZD\",\n // C\n \"CAD\",\n \"CDF\",\n \"CHE\",\n \"CHF\",\n \"CHW\",\n \"CLF\",\n \"CLP\",\n \"CNY\",\n \"COP\",\n \"COU\",\n \"CRC\",\n \"CUP\",\n \"CVE\",\n \"CZK\",\n // D\n \"DJF\",\n \"DKK\",\n \"DOP\",\n \"DZD\",\n // E\n \"EGP\",\n \"ERN\",\n \"ETB\",\n \"EUR\",\n // F\n \"FJD\",\n \"FKP\",\n // G\n \"GBP\",\n \"GEL\",\n \"GHS\",\n \"GIP\",\n \"GMD\",\n \"GNF\",\n \"GTQ\",\n \"GYD\",\n // H\n \"HKD\",\n \"HNL\",\n \"HTG\",\n \"HUF\",\n // I\n \"IDR\",\n \"ILS\",\n \"INR\",\n \"IQD\",\n \"IRR\",\n \"ISK\",\n // J\n \"JMD\",\n \"JOD\",\n \"JPY\",\n // K\n \"KES\",\n \"KGS\",\n \"KHR\",\n \"KMF\",\n \"KPW\",\n \"KRW\",\n \"KWD\",\n \"KYD\",\n \"KZT\",\n // L\n \"LAK\",\n \"LBP\",\n \"LRD\",\n \"LSL\",\n \"LYD\",\n // M\n \"MAD\",\n \"MDL\",\n \"MGA\",\n \"MKD\",\n \"MMK\",\n \"MNT\",\n \"MOP\",\n \"MRU\",\n \"MUR\",\n \"MVR\",\n \"MWK\",\n \"MXN\",\n \"MXV\",\n \"MYR\",\n \"MZN\",\n // N\n \"NAD\",\n \"NGN\",\n \"NIO\",\n \"NOK\",\n \"NPR\",\n \"NZD\",\n // O\n \"OMR\",\n // P\n \"PAB\",\n \"PEN\",\n \"PGK\",\n \"PHP\",\n \"PKR\",\n \"PLN\",\n \"PYG\",\n // Q\n \"QAR\",\n // R\n \"RON\",\n \"RSD\",\n \"RUB\",\n \"RWF\",\n // S\n \"SAR\",\n \"SBD\",\n \"SCR\",\n \"SDG\",\n \"SEK\",\n \"SGD\",\n \"SHP\",\n \"SLE\",\n \"SOS\",\n \"SRD\",\n \"SSP\",\n \"STN\",\n \"SVC\",\n \"SYP\",\n \"SZL\",\n // T\n \"THB\",\n \"TJS\",\n \"TMT\",\n \"TND\",\n \"TOP\",\n \"TRY\",\n \"TTD\",\n \"TWD\",\n \"TZS\",\n // U\n \"UAH\",\n \"UGX\",\n \"USD\",\n \"USN\",\n \"UYI\",\n \"UYU\",\n \"UZS\",\n // V\n \"VES\",\n \"VND\",\n \"VUV\",\n // W\n \"WST\",\n // X (special / supra-national)\n \"XAF\",\n \"XAG\",\n \"XAU\",\n \"XBA\",\n \"XBB\",\n \"XBC\",\n \"XBD\",\n \"XCD\",\n \"XDR\",\n \"XOF\",\n \"XPD\",\n \"XPF\",\n \"XPT\",\n \"XSU\",\n \"XTS\",\n \"XUA\",\n \"XXX\",\n // Y\n \"YER\",\n // Z\n \"ZAR\",\n \"ZMW\",\n \"ZWL\",\n];\nconst PATH_CACHE_MAX_SIZE = 500;\nconst pathCache = new Map<string, string[]>();\n\nexport function getPathArray(path: string): string[] {\n const cached = pathCache.get(path);\n if (cached) {\n // Refresh insertion order so least-recently-used entries are evicted first\n pathCache.delete(path);\n pathCache.set(path, cached);\n return cached;\n }\n\n const arr = path.split(\".\");\n if (pathCache.size >= PATH_CACHE_MAX_SIZE) {\n pathCache.delete(pathCache.keys().next().value as string);\n }\n pathCache.set(path, arr);\n return arr;\n}\n\nexport function getNestedValue(obj: unknown, path: string | string[]): unknown {\n const keys = Array.isArray(path) ? path : getPathArray(path);\n return keys.reduce((acc, key) => {\n if (acc && typeof acc === \"object\") {\n if (!Number.isNaN(Number(key)) && Array.isArray(acc)) {\n return acc[Number(key)];\n }\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\nexport function setNestedValue(obj: unknown, path: string | string[], value: unknown): void {\n const parts = Array.isArray(path) ? [...path] : [...getPathArray(path)];\n const last = parts.pop();\n if (!last) return;\n\n let target = obj as Record<string, unknown>;\n for (const key of parts) {\n if (!Number.isNaN(Number(key)) && Array.isArray(target)) {\n if (!target[Number(key)]) target[Number(key)] = {};\n target = target[Number(key)] as Record<string, unknown>;\n } else {\n if (typeof target[key] !== \"object\" || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n }\n if (!Number.isNaN(Number(last)) && Array.isArray(target)) {\n target[Number(last)] = value;\n } else {\n target[last] = value;\n }\n}\n\nexport function defaultRound(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\nexport function isValidCurrencyCode(code: string, allowedCodes?: string[]): boolean {\n const list = allowedCodes || ISO_4217_CODES;\n if (typeof code !== \"string\") return false;\n const normalized = code.toUpperCase();\n return list.some((c) => c.toUpperCase() === normalized);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mongoose-currency-convert",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "A lightweight Mongoose plugin for automatic currency conversion at save and update time — flexible, extensible, and service-agnostic.",
5
5
  "keywords": [
6
6
  "mongoose",
@@ -48,100 +48,35 @@
48
48
  "files": [
49
49
  "dist"
50
50
  ],
51
+ "sideEffects": false,
51
52
  "scripts": {
52
53
  "build": "tsup",
53
54
  "clean": "rm -rf dist",
54
- "prepare": "husky",
55
+ "typecheck": "tsc --noEmit -p tsconfig.json",
55
56
  "lint": "biome check src --verbose",
56
57
  "format": "biome format src --write",
57
58
  "prepublishOnly": "pnpm build",
58
- "release": "commit-and-tag-version",
59
- "release:minor": "commit-and-tag-version --release-as minor",
60
- "release:major": "commit-and-tag-version --release-as major",
61
- "release:dry": "commit-and-tag-version --dry-run",
62
- "test": "mocha --config .mocharc.json",
63
- "test:watch": "mocha --watch --config .mocharc.json",
64
- "coverage": "nyc pnpm test"
59
+ "release": "bash scripts/release.sh patch",
60
+ "release:minor": "bash scripts/release.sh minor",
61
+ "release:major": "bash scripts/release.sh major",
62
+ "test": "vitest run",
63
+ "test:watch": "vitest",
64
+ "coverage": "vitest run --coverage"
65
65
  },
66
66
  "peerDependencies": {
67
- "mongoose": ">=7.0.0"
67
+ "mongoose": ">=7.0.0 <9.0.0"
68
68
  },
69
69
  "devDependencies": {
70
- "@biomejs/biome": "^2.2.5",
71
- "@commitlint/config-conventional": "^20.0.0",
72
- "@types/chai": "^5.2.2",
73
- "@types/mocha": "^10.0.10",
74
- "@types/node": "^24.7.0",
75
- "chai": "^6.2.0",
76
- "commit-and-tag-version": "^12.6.1",
77
- "commitlint": "^20.1.0",
78
- "husky": "^9.1.7",
79
- "mocha": "^11.7.4",
80
- "mongoose": "^8.19.0",
81
- "nyc": "^17.1.0",
82
- "ts-node": "^10.9.2",
70
+ "@biomejs/biome": "^2.4.14",
71
+ "@types/node": "^22.0.0",
72
+ "@vitest/coverage-v8": "^4.1.5",
73
+ "mongodb-memory-server": "^11.1.0",
74
+ "mongoose": "^8.23.1",
83
75
  "tsup": "^8.5.1",
84
- "typescript": "^5.9.3"
76
+ "typescript": "^6.0.3",
77
+ "vitest": "^4.1.5"
85
78
  },
86
79
  "engines": {
87
- "node": ">=18.0.0"
88
- },
89
- "commit-and-tag-version": {
90
- "types": [
91
- {
92
- "type": "feat",
93
- "section": "Features"
94
- },
95
- {
96
- "type": "fix",
97
- "section": "Bug Fixes"
98
- },
99
- {
100
- "type": "perf",
101
- "section": "Performance"
102
- },
103
- {
104
- "type": "revert",
105
- "section": "Reverts"
106
- },
107
- {
108
- "type": "docs",
109
- "hidden": true
110
- },
111
- {
112
- "type": "chore",
113
- "hidden": true
114
- },
115
- {
116
- "type": "refactor",
117
- "hidden": true
118
- },
119
- {
120
- "type": "test",
121
- "hidden": true
122
- }
123
- ]
124
- },
125
- "nyc": {
126
- "extension": [
127
- ".ts"
128
- ],
129
- "include": [
130
- "src/**/*.ts"
131
- ],
132
- "exclude": [
133
- "test/**/*.ts",
134
- "dist/**/*.ts"
135
- ],
136
- "reporter": [
137
- "text",
138
- "lcov"
139
- ],
140
- "all": true,
141
- "check-coverage": true,
142
- "lines": 90,
143
- "functions": 90,
144
- "branches": 80,
145
- "statements": 90
80
+ "node": ">=22.0.0"
146
81
  }
147
82
  }