diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8bdf992 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,135 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +TypeScript SDK, CLI & MCP Server for Costa Rica Electronic Invoicing (Comprobantes Electrónicos) against the Ministerio de Hacienda API v4.4. Three-layer architecture: SDK (core library) → CLI (`hacienda` binary) → MCP Server (AI-accessible tools). + +See `MASTER_PLAN.md` for full architecture, backlog, spikes (S-01 through S-06), and dependency graph. + +## Commands + +```bash +pnpm install # Install dependencies +pnpm build # Build all packages (turbo, respects dependency graph) +pnpm test # Run all tests +pnpm lint # Lint all packages +pnpm format # Check formatting (format:fix to auto-fix) +pnpm typecheck # Type-check all packages +pnpm clean # Remove all dist/ directories + +# Single package +pnpm --filter @hacienda-cr/sdk build +pnpm --filter @hacienda-cr/sdk test +pnpm --filter @hacienda-cr/sdk test clave.spec.ts # Single test file +``` + +**Build order matters:** Turbo handles this automatically — `shared` builds first, then `sdk`, then `cli`/`mcp`. Always run `pnpm build` before `pnpm test` on a fresh clone. + +## Monorepo Structure + +``` +packages/ +├── sdk/ # @hacienda-cr/sdk — Core: auth, XML, signing, API client, tax calc +├── cli/ # @hacienda-cr/cli — `hacienda` binary (citty framework) +└── mcp/ # @hacienda-cr/mcp — MCP Server (@modelcontextprotocol/sdk) +shared/ # @hacienda-cr/shared — Types, Zod schemas, constants, enums +``` + +**Dependency flow:** `shared` ← `sdk` ← `cli` / `mcp`. The SDK is the foundation — CLI and MCP wrap it. + +## Architecture + +### SDK modules (`packages/sdk/src/`) + +| Module | Purpose | +| ------------ | --------------------------------------------------------------- | +| `auth/` | OAuth2 ROPC token management, .p12 credential loading | +| `api/` | Typed HTTP client wrapping Hacienda REST endpoints | +| `clave/` | 50-digit clave numérica builder and parser | +| `xml/` | XML generation (fast-xml-parser), v4.4 XSD validation | +| `signing/` | XAdES-EPES digital signature with .p12 keys (xadesjs/xmldsigjs) | +| `documents/` | Builders for all 7 document types | +| `config/` | Config file management (~/.hacienda-cr/config.toml), sequences | +| `tax/` | Tax calculation: rounding, line items, IVA math | +| `logging/` | Structured logger with levels (DEBUG→SILENT), text/JSON output | + +Each module uses barrel exports via `index.ts`. The SDK root `src/index.ts` re-exports 190+ symbols organized by domain. + +### Shared package (`shared/src/`) + +- `constants/` — Document types, tax codes, currencies, payment methods, ID types, provinces, sale conditions, environments, XAdES policy config +- `types/` — Type definitions for clave, API, documents, config +- `schemas/` — Zod schemas for validation (clave, factura, identification, emisor, etc.) + +### CLI (`packages/cli/src/`) + +Uses citty framework. Commands: `auth login|status|switch`, `submit`, `status`, `list`, `get`, `sign`, `validate`, `lookup`, `draft`. All commands support `--json` for machine-readable output. + +### MCP Server (`packages/mcp/src/`) + +Exposes SDK as MCP tools: `create_invoice`, `check_status`, `list_documents`, `get_document`, `lookup_taxpayer`, `draft_invoice`. Plus resources for schemas and reference data. + +## Domain Context + +### Hacienda API Environments + +| Env | API Base | IDP Realm | Client ID | +| ---------- | ---------------------------------------------------------- | ---------- | ---------- | +| Sandbox | `api.comprobanteselectronicos.go.cr/recepcion-sandbox/v1/` | `rut-stag` | `api-stag` | +| Production | `api.comprobanteselectronicos.go.cr/recepcion/v1/` | `rut` | `api-prod` | + +### Clave Numérica + +50-digit key: `[506][DDMMYY][12-digit taxpayer ID][4-digit branch][4-digit POS][4-digit doc type][10-digit sequence][1-digit situation][8-digit security code]`. + +### XAdES-EPES Signing + +All XML signed with XAdES-EPES v1.3.2+ using taxpayer .p12 certificate (RSA 2048 + SHA-256). Policy hash (SHA-1): `Ohixl6upD6av8N7pEvDABhEL6hM=`. + +### Credentials + +Config: `~/.hacienda-cr/config.toml`. Secrets always via env vars (`HACIENDA_PASSWORD`, `HACIENDA_P12_PIN`, `HACIENDA_P12_PATH`), never in config files. + +## Conventions + +- **Files:** kebab-case (`token-manager.ts`) +- **Types/Classes:** PascalCase +- **Functions/Variables:** camelCase +- **Constants:** UPPER_SNAKE_CASE +- **Tests:** `*.spec.ts` colocated with source, integration tests use `*.integration.spec.ts` +- **Imports:** Use `type` keyword for type-only imports (`@typescript-eslint/consistent-type-imports` enforced) +- **Unused vars:** Prefix with `_` (ESLint allows `_`-prefixed unused vars) +- **Quotes:** Double quotes (Prettier enforced) +- **Validation:** Zod schemas for all public API inputs +- **XML:** fast-xml-parser for generation and parsing +- **Config format:** TOML for human-facing config (smol-toml) +- **Module format:** ESM only (`"type": "module"` everywhere), no CJS + +## Build & Test Details + +- **tsup** builds each package to ESM in `dist/`. CLI adds `#!/usr/bin/env node` banner. MCP bundles workspace deps but externalizes third-party. +- **Vitest** with globals enabled (no need to import `describe`/`it`/`expect`). V8 coverage provider. +- **TypeScript** targets ES2023, strict mode, `noUncheckedIndexedAccess: true`. +- **Turbo** caches build outputs (`dist/**`) and test coverage (`coverage/**`). Lint/typecheck depend on `^build`. + +## Key Dependencies + +| Package | Purpose | +| --------------------------- | ----------------------------------- | +| `zod` | Runtime validation + type inference | +| `fast-xml-parser` | XML generation and parsing | +| `xadesjs` / `xmldsigjs` | XAdES-EPES digital signing | +| `node-forge` | Cryptographic operations | +| `@xmldom/xmldom` | DOM implementation for XML | +| `smol-toml` | TOML config parsing | +| `citty` | CLI framework (unjs) | +| `@modelcontextprotocol/sdk` | MCP Server framework | + +## Implementation Notes + +- Token lifecycle: access token ~5min (cache in memory, refresh 30s before expiry), refresh token ~10hrs (persist to disk) +- All XML must validate against vendored v4.4 XSD schemas before submission +- Critical path: monorepo setup → types/clave → XML builder (Factura) → signing → API submission → end-to-end test +- Spikes S-01 through S-06 in MASTER_PLAN.md must be resolved before their dependent milestones diff --git a/package.json b/package.json index a38f6dc..0240e9d 100644 --- a/package.json +++ b/package.json @@ -22,18 +22,24 @@ "clean": "turbo run clean", "changeset": "changeset", "version-packages": "changeset version", - "release": "pnpm build && changeset publish" + "release": "pnpm build && changeset publish", + "prepare": "husky" }, "devDependencies": { "@changesets/cli": "2.27.12", "@eslint/js": "^9.19.0", "@types/node": "^25.3.0", "eslint": "^9.19.0", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", "prettier": "^3.4.2", "tsup": "^8.3.6", "turbo": "^2.3.4", "typescript": "^5.7.3", "typescript-eslint": "^8.22.0", "vitest": "^3.0.5" + }, + "lint-staged": { + "*": "prettier --write --ignore-unknown" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b15fdb..98748a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,12 +20,18 @@ importers: eslint: specifier: ^9.19.0 version: 9.39.3 + husky: + specifier: ^9.1.7 + version: 9.1.7 + lint-staged: + specifier: ^16.2.7 + version: 16.2.7 prettier: specifier: ^3.4.2 version: 3.8.1 tsup: specifier: ^8.3.6 - version: 8.5.1(postcss@8.5.6)(typescript@5.9.3) + version: 8.5.1(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2) turbo: specifier: ^2.3.4 version: 2.8.10 @@ -37,7 +43,7 @@ importers: version: 8.56.0(eslint@9.39.3)(typescript@5.9.3) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/node@25.3.0) + version: 3.2.4(@types/node@25.3.0)(yaml@2.8.2) packages/cli: dependencies: @@ -698,14 +704,26 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -809,6 +827,14 @@ packages: citty@0.2.1: resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@5.1.1: + resolution: {integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==} + engines: {node: '>=20'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -816,6 +842,13 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -889,6 +922,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -897,6 +933,10 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -982,6 +1022,9 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + eventsource-parser@3.0.6: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} @@ -1097,6 +1140,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1151,6 +1198,11 @@ packages: human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -1190,6 +1242,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1262,6 +1318,15 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lint-staged@16.2.7: + resolution: {integrity: sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==} + engines: {node: '>=20.17'} + hasBin: true + + listr2@9.0.5: + resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} + engines: {node: '>=20.0.0'} + load-tsconfig@0.2.5: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1280,6 +1345,10 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -1314,6 +1383,10 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + minimatch@3.1.3: resolution: {integrity: sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==} @@ -1334,6 +1407,10 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nano-spawn@2.0.0: + resolution: {integrity: sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==} + engines: {node: '>=20.17'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1365,6 +1442,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1448,6 +1529,11 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -1556,10 +1642,17 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rollup@4.58.0: resolution: {integrity: sha512-wbT0mBmWbIvvq8NeEYWWvevvxnOyhKChir47S66WCxw1SXqhw7ssIYejnQEVt7XYQpsj2y8F9PM+Cr3SNEa0gw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -1626,6 +1719,10 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + smol-toml@1.6.0: resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} engines: {node: '>= 18'} @@ -1654,10 +1751,26 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string-width@8.2.0: + resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + engines: {node: '>=20'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -1923,6 +2036,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -1945,6 +2062,11 @@ packages: resolution: {integrity: sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA==} engines: {node: '>=0.6.0'} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -2503,13 +2625,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.3.0))': + '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.3.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.3.0) + vite: 7.3.1(@types/node@25.3.0)(yaml@2.8.2) '@vitest/pretty-format@3.2.4': dependencies: @@ -2570,12 +2692,20 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + ansi-styles@6.2.3: {} + any-promise@1.3.0: {} argparse@1.0.10: @@ -2677,12 +2807,25 @@ snapshots: citty@0.2.1: {} + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@5.1.1: + dependencies: + slice-ansi: 7.1.2 + string-width: 8.2.0 + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + colorette@2.0.20: {} + + commander@14.0.3: {} + commander@4.1.1: {} concat-map@0.0.1: {} @@ -2734,6 +2877,8 @@ snapshots: ee-first@1.1.1: {} + emoji-regex@10.6.0: {} + encodeurl@2.0.0: {} enquirer@2.4.1: @@ -2741,6 +2886,8 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + environment@1.1.0: {} + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -2860,6 +3007,8 @@ snapshots: etag@1.8.1: {} + eventemitter3@5.0.4: {} + eventsource-parser@3.0.6: {} eventsource@3.0.7: @@ -3005,6 +3154,8 @@ snapshots: function-bind@1.1.2: {} + get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -3066,6 +3217,8 @@ snapshots: human-id@1.0.2: {} + husky@9.1.7: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -3093,6 +3246,10 @@ snapshots: is-extglob@2.1.1: {} + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.5.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -3151,6 +3308,25 @@ snapshots: lines-and-columns@1.2.4: {} + lint-staged@16.2.7: + dependencies: + commander: 14.0.3 + listr2: 9.0.5 + micromatch: 4.0.8 + nano-spawn: 2.0.0 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.8.2 + + listr2@9.0.5: + dependencies: + cli-truncate: 5.1.1 + colorette: 2.0.20 + eventemitter3: 5.0.4 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.2 + load-tsconfig@0.2.5: {} locate-path@5.0.0: @@ -3165,6 +3341,14 @@ snapshots: lodash.startcase@4.4.0: {} + log-update@6.1.0: + dependencies: + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + loupe@3.2.1: {} magic-string@0.30.21: @@ -3190,6 +3374,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mimic-function@5.0.1: {} + minimatch@3.1.3: dependencies: brace-expansion: 1.1.12 @@ -3215,6 +3401,8 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 + nano-spawn@2.0.0: {} + nanoid@3.3.11: {} natural-compare@1.4.0: {} @@ -3235,6 +3423,10 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3300,6 +3492,8 @@ snapshots: picomatch@4.0.3: {} + pidtree@0.6.0: {} + pify@4.0.1: {} pirates@4.0.7: {} @@ -3321,11 +3515,12 @@ snapshots: pvutils: 1.1.5 tslib: 2.8.1 - postcss-load-config@6.0.1(postcss@8.5.6): + postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.8.2): dependencies: lilconfig: 3.1.3 optionalDependencies: postcss: 8.5.6 + yaml: 2.8.2 postcss@8.5.6: dependencies: @@ -3384,8 +3579,15 @@ snapshots: resolve-from@5.0.0: {} + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + reusify@1.1.0: {} + rfdc@1.4.1: {} + rollup@4.58.0: dependencies: '@types/estree': 1.0.8 @@ -3502,6 +3704,11 @@ snapshots: slash@3.0.0: {} + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + smol-toml@1.6.0: {} source-map-js@1.2.1: {} @@ -3521,10 +3728,27 @@ snapshots: std-env@3.10.0: {} + string-argv@0.3.2: {} + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.5.0 + strip-ansi: 7.1.2 + + string-width@8.2.0: + dependencies: + get-east-asian-width: 1.5.0 + strip-ansi: 7.1.2 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + strip-bom@3.0.0: {} strip-json-comments@3.1.1: {} @@ -3594,7 +3818,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(postcss@8.5.6)(typescript@5.9.3): + tsup@8.5.1(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2): dependencies: bundle-require: 5.1.0(esbuild@0.27.3) cac: 6.7.14 @@ -3605,7 +3829,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(postcss@8.5.6) + postcss-load-config: 6.0.1(postcss@8.5.6)(yaml@2.8.2) resolve-from: 5.0.0 rollup: 4.58.0 source-map: 0.7.6 @@ -3686,13 +3910,13 @@ snapshots: vary@1.1.2: {} - vite-node@3.2.4(@types/node@25.3.0): + vite-node@3.2.4(@types/node@25.3.0)(yaml@2.8.2): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@25.3.0) + vite: 7.3.1(@types/node@25.3.0)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti @@ -3707,7 +3931,7 @@ snapshots: - tsx - yaml - vite@7.3.1(@types/node@25.3.0): + vite@7.3.1(@types/node@25.3.0)(yaml@2.8.2): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -3718,12 +3942,13 @@ snapshots: optionalDependencies: '@types/node': 25.3.0 fsevents: 2.3.3 + yaml: 2.8.2 - vitest@3.2.4(@types/node@25.3.0): + vitest@3.2.4(@types/node@25.3.0)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.3.0)) + '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.3.0)(yaml@2.8.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -3741,8 +3966,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@25.3.0) - vite-node: 3.2.4(@types/node@25.3.0) + vite: 7.3.1(@types/node@25.3.0)(yaml@2.8.2) + vite-node: 3.2.4(@types/node@25.3.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.3.0 @@ -3771,6 +3996,12 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 + wrappy@1.0.2: {} xadesjs@2.6.5(@xmldom/xmldom@0.9.8)(xpath@0.0.34): @@ -3801,6 +4032,8 @@ snapshots: xpath@0.0.34: {} + yaml@2.8.2: {} + yocto-queue@0.1.0: {} zod-to-json-schema@3.25.1(zod@4.3.6):