├── .editorconfig
├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── .prettierrc
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── logo.png
├── package-lock.json
├── package.json
├── rollup.config.js
├── source
├── cli.ts
├── constants.ts
├── crockford.ts
├── error.ts
├── index.ts
├── stub.ts
├── types.ts
├── ulid.ts
├── utils.ts
└── uuid.ts
├── test
├── benchmark.js
└── node
│ ├── crockford.spec.ts
│ ├── ulid.spec.ts
│ └── uuid.spec.ts
├── tsconfig.dec.json
├── tsconfig.json
└── vitest.config.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | branches:
9 | - master
10 |
11 | jobs:
12 | nodejs:
13 | runs-on: ubuntu-latest
14 | strategy:
15 | matrix:
16 | node-version: [18.x, 22.x]
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Node.js specs ${{ matrix.node-version }}
20 | uses: actions/setup-node@v1
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | - run: npm i
24 | - run: npm run build
25 | - run: npm run test:specs
26 | format:
27 | runs-on: ubuntu-latest
28 | strategy:
29 | matrix:
30 | node-version: [22.x]
31 | steps:
32 | - uses: actions/checkout@v2
33 | - name: Type checks ${{ matrix.node-version }}
34 | uses: actions/setup-node@v1
35 | with:
36 | node-version: ${{ matrix.node-version }}
37 | - run: npm i
38 | - run: npm run test:format
39 | types:
40 | runs-on: ubuntu-latest
41 | strategy:
42 | matrix:
43 | node-version: [22.x]
44 | steps:
45 | - uses: actions/checkout@v2
46 | - name: Type checks ${{ matrix.node-version }}
47 | uses: actions/setup-node@v1
48 | with:
49 | node-version: ${{ matrix.node-version }}
50 | - run: npm i
51 | - run: npm run build
52 | - run: npm run test:types
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.log
3 |
4 | node_modules
5 | /dist
6 | coverage
7 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 100,
3 | "tabWidth": 4,
4 | "trailingComma": "none",
5 | "arrowParens": "avoid"
6 | }
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.preferences.importModuleSpecifierEnding": "js"
3 | }
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Alizain Feerasta
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | # Universally Unique Lexicographically Sortable Identifier
11 |
12 | [](https://github.com/ulid/javascript/actions/workflows/test.yml)
13 | [](https://codecov.io/gh/ulid/javascript)
14 | [](https://www.npmjs.com/package/ulid) [](https://www.npmjs.com/package/ulid)
15 |
16 | ULIDs are unique, sortable identifiers that work much in the same way as UUIDs, though with some improvements:
17 |
18 | * Lexicographically sortable
19 | * Canonically encoded as a 26 character string, as opposed to the 36 character UUID
20 | * Uses Crockford's base32 for better efficiency and readability (5 bits per character)
21 | * Monotonic sort order (correctly detects and handles the same millisecond)
22 |
23 | ULIDs also provide:
24 |
25 | * 128-bit compatibility with UUID
26 | * 1.21e+24 unique IDs per millisecond
27 | * Case insensitivity
28 | * No special characters (URL safe)
29 |
30 | UUID can be suboptimal for many uses-cases because:
31 |
32 | - It isn't the most character efficient way of encoding 128 bits of randomness
33 | - UUID v1/v2 is impractical in many environments, as it requires access to a unique, stable MAC address
34 | - UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures
35 | - UUID v4 provides no other information than randomness which can cause fragmentation in many data structures
36 |
37 | ## Installation
38 |
39 | Install using NPM:
40 |
41 | ```shell
42 | npm install ulid --save
43 | ```
44 |
45 | ### Compatibility
46 |
47 | ULID supports the following environments:
48 |
49 | | Version | NodeJS | Browsers | React-Native | Web Workers | Edge Functions |
50 | |-----------|-----------|---------------|---------------|---------------|-------------------|
51 | | v3 | v18+ | Yes | Yes | Yes | ? |
52 | | v2 | v16+ | Yes | No | No | No |
53 |
54 | Additionally, both ESM and CommonJS entrypoints are provided.
55 |
56 | ## Usage
57 |
58 | To quickly generate a ULID, you can simply import the `ulid` function:
59 |
60 | ```typescript
61 | import { ulid } from "ulid";
62 |
63 | ulid(); // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
64 | ```
65 |
66 | ### Seed Time
67 |
68 | You can also input a seed time which will consistently give you the same string for the time component. This is useful for migrating to ulid.
69 |
70 | ```typescript
71 | ulid(1469918176385) // "01ARYZ6S41TSV4RRFFQ69G5FAV"
72 | ```
73 |
74 | ### Monotonic ULIDs
75 |
76 | To generate monotonically increasing ULIDs, create a monotonic counter with `monotonicFactory`.
77 |
78 | > Note that the same seed time is being passed in for this example to demonstrate its behaviour when generating multiple ULIDs within the same millisecond
79 |
80 | ```typescript
81 | import { monotonicFactory } from "ulid";
82 |
83 | const ulid = monotonicFactory();
84 |
85 | // Strict ordering for the same timestamp, by incrementing the least-significant random bit by 1
86 | ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVR8"
87 | ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVR9"
88 | ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVRA"
89 | ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVRB"
90 | ulid(150000); // "000XAL6S41ACTAV9WEVGEMMVRC"
91 |
92 | // Even if a lower timestamp is passed (or generated), it will preserve sort order
93 | ulid(100000); // "000XAL6S41ACTAV9WEVGEMMVRD"
94 | ```
95 |
96 | ### Pseudo-Random Number Generators
97 |
98 | `ulid` automatically detects a suitable (cryptographically-secure) PRNG. In the browser it will use `crypto.getRandomValues` and on NodeJS it will use `crypto.randomBytes`.
99 |
100 | #### Using `Math.random` (insecure)
101 |
102 | By default, `ulid` will not use `Math.random` to generate random values. You can bypass this limitation by overriding the PRNG:
103 |
104 | ```typescript
105 | const ulid = monotonicFactory(() => Math.random());
106 |
107 | ulid(); // "01BXAVRG61YJ5YSBRM51702F6M"
108 | ```
109 |
110 | ### Validity
111 |
112 | You can verify if a value is a valid ULID by using `isValid`:
113 |
114 | ```typescript
115 | import { isValid } from "ulid";
116 |
117 | isValid("01ARYZ6S41TSV4RRFFQ69G5FAV"); // true
118 | isValid("01ARYZ6S41TSV4RRFFQ69G5FA"); // false
119 | ```
120 |
121 | ### ULID Time
122 |
123 | You can encode and decode ULID timestamps by using `encodeTime` and `decodeTime` respectively:
124 |
125 | ```typescript
126 | import { decodeTime } from "ulid";
127 |
128 | decodeTime("01ARYZ6S41TSV4RRFFQ69G5FAV"); // 1469918176385
129 | ```
130 |
131 | Note that while `decodeTime` works on full ULIDs, `encodeTime` encodes only the _time portion_ of ULIDs:
132 |
133 | ```typescript
134 | import { encodeTime } from "ulid";
135 |
136 | encodeTime(1469918176385); // "01ARYZ6S41"
137 | ```
138 |
139 | ### Tests
140 |
141 | Install dependencies using `npm install` first, and then simply run `npm test` to run the test suite.
142 |
143 | ### CLI
144 |
145 | `ulid` can be used on the command line, either via global install:
146 |
147 | ```shell
148 | npm install -g ulid
149 | ulid
150 | ```
151 |
152 | Or via `npx`:
153 |
154 | ```shell
155 | npx ulid
156 | ```
157 |
158 | You can also generate multiple IDs at the same time:
159 |
160 | ```shell
161 | ulid --count 15
162 | ```
163 |
164 | ## Specification
165 |
166 | You can find the full specification, as well as information regarding implementations in other languages, over at [ulid/spec](https://github.com/ulid/spec).
167 |
168 | ## Performance
169 |
170 | You can test `ulid`'s performance by running `npm run bench`:
171 |
172 | ```
173 | Simple ulid x 56,782 ops/sec ±2.50% (86 runs sampled)
174 | ulid with timestamp x 58,574 ops/sec ±1.80% (87 runs sampled)
175 | Done!
176 | ```
177 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ulid/javascript/09c28abcf1d6f94917bd8fb239a357a726d78997/logo.png
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ulid",
3 | "version": "3.0.1",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "ulid",
9 | "version": "3.0.1",
10 | "license": "MIT",
11 | "bin": {
12 | "ulid": "dist/cli.js"
13 | },
14 | "devDependencies": {
15 | "@rollup/plugin-alias": "^5.1.1",
16 | "@rollup/plugin-commonjs": "^28.0.3",
17 | "@rollup/plugin-node-resolve": "^16.0.1",
18 | "@rollup/plugin-typescript": "^12.1.2",
19 | "@types/node": "^22.15.30",
20 | "benchmark": "^2.1.4",
21 | "prettier": "^3.5.3",
22 | "rollup": "^4.42.0",
23 | "tslib": "^2.8.1",
24 | "typescript": "^5.8.3",
25 | "vitest": "^3.2.2"
26 | }
27 | },
28 | "node_modules/@esbuild/aix-ppc64": {
29 | "version": "0.25.5",
30 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
31 | "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
32 | "cpu": [
33 | "ppc64"
34 | ],
35 | "dev": true,
36 | "license": "MIT",
37 | "optional": true,
38 | "os": [
39 | "aix"
40 | ],
41 | "engines": {
42 | "node": ">=18"
43 | }
44 | },
45 | "node_modules/@esbuild/android-arm": {
46 | "version": "0.25.5",
47 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
48 | "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
49 | "cpu": [
50 | "arm"
51 | ],
52 | "dev": true,
53 | "license": "MIT",
54 | "optional": true,
55 | "os": [
56 | "android"
57 | ],
58 | "engines": {
59 | "node": ">=18"
60 | }
61 | },
62 | "node_modules/@esbuild/android-arm64": {
63 | "version": "0.25.5",
64 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
65 | "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
66 | "cpu": [
67 | "arm64"
68 | ],
69 | "dev": true,
70 | "license": "MIT",
71 | "optional": true,
72 | "os": [
73 | "android"
74 | ],
75 | "engines": {
76 | "node": ">=18"
77 | }
78 | },
79 | "node_modules/@esbuild/android-x64": {
80 | "version": "0.25.5",
81 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
82 | "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
83 | "cpu": [
84 | "x64"
85 | ],
86 | "dev": true,
87 | "license": "MIT",
88 | "optional": true,
89 | "os": [
90 | "android"
91 | ],
92 | "engines": {
93 | "node": ">=18"
94 | }
95 | },
96 | "node_modules/@esbuild/darwin-arm64": {
97 | "version": "0.25.5",
98 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
99 | "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
100 | "cpu": [
101 | "arm64"
102 | ],
103 | "dev": true,
104 | "license": "MIT",
105 | "optional": true,
106 | "os": [
107 | "darwin"
108 | ],
109 | "engines": {
110 | "node": ">=18"
111 | }
112 | },
113 | "node_modules/@esbuild/darwin-x64": {
114 | "version": "0.25.5",
115 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
116 | "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
117 | "cpu": [
118 | "x64"
119 | ],
120 | "dev": true,
121 | "license": "MIT",
122 | "optional": true,
123 | "os": [
124 | "darwin"
125 | ],
126 | "engines": {
127 | "node": ">=18"
128 | }
129 | },
130 | "node_modules/@esbuild/freebsd-arm64": {
131 | "version": "0.25.5",
132 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
133 | "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
134 | "cpu": [
135 | "arm64"
136 | ],
137 | "dev": true,
138 | "license": "MIT",
139 | "optional": true,
140 | "os": [
141 | "freebsd"
142 | ],
143 | "engines": {
144 | "node": ">=18"
145 | }
146 | },
147 | "node_modules/@esbuild/freebsd-x64": {
148 | "version": "0.25.5",
149 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
150 | "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
151 | "cpu": [
152 | "x64"
153 | ],
154 | "dev": true,
155 | "license": "MIT",
156 | "optional": true,
157 | "os": [
158 | "freebsd"
159 | ],
160 | "engines": {
161 | "node": ">=18"
162 | }
163 | },
164 | "node_modules/@esbuild/linux-arm": {
165 | "version": "0.25.5",
166 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
167 | "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
168 | "cpu": [
169 | "arm"
170 | ],
171 | "dev": true,
172 | "license": "MIT",
173 | "optional": true,
174 | "os": [
175 | "linux"
176 | ],
177 | "engines": {
178 | "node": ">=18"
179 | }
180 | },
181 | "node_modules/@esbuild/linux-arm64": {
182 | "version": "0.25.5",
183 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
184 | "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
185 | "cpu": [
186 | "arm64"
187 | ],
188 | "dev": true,
189 | "license": "MIT",
190 | "optional": true,
191 | "os": [
192 | "linux"
193 | ],
194 | "engines": {
195 | "node": ">=18"
196 | }
197 | },
198 | "node_modules/@esbuild/linux-ia32": {
199 | "version": "0.25.5",
200 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
201 | "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
202 | "cpu": [
203 | "ia32"
204 | ],
205 | "dev": true,
206 | "license": "MIT",
207 | "optional": true,
208 | "os": [
209 | "linux"
210 | ],
211 | "engines": {
212 | "node": ">=18"
213 | }
214 | },
215 | "node_modules/@esbuild/linux-loong64": {
216 | "version": "0.25.5",
217 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
218 | "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
219 | "cpu": [
220 | "loong64"
221 | ],
222 | "dev": true,
223 | "license": "MIT",
224 | "optional": true,
225 | "os": [
226 | "linux"
227 | ],
228 | "engines": {
229 | "node": ">=18"
230 | }
231 | },
232 | "node_modules/@esbuild/linux-mips64el": {
233 | "version": "0.25.5",
234 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
235 | "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
236 | "cpu": [
237 | "mips64el"
238 | ],
239 | "dev": true,
240 | "license": "MIT",
241 | "optional": true,
242 | "os": [
243 | "linux"
244 | ],
245 | "engines": {
246 | "node": ">=18"
247 | }
248 | },
249 | "node_modules/@esbuild/linux-ppc64": {
250 | "version": "0.25.5",
251 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
252 | "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
253 | "cpu": [
254 | "ppc64"
255 | ],
256 | "dev": true,
257 | "license": "MIT",
258 | "optional": true,
259 | "os": [
260 | "linux"
261 | ],
262 | "engines": {
263 | "node": ">=18"
264 | }
265 | },
266 | "node_modules/@esbuild/linux-riscv64": {
267 | "version": "0.25.5",
268 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
269 | "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
270 | "cpu": [
271 | "riscv64"
272 | ],
273 | "dev": true,
274 | "license": "MIT",
275 | "optional": true,
276 | "os": [
277 | "linux"
278 | ],
279 | "engines": {
280 | "node": ">=18"
281 | }
282 | },
283 | "node_modules/@esbuild/linux-s390x": {
284 | "version": "0.25.5",
285 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
286 | "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
287 | "cpu": [
288 | "s390x"
289 | ],
290 | "dev": true,
291 | "license": "MIT",
292 | "optional": true,
293 | "os": [
294 | "linux"
295 | ],
296 | "engines": {
297 | "node": ">=18"
298 | }
299 | },
300 | "node_modules/@esbuild/linux-x64": {
301 | "version": "0.25.5",
302 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
303 | "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
304 | "cpu": [
305 | "x64"
306 | ],
307 | "dev": true,
308 | "license": "MIT",
309 | "optional": true,
310 | "os": [
311 | "linux"
312 | ],
313 | "engines": {
314 | "node": ">=18"
315 | }
316 | },
317 | "node_modules/@esbuild/netbsd-arm64": {
318 | "version": "0.25.5",
319 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
320 | "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
321 | "cpu": [
322 | "arm64"
323 | ],
324 | "dev": true,
325 | "license": "MIT",
326 | "optional": true,
327 | "os": [
328 | "netbsd"
329 | ],
330 | "engines": {
331 | "node": ">=18"
332 | }
333 | },
334 | "node_modules/@esbuild/netbsd-x64": {
335 | "version": "0.25.5",
336 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
337 | "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
338 | "cpu": [
339 | "x64"
340 | ],
341 | "dev": true,
342 | "license": "MIT",
343 | "optional": true,
344 | "os": [
345 | "netbsd"
346 | ],
347 | "engines": {
348 | "node": ">=18"
349 | }
350 | },
351 | "node_modules/@esbuild/openbsd-arm64": {
352 | "version": "0.25.5",
353 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
354 | "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
355 | "cpu": [
356 | "arm64"
357 | ],
358 | "dev": true,
359 | "license": "MIT",
360 | "optional": true,
361 | "os": [
362 | "openbsd"
363 | ],
364 | "engines": {
365 | "node": ">=18"
366 | }
367 | },
368 | "node_modules/@esbuild/openbsd-x64": {
369 | "version": "0.25.5",
370 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
371 | "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
372 | "cpu": [
373 | "x64"
374 | ],
375 | "dev": true,
376 | "license": "MIT",
377 | "optional": true,
378 | "os": [
379 | "openbsd"
380 | ],
381 | "engines": {
382 | "node": ">=18"
383 | }
384 | },
385 | "node_modules/@esbuild/sunos-x64": {
386 | "version": "0.25.5",
387 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
388 | "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
389 | "cpu": [
390 | "x64"
391 | ],
392 | "dev": true,
393 | "license": "MIT",
394 | "optional": true,
395 | "os": [
396 | "sunos"
397 | ],
398 | "engines": {
399 | "node": ">=18"
400 | }
401 | },
402 | "node_modules/@esbuild/win32-arm64": {
403 | "version": "0.25.5",
404 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
405 | "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
406 | "cpu": [
407 | "arm64"
408 | ],
409 | "dev": true,
410 | "license": "MIT",
411 | "optional": true,
412 | "os": [
413 | "win32"
414 | ],
415 | "engines": {
416 | "node": ">=18"
417 | }
418 | },
419 | "node_modules/@esbuild/win32-ia32": {
420 | "version": "0.25.5",
421 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
422 | "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
423 | "cpu": [
424 | "ia32"
425 | ],
426 | "dev": true,
427 | "license": "MIT",
428 | "optional": true,
429 | "os": [
430 | "win32"
431 | ],
432 | "engines": {
433 | "node": ">=18"
434 | }
435 | },
436 | "node_modules/@esbuild/win32-x64": {
437 | "version": "0.25.5",
438 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
439 | "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
440 | "cpu": [
441 | "x64"
442 | ],
443 | "dev": true,
444 | "license": "MIT",
445 | "optional": true,
446 | "os": [
447 | "win32"
448 | ],
449 | "engines": {
450 | "node": ">=18"
451 | }
452 | },
453 | "node_modules/@jridgewell/sourcemap-codec": {
454 | "version": "1.5.0",
455 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
456 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
457 | "dev": true,
458 | "license": "MIT"
459 | },
460 | "node_modules/@rollup/plugin-alias": {
461 | "version": "5.1.1",
462 | "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz",
463 | "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==",
464 | "dev": true,
465 | "license": "MIT",
466 | "engines": {
467 | "node": ">=14.0.0"
468 | },
469 | "peerDependencies": {
470 | "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
471 | },
472 | "peerDependenciesMeta": {
473 | "rollup": {
474 | "optional": true
475 | }
476 | }
477 | },
478 | "node_modules/@rollup/plugin-commonjs": {
479 | "version": "28.0.3",
480 | "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.3.tgz",
481 | "integrity": "sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==",
482 | "dev": true,
483 | "license": "MIT",
484 | "dependencies": {
485 | "@rollup/pluginutils": "^5.0.1",
486 | "commondir": "^1.0.1",
487 | "estree-walker": "^2.0.2",
488 | "fdir": "^6.2.0",
489 | "is-reference": "1.2.1",
490 | "magic-string": "^0.30.3",
491 | "picomatch": "^4.0.2"
492 | },
493 | "engines": {
494 | "node": ">=16.0.0 || 14 >= 14.17"
495 | },
496 | "peerDependencies": {
497 | "rollup": "^2.68.0||^3.0.0||^4.0.0"
498 | },
499 | "peerDependenciesMeta": {
500 | "rollup": {
501 | "optional": true
502 | }
503 | }
504 | },
505 | "node_modules/@rollup/plugin-node-resolve": {
506 | "version": "16.0.1",
507 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz",
508 | "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==",
509 | "dev": true,
510 | "license": "MIT",
511 | "dependencies": {
512 | "@rollup/pluginutils": "^5.0.1",
513 | "@types/resolve": "1.20.2",
514 | "deepmerge": "^4.2.2",
515 | "is-module": "^1.0.0",
516 | "resolve": "^1.22.1"
517 | },
518 | "engines": {
519 | "node": ">=14.0.0"
520 | },
521 | "peerDependencies": {
522 | "rollup": "^2.78.0||^3.0.0||^4.0.0"
523 | },
524 | "peerDependenciesMeta": {
525 | "rollup": {
526 | "optional": true
527 | }
528 | }
529 | },
530 | "node_modules/@rollup/plugin-typescript": {
531 | "version": "12.1.2",
532 | "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.1.2.tgz",
533 | "integrity": "sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg==",
534 | "dev": true,
535 | "license": "MIT",
536 | "dependencies": {
537 | "@rollup/pluginutils": "^5.1.0",
538 | "resolve": "^1.22.1"
539 | },
540 | "engines": {
541 | "node": ">=14.0.0"
542 | },
543 | "peerDependencies": {
544 | "rollup": "^2.14.0||^3.0.0||^4.0.0",
545 | "tslib": "*",
546 | "typescript": ">=3.7.0"
547 | },
548 | "peerDependenciesMeta": {
549 | "rollup": {
550 | "optional": true
551 | },
552 | "tslib": {
553 | "optional": true
554 | }
555 | }
556 | },
557 | "node_modules/@rollup/pluginutils": {
558 | "version": "5.1.4",
559 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
560 | "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
561 | "dev": true,
562 | "license": "MIT",
563 | "dependencies": {
564 | "@types/estree": "^1.0.0",
565 | "estree-walker": "^2.0.2",
566 | "picomatch": "^4.0.2"
567 | },
568 | "engines": {
569 | "node": ">=14.0.0"
570 | },
571 | "peerDependencies": {
572 | "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
573 | },
574 | "peerDependenciesMeta": {
575 | "rollup": {
576 | "optional": true
577 | }
578 | }
579 | },
580 | "node_modules/@rollup/rollup-android-arm-eabi": {
581 | "version": "4.42.0",
582 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.42.0.tgz",
583 | "integrity": "sha512-gldmAyS9hpj+H6LpRNlcjQWbuKUtb94lodB9uCz71Jm+7BxK1VIOo7y62tZZwxhA7j1ylv/yQz080L5WkS+LoQ==",
584 | "cpu": [
585 | "arm"
586 | ],
587 | "dev": true,
588 | "license": "MIT",
589 | "optional": true,
590 | "os": [
591 | "android"
592 | ]
593 | },
594 | "node_modules/@rollup/rollup-android-arm64": {
595 | "version": "4.42.0",
596 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.42.0.tgz",
597 | "integrity": "sha512-bpRipfTgmGFdCZDFLRvIkSNO1/3RGS74aWkJJTFJBH7h3MRV4UijkaEUeOMbi9wxtxYmtAbVcnMtHTPBhLEkaw==",
598 | "cpu": [
599 | "arm64"
600 | ],
601 | "dev": true,
602 | "license": "MIT",
603 | "optional": true,
604 | "os": [
605 | "android"
606 | ]
607 | },
608 | "node_modules/@rollup/rollup-darwin-arm64": {
609 | "version": "4.42.0",
610 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.42.0.tgz",
611 | "integrity": "sha512-JxHtA081izPBVCHLKnl6GEA0w3920mlJPLh89NojpU2GsBSB6ypu4erFg/Wx1qbpUbepn0jY4dVWMGZM8gplgA==",
612 | "cpu": [
613 | "arm64"
614 | ],
615 | "dev": true,
616 | "license": "MIT",
617 | "optional": true,
618 | "os": [
619 | "darwin"
620 | ]
621 | },
622 | "node_modules/@rollup/rollup-darwin-x64": {
623 | "version": "4.42.0",
624 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.42.0.tgz",
625 | "integrity": "sha512-rv5UZaWVIJTDMyQ3dCEK+m0SAn6G7H3PRc2AZmExvbDvtaDc+qXkei0knQWcI3+c9tEs7iL/4I4pTQoPbNL2SA==",
626 | "cpu": [
627 | "x64"
628 | ],
629 | "dev": true,
630 | "license": "MIT",
631 | "optional": true,
632 | "os": [
633 | "darwin"
634 | ]
635 | },
636 | "node_modules/@rollup/rollup-freebsd-arm64": {
637 | "version": "4.42.0",
638 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.42.0.tgz",
639 | "integrity": "sha512-fJcN4uSGPWdpVmvLuMtALUFwCHgb2XiQjuECkHT3lWLZhSQ3MBQ9pq+WoWeJq2PrNxr9rPM1Qx+IjyGj8/c6zQ==",
640 | "cpu": [
641 | "arm64"
642 | ],
643 | "dev": true,
644 | "license": "MIT",
645 | "optional": true,
646 | "os": [
647 | "freebsd"
648 | ]
649 | },
650 | "node_modules/@rollup/rollup-freebsd-x64": {
651 | "version": "4.42.0",
652 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.42.0.tgz",
653 | "integrity": "sha512-CziHfyzpp8hJpCVE/ZdTizw58gr+m7Y2Xq5VOuCSrZR++th2xWAz4Nqk52MoIIrV3JHtVBhbBsJcAxs6NammOQ==",
654 | "cpu": [
655 | "x64"
656 | ],
657 | "dev": true,
658 | "license": "MIT",
659 | "optional": true,
660 | "os": [
661 | "freebsd"
662 | ]
663 | },
664 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
665 | "version": "4.42.0",
666 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.42.0.tgz",
667 | "integrity": "sha512-UsQD5fyLWm2Fe5CDM7VPYAo+UC7+2Px4Y+N3AcPh/LdZu23YcuGPegQly++XEVaC8XUTFVPscl5y5Cl1twEI4A==",
668 | "cpu": [
669 | "arm"
670 | ],
671 | "dev": true,
672 | "license": "MIT",
673 | "optional": true,
674 | "os": [
675 | "linux"
676 | ]
677 | },
678 | "node_modules/@rollup/rollup-linux-arm-musleabihf": {
679 | "version": "4.42.0",
680 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.42.0.tgz",
681 | "integrity": "sha512-/i8NIrlgc/+4n1lnoWl1zgH7Uo0XK5xK3EDqVTf38KvyYgCU/Rm04+o1VvvzJZnVS5/cWSd07owkzcVasgfIkQ==",
682 | "cpu": [
683 | "arm"
684 | ],
685 | "dev": true,
686 | "license": "MIT",
687 | "optional": true,
688 | "os": [
689 | "linux"
690 | ]
691 | },
692 | "node_modules/@rollup/rollup-linux-arm64-gnu": {
693 | "version": "4.42.0",
694 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.42.0.tgz",
695 | "integrity": "sha512-eoujJFOvoIBjZEi9hJnXAbWg+Vo1Ov8n/0IKZZcPZ7JhBzxh2A+2NFyeMZIRkY9iwBvSjloKgcvnjTbGKHE44Q==",
696 | "cpu": [
697 | "arm64"
698 | ],
699 | "dev": true,
700 | "license": "MIT",
701 | "optional": true,
702 | "os": [
703 | "linux"
704 | ]
705 | },
706 | "node_modules/@rollup/rollup-linux-arm64-musl": {
707 | "version": "4.42.0",
708 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.42.0.tgz",
709 | "integrity": "sha512-/3NrcOWFSR7RQUQIuZQChLND36aTU9IYE4j+TB40VU78S+RA0IiqHR30oSh6P1S9f9/wVOenHQnacs/Byb824g==",
710 | "cpu": [
711 | "arm64"
712 | ],
713 | "dev": true,
714 | "license": "MIT",
715 | "optional": true,
716 | "os": [
717 | "linux"
718 | ]
719 | },
720 | "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
721 | "version": "4.42.0",
722 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.42.0.tgz",
723 | "integrity": "sha512-O8AplvIeavK5ABmZlKBq9/STdZlnQo7Sle0LLhVA7QT+CiGpNVe197/t8Aph9bhJqbDVGCHpY2i7QyfEDDStDg==",
724 | "cpu": [
725 | "loong64"
726 | ],
727 | "dev": true,
728 | "license": "MIT",
729 | "optional": true,
730 | "os": [
731 | "linux"
732 | ]
733 | },
734 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
735 | "version": "4.42.0",
736 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.42.0.tgz",
737 | "integrity": "sha512-6Qb66tbKVN7VyQrekhEzbHRxXXFFD8QKiFAwX5v9Xt6FiJ3BnCVBuyBxa2fkFGqxOCSGGYNejxd8ht+q5SnmtA==",
738 | "cpu": [
739 | "ppc64"
740 | ],
741 | "dev": true,
742 | "license": "MIT",
743 | "optional": true,
744 | "os": [
745 | "linux"
746 | ]
747 | },
748 | "node_modules/@rollup/rollup-linux-riscv64-gnu": {
749 | "version": "4.42.0",
750 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.42.0.tgz",
751 | "integrity": "sha512-KQETDSEBamQFvg/d8jajtRwLNBlGc3aKpaGiP/LvEbnmVUKlFta1vqJqTrvPtsYsfbE/DLg5CC9zyXRX3fnBiA==",
752 | "cpu": [
753 | "riscv64"
754 | ],
755 | "dev": true,
756 | "license": "MIT",
757 | "optional": true,
758 | "os": [
759 | "linux"
760 | ]
761 | },
762 | "node_modules/@rollup/rollup-linux-riscv64-musl": {
763 | "version": "4.42.0",
764 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.42.0.tgz",
765 | "integrity": "sha512-qMvnyjcU37sCo/tuC+JqeDKSuukGAd+pVlRl/oyDbkvPJ3awk6G6ua7tyum02O3lI+fio+eM5wsVd66X0jQtxw==",
766 | "cpu": [
767 | "riscv64"
768 | ],
769 | "dev": true,
770 | "license": "MIT",
771 | "optional": true,
772 | "os": [
773 | "linux"
774 | ]
775 | },
776 | "node_modules/@rollup/rollup-linux-s390x-gnu": {
777 | "version": "4.42.0",
778 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.42.0.tgz",
779 | "integrity": "sha512-I2Y1ZUgTgU2RLddUHXTIgyrdOwljjkmcZ/VilvaEumtS3Fkuhbw4p4hgHc39Ypwvo2o7sBFNl2MquNvGCa55Iw==",
780 | "cpu": [
781 | "s390x"
782 | ],
783 | "dev": true,
784 | "license": "MIT",
785 | "optional": true,
786 | "os": [
787 | "linux"
788 | ]
789 | },
790 | "node_modules/@rollup/rollup-linux-x64-gnu": {
791 | "version": "4.42.0",
792 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.42.0.tgz",
793 | "integrity": "sha512-Gfm6cV6mj3hCUY8TqWa63DB8Mx3NADoFwiJrMpoZ1uESbK8FQV3LXkhfry+8bOniq9pqY1OdsjFWNsSbfjPugw==",
794 | "cpu": [
795 | "x64"
796 | ],
797 | "dev": true,
798 | "license": "MIT",
799 | "optional": true,
800 | "os": [
801 | "linux"
802 | ]
803 | },
804 | "node_modules/@rollup/rollup-linux-x64-musl": {
805 | "version": "4.42.0",
806 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.42.0.tgz",
807 | "integrity": "sha512-g86PF8YZ9GRqkdi0VoGlcDUb4rYtQKyTD1IVtxxN4Hpe7YqLBShA7oHMKU6oKTCi3uxwW4VkIGnOaH/El8de3w==",
808 | "cpu": [
809 | "x64"
810 | ],
811 | "dev": true,
812 | "license": "MIT",
813 | "optional": true,
814 | "os": [
815 | "linux"
816 | ]
817 | },
818 | "node_modules/@rollup/rollup-win32-arm64-msvc": {
819 | "version": "4.42.0",
820 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.42.0.tgz",
821 | "integrity": "sha512-+axkdyDGSp6hjyzQ5m1pgcvQScfHnMCcsXkx8pTgy/6qBmWVhtRVlgxjWwDp67wEXXUr0x+vD6tp5W4x6V7u1A==",
822 | "cpu": [
823 | "arm64"
824 | ],
825 | "dev": true,
826 | "license": "MIT",
827 | "optional": true,
828 | "os": [
829 | "win32"
830 | ]
831 | },
832 | "node_modules/@rollup/rollup-win32-ia32-msvc": {
833 | "version": "4.42.0",
834 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.42.0.tgz",
835 | "integrity": "sha512-F+5J9pelstXKwRSDq92J0TEBXn2nfUrQGg+HK1+Tk7VOL09e0gBqUHugZv7SW4MGrYj41oNCUe3IKCDGVlis2g==",
836 | "cpu": [
837 | "ia32"
838 | ],
839 | "dev": true,
840 | "license": "MIT",
841 | "optional": true,
842 | "os": [
843 | "win32"
844 | ]
845 | },
846 | "node_modules/@rollup/rollup-win32-x64-msvc": {
847 | "version": "4.42.0",
848 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.42.0.tgz",
849 | "integrity": "sha512-LpHiJRwkaVz/LqjHjK8LCi8osq7elmpwujwbXKNW88bM8eeGxavJIKKjkjpMHAh/2xfnrt1ZSnhTv41WYUHYmA==",
850 | "cpu": [
851 | "x64"
852 | ],
853 | "dev": true,
854 | "license": "MIT",
855 | "optional": true,
856 | "os": [
857 | "win32"
858 | ]
859 | },
860 | "node_modules/@types/chai": {
861 | "version": "5.2.2",
862 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz",
863 | "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==",
864 | "dev": true,
865 | "license": "MIT",
866 | "dependencies": {
867 | "@types/deep-eql": "*"
868 | }
869 | },
870 | "node_modules/@types/deep-eql": {
871 | "version": "4.0.2",
872 | "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
873 | "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
874 | "dev": true,
875 | "license": "MIT"
876 | },
877 | "node_modules/@types/estree": {
878 | "version": "1.0.7",
879 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
880 | "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
881 | "dev": true,
882 | "license": "MIT"
883 | },
884 | "node_modules/@types/node": {
885 | "version": "22.15.30",
886 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.30.tgz",
887 | "integrity": "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==",
888 | "dev": true,
889 | "license": "MIT",
890 | "dependencies": {
891 | "undici-types": "~6.21.0"
892 | }
893 | },
894 | "node_modules/@types/resolve": {
895 | "version": "1.20.2",
896 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
897 | "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
898 | "dev": true,
899 | "license": "MIT"
900 | },
901 | "node_modules/@vitest/expect": {
902 | "version": "3.2.2",
903 | "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.2.tgz",
904 | "integrity": "sha512-ipHw0z669vEMjzz3xQE8nJX1s0rQIb7oEl4jjl35qWTwm/KIHERIg/p/zORrjAaZKXfsv7IybcNGHwhOOAPMwQ==",
905 | "dev": true,
906 | "license": "MIT",
907 | "dependencies": {
908 | "@types/chai": "^5.2.2",
909 | "@vitest/spy": "3.2.2",
910 | "@vitest/utils": "3.2.2",
911 | "chai": "^5.2.0",
912 | "tinyrainbow": "^2.0.0"
913 | },
914 | "funding": {
915 | "url": "https://opencollective.com/vitest"
916 | }
917 | },
918 | "node_modules/@vitest/mocker": {
919 | "version": "3.2.2",
920 | "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.2.tgz",
921 | "integrity": "sha512-jKojcaRyIYpDEf+s7/dD3LJt53c0dPfp5zCPXz9H/kcGrSlovU/t1yEaNzM9oFME3dcd4ULwRI/x0Po1Zf+LTw==",
922 | "dev": true,
923 | "license": "MIT",
924 | "dependencies": {
925 | "@vitest/spy": "3.2.2",
926 | "estree-walker": "^3.0.3",
927 | "magic-string": "^0.30.17"
928 | },
929 | "funding": {
930 | "url": "https://opencollective.com/vitest"
931 | },
932 | "peerDependencies": {
933 | "msw": "^2.4.9",
934 | "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
935 | },
936 | "peerDependenciesMeta": {
937 | "msw": {
938 | "optional": true
939 | },
940 | "vite": {
941 | "optional": true
942 | }
943 | }
944 | },
945 | "node_modules/@vitest/mocker/node_modules/estree-walker": {
946 | "version": "3.0.3",
947 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
948 | "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
949 | "dev": true,
950 | "license": "MIT",
951 | "dependencies": {
952 | "@types/estree": "^1.0.0"
953 | }
954 | },
955 | "node_modules/@vitest/pretty-format": {
956 | "version": "3.2.2",
957 | "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.2.tgz",
958 | "integrity": "sha512-FY4o4U1UDhO9KMd2Wee5vumwcaHw7Vg4V7yR4Oq6uK34nhEJOmdRYrk3ClburPRUA09lXD/oXWZ8y/Sdma0aUQ==",
959 | "dev": true,
960 | "license": "MIT",
961 | "dependencies": {
962 | "tinyrainbow": "^2.0.0"
963 | },
964 | "funding": {
965 | "url": "https://opencollective.com/vitest"
966 | }
967 | },
968 | "node_modules/@vitest/runner": {
969 | "version": "3.2.2",
970 | "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.2.tgz",
971 | "integrity": "sha512-GYcHcaS3ejGRZYed2GAkvsjBeXIEerDKdX3orQrBJqLRiea4NSS9qvn9Nxmuy1IwIB+EjFOaxXnX79l8HFaBwg==",
972 | "dev": true,
973 | "license": "MIT",
974 | "dependencies": {
975 | "@vitest/utils": "3.2.2",
976 | "pathe": "^2.0.3"
977 | },
978 | "funding": {
979 | "url": "https://opencollective.com/vitest"
980 | }
981 | },
982 | "node_modules/@vitest/snapshot": {
983 | "version": "3.2.2",
984 | "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.2.tgz",
985 | "integrity": "sha512-aMEI2XFlR1aNECbBs5C5IZopfi5Lb8QJZGGpzS8ZUHML5La5wCbrbhLOVSME68qwpT05ROEEOAZPRXFpxZV2wA==",
986 | "dev": true,
987 | "license": "MIT",
988 | "dependencies": {
989 | "@vitest/pretty-format": "3.2.2",
990 | "magic-string": "^0.30.17",
991 | "pathe": "^2.0.3"
992 | },
993 | "funding": {
994 | "url": "https://opencollective.com/vitest"
995 | }
996 | },
997 | "node_modules/@vitest/spy": {
998 | "version": "3.2.2",
999 | "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.2.tgz",
1000 | "integrity": "sha512-6Utxlx3o7pcTxvp0u8kUiXtRFScMrUg28KjB3R2hon7w4YqOFAEA9QwzPVVS1QNL3smo4xRNOpNZClRVfpMcYg==",
1001 | "dev": true,
1002 | "license": "MIT",
1003 | "dependencies": {
1004 | "tinyspy": "^4.0.3"
1005 | },
1006 | "funding": {
1007 | "url": "https://opencollective.com/vitest"
1008 | }
1009 | },
1010 | "node_modules/@vitest/utils": {
1011 | "version": "3.2.2",
1012 | "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.2.tgz",
1013 | "integrity": "sha512-qJYMllrWpF/OYfWHP32T31QCaLa3BAzT/n/8mNGhPdVcjY+JYazQFO1nsJvXU12Kp1xMpNY4AGuljPTNjQve6A==",
1014 | "dev": true,
1015 | "license": "MIT",
1016 | "dependencies": {
1017 | "@vitest/pretty-format": "3.2.2",
1018 | "loupe": "^3.1.3",
1019 | "tinyrainbow": "^2.0.0"
1020 | },
1021 | "funding": {
1022 | "url": "https://opencollective.com/vitest"
1023 | }
1024 | },
1025 | "node_modules/assertion-error": {
1026 | "version": "2.0.1",
1027 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
1028 | "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
1029 | "dev": true,
1030 | "license": "MIT",
1031 | "engines": {
1032 | "node": ">=12"
1033 | }
1034 | },
1035 | "node_modules/benchmark": {
1036 | "version": "2.1.4",
1037 | "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz",
1038 | "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==",
1039 | "dev": true,
1040 | "license": "MIT",
1041 | "dependencies": {
1042 | "lodash": "^4.17.4",
1043 | "platform": "^1.3.3"
1044 | }
1045 | },
1046 | "node_modules/cac": {
1047 | "version": "6.7.14",
1048 | "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
1049 | "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
1050 | "dev": true,
1051 | "license": "MIT",
1052 | "engines": {
1053 | "node": ">=8"
1054 | }
1055 | },
1056 | "node_modules/chai": {
1057 | "version": "5.2.0",
1058 | "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
1059 | "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
1060 | "dev": true,
1061 | "license": "MIT",
1062 | "dependencies": {
1063 | "assertion-error": "^2.0.1",
1064 | "check-error": "^2.1.1",
1065 | "deep-eql": "^5.0.1",
1066 | "loupe": "^3.1.0",
1067 | "pathval": "^2.0.0"
1068 | },
1069 | "engines": {
1070 | "node": ">=12"
1071 | }
1072 | },
1073 | "node_modules/check-error": {
1074 | "version": "2.1.1",
1075 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
1076 | "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
1077 | "dev": true,
1078 | "license": "MIT",
1079 | "engines": {
1080 | "node": ">= 16"
1081 | }
1082 | },
1083 | "node_modules/commondir": {
1084 | "version": "1.0.1",
1085 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
1086 | "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
1087 | "dev": true,
1088 | "license": "MIT"
1089 | },
1090 | "node_modules/debug": {
1091 | "version": "4.4.1",
1092 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
1093 | "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
1094 | "dev": true,
1095 | "license": "MIT",
1096 | "dependencies": {
1097 | "ms": "^2.1.3"
1098 | },
1099 | "engines": {
1100 | "node": ">=6.0"
1101 | },
1102 | "peerDependenciesMeta": {
1103 | "supports-color": {
1104 | "optional": true
1105 | }
1106 | }
1107 | },
1108 | "node_modules/deep-eql": {
1109 | "version": "5.0.2",
1110 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
1111 | "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
1112 | "dev": true,
1113 | "license": "MIT",
1114 | "engines": {
1115 | "node": ">=6"
1116 | }
1117 | },
1118 | "node_modules/deepmerge": {
1119 | "version": "4.3.1",
1120 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
1121 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
1122 | "dev": true,
1123 | "license": "MIT",
1124 | "engines": {
1125 | "node": ">=0.10.0"
1126 | }
1127 | },
1128 | "node_modules/es-module-lexer": {
1129 | "version": "1.7.0",
1130 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
1131 | "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
1132 | "dev": true,
1133 | "license": "MIT"
1134 | },
1135 | "node_modules/esbuild": {
1136 | "version": "0.25.5",
1137 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
1138 | "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
1139 | "dev": true,
1140 | "hasInstallScript": true,
1141 | "license": "MIT",
1142 | "bin": {
1143 | "esbuild": "bin/esbuild"
1144 | },
1145 | "engines": {
1146 | "node": ">=18"
1147 | },
1148 | "optionalDependencies": {
1149 | "@esbuild/aix-ppc64": "0.25.5",
1150 | "@esbuild/android-arm": "0.25.5",
1151 | "@esbuild/android-arm64": "0.25.5",
1152 | "@esbuild/android-x64": "0.25.5",
1153 | "@esbuild/darwin-arm64": "0.25.5",
1154 | "@esbuild/darwin-x64": "0.25.5",
1155 | "@esbuild/freebsd-arm64": "0.25.5",
1156 | "@esbuild/freebsd-x64": "0.25.5",
1157 | "@esbuild/linux-arm": "0.25.5",
1158 | "@esbuild/linux-arm64": "0.25.5",
1159 | "@esbuild/linux-ia32": "0.25.5",
1160 | "@esbuild/linux-loong64": "0.25.5",
1161 | "@esbuild/linux-mips64el": "0.25.5",
1162 | "@esbuild/linux-ppc64": "0.25.5",
1163 | "@esbuild/linux-riscv64": "0.25.5",
1164 | "@esbuild/linux-s390x": "0.25.5",
1165 | "@esbuild/linux-x64": "0.25.5",
1166 | "@esbuild/netbsd-arm64": "0.25.5",
1167 | "@esbuild/netbsd-x64": "0.25.5",
1168 | "@esbuild/openbsd-arm64": "0.25.5",
1169 | "@esbuild/openbsd-x64": "0.25.5",
1170 | "@esbuild/sunos-x64": "0.25.5",
1171 | "@esbuild/win32-arm64": "0.25.5",
1172 | "@esbuild/win32-ia32": "0.25.5",
1173 | "@esbuild/win32-x64": "0.25.5"
1174 | }
1175 | },
1176 | "node_modules/estree-walker": {
1177 | "version": "2.0.2",
1178 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
1179 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
1180 | "dev": true,
1181 | "license": "MIT"
1182 | },
1183 | "node_modules/expect-type": {
1184 | "version": "1.2.1",
1185 | "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz",
1186 | "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==",
1187 | "dev": true,
1188 | "license": "Apache-2.0",
1189 | "engines": {
1190 | "node": ">=12.0.0"
1191 | }
1192 | },
1193 | "node_modules/fdir": {
1194 | "version": "6.4.5",
1195 | "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz",
1196 | "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==",
1197 | "dev": true,
1198 | "license": "MIT",
1199 | "peerDependencies": {
1200 | "picomatch": "^3 || ^4"
1201 | },
1202 | "peerDependenciesMeta": {
1203 | "picomatch": {
1204 | "optional": true
1205 | }
1206 | }
1207 | },
1208 | "node_modules/fsevents": {
1209 | "version": "2.3.3",
1210 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1211 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1212 | "dev": true,
1213 | "hasInstallScript": true,
1214 | "license": "MIT",
1215 | "optional": true,
1216 | "os": [
1217 | "darwin"
1218 | ],
1219 | "engines": {
1220 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1221 | }
1222 | },
1223 | "node_modules/function-bind": {
1224 | "version": "1.1.2",
1225 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
1226 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
1227 | "dev": true,
1228 | "license": "MIT",
1229 | "funding": {
1230 | "url": "https://github.com/sponsors/ljharb"
1231 | }
1232 | },
1233 | "node_modules/hasown": {
1234 | "version": "2.0.2",
1235 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
1236 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
1237 | "dev": true,
1238 | "license": "MIT",
1239 | "dependencies": {
1240 | "function-bind": "^1.1.2"
1241 | },
1242 | "engines": {
1243 | "node": ">= 0.4"
1244 | }
1245 | },
1246 | "node_modules/is-core-module": {
1247 | "version": "2.16.1",
1248 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
1249 | "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
1250 | "dev": true,
1251 | "license": "MIT",
1252 | "dependencies": {
1253 | "hasown": "^2.0.2"
1254 | },
1255 | "engines": {
1256 | "node": ">= 0.4"
1257 | },
1258 | "funding": {
1259 | "url": "https://github.com/sponsors/ljharb"
1260 | }
1261 | },
1262 | "node_modules/is-module": {
1263 | "version": "1.0.0",
1264 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
1265 | "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
1266 | "dev": true,
1267 | "license": "MIT"
1268 | },
1269 | "node_modules/is-reference": {
1270 | "version": "1.2.1",
1271 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
1272 | "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
1273 | "dev": true,
1274 | "license": "MIT",
1275 | "dependencies": {
1276 | "@types/estree": "*"
1277 | }
1278 | },
1279 | "node_modules/lodash": {
1280 | "version": "4.17.21",
1281 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
1282 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
1283 | "dev": true,
1284 | "license": "MIT"
1285 | },
1286 | "node_modules/loupe": {
1287 | "version": "3.1.3",
1288 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz",
1289 | "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
1290 | "dev": true,
1291 | "license": "MIT"
1292 | },
1293 | "node_modules/magic-string": {
1294 | "version": "0.30.17",
1295 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
1296 | "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
1297 | "dev": true,
1298 | "license": "MIT",
1299 | "dependencies": {
1300 | "@jridgewell/sourcemap-codec": "^1.5.0"
1301 | }
1302 | },
1303 | "node_modules/ms": {
1304 | "version": "2.1.3",
1305 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1306 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1307 | "dev": true,
1308 | "license": "MIT"
1309 | },
1310 | "node_modules/nanoid": {
1311 | "version": "3.3.11",
1312 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
1313 | "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
1314 | "dev": true,
1315 | "funding": [
1316 | {
1317 | "type": "github",
1318 | "url": "https://github.com/sponsors/ai"
1319 | }
1320 | ],
1321 | "license": "MIT",
1322 | "bin": {
1323 | "nanoid": "bin/nanoid.cjs"
1324 | },
1325 | "engines": {
1326 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
1327 | }
1328 | },
1329 | "node_modules/path-parse": {
1330 | "version": "1.0.7",
1331 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
1332 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
1333 | "dev": true,
1334 | "license": "MIT"
1335 | },
1336 | "node_modules/pathe": {
1337 | "version": "2.0.3",
1338 | "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
1339 | "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
1340 | "dev": true,
1341 | "license": "MIT"
1342 | },
1343 | "node_modules/pathval": {
1344 | "version": "2.0.0",
1345 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
1346 | "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
1347 | "dev": true,
1348 | "license": "MIT",
1349 | "engines": {
1350 | "node": ">= 14.16"
1351 | }
1352 | },
1353 | "node_modules/picocolors": {
1354 | "version": "1.1.1",
1355 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
1356 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
1357 | "dev": true,
1358 | "license": "ISC"
1359 | },
1360 | "node_modules/picomatch": {
1361 | "version": "4.0.2",
1362 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
1363 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
1364 | "dev": true,
1365 | "license": "MIT",
1366 | "engines": {
1367 | "node": ">=12"
1368 | },
1369 | "funding": {
1370 | "url": "https://github.com/sponsors/jonschlinkert"
1371 | }
1372 | },
1373 | "node_modules/platform": {
1374 | "version": "1.3.6",
1375 | "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
1376 | "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==",
1377 | "dev": true,
1378 | "license": "MIT"
1379 | },
1380 | "node_modules/postcss": {
1381 | "version": "8.5.4",
1382 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
1383 | "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
1384 | "dev": true,
1385 | "funding": [
1386 | {
1387 | "type": "opencollective",
1388 | "url": "https://opencollective.com/postcss/"
1389 | },
1390 | {
1391 | "type": "tidelift",
1392 | "url": "https://tidelift.com/funding/github/npm/postcss"
1393 | },
1394 | {
1395 | "type": "github",
1396 | "url": "https://github.com/sponsors/ai"
1397 | }
1398 | ],
1399 | "license": "MIT",
1400 | "dependencies": {
1401 | "nanoid": "^3.3.11",
1402 | "picocolors": "^1.1.1",
1403 | "source-map-js": "^1.2.1"
1404 | },
1405 | "engines": {
1406 | "node": "^10 || ^12 || >=14"
1407 | }
1408 | },
1409 | "node_modules/prettier": {
1410 | "version": "3.5.3",
1411 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
1412 | "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
1413 | "dev": true,
1414 | "license": "MIT",
1415 | "bin": {
1416 | "prettier": "bin/prettier.cjs"
1417 | },
1418 | "engines": {
1419 | "node": ">=14"
1420 | },
1421 | "funding": {
1422 | "url": "https://github.com/prettier/prettier?sponsor=1"
1423 | }
1424 | },
1425 | "node_modules/resolve": {
1426 | "version": "1.22.10",
1427 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
1428 | "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
1429 | "dev": true,
1430 | "license": "MIT",
1431 | "dependencies": {
1432 | "is-core-module": "^2.16.0",
1433 | "path-parse": "^1.0.7",
1434 | "supports-preserve-symlinks-flag": "^1.0.0"
1435 | },
1436 | "bin": {
1437 | "resolve": "bin/resolve"
1438 | },
1439 | "engines": {
1440 | "node": ">= 0.4"
1441 | },
1442 | "funding": {
1443 | "url": "https://github.com/sponsors/ljharb"
1444 | }
1445 | },
1446 | "node_modules/rollup": {
1447 | "version": "4.42.0",
1448 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.42.0.tgz",
1449 | "integrity": "sha512-LW+Vse3BJPyGJGAJt1j8pWDKPd73QM8cRXYK1IxOBgL2AGLu7Xd2YOW0M2sLUBCkF5MshXXtMApyEAEzMVMsnw==",
1450 | "dev": true,
1451 | "license": "MIT",
1452 | "dependencies": {
1453 | "@types/estree": "1.0.7"
1454 | },
1455 | "bin": {
1456 | "rollup": "dist/bin/rollup"
1457 | },
1458 | "engines": {
1459 | "node": ">=18.0.0",
1460 | "npm": ">=8.0.0"
1461 | },
1462 | "optionalDependencies": {
1463 | "@rollup/rollup-android-arm-eabi": "4.42.0",
1464 | "@rollup/rollup-android-arm64": "4.42.0",
1465 | "@rollup/rollup-darwin-arm64": "4.42.0",
1466 | "@rollup/rollup-darwin-x64": "4.42.0",
1467 | "@rollup/rollup-freebsd-arm64": "4.42.0",
1468 | "@rollup/rollup-freebsd-x64": "4.42.0",
1469 | "@rollup/rollup-linux-arm-gnueabihf": "4.42.0",
1470 | "@rollup/rollup-linux-arm-musleabihf": "4.42.0",
1471 | "@rollup/rollup-linux-arm64-gnu": "4.42.0",
1472 | "@rollup/rollup-linux-arm64-musl": "4.42.0",
1473 | "@rollup/rollup-linux-loongarch64-gnu": "4.42.0",
1474 | "@rollup/rollup-linux-powerpc64le-gnu": "4.42.0",
1475 | "@rollup/rollup-linux-riscv64-gnu": "4.42.0",
1476 | "@rollup/rollup-linux-riscv64-musl": "4.42.0",
1477 | "@rollup/rollup-linux-s390x-gnu": "4.42.0",
1478 | "@rollup/rollup-linux-x64-gnu": "4.42.0",
1479 | "@rollup/rollup-linux-x64-musl": "4.42.0",
1480 | "@rollup/rollup-win32-arm64-msvc": "4.42.0",
1481 | "@rollup/rollup-win32-ia32-msvc": "4.42.0",
1482 | "@rollup/rollup-win32-x64-msvc": "4.42.0",
1483 | "fsevents": "~2.3.2"
1484 | }
1485 | },
1486 | "node_modules/siginfo": {
1487 | "version": "2.0.0",
1488 | "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
1489 | "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
1490 | "dev": true,
1491 | "license": "ISC"
1492 | },
1493 | "node_modules/source-map-js": {
1494 | "version": "1.2.1",
1495 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
1496 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
1497 | "dev": true,
1498 | "license": "BSD-3-Clause",
1499 | "engines": {
1500 | "node": ">=0.10.0"
1501 | }
1502 | },
1503 | "node_modules/stackback": {
1504 | "version": "0.0.2",
1505 | "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
1506 | "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
1507 | "dev": true,
1508 | "license": "MIT"
1509 | },
1510 | "node_modules/std-env": {
1511 | "version": "3.9.0",
1512 | "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
1513 | "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
1514 | "dev": true,
1515 | "license": "MIT"
1516 | },
1517 | "node_modules/supports-preserve-symlinks-flag": {
1518 | "version": "1.0.0",
1519 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
1520 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
1521 | "dev": true,
1522 | "license": "MIT",
1523 | "engines": {
1524 | "node": ">= 0.4"
1525 | },
1526 | "funding": {
1527 | "url": "https://github.com/sponsors/ljharb"
1528 | }
1529 | },
1530 | "node_modules/tinybench": {
1531 | "version": "2.9.0",
1532 | "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
1533 | "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
1534 | "dev": true,
1535 | "license": "MIT"
1536 | },
1537 | "node_modules/tinyexec": {
1538 | "version": "0.3.2",
1539 | "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
1540 | "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
1541 | "dev": true,
1542 | "license": "MIT"
1543 | },
1544 | "node_modules/tinyglobby": {
1545 | "version": "0.2.14",
1546 | "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
1547 | "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
1548 | "dev": true,
1549 | "license": "MIT",
1550 | "dependencies": {
1551 | "fdir": "^6.4.4",
1552 | "picomatch": "^4.0.2"
1553 | },
1554 | "engines": {
1555 | "node": ">=12.0.0"
1556 | },
1557 | "funding": {
1558 | "url": "https://github.com/sponsors/SuperchupuDev"
1559 | }
1560 | },
1561 | "node_modules/tinypool": {
1562 | "version": "1.1.0",
1563 | "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.0.tgz",
1564 | "integrity": "sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==",
1565 | "dev": true,
1566 | "license": "MIT",
1567 | "engines": {
1568 | "node": "^18.0.0 || >=20.0.0"
1569 | }
1570 | },
1571 | "node_modules/tinyrainbow": {
1572 | "version": "2.0.0",
1573 | "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
1574 | "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
1575 | "dev": true,
1576 | "license": "MIT",
1577 | "engines": {
1578 | "node": ">=14.0.0"
1579 | }
1580 | },
1581 | "node_modules/tinyspy": {
1582 | "version": "4.0.3",
1583 | "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz",
1584 | "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==",
1585 | "dev": true,
1586 | "license": "MIT",
1587 | "engines": {
1588 | "node": ">=14.0.0"
1589 | }
1590 | },
1591 | "node_modules/tslib": {
1592 | "version": "2.8.1",
1593 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
1594 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
1595 | "dev": true,
1596 | "license": "0BSD"
1597 | },
1598 | "node_modules/typescript": {
1599 | "version": "5.8.3",
1600 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
1601 | "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
1602 | "dev": true,
1603 | "license": "Apache-2.0",
1604 | "bin": {
1605 | "tsc": "bin/tsc",
1606 | "tsserver": "bin/tsserver"
1607 | },
1608 | "engines": {
1609 | "node": ">=14.17"
1610 | }
1611 | },
1612 | "node_modules/undici-types": {
1613 | "version": "6.21.0",
1614 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
1615 | "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
1616 | "dev": true,
1617 | "license": "MIT"
1618 | },
1619 | "node_modules/vite": {
1620 | "version": "6.3.5",
1621 | "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
1622 | "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
1623 | "dev": true,
1624 | "license": "MIT",
1625 | "dependencies": {
1626 | "esbuild": "^0.25.0",
1627 | "fdir": "^6.4.4",
1628 | "picomatch": "^4.0.2",
1629 | "postcss": "^8.5.3",
1630 | "rollup": "^4.34.9",
1631 | "tinyglobby": "^0.2.13"
1632 | },
1633 | "bin": {
1634 | "vite": "bin/vite.js"
1635 | },
1636 | "engines": {
1637 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
1638 | },
1639 | "funding": {
1640 | "url": "https://github.com/vitejs/vite?sponsor=1"
1641 | },
1642 | "optionalDependencies": {
1643 | "fsevents": "~2.3.3"
1644 | },
1645 | "peerDependencies": {
1646 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
1647 | "jiti": ">=1.21.0",
1648 | "less": "*",
1649 | "lightningcss": "^1.21.0",
1650 | "sass": "*",
1651 | "sass-embedded": "*",
1652 | "stylus": "*",
1653 | "sugarss": "*",
1654 | "terser": "^5.16.0",
1655 | "tsx": "^4.8.1",
1656 | "yaml": "^2.4.2"
1657 | },
1658 | "peerDependenciesMeta": {
1659 | "@types/node": {
1660 | "optional": true
1661 | },
1662 | "jiti": {
1663 | "optional": true
1664 | },
1665 | "less": {
1666 | "optional": true
1667 | },
1668 | "lightningcss": {
1669 | "optional": true
1670 | },
1671 | "sass": {
1672 | "optional": true
1673 | },
1674 | "sass-embedded": {
1675 | "optional": true
1676 | },
1677 | "stylus": {
1678 | "optional": true
1679 | },
1680 | "sugarss": {
1681 | "optional": true
1682 | },
1683 | "terser": {
1684 | "optional": true
1685 | },
1686 | "tsx": {
1687 | "optional": true
1688 | },
1689 | "yaml": {
1690 | "optional": true
1691 | }
1692 | }
1693 | },
1694 | "node_modules/vite-node": {
1695 | "version": "3.2.2",
1696 | "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.2.tgz",
1697 | "integrity": "sha512-Xj/jovjZvDXOq2FgLXu8NsY4uHUMWtzVmMC2LkCu9HWdr9Qu1Is5sanX3Z4jOFKdohfaWDnEJWp9pRP0vVpAcA==",
1698 | "dev": true,
1699 | "license": "MIT",
1700 | "dependencies": {
1701 | "cac": "^6.7.14",
1702 | "debug": "^4.4.1",
1703 | "es-module-lexer": "^1.7.0",
1704 | "pathe": "^2.0.3",
1705 | "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
1706 | },
1707 | "bin": {
1708 | "vite-node": "vite-node.mjs"
1709 | },
1710 | "engines": {
1711 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
1712 | },
1713 | "funding": {
1714 | "url": "https://opencollective.com/vitest"
1715 | }
1716 | },
1717 | "node_modules/vitest": {
1718 | "version": "3.2.2",
1719 | "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.2.tgz",
1720 | "integrity": "sha512-fyNn/Rp016Bt5qvY0OQvIUCwW2vnaEBLxP42PmKbNIoasSYjML+8xyeADOPvBe+Xfl/ubIw4og7Lt9jflRsCNw==",
1721 | "dev": true,
1722 | "license": "MIT",
1723 | "dependencies": {
1724 | "@types/chai": "^5.2.2",
1725 | "@vitest/expect": "3.2.2",
1726 | "@vitest/mocker": "3.2.2",
1727 | "@vitest/pretty-format": "^3.2.2",
1728 | "@vitest/runner": "3.2.2",
1729 | "@vitest/snapshot": "3.2.2",
1730 | "@vitest/spy": "3.2.2",
1731 | "@vitest/utils": "3.2.2",
1732 | "chai": "^5.2.0",
1733 | "debug": "^4.4.1",
1734 | "expect-type": "^1.2.1",
1735 | "magic-string": "^0.30.17",
1736 | "pathe": "^2.0.3",
1737 | "picomatch": "^4.0.2",
1738 | "std-env": "^3.9.0",
1739 | "tinybench": "^2.9.0",
1740 | "tinyexec": "^0.3.2",
1741 | "tinyglobby": "^0.2.14",
1742 | "tinypool": "^1.1.0",
1743 | "tinyrainbow": "^2.0.0",
1744 | "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
1745 | "vite-node": "3.2.2",
1746 | "why-is-node-running": "^2.3.0"
1747 | },
1748 | "bin": {
1749 | "vitest": "vitest.mjs"
1750 | },
1751 | "engines": {
1752 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
1753 | },
1754 | "funding": {
1755 | "url": "https://opencollective.com/vitest"
1756 | },
1757 | "peerDependencies": {
1758 | "@edge-runtime/vm": "*",
1759 | "@types/debug": "^4.1.12",
1760 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
1761 | "@vitest/browser": "3.2.2",
1762 | "@vitest/ui": "3.2.2",
1763 | "happy-dom": "*",
1764 | "jsdom": "*"
1765 | },
1766 | "peerDependenciesMeta": {
1767 | "@edge-runtime/vm": {
1768 | "optional": true
1769 | },
1770 | "@types/debug": {
1771 | "optional": true
1772 | },
1773 | "@types/node": {
1774 | "optional": true
1775 | },
1776 | "@vitest/browser": {
1777 | "optional": true
1778 | },
1779 | "@vitest/ui": {
1780 | "optional": true
1781 | },
1782 | "happy-dom": {
1783 | "optional": true
1784 | },
1785 | "jsdom": {
1786 | "optional": true
1787 | }
1788 | }
1789 | },
1790 | "node_modules/why-is-node-running": {
1791 | "version": "2.3.0",
1792 | "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
1793 | "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
1794 | "dev": true,
1795 | "license": "MIT",
1796 | "dependencies": {
1797 | "siginfo": "^2.0.0",
1798 | "stackback": "0.0.2"
1799 | },
1800 | "bin": {
1801 | "why-is-node-running": "cli.js"
1802 | },
1803 | "engines": {
1804 | "node": ">=8"
1805 | }
1806 | }
1807 | }
1808 | }
1809 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ulid",
3 | "version": "3.0.1",
4 | "description": "A universally-unique, lexicographically-sortable, identifier generator",
5 | "type": "module",
6 | "exports": {
7 | ".": {
8 | "types": {
9 | "require": "./dist/index.d.cts",
10 | "default": "./dist/index.d.ts"
11 | },
12 | "node": {
13 | "require": "./dist/node/index.cjs",
14 | "default": "./dist/node/index.js"
15 | },
16 | "default": {
17 | "require": "./dist/browser/index.cjs",
18 | "default": "./dist/browser/index.js"
19 | }
20 | },
21 | "./package.json": "./package.json"
22 | },
23 | "main": "dist/node/index.cjs",
24 | "module": "./dist/node/index.js",
25 | "browser": {
26 | "./dist/node/index.cjs": "./dist/browser/index.cjs",
27 | "./dist/node/index.js": "./dist/browser/index.js"
28 | },
29 | "react-native": "./dist/browser/index.cjs",
30 | "types": "dist/index.d.ts",
31 | "sideEffects": false,
32 | "bin": "./dist/cli.js",
33 | "scripts": {
34 | "bench": "npm run build && node test/benchmark.js",
35 | "build": "npm run clean && npm run build:node:cjs && npm run build:node:esm && npm run build:browser:cjs && npm run build:browser:esm && npm run build:cli && npm run build:types",
36 | "build:browser:cjs": "FMT=cjs ENV=browser rollup -c --name ulidx",
37 | "build:browser:esm": "FMT=esm ENV=browser rollup -c --name ulidx",
38 | "build:cli": "FMT=esm ENV=cli rollup -c && chmod +x ./dist/cli.js",
39 | "build:node:cjs": "FMT=cjs ENV=node rollup -c",
40 | "build:node:esm": "FMT=esm ENV=node rollup -c",
41 | "build:types": "tsc -p tsconfig.dec.json --emitDeclarationOnly && find ./dist -name '*.d.ts' -exec sh -c 'cp {} $(dirname {})/$(basename -s .d.ts {}).d.cts' \\;",
42 | "clean": "rm -rf ./dist",
43 | "format": "prettier --write \"{{source,test}/**/*.{js,ts},rollup.config.js,vitest.config.js}\"",
44 | "prepublishOnly": "npm run build",
45 | "test": "npm run build && npm run test:specs && npm run test:format && npm run test:types",
46 | "test:format": "prettier --check \"{{source,test}/**/*.{js,ts},rollup.config.js,vitest.config.js}\"",
47 | "test:specs": "vitest",
48 | "test:types": "npx --yes @arethetypeswrong/cli --pack ."
49 | },
50 | "files": [
51 | "dist/**/*"
52 | ],
53 | "repository": {
54 | "type": "git",
55 | "url": "git+https://github.com/ulid/javascript.git"
56 | },
57 | "author": "Alizain Feerasta",
58 | "license": "MIT",
59 | "bugs": {
60 | "url": "https://github.com/ulid/javascript/issues"
61 | },
62 | "homepage": "https://github.com/ulid/javascript#readme",
63 | "devDependencies": {
64 | "@rollup/plugin-alias": "^5.1.1",
65 | "@rollup/plugin-commonjs": "^28.0.3",
66 | "@rollup/plugin-node-resolve": "^16.0.1",
67 | "@rollup/plugin-typescript": "^12.1.2",
68 | "@types/node": "^22.15.30",
69 | "benchmark": "^2.1.4",
70 | "prettier": "^3.5.3",
71 | "rollup": "^4.42.0",
72 | "tslib": "^2.8.1",
73 | "typescript": "^5.8.3",
74 | "vitest": "^3.2.2"
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import { builtinModules } from "node:module";
2 | import typescript from "@rollup/plugin-typescript";
3 | import resolve from "@rollup/plugin-node-resolve";
4 | import alias from "@rollup/plugin-alias";
5 | import pkg from "./package.json" with { type: "json" };
6 |
7 | const EXTENSIONS = [".js", ".ts"];
8 | const ENV = process.env.ENV ? process.env.ENV : "node";
9 | const FMT = process.env.FMT ? process.env.FMT : "esm";
10 |
11 | const entry = ENV === "cli" ? "source/cli.ts" : "source/index.ts";
12 | const output = ENV === "cli" ? "dist" : `dist/${ENV}`;
13 |
14 | const plugins = [
15 | typescript({
16 | tsconfig: "tsconfig.json"
17 | }),
18 | resolve({ extensions: EXTENSIONS })
19 | ];
20 | if (ENV !== "node") {
21 | plugins.unshift(
22 | alias({
23 | entries: [{ find: "node:crypto", replacement: "./stub.js" }]
24 | })
25 | );
26 | }
27 | const extension = FMT === "cjs" ? "cjs" : "js";
28 | const externals =
29 | FMT === "esm"
30 | ? [...builtinModules, ...(pkg.dependencies ? Object.keys(pkg.dependencies) : [])]
31 | : [...builtinModules];
32 |
33 | export default {
34 | external: externals,
35 | input: entry,
36 | output: [
37 | {
38 | dir: output,
39 | format: FMT,
40 | entryFileNames: `[name].${extension}`
41 | }
42 | ],
43 | plugins
44 | };
45 |
--------------------------------------------------------------------------------
/source/cli.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { monotonicFactory } from "./ulid.js";
4 |
5 | function parseArgs(args: Array): Record {
6 | const output = {};
7 |
8 | while (args.length > 0) {
9 | const arg = args.shift();
10 |
11 | if (/^\-\-/.test(arg)) {
12 | if (/=/.test(arg)) {
13 | const [key, value] = arg.split("=");
14 | output[key.substring(2)] = value;
15 | } else {
16 | const value = args.shift();
17 |
18 | if (/^-/.test(value)) {
19 | args.unshift(value);
20 | } else if (!value) {
21 | output[arg.substring(2)] = true;
22 | } else {
23 | output[arg.substring(2)] = value;
24 | }
25 | }
26 | }
27 | }
28 |
29 | return output;
30 | }
31 |
32 | const argv = parseArgs(process.argv.slice(2));
33 |
34 | const count = /^\d+/.test(argv["count"] as string) ? parseInt(argv["count"] as string, 10) : 1;
35 |
36 | const factory = monotonicFactory();
37 |
38 | for (let i = 0; i < count; i += 1) {
39 | console.log(factory());
40 | }
41 |
--------------------------------------------------------------------------------
/source/constants.ts:
--------------------------------------------------------------------------------
1 | // These values should NEVER change. The values are precisely for
2 | // generating ULIDs.
3 | export const B32_CHARACTERS = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
4 | export const ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; // Crockford's Base32
5 | export const ENCODING_LEN = 32; // from ENCODING.length;
6 | export const MAX_ULID = "7ZZZZZZZZZZZZZZZZZZZZZZZZZ";
7 | export const MIN_ULID = "00000000000000000000000000";
8 | export const RANDOM_LEN = 16;
9 | export const TIME_LEN = 10;
10 | export const TIME_MAX = 281474976710655; // from Math.pow(2, 48) - 1;
11 | export const ULID_REGEX = /^[0-7][0-9a-hjkmnp-tv-zA-HJKMNP-TV-Z]{25}$/;
12 | export const UUID_REGEX = /^[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$/;
13 |
--------------------------------------------------------------------------------
/source/crockford.ts:
--------------------------------------------------------------------------------
1 | // Code from https://github.com/devbanana/crockford-base32/blob/develop/src/index.ts
2 | import { B32_CHARACTERS, ENCODING, ENCODING_LEN } from "./constants.js";
3 | import { ULIDError, ULIDErrorCode } from "./error.js";
4 | import { replaceCharAt } from "./utils.js";
5 |
6 | export function crockfordEncode(input: Uint8Array): string {
7 | const output: number[] = [];
8 | let bitsRead = 0;
9 | let buffer = 0;
10 | const reversedInput = new Uint8Array(input.slice().reverse());
11 | for (const byte of reversedInput) {
12 | buffer |= byte << bitsRead;
13 | bitsRead += 8;
14 |
15 | while (bitsRead >= 5) {
16 | output.unshift(buffer & 0x1f);
17 | buffer >>>= 5;
18 | bitsRead -= 5;
19 | }
20 | }
21 | if (bitsRead > 0) {
22 | output.unshift(buffer & 0x1f);
23 | }
24 | return output.map(byte => B32_CHARACTERS.charAt(byte)).join("");
25 | }
26 |
27 | export function crockfordDecode(input: string): Uint8Array {
28 | const sanitizedInput = input.toUpperCase().split("").reverse().join("");
29 | const output: number[] = [];
30 | let bitsRead = 0;
31 | let buffer = 0;
32 | for (const character of sanitizedInput) {
33 | const byte = B32_CHARACTERS.indexOf(character);
34 | if (byte === -1) {
35 | throw new Error(`Invalid base 32 character found in string: ${character}`);
36 | }
37 | buffer |= byte << bitsRead;
38 | bitsRead += 5;
39 | while (bitsRead >= 8) {
40 | output.unshift(buffer & 0xff);
41 | buffer >>>= 8;
42 | bitsRead -= 8;
43 | }
44 | }
45 | if (bitsRead >= 5 || buffer > 0) {
46 | output.unshift(buffer & 0xff);
47 | }
48 | return new Uint8Array(output);
49 | }
50 |
51 | /**
52 | * Fix a ULID's Base32 encoding -
53 | * i and l (case-insensitive) will be treated as 1 and o (case-insensitive) will be treated as 0.
54 | * hyphens are ignored during decoding.
55 | * @param id The ULID
56 | * @returns The cleaned up ULID
57 | */
58 | export function fixULIDBase32(id: string): string {
59 | return id.replace(/i/gi, "1").replace(/l/gi, "1").replace(/o/gi, "0").replace(/-/g, "");
60 | }
61 |
62 | export function incrementBase32(str: string): string {
63 | let done: string | undefined = undefined,
64 | index = str.length,
65 | char: string,
66 | charIndex: number,
67 | output = str;
68 | const maxCharIndex = ENCODING_LEN - 1;
69 | while (!done && index-- >= 0) {
70 | char = output[index];
71 | charIndex = ENCODING.indexOf(char);
72 | if (charIndex === -1) {
73 | throw new ULIDError(
74 | ULIDErrorCode.Base32IncorrectEncoding,
75 | "Incorrectly encoded string"
76 | );
77 | }
78 | if (charIndex === maxCharIndex) {
79 | output = replaceCharAt(output, index, ENCODING[0]);
80 | continue;
81 | }
82 | done = replaceCharAt(output, index, ENCODING[charIndex + 1]);
83 | }
84 | if (typeof done === "string") {
85 | return done;
86 | }
87 | throw new ULIDError(ULIDErrorCode.Base32IncorrectEncoding, "Failed incrementing string");
88 | }
89 |
--------------------------------------------------------------------------------
/source/error.ts:
--------------------------------------------------------------------------------
1 | export enum ULIDErrorCode {
2 | Base32IncorrectEncoding = "B32_ENC_INVALID",
3 | DecodeTimeInvalidCharacter = "DEC_TIME_CHAR",
4 | DecodeTimeValueMalformed = "DEC_TIME_MALFORMED",
5 | EncodeTimeNegative = "ENC_TIME_NEG",
6 | EncodeTimeSizeExceeded = "ENC_TIME_SIZE_EXCEED",
7 | EncodeTimeValueMalformed = "ENC_TIME_MALFORMED",
8 | PRNGDetectFailure = "PRNG_DETECT",
9 | ULIDInvalid = "ULID_INVALID",
10 | Unexpected = "UNEXPECTED",
11 | UUIDInvalid = "UUID_INVALID"
12 | }
13 |
14 | export class ULIDError extends Error {
15 | public code: ULIDErrorCode;
16 |
17 | constructor(errorCode: ULIDErrorCode, message: string) {
18 | super(`${message} (${errorCode})`);
19 |
20 | this.name = "ULIDError";
21 |
22 | this.code = errorCode;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/index.ts:
--------------------------------------------------------------------------------
1 | export { decodeTime, encodeTime, isValid, monotonicFactory, ulid } from "./ulid.js";
2 | export { ulidToUUID, uuidToULID } from "./uuid.js";
3 | export { fixULIDBase32, incrementBase32 } from "./crockford.js";
4 | export { ULIDError, ULIDErrorCode } from "./error.js";
5 | export { MAX_ULID, MIN_ULID, TIME_LEN, TIME_MAX } from "./constants.js";
6 | export * from "./types.js";
7 |
--------------------------------------------------------------------------------
/source/stub.ts:
--------------------------------------------------------------------------------
1 | export default undefined;
2 |
--------------------------------------------------------------------------------
/source/types.ts:
--------------------------------------------------------------------------------
1 | export type PRNG = () => number;
2 |
3 | export type ULID = string;
4 |
5 | export type ULIDFactory = (seedTime?: number) => ULID;
6 |
7 | export type UUID = string;
8 |
--------------------------------------------------------------------------------
/source/ulid.ts:
--------------------------------------------------------------------------------
1 | import crypto from "node:crypto";
2 | import { incrementBase32 } from "./crockford.js";
3 | import { ENCODING, ENCODING_LEN, RANDOM_LEN, TIME_LEN, TIME_MAX } from "./constants.js";
4 | import { ULIDError, ULIDErrorCode } from "./error.js";
5 | import { PRNG, ULID, ULIDFactory } from "./types.js";
6 | import { randomChar } from "./utils.js";
7 |
8 | /**
9 | * Decode time from a ULID
10 | * @param id The ULID
11 | * @returns The decoded timestamp
12 | */
13 | export function decodeTime(id: ULID): number {
14 | if (id.length !== TIME_LEN + RANDOM_LEN) {
15 | throw new ULIDError(ULIDErrorCode.DecodeTimeValueMalformed, "Malformed ULID");
16 | }
17 | const time = id
18 | .substr(0, TIME_LEN)
19 | .toUpperCase()
20 | .split("")
21 | .reverse()
22 | .reduce((carry, char, index) => {
23 | const encodingIndex = ENCODING.indexOf(char);
24 | if (encodingIndex === -1) {
25 | throw new ULIDError(
26 | ULIDErrorCode.DecodeTimeInvalidCharacter,
27 | `Time decode error: Invalid character: ${char}`
28 | );
29 | }
30 | return (carry += encodingIndex * Math.pow(ENCODING_LEN, index));
31 | }, 0);
32 | if (time > TIME_MAX) {
33 | throw new ULIDError(
34 | ULIDErrorCode.DecodeTimeValueMalformed,
35 | `Malformed ULID: timestamp too large: ${time}`
36 | );
37 | }
38 | return time;
39 | }
40 |
41 | /**
42 | * Detect the best PRNG (pseudo-random number generator)
43 | * @param root The root to check from (global/window)
44 | * @returns The PRNG function
45 | */
46 | export function detectPRNG(root?: any): PRNG {
47 | const rootLookup = root || detectRoot();
48 | const globalCrypto =
49 | (rootLookup && (rootLookup.crypto || rootLookup.msCrypto)) ||
50 | (typeof crypto !== "undefined" ? crypto : null);
51 | if (typeof globalCrypto?.getRandomValues === "function") {
52 | return () => {
53 | const buffer = new Uint8Array(1);
54 | globalCrypto.getRandomValues(buffer);
55 | return buffer[0] / 0xff;
56 | };
57 | } else if (typeof globalCrypto?.randomBytes === "function") {
58 | return () => globalCrypto.randomBytes(1).readUInt8() / 0xff;
59 | } else if (crypto?.randomBytes) {
60 | return () => crypto.randomBytes(1).readUInt8() / 0xff;
61 | }
62 | throw new ULIDError(ULIDErrorCode.PRNGDetectFailure, "Failed to find a reliable PRNG");
63 | }
64 |
65 | function detectRoot(): any {
66 | if (inWebWorker()) return self;
67 | if (typeof window !== "undefined") {
68 | return window;
69 | }
70 | if (typeof global !== "undefined") {
71 | return global;
72 | }
73 | if (typeof globalThis !== "undefined") {
74 | return globalThis;
75 | }
76 | return null;
77 | }
78 |
79 | export function encodeRandom(len: number, prng: PRNG): string {
80 | let str = "";
81 | for (; len > 0; len--) {
82 | str = randomChar(prng) + str;
83 | }
84 | return str;
85 | }
86 |
87 | /**
88 | * Encode the time portion of a ULID
89 | * @param now The current timestamp
90 | * @param len Length to generate
91 | * @returns The encoded time
92 | */
93 | export function encodeTime(now: number, len: number = TIME_LEN): string {
94 | if (isNaN(now)) {
95 | throw new ULIDError(
96 | ULIDErrorCode.EncodeTimeValueMalformed,
97 | `Time must be a number: ${now}`
98 | );
99 | } else if (now > TIME_MAX) {
100 | throw new ULIDError(
101 | ULIDErrorCode.EncodeTimeSizeExceeded,
102 | `Cannot encode a time larger than ${TIME_MAX}: ${now}`
103 | );
104 | } else if (now < 0) {
105 | throw new ULIDError(ULIDErrorCode.EncodeTimeNegative, `Time must be positive: ${now}`);
106 | } else if (Number.isInteger(now) === false) {
107 | throw new ULIDError(
108 | ULIDErrorCode.EncodeTimeValueMalformed,
109 | `Time must be an integer: ${now}`
110 | );
111 | }
112 | let mod: number,
113 | str: string = "";
114 | for (let currentLen = len; currentLen > 0; currentLen--) {
115 | mod = now % ENCODING_LEN;
116 | str = ENCODING.charAt(mod) + str;
117 | now = (now - mod) / ENCODING_LEN;
118 | }
119 | return str;
120 | }
121 |
122 | function inWebWorker(): boolean {
123 | // @ts-ignore
124 | return typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope;
125 | }
126 |
127 | /**
128 | * Check if a ULID is valid
129 | * @param id The ULID to test
130 | * @returns True if valid, false otherwise
131 | * @example
132 | * isValid("01HNZX8JGFACFA36RBXDHEQN6E"); // true
133 | * isValid(""); // false
134 | */
135 | export function isValid(id: string): boolean {
136 | return (
137 | typeof id === "string" &&
138 | id.length === TIME_LEN + RANDOM_LEN &&
139 | id
140 | .toUpperCase()
141 | .split("")
142 | .every(char => ENCODING.indexOf(char) !== -1)
143 | );
144 | }
145 |
146 | /**
147 | * Create a ULID factory to generate monotonically-increasing
148 | * ULIDs
149 | * @param prng The PRNG to use
150 | * @returns A ulid factory
151 | * @example
152 | * const ulid = monotonicFactory();
153 | * ulid(); // "01HNZXD07M5CEN5XA66EMZSRZW"
154 | */
155 | export function monotonicFactory(prng?: PRNG): ULIDFactory {
156 | const currentPRNG = prng || detectPRNG();
157 | let lastTime: number = 0,
158 | lastRandom: string;
159 | return function _ulid(seedTime?: number): ULID {
160 | const seed = !seedTime || isNaN(seedTime) ? Date.now() : seedTime;
161 | if (seed <= lastTime) {
162 | const incrementedRandom = (lastRandom = incrementBase32(lastRandom));
163 | return encodeTime(lastTime, TIME_LEN) + incrementedRandom;
164 | }
165 | lastTime = seed;
166 | const newRandom = (lastRandom = encodeRandom(RANDOM_LEN, currentPRNG));
167 | return encodeTime(seed, TIME_LEN) + newRandom;
168 | };
169 | }
170 |
171 | /**
172 | * Generate a ULID
173 | * @param seedTime Optional time seed
174 | * @param prng Optional PRNG function
175 | * @returns A ULID string
176 | * @example
177 | * ulid(); // "01HNZXD07M5CEN5XA66EMZSRZW"
178 | */
179 | export function ulid(seedTime?: number, prng?: PRNG): ULID {
180 | const currentPRNG = prng || detectPRNG();
181 | const seed = !seedTime || isNaN(seedTime) ? Date.now() : seedTime;
182 | return encodeTime(seed, TIME_LEN) + encodeRandom(RANDOM_LEN, currentPRNG);
183 | }
184 |
--------------------------------------------------------------------------------
/source/utils.ts:
--------------------------------------------------------------------------------
1 | import { ENCODING, ENCODING_LEN } from "./constants.js";
2 | import { PRNG } from "./types.js";
3 |
4 | export function randomChar(prng: PRNG): string {
5 | // Currently PRNGs generate fractions from 0 to _less than_ 1, so no "%" is necessary.
6 | // However, just in case a future PRNG can generate 1,
7 | // we are applying "% ENCODING LEN" to wrap back to the first character
8 | const randomPosition = Math.floor(prng() * ENCODING_LEN) % ENCODING_LEN;
9 | return ENCODING.charAt(randomPosition);
10 | }
11 |
12 | export function replaceCharAt(str: string, index: number, char: string): string {
13 | if (index > str.length - 1) {
14 | return str;
15 | }
16 | return str.substr(0, index) + char + str.substr(index + 1);
17 | }
18 |
--------------------------------------------------------------------------------
/source/uuid.ts:
--------------------------------------------------------------------------------
1 | import { UUID } from "crypto";
2 | import { ULID_REGEX, UUID_REGEX } from "./constants.js";
3 | import { crockfordDecode, crockfordEncode } from "./crockford.js";
4 | import { ULIDError, ULIDErrorCode } from "./error.js";
5 | import { ULID } from "./types.js";
6 |
7 | /**
8 | * Convert a ULID to a UUID
9 | * @param ulid The ULID to convert
10 | * @returns A UUID string
11 | */
12 | export function ulidToUUID(ulid: ULID): UUID {
13 | const isValid = ULID_REGEX.test(ulid);
14 | if (!isValid) {
15 | throw new ULIDError(ULIDErrorCode.ULIDInvalid, `Invalid ULID: ${ulid}`);
16 | }
17 | const uint8Array = crockfordDecode(ulid);
18 | let uuid = Array.from(uint8Array)
19 | .map(byte => byte.toString(16).padStart(2, "0"))
20 | .join("");
21 | uuid =
22 | uuid.substring(0, 8) +
23 | "-" +
24 | uuid.substring(8, 12) +
25 | "-" +
26 | uuid.substring(12, 16) +
27 | "-" +
28 | uuid.substring(16, 20) +
29 | "-" +
30 | uuid.substring(20);
31 | return uuid.toUpperCase() as UUID;
32 | }
33 |
34 | /**
35 | * Convert a UUID to a ULID
36 | * @param uuid The UUID to convert
37 | * @returns A ULID string
38 | */
39 | export function uuidToULID(uuid: string): ULID {
40 | const isValid = UUID_REGEX.test(uuid);
41 | if (!isValid) {
42 | throw new ULIDError(ULIDErrorCode.UUIDInvalid, `Invalid UUID: ${uuid}`);
43 | }
44 | const bytes = uuid.replace(/-/g, "").match(/.{1,2}/g);
45 | if (!bytes) {
46 | throw new ULIDError(ULIDErrorCode.Unexpected, `Failed parsing UUID bytes: ${uuid}`);
47 | }
48 | const uint8Array = new Uint8Array(bytes.map(byte => parseInt(byte, 16)));
49 | return crockfordEncode(uint8Array);
50 | }
51 |
--------------------------------------------------------------------------------
/test/benchmark.js:
--------------------------------------------------------------------------------
1 | import Benchmark from "benchmark";
2 | import { ulid } from "../dist/node/index.js";
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | // add tests
7 | suite.add("Simple ulid", function () {
8 | ulid();
9 | });
10 | suite.add("ulid with timestamp", function () {
11 | ulid(Date.now());
12 | });
13 |
14 | // add listeners
15 | suite.on("cycle", function (event) {
16 | console.log(String(event.target));
17 | });
18 | suite.on("complete", function () {
19 | console.log("Done!");
20 | });
21 |
22 | // run async
23 | suite.run({ async: true });
24 |
--------------------------------------------------------------------------------
/test/node/crockford.spec.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from "vitest";
2 | import { fixULIDBase32, incrementBase32 } from "../../";
3 |
4 | describe("fixULIDBase32", () => {
5 | it("fixes mis-encoded ULIDs", () => {
6 | expect(fixULIDBase32("oLARYZ6-S41TSV4RRF-FQ69G5FAV")).to.equal(
7 | "01ARYZ6S41TSV4RRFFQ69G5FAV"
8 | );
9 | });
10 | });
11 |
12 | describe("incrementBase32", () => {
13 | it("increments correctly", () => {
14 | expect(incrementBase32("A109C")).toEqual("A109D");
15 | });
16 |
17 | it("carries correctly", () => {
18 | expect(incrementBase32("A1YZZ")).toEqual("A1Z00");
19 | });
20 |
21 | it("double increments correctly", () => {
22 | expect(incrementBase32(incrementBase32("A1YZZ"))).toEqual("A1Z01");
23 | });
24 |
25 | it("throws when it cannot increment", () => {
26 | expect(() => {
27 | incrementBase32("ZZZ");
28 | }).toThrow(/B32_ENC_INVALID/);
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/test/node/ulid.spec.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from "vitest";
2 | import { decodeTime, encodeTime, monotonicFactory, ulid, ULIDFactory } from "../../";
3 |
4 | const ULID_REXP = /^[0-7][0-9a-hjkmnp-tv-zA-HJKMNP-TV-Z]{25}$/;
5 |
6 | describe("decodeTime", function () {
7 | it("extracts a timestamp from a ULID", () => {
8 | expect(decodeTime("01ARYZ6S41TSV4RRFFQ69G5FAV")).to.equal(1469918176385);
9 | });
10 | });
11 |
12 | describe("encodeTime", function () {
13 | it("encodes a timestamp", () => {
14 | expect(encodeTime(1469918176385)).to.equal("01ARYZ6S41");
15 | });
16 | });
17 |
18 | describe("monotonicFactory", () => {
19 | function stubbedPrng() {
20 | return 0.96;
21 | }
22 |
23 | it("creates a factory", () => {
24 | const factory = monotonicFactory();
25 | expect(factory).toBeTypeOf("function");
26 | });
27 |
28 | describe("returned factory", () => {
29 | it("generates a ULID", () => {
30 | const factory = monotonicFactory();
31 | const id = factory();
32 | expect(id).toMatch(ULID_REXP);
33 | });
34 |
35 | describe("during single point in time", function () {
36 | const SEED_TIME = 1469918176385;
37 | const stubbedUlid: ULIDFactory = monotonicFactory(stubbedPrng);
38 |
39 | it("first call", function () {
40 | expect(stubbedUlid(SEED_TIME)).to.equal("01ARYZ6S41YYYYYYYYYYYYYYYY");
41 | });
42 |
43 | it("second call", function () {
44 | expect(stubbedUlid(SEED_TIME)).to.equal("01ARYZ6S41YYYYYYYYYYYYYYYZ");
45 | });
46 |
47 | it("third call", function () {
48 | expect(stubbedUlid(SEED_TIME)).to.equal("01ARYZ6S41YYYYYYYYYYYYYYZ0");
49 | });
50 |
51 | it("fourth call", function () {
52 | expect(stubbedUlid(SEED_TIME)).to.equal("01ARYZ6S41YYYYYYYYYYYYYYZ1");
53 | });
54 | });
55 |
56 | describe("with specific seedTime", function () {
57 | const stubbedUlid: ULIDFactory = monotonicFactory(stubbedPrng);
58 |
59 | it("first call", function () {
60 | expect(stubbedUlid(1469918176385)).to.equal("01ARYZ6S41YYYYYYYYYYYYYYYY");
61 | });
62 |
63 | it("second call with the same", function () {
64 | expect(stubbedUlid(1469918176385)).to.equal("01ARYZ6S41YYYYYYYYYYYYYYYZ");
65 | });
66 |
67 | it("third call with less than", function () {
68 | expect(stubbedUlid(100000000)).to.equal("01ARYZ6S41YYYYYYYYYYYYYYZ0");
69 | });
70 |
71 | it("fourth call with even more less than", function () {
72 | expect(stubbedUlid(10000)).to.equal("01ARYZ6S41YYYYYYYYYYYYYYZ1");
73 | });
74 |
75 | it("fifth call with 1 greater than", function () {
76 | expect(stubbedUlid(1469918176386)).to.equal("01ARYZ6S42YYYYYYYYYYYYYYYY");
77 | });
78 | });
79 | });
80 | });
81 |
82 | describe("ulid", () => {
83 | it("generates a ULID", () => {
84 | const id = ulid();
85 | expect(id).toMatch(ULID_REXP);
86 | });
87 | });
88 |
--------------------------------------------------------------------------------
/test/node/uuid.spec.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from "vitest";
2 | import { ulidToUUID, uuidToULID } from "../../";
3 |
4 | describe("ulidToUUID", () => {
5 | it("converts ULIDs to UUIDs", () => {
6 | expect(ulidToUUID("01ARYZ6S41TSV4RRFFQ69G5FAV")).to.equal(
7 | "01563DF3-6481-D676-4C61-EFB99302BD5B"
8 | );
9 | expect(ulidToUUID("01JQ4T23H220KM7X0B3V1109DQ")).to.equal(
10 | "0195C9A1-0E22-1027-43F4-0B1EC21025B7"
11 | );
12 | });
13 | });
14 |
15 | describe("uuidToULID", () => {
16 | it("converts UUIDs to ULIDs", () => {
17 | expect(uuidToULID("0195C9A4-2E32-C014-5F4F-A7CEF5BE83D5")).to.equal(
18 | "01JQ4T8BHJR0A5YKX7SVTVX0YN"
19 | );
20 | expect(uuidToULID("0195C9A4-74CC-5149-BCC4-0A556A0CF19D")).to.equal(
21 | "01JQ4T8X6CA54VSH0AANN0SWCX"
22 | );
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/tsconfig.dec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "declaration": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "esModuleInterop": true,
4 | "module": "node16",
5 | "moduleResolution": "node16",
6 | "declaration": false,
7 | "target": "es2020",
8 | "types": ["node"]
9 | },
10 | "include": [
11 | "./source/**/*"
12 | ],
13 | "exclude":[
14 | "node_modules"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/vitest.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vitest/config";
2 |
3 | export default defineConfig({
4 | test: {
5 | exclude: [],
6 | watch: false
7 | }
8 | });
9 |
--------------------------------------------------------------------------------