diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8c52ff9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..fbeff90 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @rzcoder diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7cf29ae --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,26 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 5 + groups: + dev-dependencies: + dependency-type: development + update-types: [minor, patch] + prod-dependencies: + dependency-type: production + update-types: [minor, patch] + ignore: + - dependency-name: '*' + update-types: [version-update:semver-major] + + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + groups: + actions: + patterns: ['*'] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..26c97ca --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,18 @@ +## Summary + + + +## Changes + + + +## Testing + +- [ ] `npm test` passes +- [ ] `npm run lint` passes +- [ ] `npm run typecheck` passes +- [ ] (If perf-sensitive) `npm run bench` results attached + +## Notes + + diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000..4e263c6 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,40 @@ +name: Benchmark + +on: + workflow_dispatch: + inputs: + ref: + description: 'Git ref to benchmark' + required: false + default: 'main' + +permissions: + contents: read + +jobs: + bench: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run build + - run: npm run bench | tee bench-results.txt + - uses: actions/upload-artifact@v4 + with: + name: bench-results-${{ inputs.ref }} + path: bench-results.txt + retention-days: 30 + - name: Append to job summary + run: | + { + echo '### Benchmark results (`${{ inputs.ref }}`)' + echo '```' + cat bench-results.txt + echo '```' + } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f169b75 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,101 @@ +name: CI + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run format:check + - run: npm run lint + + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + # Fail only on high/critical advisories in production deps. + # Dev-only moderate advisories (vitest/vite/esbuild dev-server chain) are tolerated. + - run: npm audit --audit-level=high --omit=dev + + typecheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run typecheck + + test: + name: test (Node ${{ matrix.node }} / ${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + node: [20, 22, 24] + include: + - os: windows-latest + node: 22 + - os: macos-latest + node: 22 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: npm + - run: npm ci + - run: npm run test:coverage + - name: Upload coverage + if: matrix.os == 'ubuntu-latest' && matrix.node == 22 + uses: codecov/codecov-action@v4 + with: + files: ./coverage/lcov.info + fail_ci_if_error: false + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run build + - name: Verify dual entrypoints exist + run: | + test -f dist/index.mjs + test -f dist/index.cjs + test -f dist/index.d.ts + test -f dist/index.d.cts + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + retention-days: 7 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0f21cda --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,45 @@ +name: Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + id-token: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + registry-url: 'https://registry.npmjs.org' + + - run: npm install -g npm@latest + - run: npm ci + - run: npm run lint + - run: npm run typecheck + - run: npm test + - run: npm run build + + - name: Verify tag matches package.json version + run: | + PKG_VERSION="v$(node -p "require('./package.json').version")" + TAG="${GITHUB_REF#refs/tags/}" + if [ "$PKG_VERSION" != "$TAG" ]; then + echo "Tag $TAG does not match package.json $PKG_VERSION" + exit 1 + fi + + - name: Publish to npm + run: npm publish --access public + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true diff --git a/.gitignore b/.gitignore index 263ba4d..3746a2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ +node_modules/ +dist/ +coverage/ +*.tsbuildinfo +.vitest-cache/ .DS_Store -.idea -node_modules/ \ No newline at end of file +.idea/ +.vscode/ +*.log +.env +.env.local diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..15692cb --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +engine-strict=true +save-exact=false diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e4e8224 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,57 @@ +# Changelog + +All notable changes to this project are documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Performance + +- Field-iteration path strings (`${path}.${key}`, `${path}[${i}]`) are no longer allocated on the happy path. `struct` / `array` codecs now wrap each child call in `try { ... } catch (e) { rethrowWithPrefix(e, segment) }` and build the error path only when something throws. Measured on Node 22: + - `nested` encode (compiled): -33% + - `list of list` encode (compiled): -59% + - `list of list` decode (compiled): -45% + - `hero` encode / decode (compiled): -17% each + +### Changed + +- Build: `tsup` now emits minified output. `dist/index.mjs` shrinks from ~15 KB to ~7.5 KB (~-50%); behaviour is unchanged. + +### Security + +- Decoded structs are now created with a `null` prototype, neutralising prototype-pollution risk if a schema is built from untrusted input that contains a `__proto__` key. +- String decoder now uses `TextDecoder` in `fatal: true` mode and throws `SCHEMA_MISMATCH` on malformed UTF-8 (previously such bytes were silently replaced with `U+FFFD`). +- `struct.encode` now asserts that `write()` emits exactly as many bytes as `measure()` reported. Defends against codec bugs leaking uninitialised memory from `Buffer.allocUnsafe`. +- CI now runs `npm audit --audit-level=high --omit=dev` and fails on high/critical advisories in production dependencies. + +## [0.1.0] - 2026-05-16 + +### Added +- Full TypeScript rewrite. +- New codec-token API: `t.bool`, `t.i8/u8/i16/u16/i32/u32`, `t.f32/f64`, `t.i64/u64`, `t.string`, `t.shortBytes`, `t.bytes`. +- Little-endian variants under `t.le.*`. +- `struct(schema)` factory that compiles a schema once and reuses it across `encode`/`decode`/`sizeOf` calls. +- Functional `encode(value, schema)` and `decode(buf, schema)`. +- `Infer` type helper that derives the TypeScript shape of decoded values from a schema. +- `DataStructError` with codes (`VALUE_OUT_OF_RANGE`, `STRING_TOO_LONG`, `BYTES_TOO_LONG`, `ARRAY_TOO_LONG`, `BUFFER_UNDERFLOW`, `SCHEMA_MISMATCH`, `INVALID_SCHEMA`), `path` (e.g. `$.skills[1].description`), and `offset` (for decode errors). +- Dual ESM + CommonJS build with separate `.d.mts` / `.d.cts` type declarations. +- Vitest test suite (wire-format goldens, roundtrip, error paths) with v8 coverage. +- `tinybench`-based benchmark suite. +- GitHub Actions: CI matrix (Node 20/22/24 on Linux + Node 22 on macOS/Windows), on-demand benchmark workflow, tag-triggered release with npm provenance. +- Dependabot, PR template, CODEOWNERS. + +### Changed +- Module format: package is now `"type": "module"`; entry points are `dist/index.mjs` (ESM) and `dist/index.cjs` (CJS). +- Minimum Node.js version: `>=20.9`. +- Encoder now allocates the output `Buffer` exactly once via a two-pass measure/write strategy (no `Buffer.concat`). +- Decoded `shortBytes` / `bytes` are returned as independent copies of the source memory rather than aliased views. +- Replaced deprecated `new Buffer(...)` calls with `Buffer.allocUnsafe` (for output) and `TextEncoder`/`TextDecoder` for string codecs. + +### Removed +- Legacy exports `DataTypes`, `DataReader`, `DataWriter` (clean break — see README migration table). +- `grunt`, `grunt-simple-mocha`, `jit-grunt`, `grunt-contrib-jshint`, `chai`, `benchmark`. + +### Wire format +- **Byte-identical** with `0.0.x` for the corresponding new codecs. The previous test suite's golden buffers are preserved as goldens in `test/wire-format.test.ts`. diff --git a/README.md b/README.md index 58a27a2..6697fe5 100644 --- a/README.md +++ b/README.md @@ -1,102 +1,179 @@ -# Data structure +# data-struct -Convert between JS object and Node.js buffer with rigidly predetermined scheme. +[![CI](https://github.com/rzcoder/data-struct/actions/workflows/ci.yml/badge.svg)](https://github.com/rzcoder/data-struct/actions/workflows/ci.yml) +[![npm](https://img.shields.io/npm/v/data-struct.svg)](https://www.npmjs.com/package/data-struct) -## Installing +Schema-driven binary serialization between JavaScript values and Node `Buffer`s. -```shell - npm install data-struct +- **Tiny.** No runtime dependencies. +- **Typed.** A schema infers the exact TypeScript shape of the decoded value via `Infer`. +- **Fast.** Two-pass encoder allocates the output buffer exactly once. +- **Dual-format.** Ships ESM + CommonJS + `.d.ts` for both. +- **Wire-stable.** Big-endian by default, byte-identical with prior `0.0.x` releases. + +## Install + +```sh +npm install data-struct ``` +Requires Node `>=20.9`. ## Usage -`require("data-struct")` exports just 3 namespaces: - - * `DataTypes` – dictonary of supported types: - * **boolean** – 1 byte - * **int8** – 1 byte - * **uint8** – 1 byte - * **int16** – 2 bytes - * **uint16** – 2 bytes - * **int32** – 4 bytes - * **uint32** – 4 bytes - * **float** – 4 bytes - * **double** – 8 bytes - * **string** – 2 bytes header + string bytes length (max length: 65535 bytes, **not string length!**) - * **shortBuffer** – 2 bytes header + buffer length (max length: 65535 bytes) - * **buffer** – 4 bytes header + buffer length (max length 4294967295 bytes) - * `DataReader(buffer, scheme)` – buffer -> object function. - * `DataWriter(object, scheme)` – object -> buffer function. - -## Example - - -```javascript - -var DataTypes = require("data-struct").DataTypes; -var DataReader = require("data-struct").DataReader; -var DataWriter = require("data-struct").DataWriter; - -var hero = { - id: 9, - name: 'CirnoBaka', - hp: 146, - skills: [ - { - id: 34, - description: 'freezing frogs' - }, - { - id: 16, - description: 'perfect math' - } - ], - playable: false, - experience: 99999999, - position: { - x: 2, - y: 3 - } -}; +```ts +import { struct, t, type Infer } from 'data-struct'; + +const Hero = struct({ + id: t.u32, + name: t.string, + hp: t.i16, + skills: [{ id: t.u16, description: t.string }], + playable: t.bool, + experience: t.u32, + position: { x: t.u16, y: t.u16 }, +}); + +type Hero = Infer; + +const buf = Hero.encode({ + id: 9, + name: 'CirnoBaka', + hp: 146, + skills: [ + { id: 34, description: 'freezing frogs' }, + { id: 16, description: 'perfect math' }, + ], + playable: false, + experience: 99_999_999, + position: { x: 2, y: 3 }, +}); + +const hero = Hero.decode(buf); // typed as Hero +``` + +Functional form, when you don't want to keep a compiled `struct` around: + +```ts +import { encode, decode, t } from 'data-struct'; + +const Map2D = [[t.u8]]; +const buf = encode([[0, 1, 0], [1, 0, 1]], Map2D); +const map = decode(buf, Map2D); // number[][] +``` + +## API + +### Codec tokens — `t` + +| Token | Bytes | TS type | Notes | +| ---------------- | ---------- | ------------ | ------------------------------------------- | +| `t.bool` | 1 | `boolean` | | +| `t.i8` / `t.u8` | 1 | `number` | | +| `t.i16` / `t.u16`| 2 | `number` | big-endian | +| `t.i32` / `t.u32`| 4 | `number` | big-endian | +| `t.f32` / `t.f64`| 4 / 8 | `number` | big-endian | +| `t.i64` / `t.u64`| 8 | `bigint` | big-endian | +| `t.string` | 2 + utf-8 | `string` | uint16 length prefix, max 65535 utf-8 bytes | +| `t.shortBytes` | 2 + n | `Uint8Array` | uint16 length prefix, max 65535 bytes | +| `t.bytes` | 4 + n | `Uint8Array` | uint32 length prefix, max 4294967295 bytes | + +Little-endian variants live under `t.le.*` (e.g. `t.le.u32`, `t.le.f64`, `t.le.string`). + +### Schema shape -var heroScheme = { - id: DataTypes.uint32, - name: DataTypes.string, - hp: DataTypes.int16, - skills: [{ - id: DataTypes.uint16, - description: DataTypes.string - }], - playable: DataTypes.boolean, - experience: DataTypes.uint32, - position: { - x: DataTypes.uint16, - y: DataTypes.uint16 - } +A schema is one of: + +- A codec token (`t.u32`). +- A single-element array `[Schema]` — encodes as a uint16 length prefix followed by N child encodings. +- A plain object — fields encoded in declared key order. + +```ts +type Schema = Codec | Schema[] | { [k: string]: Schema }; +type Infer = /* recursively maps each leaf to its TS type */; +``` + +### Functions + +```ts +struct(schema: S): { + schema: S; + encode(value: Infer): Buffer; + decode(input: Uint8Array): Infer; + sizeOf(value: Infer): number; }; -var heroBuf = DataWriter(hero, heroScheme); -var heroClone = DataReader(heroBuf, heroScheme); +encode(value: Infer, schema: S): Buffer; +decode(input: Uint8Array, schema: S): Infer; +``` + +`struct(schema)` compiles the schema tree once and reuses the compiled codec across calls — prefer it in hot paths. + +### Errors + +Validation throws `DataStructError` with a `code`: +| Code | When | +| --------------------- | ------------------------------------------------- | +| `VALUE_OUT_OF_RANGE` | Numeric value outside the leaf's range or non-int | +| `STRING_TOO_LONG` | UTF-8 byte length exceeds 65535 | +| `BYTES_TOO_LONG` | Bytes value exceeds the leaf's length cap | +| `ARRAY_TOO_LONG` | Array length exceeds 65535 | +| `BUFFER_UNDERFLOW` | Decode would read past the end of the input | +| `SCHEMA_MISMATCH` | Value shape does not match the schema | +| `INVALID_SCHEMA` | Schema itself is malformed | -//nested arrays -var map = [ - [0,1,0,0,1,1,1,1], - [1,1,0,0,0,1,1,1], - [1,1,0,0,0,0,1,1], - [1,1,1,1,0,0,1,1], - [0,1,1,0,0,0,1,1], - [0,0,0,0,0,1,1,1], - [0,0,0,0,1,1,1,1] -]; +Every error carries `path` (e.g. `$.skills[1].description`) and, for decode errors, `offset`. -var mapScheme = [[DataTypes.uint8]]; +## Wire format + +``` +bool : 1 byte 0x00 = false, anything else = true +i8/u8 : 1 byte +i16/u16 : 2 bytes BE +i32/u32 : 4 bytes BE +f32/f64 : 4 / 8 bytes BE +i64/u64 : 8 bytes BE +string : uint16 BE length || utf-8 bytes +shortBytes : uint16 BE length || raw bytes +bytes : uint32 BE length || raw bytes +array [E] : uint16 BE length || N encoded elements +object {…} : fields encoded in declared key order, no header +``` -var mapBuf = DataWriter(map, mapScheme); -var mapClone = DataReader(mapBuf, mapScheme); +LE variants (`t.le.*`) swap the byte order of length prefixes and the numeric payload. + +## Migration from `0.0.x` + +The 0.1.0 release is a full rewrite with a new API surface. The wire format is preserved, so buffers produced by older versions decode correctly under the new codecs. + +| Old | New | +| ------------------------- | ------------------------- | +| `DataTypes.boolean` | `t.bool` | +| `DataTypes.int8` / `uint8`| `t.i8` / `t.u8` | +| `DataTypes.int16`/`uint16`| `t.i16` / `t.u16` | +| `DataTypes.int32`/`uint32`| `t.i32` / `t.u32` | +| `DataTypes.float` | `t.f32` | +| `DataTypes.double` | `t.f64` | +| `DataTypes.string` | `t.string` | +| `DataTypes.shortBuffer` | `t.shortBytes` | +| `DataTypes.buffer` | `t.bytes` | +| `DataWriter(obj, scheme)` | `encode(obj, schema)` | +| `DataReader(buf, scheme)` | `decode(buf, schema)` | + +The legacy `DataTypes` / `DataReader` / `DataWriter` exports are removed. + +## Development + +```sh +npm install +npm run typecheck +npm run lint +npm test +npm run bench +npm run build ``` ## License -MIT \ No newline at end of file +MIT diff --git a/benchmark/benchmark.js b/benchmark/benchmark.js deleted file mode 100644 index 2ee970f..0000000 --- a/benchmark/benchmark.js +++ /dev/null @@ -1,52 +0,0 @@ -var Benchmark = require('benchmark'); -var suite = new Benchmark.Suite; - -DataTypes = require("../src/index").DataTypes; -DataReader = require("../src/index").DataReader; -DataWriter = require("../src/index").DataWriter; - - - -var suites = { - 'int32': { - object: 0x0F00FF00, - scheme: DataTypes.int32 - }, - 'string': { - object: 'Hello I String', - scheme: DataTypes.string - }, - 'nested': { - object: { nested: { nested2: { nested3: { nested4: { nested5: 42 } } } } }, - scheme: { nested: { nested2: { nested3: { nested4: { nested5: DataTypes.uint8 } } } } } - }, - 'list of list': { - object: [ - [90,10,101], - [20,30,400], - [100,110,1] - ], - scheme: [[DataTypes.int16]] - } -}; - -for(s in suites) { - var object = suites[s].object; - var scheme = suites[s].scheme; - - (function(s, object, scheme) { - var buf = null; - var obj = null; - suite.add(s + '#writing to buffer', function () { - buf = DataWriter(object, scheme); - }) - .add(s + '#reading from buffer', function () { - obj = DataReader(buf, scheme); - }); - })(s, object, scheme); -} - - -suite.on('cycle', function(event) { - console.log(String(event.target)); -}).run(); \ No newline at end of file diff --git a/benchmark/benchmark.ts b/benchmark/benchmark.ts new file mode 100644 index 0000000..54e947f --- /dev/null +++ b/benchmark/benchmark.ts @@ -0,0 +1,92 @@ +import { Bench } from 'tinybench'; +import { decode, encode, struct, t } from '../src/index.js'; +import type { Schema } from '../src/index.js'; + +interface Scenario { + readonly name: string; + readonly schema: Schema; + readonly value: unknown; +} + +const scenarios: Scenario[] = [ + { name: 'i32', schema: t.i32, value: 0x0f00ff00 }, + { name: 'string', schema: t.string, value: 'Hello I String' }, + { + name: 'nested', + schema: { nested: { nested2: { nested3: { nested4: { nested5: t.u8 } } } } }, + value: { nested: { nested2: { nested3: { nested4: { nested5: 42 } } } } }, + }, + { + name: 'list of list', + schema: [[t.i16]], + value: [ + [90, 10, 101], + [20, 30, 400], + [100, 110, 1], + ], + }, + { + name: 'hero (struct factory)', + schema: { + id: t.u32, + name: t.string, + hp: t.i16, + skills: [{ id: t.u16, description: t.string }], + playable: t.bool, + experience: t.u32, + position: { x: t.u16, y: t.u16 }, + }, + value: { + id: 9, + name: 'CirnoBaka', + hp: 146, + skills: [ + { id: 34, description: 'freezing frogs' }, + { id: 16, description: 'perfect math' }, + ], + playable: false, + experience: 99999999, + position: { x: 2, y: 3 }, + }, + }, +]; + +async function main(): Promise { + const bench = new Bench({ time: 500 }); + + for (const scenario of scenarios) { + const codec = struct(scenario.schema); + const buffer = encode(scenario.value as never, scenario.schema); + + bench + .add(`${scenario.name} :: encode (loose)`, () => { + encode(scenario.value as never, scenario.schema); + }) + .add(`${scenario.name} :: encode (compiled struct)`, () => { + codec.encode(scenario.value as never); + }) + .add(`${scenario.name} :: decode (loose)`, () => { + decode(buffer, scenario.schema); + }) + .add(`${scenario.name} :: decode (compiled struct)`, () => { + codec.decode(buffer); + }); + } + + await bench.run(); + + console.log('\n=== data-struct benchmark ==='); + console.table( + bench.tasks.map((task) => ({ + task: task.name, + 'ops/sec': task.result?.hz.toFixed(0), + 'avg (ns)': task.result?.mean ? (task.result.mean * 1e6).toFixed(2) : '—', + samples: task.result?.samples.length, + })), + ); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..66bc5c4 --- /dev/null +++ b/biome.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignore": ["dist", "coverage", "node_modules", "*.tgz"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 100, + "lineEnding": "lf" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error", + "noUnusedImports": "error" + }, + "style": { + "useImportType": "error", + "useNodejsImportProtocol": "error", + "useConsistentArrayType": { "level": "error", "options": { "syntax": "shorthand" } }, + "noNonNullAssertion": "off", + "noParameterAssign": "off" + }, + "suspicious": { + "noExplicitAny": "warn" + }, + "complexity": { + "noBannedTypes": "off" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "semicolons": "always", + "trailingCommas": "all", + "arrowParentheses": "always" + } + } +} diff --git a/examples/01-basics.ts b/examples/01-basics.ts new file mode 100644 index 0000000..5ae563d --- /dev/null +++ b/examples/01-basics.ts @@ -0,0 +1,17 @@ +import { decode, encode, struct, t } from '../src/index.js'; + +// Single primitive: a 4-byte big-endian unsigned int. +const u32Buf = encode(0xdead_beef, t.u32); +console.log('u32 buffer :', u32Buf.toString('hex')); +console.log('u32 decoded:', decode(u32Buf, t.u32).toString(16)); + +// String: 2-byte length prefix followed by UTF-8 bytes. +const strBuf = encode('hello', t.string); +console.log('string buffer :', strBuf.toString('hex')); +console.log('string decoded:', decode(strBuf, t.string)); + +// Object: fields encoded in declared key order, no header. +const User = struct({ id: t.u32, name: t.string, active: t.bool }); +const userBuf = User.encode({ id: 7, name: 'ada', active: true }); +console.log('user buffer :', userBuf.toString('hex')); +console.log('user decoded:', User.decode(userBuf)); diff --git a/examples/02-hero.ts b/examples/02-hero.ts new file mode 100644 index 0000000..21d8bb1 --- /dev/null +++ b/examples/02-hero.ts @@ -0,0 +1,34 @@ +import { struct, t } from '../src/index.js'; +import type { Infer } from '../src/index.js'; + +const Hero = struct({ + id: t.u32, + name: t.string, + hp: t.i16, + skills: [{ id: t.u16, description: t.string }], + playable: t.bool, + experience: t.u32, + position: { x: t.u16, y: t.u16 }, +}); + +type Hero = Infer; + +const cirno: Hero = { + id: 9, + name: 'CirnoBaka', + hp: 146, + skills: [ + { id: 34, description: 'freezing frogs' }, + { id: 16, description: 'perfect math' }, + ], + playable: false, + experience: 99_999_999, + position: { x: 2, y: 3 }, +}; + +const buf = Hero.encode(cirno); +const decoded = Hero.decode(buf); + +console.log(`encoded ${buf.byteLength} bytes:`, buf.toString('hex')); +console.log('decoded hero :', decoded); +console.log('roundtrip eq :', JSON.stringify(cirno) === JSON.stringify(decoded)); diff --git a/examples/03-functional.ts b/examples/03-functional.ts new file mode 100644 index 0000000..a7a763e --- /dev/null +++ b/examples/03-functional.ts @@ -0,0 +1,19 @@ +import { decode, encode, t } from '../src/index.js'; + +// One-shot encoding/decoding without keeping a compiled struct around. +// Schemas are plain values, so they compose freely. + +const Map2D = [[t.u8]]; +const map: number[][] = [ + [0, 1, 0], + [1, 0, 1], +]; +const mapBuf = encode(map, Map2D); +console.log('Map2D buffer :', mapBuf.toString('hex')); +console.log('Map2D decoded:', decode(mapBuf, Map2D)); + +const Names = [t.string]; +const names = ['alice', 'bob', 'carol']; +const namesBuf = encode(names, Names); +console.log('Names buffer :', namesBuf.toString('hex')); +console.log('Names decoded:', decode(namesBuf, Names)); diff --git a/examples/04-errors.ts b/examples/04-errors.ts new file mode 100644 index 0000000..d05ba95 --- /dev/null +++ b/examples/04-errors.ts @@ -0,0 +1,29 @@ +import { DataStructError, decode, encode, t } from '../src/index.js'; + +function runCase(label: string, fn: () => unknown): void { + try { + fn(); + console.log(`[${label}] no error — unexpected`); + } catch (err) { + if (!(err instanceof DataStructError)) throw err; + const offset = err.offset !== undefined ? ` offset=${err.offset}` : ''; + console.log(`[${label}] code=${err.code} path=${err.path}${offset} :: ${err.message}`); + } +} + +// Numeric value outside the leaf's range. +runCase('VALUE_OUT_OF_RANGE', () => encode(300, t.u8)); + +// UTF-8 byte length exceeds the 65535-byte string limit. +runCase('STRING_TOO_LONG', () => encode('a'.repeat(65_536), t.string)); + +// Array length exceeds the 65535-element limit. +runCase('ARRAY_TOO_LONG', () => encode(new Array(65_536).fill(0), [t.u8])); + +// Value shape does not match the schema (name should be a string). +const Person = { id: t.u32, name: t.string }; +type PersonValue = { id: number; name: string }; +runCase('SCHEMA_MISMATCH', () => encode({ id: 1, name: 42 } as unknown as PersonValue, Person)); + +// Decode would read past the end of the input — length prefix says 5, only 2 follow. +runCase('BUFFER_UNDERFLOW', () => decode(new Uint8Array([0x00, 0x05, 0x68, 0x65]), t.string)); diff --git a/examples/05-little-endian.ts b/examples/05-little-endian.ts new file mode 100644 index 0000000..d67fc41 --- /dev/null +++ b/examples/05-little-endian.ts @@ -0,0 +1,19 @@ +import { decode, encode, t } from '../src/index.js'; + +// Big-endian (default) vs little-endian for the same value. +const value = 0x1122_3344; +const beBuf = encode(value, t.u32); +const leBuf = encode(value, t.le.u32); + +console.log('be u32:', beBuf.toString('hex')); // 11223344 +console.log('le u32:', leBuf.toString('hex')); // 44332211 + +// The length prefix on strings also flips with t.le.string. +const beStr = encode('hi', t.string); +const leStr = encode('hi', t.le.string); +console.log('be string:', beStr.toString('hex')); // 00026869 +console.log('le string:', leStr.toString('hex')); // 02006869 + +// Roundtrip via the LE codec. +console.log('le u32 decoded:', decode(leBuf, t.le.u32).toString(16)); +console.log('le string decoded:', decode(leStr, t.le.string)); diff --git a/examples/06-size-of.ts b/examples/06-size-of.ts new file mode 100644 index 0000000..7a09547 --- /dev/null +++ b/examples/06-size-of.ts @@ -0,0 +1,20 @@ +import { struct, t } from '../src/index.js'; + +const Row = struct({ id: t.u32, name: t.string }); + +// sizeOf returns the exact byte length encode() will produce for that value. +const single = { id: 42, name: 'hello' }; +console.log('single sizeOf :', Row.sizeOf(single)); // 4 (u32) + 2 (len) + 5 (utf-8) = 11 +console.log('single encoded:', Row.encode(single).byteLength); + +// Pre-compute total bytes for a batch before allocating your own output buffer. +const batch = Array.from({ length: 5 }, (_, i) => ({ id: i, name: `item-${i}` })); +let totalRowBytes = 0; +for (const item of batch) totalRowBytes += Row.sizeOf(item); +console.log(`sum of ${batch.length} row sizes:`, totalRowBytes); + +// When you encode the array as a single value, the wire format adds 2 bytes +// for the array length prefix, so the result is totalRowBytes + 2. +const Batch = struct([{ id: t.u32, name: t.string }]); +const batchBuf = Batch.encode(batch); +console.log('encoded batch :', batchBuf.byteLength, '(rows + 2-byte array length prefix)'); diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..32861e6 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,22 @@ +# examples + +Runnable demos of the `data-struct` API. Each file is self-contained — run any of them with: + +```sh +npx tsx examples/01-basics.ts +``` + +| File | Shows | +| --- | --- | +| [01-basics.ts](01-basics.ts) | Primitive codecs (`t.u32`, `t.string`, `t.bool`) and a small `struct({...})` roundtrip. | +| [02-hero.ts](02-hero.ts) | Nested object + array of objects, with the decoded value typed via `Infer`. | +| [03-functional.ts](03-functional.ts) | Top-level `encode` / `decode` for one-shot use, without keeping a compiled struct. | +| [04-errors.ts](04-errors.ts) | Each `DataStructError` kind triggered and inspected (`code`, `path`, `offset`). | +| [05-little-endian.ts](05-little-endian.ts) | `t.le.*` variants and how the bytes differ from the big-endian default. | +| [06-size-of.ts](06-size-of.ts) | `sizeOf()` for pre-budgeting buffer sizes. | + +Examples import from `../src/index.js` so they work against the in-repo source. In your own project, swap that for: + +```ts +import { struct, t } from 'data-struct'; +``` diff --git a/gruntfile.js b/gruntfile.js deleted file mode 100644 index 1cb1aa5..0000000 --- a/gruntfile.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = function(grunt) { - grunt.initConfig({ - jshint: { - options: { - }, - default: { - files: { - src: ['src/**/*.js', '!src/libs/**/*'] - } - }, - libs: { - files: { - src: ['src/libs/**/*'] - } - } - }, - - simplemocha: { - options: { - reporter: 'List', - ui: 'tdd' - }, - all: { src: ['test/**/*.js'] } - } - }); - - require('jit-grunt')(grunt, { - 'simplemocha': 'grunt-simple-mocha' - }); - - - grunt.registerTask('lint', ['jshint:default']); - grunt.registerTask('test', ['simplemocha']); - - grunt.registerTask('default', ['lint', 'test']); -}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..00a5e66 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3927 @@ +{ + "name": "data-struct", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "data-struct", + "version": "0.1.0", + "license": "MIT", + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@types/node": "^20.17.0", + "@vitest/coverage-v8": "^2.1.8", + "tinybench": "^3.1.0", + "tsup": "^8.3.5", + "tsx": "^4.19.2", + "typescript": "^5.7.2", + "vitest": "^2.1.8" + }, + "engines": { + "node": ">=20.9" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@biomejs/biome": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz", + "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==", + "dev": true, + "hasInstallScript": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.9.4", + "@biomejs/cli-darwin-x64": "1.9.4", + "@biomejs/cli-linux-arm64": "1.9.4", + "@biomejs/cli-linux-arm64-musl": "1.9.4", + "@biomejs/cli-linux-x64": "1.9.4", + "@biomejs/cli-linux-x64-musl": "1.9.4", + "@biomejs/cli-win32-arm64": "1.9.4", + "@biomejs/cli-win32-x64": "1.9.4" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", + "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", + "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz", + "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz", + "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", + "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", + "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", + "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", + "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", + "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.9.tgz", + "integrity": "sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^0.2.3", + "debug": "^4.3.7", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.12", + "magicast": "^0.3.5", + "std-env": "^3.8.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "2.1.9", + "vitest": "2.1.9" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bundle-require": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", + "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fix-dts-default-cjs-exports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", + "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "rollup": "^4.34.8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz", + "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^10.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinybench": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-3.1.1.tgz", + "integrity": "sha512-74pmf47HY/bHqamcCMGris+1AtGGsqTZ3Hc/UK4QvSmRuf/9PIF9753+c8XBh7JfX2r9KeZtVjOYjd6vFpc0qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tsup": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", + "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.27.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "^0.7.6", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsx": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.0.tgz", + "integrity": "sha512-8ccZMPD69s1AbKXx0C5ddTNZfNjwV04iIKgjZmKfKxMynEtSYcK0Lh7iQFh53fI5Yu4pb9usgAiqyPmEONaALg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-node/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest/node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/package.json b/package.json index 22e36f0..97d93aa 100644 --- a/package.json +++ b/package.json @@ -1,35 +1,75 @@ { "name": "data-struct", - "version": "0.0.11", - "description": "Convert between JS object and Node.js buffer", - "main": "src/index.js", + "version": "0.1.0", + "description": "Schema-driven binary serialization between JS objects and Node Buffers", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.cts", + "exports": { + ".": { + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + }, + "./package.json": "./package.json" + }, + "files": ["dist", "README.md", "LICENSE", "CHANGELOG.md"], + "engines": { + "node": ">=20.9" + }, + "sideEffects": false, "scripts": { - "test": "grunt test" + "build": "tsup", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", + "bench": "tsx benchmark/benchmark.ts", + "lint": "biome check .", + "lint:fix": "biome check --write .", + "format": "biome format --write .", + "format:check": "biome format .", + "typecheck": "tsc --noEmit", + "prepublishOnly": "npm run typecheck && npm run lint && npm test && npm run build" }, "repository": { "type": "git", - "url": "https://github.com/rzcoder/data-struct.git" + "url": "git+https://github.com/rzcoder/data-struct.git" }, "keywords": [ - "node", + "binary", "buffer", - "object", + "codec", + "decode", + "encode", + "schema", "serialization", - "convert" + "struct", + "typescript" ], "author": "rzcoder", "license": "MIT", "bugs": { "url": "https://github.com/rzcoder/data-struct/issues" }, - "homepage": "https://github.com/rzcoder/data-struct", - "devDependencies": { - "grunt": "^0.4.4", - "grunt-simple-mocha": "^0.4.0", - "jit-grunt": "^0.3.2", - "chai": "^1.9.1", - "grunt-contrib-jshint": "^0.9.2", - "benchmark": "^1.0.0" + "homepage": "https://github.com/rzcoder/data-struct#readme", + "publishConfig": { + "access": "public", + "provenance": true }, - "dependencies": {} + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@types/node": "^20.17.0", + "@vitest/coverage-v8": "^2.1.8", + "tinybench": "^3.1.0", + "tsup": "^8.3.5", + "tsx": "^4.19.2", + "typescript": "^5.7.2", + "vitest": "^2.1.8" + } } diff --git a/src/codecs.ts b/src/codecs.ts new file mode 100644 index 0000000..9d5e178 --- /dev/null +++ b/src/codecs.ts @@ -0,0 +1,325 @@ +import { DataStructError } from './errors.js'; +import type { Codec, CodecImpl } from './types.js'; + +const textEncoder = new TextEncoder(); +const textDecoder = new TextDecoder('utf-8', { fatal: true }); + +const U8_MAX = 0xff; +const U16_MAX = 0xffff; +const U32_MAX = 0xffffffff; +const I8_MIN = -0x80; +const I8_MAX = 0x7f; +const I16_MIN = -0x8000; +const I16_MAX = 0x7fff; +const I32_MIN = -0x80000000; +const I32_MAX = 0x7fffffff; +const I64_MIN = -(1n << 63n); +const I64_MAX = (1n << 63n) - 1n; +const U64_MAX = (1n << 64n) - 1n; + +// Leaves throw without path context; parent codecs (struct/array) prefix +// the segment via prefixPath() in struct.ts. This keeps the happy path +// allocation-free for the field-iteration string concatenations. + +function ensureCapacity(view: DataView, offset: number, need: number): void { + if (offset + need > view.byteLength) { + throw new DataStructError( + 'BUFFER_UNDERFLOW', + `need ${need} byte(s) at offset ${offset}, but buffer has ${view.byteLength}`, + { offset }, + ); + } +} + +function ensureInt(value: number, min: number, max: number, type: string): void { + if (typeof value !== 'number' || !Number.isInteger(value) || value < min || value > max) { + throw new DataStructError( + 'VALUE_OUT_OF_RANGE', + `${type} requires integer in [${min}, ${max}], got ${value}`, + ); + } +} + +function ensureFiniteNumber(value: number, type: string): void { + if (typeof value !== 'number') { + throw new DataStructError('VALUE_OUT_OF_RANGE', `${type} requires number, got ${typeof value}`); + } +} + +function ensureBigInt(value: bigint, min: bigint, max: bigint, type: string): void { + if (typeof value !== 'bigint' || value < min || value > max) { + throw new DataStructError( + 'VALUE_OUT_OF_RANGE', + `${type} requires bigint in [${min}, ${max}], got ${value}`, + ); + } +} + +function ensureUint8Array(value: unknown, type: string): asserts value is Uint8Array { + if (!(value instanceof Uint8Array)) { + throw new DataStructError( + 'SCHEMA_MISMATCH', + `${type} requires Uint8Array, got ${typeof value}`, + ); + } +} + +function fixed( + tag: number, + size: number, + write: (view: DataView, offset: number, value: T) => void, + read: (view: DataView, offset: number) => T, + validate: (value: T) => void, +): Codec { + const impl: CodecImpl = { + measure: () => size, + write(view, _bytes, offset, value) { + validate(value); + write(view, offset, value); + return offset + size; + }, + read(view, _bytes, offset) { + ensureCapacity(view, offset, size); + return { value: read(view, offset), offset: offset + size }; + }, + }; + return { tag, impl }; +} + +const boolImpl: CodecImpl = { + measure: () => 1, + write(view, _bytes, offset, value) { + if (typeof value !== 'boolean') { + throw new DataStructError('SCHEMA_MISMATCH', `bool requires boolean, got ${typeof value}`); + } + view.setUint8(offset, value ? 1 : 0); + return offset + 1; + }, + read(view, _bytes, offset) { + ensureCapacity(view, offset, 1); + return { value: view.getInt8(offset) !== 0, offset: offset + 1 }; + }, +}; + +function makeString(littleEndian: boolean, tag: number): Codec { + const impl: CodecImpl = { + measure(value, plan) { + if (typeof value !== 'string') { + throw new DataStructError('SCHEMA_MISMATCH', `string requires string, got ${typeof value}`); + } + const encoded = textEncoder.encode(value); + if (encoded.byteLength > U16_MAX) { + throw new DataStructError( + 'STRING_TOO_LONG', + `string UTF-8 byte length ${encoded.byteLength} exceeds 65535`, + ); + } + plan.strings.push(encoded); + return 2 + encoded.byteLength; + }, + write(view, bytes, offset, _value, plan) { + const encoded = plan.strings[plan.cursor++] as Uint8Array; + view.setUint16(offset, encoded.byteLength, littleEndian); + offset += 2; + bytes.set(encoded, offset); + return offset + encoded.byteLength; + }, + read(view, bytes, offset) { + ensureCapacity(view, offset, 2); + const length = view.getUint16(offset, littleEndian); + offset += 2; + ensureCapacity(view, offset, length); + let value: string; + try { + value = textDecoder.decode(bytes.subarray(offset, offset + length)); + } catch (cause) { + throw new DataStructError('SCHEMA_MISMATCH', 'invalid UTF-8 in string field', { + offset, + cause, + }); + } + return { value, offset: offset + length }; + }, + }; + return { tag, impl }; +} + +function makeShortBytes(littleEndian: boolean, tag: number): Codec { + const impl: CodecImpl = { + measure(value) { + ensureUint8Array(value, 'shortBytes'); + if (value.byteLength > U16_MAX) { + throw new DataStructError( + 'BYTES_TOO_LONG', + `shortBytes length ${value.byteLength} exceeds 65535`, + ); + } + return 2 + value.byteLength; + }, + write(view, bytes, offset, value) { + view.setUint16(offset, value.byteLength, littleEndian); + offset += 2; + bytes.set(value, offset); + return offset + value.byteLength; + }, + read(view, bytes, offset) { + ensureCapacity(view, offset, 2); + const length = view.getUint16(offset, littleEndian); + offset += 2; + ensureCapacity(view, offset, length); + const value = new Uint8Array(length); + value.set(bytes.subarray(offset, offset + length)); + return { value, offset: offset + length }; + }, + }; + return { tag, impl }; +} + +function makeBytes(littleEndian: boolean, tag: number): Codec { + const impl: CodecImpl = { + measure(value) { + ensureUint8Array(value, 'bytes'); + if (value.byteLength > U32_MAX) { + throw new DataStructError( + 'BYTES_TOO_LONG', + `bytes length ${value.byteLength} exceeds 4294967295`, + ); + } + return 4 + value.byteLength; + }, + write(view, bytes, offset, value) { + view.setUint32(offset, value.byteLength, littleEndian); + offset += 4; + bytes.set(value, offset); + return offset + value.byteLength; + }, + read(view, bytes, offset) { + ensureCapacity(view, offset, 4); + const length = view.getUint32(offset, littleEndian); + offset += 4; + ensureCapacity(view, offset, length); + const value = new Uint8Array(length); + value.set(bytes.subarray(offset, offset + length)); + return { value, offset: offset + length }; + }, + }; + return { tag, impl }; +} + +function intCodec( + tag: number, + size: number, + signed: boolean, + min: number, + max: number, + name: string, + littleEndian: boolean, +): Codec { + const setters: Record void> = { + 'i:1': (v, o, x) => v.setInt8(o, x), + 'u:1': (v, o, x) => v.setUint8(o, x), + 'i:2': (v, o, x, le) => v.setInt16(o, x, le), + 'u:2': (v, o, x, le) => v.setUint16(o, x, le), + 'i:4': (v, o, x, le) => v.setInt32(o, x, le), + 'u:4': (v, o, x, le) => v.setUint32(o, x, le), + }; + const getters: Record number> = { + 'i:1': (v, o) => v.getInt8(o), + 'u:1': (v, o) => v.getUint8(o), + 'i:2': (v, o, le) => v.getInt16(o, le), + 'u:2': (v, o, le) => v.getUint16(o, le), + 'i:4': (v, o, le) => v.getInt32(o, le), + 'u:4': (v, o, le) => v.getUint32(o, le), + }; + const key = `${signed ? 'i' : 'u'}:${size}`; + const setter = setters[key] as (view: DataView, o: number, v: number, le: boolean) => void; + const getter = getters[key] as (view: DataView, o: number, le: boolean) => number; + return fixed( + tag, + size, + (view, offset, value) => setter(view, offset, value, littleEndian), + (view, offset) => getter(view, offset, littleEndian), + (value) => ensureInt(value, min, max, name), + ); +} + +function floatCodec(tag: number, size: 4 | 8, name: string, littleEndian: boolean): Codec { + if (size === 4) { + return fixed( + tag, + 4, + (view, offset, value) => view.setFloat32(offset, value, littleEndian), + (view, offset) => view.getFloat32(offset, littleEndian), + (value) => ensureFiniteNumber(value, name), + ); + } + return fixed( + tag, + 8, + (view, offset, value) => view.setFloat64(offset, value, littleEndian), + (view, offset) => view.getFloat64(offset, littleEndian), + (value) => ensureFiniteNumber(value, name), + ); +} + +function bigIntCodec( + tag: number, + signed: boolean, + name: string, + littleEndian: boolean, +): Codec { + const min = signed ? I64_MIN : 0n; + const max = signed ? I64_MAX : U64_MAX; + return fixed( + tag, + 8, + (view, offset, value) => { + if (signed) view.setBigInt64(offset, value, littleEndian); + else view.setBigUint64(offset, value, littleEndian); + }, + (view, offset) => + signed ? view.getBigInt64(offset, littleEndian) : view.getBigUint64(offset, littleEndian), + (value) => ensureBigInt(value, min, max, name), + ); +} + +const BE = false; +const LE = true; + +const beCodecs = { + bool: { tag: 0x000, impl: boolImpl } as Codec, + i8: intCodec(0x010, 1, true, I8_MIN, I8_MAX, 'i8', BE), + u8: intCodec(0x011, 1, false, 0, U8_MAX, 'u8', BE), + i16: intCodec(0x020, 2, true, I16_MIN, I16_MAX, 'i16', BE), + u16: intCodec(0x021, 2, false, 0, U16_MAX, 'u16', BE), + i32: intCodec(0x030, 4, true, I32_MIN, I32_MAX, 'i32', BE), + u32: intCodec(0x031, 4, false, 0, U32_MAX, 'u32', BE), + f32: floatCodec(0x040, 4, 'f32', BE), + f64: floatCodec(0x041, 8, 'f64', BE), + i64: bigIntCodec(0x050, true, 'i64', BE), + u64: bigIntCodec(0x051, false, 'u64', BE), + string: makeString(BE, 0x200), + shortBytes: makeShortBytes(BE, 0x210), + bytes: makeBytes(BE, 0x211), +}; + +const leCodecs = { + i16: intCodec(0x1020, 2, true, I16_MIN, I16_MAX, 'le.i16', LE), + u16: intCodec(0x1021, 2, false, 0, U16_MAX, 'le.u16', LE), + i32: intCodec(0x1030, 4, true, I32_MIN, I32_MAX, 'le.i32', LE), + u32: intCodec(0x1031, 4, false, 0, U32_MAX, 'le.u32', LE), + f32: floatCodec(0x1040, 4, 'le.f32', LE), + f64: floatCodec(0x1041, 8, 'le.f64', LE), + i64: bigIntCodec(0x1050, true, 'le.i64', LE), + u64: bigIntCodec(0x1051, false, 'le.u64', LE), + string: makeString(LE, 0x1200), + shortBytes: makeShortBytes(LE, 0x1210), + bytes: makeBytes(LE, 0x1211), +}; + +export const t = { + ...beCodecs, + le: leCodecs, +} as const; + +export type TypeRegistry = typeof t; diff --git a/src/dataReader.js b/src/dataReader.js deleted file mode 100644 index 1490d52..0000000 --- a/src/dataReader.js +++ /dev/null @@ -1,128 +0,0 @@ -var DataTypes = require('./dataTypes'); - -var typesTable = {}; - -typesTable[DataTypes.boolean] = function (pointer, buffer) { - var res = buffer.readInt8(pointer.offset); - pointer.offset += 1; - return !!res; -}; - -typesTable[DataTypes.int8] = function (pointer, buffer) { - var res = buffer.readInt8(pointer.offset); - pointer.offset += 1; - return res; -}; - -typesTable[DataTypes.uint8] = function (pointer, buffer) { - var res = buffer.readUInt8(pointer.offset); - pointer.offset += 1; - return res; -}; - -typesTable[DataTypes.int16] = function (pointer, buffer) { - var res = buffer.readInt16BE(pointer.offset); - pointer.offset += 2; - return res; -}; - -typesTable[DataTypes.uint16] = function (pointer, buffer) { - var res = buffer.readUInt16BE(pointer.offset); - pointer.offset += 2; - return res; -}; - -typesTable[DataTypes.int32] = function (pointer, buffer) { - var res = buffer.readInt32BE(pointer.offset); - pointer.offset += 4; - return res; -}; - -typesTable[DataTypes.uint32] = function (pointer, buffer) { - var res = buffer.readUInt32BE(pointer.offset); - pointer.offset += 4; - return res; -}; - -typesTable[DataTypes.float] = function (pointer, buffer) { - var res = buffer.readFloatBE(pointer.offset); - pointer.offset += 4; - return res; -}; - -typesTable[DataTypes.double] = function (pointer, buffer) { - var res = buffer.readDoubleBE(pointer.offset); - pointer.offset += 8; - return res; -}; - -typesTable[DataTypes.string] = function (pointer, buffer) { - var length; - length = buffer.readUInt16BE(pointer.offset); - pointer.offset += 2; - var res = buffer.toString('utf8', pointer.offset, pointer.offset + length); - pointer.offset += length; - return res; -}; - -typesTable[DataTypes.shortBuffer] = function (pointer, buffer) { - var length; - length = buffer.readUInt16BE(pointer.offset); - pointer.offset += 2; - var res = buffer.slice(pointer.offset, pointer.offset + length); - pointer.offset += length; - return res; -}; - -typesTable[DataTypes.buffer] = function (pointer, buffer) { - var length; - length = buffer.readUInt32BE(pointer.offset); - pointer.offset += 4; - var res = buffer.slice(pointer.offset, pointer.offset + length); - pointer.offset += length; - return res; -}; - -function list (pointer, buffer, scheme) { - var length = buffer.readUInt16BE(pointer.offset); - pointer.offset += 2; - - var res = []; - while (length--) { - res.push(structureReader(pointer, buffer, scheme)); - } - return res; -} - -var structureReader = function (pointer, buffer, scheme) { - var res = {}; - - if (arguments.length === 2) { - scheme = buffer; - buffer = pointer; - pointer = { - offset: 0 - }; - } - - if(typeof scheme === 'number') { - res = typesTable[scheme](pointer, buffer); - } else if (Array.isArray(scheme)) { - res = list(pointer, buffer, scheme[0]); - } else { - for (var el in scheme) { - var s = scheme[el]; - if (typeof s === 'number') { - res[el] = typesTable[s](pointer, buffer); - } else if (Array.isArray(s)) { - res[el] = list(pointer, buffer, s[0]); - } else { - res[el] = structureReader(pointer, buffer, s); - } - } - } - - return res; -}; - -module.exports = structureReader; \ No newline at end of file diff --git a/src/dataTypes.js b/src/dataTypes.js deleted file mode 100644 index 1f1a440..0000000 --- a/src/dataTypes.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - boolean: 0x000, - int8: 0x010, - uint8: 0x011, - int16: 0x020, - uint16: 0x021, - int32: 0x030, - uint32: 0x031, - float: 0x040, - double: 0x041, - - string: 0x200, - shortBuffer: 0x210, - buffer: 0x211 -}; \ No newline at end of file diff --git a/src/dataWriter.js b/src/dataWriter.js deleted file mode 100644 index 9961e83..0000000 --- a/src/dataWriter.js +++ /dev/null @@ -1,141 +0,0 @@ -var DataTypes = require('./dataTypes'); - -var typesTable = {}; - -typesTable[DataTypes.boolean] = function (value) { - var buffer = new Buffer(1); - buffer.writeInt8(value, 0); - return buffer; -}; - -typesTable[DataTypes.int8] = function (value) { - var buffer = new Buffer(1); - buffer.writeInt8(value, 0); - return buffer; -}; - -typesTable[DataTypes.uint8] = function (value) { - var buffer = new Buffer(1); - buffer.writeUInt8(value, 0); - return buffer; -}; - -typesTable[DataTypes.int16] = function (value) { - var buffer = new Buffer(2); - buffer.writeInt16BE(value, 0); - return buffer; -}; - -typesTable[DataTypes.uint16] = function (value) { - var buffer = new Buffer(2); - buffer.writeUInt16BE(value, 0); - return buffer; -}; - -typesTable[DataTypes.int32] = function (value) { - var buffer = new Buffer(4); - buffer.writeInt32BE(value, 0); - return buffer; -}; - -typesTable[DataTypes.uint32] = function (value) { - var buffer = new Buffer(4); - buffer.writeUInt32BE(value, 0); - return buffer; -}; - -typesTable[DataTypes.float] = function (value) { - var buffer = new Buffer(4); - buffer.writeFloatBE(value, 0); - return buffer; -}; - -typesTable[DataTypes.double] = function (value) { - var buffer = new Buffer(8); - buffer.writeDoubleBE(value, 0); - return buffer; -}; - -typesTable[DataTypes.string] = function (value) { - var buffer = new Buffer(value); - var length = buffer.length; - if (length > 0xFFFF) { - throw Error('String too long'); - } - - var res = new Buffer(2 + length); - res.writeUInt16BE(length, 0); - buffer.copy(res, 2); - - return res; -}; - -typesTable[DataTypes.shortBuffer] = function (value) { - var length = value.length; - if (length > 0xFFFF) { - throw Error('Buffer too long'); - } - - var res = new Buffer(2 + length); - res.writeUInt16BE(length, 0); - value.copy(res, 2); - - return res; -}; - -typesTable[DataTypes.buffer] = function (value) { - var length = value.length; - - if (length > 0xFFFFFFFF) { - throw Error('Buffer too long'); - } - - var res = new Buffer(4 + length); - res.writeUInt32BE(length, 0); - value.copy(res, 4); - - return res; -}; - -function list (value, scheme) { - if (!Array.isArray(value)) { - throw Error('Value is not array.'); - } - - var res = []; - var lenBuf = new Buffer(2); - var length = value.length; - lenBuf.writeUInt16BE(length,0); - res.push(lenBuf); - - for(var i = 0; i < length; i++) { - res.push(structureWriter(value[i], scheme)); - } - - return Buffer.concat(res); -} - -var structureWriter = function (object, scheme) { - var res = []; - - if(typeof scheme === 'number') { - res.push(typesTable[scheme](object)); - } else if(Array.isArray(scheme)) { - res.push(list(object, scheme[0])); - } else { - for (var el in scheme) { - var s = scheme[el]; - if (typeof s === 'number') { - res.push(typesTable[s](object[el])); - } else if (Array.isArray(s)) { - res.push(list(object[el], s[0])); - } else { - res.push(structureWriter(object[el], s)); - } - } - } - - return new Buffer.concat(res); -}; - -module.exports = structureWriter; \ No newline at end of file diff --git a/src/errors.ts b/src/errors.ts new file mode 100644 index 0000000..579d591 --- /dev/null +++ b/src/errors.ts @@ -0,0 +1,28 @@ +export type DataStructErrorCode = + | 'VALUE_OUT_OF_RANGE' + | 'STRING_TOO_LONG' + | 'BYTES_TOO_LONG' + | 'ARRAY_TOO_LONG' + | 'BUFFER_UNDERFLOW' + | 'SCHEMA_MISMATCH' + | 'INVALID_SCHEMA'; + +export interface DataStructErrorOptions { + path?: string; + offset?: number; + cause?: unknown; +} + +export class DataStructError extends Error { + readonly code: DataStructErrorCode; + readonly path: string; + readonly offset: number | undefined; + + constructor(code: DataStructErrorCode, message: string, opts: DataStructErrorOptions = {}) { + super(opts.path ? `${message} at ${opts.path}` : message, { cause: opts.cause }); + this.name = 'DataStructError'; + this.code = code; + this.path = opts.path ?? '$'; + this.offset = opts.offset; + } +} diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 2eb7b20..0000000 --- a/src/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports.DataTypes = require('./dataTypes'); -module.exports.DataReader = require('./dataReader'); -module.exports.DataWriter = require('./dataWriter'); \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..128a80e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,7 @@ +export { t } from './codecs.js'; +export type { TypeRegistry } from './codecs.js'; +export { DataStructError } from './errors.js'; +export type { DataStructErrorCode, DataStructErrorOptions } from './errors.js'; +export { decode, encode, struct } from './struct.js'; +export type { Struct } from './struct.js'; +export type { Codec, CodecImpl, Infer, Schema } from './types.js'; diff --git a/src/struct.ts b/src/struct.ts new file mode 100644 index 0000000..0eb71e9 --- /dev/null +++ b/src/struct.ts @@ -0,0 +1,221 @@ +import { Buffer } from 'node:buffer'; +import { DataStructError } from './errors.js'; +import type { AnyCodec, Codec, CodecImpl, EncodePlan, Infer, Schema } from './types.js'; + +const ARRAY_LENGTH_MAX = 0xffff; +const PATH_AT = ' at '; + +function isCodec(v: unknown): v is AnyCodec { + return ( + typeof v === 'object' && + v !== null && + 'impl' in v && + 'tag' in v && + typeof (v as { tag: unknown }).tag === 'number' + ); +} + +// Re-throw a DataStructError after prefixing its path with a new segment. +// `segment` is either `.field` or `[index]`. Only allocated on the error path. +function rethrowWithPrefix(err: unknown, segment: string): never { + if (!(err instanceof DataStructError)) throw err; + const oldPath = err.path === '$' ? '' : err.path.slice(1); + const newPath = `$${segment}${oldPath}`; + // DataStructError's constructor appends " at " to the message when + // a path is provided; strip the previous suffix so we don't accumulate. + const oldSuffix = err.path === '$' ? '' : `${PATH_AT}${err.path}`; + const baseMessage = + oldSuffix && err.message.endsWith(oldSuffix) + ? err.message.slice(0, -oldSuffix.length) + : err.message; + const opts: { path: string; offset?: number; cause?: unknown } = { path: newPath }; + if (err.offset !== undefined) opts.offset = err.offset; + opts.cause = err.cause ?? err; + throw new DataStructError(err.code, baseMessage, opts); +} + +function compile(schema: Schema): AnyCodec { + if (isCodec(schema)) return schema; + if (Array.isArray(schema)) { + if (schema.length !== 1) { + throw new DataStructError( + 'INVALID_SCHEMA', + `array schema must have exactly one element descriptor, got ${schema.length}`, + ); + } + const element = schema[0]; + if (element === undefined) { + throw new DataStructError('INVALID_SCHEMA', 'array schema element is undefined'); + } + return arrayCodec(compile(element)); + } + if (typeof schema === 'object' && schema !== null) { + return structCodec(schema as Record); + } + throw new DataStructError('INVALID_SCHEMA', `unsupported schema node: ${String(schema)}`); +} + +function arrayCodec(element: AnyCodec): Codec { + const impl: CodecImpl = { + measure(value, plan) { + if (!Array.isArray(value)) { + throw new DataStructError('SCHEMA_MISMATCH', `expected array, got ${typeof value}`); + } + if (value.length > ARRAY_LENGTH_MAX) { + throw new DataStructError( + 'ARRAY_TOO_LONG', + `array length ${value.length} exceeds ${ARRAY_LENGTH_MAX}`, + ); + } + let size = 2; + for (let i = 0; i < value.length; i++) { + try { + size += element.impl.measure(value[i], plan); + } catch (e) { + rethrowWithPrefix(e, `[${i}]`); + } + } + return size; + }, + write(view, bytes, offset, value, plan) { + view.setUint16(offset, value.length, false); + offset += 2; + for (let i = 0; i < value.length; i++) { + try { + offset = element.impl.write(view, bytes, offset, value[i], plan); + } catch (e) { + rethrowWithPrefix(e, `[${i}]`); + } + } + return offset; + }, + read(view, bytes, offset) { + if (offset + 2 > view.byteLength) { + throw new DataStructError( + 'BUFFER_UNDERFLOW', + `need 2 byte(s) for array length at offset ${offset}`, + { offset }, + ); + } + const length = view.getUint16(offset, false); + offset += 2; + const out = new Array(length); + for (let i = 0; i < length; i++) { + try { + const r = element.impl.read(view, bytes, offset); + out[i] = r.value; + offset = r.offset; + } catch (e) { + rethrowWithPrefix(e, `[${i}]`); + } + } + return { value: out, offset }; + }, + }; + return { tag: 0x100, impl }; +} + +function structCodec(schema: Record): Codec> { + const keys = Object.keys(schema); + const fields: [string, AnyCodec][] = keys.map((key) => { + const child = schema[key]; + if (child === undefined) { + throw new DataStructError('INVALID_SCHEMA', `field "${key}" is undefined`); + } + return [key, compile(child)]; + }); + + const impl: CodecImpl> = { + measure(value, plan) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new DataStructError('SCHEMA_MISMATCH', `expected object, got ${typeof value}`); + } + const obj = value as Record; + let size = 0; + for (const [key, codec] of fields) { + try { + size += codec.impl.measure(obj[key], plan); + } catch (e) { + rethrowWithPrefix(e, `.${key}`); + } + } + return size; + }, + write(view, bytes, offset, value, plan) { + for (const [key, codec] of fields) { + try { + offset = codec.impl.write(view, bytes, offset, value[key], plan); + } catch (e) { + rethrowWithPrefix(e, `.${key}`); + } + } + return offset; + }, + read(view, bytes, offset) { + const out = Object.create(null) as Record; + for (const [key, codec] of fields) { + try { + const r = codec.impl.read(view, bytes, offset); + out[key] = r.value; + offset = r.offset; + } catch (e) { + rethrowWithPrefix(e, `.${key}`); + } + } + return { value: out, offset }; + }, + }; + return { tag: 0x300, impl }; +} + +export interface Struct { + readonly schema: S; + encode(value: Infer): Buffer; + decode(input: Uint8Array): Infer; + sizeOf(value: Infer): number; +} + +export function struct(schema: S): Struct { + const codec = compile(schema); + + return { + schema, + encode(value): Buffer { + const plan: EncodePlan = { strings: [], cursor: 0 }; + const size = codec.impl.measure(value, plan); + const out = Buffer.allocUnsafe(size); + const view = new DataView(out.buffer, out.byteOffset, out.byteLength); + plan.cursor = 0; + const written = codec.impl.write(view, out, 0, value, plan); + if (written !== size) { + throw new DataStructError( + 'INVALID_SCHEMA', + `internal size mismatch: measured ${size}, wrote ${written}`, + ); + } + return out; + }, + decode(input): Infer { + if (!(input instanceof Uint8Array)) { + throw new DataStructError( + 'SCHEMA_MISMATCH', + `decode expects Uint8Array, got ${typeof input}`, + ); + } + const view = new DataView(input.buffer, input.byteOffset, input.byteLength); + const { value } = codec.impl.read(view, input, 0); + return value as Infer; + }, + sizeOf(value): number { + return codec.impl.measure(value, { strings: [], cursor: 0 }); + }, + }; +} + +export function encode(value: Infer, schema: S): Buffer { + return struct(schema).encode(value); +} + +export function decode(input: Uint8Array, schema: S): Infer { + return struct(schema).decode(input); +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..a779506 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,38 @@ +declare const phantom: unique symbol; + +export interface EncodePlan { + strings: Uint8Array[]; + cursor: number; +} + +export interface ReadResult { + value: T; + offset: number; +} + +export interface CodecImpl { + measure(value: T, plan: EncodePlan): number; + write(view: DataView, bytes: Uint8Array, offset: number, value: T, plan: EncodePlan): number; + read(view: DataView, bytes: Uint8Array, offset: number): ReadResult; +} + +export interface Codec { + readonly tag: number; + readonly impl: CodecImpl; + readonly [phantom]?: T; +} + +// biome-ignore lint/suspicious/noExplicitAny: top type for schema discriminator +export type AnyCodec = Codec; + +export type Schema = AnyCodec | readonly Schema[] | { readonly [key: string]: Schema }; + +export type Infer = S extends Codec + ? T + : S extends readonly (infer E)[] + ? E extends Schema + ? Infer[] + : never + : S extends { readonly [key: string]: Schema } + ? { -readonly [K in keyof S]: Infer } + : never; diff --git a/test/errors.test.ts b/test/errors.test.ts new file mode 100644 index 0000000..71fd274 --- /dev/null +++ b/test/errors.test.ts @@ -0,0 +1,137 @@ +import { Buffer } from 'node:buffer'; +import { describe, expect, it } from 'vitest'; +import { DataStructError, decode, encode, t } from '../src/index.js'; + +describe('errors', () => { + it('throws VALUE_OUT_OF_RANGE for negative uint', () => { + try { + encode(-1, t.u8); + throw new Error('expected throw'); + } catch (err) { + expect(err).toBeInstanceOf(DataStructError); + expect((err as DataStructError).code).toBe('VALUE_OUT_OF_RANGE'); + } + }); + + it('throws VALUE_OUT_OF_RANGE for overflow', () => { + expect(() => encode(256, t.u8)).toThrow(/u8/); + expect(() => encode(0x10000, t.u16)).toThrow(/u16/); + expect(() => encode(2.5, t.i32)).toThrow(/integer/); + }); + + it('throws STRING_TOO_LONG for >64KiB strings', () => { + const huge = 'a'.repeat(65536); + try { + encode(huge, t.string); + throw new Error('expected throw'); + } catch (err) { + expect((err as DataStructError).code).toBe('STRING_TOO_LONG'); + } + }); + + it('throws ARRAY_TOO_LONG for >64KiB arrays', () => { + const huge = new Array(65536).fill(0); + try { + encode(huge, [t.u8]); + throw new Error('expected throw'); + } catch (err) { + expect((err as DataStructError).code).toBe('ARRAY_TOO_LONG'); + } + }); + + it('throws BUFFER_UNDERFLOW when decode runs past end', () => { + try { + decode(Buffer.from([0x00]), t.u16); + throw new Error('expected throw'); + } catch (err) { + expect((err as DataStructError).code).toBe('BUFFER_UNDERFLOW'); + } + }); + + it('throws SCHEMA_MISMATCH when value shape is wrong', () => { + try { + encode('not an array' as never, [t.u8]); + throw new Error('expected throw'); + } catch (err) { + expect((err as DataStructError).code).toBe('SCHEMA_MISMATCH'); + } + }); + + it('includes the field path in error messages', () => { + try { + encode({ outer: { inner: -5 } }, { outer: { inner: t.u8 } }); + throw new Error('expected throw'); + } catch (err) { + const e = err as DataStructError; + expect(e.code).toBe('VALUE_OUT_OF_RANGE'); + expect(e.path).toBe('$.outer.inner'); + expect(e.message).toContain('$.outer.inner'); + } + }); + + it('throws INVALID_SCHEMA for malformed array schema', () => { + try { + encode([1, 2], [t.u8, t.u16]); + throw new Error('expected throw'); + } catch (err) { + expect((err as DataStructError).code).toBe('INVALID_SCHEMA'); + } + }); + + it('throws SCHEMA_MISMATCH when string codec receives a non-string', () => { + expect(() => encode(42 as never, t.string)).toThrow(/string requires string/); + }); + + it('throws SCHEMA_MISMATCH when shortBytes / bytes receive non-Uint8Array', () => { + expect(() => encode([1, 2, 3] as never, t.shortBytes)).toThrow(/Uint8Array/); + expect(() => encode('not bytes' as never, t.bytes)).toThrow(/Uint8Array/); + }); + + it('throws BYTES_TOO_LONG for shortBytes > 65535', () => { + const huge = new Uint8Array(65536); + expect(() => encode(huge, t.shortBytes)).toThrow(/shortBytes length/); + }); + + it('throws SCHEMA_MISMATCH for non-object value against struct schema', () => { + expect(() => encode(null as never, { a: t.u8 })).toThrow(/expected object/); + expect(() => encode([1] as never, { a: t.u8 })).toThrow(/expected object/); + }); + + it('throws SCHEMA_MISMATCH when decode input is not Uint8Array', () => { + expect(() => decode('not bytes' as never, t.u8)).toThrow(/Uint8Array/); + }); + + it('throws VALUE_OUT_OF_RANGE for non-bigint i64/u64', () => { + expect(() => encode(5 as never, t.i64)).toThrow(/bigint/); + expect(() => encode(-1n, t.u64)).toThrow(/bigint/); + }); + + it('throws SCHEMA_MISMATCH for bool with non-boolean input', () => { + expect(() => encode(1 as never, t.bool)).toThrow(/bool requires boolean/); + }); + + it('throws VALUE_OUT_OF_RANGE for non-number floats', () => { + expect(() => encode('nope' as never, t.f64)).toThrow(/f64/); + }); + + it('throws SCHEMA_MISMATCH on invalid UTF-8 in string field', () => { + // 0x00 0x02 = uint16 length 2, then 0xc3 0x28 = invalid UTF-8 sequence + const bad = new Uint8Array([0x00, 0x02, 0xc3, 0x28]); + try { + decode(bad, t.string); + throw new Error('expected throw'); + } catch (err) { + const e = err as DataStructError; + expect(e.code).toBe('SCHEMA_MISMATCH'); + expect(e.message).toMatch(/UTF-8/); + } + }); + + it('decoded structs have null prototype (proto-pollution defence)', () => { + const { decoded } = (() => { + const buf = encode({ x: 1 }, { x: t.u8 }); + return { decoded: decode(buf, { x: t.u8 }) }; + })(); + expect(Object.getPrototypeOf(decoded)).toBeNull(); + }); +}); diff --git a/test/roundtrip.test.ts b/test/roundtrip.test.ts new file mode 100644 index 0000000..34f9879 --- /dev/null +++ b/test/roundtrip.test.ts @@ -0,0 +1,133 @@ +import { Buffer } from 'node:buffer'; +import { describe, expect, expectTypeOf, it } from 'vitest'; +import { decode, encode, struct, t } from '../src/index.js'; +import type { Infer } from '../src/index.js'; + +describe('roundtrip', () => { + it('deeply nested struct', () => { + const schema = { + nested: { nested2: { nested3: { nested4: { nested5: t.u8 } } } }, + }; + const value = { nested: { nested2: { nested3: { nested4: { nested5: 42 } } } } }; + expect(decode(encode(value, schema), schema)).toEqual(value); + }); + + it('list of list', () => { + const schema = [[t.i16]]; + const value = [ + [90, 10, 101], + [20, 30, 400], + [100, 110, 1], + ]; + expect(decode(encode(value, schema), schema)).toEqual(value); + }); + + it('list of list of list of list of object', () => { + const schema = { list: [[[[{ i: t.i16 }]]]] }; + const value = { + list: [[[[{ i: 1 }, { i: 2 }, { i: 3 }], [{ i: 1 }]], [[{ i: 1 }]]]], + }; + expect(decode(encode(value, schema), schema)).toEqual(value); + }); + + it('struct() factory produces same output as encode/decode', () => { + const codec = struct({ a: t.u32, b: t.string }); + const v = { a: 1234567, b: 'hello' }; + const buf = codec.encode(v); + expect(codec.decode(buf)).toEqual(v); + expect(codec.sizeOf(v)).toBe(buf.byteLength); + }); + + it('decoded shortBytes / bytes are independent copies of the source', () => { + const schema = { x: t.shortBytes }; + const src = Buffer.from([0x00, 0x02, 0xaa, 0xbb]); + const { x } = decode(src, schema); + src[2] = 0; + expect(x[0]).toBe(0xaa); + }); + + it('accepts plain Uint8Array as input', () => { + const buf = encode({ b: Buffer.from([1, 2, 3]) }, { b: t.shortBytes }); + const view = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); + const out = decode(view, { b: t.shortBytes }); + expect(Array.from(out.b)).toEqual([1, 2, 3]); + }); + + it('all primitive number types roundtrip at boundaries', () => { + const cases: { codec: { tag: number }; values: number[] }[] = [ + { codec: t.i8, values: [-128, 0, 127] }, + { codec: t.u8, values: [0, 255] }, + { codec: t.i16, values: [-32768, 0, 32767] }, + { codec: t.u16, values: [0, 65535] }, + { codec: t.i32, values: [-2147483648, 0, 2147483647] }, + { codec: t.u32, values: [0, 4294967295] }, + ]; + for (const { codec, values } of cases) { + for (const v of values) { + const buf = encode(v as never, codec as never); + expect(decode(buf, codec as never)).toBe(v); + } + } + }); + + it('bigint i64 / u64 roundtrip', () => { + expect(decode(encode(-(1n << 63n), t.i64), t.i64)).toBe(-(1n << 63n)); + expect(decode(encode((1n << 63n) - 1n, t.i64), t.i64)).toBe((1n << 63n) - 1n); + expect(decode(encode((1n << 64n) - 1n, t.u64), t.u64)).toBe((1n << 64n) - 1n); + }); + + it('little-endian codecs produce LE bytes', () => { + expect(Array.from(encode(0x1234, t.le.u16))).toEqual([0x34, 0x12]); + expect(Array.from(encode(0x12345678, t.le.u32))).toEqual([0x78, 0x56, 0x34, 0x12]); + expect(decode(encode(-1, t.le.i32), t.le.i32)).toBe(-1); + }); + + it('empty string and empty array roundtrip', () => { + expect(decode(encode('', t.string), t.string)).toBe(''); + expect(decode(encode([], [t.u8]), [t.u8])).toEqual([]); + }); + + it('Infer derives the value type', () => { + const schema = { + id: t.u32, + name: t.string, + tags: [t.string], + active: t.bool, + } as const; + type Value = Infer; + expectTypeOf().toEqualTypeOf<{ + id: number; + name: string; + tags: string[]; + active: boolean; + }>(); + }); + + it('Infer works for top-level array schemas (no object wrapper)', () => { + // Plain `[t.u8]` literal — must infer as number[] + expectTypeOf>().toEqualTypeOf< + number[] + >(); + + // `as const` form (readonly tuple) + const ro = [t.string] as const; + expectTypeOf>().toEqualTypeOf(); + + // Nested arrays + const matrix = [[t.i16]]; + expectTypeOf>().toEqualTypeOf(); + + // Array of structs + const list = [{ id: t.u32, name: t.string }]; + expectTypeOf>().toEqualTypeOf<{ id: number; name: string }[]>(); + + // struct() factory accepting an array schema directly + const codec = struct([t.u8]); + expectTypeOf(codec.encode).parameter(0).toEqualTypeOf(); + expectTypeOf(codec.decode).returns.toEqualTypeOf(); + + // Runtime roundtrip on the same array codec + const buf = codec.encode([1, 2, 3, 255]); + expect(codec.decode(buf)).toEqual([1, 2, 3, 255]); + }); +}); diff --git a/test/tests.js b/test/tests.js deleted file mode 100644 index 3bab424..0000000 --- a/test/tests.js +++ /dev/null @@ -1,219 +0,0 @@ -/** - * TODO: tests for compatibility with other rsa libraries - */ - -var assert = require("chai").assert; -DataTypes = require("../src/index").DataTypes; -DataReader = require("../src/index").DataReader; -DataWriter = require("../src/index").DataWriter; - -suite("DataStruct", function(){ - - var dataBundle = { - 'basic types': { - object: 42, - scheme: DataTypes.uint16, - buffer: new Buffer([0x00, 0x2a]) - }, - - 'flat structure (basic types)': { - object: { - boolean: true, - int8: -126, - uint8: 255, - int16: -1000, - uint16: 65535, - int32: -100000, - uint32: 100000, - float: 1230000, - double: -123.456 - }, - - scheme: { - boolean: DataTypes.boolean, - int8: DataTypes.int8, - uint8: DataTypes.uint8, - int16: DataTypes.int16, - uint16: DataTypes.uint16, - int32: DataTypes.int32, - uint32: DataTypes.uint32, - float: DataTypes.float, - double: DataTypes.double - }, - - buffer: new Buffer([ - 0x01, // boolean - 0x82, // int8 - 0xff, // uint8 - 0xfc, 0x18, // int16 - 0xff, 0xff, // uint16 - 0xff, 0xfe, 0x79, 0x60, // int32 - 0x00, 0x01, 0x86, 0xa0, // uint32 - 0x49, 0x96, 0x25, 0x80, // float - 0xc0, 0x5e, 0xdd, 0x2f, 0x1a, 0x9f, 0xbe, 0x77, // double - ]) - }, - - 'flat structure (composite types)': { - object: { - string: 'Some text + юникод', - shortBuffer: new Buffer([1,2,3]), - buffer: new Buffer([0xaa,0xbb,0xcc]) - }, - - scheme: { - string: DataTypes.string, - shortBuffer: DataTypes.shortBuffer, - buffer: DataTypes.buffer - }, - - buffer: new Buffer([ - 0x00, 0x18, // string length (uint16 BE) - 0x53, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x2b, 0x20, 0xd1, 0x8e, 0xd0, 0xbd, 0xd0, 0xb8, 0xd0, 0xba, 0xd0, 0xbe, 0xd0, 0xb4, // string - 0x00, 0x03, // short buffer length (uint16 BE) - 0x01, 0x02, 0x03, // shortBuffer - 0x00, 0x00, 0x00, 0x03, // buffer length (uint16 BE) - 0xaa, 0xbb, 0xcc // buffer - ]) - }, - - 'list of strings': { - object: { - values: [ - 'string1', - 'string20', - 'string300' - ] - }, - - scheme: { - values: [DataTypes.string] - }, - - buffer: new Buffer([ - 0x00, 0x03, // list length (uint16 BE) - 0x00, 0x07, // string length (uint16 BE) - 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, // string1 - 0x00, 0x08, // string length (uint16 BE) - 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x30, // string20 - 0x00, 0x09, // string length (uint16 BE) - 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x33, 0x30, 0x30 // string300 - ]) - }, - - 'list of objects': { - object: { - friends: [ - { - name: 'Alice', - age: 21 - }, - { - name: 'Bob', - age: 17 - } - ], - numbers: [ - 0x10, 0x26, 0x61, 0xff - ] - }, - - scheme: { - friends: [{ - name: DataTypes.string, - age: DataTypes.uint32 - }], - numbers:[DataTypes.uint8] - }, - - buffer: new Buffer([ - 0x00, 0x02, // friends list length (uint16 BE) - 0x00, 0x05, // string length (uint16 BE) - 0x41, 0x6c, 0x69, 0x63, 0x65, // string - 0x00, 0x00, 0x00, 0x15, //uint32 - 0x00, 0x03, // string length (uint16 BE) - 0x42, 0x6f, 0x62, // string - 0x00, 0x00, 0x00, 0x11, //uint32 - 0x00, 0x04, // numbers list length (uint16 BE) - 0x10, 0x26, 0x61, 0xff // numbers - ]) - } - - }; - - var dataBundleExtend = { - nested: { - - object: { nested: { nested2: { nested3: { nested4: { nested5: 42 } } } } }, - - scheme: { nested: { nested2: { nested3: { nested4: { nested5: DataTypes.uint8 } } } } } - - }, - - 'list of list': { - object: [ - [90,10,101], - [20,30,400], - [100,110,1] - ], - - scheme: [[DataTypes.int16]] - - }, - - 'list of list of list of list of object': { - object: { - list: [ - [[ - [{i: 1},{i: 2},{i: 3}],[{i: 1}] - ], - [ - [{i: 1}] - ]] - ] - }, - - scheme: { - list: [[[[{i: DataTypes.int16}]]]] - } - } - - }; - - suite("Buffer to Object convert", function(){ - for(var suite in dataBundle) { - var data = dataBundle[suite]; - (function(suite, data) { - test("should return buffer for '" + suite + "' suite", function () { - var res = DataReader(data.buffer, data.scheme); - assert.deepEqual(res, data.object); - }); - })(suite, data); - } - }); - - suite("Object to Buffer convert", function(){ - for(var suite in dataBundle) { - var data = dataBundle[suite]; - (function(suite, data) { - test("should return buffer for '" + suite + "' suite", function () { - var res = DataWriter(data.object, data.scheme); - assert.deepEqual(res, data.buffer); - }); - })(suite, data); - } - }); - - suite("Object to Buffer to Object convert", function() { - for(var suite in dataBundleExtend) { - var data = dataBundleExtend[suite]; - (function(suite, data) { - test("should convert to buffer and read same for '" + suite + "' suite", function () { - var buf = DataWriter(data.object, data.scheme); - var obj = DataReader(buf, data.scheme); - assert.deepEqual(obj, data.object); - }); - })(suite, data); - } - }); -}); \ No newline at end of file diff --git a/test/wire-format.test.ts b/test/wire-format.test.ts new file mode 100644 index 0000000..08060b2 --- /dev/null +++ b/test/wire-format.test.ts @@ -0,0 +1,111 @@ +import { Buffer } from 'node:buffer'; +import { describe, expect, it } from 'vitest'; +import { decode, encode, t } from '../src/index.js'; +import type { Schema } from '../src/index.js'; + +interface Fixture { + readonly name: string; + readonly schema: Schema; + readonly value: unknown; + readonly bytes: Buffer; +} + +const fixtures: Fixture[] = [ + { + name: 'leaf u16', + schema: t.u16, + value: 42, + bytes: Buffer.from([0x00, 0x2a]), + }, + { + name: 'flat numeric struct', + schema: { + boolean: t.bool, + int8: t.i8, + uint8: t.u8, + int16: t.i16, + uint16: t.u16, + int32: t.i32, + uint32: t.u32, + float: t.f32, + double: t.f64, + }, + value: { + boolean: true, + int8: -126, + uint8: 255, + int16: -1000, + uint16: 65535, + int32: -100000, + uint32: 100000, + float: 1230000, + double: -123.456, + }, + bytes: Buffer.from([ + 0x01, 0x82, 0xff, 0xfc, 0x18, 0xff, 0xff, 0xff, 0xfe, 0x79, 0x60, 0x00, 0x01, 0x86, 0xa0, + 0x49, 0x96, 0x25, 0x80, 0xc0, 0x5e, 0xdd, 0x2f, 0x1a, 0x9f, 0xbe, 0x77, + ]), + }, + { + name: 'string + bytes variants', + schema: { + str: t.string, + shortBytes: t.shortBytes, + bytes: t.bytes, + }, + value: { + str: 'Some text + юникод', + shortBytes: new Uint8Array([1, 2, 3]), + bytes: new Uint8Array([0xaa, 0xbb, 0xcc]), + }, + bytes: Buffer.from([ + 0x00, 0x18, 0x53, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x2b, 0x20, 0xd1, + 0x8e, 0xd0, 0xbd, 0xd0, 0xb8, 0xd0, 0xba, 0xd0, 0xbe, 0xd0, 0xb4, 0x00, 0x03, 0x01, 0x02, + 0x03, 0x00, 0x00, 0x00, 0x03, 0xaa, 0xbb, 0xcc, + ]), + }, + { + name: 'list of strings', + schema: { values: [t.string] }, + value: { values: ['string1', 'string20', 'string300'] }, + bytes: Buffer.from([ + 0x00, 0x03, 0x00, 0x07, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x00, 0x08, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x32, 0x30, 0x00, 0x09, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x33, + 0x30, 0x30, + ]), + }, + { + name: 'list of objects + list of u8', + schema: { + friends: [{ name: t.string, age: t.u32 }], + numbers: [t.u8], + }, + value: { + friends: [ + { name: 'Alice', age: 21 }, + { name: 'Bob', age: 17 }, + ], + numbers: [0x10, 0x26, 0x61, 0xff], + }, + bytes: Buffer.from([ + 0x00, 0x02, 0x00, 0x05, 0x41, 0x6c, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x15, 0x00, 0x03, + 0x42, 0x6f, 0x62, 0x00, 0x00, 0x00, 0x11, 0x00, 0x04, 0x10, 0x26, 0x61, 0xff, + ]), + }, +]; + +describe('wire format (byte-identical to legacy v0.0.11)', () => { + for (const fixture of fixtures) { + describe(fixture.name, () => { + it('encode produces the golden byte sequence', () => { + const encoded = encode(fixture.value as never, fixture.schema); + expect(Buffer.from(encoded).equals(fixture.bytes)).toBe(true); + }); + + it('decode reverses the golden byte sequence', () => { + const decoded = decode(fixture.bytes, fixture.schema); + expect(decoded).toEqual(fixture.value); + }); + }); + } +}); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..15a6c68 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "dist" + }, + "include": ["src"], + "exclude": ["test", "benchmark", "**/*.test.ts"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1098a9e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022"], + "module": "ESNext", + "moduleResolution": "Bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": false, + "esModuleInterop": true, + "resolveJsonModule": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "strict": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noFallthroughCasesInSwitch": true, + "exactOptionalPropertyTypes": true, + "noEmit": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["src", "test", "benchmark", "examples", "*.config.ts"] +} diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 0000000..369bcf2 --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm', 'cjs'], + outExtension: ({ format }) => ({ js: format === 'esm' ? '.mjs' : '.cjs' }), + dts: true, + sourcemap: true, + clean: true, + treeshake: true, + target: 'node20.9', + splitting: false, + minify: true, + shims: false, +}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..4834d4d --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['test/**/*.test.ts'], + environment: 'node', + coverage: { + provider: 'v8', + reporter: ['text', 'html', 'lcov'], + include: ['src/**/*.ts'], + exclude: ['src/**/*.d.ts', 'src/types.ts'], + thresholds: { + lines: 90, + functions: 90, + branches: 85, + statements: 90, + }, + }, + }, +});