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 +17 -22
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +28 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -9
- package/dist/index.mjs.map +1 -1
- package/dist/utils/cache.js.map +1 -1
- package/dist/utils/cache.mjs.map +1 -1
- package/dist/validate.js +0 -2
- package/dist/validate.js.map +1 -1
- package/dist/validate.mjs +0 -2
- package/dist/validate.mjs.map +1 -1
- package/package.json +18 -83
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# mongoose-currency-convert
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/mongoose-currency-convert)
|
|
4
|
-
[](https://github.com/maku85/mongoose-currency-convert/actions/workflows/ci.yml)
|
|
5
5
|
[](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` | `
|
|
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
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
363
|
+
# minor release (0.2.4 → 0.3.0)
|
|
367
364
|
pnpm release:minor
|
|
368
|
-
pnpm release:major
|
|
369
365
|
|
|
370
|
-
#
|
|
371
|
-
|
|
366
|
+
# major release (0.2.4 → 1.0.0)
|
|
367
|
+
pnpm release:major
|
|
372
368
|
```
|
|
373
369
|
|
|
374
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 &&
|
|
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.
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
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 &&
|
|
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.
|
|
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 =
|
|
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 =
|
|
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:
|
|
510
|
+
amount: Number.isFinite(roundedAmount) ? roundedAmount : rawAmount,
|
|
492
511
|
currency: toCurrency,
|
|
493
512
|
date: conversionDate
|
|
494
513
|
};
|
package/dist/index.mjs.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,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;AA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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 \"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/utils/cache.js.map
CHANGED
|
@@ -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:
|
|
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"]}
|
package/dist/utils/cache.mjs.map
CHANGED
|
@@ -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:
|
|
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
package/dist/validate.js.map
CHANGED
|
@@ -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
|
|
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
package/dist/validate.mjs.map
CHANGED
|
@@ -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
|
|
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.
|
|
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
|
-
"
|
|
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": "
|
|
59
|
-
"release:minor": "
|
|
60
|
-
"release:major": "
|
|
61
|
-
"
|
|
62
|
-
"test": "
|
|
63
|
-
"
|
|
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.
|
|
71
|
-
"@
|
|
72
|
-
"@
|
|
73
|
-
"
|
|
74
|
-
"
|
|
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": "^
|
|
76
|
+
"typescript": "^6.0.3",
|
|
77
|
+
"vitest": "^4.1.5"
|
|
85
78
|
},
|
|
86
79
|
"engines": {
|
|
87
|
-
"node": ">=
|
|
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
|
}
|