altcha-lib 0.5.1 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # ALTCHA JS Library
2
2
 
3
- ALTCHA JS Library is a lightweight, zero-dependency library designed for creating and verifying [ALTCHA](https://altcha.org) challenges specifically tailored for Node.js, Bun, and Deno environments.
3
+ ALTCHA JS Library is a lightweight, zero-dependency library designed for creating and verifying [ALTCHA](https://altcha.org) challenges.
4
4
 
5
5
  ## Compatibility
6
6
 
@@ -9,6 +9,7 @@ This library utilizes [Web Crypto](https://developer.mozilla.org/en-US/docs/Web/
9
9
  - Node.js 16+
10
10
  - Bun 1+
11
11
  - Deno 1+
12
+ - WinterCG-compatible runtimes
12
13
  - All modern browsers
13
14
 
14
15
  ## Usage
@@ -1,9 +1,57 @@
1
1
  import type { Algorithm } from './types.js';
2
2
  export declare const encoder: TextEncoder;
3
+ /**
4
+ * Converts an ArrayBuffer or Uint8Array to a hexadecimal string.
5
+ *
6
+ * @param ab - The ArrayBuffer or Uint8Array to convert.
7
+ * @returns The hexadecimal string representation of the input.
8
+ */
3
9
  export declare function ab2hex(ab: ArrayBuffer | Uint8Array): string;
10
+ /**
11
+ * Generates a cryptographic hash using the specified algorithm.
12
+ *
13
+ * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').
14
+ * @param data - The data to hash, either as a string or ArrayBuffer.
15
+ * @returns A Promise that resolves to the computed hash as an ArrayBuffer.
16
+ */
4
17
  export declare function hash(algorithm: Algorithm, data: ArrayBuffer | string): Promise<ArrayBuffer>;
18
+ /**
19
+ * Generates a cryptographic hash using the specified algorithm and returns it as a hexadecimal string.
20
+ *
21
+ * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').
22
+ * @param data - The data to hash, either as a string or ArrayBuffer.
23
+ * @returns A Promise that resolves to the computed hash as a hexadecimal string.
24
+ */
5
25
  export declare function hashHex(algorithm: Algorithm, data: ArrayBuffer | string): Promise<string>;
26
+ /**
27
+ * Generates an HMAC using the specified algorithm and secret key.
28
+ *
29
+ * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').
30
+ * @param data - The data to sign, either as a string or ArrayBuffer.
31
+ * @param secret - The secret key to use for HMAC.
32
+ * @returns A Promise that resolves to the computed HMAC as an ArrayBuffer.
33
+ */
6
34
  export declare function hmac(algorithm: Algorithm, data: ArrayBuffer | string, secret: string): Promise<ArrayBuffer>;
35
+ /**
36
+ * Generates an HMAC using the specified algorithm and secret key, and returns it as a hexadecimal string.
37
+ *
38
+ * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').
39
+ * @param data - The data to sign, either as a string or ArrayBuffer.
40
+ * @param secret - The secret key to use for HMAC.
41
+ * @returns A Promise that resolves to the computed HMAC as a hexadecimal string.
42
+ */
7
43
  export declare function hmacHex(algorithm: Algorithm, data: ArrayBuffer | string, secret: string): Promise<string>;
44
+ /**
45
+ * Generates a random sequence of bytes of the specified length.
46
+ *
47
+ * @param length - The number of random bytes to generate.
48
+ * @returns A Uint8Array containing the random bytes.
49
+ */
8
50
  export declare function randomBytes(length: number): Uint8Array;
51
+ /**
52
+ * Generates a random integer between 1 and the specified maximum value (inclusive).
53
+ *
54
+ * @param max - The maximum value for the random integer.
55
+ * @returns A random integer between 1 and the specified max value.
56
+ */
9
57
  export declare function randomInt(max: number): number;
@@ -1,21 +1,54 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.randomInt = exports.randomBytes = exports.hmacHex = exports.hmac = exports.hashHex = exports.hash = exports.ab2hex = exports.encoder = void 0;
3
+ exports.encoder = void 0;
4
+ exports.ab2hex = ab2hex;
5
+ exports.hash = hash;
6
+ exports.hashHex = hashHex;
7
+ exports.hmac = hmac;
8
+ exports.hmacHex = hmacHex;
9
+ exports.randomBytes = randomBytes;
10
+ exports.randomInt = randomInt;
11
+ // Create a TextEncoder instance to convert strings to UTF-8 byte arrays.
4
12
  exports.encoder = new TextEncoder();
13
+ /**
14
+ * Converts an ArrayBuffer or Uint8Array to a hexadecimal string.
15
+ *
16
+ * @param ab - The ArrayBuffer or Uint8Array to convert.
17
+ * @returns The hexadecimal string representation of the input.
18
+ */
5
19
  function ab2hex(ab) {
6
20
  return [...new Uint8Array(ab)]
7
21
  .map((x) => x.toString(16).padStart(2, '0'))
8
22
  .join('');
9
23
  }
10
- exports.ab2hex = ab2hex;
24
+ /**
25
+ * Generates a cryptographic hash using the specified algorithm.
26
+ *
27
+ * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').
28
+ * @param data - The data to hash, either as a string or ArrayBuffer.
29
+ * @returns A Promise that resolves to the computed hash as an ArrayBuffer.
30
+ */
11
31
  async function hash(algorithm, data) {
12
32
  return crypto.subtle.digest(algorithm.toUpperCase(), typeof data === 'string' ? exports.encoder.encode(data) : new Uint8Array(data));
13
33
  }
14
- exports.hash = hash;
34
+ /**
35
+ * Generates a cryptographic hash using the specified algorithm and returns it as a hexadecimal string.
36
+ *
37
+ * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').
38
+ * @param data - The data to hash, either as a string or ArrayBuffer.
39
+ * @returns A Promise that resolves to the computed hash as a hexadecimal string.
40
+ */
15
41
  async function hashHex(algorithm, data) {
16
42
  return ab2hex(await hash(algorithm, data));
17
43
  }
18
- exports.hashHex = hashHex;
44
+ /**
45
+ * Generates an HMAC using the specified algorithm and secret key.
46
+ *
47
+ * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').
48
+ * @param data - The data to sign, either as a string or ArrayBuffer.
49
+ * @param secret - The secret key to use for HMAC.
50
+ * @returns A Promise that resolves to the computed HMAC as an ArrayBuffer.
51
+ */
19
52
  async function hmac(algorithm, data, secret) {
20
53
  const key = await crypto.subtle.importKey('raw', exports.encoder.encode(secret), {
21
54
  name: 'HMAC',
@@ -23,21 +56,37 @@ async function hmac(algorithm, data, secret) {
23
56
  }, false, ['sign', 'verify']);
24
57
  return crypto.subtle.sign('HMAC', key, typeof data === 'string' ? exports.encoder.encode(data) : new Uint8Array(data));
25
58
  }
26
- exports.hmac = hmac;
59
+ /**
60
+ * Generates an HMAC using the specified algorithm and secret key, and returns it as a hexadecimal string.
61
+ *
62
+ * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').
63
+ * @param data - The data to sign, either as a string or ArrayBuffer.
64
+ * @param secret - The secret key to use for HMAC.
65
+ * @returns A Promise that resolves to the computed HMAC as a hexadecimal string.
66
+ */
27
67
  async function hmacHex(algorithm, data, secret) {
28
68
  return ab2hex(await hmac(algorithm, data, secret));
29
69
  }
30
- exports.hmacHex = hmacHex;
70
+ /**
71
+ * Generates a random sequence of bytes of the specified length.
72
+ *
73
+ * @param length - The number of random bytes to generate.
74
+ * @returns A Uint8Array containing the random bytes.
75
+ */
31
76
  function randomBytes(length) {
32
77
  const ab = new Uint8Array(length);
33
78
  crypto.getRandomValues(ab);
34
79
  return ab;
35
80
  }
36
- exports.randomBytes = randomBytes;
81
+ /**
82
+ * Generates a random integer between 1 and the specified maximum value (inclusive).
83
+ *
84
+ * @param max - The maximum value for the random integer.
85
+ * @returns A random integer between 1 and the specified max value.
86
+ */
37
87
  function randomInt(max) {
38
88
  const ab = new Uint32Array(1);
39
89
  crypto.getRandomValues(ab);
40
90
  const randomNumber = ab[0] / (0xffffffff + 1);
41
91
  return Math.floor(randomNumber * max + 1);
42
92
  }
43
- exports.randomInt = randomInt;
package/cjs/dist/index.js CHANGED
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.solveChallengeWorkers = exports.solveChallenge = exports.verifyServerSignature = exports.verifyFieldsHash = exports.verifySolution = exports.extractParams = exports.createChallenge = void 0;
3
+ exports.createChallenge = createChallenge;
4
+ exports.extractParams = extractParams;
5
+ exports.verifySolution = verifySolution;
6
+ exports.verifyFieldsHash = verifyFieldsHash;
7
+ exports.verifyServerSignature = verifyServerSignature;
8
+ exports.solveChallenge = solveChallenge;
9
+ exports.solveChallengeWorkers = solveChallengeWorkers;
4
10
  const helpers_js_1 = require("./helpers.js");
5
11
  const DEFAULT_MAX_NUMBER = 1e6;
6
12
  const DEFAULT_SALT_LEN = 12;
@@ -24,7 +30,7 @@ async function createChallenge(options) {
24
30
  if (Object.keys(Object.fromEntries(params)).length) {
25
31
  salt = salt + '?' + params.toString();
26
32
  }
27
- const number = options.number === void 0 ? (0, helpers_js_1.randomInt)(maxnumber) : options.number;
33
+ const number = options.number === undefined ? (0, helpers_js_1.randomInt)(maxnumber) : options.number;
28
34
  const challenge = await (0, helpers_js_1.hashHex)(algorithm, salt + number);
29
35
  return {
30
36
  algorithm,
@@ -34,7 +40,6 @@ async function createChallenge(options) {
34
40
  signature: await (0, helpers_js_1.hmacHex)(algorithm, challenge, options.hmacKey),
35
41
  };
36
42
  }
37
- exports.createChallenge = createChallenge;
38
43
  /**
39
44
  * Extracts parameters from the payload.
40
45
  *
@@ -47,7 +52,6 @@ function extractParams(payload) {
47
52
  }
48
53
  return Object.fromEntries(new URLSearchParams(payload?.salt?.split('?')?.[1] || ''));
49
54
  }
50
- exports.extractParams = extractParams;
51
55
  /**
52
56
  * Verifies the solution provided by the client.
53
57
  *
@@ -66,10 +70,13 @@ async function verifySolution(payload, hmacKey, checkExpires = true) {
66
70
  }
67
71
  }
68
72
  const params = extractParams(payload);
69
- const expires = params.expires || params.expire;
70
- if (checkExpires && expires) {
73
+ if (checkExpires) {
74
+ const expires = params.expires || params.expire;
75
+ if (!expires) {
76
+ return false;
77
+ }
71
78
  const date = new Date(parseInt(expires, 10) * 1000);
72
- if (!isNaN(date.getTime()) && date.getTime() < Date.now()) {
79
+ if (Number.isNaN(date.getTime()) || date.getTime() < Date.now()) {
73
80
  return false;
74
81
  }
75
82
  }
@@ -82,7 +89,6 @@ async function verifySolution(payload, hmacKey, checkExpires = true) {
82
89
  return (check.challenge === payload.challenge &&
83
90
  check.signature === payload.signature);
84
91
  }
85
- exports.verifySolution = verifySolution;
86
92
  /**
87
93
  * Verifies the hash of form fields.
88
94
  *
@@ -100,7 +106,6 @@ async function verifyFieldsHash(formData, fields, fieldsHash, algorithm = DEFAUL
100
106
  }
101
107
  return (await (0, helpers_js_1.hashHex)(algorithm, lines.join('\n'))) === fieldsHash;
102
108
  }
103
- exports.verifyFieldsHash = verifyFieldsHash;
104
109
  /**
105
110
  * Verifies the server's signature.
106
111
  *
@@ -131,7 +136,7 @@ async function verifyServerSignature(payload, hmacKey) {
131
136
  reasons: params.get('reasons')?.split(','),
132
137
  score: params.get('score')
133
138
  ? parseFloat(params.get('score') || '0')
134
- : void 0,
139
+ : undefined,
135
140
  time: parseInt(params.get('time') || '0', 10),
136
141
  verified: params.get('verified') === 'true',
137
142
  };
@@ -147,7 +152,6 @@ async function verifyServerSignature(payload, hmacKey) {
147
152
  payload.signature === signature,
148
153
  };
149
154
  }
150
- exports.verifyServerSignature = verifyServerSignature;
151
155
  /**
152
156
  * Solves a challenge by brute force.
153
157
  *
@@ -181,7 +185,6 @@ function solveChallenge(challenge, salt, algorithm = 'SHA-256', max = 1e6, start
181
185
  controller,
182
186
  };
183
187
  }
184
- exports.solveChallenge = solveChallenge;
185
188
  /**
186
189
  * Solves a challenge using web workers for parallel computation.
187
190
  *
@@ -238,7 +241,6 @@ async function solveChallengeWorkers(workerScript, concurrency, challenge, salt,
238
241
  }
239
242
  return solutions.find((solution) => !!solution) || null;
240
243
  }
241
- exports.solveChallengeWorkers = solveChallengeWorkers;
242
244
  exports.default = {
243
245
  createChallenge,
244
246
  extractParams,
package/dist/helpers.d.ts CHANGED
@@ -1,9 +1,57 @@
1
1
  import type { Algorithm } from './types.js';
2
2
  export declare const encoder: TextEncoder;
3
+ /**
4
+ * Converts an ArrayBuffer or Uint8Array to a hexadecimal string.
5
+ *
6
+ * @param ab - The ArrayBuffer or Uint8Array to convert.
7
+ * @returns The hexadecimal string representation of the input.
8
+ */
3
9
  export declare function ab2hex(ab: ArrayBuffer | Uint8Array): string;
10
+ /**
11
+ * Generates a cryptographic hash using the specified algorithm.
12
+ *
13
+ * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').
14
+ * @param data - The data to hash, either as a string or ArrayBuffer.
15
+ * @returns A Promise that resolves to the computed hash as an ArrayBuffer.
16
+ */
4
17
  export declare function hash(algorithm: Algorithm, data: ArrayBuffer | string): Promise<ArrayBuffer>;
18
+ /**
19
+ * Generates a cryptographic hash using the specified algorithm and returns it as a hexadecimal string.
20
+ *
21
+ * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').
22
+ * @param data - The data to hash, either as a string or ArrayBuffer.
23
+ * @returns A Promise that resolves to the computed hash as a hexadecimal string.
24
+ */
5
25
  export declare function hashHex(algorithm: Algorithm, data: ArrayBuffer | string): Promise<string>;
26
+ /**
27
+ * Generates an HMAC using the specified algorithm and secret key.
28
+ *
29
+ * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').
30
+ * @param data - The data to sign, either as a string or ArrayBuffer.
31
+ * @param secret - The secret key to use for HMAC.
32
+ * @returns A Promise that resolves to the computed HMAC as an ArrayBuffer.
33
+ */
6
34
  export declare function hmac(algorithm: Algorithm, data: ArrayBuffer | string, secret: string): Promise<ArrayBuffer>;
35
+ /**
36
+ * Generates an HMAC using the specified algorithm and secret key, and returns it as a hexadecimal string.
37
+ *
38
+ * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').
39
+ * @param data - The data to sign, either as a string or ArrayBuffer.
40
+ * @param secret - The secret key to use for HMAC.
41
+ * @returns A Promise that resolves to the computed HMAC as a hexadecimal string.
42
+ */
7
43
  export declare function hmacHex(algorithm: Algorithm, data: ArrayBuffer | string, secret: string): Promise<string>;
44
+ /**
45
+ * Generates a random sequence of bytes of the specified length.
46
+ *
47
+ * @param length - The number of random bytes to generate.
48
+ * @returns A Uint8Array containing the random bytes.
49
+ */
8
50
  export declare function randomBytes(length: number): Uint8Array;
51
+ /**
52
+ * Generates a random integer between 1 and the specified maximum value (inclusive).
53
+ *
54
+ * @param max - The maximum value for the random integer.
55
+ * @returns A random integer between 1 and the specified max value.
56
+ */
9
57
  export declare function randomInt(max: number): number;
package/dist/helpers.js CHANGED
@@ -1,15 +1,44 @@
1
+ // Create a TextEncoder instance to convert strings to UTF-8 byte arrays.
1
2
  export const encoder = new TextEncoder();
3
+ /**
4
+ * Converts an ArrayBuffer or Uint8Array to a hexadecimal string.
5
+ *
6
+ * @param ab - The ArrayBuffer or Uint8Array to convert.
7
+ * @returns The hexadecimal string representation of the input.
8
+ */
2
9
  export function ab2hex(ab) {
3
10
  return [...new Uint8Array(ab)]
4
11
  .map((x) => x.toString(16).padStart(2, '0'))
5
12
  .join('');
6
13
  }
14
+ /**
15
+ * Generates a cryptographic hash using the specified algorithm.
16
+ *
17
+ * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').
18
+ * @param data - The data to hash, either as a string or ArrayBuffer.
19
+ * @returns A Promise that resolves to the computed hash as an ArrayBuffer.
20
+ */
7
21
  export async function hash(algorithm, data) {
8
22
  return crypto.subtle.digest(algorithm.toUpperCase(), typeof data === 'string' ? encoder.encode(data) : new Uint8Array(data));
9
23
  }
24
+ /**
25
+ * Generates a cryptographic hash using the specified algorithm and returns it as a hexadecimal string.
26
+ *
27
+ * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').
28
+ * @param data - The data to hash, either as a string or ArrayBuffer.
29
+ * @returns A Promise that resolves to the computed hash as a hexadecimal string.
30
+ */
10
31
  export async function hashHex(algorithm, data) {
11
32
  return ab2hex(await hash(algorithm, data));
12
33
  }
34
+ /**
35
+ * Generates an HMAC using the specified algorithm and secret key.
36
+ *
37
+ * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').
38
+ * @param data - The data to sign, either as a string or ArrayBuffer.
39
+ * @param secret - The secret key to use for HMAC.
40
+ * @returns A Promise that resolves to the computed HMAC as an ArrayBuffer.
41
+ */
13
42
  export async function hmac(algorithm, data, secret) {
14
43
  const key = await crypto.subtle.importKey('raw', encoder.encode(secret), {
15
44
  name: 'HMAC',
@@ -17,14 +46,34 @@ export async function hmac(algorithm, data, secret) {
17
46
  }, false, ['sign', 'verify']);
18
47
  return crypto.subtle.sign('HMAC', key, typeof data === 'string' ? encoder.encode(data) : new Uint8Array(data));
19
48
  }
49
+ /**
50
+ * Generates an HMAC using the specified algorithm and secret key, and returns it as a hexadecimal string.
51
+ *
52
+ * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').
53
+ * @param data - The data to sign, either as a string or ArrayBuffer.
54
+ * @param secret - The secret key to use for HMAC.
55
+ * @returns A Promise that resolves to the computed HMAC as a hexadecimal string.
56
+ */
20
57
  export async function hmacHex(algorithm, data, secret) {
21
58
  return ab2hex(await hmac(algorithm, data, secret));
22
59
  }
60
+ /**
61
+ * Generates a random sequence of bytes of the specified length.
62
+ *
63
+ * @param length - The number of random bytes to generate.
64
+ * @returns A Uint8Array containing the random bytes.
65
+ */
23
66
  export function randomBytes(length) {
24
67
  const ab = new Uint8Array(length);
25
68
  crypto.getRandomValues(ab);
26
69
  return ab;
27
70
  }
71
+ /**
72
+ * Generates a random integer between 1 and the specified maximum value (inclusive).
73
+ *
74
+ * @param max - The maximum value for the random integer.
75
+ * @returns A random integer between 1 and the specified max value.
76
+ */
28
77
  export function randomInt(max) {
29
78
  const ab = new Uint32Array(1);
30
79
  crypto.getRandomValues(ab);
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ export async function createChallenge(options) {
21
21
  if (Object.keys(Object.fromEntries(params)).length) {
22
22
  salt = salt + '?' + params.toString();
23
23
  }
24
- const number = options.number === void 0 ? randomInt(maxnumber) : options.number;
24
+ const number = options.number === undefined ? randomInt(maxnumber) : options.number;
25
25
  const challenge = await hashHex(algorithm, salt + number);
26
26
  return {
27
27
  algorithm,
@@ -61,10 +61,13 @@ export async function verifySolution(payload, hmacKey, checkExpires = true) {
61
61
  }
62
62
  }
63
63
  const params = extractParams(payload);
64
- const expires = params.expires || params.expire;
65
- if (checkExpires && expires) {
64
+ if (checkExpires) {
65
+ const expires = params.expires || params.expire;
66
+ if (!expires) {
67
+ return false;
68
+ }
66
69
  const date = new Date(parseInt(expires, 10) * 1000);
67
- if (!isNaN(date.getTime()) && date.getTime() < Date.now()) {
70
+ if (Number.isNaN(date.getTime()) || date.getTime() < Date.now()) {
68
71
  return false;
69
72
  }
70
73
  }
@@ -124,7 +127,7 @@ export async function verifyServerSignature(payload, hmacKey) {
124
127
  reasons: params.get('reasons')?.split(','),
125
128
  score: params.get('score')
126
129
  ? parseFloat(params.get('score') || '0')
127
- : void 0,
130
+ : undefined,
128
131
  time: parseInt(params.get('time') || '0', 10),
129
132
  verified: params.get('verified') === 'true',
130
133
  };
package/package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "name": "altcha-lib",
3
- "version": "0.5.1",
3
+ "version": "1.0.0",
4
4
  "description": "A library for creating and verifying ALTCHA challenges for Node.js, Bun and Deno.",
5
- "author": "Daniel Regeci",
5
+ "author": {
6
+ "name": "Daniel Regeci",
7
+ "url": "https://altcha.org"
8
+ },
9
+ "homepage": "https://altcha.org",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/altcha-org/altcha-lib"
13
+ },
6
14
  "license": "MIT",
7
15
  "keywords": [
8
16
  "altcha",
@@ -53,16 +61,16 @@
53
61
  }
54
62
  },
55
63
  "devDependencies": {
56
- "@types/node": "^20.9.0",
57
- "@typescript-eslint/eslint-plugin": "^6.21.0",
58
- "denoify": "^1.6.9",
59
- "eslint": "^8.56.0",
60
- "husky": "^9.0.11",
61
- "prettier": "^3.2.5",
62
- "rimraf": "^5.0.5",
63
- "ts-node": "^10.9.1",
64
- "tsx": "^4.0.0",
65
- "typescript": "^5.2.2",
66
- "vitest": "^1.0.1"
64
+ "@types/node": "^20.16.3",
65
+ "@typescript-eslint/eslint-plugin": "^8.4.0",
66
+ "denoify": "^1.6.13",
67
+ "eslint": "^8.57.0",
68
+ "husky": "^9.1.5",
69
+ "prettier": "^3.3.3",
70
+ "rimraf": "^5.0.10",
71
+ "ts-node": "^10.9.2",
72
+ "tsx": "^4.19.0",
73
+ "typescript": "^5.5.4",
74
+ "vitest": "^1.6.0"
67
75
  }
68
76
  }