@nr1e/commons 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,18 @@
5
5
 
6
6
  This project provides reusable components commonly needed in TypeScript projects.
7
7
 
8
+ | Module | Description |
9
+ | -------------------------- | --------------------------------------------------------------------------------------------- |
10
+ | `@nr1e/commons/bitsnbytes` | Base64 encoding/decoding utilities |
11
+ | `@nr1e/commons/encryption` | Cryptographic utilities including AES encryption and RSA encryption |
12
+ | `@nr1e/commons/errors` | Error handling utilities and custom error types |
13
+ | `@nr1e/commons/http` | HTTP status codes and HTTP method constants |
14
+ | `@nr1e/commons/ids` | ID generation utilities (UUID v4/v7, KSUID) |
15
+ | `@nr1e/commons/lang` | Language utilities for currency, datetime, equality, merge, sleep, string, and type functions |
16
+ | `@nr1e/commons/oauth` | OAuth 2.0 cryptographic functions (PKCE) |
17
+ | `@nr1e/commons/os` | Operating system utilities including environment variable helpers |
18
+ | `@nr1e/commons/validator` | Input validation utilities |
19
+
8
20
  [github-url]: https://github.com/nr1etech/lib-js/actions
9
21
  [github-image]: https://github.com/nr1etech/lib-js/workflows/ci/badge.svg
10
22
  [npm-url]: https://npmjs.org/package/@nr1e/commons-js
@@ -1,2 +1,3 @@
1
1
  export * from './errors.mjs';
2
+ export * from './safe.mjs';
2
3
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/errors/index.mts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/errors/index.mts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export * from './errors.mjs';
2
+ export * from './safe.mjs';
2
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/errors/index.mts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/errors/index.mts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,15 @@
1
+ export type SafeResult<T> = {
2
+ success: true;
3
+ output: T;
4
+ } | {
5
+ success: false;
6
+ error: string;
7
+ };
8
+ /**
9
+ * Wraps a throwing function and returns a non-throwing result.
10
+ *
11
+ * @param fn - Function that may throw
12
+ * @param defaultMessage - Message to use if a non-Error is thrown
13
+ */
14
+ export declare function safeCall<T>(fn: () => T, defaultMessage?: string): SafeResult<T>;
15
+ //# sourceMappingURL=safe.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe.d.mts","sourceRoot":"","sources":["../../src/errors/safe.mts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB;IAAC,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAC,GAC1B;IAAC,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC;AAEpC;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,EAAE,EAAE,MAAM,CAAC,EACX,cAAc,SAAkB,GAC/B,UAAU,CAAC,CAAC,CAAC,CASf"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Wraps a throwing function and returns a non-throwing result.
3
+ *
4
+ * @param fn - Function that may throw
5
+ * @param defaultMessage - Message to use if a non-Error is thrown
6
+ */
7
+ export function safeCall(fn, defaultMessage = 'Unknown error') {
8
+ try {
9
+ return { success: true, output: fn() };
10
+ }
11
+ catch (err) {
12
+ return {
13
+ success: false,
14
+ error: err instanceof Error ? err.message : defaultMessage,
15
+ };
16
+ }
17
+ }
18
+ //# sourceMappingURL=safe.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe.mjs","sourceRoot":"","sources":["../../src/errors/safe.mts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CACtB,EAAW,EACX,cAAc,GAAG,eAAe;IAEhC,IAAI,CAAC;QACH,OAAO,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc;SAC3D,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { SafeResult } from '../errors/index.mjs';
2
+ /**
3
+ * Parses an amount in the format "0.00", "0.0" or "0" and converts it to a
4
+ * number. Both positive and negative values are supported. This will throw
5
+ * an error if the amount is not in the expected format.
6
+ *
7
+ * @param amount - The amount string to parse
8
+ * @returns The parsed amount as a number
9
+ * @throws Error if the amount is not in the expected format or is not a finite number
10
+ */
11
+ export declare function parseAmount(amount: string): number;
12
+ /**
13
+ * Parses an amount in the format "0.00", "0.0" or "0" and converts it to a
14
+ * number. Both positive and negative values are supported. This will return
15
+ * an error message if the amount is not in the expected format.
16
+ *
17
+ * @param input - The amount string to parse
18
+ * @returns A safe result containing the parsed amount as a number, or an error message if the amount is invalid.
19
+ */
20
+ export declare function safeParseAmount(input: string): SafeResult<number>;
21
+ /**
22
+ * Formats a number into a canonical "0.00" amount string. Numbers must be two
23
+ * decimal places or less. Both positive and negative values are supported.
24
+ *
25
+ * @param value - The number to format
26
+ * @returns The formatted amount string, e.g., "10.00" or "-10.00"
27
+ * @throws Error if the value is not finite or exceeds two decimal places
28
+ */
29
+ export declare function formatAmount(value: number): string;
30
+ /**
31
+ * Formats a number into a canonical "0.00" amount string. Numbers must be two
32
+ * decimal places or less. Both positive and negative values are supported.
33
+ *
34
+ * @param value - The number to format
35
+ * @returns A safe result containing the formatted amount string, or an error message if the value is invalid.
36
+ */
37
+ export declare function safeFormatAmount(value: number): SafeResult<string>;
38
+ //# sourceMappingURL=amount.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"amount.d.mts","sourceRoot":"","sources":["../../src/lang/amount.mts"],"names":[],"mappings":"AAAA,OAAO,EAAW,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAelD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAEjE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAsBlD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAElE"}
@@ -0,0 +1,70 @@
1
+ import { safeCall } from '../errors/index.mjs';
2
+ /**
3
+ * Parses an amount in the format "0.00", "0.0" or "0" and converts it to a
4
+ * number. Both positive and negative values are supported. This will throw
5
+ * an error if the amount is not in the expected format.
6
+ *
7
+ * @param amount - The amount string to parse
8
+ * @returns The parsed amount as a number
9
+ * @throws Error if the amount is not in the expected format or is not a finite number
10
+ */
11
+ export function parseAmount(amount) {
12
+ const trimmed = amount.trim();
13
+ const AMOUNT_REGEX = /^-?\d+(\.\d{1,2})?$/;
14
+ if (!AMOUNT_REGEX.test(trimmed)) {
15
+ throw new Error(`Invalid amount format: "${amount}"`);
16
+ }
17
+ const value = Number(trimmed);
18
+ if (!Number.isFinite(value)) {
19
+ throw new Error(`Invalid numeric value: "${amount}"`);
20
+ }
21
+ return value;
22
+ }
23
+ /**
24
+ * Parses an amount in the format "0.00", "0.0" or "0" and converts it to a
25
+ * number. Both positive and negative values are supported. This will return
26
+ * an error message if the amount is not in the expected format.
27
+ *
28
+ * @param input - The amount string to parse
29
+ * @returns A safe result containing the parsed amount as a number, or an error message if the amount is invalid.
30
+ */
31
+ export function safeParseAmount(input) {
32
+ return safeCall(() => parseAmount(input), 'Invalid amount format');
33
+ }
34
+ /**
35
+ * Formats a number into a canonical "0.00" amount string. Numbers must be two
36
+ * decimal places or less. Both positive and negative values are supported.
37
+ *
38
+ * @param value - The number to format
39
+ * @returns The formatted amount string, e.g., "10.00" or "-10.00"
40
+ * @throws Error if the value is not finite or exceeds two decimal places
41
+ */
42
+ export function formatAmount(value) {
43
+ if (!Number.isFinite(value)) {
44
+ throw new Error('Amount must be a finite number');
45
+ }
46
+ if (Number.isNaN(value)) {
47
+ throw new Error('Amount must be a valid number');
48
+ }
49
+ // Normalize -0 → 0
50
+ const normalized = Object.is(value, -0) ? 0 : value;
51
+ // Convert to string without scientific notation
52
+ const asString = normalized.toString();
53
+ // Validate decimal precision (max 2 decimal places)
54
+ const DECIMAL_REGEX = /^-?\d+(\.\d{1,2})?$/;
55
+ if (!DECIMAL_REGEX.test(asString)) {
56
+ throw new Error(`Invalid amount format: "${asString}"`);
57
+ }
58
+ return normalized.toFixed(2);
59
+ }
60
+ /**
61
+ * Formats a number into a canonical "0.00" amount string. Numbers must be two
62
+ * decimal places or less. Both positive and negative values are supported.
63
+ *
64
+ * @param value - The number to format
65
+ * @returns A safe result containing the formatted amount string, or an error message if the value is invalid.
66
+ */
67
+ export function safeFormatAmount(value) {
68
+ return safeCall(() => formatAmount(value), 'Invalid amount');
69
+ }
70
+ //# sourceMappingURL=amount.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"amount.mjs","sourceRoot":"","sources":["../../src/lang/amount.mts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAa,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,MAAM,YAAY,GAAG,qBAAqB,CAAC;IAE3C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAE9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,uBAAuB,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IAED,mBAAmB;IACnB,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAEpD,gDAAgD;IAChD,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;IAEvC,oDAAoD;IACpD,MAAM,aAAa,GAAG,qBAAqB,CAAC;IAE5C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=amount.test.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"amount.test.d.mts","sourceRoot":"","sources":["../../src/lang/amount.test.mts"],"names":[],"mappings":""}
@@ -0,0 +1,104 @@
1
+ import { test, expect, describe } from 'vitest';
2
+ import { parseAmount, safeParseAmount, formatAmount, safeFormatAmount, } from './amount.mjs';
3
+ describe('parseAmount', () => {
4
+ test('parses valid integer formats', () => {
5
+ expect(parseAmount('0')).toBe(0);
6
+ expect(parseAmount('10')).toBe(10);
7
+ expect(parseAmount('100')).toBe(100);
8
+ });
9
+ test('parses valid decimal formats', () => {
10
+ expect(parseAmount('10.0')).toBe(10);
11
+ expect(parseAmount('10.00')).toBe(10);
12
+ expect(parseAmount('10.5')).toBe(10.5);
13
+ expect(parseAmount('10.99')).toBe(10.99);
14
+ expect(parseAmount('0.01')).toBe(0.01);
15
+ });
16
+ test('parses negative values', () => {
17
+ expect(parseAmount('-10')).toBe(-10);
18
+ expect(parseAmount('-10.50')).toBe(-10.5);
19
+ expect(parseAmount('-0.01')).toBe(-0.01);
20
+ });
21
+ test('handles whitespace', () => {
22
+ expect(parseAmount(' 10.00 ')).toBe(10);
23
+ expect(parseAmount('\t10.50\n')).toBe(10.5);
24
+ });
25
+ test('throws on invalid formats', () => {
26
+ expect(() => parseAmount('')).toThrow('Invalid amount format');
27
+ expect(() => parseAmount(' ')).toThrow('Invalid amount format');
28
+ expect(() => parseAmount('abc')).toThrow('Invalid amount format');
29
+ expect(() => parseAmount('10.000')).toThrow('Invalid amount format');
30
+ expect(() => parseAmount('10.')).toThrow('Invalid amount format');
31
+ expect(() => parseAmount('.10')).toThrow('Invalid amount format');
32
+ expect(() => parseAmount('10.5.5')).toThrow('Invalid amount format');
33
+ expect(() => parseAmount('$10.00')).toThrow('Invalid amount format');
34
+ expect(() => parseAmount('10,000.00')).toThrow('Invalid amount format');
35
+ });
36
+ test('throws on special numeric values', () => {
37
+ expect(() => parseAmount('NaN')).toThrow('Invalid amount format');
38
+ expect(() => parseAmount('Infinity')).toThrow('Invalid amount format');
39
+ expect(() => parseAmount('-Infinity')).toThrow('Invalid amount format');
40
+ });
41
+ });
42
+ describe('safeParseAmount', () => {
43
+ test('returns success for valid amounts', () => {
44
+ const result = safeParseAmount('10.50');
45
+ expect(result.success).toBe(true);
46
+ if (result.success) {
47
+ expect(result.output).toBe(10.5);
48
+ }
49
+ });
50
+ test('returns error for invalid amounts', () => {
51
+ const result = safeParseAmount('invalid');
52
+ expect(result.success).toBe(false);
53
+ if (!result.success) {
54
+ expect(result.error).toContain('Invalid amount format');
55
+ }
56
+ });
57
+ });
58
+ describe('formatAmount', () => {
59
+ test('formats integers with two decimal places', () => {
60
+ expect(formatAmount(0)).toBe('0.00');
61
+ expect(formatAmount(10)).toBe('10.00');
62
+ expect(formatAmount(100)).toBe('100.00');
63
+ });
64
+ test('formats decimals with two decimal places', () => {
65
+ expect(formatAmount(10.5)).toBe('10.50');
66
+ expect(formatAmount(10.99)).toBe('10.99');
67
+ expect(formatAmount(0.01)).toBe('0.01');
68
+ });
69
+ test('formats negative values', () => {
70
+ expect(formatAmount(-10)).toBe('-10.00');
71
+ expect(formatAmount(-10.5)).toBe('-10.50');
72
+ expect(formatAmount(-0.01)).toBe('-0.01');
73
+ });
74
+ test('normalizes negative zero', () => {
75
+ expect(formatAmount(-0)).toBe('0.00');
76
+ });
77
+ test('throws on non-finite numbers', () => {
78
+ expect(() => formatAmount(NaN)).toThrow('Amount must be a finite number');
79
+ expect(() => formatAmount(Infinity)).toThrow('Amount must be a finite number');
80
+ expect(() => formatAmount(-Infinity)).toThrow('Amount must be a finite number');
81
+ });
82
+ test('throws on excessive decimal precision', () => {
83
+ expect(() => formatAmount(10.999)).toThrow('Invalid amount format');
84
+ expect(() => formatAmount(0.001)).toThrow('Invalid amount format');
85
+ expect(() => formatAmount(10.123456)).toThrow('Invalid amount format');
86
+ });
87
+ });
88
+ describe('safeFormatAmount', () => {
89
+ test('returns success for valid amounts', () => {
90
+ const result = safeFormatAmount(10.5);
91
+ expect(result.success).toBe(true);
92
+ if (result.success) {
93
+ expect(result.output).toBe('10.50');
94
+ }
95
+ });
96
+ test('returns error for invalid amounts', () => {
97
+ const result = safeFormatAmount(NaN);
98
+ expect(result.success).toBe(false);
99
+ if (!result.success) {
100
+ expect(result.error).toBe('Amount must be a finite number');
101
+ }
102
+ });
103
+ });
104
+ //# sourceMappingURL=amount.test.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"amount.test.mjs","sourceRoot":"","sources":["../../src/lang/amount.test.mts"],"names":[],"mappings":"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"}
@@ -1,10 +1,23 @@
1
+ import { SafeResult } from '../errors/index.mjs';
1
2
  /**
2
- * Formats a currency amount using the Intl.NumberFormat API
3
+ * Formats a currency amount using the Intl.NumberFormat API.
4
+ * All inputs are validated and normalized to two decimal places.
3
5
  *
4
- * @param amount - The amount in cents (e.g., 1000 for $10.00) as number or string
5
- * @param currency - The currency code (e.g., 'USD', 'EUR')
6
- * @param locale - The locale to use (e.g., 'en-US', 'fr-FR') - defaults to 'en-US'
6
+ * @param amount - Amount as number or string ("0", "0.0", "0.00")
7
+ * @param currency - Currency code (e.g., 'USD', 'EUR')
8
+ * @param locale - Locale (defaults to 'en-US')
7
9
  * @returns Formatted currency string
10
+ * @throws Error if the amount is invalid
8
11
  */
9
- export declare const formatCurrency: (amount: number | string, currency: string, locale?: string) => string;
12
+ export declare function formatCurrency(amount: number | string, currency: string, locale?: string): string;
13
+ /**
14
+ * Safely formats a currency amount.
15
+ *
16
+ * @param amount - Amount as number or string
17
+ * @param currency - Currency code (e.g., 'USD')
18
+ * @param locale - Locale (defaults to 'en-US')
19
+ * @returns A safe result containing the formatted currency string,
20
+ * or an error message if the amount is invalid.
21
+ */
22
+ export declare function safeFormatCurrency(amount: number | string, currency: string, locale?: string): SafeResult<string>;
10
23
  //# sourceMappingURL=currency.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"currency.d.mts","sourceRoot":"","sources":["../../src/lang/currency.mts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,WACjB,MAAM,GAAG,MAAM,YACb,MAAM,WACP,MAAM,KACd,MAOF,CAAC"}
1
+ {"version":3,"file":"currency.d.mts","sourceRoot":"","sources":["../../src/lang/currency.mts"],"names":[],"mappings":"AACA,OAAO,EAAW,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAgBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,UAAU,CAAC,MAAM,CAAC,CAKpB"}
@@ -1,16 +1,42 @@
1
+ import { formatAmount, parseAmount } from './amount.mjs';
2
+ import { safeCall } from '../errors/index.mjs';
1
3
  /**
2
- * Formats a currency amount using the Intl.NumberFormat API
4
+ * Formats a currency amount using the Intl.NumberFormat API.
5
+ * All inputs are validated and normalized to two decimal places.
3
6
  *
4
- * @param amount - The amount in cents (e.g., 1000 for $10.00) as number or string
5
- * @param currency - The currency code (e.g., 'USD', 'EUR')
6
- * @param locale - The locale to use (e.g., 'en-US', 'fr-FR') - defaults to 'en-US'
7
+ * @param amount - Amount as number or string ("0", "0.0", "0.00")
8
+ * @param currency - Currency code (e.g., 'USD', 'EUR')
9
+ * @param locale - Locale (defaults to 'en-US')
7
10
  * @returns Formatted currency string
11
+ * @throws Error if the amount is invalid
8
12
  */
9
- export const formatCurrency = (amount, currency, locale) => {
10
- const numericAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
13
+ export function formatCurrency(amount, currency, locale) {
14
+ let numericAmount;
15
+ if (typeof amount === 'string') {
16
+ // strict string validation: disallows "0.000", etc.
17
+ numericAmount = parseAmount(amount);
18
+ }
19
+ else {
20
+ // strict numeric validation + normalization
21
+ numericAmount = parseFloat(formatAmount(amount));
22
+ }
11
23
  return new Intl.NumberFormat(locale ?? 'en-US', {
12
24
  style: 'currency',
13
25
  currency: currency.toUpperCase(),
26
+ minimumFractionDigits: 2,
27
+ maximumFractionDigits: 2,
14
28
  }).format(numericAmount);
15
- };
29
+ }
30
+ /**
31
+ * Safely formats a currency amount.
32
+ *
33
+ * @param amount - Amount as number or string
34
+ * @param currency - Currency code (e.g., 'USD')
35
+ * @param locale - Locale (defaults to 'en-US')
36
+ * @returns A safe result containing the formatted currency string,
37
+ * or an error message if the amount is invalid.
38
+ */
39
+ export function safeFormatCurrency(amount, currency, locale) {
40
+ return safeCall(() => formatCurrency(amount, currency, locale), 'Invalid currency amount');
41
+ }
16
42
  //# sourceMappingURL=currency.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"currency.mjs","sourceRoot":"","sources":["../../src/lang/currency.mts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAAuB,EACvB,QAAgB,EAChB,MAAe,EACP,EAAE;IACV,MAAM,aAAa,GACjB,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3D,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,IAAI,OAAO,EAAE;QAC9C,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,QAAQ,CAAC,WAAW,EAAE;KACjC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AAC3B,CAAC,CAAC"}
1
+ {"version":3,"file":"currency.mjs","sourceRoot":"","sources":["../../src/lang/currency.mts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,WAAW,EAAC,MAAM,cAAc,CAAC;AACvD,OAAO,EAAC,QAAQ,EAAa,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAuB,EACvB,QAAgB,EAChB,MAAe;IAEf,IAAI,aAAqB,CAAC;IAC1B,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,oDAAoD;QACpD,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,4CAA4C;QAC5C,aAAa,GAAG,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,IAAI,OAAO,EAAE;QAC9C,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,QAAQ,CAAC,WAAW,EAAE;QAChC,qBAAqB,EAAE,CAAC;QACxB,qBAAqB,EAAE,CAAC;KACzB,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAuB,EACvB,QAAgB,EAChB,MAAe;IAEf,OAAO,QAAQ,CACb,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,EAC9C,yBAAyB,CAC1B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=currency.test.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currency.test.d.mts","sourceRoot":"","sources":["../../src/lang/currency.test.mts"],"names":[],"mappings":""}
@@ -0,0 +1,97 @@
1
+ import { test, expect, describe } from 'vitest';
2
+ import { formatCurrency, safeFormatCurrency } from './currency.mjs';
3
+ describe('formatCurrency', () => {
4
+ test('formats string amounts with USD', () => {
5
+ expect(formatCurrency('10', 'USD')).toBe('$10.00');
6
+ expect(formatCurrency('10.5', 'USD')).toBe('$10.50');
7
+ expect(formatCurrency('10.99', 'USD')).toBe('$10.99');
8
+ expect(formatCurrency('0', 'USD')).toBe('$0.00');
9
+ });
10
+ test('formats number amounts with USD', () => {
11
+ expect(formatCurrency(10, 'USD')).toBe('$10.00');
12
+ expect(formatCurrency(10.5, 'USD')).toBe('$10.50');
13
+ expect(formatCurrency(10.99, 'USD')).toBe('$10.99');
14
+ expect(formatCurrency(0, 'USD')).toBe('$0.00');
15
+ });
16
+ test('formats negative amounts', () => {
17
+ expect(formatCurrency('-10.50', 'USD')).toBe('-$10.50');
18
+ expect(formatCurrency(-10.5, 'USD')).toBe('-$10.50');
19
+ });
20
+ test('handles different currencies', () => {
21
+ expect(formatCurrency('10', 'EUR')).toBe('€10.00');
22
+ expect(formatCurrency('10', 'GBP')).toBe('£10.00');
23
+ expect(formatCurrency('10', 'JPY')).toBe('¥10.00');
24
+ });
25
+ test('handles lowercase currency codes', () => {
26
+ expect(formatCurrency('10', 'usd')).toBe('$10.00');
27
+ expect(formatCurrency('10', 'eur')).toBe('€10.00');
28
+ });
29
+ test('formats with different locales', () => {
30
+ // German locale uses different formatting
31
+ expect(formatCurrency('1234.56', 'EUR', 'de-DE')).toBe('1.234,56\u00A0€');
32
+ // Japanese locale (uses fullwidth yen symbol ¥)
33
+ expect(formatCurrency('1234.56', 'JPY', 'ja-JP')).toBe('¥1,234.56');
34
+ // US locale (default)
35
+ expect(formatCurrency('1234.56', 'USD', 'en-US')).toBe('$1,234.56');
36
+ });
37
+ test('validates and normalizes numeric precision', () => {
38
+ // Numbers with valid precision are formatted correctly
39
+ expect(formatCurrency(10.5, 'USD')).toBe('$10.50');
40
+ expect(formatCurrency(10.99, 'USD')).toBe('$10.99');
41
+ });
42
+ test('throws on invalid string amounts', () => {
43
+ expect(() => formatCurrency('invalid', 'USD')).toThrow('Invalid amount format');
44
+ expect(() => formatCurrency('10.000', 'USD')).toThrow('Invalid amount format');
45
+ expect(() => formatCurrency('$10.00', 'USD')).toThrow('Invalid amount format');
46
+ });
47
+ test('throws on invalid numeric amounts', () => {
48
+ expect(() => formatCurrency(NaN, 'USD')).toThrow('Amount must be a finite number');
49
+ expect(() => formatCurrency(Infinity, 'USD')).toThrow('Amount must be a finite number');
50
+ expect(() => formatCurrency(10.999, 'USD')).toThrow('Invalid amount format');
51
+ });
52
+ test('uses en-US locale by default', () => {
53
+ expect(formatCurrency('1234.56', 'USD')).toBe('$1,234.56');
54
+ });
55
+ test('handles large amounts', () => {
56
+ expect(formatCurrency('1000000', 'USD')).toBe('$1,000,000.00');
57
+ expect(formatCurrency('1000000.99', 'USD')).toBe('$1,000,000.99');
58
+ });
59
+ });
60
+ describe('safeFormatCurrency', () => {
61
+ test('returns success for valid string amounts', () => {
62
+ const result = safeFormatCurrency('10.50', 'USD');
63
+ expect(result.success).toBe(true);
64
+ if (result.success) {
65
+ expect(result.output).toBe('$10.50');
66
+ }
67
+ });
68
+ test('returns success for valid numeric amounts', () => {
69
+ const result = safeFormatCurrency(10.5, 'USD');
70
+ expect(result.success).toBe(true);
71
+ if (result.success) {
72
+ expect(result.output).toBe('$10.50');
73
+ }
74
+ });
75
+ test('returns error for invalid string amounts', () => {
76
+ const result = safeFormatCurrency('invalid', 'USD');
77
+ expect(result.success).toBe(false);
78
+ if (!result.success) {
79
+ expect(result.error).toBe('Invalid amount format: "invalid"');
80
+ }
81
+ });
82
+ test('returns error for invalid numeric amounts', () => {
83
+ const result = safeFormatCurrency(NaN, 'USD');
84
+ expect(result.success).toBe(false);
85
+ if (!result.success) {
86
+ expect(result.error).toBe('Amount must be a finite number');
87
+ }
88
+ });
89
+ test('returns error for excessive precision', () => {
90
+ const result = safeFormatCurrency(10.999, 'USD');
91
+ expect(result.success).toBe(false);
92
+ if (!result.success) {
93
+ expect(result.error).toBe('Invalid amount format: "10.999"');
94
+ }
95
+ });
96
+ });
97
+ //# sourceMappingURL=currency.test.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currency.test.mjs","sourceRoot":"","sources":["../../src/lang/currency.test.mts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAC,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAC,cAAc,EAAE,kBAAkB,EAAC,MAAM,gBAAgB,CAAC;AAElE,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxD,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAC1C,0CAA0C;QAC1C,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC1E,gDAAgD;QAChD,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACpE,sBAAsB;QACtB,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACtD,uDAAuD;QACvD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CACpD,uBAAuB,CACxB,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CACnD,uBAAuB,CACxB,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CACnD,uBAAuB,CACxB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAC9C,gCAAgC,CACjC,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CACnD,gCAAgC,CACjC,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CACjD,uBAAuB,CACxB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACjC,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC/D,MAAM,CAAC,cAAc,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACrD,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACrD,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,uCAAuC,EAAE,GAAG,EAAE;QACjD,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,3 +1,4 @@
1
+ export * from './amount.mjs';
1
2
  export * from './currency.mjs';
2
3
  export * from './datetime.mjs';
3
4
  export * from './equality.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/lang/index.mts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/lang/index.mts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
@@ -1,3 +1,4 @@
1
+ export * from './amount.mjs';
1
2
  export * from './currency.mjs';
2
3
  export * from './datetime.mjs';
3
4
  export * from './equality.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/lang/index.mts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/lang/index.mts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nr1e/commons",
3
3
  "description": "Common utilities for TypeScript projects",
4
- "version": "0.3.1",
4
+ "version": "0.3.3",
5
5
  "type": "module",
6
6
  "author": "NR1E, Inc.",
7
7
  "publishConfig": {
@@ -17,10 +17,10 @@
17
17
  ],
18
18
  "devDependencies": {
19
19
  "@eslint/js": "latest",
20
- "@types/node": "^20.19.0",
20
+ "@types/node": "^25.0.10",
21
21
  "@types/uuid": "^10.0.0",
22
- "eslint": "9.32.0",
23
- "prettier": "3.6.2",
22
+ "eslint": "9.39.2",
23
+ "prettier": "3.8.1",
24
24
  "typescript": "5.4.5",
25
25
  "typescript-eslint": "8.38.0",
26
26
  "vitest": "4.0.6"
@@ -72,7 +72,7 @@
72
72
  "prebuild": "prettier --check . && eslint .",
73
73
  "build": "tsc",
74
74
  "watch": "tsc -w",
75
- "test": "vitest run",
75
+ "test": "vitest run src",
76
76
  "clean": "rm -rf dist",
77
77
  "fmt": "prettier --write ."
78
78
  }