@hardlydifficult/text 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -0
- package/dist/chunkText.d.ts +13 -0
- package/dist/chunkText.d.ts.map +1 -0
- package/dist/chunkText.js +36 -0
- package/dist/chunkText.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/template.d.ts +20 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +40 -0
- package/dist/template.js.map +1 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @hardlydifficult/text
|
|
2
|
+
|
|
3
|
+
Text utilities for error formatting, template replacement, and chunking.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @hardlydifficult/text
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### `getErrorMessage(err: unknown): string`
|
|
14
|
+
|
|
15
|
+
Extract a message string from an unknown error. Returns `err.message` for `Error` instances, `String(err)` otherwise.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { getErrorMessage } from "@hardlydifficult/text";
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
await riskyOperation();
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error(getErrorMessage(err));
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### `formatError(err: unknown, context?: string): string`
|
|
28
|
+
|
|
29
|
+
Format an error for user-facing output. Prepends an optional context prefix.
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { formatError } from "@hardlydifficult/text";
|
|
33
|
+
|
|
34
|
+
formatError(new Error("not found"), "User lookup"); // "User lookup: not found"
|
|
35
|
+
formatError(new Error("not found")); // "not found"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### `formatErrorForLog(err: unknown): string`
|
|
39
|
+
|
|
40
|
+
Format an error for logging. Returns the message for `Error` instances, `String(err)` otherwise.
|
|
41
|
+
|
|
42
|
+
### `replaceTemplate(template: string, values: Record<string, string>): string`
|
|
43
|
+
|
|
44
|
+
Replace `{{variable}}` placeholders with provided values. Unmatched placeholders are left as-is.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { replaceTemplate } from "@hardlydifficult/text";
|
|
48
|
+
|
|
49
|
+
replaceTemplate("Hello {{name}}, welcome to {{place}}!", {
|
|
50
|
+
name: "Alice",
|
|
51
|
+
place: "Wonderland",
|
|
52
|
+
});
|
|
53
|
+
// "Hello Alice, welcome to Wonderland!"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `extractPlaceholders(template: string): string[]`
|
|
57
|
+
|
|
58
|
+
Extract all unique placeholder names from a template.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { extractPlaceholders } from "@hardlydifficult/text";
|
|
62
|
+
|
|
63
|
+
extractPlaceholders("{{name}} is in {{place}}"); // ["name", "place"]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `chunkText(text: string, maxLength: number): string[]`
|
|
67
|
+
|
|
68
|
+
Split text into chunks of at most `maxLength` characters. Prefers breaking on newlines, then spaces, and falls back to hard breaks.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { chunkText } from "@hardlydifficult/text";
|
|
72
|
+
|
|
73
|
+
const chunks = chunkText(longMessage, 2000);
|
|
74
|
+
for (const chunk of chunks) {
|
|
75
|
+
await channel.send(chunk);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split text into chunks that respect a maximum length.
|
|
3
|
+
* Prefers breaking on newlines, then spaces, and falls back to hard breaks.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Split text into chunks of at most `maxLength` characters.
|
|
7
|
+
*
|
|
8
|
+
* @param text - The text to split
|
|
9
|
+
* @param maxLength - Maximum length of each chunk
|
|
10
|
+
* @returns Array of text chunks
|
|
11
|
+
*/
|
|
12
|
+
export declare function chunkText(text: string, maxLength: number): string[];
|
|
13
|
+
//# sourceMappingURL=chunkText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunkText.d.ts","sourceRoot":"","sources":["../src/chunkText.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBnE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Split text into chunks that respect a maximum length.
|
|
4
|
+
* Prefers breaking on newlines, then spaces, and falls back to hard breaks.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.chunkText = chunkText;
|
|
8
|
+
/**
|
|
9
|
+
* Split text into chunks of at most `maxLength` characters.
|
|
10
|
+
*
|
|
11
|
+
* @param text - The text to split
|
|
12
|
+
* @param maxLength - Maximum length of each chunk
|
|
13
|
+
* @returns Array of text chunks
|
|
14
|
+
*/
|
|
15
|
+
function chunkText(text, maxLength) {
|
|
16
|
+
const chunks = [];
|
|
17
|
+
let remaining = text;
|
|
18
|
+
while (remaining.length > 0) {
|
|
19
|
+
if (remaining.length <= maxLength) {
|
|
20
|
+
chunks.push(remaining);
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
// Find a good break point (newline or space)
|
|
24
|
+
let breakPoint = remaining.lastIndexOf("\n", maxLength);
|
|
25
|
+
if (breakPoint === -1 || breakPoint < maxLength / 2) {
|
|
26
|
+
breakPoint = remaining.lastIndexOf(" ", maxLength);
|
|
27
|
+
}
|
|
28
|
+
if (breakPoint === -1 || breakPoint < maxLength / 2) {
|
|
29
|
+
breakPoint = maxLength;
|
|
30
|
+
}
|
|
31
|
+
chunks.push(remaining.slice(0, breakPoint));
|
|
32
|
+
remaining = remaining.slice(breakPoint).trimStart();
|
|
33
|
+
}
|
|
34
|
+
return chunks;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=chunkText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunkText.js","sourceRoot":"","sources":["../src/chunkText.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AASH,8BAwBC;AA/BD;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,IAAY,EAAE,SAAiB;IACvD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,IAAI,CAAC;IAErB,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvB,MAAM;QACR,CAAC;QAED,6CAA6C;QAC7C,IAAI,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACxD,IAAI,UAAU,KAAK,CAAC,CAAC,IAAI,UAAU,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC;YACpD,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,UAAU,KAAK,CAAC,CAAC,IAAI,UAAU,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC;YACpD,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;QAC5C,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC;IACtD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error utilities - consistent error handling across the codebase
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Extract a message string from an unknown error
|
|
6
|
+
*/
|
|
7
|
+
export declare function getErrorMessage(err: unknown): string;
|
|
8
|
+
/**
|
|
9
|
+
* Format an error for user-facing output
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatError(err: unknown, context?: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Format an error for logging (includes more detail for non-Error types)
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatErrorForLog(err: unknown): string;
|
|
16
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAKpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAKtD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Error utilities - consistent error handling across the codebase
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getErrorMessage = getErrorMessage;
|
|
7
|
+
exports.formatError = formatError;
|
|
8
|
+
exports.formatErrorForLog = formatErrorForLog;
|
|
9
|
+
/**
|
|
10
|
+
* Extract a message string from an unknown error
|
|
11
|
+
*/
|
|
12
|
+
function getErrorMessage(err) {
|
|
13
|
+
if (err instanceof Error) {
|
|
14
|
+
return err.message;
|
|
15
|
+
}
|
|
16
|
+
return String(err);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Format an error for user-facing output
|
|
20
|
+
*/
|
|
21
|
+
function formatError(err, context) {
|
|
22
|
+
const message = getErrorMessage(err);
|
|
23
|
+
if (context !== undefined && context !== "") {
|
|
24
|
+
return `${context}: ${message}`;
|
|
25
|
+
}
|
|
26
|
+
return message;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Format an error for logging (includes more detail for non-Error types)
|
|
30
|
+
*/
|
|
31
|
+
function formatErrorForLog(err) {
|
|
32
|
+
if (err instanceof Error) {
|
|
33
|
+
return err.message;
|
|
34
|
+
}
|
|
35
|
+
return String(err);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAKH,0CAKC;AAKD,kCAMC;AAKD,8CAKC;AA7BD;;GAEG;AACH,SAAgB,eAAe,CAAC,GAAY;IAC1C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,GAAY,EAAE,OAAgB;IACxD,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QAC5C,OAAO,GAAG,OAAO,KAAK,OAAO,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,GAAY;IAC5C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.chunkText = exports.extractPlaceholders = exports.replaceTemplate = exports.formatErrorForLog = exports.formatError = exports.getErrorMessage = void 0;
|
|
4
|
+
var errors_js_1 = require("./errors.js");
|
|
5
|
+
Object.defineProperty(exports, "getErrorMessage", { enumerable: true, get: function () { return errors_js_1.getErrorMessage; } });
|
|
6
|
+
Object.defineProperty(exports, "formatError", { enumerable: true, get: function () { return errors_js_1.formatError; } });
|
|
7
|
+
Object.defineProperty(exports, "formatErrorForLog", { enumerable: true, get: function () { return errors_js_1.formatErrorForLog; } });
|
|
8
|
+
var template_js_1 = require("./template.js");
|
|
9
|
+
Object.defineProperty(exports, "replaceTemplate", { enumerable: true, get: function () { return template_js_1.replaceTemplate; } });
|
|
10
|
+
Object.defineProperty(exports, "extractPlaceholders", { enumerable: true, get: function () { return template_js_1.extractPlaceholders; } });
|
|
11
|
+
var chunkText_js_1 = require("./chunkText.js");
|
|
12
|
+
Object.defineProperty(exports, "chunkText", { enumerable: true, get: function () { return chunkText_js_1.chunkText; } });
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA8E;AAArE,4GAAA,eAAe,OAAA;AAAE,wGAAA,WAAW,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AACxD,6CAAqE;AAA5D,8GAAA,eAAe,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAC7C,+CAA2C;AAAlC,yGAAA,SAAS,OAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple template utility for placeholder replacement.
|
|
3
|
+
* Replaces {{variable}} placeholders with provided values.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Replace template placeholders with values
|
|
7
|
+
*
|
|
8
|
+
* @param template - The template string with {{variable}} placeholders
|
|
9
|
+
* @param values - Object mapping variable names to their values
|
|
10
|
+
* @returns The template with placeholders replaced
|
|
11
|
+
*/
|
|
12
|
+
export declare function replaceTemplate(template: string, values: Record<string, string>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Extract all placeholder names from a template
|
|
15
|
+
*
|
|
16
|
+
* @param template - The template string with {{variable}} placeholders
|
|
17
|
+
* @returns Array of unique placeholder names
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractPlaceholders(template: string): string[];
|
|
20
|
+
//# sourceMappingURL=template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAOR;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAW9D"}
|
package/dist/template.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Simple template utility for placeholder replacement.
|
|
4
|
+
* Replaces {{variable}} placeholders with provided values.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.replaceTemplate = replaceTemplate;
|
|
8
|
+
exports.extractPlaceholders = extractPlaceholders;
|
|
9
|
+
/**
|
|
10
|
+
* Replace template placeholders with values
|
|
11
|
+
*
|
|
12
|
+
* @param template - The template string with {{variable}} placeholders
|
|
13
|
+
* @param values - Object mapping variable names to their values
|
|
14
|
+
* @returns The template with placeholders replaced
|
|
15
|
+
*/
|
|
16
|
+
function replaceTemplate(template, values) {
|
|
17
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
18
|
+
if (Object.prototype.hasOwnProperty.call(values, key)) {
|
|
19
|
+
return values[key] ?? match;
|
|
20
|
+
}
|
|
21
|
+
return match;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Extract all placeholder names from a template
|
|
26
|
+
*
|
|
27
|
+
* @param template - The template string with {{variable}} placeholders
|
|
28
|
+
* @returns Array of unique placeholder names
|
|
29
|
+
*/
|
|
30
|
+
function extractPlaceholders(template) {
|
|
31
|
+
const matches = template.matchAll(/\{\{(\w+)\}\}/g);
|
|
32
|
+
const placeholders = new Set();
|
|
33
|
+
for (const match of matches) {
|
|
34
|
+
if (match[1]) {
|
|
35
|
+
placeholders.add(match[1]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return Array.from(placeholders);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AASH,0CAUC;AAQD,kDAWC;AApCD;;;;;;GAMG;AACH,SAAgB,eAAe,CAC7B,QAAgB,EAChB,MAA8B;IAE9B,OAAO,QAAQ,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE;QAC/D,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;YACtD,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC;QAC9B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,QAAgB;IAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hardlydifficult/text",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"test:coverage": "vitest run --coverage",
|
|
14
|
+
"lint": "tsc --noEmit",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "20.19.31",
|
|
19
|
+
"typescript": "5.8.3",
|
|
20
|
+
"vitest": "1.6.1"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|