From 978a480144779fb4debd60d61cfec3d0388f0db5 Mon Sep 17 00:00:00 2001 From: Szymeo Date: Thu, 18 Dec 2025 16:28:08 +0800 Subject: [PATCH 1/4] feat: queue, retry, flushing, exponential backoff --- .github/workflows/ci.yml | 38 + README.md | 63 +- package.json | 93 ++- pnpm-lock.yaml | 1202 +++++++++++++-------------- src/LogDash.ts | 30 - src/Logdash_.ts | 205 +++++ src/__tests__/HttpTransport.test.ts | 180 ++++ src/__tests__/Logdash.test.ts | 172 ++++ src/__tests__/RequestQueue.test.ts | 179 ++++ src/index.ts | 6 +- src/logger/Logger.ts | 87 -- src/logger/internal-logger.ts | 6 - src/logger/internalLogger.ts | 18 + src/metrics/BaseMetrics.ts | 4 - src/metrics/Metrics.ts | 50 -- src/metrics/NoopMetrics.ts | 6 - src/metrics/createMetrics.ts | 18 - src/queue/RequestQueue.ts | 120 +++ src/sync/HttpLogSync.ts | 29 - src/sync/LogSync.ts | 5 - src/sync/NoopLogSync.ts | 5 - src/sync/createLogSync.ts | 18 - src/transport/HttpTransport.ts | 74 ++ src/types/InitializationParams.ts | 7 - test.ts | 38 +- tsconfig.lib.json | 53 +- vite.config.ts | 26 +- 27 files changed, 1720 insertions(+), 1012 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 src/LogDash.ts create mode 100644 src/Logdash_.ts create mode 100644 src/__tests__/HttpTransport.test.ts create mode 100644 src/__tests__/Logdash.test.ts create mode 100644 src/__tests__/RequestQueue.test.ts delete mode 100644 src/logger/Logger.ts delete mode 100644 src/logger/internal-logger.ts create mode 100644 src/logger/internalLogger.ts delete mode 100644 src/metrics/BaseMetrics.ts delete mode 100644 src/metrics/Metrics.ts delete mode 100644 src/metrics/NoopMetrics.ts delete mode 100644 src/metrics/createMetrics.ts create mode 100644 src/queue/RequestQueue.ts delete mode 100644 src/sync/HttpLogSync.ts delete mode 100644 src/sync/LogSync.ts delete mode 100644 src/sync/NoopLogSync.ts delete mode 100644 src/sync/createLogSync.ts create mode 100644 src/transport/HttpTransport.ts delete mode 100644 src/types/InitializationParams.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8b99e81 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18, 20, 22] + + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install + + - name: Build + run: pnpm build + + - name: Test + run: pnpm test diff --git a/README.md b/README.md index 1f4afcd..94f0e79 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# logdash - JS SDK +# @logdash/node -Logdash is a zero-config observability platform. This package serves an javascript interface to use it. +Logdash is a zero-config observability platform. This package serves a Node.js/Bun/Deno/Browser interface to use it. ## Pre-requisites @@ -9,39 +9,48 @@ Setup your free project in less than 2 minutes at [logdash.io](https://logdash.i ## Installation ``` -npm install @logdash/js-sdk +npm install @logdash/node ``` ## Logging ```typescript -import { createLogDash } from '@logdash/js-sdk'; +import { Logdash } from '@logdash/node'; -const { logger } = createLogDash({ - // optional, but recommended to see your logs in the dashboard - apiKey: '', -}); +const logdash = new Logdash(''); -logger.info('Application started successfully'); -logger.error('An unexpected error occurred'); -logger.warn('Low disk space warning'); +logdash.info('Application started successfully'); +logdash.error('An unexpected error occurred'); +logdash.warn('Low disk space warning'); +``` + +## Namespaced Logging + +```typescript +const authLogdash = logdash.withNamespace('auth'); +authLogdash.info('User logged in'); +authLogdash.error('Authentication failed'); ``` ## Metrics ```typescript -import { createLogDash } from '@logdash/js-sdk'; +import { Logdash } from '@logdash/node'; -const { metrics } = createLogDash({ - // optional, but recommended as metrics are only hosted remotely - apiKey: '', -}); +const logdash = new Logdash(''); // to set absolute value -metrics.set('users', 0); +logdash.setMetric('users', 0); // to modify existing metric -metrics.mutate('users', 1); +logdash.mutateMetric('users', 1); +``` + +## Graceful Shutdown + +```typescript +// Ensure all logs and metrics are sent before exiting +await logdash.flush(); ``` ## View @@ -53,20 +62,20 @@ To see the logs or metrics, go to your project dashboard ## Configuration -| Parameter | Required | Default | Description | -| --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------ | -| `apiKey` | no | - | Api key used to authorize against logdash servers. If you don't provide one, logs will be logged into local console only | -| `host` | no | - | Custom API host, useful with self-hosted instances | -| `verbose` | no | - | Useful for debugging purposes | +```typescript +new Logdash(apiKey?, options?) +``` + +| Parameter | Required | Default | Description | +| ----------------- | -------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------ | +| `apiKey` | no | - | Api key used to authorize against logdash servers. If you don't provide one, logs will be logged into local console only | +| `options.host` | no | `https://api.logdash.io` | Custom API host, useful with self-hosted instances | +| `options.verbose` | no | `false` | Useful for debugging purposes | ## License This project is licensed under the MIT License. -## Contributing - -Contributions are welcome! Feel free to open issues or submit pull requests. - ## Support If you encounter any issues, please open an issue on GitHub or let us know at [contact@logdash.io](mailto:contact@logdash.io). diff --git a/package.json b/package.json index b213e5e..3bc56e7 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,50 @@ { - "name": "@logdash/js-sdk", - "version": "1.0.9", - "private": false, - "description": "Modern observability platform.", - "scripts": { - "build": "tsc -p tsconfig.lib.json", - "release": "pnpm build && changeset publish", - "changeset": "changeset", - "version-packages": "changeset version" - }, - "author": "Simon Gracki ", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/logdash-io/js-sdk.git" - }, - "homepage": "https://github.com/logdash-io/js-sdk", - "devDependencies": { - "@changesets/cli": "^2.28.1", - "@swc/core": "^1.10.18", - "@types/node": "^22.13.5", - "prettier": "^3.5.2", - "typescript": "5.7.3", - "vitest": "^3.0.6" - }, - "bugs": { - "url": "https://github.com/logdash-io/js-sdk/issues" - }, - "packageManager": "pnpm@9.0.0", - "engines": { - "node": ">=18" - }, - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", - "keywords": [ - "observability", - "monitoring", - "logging", - "tracing", - "metrics" - ], - "dependencies": { - "chalk": "^4.1.2" - } + "name": "@logdash/node", + "version": "1.0.0", + "private": false, + "description": "How solo founders keep their SaaS apps healthy.", + "scripts": { + "build": "tsc -p tsconfig.lib.json", + "test": "vitest run", + "test:watch": "vitest", + "release": "pnpm build && changeset publish", + "changeset": "changeset", + "version-packages": "changeset version" + }, + "author": "Logdash Team ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/logdash-io/node-sdk.git" + }, + "homepage": "https://github.com/logdash-io/node-sdk", + "devDependencies": { + "@changesets/cli": "^2.29.8", + "@swc/core": "^1.15.6", + "@types/node": "^25.0.3", + "prettier": "^3.7.4", + "typescript": "5.9.3", + "vitest": "^4.0.16" + }, + "bugs": { + "url": "https://github.com/logdash-io/node-sdk/issues" + }, + "packageManager": "pnpm@9.0.0", + "engines": { + "node": ">=18" + }, + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "keywords": [ + "observability", + "monitoring", + "logging", + "tracing", + "metrics" + ], + "dependencies": { + "chalk": "^5.6.2" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7978f5b..4e39420 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,49 +9,49 @@ importers: .: dependencies: chalk: - specifier: ^4.1.2 - version: 4.1.2 + specifier: ^5.6.2 + version: 5.6.2 devDependencies: '@changesets/cli': - specifier: ^2.28.1 - version: 2.28.1 + specifier: ^2.29.8 + version: 2.29.8(@types/node@25.0.3) '@swc/core': - specifier: ^1.10.18 - version: 1.10.18 + specifier: ^1.15.6 + version: 1.15.6 '@types/node': - specifier: ^22.13.5 - version: 22.13.5 + specifier: ^25.0.3 + version: 25.0.3 prettier: - specifier: ^3.5.2 - version: 3.5.2 + specifier: ^3.7.4 + version: 3.7.4 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.9.3 + version: 5.9.3 vitest: - specifier: ^3.0.6 - version: 3.0.6(@types/node@22.13.5) + specifier: ^4.0.16 + version: 4.0.16(@types/node@25.0.3) packages: - '@babel/runtime@7.26.9': - resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - '@changesets/apply-release-plan@7.0.10': - resolution: {integrity: sha512-wNyeIJ3yDsVspYvHnEz1xQDq18D9ifed3lI+wxRQRK4pArUcuHgCTrHv0QRnnwjhVCQACxZ+CBih3wgOct6UXw==} + '@changesets/apply-release-plan@7.0.14': + resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} - '@changesets/assemble-release-plan@6.0.6': - resolution: {integrity: sha512-Frkj8hWJ1FRZiY3kzVCKzS0N5mMwWKwmv9vpam7vt8rZjLL1JMthdh6pSDVSPumHPshTTkKZ0VtNbE0cJHZZUg==} + '@changesets/assemble-release-plan@6.0.9': + resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} '@changesets/changelog-git@0.2.1': resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} - '@changesets/cli@2.28.1': - resolution: {integrity: sha512-PiIyGRmSc6JddQJe/W1hRPjiN4VrMvb2VfQ6Uydy2punBioQrsxppyG5WafinKcW1mT0jOe/wU4k9Zy5ff21AA==} + '@changesets/cli@2.29.8': + resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==} hasBin: true - '@changesets/config@3.1.1': - resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==} + '@changesets/config@3.1.2': + resolution: {integrity: sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog==} '@changesets/errors@0.2.0': resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} @@ -59,26 +59,26 @@ packages: '@changesets/get-dependents-graph@2.1.3': resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} - '@changesets/get-release-plan@4.0.8': - resolution: {integrity: sha512-MM4mq2+DQU1ZT7nqxnpveDMTkMBLnwNX44cX7NSxlXmr7f8hO6/S2MXNiXG54uf/0nYnefv0cfy4Czf/ZL/EKQ==} + '@changesets/get-release-plan@4.0.14': + resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==} '@changesets/get-version-range-type@0.4.0': resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} - '@changesets/git@3.0.2': - resolution: {integrity: sha512-r1/Kju9Y8OxRRdvna+nxpQIsMsRQn9dhhAZt94FLDeu0Hij2hnOozW8iqnHBgvu+KdnJppCveQwK4odwfw/aWQ==} + '@changesets/git@3.0.4': + resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} '@changesets/logger@0.1.1': resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} - '@changesets/parse@0.4.1': - resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==} + '@changesets/parse@0.4.2': + resolution: {integrity: sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA==} '@changesets/pre@2.0.2': resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} - '@changesets/read@0.6.3': - resolution: {integrity: sha512-9H4p/OuJ3jXEUTjaVGdQEhBdqoT2cO5Ts95JTFsQyawmKzpL8FnIeJSyhTDPW1MBRDnwZlHFEM9SpPwJDY5wIg==} + '@changesets/read@0.6.6': + resolution: {integrity: sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg==} '@changesets/should-skip-package@0.1.2': resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} @@ -92,158 +92,173 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@esbuild/aix-ppc64@0.24.2': - resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.24.2': - resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.24.2': - resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.24.2': - resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.24.2': - resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.24.2': - resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.24.2': - resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.24.2': - resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.24.2': - resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.24.2': - resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.24.2': - resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.24.2': - resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.24.2': - resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.24.2': - resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.24.2': - resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.24.2': - resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.24.2': - resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.24.2': - resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.24.2': - resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.24.2': - resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.24.2': - resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.24.2': - resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.24.2': - resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.24.2': - resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.24.2': - resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -263,166 +278,184 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@rollup/rollup-android-arm-eabi@4.34.8': - resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==} + '@rollup/rollup-android-arm-eabi@4.53.5': + resolution: {integrity: sha512-iDGS/h7D8t7tvZ1t6+WPK04KD0MwzLZrG0se1hzBjSi5fyxlsiggoJHwh18PCFNn7tG43OWb6pdZ6Y+rMlmyNQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.34.8': - resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==} + '@rollup/rollup-android-arm64@4.53.5': + resolution: {integrity: sha512-wrSAViWvZHBMMlWk6EJhvg8/rjxzyEhEdgfMMjREHEq11EtJ6IP6yfcCH57YAEca2Oe3FNCE9DSTgU70EIGmVw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.34.8': - resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==} + '@rollup/rollup-darwin-arm64@4.53.5': + resolution: {integrity: sha512-S87zZPBmRO6u1YXQLwpveZm4JfPpAa6oHBX7/ghSiGH3rz/KDgAu1rKdGutV+WUI6tKDMbaBJomhnT30Y2t4VQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.34.8': - resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==} + '@rollup/rollup-darwin-x64@4.53.5': + resolution: {integrity: sha512-YTbnsAaHo6VrAczISxgpTva8EkfQus0VPEVJCEaboHtZRIb6h6j0BNxRBOwnDciFTZLDPW5r+ZBmhL/+YpTZgA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.34.8': - resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==} + '@rollup/rollup-freebsd-arm64@4.53.5': + resolution: {integrity: sha512-1T8eY2J8rKJWzaznV7zedfdhD1BqVs1iqILhmHDq/bqCUZsrMt+j8VCTHhP0vdfbHK3e1IQ7VYx3jlKqwlf+vw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.34.8': - resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==} + '@rollup/rollup-freebsd-x64@4.53.5': + resolution: {integrity: sha512-sHTiuXyBJApxRn+VFMaw1U+Qsz4kcNlxQ742snICYPrY+DDL8/ZbaC4DVIB7vgZmp3jiDaKA0WpBdP0aqPJoBQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.34.8': - resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==} + '@rollup/rollup-linux-arm-gnueabihf@4.53.5': + resolution: {integrity: sha512-dV3T9MyAf0w8zPVLVBptVlzaXxka6xg1f16VAQmjg+4KMSTWDvhimI/Y6mp8oHwNrmnmVl9XxJ/w/mO4uIQONA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.34.8': - resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==} + '@rollup/rollup-linux-arm-musleabihf@4.53.5': + resolution: {integrity: sha512-wIGYC1x/hyjP+KAu9+ewDI+fi5XSNiUi9Bvg6KGAh2TsNMA3tSEs+Sh6jJ/r4BV/bx/CyWu2ue9kDnIdRyafcQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.34.8': - resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==} + '@rollup/rollup-linux-arm64-gnu@4.53.5': + resolution: {integrity: sha512-Y+qVA0D9d0y2FRNiG9oM3Hut/DgODZbU9I8pLLPwAsU0tUKZ49cyV1tzmB/qRbSzGvY8lpgGkJuMyuhH7Ma+Vg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.34.8': - resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==} + '@rollup/rollup-linux-arm64-musl@4.53.5': + resolution: {integrity: sha512-juaC4bEgJsyFVfqhtGLz8mbopaWD+WeSOYr5E16y+1of6KQjc0BpwZLuxkClqY1i8sco+MdyoXPNiCkQou09+g==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.34.8': - resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==} + '@rollup/rollup-linux-loong64-gnu@4.53.5': + resolution: {integrity: sha512-rIEC0hZ17A42iXtHX+EPJVL/CakHo+tT7W0pbzdAGuWOt2jxDFh7A/lRhsNHBcqL4T36+UiAgwO8pbmn3dE8wA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': - resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==} + '@rollup/rollup-linux-ppc64-gnu@4.53.5': + resolution: {integrity: sha512-T7l409NhUE552RcAOcmJHj3xyZ2h7vMWzcwQI0hvn5tqHh3oSoclf9WgTl+0QqffWFG8MEVZZP1/OBglKZx52Q==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.34.8': - resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==} + '@rollup/rollup-linux-riscv64-gnu@4.53.5': + resolution: {integrity: sha512-7OK5/GhxbnrMcxIFoYfhV/TkknarkYC1hqUw1wU2xUN3TVRLNT5FmBv4KkheSG2xZ6IEbRAhTooTV2+R5Tk0lQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.34.8': - resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==} + '@rollup/rollup-linux-riscv64-musl@4.53.5': + resolution: {integrity: sha512-GwuDBE/PsXaTa76lO5eLJTyr2k8QkPipAyOrs4V/KJufHCZBJ495VCGJol35grx9xryk4V+2zd3Ri+3v7NPh+w==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.53.5': + resolution: {integrity: sha512-IAE1Ziyr1qNfnmiQLHBURAD+eh/zH1pIeJjeShleII7Vj8kyEm2PF77o+lf3WTHDpNJcu4IXJxNO0Zluro8bOw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.34.8': - resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==} + '@rollup/rollup-linux-x64-gnu@4.53.5': + resolution: {integrity: sha512-Pg6E+oP7GvZ4XwgRJBuSXZjcqpIW3yCBhK4BcsANvb47qMvAbCjR6E+1a/U2WXz1JJxp9/4Dno3/iSJLcm5auw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.34.8': - resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==} + '@rollup/rollup-linux-x64-musl@4.53.5': + resolution: {integrity: sha512-txGtluxDKTxaMDzUduGP0wdfng24y1rygUMnmlUJ88fzCCULCLn7oE5kb2+tRB+MWq1QDZT6ObT5RrR8HFRKqg==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.34.8': - resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==} + '@rollup/rollup-openharmony-arm64@4.53.5': + resolution: {integrity: sha512-3DFiLPnTxiOQV993fMc+KO8zXHTcIjgaInrqlG8zDp1TlhYl6WgrOHuJkJQ6M8zHEcntSJsUp1XFZSY8C1DYbg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.53.5': + resolution: {integrity: sha512-nggc/wPpNTgjGg75hu+Q/3i32R00Lq1B6N1DO7MCU340MRKL3WZJMjA9U4K4gzy3dkZPXm9E1Nc81FItBVGRlA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.34.8': - resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==} + '@rollup/rollup-win32-ia32-msvc@4.53.5': + resolution: {integrity: sha512-U/54pTbdQpPLBdEzCT6NBCFAfSZMvmjr0twhnD9f4EIvlm9wy3jjQ38yQj1AGznrNO65EWQMgm/QUjuIVrYF9w==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.34.8': - resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==} + '@rollup/rollup-win32-x64-gnu@4.53.5': + resolution: {integrity: sha512-2NqKgZSuLH9SXBBV2dWNRCZmocgSOx8OJSdpRaEcRlIfX8YrKxUT6z0F1NpvDVhOsl190UFTRh2F2WDWWCYp3A==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.53.5': + resolution: {integrity: sha512-JRpZUhCfhZ4keB5v0fe02gQJy05GqboPOaxvjugW04RLSYYoB/9t2lx2u/tMs/Na/1NXfY8QYjgRljRpN+MjTQ==} cpu: [x64] os: [win32] - '@swc/core-darwin-arm64@1.10.18': - resolution: {integrity: sha512-FdGqzAIKVQJu8ROlnHElP59XAUsUzCFSNsou+tY/9ba+lhu8R9v0OI5wXiPErrKGZpQFMmx/BPqqhx3X4SuGNg==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/core-darwin-arm64@1.15.6': + resolution: {integrity: sha512-8pv6W49H70/yxNAC0k+W/Ko3nJW2Za706C1a8q6XhT4JtMLyaYqb+KeoBfIOR8F7qNhMdMa7wdOY5DLPk5cPSg==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.10.18': - resolution: {integrity: sha512-RZ73gZRituL/ZVLgrW6BYnQ5g8tuStG4cLUiPGJsUZpUm0ullSH6lHFvZTCBNFTfpQChG6eEhi2IdG6DwFp1lw==} + '@swc/core-darwin-x64@1.15.6': + resolution: {integrity: sha512-v4mDTwA+UdYEHKvzefc3VX/4a7QrRnAFZzNwL33PcLNUJhWbBg6ptcQpBDz/xWOjU6m+pC0IQfzcs16rkAFCHg==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.10.18': - resolution: {integrity: sha512-8iJqI3EkxJuuq21UHoen1VS+QlS23RvynRuk95K+Q2HBjygetztCGGEc+Xelx9a0uPkDaaAtFvds4JMDqb9SAA==} + '@swc/core-linux-arm-gnueabihf@1.15.6': + resolution: {integrity: sha512-OT8rIl24/mu4bgDPJT6FVcW+WF3ep9VTau69FspjeycNIa0U0est1ooHxxJyTcO8Qdv0Jy11oXHwtxslZ6KXcw==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.10.18': - resolution: {integrity: sha512-8f1kSktWzMB6PG+r8lOlCfXz5E8Qhsmfwonn77T/OfjvGwQaWrcoASh2cdjpk3dydbf8jsKGPQE1lSc7GyjXRQ==} + '@swc/core-linux-arm64-gnu@1.15.6': + resolution: {integrity: sha512-RKdeG9HBecClhtNJpGyZCYwvGrjzxDzQxGaVOQa44DbNSlVgupj6LnqNSt0RCTy8HEjra1WTD8dCJ9AR++dznQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.10.18': - resolution: {integrity: sha512-4rv+E4VLdgQw6zjbTAauCAEExxChvxMpBUMCiZweTNPKbJJ2dY6BX2WGJ1ea8+RcgqR/Xysj3AFbOz1LBz6dGA==} + '@swc/core-linux-arm64-musl@1.15.6': + resolution: {integrity: sha512-+llo+x7fRyyYd5qGfeYyHgDoZy7M9jKQKmYjTKTJ1BMoydeBoujUWtw+L3tOHyrzKBWOdmVhwdyK+Rx8DeOaGQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.10.18': - resolution: {integrity: sha512-vTNmyRBVP+sZca+vtwygYPGTNudTU6Gl6XhaZZ7cEUTBr8xvSTgEmYXoK/2uzyXpaTUI4Bmtp1x81cGN0mMoLQ==} + '@swc/core-linux-x64-gnu@1.15.6': + resolution: {integrity: sha512-1Ufezv5CtJOZaIzYUVMWPORNXgY1MuBrU6LPIeACkdpIaY2wiyfvTiMF57yZ3/c6RQQAY5ZmgV44wCe4dhUFew==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.10.18': - resolution: {integrity: sha512-1TZPReKhFCeX776XaT6wegknfg+g3zODve+r4oslFHI+g7cInfWlxoGNDS3niPKyuafgCdOjme2g3OF+zzxfsQ==} + '@swc/core-linux-x64-musl@1.15.6': + resolution: {integrity: sha512-hKhR3mAvLvp1bmSrM68DyW+p8vKoFospxtffCTdC0fUR+Y6GEmSMTh+KcQ5vcGptnS2VB6QhZx3oLdzoBs0R6g==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.10.18': - resolution: {integrity: sha512-o/2CsaWSN3bkzVQ6DA+BiFKSVEYvhWGA1h+wnL2zWmIDs2Knag54sOEXZkCaf8YQyZesGeXJtPEy9hh/vjJgkA==} + '@swc/core-win32-arm64-msvc@1.15.6': + resolution: {integrity: sha512-s3AMvEOxS+H4l2+bEYwKkfDBf34u1/i+t7OgflFCaZ9wSDA3f693bptPO3m1/DrMTq1iEztEV2MPbjMmQqOmBw==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.10.18': - resolution: {integrity: sha512-eTPASeJtk4mJDfWiYEiOC6OYUi/N7meHbNHcU8e+aKABonhXrIo/FmnTE8vsUtC6+jakT1TQBdiQ8fzJ1kJVwA==} + '@swc/core-win32-ia32-msvc@1.15.6': + resolution: {integrity: sha512-oD9REGtkA/kU+d9xBa0jddrn4BEIfWA7Jx+O+KD1Dhvgd23aYVWwR98kote6DbC/5nAbt201JnW73SkYHBm4pQ==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.10.18': - resolution: {integrity: sha512-1Dud8CDBnc34wkBOboFBQud9YlV1bcIQtKSg7zC8LtwR3h+XAaCayZPkpGmmAlCv1DLQPvkF+s0JcaVC9mfffQ==} + '@swc/core-win32-x64-msvc@1.15.6': + resolution: {integrity: sha512-oJ17Ouy1BkoUM5R8HJF8nX8IbiDror8tjW9x/PUoUVmtxxVb42vpXrS6xGDpH0mXx8K1wVVS6DOgH83uwKEBUQ==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.10.18': - resolution: {integrity: sha512-IUWKD6uQYGRy8w2X9EZrtYg1O3SCijlHbCXzMaHQYc1X7yjijQh4H3IVL9ssZZyVp2ZDfQZu4bD5DWxxvpyjvg==} + '@swc/core@1.15.6': + resolution: {integrity: sha512-BpSCKSwE5DG4N4Um+ZZwvJzJ/4iyMVlzvhJQoR0wJSgccca9ES3+P/7SbPxTM/jtV9vE1llfLPphw+Y+MFhnZg==} engines: {node: '>=10'} peerDependencies: - '@swc/helpers': '*' + '@swc/helpers': '>=0.5.17' peerDependenciesMeta: '@swc/helpers': optional: true @@ -430,46 +463,52 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/types@0.1.17': - resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} + '@swc/types@0.1.25': + resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@22.13.5': - resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==} + '@types/node@25.0.3': + resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==} - '@vitest/expect@3.0.6': - resolution: {integrity: sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==} + '@vitest/expect@4.0.16': + resolution: {integrity: sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==} - '@vitest/mocker@3.0.6': - resolution: {integrity: sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==} + '@vitest/mocker@4.0.16': + resolution: {integrity: sha512-yb6k4AZxJTB+q9ycAvsoxGn+j/po0UaPgajllBgt1PzoMAAmJGYFdDk0uCcRcxb3BrME34I6u8gHZTQlkqSZpg==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 + vite: ^6.0.0 || ^7.0.0-0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@3.0.6': - resolution: {integrity: sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==} + '@vitest/pretty-format@4.0.16': + resolution: {integrity: sha512-eNCYNsSty9xJKi/UdVD8Ou16alu7AYiS2fCPRs0b1OdhJiV89buAXQLpTbe+X8V9L6qrs9CqyvU7OaAopJYPsA==} - '@vitest/runner@3.0.6': - resolution: {integrity: sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==} + '@vitest/runner@4.0.16': + resolution: {integrity: sha512-VWEDm5Wv9xEo80ctjORcTQRJ539EGPB3Pb9ApvVRAY1U/WkHXmmYISqU5E79uCwcW7xYUV38gwZD+RV755fu3Q==} - '@vitest/snapshot@3.0.6': - resolution: {integrity: sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==} + '@vitest/snapshot@4.0.16': + resolution: {integrity: sha512-sf6NcrYhYBsSYefxnry+DR8n3UV4xWZwWxYbCJUt2YdvtqzSPR7VfGrY0zsv090DAbjFZsi7ZaMi1KnSRyK1XA==} - '@vitest/spy@3.0.6': - resolution: {integrity: sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==} + '@vitest/spy@4.0.16': + resolution: {integrity: sha512-4jIOWjKP0ZUaEmJm00E0cOBLU+5WE0BpeNr3XN6TEF05ltro6NJqHWxXD0kA8/Zc8Nh23AT8WQxwNG+WeROupw==} - '@vitest/utils@3.0.6': - resolution: {integrity: sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==} + '@vitest/utils@4.0.16': + resolution: {integrity: sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA==} ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} @@ -479,13 +518,12 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -502,53 +540,25 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - chai@5.2.0: - resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} - engines: {node: '>=12'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chai@6.2.1: + resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + engines: {node: '>=18'} - chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} - engines: {node: '>= 16'} + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -561,11 +571,11 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} - es-module-lexer@1.6.0: - resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - esbuild@0.24.2: - resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} hasBin: true @@ -577,23 +587,28 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - expect-type@1.1.0: - resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} - external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - fastq@1.19.0: - resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} @@ -627,16 +642,12 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - human-id@4.1.1: - resolution: {integrity: sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==} + human-id@4.1.3: + resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} hasBin: true - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + iconv-lite@0.7.1: + resolution: {integrity: sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==} engines: {node: '>=0.10.0'} ignore@5.3.2: @@ -666,8 +677,12 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true jsonfile@4.0.0: @@ -680,11 +695,8 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - loupe@3.1.3: - resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} - - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} @@ -698,17 +710,13 @@ packages: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.8: - resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} @@ -733,8 +741,8 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - package-manager-detector@0.2.9: - resolution: {integrity: sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==} + package-manager-detector@0.2.11: + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -751,10 +759,6 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.0: - resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} - engines: {node: '>= 14.16'} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -762,12 +766,16 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} - postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} prettier@2.8.8: @@ -775,11 +783,14 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.5.2: - resolution: {integrity: sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==} + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} engines: {node: '>=14'} hasBin: true + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -787,19 +798,16 @@ packages: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} - regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.34.8: - resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==} + rollup@4.53.5: + resolution: {integrity: sha512-iTNAbFSlRpcHeeWu73ywU/8KuU/LZmNCSxp6fjQkJBD3ivUb8tpDrXhIxEzA05HlYMEwmtaUnb3RP+YNv162OQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -809,8 +817,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true @@ -846,8 +854,8 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.8.0: - resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} @@ -857,10 +865,6 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} @@ -868,59 +872,47 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - - tinypool@1.0.2: - resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} - engines: {node: ^18.0.0 || >=20.0.0} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} - tinyspy@3.0.2: - resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} - tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - typescript@5.7.3: - resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} - vite-node@3.0.6: - resolution: {integrity: sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - - vite@6.1.1: - resolution: {integrity: sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@7.3.0: + resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 jiti: '>=1.21.0' - less: '*' + less: ^4.0.0 lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 @@ -948,26 +940,32 @@ packages: yaml: optional: true - vitest@3.0.6: - resolution: {integrity: sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vitest@4.0.16: + resolution: {integrity: sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.0.6 - '@vitest/ui': 3.0.6 + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.16 + '@vitest/browser-preview': 4.0.16 + '@vitest/browser-webdriverio': 4.0.16 + '@vitest/ui': 4.0.16 happy-dom: '*' jsdom: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true - '@types/debug': + '@opentelemetry/api': optional: true '@types/node': optional: true - '@vitest/browser': + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': optional: true '@vitest/ui': optional: true @@ -988,15 +986,13 @@ packages: snapshots: - '@babel/runtime@7.26.9': - dependencies: - regenerator-runtime: 0.14.1 + '@babel/runtime@7.28.4': {} - '@changesets/apply-release-plan@7.0.10': + '@changesets/apply-release-plan@7.0.14': dependencies: - '@changesets/config': 3.1.1 + '@changesets/config': 3.1.2 '@changesets/get-version-range-type': 0.4.0 - '@changesets/git': 3.0.2 + '@changesets/git': 3.0.4 '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 @@ -1006,53 +1002,55 @@ snapshots: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.7.1 + semver: 7.7.3 - '@changesets/assemble-release-plan@6.0.6': + '@changesets/assemble-release-plan@6.0.9': dependencies: '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 - semver: 7.7.1 + semver: 7.7.3 '@changesets/changelog-git@0.2.1': dependencies: '@changesets/types': 6.1.0 - '@changesets/cli@2.28.1': + '@changesets/cli@2.29.8(@types/node@25.0.3)': dependencies: - '@changesets/apply-release-plan': 7.0.10 - '@changesets/assemble-release-plan': 6.0.6 + '@changesets/apply-release-plan': 7.0.14 + '@changesets/assemble-release-plan': 6.0.9 '@changesets/changelog-git': 0.2.1 - '@changesets/config': 3.1.1 + '@changesets/config': 3.1.2 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 - '@changesets/get-release-plan': 4.0.8 - '@changesets/git': 3.0.2 + '@changesets/get-release-plan': 4.0.14 + '@changesets/git': 3.0.4 '@changesets/logger': 0.1.1 '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.3 + '@changesets/read': 0.6.6 '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@25.0.3) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 ci-info: 3.9.0 enquirer: 2.4.1 - external-editor: 3.1.0 fs-extra: 7.0.1 mri: 1.2.0 p-limit: 2.3.0 - package-manager-detector: 0.2.9 + package-manager-detector: 0.2.11 picocolors: 1.1.1 resolve-from: 5.0.0 - semver: 7.7.1 + semver: 7.7.3 spawndamnit: 3.0.1 term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' - '@changesets/config@3.1.1': + '@changesets/config@3.1.2': dependencies: '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 @@ -1071,20 +1069,20 @@ snapshots: '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 picocolors: 1.1.1 - semver: 7.7.1 + semver: 7.7.3 - '@changesets/get-release-plan@4.0.8': + '@changesets/get-release-plan@4.0.14': dependencies: - '@changesets/assemble-release-plan': 6.0.6 - '@changesets/config': 3.1.1 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/config': 3.1.2 '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.3 + '@changesets/read': 0.6.6 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 '@changesets/get-version-range-type@0.4.0': {} - '@changesets/git@3.0.2': + '@changesets/git@3.0.4': dependencies: '@changesets/errors': 0.2.0 '@manypkg/get-packages': 1.1.3 @@ -1096,10 +1094,10 @@ snapshots: dependencies: picocolors: 1.1.1 - '@changesets/parse@0.4.1': + '@changesets/parse@0.4.2': dependencies: '@changesets/types': 6.1.0 - js-yaml: 3.14.1 + js-yaml: 4.1.1 '@changesets/pre@2.0.2': dependencies: @@ -1108,11 +1106,11 @@ snapshots: '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 - '@changesets/read@0.6.3': + '@changesets/read@0.6.6': dependencies: - '@changesets/git': 3.0.2 + '@changesets/git': 3.0.4 '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.1 + '@changesets/parse': 0.4.2 '@changesets/types': 6.1.0 fs-extra: 7.0.1 p-filter: 2.1.0 @@ -1131,96 +1129,106 @@ snapshots: dependencies: '@changesets/types': 6.1.0 fs-extra: 7.0.1 - human-id: 4.1.1 + human-id: 4.1.3 prettier: 2.8.8 - '@esbuild/aix-ppc64@0.24.2': + '@esbuild/aix-ppc64@0.27.2': optional: true - '@esbuild/android-arm64@0.24.2': + '@esbuild/android-arm64@0.27.2': optional: true - '@esbuild/android-arm@0.24.2': + '@esbuild/android-arm@0.27.2': optional: true - '@esbuild/android-x64@0.24.2': + '@esbuild/android-x64@0.27.2': optional: true - '@esbuild/darwin-arm64@0.24.2': + '@esbuild/darwin-arm64@0.27.2': optional: true - '@esbuild/darwin-x64@0.24.2': + '@esbuild/darwin-x64@0.27.2': optional: true - '@esbuild/freebsd-arm64@0.24.2': + '@esbuild/freebsd-arm64@0.27.2': optional: true - '@esbuild/freebsd-x64@0.24.2': + '@esbuild/freebsd-x64@0.27.2': optional: true - '@esbuild/linux-arm64@0.24.2': + '@esbuild/linux-arm64@0.27.2': optional: true - '@esbuild/linux-arm@0.24.2': + '@esbuild/linux-arm@0.27.2': optional: true - '@esbuild/linux-ia32@0.24.2': + '@esbuild/linux-ia32@0.27.2': optional: true - '@esbuild/linux-loong64@0.24.2': + '@esbuild/linux-loong64@0.27.2': optional: true - '@esbuild/linux-mips64el@0.24.2': + '@esbuild/linux-mips64el@0.27.2': optional: true - '@esbuild/linux-ppc64@0.24.2': + '@esbuild/linux-ppc64@0.27.2': optional: true - '@esbuild/linux-riscv64@0.24.2': + '@esbuild/linux-riscv64@0.27.2': optional: true - '@esbuild/linux-s390x@0.24.2': + '@esbuild/linux-s390x@0.27.2': optional: true - '@esbuild/linux-x64@0.24.2': + '@esbuild/linux-x64@0.27.2': optional: true - '@esbuild/netbsd-arm64@0.24.2': + '@esbuild/netbsd-arm64@0.27.2': optional: true - '@esbuild/netbsd-x64@0.24.2': + '@esbuild/netbsd-x64@0.27.2': optional: true - '@esbuild/openbsd-arm64@0.24.2': + '@esbuild/openbsd-arm64@0.27.2': optional: true - '@esbuild/openbsd-x64@0.24.2': + '@esbuild/openbsd-x64@0.27.2': optional: true - '@esbuild/sunos-x64@0.24.2': + '@esbuild/openharmony-arm64@0.27.2': optional: true - '@esbuild/win32-arm64@0.24.2': + '@esbuild/sunos-x64@0.27.2': optional: true - '@esbuild/win32-ia32@0.24.2': + '@esbuild/win32-arm64@0.27.2': optional: true - '@esbuild/win32-x64@0.24.2': + '@esbuild/win32-ia32@0.27.2': optional: true - '@jridgewell/sourcemap-codec@1.5.0': {} + '@esbuild/win32-x64@0.27.2': + optional: true + + '@inquirer/external-editor@1.0.3(@types/node@25.0.3)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.1 + optionalDependencies: + '@types/node': 25.0.3 + + '@jridgewell/sourcemap-codec@1.5.5': {} '@manypkg/find-root@1.1.0': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.28.4 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 '@manypkg/get-packages@1.1.3': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.28.4 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -1237,177 +1245,192 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.0 + fastq: 1.19.1 - '@rollup/rollup-android-arm-eabi@4.34.8': + '@rollup/rollup-android-arm-eabi@4.53.5': optional: true - '@rollup/rollup-android-arm64@4.34.8': + '@rollup/rollup-android-arm64@4.53.5': optional: true - '@rollup/rollup-darwin-arm64@4.34.8': + '@rollup/rollup-darwin-arm64@4.53.5': optional: true - '@rollup/rollup-darwin-x64@4.34.8': + '@rollup/rollup-darwin-x64@4.53.5': optional: true - '@rollup/rollup-freebsd-arm64@4.34.8': + '@rollup/rollup-freebsd-arm64@4.53.5': optional: true - '@rollup/rollup-freebsd-x64@4.34.8': + '@rollup/rollup-freebsd-x64@4.53.5': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.34.8': + '@rollup/rollup-linux-arm-gnueabihf@4.53.5': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.34.8': + '@rollup/rollup-linux-arm-musleabihf@4.53.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.34.8': + '@rollup/rollup-linux-arm64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-arm64-musl@4.34.8': + '@rollup/rollup-linux-arm64-musl@4.53.5': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.34.8': + '@rollup/rollup-linux-loong64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': + '@rollup/rollup-linux-ppc64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.34.8': + '@rollup/rollup-linux-riscv64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.34.8': + '@rollup/rollup-linux-riscv64-musl@4.53.5': optional: true - '@rollup/rollup-linux-x64-gnu@4.34.8': + '@rollup/rollup-linux-s390x-gnu@4.53.5': optional: true - '@rollup/rollup-linux-x64-musl@4.34.8': + '@rollup/rollup-linux-x64-gnu@4.53.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.34.8': + '@rollup/rollup-linux-x64-musl@4.53.5': optional: true - '@rollup/rollup-win32-ia32-msvc@4.34.8': + '@rollup/rollup-openharmony-arm64@4.53.5': optional: true - '@rollup/rollup-win32-x64-msvc@4.34.8': + '@rollup/rollup-win32-arm64-msvc@4.53.5': optional: true - '@swc/core-darwin-arm64@1.10.18': + '@rollup/rollup-win32-ia32-msvc@4.53.5': optional: true - '@swc/core-darwin-x64@1.10.18': + '@rollup/rollup-win32-x64-gnu@4.53.5': optional: true - '@swc/core-linux-arm-gnueabihf@1.10.18': + '@rollup/rollup-win32-x64-msvc@4.53.5': optional: true - '@swc/core-linux-arm64-gnu@1.10.18': + '@standard-schema/spec@1.1.0': {} + + '@swc/core-darwin-arm64@1.15.6': optional: true - '@swc/core-linux-arm64-musl@1.10.18': + '@swc/core-darwin-x64@1.15.6': optional: true - '@swc/core-linux-x64-gnu@1.10.18': + '@swc/core-linux-arm-gnueabihf@1.15.6': optional: true - '@swc/core-linux-x64-musl@1.10.18': + '@swc/core-linux-arm64-gnu@1.15.6': optional: true - '@swc/core-win32-arm64-msvc@1.10.18': + '@swc/core-linux-arm64-musl@1.15.6': optional: true - '@swc/core-win32-ia32-msvc@1.10.18': + '@swc/core-linux-x64-gnu@1.15.6': optional: true - '@swc/core-win32-x64-msvc@1.10.18': + '@swc/core-linux-x64-musl@1.15.6': optional: true - '@swc/core@1.10.18': + '@swc/core-win32-arm64-msvc@1.15.6': + optional: true + + '@swc/core-win32-ia32-msvc@1.15.6': + optional: true + + '@swc/core-win32-x64-msvc@1.15.6': + optional: true + + '@swc/core@1.15.6': dependencies: '@swc/counter': 0.1.3 - '@swc/types': 0.1.17 + '@swc/types': 0.1.25 optionalDependencies: - '@swc/core-darwin-arm64': 1.10.18 - '@swc/core-darwin-x64': 1.10.18 - '@swc/core-linux-arm-gnueabihf': 1.10.18 - '@swc/core-linux-arm64-gnu': 1.10.18 - '@swc/core-linux-arm64-musl': 1.10.18 - '@swc/core-linux-x64-gnu': 1.10.18 - '@swc/core-linux-x64-musl': 1.10.18 - '@swc/core-win32-arm64-msvc': 1.10.18 - '@swc/core-win32-ia32-msvc': 1.10.18 - '@swc/core-win32-x64-msvc': 1.10.18 + '@swc/core-darwin-arm64': 1.15.6 + '@swc/core-darwin-x64': 1.15.6 + '@swc/core-linux-arm-gnueabihf': 1.15.6 + '@swc/core-linux-arm64-gnu': 1.15.6 + '@swc/core-linux-arm64-musl': 1.15.6 + '@swc/core-linux-x64-gnu': 1.15.6 + '@swc/core-linux-x64-musl': 1.15.6 + '@swc/core-win32-arm64-msvc': 1.15.6 + '@swc/core-win32-ia32-msvc': 1.15.6 + '@swc/core-win32-x64-msvc': 1.15.6 '@swc/counter@0.1.3': {} - '@swc/types@0.1.17': + '@swc/types@0.1.25': dependencies: '@swc/counter': 0.1.3 - '@types/estree@1.0.6': {} + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} '@types/node@12.20.55': {} - '@types/node@22.13.5': + '@types/node@25.0.3': dependencies: - undici-types: 6.20.0 + undici-types: 7.16.0 - '@vitest/expect@3.0.6': + '@vitest/expect@4.0.16': dependencies: - '@vitest/spy': 3.0.6 - '@vitest/utils': 3.0.6 - chai: 5.2.0 - tinyrainbow: 2.0.0 + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.16 + '@vitest/utils': 4.0.16 + chai: 6.2.1 + tinyrainbow: 3.0.3 - '@vitest/mocker@3.0.6(vite@6.1.1(@types/node@22.13.5))': + '@vitest/mocker@4.0.16(vite@7.3.0(@types/node@25.0.3))': dependencies: - '@vitest/spy': 3.0.6 + '@vitest/spy': 4.0.16 estree-walker: 3.0.3 - magic-string: 0.30.17 + magic-string: 0.30.21 optionalDependencies: - vite: 6.1.1(@types/node@22.13.5) + vite: 7.3.0(@types/node@25.0.3) - '@vitest/pretty-format@3.0.6': + '@vitest/pretty-format@4.0.16': dependencies: - tinyrainbow: 2.0.0 + tinyrainbow: 3.0.3 - '@vitest/runner@3.0.6': + '@vitest/runner@4.0.16': dependencies: - '@vitest/utils': 3.0.6 + '@vitest/utils': 4.0.16 pathe: 2.0.3 - '@vitest/snapshot@3.0.6': + '@vitest/snapshot@4.0.16': dependencies: - '@vitest/pretty-format': 3.0.6 - magic-string: 0.30.17 + '@vitest/pretty-format': 4.0.16 + magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@3.0.6': - dependencies: - tinyspy: 3.0.2 + '@vitest/spy@4.0.16': {} - '@vitest/utils@3.0.6': + '@vitest/utils@4.0.16': dependencies: - '@vitest/pretty-format': 3.0.6 - loupe: 3.1.3 - tinyrainbow: 2.0.0 + '@vitest/pretty-format': 4.0.16 + tinyrainbow: 3.0.3 ansi-colors@4.1.3: {} ansi-regex@5.0.1: {} - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - argparse@1.0.10: dependencies: sprintf-js: 1.0.3 + argparse@2.0.1: {} + array-union@2.1.0: {} assertion-error@2.0.1: {} @@ -1420,45 +1443,20 @@ snapshots: dependencies: fill-range: 7.1.1 - cac@6.7.14: {} + chai@6.2.1: {} - chai@5.2.0: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.1.3 - pathval: 2.0.0 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 + chalk@5.6.2: {} - chardet@0.7.0: {} - - check-error@2.1.1: {} + chardet@2.1.1: {} ci-info@3.9.0: {} - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - debug@4.4.0: - dependencies: - ms: 2.1.3 - - deep-eql@5.0.2: {} - detect-indent@6.1.0: {} dir-glob@3.0.1: @@ -1470,52 +1468,47 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 - es-module-lexer@1.6.0: {} + es-module-lexer@1.7.0: {} - esbuild@0.24.2: + esbuild@0.27.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.24.2 - '@esbuild/android-arm': 0.24.2 - '@esbuild/android-arm64': 0.24.2 - '@esbuild/android-x64': 0.24.2 - '@esbuild/darwin-arm64': 0.24.2 - '@esbuild/darwin-x64': 0.24.2 - '@esbuild/freebsd-arm64': 0.24.2 - '@esbuild/freebsd-x64': 0.24.2 - '@esbuild/linux-arm': 0.24.2 - '@esbuild/linux-arm64': 0.24.2 - '@esbuild/linux-ia32': 0.24.2 - '@esbuild/linux-loong64': 0.24.2 - '@esbuild/linux-mips64el': 0.24.2 - '@esbuild/linux-ppc64': 0.24.2 - '@esbuild/linux-riscv64': 0.24.2 - '@esbuild/linux-s390x': 0.24.2 - '@esbuild/linux-x64': 0.24.2 - '@esbuild/netbsd-arm64': 0.24.2 - '@esbuild/netbsd-x64': 0.24.2 - '@esbuild/openbsd-arm64': 0.24.2 - '@esbuild/openbsd-x64': 0.24.2 - '@esbuild/sunos-x64': 0.24.2 - '@esbuild/win32-arm64': 0.24.2 - '@esbuild/win32-ia32': 0.24.2 - '@esbuild/win32-x64': 0.24.2 + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 esprima@4.0.1: {} estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 - expect-type@1.1.0: {} + expect-type@1.3.0: {} extendable-error@0.1.7: {} - external-editor@3.1.0: - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 - fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -1524,9 +1517,13 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fastq@1.19.0: + fastq@1.19.1: dependencies: - reusify: 1.0.4 + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 fill-range@7.1.1: dependencies: @@ -1567,11 +1564,9 @@ snapshots: graceful-fs@4.2.11: {} - has-flag@4.0.0: {} + human-id@4.1.3: {} - human-id@4.1.1: {} - - iconv-lite@0.4.24: + iconv-lite@0.7.1: dependencies: safer-buffer: 2.1.2 @@ -1593,11 +1588,15 @@ snapshots: isexe@2.0.0: {} - js-yaml@3.14.1: + js-yaml@3.14.2: dependencies: argparse: 1.0.10 esprima: 4.0.1 + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -1608,11 +1607,9 @@ snapshots: lodash.startcase@4.4.0: {} - loupe@3.1.3: {} - - magic-string@0.30.17: + magic-string@0.30.21: dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 merge2@1.4.1: {} @@ -1623,11 +1620,9 @@ snapshots: mri@1.2.0: {} - ms@2.1.3: {} + nanoid@3.3.11: {} - nanoid@3.3.8: {} - - os-tmpdir@1.0.2: {} + obug@2.1.1: {} outdent@0.5.0: {} @@ -1647,7 +1642,9 @@ snapshots: p-try@2.2.0: {} - package-manager-detector@0.2.9: {} + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.11 path-exists@4.0.0: {} @@ -1657,62 +1654,65 @@ snapshots: pathe@2.0.3: {} - pathval@2.0.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} + picomatch@4.0.3: {} + pify@4.0.1: {} - postcss@8.5.3: + postcss@8.5.6: dependencies: - nanoid: 3.3.8 + nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 prettier@2.8.8: {} - prettier@3.5.2: {} + prettier@3.7.4: {} + + quansync@0.2.11: {} queue-microtask@1.2.3: {} read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 - js-yaml: 3.14.1 + js-yaml: 3.14.2 pify: 4.0.1 strip-bom: 3.0.0 - regenerator-runtime@0.14.1: {} - resolve-from@5.0.0: {} - reusify@1.0.4: {} + reusify@1.1.0: {} - rollup@4.34.8: + rollup@4.53.5: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.34.8 - '@rollup/rollup-android-arm64': 4.34.8 - '@rollup/rollup-darwin-arm64': 4.34.8 - '@rollup/rollup-darwin-x64': 4.34.8 - '@rollup/rollup-freebsd-arm64': 4.34.8 - '@rollup/rollup-freebsd-x64': 4.34.8 - '@rollup/rollup-linux-arm-gnueabihf': 4.34.8 - '@rollup/rollup-linux-arm-musleabihf': 4.34.8 - '@rollup/rollup-linux-arm64-gnu': 4.34.8 - '@rollup/rollup-linux-arm64-musl': 4.34.8 - '@rollup/rollup-linux-loongarch64-gnu': 4.34.8 - '@rollup/rollup-linux-powerpc64le-gnu': 4.34.8 - '@rollup/rollup-linux-riscv64-gnu': 4.34.8 - '@rollup/rollup-linux-s390x-gnu': 4.34.8 - '@rollup/rollup-linux-x64-gnu': 4.34.8 - '@rollup/rollup-linux-x64-musl': 4.34.8 - '@rollup/rollup-win32-arm64-msvc': 4.34.8 - '@rollup/rollup-win32-ia32-msvc': 4.34.8 - '@rollup/rollup-win32-x64-msvc': 4.34.8 + '@rollup/rollup-android-arm-eabi': 4.53.5 + '@rollup/rollup-android-arm64': 4.53.5 + '@rollup/rollup-darwin-arm64': 4.53.5 + '@rollup/rollup-darwin-x64': 4.53.5 + '@rollup/rollup-freebsd-arm64': 4.53.5 + '@rollup/rollup-freebsd-x64': 4.53.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.5 + '@rollup/rollup-linux-arm-musleabihf': 4.53.5 + '@rollup/rollup-linux-arm64-gnu': 4.53.5 + '@rollup/rollup-linux-arm64-musl': 4.53.5 + '@rollup/rollup-linux-loong64-gnu': 4.53.5 + '@rollup/rollup-linux-ppc64-gnu': 4.53.5 + '@rollup/rollup-linux-riscv64-gnu': 4.53.5 + '@rollup/rollup-linux-riscv64-musl': 4.53.5 + '@rollup/rollup-linux-s390x-gnu': 4.53.5 + '@rollup/rollup-linux-x64-gnu': 4.53.5 + '@rollup/rollup-linux-x64-musl': 4.53.5 + '@rollup/rollup-openharmony-arm64': 4.53.5 + '@rollup/rollup-win32-arm64-msvc': 4.53.5 + '@rollup/rollup-win32-ia32-msvc': 4.53.5 + '@rollup/rollup-win32-x64-gnu': 4.53.5 + '@rollup/rollup-win32-x64-msvc': 4.53.5 fsevents: 2.3.3 run-parallel@1.2.0: @@ -1721,7 +1721,7 @@ snapshots: safer-buffer@2.1.2: {} - semver@7.7.1: {} + semver@7.7.3: {} shebang-command@2.0.0: dependencies: @@ -1746,7 +1746,7 @@ snapshots: stackback@0.0.2: {} - std-env@3.8.0: {} + std-env@3.10.0: {} strip-ansi@6.0.1: dependencies: @@ -1754,90 +1754,65 @@ snapshots: strip-bom@3.0.0: {} - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - term-size@2.2.1: {} tinybench@2.9.0: {} - tinyexec@0.3.2: {} - - tinypool@1.0.2: {} - - tinyrainbow@2.0.0: {} + tinyexec@1.0.2: {} - tinyspy@3.0.2: {} - - tmp@0.0.33: + tinyglobby@0.2.15: dependencies: - os-tmpdir: 1.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyrainbow@3.0.3: {} to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - typescript@5.7.3: {} + typescript@5.9.3: {} - undici-types@6.20.0: {} + undici-types@7.16.0: {} universalify@0.1.2: {} - vite-node@3.0.6(@types/node@22.13.5): - dependencies: - cac: 6.7.14 - debug: 4.4.0 - es-module-lexer: 1.6.0 - pathe: 2.0.3 - vite: 6.1.1(@types/node@22.13.5) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite@6.1.1(@types/node@22.13.5): + vite@7.3.0(@types/node@25.0.3): dependencies: - esbuild: 0.24.2 - postcss: 8.5.3 - rollup: 4.34.8 + esbuild: 0.27.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.5 + tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 22.13.5 + '@types/node': 25.0.3 fsevents: 2.3.3 - vitest@3.0.6(@types/node@22.13.5): - dependencies: - '@vitest/expect': 3.0.6 - '@vitest/mocker': 3.0.6(vite@6.1.1(@types/node@22.13.5)) - '@vitest/pretty-format': 3.0.6 - '@vitest/runner': 3.0.6 - '@vitest/snapshot': 3.0.6 - '@vitest/spy': 3.0.6 - '@vitest/utils': 3.0.6 - chai: 5.2.0 - debug: 4.4.0 - expect-type: 1.1.0 - magic-string: 0.30.17 + vitest@4.0.16(@types/node@25.0.3): + dependencies: + '@vitest/expect': 4.0.16 + '@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@25.0.3)) + '@vitest/pretty-format': 4.0.16 + '@vitest/runner': 4.0.16 + '@vitest/snapshot': 4.0.16 + '@vitest/spy': 4.0.16 + '@vitest/utils': 4.0.16 + es-module-lexer: 1.7.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 pathe: 2.0.3 - std-env: 3.8.0 + picomatch: 4.0.3 + std-env: 3.10.0 tinybench: 2.9.0 - tinyexec: 0.3.2 - tinypool: 1.0.2 - tinyrainbow: 2.0.0 - vite: 6.1.1(@types/node@22.13.5) - vite-node: 3.0.6(@types/node@22.13.5) + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.3.0(@types/node@25.0.3) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.13.5 + '@types/node': 25.0.3 transitivePeerDependencies: - jiti - less @@ -1847,7 +1822,6 @@ snapshots: - sass-embedded - stylus - sugarss - - supports-color - terser - tsx - yaml diff --git a/src/LogDash.ts b/src/LogDash.ts deleted file mode 100644 index 9d7ca95..0000000 --- a/src/LogDash.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Logger } from './logger/Logger.js'; -import { BaseMetrics } from './metrics/BaseMetrics.js'; -import { createMetrics } from './metrics/createMetrics.js'; -import { createLogSync } from './sync/createLogSync.js'; -import { InitializationParams } from './types/InitializationParams.js'; - -export type LogdashInstance = { - logger: Logger; - metrics: BaseMetrics; -}; - -export const createLogDash = ( - params?: InitializationParams, -): LogdashInstance => { - const requiredParams = { - apiKey: params?.apiKey || '', - host: params?.host || 'https://api.logdash.io', - verbose: params?.verbose || false, - }; - const logSync = createLogSync(requiredParams); - const metrics = createMetrics(requiredParams); - - return { - // todo: make Logger params an object - logger: new Logger(console.log, undefined, (level, message) => { - logSync.send(message, level, new Date().toISOString()); - }), - metrics, - }; -}; diff --git a/src/Logdash_.ts b/src/Logdash_.ts new file mode 100644 index 0000000..7f31cf2 --- /dev/null +++ b/src/Logdash_.ts @@ -0,0 +1,205 @@ +import chalk from 'chalk'; +import { internalLogger } from './logger/internalLogger.js'; +import { RequestQueue } from './queue/RequestQueue.js'; +import { + HttpTransport, + LogPayload, + MetricPayload, +} from './transport/HttpTransport.js'; +import { LogLevel } from './types/LogLevel.js'; + +export interface LogdashOptions { + host?: string; + verbose?: boolean; +} + +const LOG_LEVEL_COLORS: Record = { + [LogLevel.ERROR]: [231, 0, 11], + [LogLevel.WARN]: [254, 154, 0], + [LogLevel.INFO]: [21, 93, 252], + [LogLevel.HTTP]: [0, 166, 166], + [LogLevel.VERBOSE]: [0, 166, 0], + [LogLevel.DEBUG]: [0, 166, 62], + [LogLevel.SILLY]: [80, 80, 80], +}; + +interface LogdashCore { + logQueue: RequestQueue; + metricQueue: RequestQueue; + sequenceNumber: number; + verbose: boolean; +} + +export class Logdash { + private readonly core: LogdashCore; + private readonly namespace?: string; + + constructor(apiKey?: string, options?: LogdashOptions); + constructor(core: LogdashCore, namespace: string); + constructor( + apiKeyOrCore?: string | LogdashCore, + optionsOrNamespace?: LogdashOptions | string, + ) { + if (this.isLogdashCore(apiKeyOrCore)) { + // Internal constructor for namespaced instances + this.core = apiKeyOrCore; + this.namespace = optionsOrNamespace as string; + } else { + // Public constructor: new Logdash(apiKey?, options?) + const apiKey = apiKeyOrCore ?? ''; + const options = optionsOrNamespace as LogdashOptions | undefined; + const host = options?.host ?? 'https://api.logdash.io'; + const verbose = options?.verbose ?? false; + + const transport = new HttpTransport({ host, apiKey }); + + this.core = { + logQueue: new RequestQueue((logs) => transport.sendLogs(logs)), + metricQueue: new RequestQueue((metrics) => + transport.sendMetrics(metrics), + ), + sequenceNumber: 0, + verbose, + }; + this.namespace = undefined; + } + } + + private isLogdashCore(value: unknown): value is LogdashCore { + return ( + typeof value === 'object' && + value !== null && + 'logQueue' in value && + 'metricQueue' in value + ); + } + + // === Logging Methods === + + error(...data: unknown[]): void { + this.log(LogLevel.ERROR, data); + } + + warn(...data: unknown[]): void { + this.log(LogLevel.WARN, data); + } + + info(...data: unknown[]): void { + this.log(LogLevel.INFO, data); + } + + http(...data: unknown[]): void { + this.log(LogLevel.HTTP, data); + } + + verbose(...data: unknown[]): void { + this.log(LogLevel.VERBOSE, data); + } + + debug(...data: unknown[]): void { + this.log(LogLevel.DEBUG, data); + } + + silly(...data: unknown[]): void { + this.log(LogLevel.SILLY, data); + } + + // === Metric Methods === + + setMetric(name: string, value: number): void { + if (this.core.verbose) { + internalLogger.verbose(`Setting metric ${name} to ${value}`); + } + + this.core.metricQueue.add({ + name, + value, + operation: 'set', + namespace: this.namespace, + }); + } + + mutateMetric(name: string, delta: number): void { + if (this.core.verbose) { + internalLogger.verbose(`Mutating metric ${name} by ${delta}`); + } + + this.core.metricQueue.add({ + name, + value: delta, + operation: 'change', + namespace: this.namespace, + }); + } + + // === Namespace === + + withNamespace(name: string): Logdash { + return new Logdash(this.core, name); + } + + // === Lifecycle === + + async flush(): Promise { + await Promise.all([ + this.core.logQueue.flush(), + this.core.metricQueue.flush(), + ]); + } + + destroy(): void { + this.core.logQueue.destroy(); + this.core.metricQueue.destroy(); + } + + // === Private Methods === + + private log(level: LogLevel, data: unknown[]): void { + const message = this.formatData(data); + const now = new Date(); + + // Print to console with colors + this.printToConsole(level, message, now); + + // Queue for sending + this.core.logQueue.add({ + message, + level, + createdAt: now.toISOString(), + sequenceNumber: this.core.sequenceNumber++, + namespace: this.namespace, + }); + } + + private printToConsole(level: LogLevel, message: string, date: Date): void { + const color = LOG_LEVEL_COLORS[level]; + + const datePrefix = chalk.rgb(156, 156, 156)(`[${date.toISOString()}]`); + const levelPrefix = chalk.rgb( + color[0], + color[1], + color[2], + )(`${level.toUpperCase()} `); + const namespacePrefix = this.namespace + ? chalk.rgb(180, 180, 180)(`[${this.namespace}] `) + : ''; + + const formattedMessage = `${datePrefix} ${levelPrefix}${namespacePrefix}${message}`; + console.log(formattedMessage); + } + + private formatData(data: unknown[]): string { + return data + .map((item) => { + if (typeof item === 'object' && item !== null) { + try { + return JSON.stringify(item); + } catch { + return String(item); + } + } + return String(item); + }) + .join(' '); + } +} diff --git a/src/__tests__/HttpTransport.test.ts b/src/__tests__/HttpTransport.test.ts new file mode 100644 index 0000000..512ec71 --- /dev/null +++ b/src/__tests__/HttpTransport.test.ts @@ -0,0 +1,180 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { HttpTransport } from '../transport/HttpTransport.js'; + +describe('HttpTransport', () => { + let mockFetch: ReturnType; + + beforeEach(() => { + mockFetch = vi.fn().mockResolvedValue({ + ok: true, + status: 200, + statusText: 'OK', + }); + vi.stubGlobal('fetch', mockFetch); + }); + + afterEach(() => { + vi.unstubAllGlobals(); + vi.restoreAllMocks(); + }); + + describe('constructor', () => { + it('creates instance with required options', () => { + const transport = new HttpTransport({ + host: 'https://api.test.com', + apiKey: 'test-key', + }); + expect(transport).toBeInstanceOf(HttpTransport); + }); + }); + + describe('sendLogs', () => { + it('sends logs to /logs/batch endpoint', async () => { + const transport = new HttpTransport({ + host: 'https://api.test.com', + apiKey: 'test-key', + }); + + await transport.sendLogs([ + { + message: 'test', + level: 'info', + createdAt: '2024-01-01T00:00:00.000Z', + sequenceNumber: 0, + }, + ]); + + expect(mockFetch).toHaveBeenCalledWith( + 'https://api.test.com/logs/batch', + expect.objectContaining({ + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'project-api-key': 'test-key', + }, + }), + ); + }); + + it('wraps logs in batch format', async () => { + const transport = new HttpTransport({ + host: 'https://api.test.com', + apiKey: 'test-key', + }); + + await transport.sendLogs([ + { + message: 'test message', + level: 'error', + createdAt: '2024-01-01T00:00:00.000Z', + sequenceNumber: 42, + namespace: 'auth', + }, + ]); + + expect(mockFetch).toHaveBeenCalledTimes(1); + const call = mockFetch.mock.calls[0]; + const body = JSON.parse(call[1].body); + + expect(body).toEqual({ + logs: [ + { + message: 'test message', + level: 'error', + createdAt: '2024-01-01T00:00:00.000Z', + sequenceNumber: 42, + namespace: 'auth', + }, + ], + }); + }); + }); + + describe('sendMetrics', () => { + it('sends metrics to /metrics endpoint', async () => { + const transport = new HttpTransport({ + host: 'https://api.test.com', + apiKey: 'test-key', + }); + + await transport.sendMetrics([ + { + name: 'users', + value: 100, + operation: 'set', + }, + ]); + + expect(mockFetch).toHaveBeenCalledWith( + 'https://api.test.com/metrics', + expect.objectContaining({ + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'project-api-key': 'test-key', + }, + }), + ); + }); + + it('sends each metric individually', async () => { + const transport = new HttpTransport({ + host: 'https://api.test.com', + apiKey: 'test-key', + }); + + await transport.sendMetrics([ + { name: 'users', value: 100, operation: 'set' }, + { name: 'requests', value: 1, operation: 'change' }, + ]); + + expect(mockFetch).toHaveBeenCalledTimes(2); + }); + }); + + describe('error handling', () => { + it('throws on non-ok response', async () => { + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 500, + statusText: 'Internal Server Error', + }); + + const transport = new HttpTransport({ + host: 'https://api.test.com', + apiKey: 'test-key', + }); + + await expect( + transport.sendLogs([ + { + message: 'test', + level: 'info', + createdAt: '2024-01-01T00:00:00.000Z', + sequenceNumber: 0, + }, + ]), + ).rejects.toThrow('HTTP 500: Internal Server Error'); + }); + + it('throws on network error', async () => { + mockFetch.mockRejectedValueOnce(new Error('Network error')); + + const transport = new HttpTransport({ + host: 'https://api.test.com', + apiKey: 'test-key', + }); + + await expect( + transport.sendLogs([ + { + message: 'test', + level: 'info', + createdAt: '2024-01-01T00:00:00.000Z', + sequenceNumber: 0, + }, + ]), + ).rejects.toThrow('Network error'); + }); + }); +}); diff --git a/src/__tests__/Logdash.test.ts b/src/__tests__/Logdash.test.ts new file mode 100644 index 0000000..39e2ca2 --- /dev/null +++ b/src/__tests__/Logdash.test.ts @@ -0,0 +1,172 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { Logdash } from '../Logdash_.js'; + +describe('Logdash', () => { + beforeEach(() => { + vi.spyOn(console, 'log').mockImplementation(() => {}); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('constructor', () => { + it('creates instance without options', () => { + const logdash = new Logdash(); + expect(logdash).toBeInstanceOf(Logdash); + logdash.destroy(); + }); + + it('creates instance with apiKey', () => { + const logdash = new Logdash('test-key'); + expect(logdash).toBeInstanceOf(Logdash); + logdash.destroy(); + }); + + it('creates instance with custom host', () => { + const logdash = new Logdash('test-key', { + host: 'https://custom.api.com', + }); + expect(logdash).toBeInstanceOf(Logdash); + logdash.destroy(); + }); + }); + + describe('logging methods', () => { + let logdash: Logdash; + + beforeEach(() => { + logdash = new Logdash(); + }); + + afterEach(() => { + logdash.destroy(); + }); + + it('logs error messages', () => { + logdash.error('test error'); + expect(console.log).toHaveBeenCalled(); + }); + + it('logs warn messages', () => { + logdash.warn('test warning'); + expect(console.log).toHaveBeenCalled(); + }); + + it('logs info messages', () => { + logdash.info('test info'); + expect(console.log).toHaveBeenCalled(); + }); + + it('logs http messages', () => { + logdash.http('test http'); + expect(console.log).toHaveBeenCalled(); + }); + + it('logs verbose messages', () => { + logdash.verbose('test verbose'); + expect(console.log).toHaveBeenCalled(); + }); + + it('logs debug messages', () => { + logdash.debug('test debug'); + expect(console.log).toHaveBeenCalled(); + }); + + it('logs silly messages', () => { + logdash.silly('test silly'); + expect(console.log).toHaveBeenCalled(); + }); + + it('formats objects as JSON', () => { + logdash.info('data:', { key: 'value' }); + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining('{"key":"value"}'), + ); + }); + + it('handles multiple arguments', () => { + logdash.info('first', 'second', 123); + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining('first second 123'), + ); + }); + }); + + describe('withNamespace', () => { + let logdash: Logdash; + + beforeEach(() => { + logdash = new Logdash(); + }); + + afterEach(() => { + logdash.destroy(); + }); + + it('returns a new Logdash instance', () => { + const namespaced = logdash.withNamespace('auth'); + expect(namespaced).toBeInstanceOf(Logdash); + }); + + it('includes namespace in log output', () => { + const namespaced = logdash.withNamespace('auth'); + namespaced.info('test message'); + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining('[auth]'), + ); + }); + + it('allows creating multiple namespaces', () => { + const auth = logdash.withNamespace('auth'); + const db = logdash.withNamespace('db'); + + auth.info('auth message'); + db.info('db message'); + + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining('[auth]'), + ); + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining('[db]'), + ); + }); + }); + + describe('metrics', () => { + let logdash: Logdash; + + beforeEach(() => { + logdash = new Logdash(); + }); + + afterEach(() => { + logdash.destroy(); + }); + + it('queues setMetric calls', () => { + // This shouldn't throw + expect(() => logdash.setMetric('users', 100)).not.toThrow(); + }); + + it('queues mutateMetric calls', () => { + // This shouldn't throw + expect(() => logdash.mutateMetric('requests', 1)).not.toThrow(); + }); + }); + + describe('flush', () => { + it('resolves when queue is empty', async () => { + const logdash = new Logdash(); + await expect(logdash.flush()).resolves.toBeUndefined(); + logdash.destroy(); + }); + + it('waits for pending items', async () => { + const logdash = new Logdash(); + logdash.info('test message'); + await expect(logdash.flush()).resolves.toBeUndefined(); + logdash.destroy(); + }); + }); +}); diff --git a/src/__tests__/RequestQueue.test.ts b/src/__tests__/RequestQueue.test.ts new file mode 100644 index 0000000..0712e73 --- /dev/null +++ b/src/__tests__/RequestQueue.test.ts @@ -0,0 +1,179 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { RequestQueue } from '../queue/RequestQueue.js'; + +describe('RequestQueue', () => { + beforeEach(() => { + vi.spyOn(console, 'log').mockImplementation(() => {}); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('add', () => { + it('adds items to the queue', () => { + const sendFn = vi.fn().mockResolvedValue(undefined); + const queue = new RequestQueue(sendFn); + + queue.add({ id: 1 }); + queue.add({ id: 2 }); + + queue.destroy(); + expect(sendFn).not.toHaveBeenCalled(); // Not flushed yet + }); + + it('ignores items after destroy', () => { + const sendFn = vi.fn().mockResolvedValue(undefined); + const queue = new RequestQueue(sendFn); + + queue.destroy(); + queue.add({ id: 1 }); + + expect(sendFn).not.toHaveBeenCalled(); + }); + }); + + describe('batching', () => { + it('flushes when batch size is reached', async () => { + const sendFn = vi.fn().mockResolvedValue(undefined); + const queue = new RequestQueue(sendFn, { batchSize: 3 }); + + queue.add({ id: 1 }); + queue.add({ id: 2 }); + expect(sendFn).not.toHaveBeenCalled(); + + queue.add({ id: 3 }); // Triggers flush + + // Wait for the async operation + await new Promise((resolve) => setTimeout(resolve, 10)); + + expect(sendFn).toHaveBeenCalledWith([ + { id: 1 }, + { id: 2 }, + { id: 3 }, + ]); + + queue.destroy(); + }); + + it('flushes on interval', async () => { + const sendFn = vi.fn().mockResolvedValue(undefined); + const queue = new RequestQueue(sendFn, { + batchSize: 100, + flushIntervalMs: 50, + }); + + queue.add({ id: 1 }); + queue.add({ id: 2 }); + + // Wait for interval + await new Promise((resolve) => setTimeout(resolve, 100)); + + expect(sendFn).toHaveBeenCalledWith([{ id: 1 }, { id: 2 }]); + + queue.destroy(); + }); + }); + + describe('retry', () => { + it('retries failed requests', async () => { + const sendFn = vi + .fn() + .mockRejectedValueOnce(new Error('Network error')) + .mockResolvedValueOnce(undefined); + + const queue = new RequestQueue(sendFn, { + batchSize: 1, + maxRetries: 3, + baseRetryDelayMs: 10, + }); + + queue.add({ id: 1 }); + + // Wait for retries + await new Promise((resolve) => setTimeout(resolve, 100)); + + expect(sendFn).toHaveBeenCalledTimes(2); + + queue.destroy(); + }); + + it('stops after max retries', async () => { + const sendFn = vi + .fn() + .mockRejectedValue(new Error('Network error')); + + const queue = new RequestQueue(sendFn, { + batchSize: 1, + maxRetries: 3, + baseRetryDelayMs: 10, + }); + + queue.add({ id: 1 }); + + // Wait for all retries (10 + 20 + 40 = 70ms base, add buffer) + await new Promise((resolve) => setTimeout(resolve, 200)); + + expect(sendFn).toHaveBeenCalledTimes(3); + + queue.destroy(); + }); + }); + + describe('flush', () => { + it('sends remaining items immediately', async () => { + const sendFn = vi.fn().mockResolvedValue(undefined); + const queue = new RequestQueue(sendFn, { batchSize: 100 }); + + queue.add({ id: 1 }); + queue.add({ id: 2 }); + + await queue.flush(); + + expect(sendFn).toHaveBeenCalledWith([{ id: 1 }, { id: 2 }]); + + queue.destroy(); + }); + + it('waits for in-flight requests', async () => { + let resolveRequest: () => void; + const sendFn = vi.fn().mockImplementation( + () => + new Promise((resolve) => { + resolveRequest = resolve; + }), + ); + + const queue = new RequestQueue(sendFn, { batchSize: 1 }); + + queue.add({ id: 1 }); + + // Start flush but don't await yet + const flushPromise = queue.flush(); + + // Resolve the pending request + await new Promise((resolve) => setTimeout(resolve, 10)); + resolveRequest!(); + + await flushPromise; + + expect(sendFn).toHaveBeenCalled(); + + queue.destroy(); + }); + }); + + describe('destroy', () => { + it('stops the flush timer', async () => { + const sendFn = vi.fn().mockResolvedValue(undefined); + const queue = new RequestQueue(sendFn, { flushIntervalMs: 50 }); + + queue.add({ id: 1 }); + queue.destroy(); + + await new Promise((resolve) => setTimeout(resolve, 100)); + + expect(sendFn).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/src/index.ts b/src/index.ts index 4d82a2e..f75a348 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ -export { createLogDash } from './LogDash.js'; -export * from './logger/Logger.js'; -export * from './metrics/Metrics.js'; +export { Logdash } from './Logdash_.js'; +export type { LogdashOptions } from './Logdash_.js'; +export { LogLevel } from './types/LogLevel.js'; diff --git a/src/logger/Logger.ts b/src/logger/Logger.ts deleted file mode 100644 index 0a691bc..0000000 --- a/src/logger/Logger.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { LogLevel } from '../types/LogLevel.js'; -import chalk from 'chalk'; - -const LOG_LEVEL_COLORS: Record = { - [LogLevel.ERROR]: [231, 0, 11], - [LogLevel.WARN]: [254, 154, 0], - [LogLevel.INFO]: [21, 93, 252], - [LogLevel.HTTP]: [0, 166, 166], - [LogLevel.VERBOSE]: [0, 166, 0], - [LogLevel.DEBUG]: [0, 166, 62], - [LogLevel.SILLY]: [80, 80, 80], -}; - -export class Logger { - constructor( - private readonly logMethod = console.log, - private readonly prefix: (level: LogLevel) => string = (level) => - `${String(level).toUpperCase()} `, - private readonly onLog?: (level: LogLevel, message: string) => void, - ) {} - - error(...data: any[]): void { - this._log(LogLevel.ERROR, this._formatData(data)); - } - - warn(...data: any[]): void { - this._log(LogLevel.WARN, this._formatData(data)); - } - - info(...data: any[]): void { - this._log(LogLevel.INFO, this._formatData(data)); - } - - log(...data: any[]): void { - this._log(LogLevel.INFO, this._formatData(data)); - } - - http(...data: any[]): void { - this._log(LogLevel.HTTP, this._formatData(data)); - } - - verbose(...data: any[]): void { - this._log(LogLevel.VERBOSE, this._formatData(data)); - } - - debug(...data: any[]): void { - this._log(LogLevel.DEBUG, this._formatData(data)); - } - - silly(...data: any[]): void { - this._log(LogLevel.SILLY, this._formatData(data)); - } - - private _formatData(data: any[]): string { - return data - .map((item) => { - if (typeof item === 'object' && item !== null) { - try { - return JSON.stringify(item); - } catch (e) { - return String(item); - } - } - return String(item); - }) - .join(' '); - } - - private _log(level: LogLevel, message: string): void { - const color = LOG_LEVEL_COLORS[level]; - - const datePrefix = chalk.rgb( - 156, - 156, - 156, - )(`[${new Date().toISOString()}]`); - const prefix = chalk.rgb( - color[0], - color[1], - color[2], - )(`${this.prefix(level)}`); - const formattedMessage = `${datePrefix} ${prefix}${message}`; - - this.logMethod(formattedMessage); - this.onLog?.(level, message); - } -} diff --git a/src/logger/internal-logger.ts b/src/logger/internal-logger.ts deleted file mode 100644 index 6f1834c..0000000 --- a/src/logger/internal-logger.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Logger } from './Logger.js'; -import chalk from 'chalk'; - -export const internalLogger = new Logger(console.log, () => - chalk.rgb(230, 0, 118)(`[LogDash] `), -); diff --git a/src/logger/internalLogger.ts b/src/logger/internalLogger.ts new file mode 100644 index 0000000..1b8b2c0 --- /dev/null +++ b/src/logger/internalLogger.ts @@ -0,0 +1,18 @@ +import chalk from 'chalk'; + +const PREFIX = chalk.rgb(230, 0, 118)('[Logdash]'); + +export const internalLogger = { + error: (...args: unknown[]) => { + console.log(PREFIX, chalk.red('ERROR'), ...args); + }, + warn: (...args: unknown[]) => { + console.log(PREFIX, chalk.yellow('WARN'), ...args); + }, + info: (...args: unknown[]) => { + console.log(PREFIX, ...args); + }, + verbose: (...args: unknown[]) => { + console.log(PREFIX, chalk.gray(...args)); + }, +}; diff --git a/src/metrics/BaseMetrics.ts b/src/metrics/BaseMetrics.ts deleted file mode 100644 index 60ad7fc..0000000 --- a/src/metrics/BaseMetrics.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface BaseMetrics { - set(key: string, value: number): void; - mutate(key: string, value: number): void; -} diff --git a/src/metrics/Metrics.ts b/src/metrics/Metrics.ts deleted file mode 100644 index 9e243a1..0000000 --- a/src/metrics/Metrics.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { internalLogger } from '../logger/internal-logger'; -import { RequiredInitializationParams } from '../types/InitializationParams'; -import { BaseMetrics } from './BaseMetrics'; - -export enum MetricOperation { - Set = 'set', - Change = 'change', -} - -export class Metrics implements BaseMetrics { - constructor(private readonly params: RequiredInitializationParams) {} - - set(name: string, value: number): void { - if (this.params.verbose) { - internalLogger.verbose(`Setting metric ${name} to ${value}`); - } - - fetch(`${this.params.host}/metrics`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'project-api-key': this.params.apiKey, - }, - body: JSON.stringify({ - name, - value, - operation: MetricOperation.Set, - }), - }); - } - - mutate(name: string, value: number): void { - if (this.params.verbose) { - internalLogger.verbose(`Mutating metric ${name} by ${value}`); - } - - fetch(`${this.params.host}/metrics`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'project-api-key': this.params.apiKey, - }, - body: JSON.stringify({ - name, - value, - operation: MetricOperation.Change, - }), - }); - } -} diff --git a/src/metrics/NoopMetrics.ts b/src/metrics/NoopMetrics.ts deleted file mode 100644 index 5271104..0000000 --- a/src/metrics/NoopMetrics.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { BaseMetrics } from './BaseMetrics'; - -export class NoopMetrics implements BaseMetrics { - set(): void {} - mutate(): void {} -} diff --git a/src/metrics/createMetrics.ts b/src/metrics/createMetrics.ts deleted file mode 100644 index 1fb7256..0000000 --- a/src/metrics/createMetrics.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { internalLogger } from '../logger/internal-logger.js'; -import { RequiredInitializationParams } from '../types/InitializationParams.js'; -import { BaseMetrics } from './BaseMetrics.js'; -import { Metrics } from './Metrics.js'; -import { NoopMetrics } from './NoopMetrics.js'; - -export const createMetrics = ( - params: RequiredInitializationParams, -): BaseMetrics => { - if (!params.apiKey) { - internalLogger.log( - 'Api key was not provided in the InitializationParams when calling createLogdash(), metrics will not be registered.\n', - ); - return new NoopMetrics(); - } - - return new Metrics(params); -}; diff --git a/src/queue/RequestQueue.ts b/src/queue/RequestQueue.ts new file mode 100644 index 0000000..75359f0 --- /dev/null +++ b/src/queue/RequestQueue.ts @@ -0,0 +1,120 @@ +import { internalLogger } from '../logger/internalLogger.js'; + +export type SendFunction = (items: T[]) => Promise; + +export interface RequestQueueOptions { + batchSize?: number; + flushIntervalMs?: number; + maxRetries?: number; + baseRetryDelayMs?: number; +} + +const DEFAULT_OPTIONS: Required = { + batchSize: 25, + flushIntervalMs: 1000, + maxRetries: 3, + baseRetryDelayMs: 1000, +}; + +export class RequestQueue { + private queue: T[] = []; + private inFlightPromises: Set> = new Set(); + private flushTimer: ReturnType | null = null; + private destroyed = false; + private readonly options: Required; + + constructor( + private readonly sendFn: SendFunction, + options?: RequestQueueOptions, + ) { + this.options = { ...DEFAULT_OPTIONS, ...options }; + this.scheduleFlush(); + } + + add(item: T): void { + if (this.destroyed) { + return; + } + + this.queue.push(item); + + if (this.queue.length >= this.options.batchSize) { + this.flushBatch(); + } + } + + async flush(): Promise { + // Flush any remaining items in the queue + if (this.queue.length > 0) { + this.flushBatch(); + } + + // Wait for all in-flight requests to complete + await Promise.all(Array.from(this.inFlightPromises)); + } + + destroy(): void { + this.destroyed = true; + if (this.flushTimer) { + clearTimeout(this.flushTimer); + this.flushTimer = null; + } + } + + private scheduleFlush(): void { + if (this.destroyed) { + return; + } + + this.flushTimer = setTimeout(() => { + if (this.queue.length > 0) { + this.flushBatch(); + } + this.scheduleFlush(); + }, this.options.flushIntervalMs); + } + + private flushBatch(): void { + if (this.queue.length === 0) { + return; + } + + const batch = this.queue.splice(0, this.options.batchSize); + const promise = this.sendWithRetry(batch); + + this.inFlightPromises.add(promise); + promise.finally(() => { + this.inFlightPromises.delete(promise); + }); + } + + private async sendWithRetry(items: T[]): Promise { + let lastError: Error | null = null; + + for (let attempt = 0; attempt < this.options.maxRetries; attempt++) { + try { + await this.sendFn(items); + return; + } catch (error) { + lastError = + error instanceof Error ? error : new Error(String(error)); + + if (attempt < this.options.maxRetries - 1) { + const delay = + this.options.baseRetryDelayMs * Math.pow(2, attempt); + await this.sleep(delay); + } + } + } + + // All retries exhausted - log error but don't throw to avoid breaking the app + internalLogger.error( + `Failed to send batch after ${this.options.maxRetries} attempts:`, + lastError?.message, + ); + } + + private sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); + } +} diff --git a/src/sync/HttpLogSync.ts b/src/sync/HttpLogSync.ts deleted file mode 100644 index 8468b89..0000000 --- a/src/sync/HttpLogSync.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { RequiredInitializationParams } from '../types/InitializationParams.js'; -import { LogLevel } from '../types/LogLevel.js'; -import { LogSync } from './LogSync.js'; - -export class HttpLogSync implements LogSync { - private sequenceNumber = 0; - - constructor(private readonly params: RequiredInitializationParams) {} - - // todos: - // - queue - // - retry - // - batching - send(message: string, level: LogLevel, createdAt: string): void { - fetch(`${this.params.host}/logs`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'project-api-key': this.params.apiKey, - }, - body: JSON.stringify({ - message, - level, - createdAt, - sequenceNumber: this.sequenceNumber++, - }), - }); - } -} diff --git a/src/sync/LogSync.ts b/src/sync/LogSync.ts deleted file mode 100644 index 3d16cb2..0000000 --- a/src/sync/LogSync.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { LogLevel } from '../types/LogLevel.js'; - -export interface LogSync { - send(message: string, level: LogLevel, createdAt: string): void; -} diff --git a/src/sync/NoopLogSync.ts b/src/sync/NoopLogSync.ts deleted file mode 100644 index 7c2277a..0000000 --- a/src/sync/NoopLogSync.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { LogSync } from './LogSync.js'; - -export class NoopLogSync implements LogSync { - send(message: string, level: string, createdAt: string): void {} -} diff --git a/src/sync/createLogSync.ts b/src/sync/createLogSync.ts deleted file mode 100644 index 5c9c69f..0000000 --- a/src/sync/createLogSync.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { internalLogger } from '../logger/internal-logger.js'; -import { RequiredInitializationParams } from '../types/InitializationParams.js'; -import { HttpLogSync } from './HttpLogSync.js'; -import { LogSync } from './LogSync.js'; -import { NoopLogSync } from './NoopLogSync.js'; - -export const createLogSync = ( - params: RequiredInitializationParams, -): LogSync => { - if (!params.apiKey) { - internalLogger.log( - 'Api key was not provided in the InitializationParams when calling createLogdash(), using only local logger.\n', - ); - return new NoopLogSync(); - } - - return new HttpLogSync(params); -}; diff --git a/src/transport/HttpTransport.ts b/src/transport/HttpTransport.ts new file mode 100644 index 0000000..aab2217 --- /dev/null +++ b/src/transport/HttpTransport.ts @@ -0,0 +1,74 @@ +export interface HttpTransportOptions { + host: string; + apiKey: string; + timeoutMs?: number; +} + +const DEFAULT_TIMEOUT_MS = 10000; + +export class HttpTransport { + private readonly host: string; + private readonly apiKey: string; + private readonly timeoutMs: number; + + constructor(options: HttpTransportOptions) { + this.host = options.host; + this.apiKey = options.apiKey; + this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS; + } + + async sendLogs(logs: LogPayload[]): Promise { + await this.request('POST', '/logs/batch', { logs }); + } + + async sendMetrics(metrics: MetricPayload[]): Promise { + // Send metrics one by one since the API expects single metric updates + await Promise.all( + metrics.map((metric) => this.request('PUT', '/metrics', metric)), + ); + } + + private async request( + method: 'POST' | 'PUT', + path: string, + body: unknown, + ): Promise { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs); + + try { + const response = await fetch(`${this.host}${path}`, { + method, + headers: { + 'Content-Type': 'application/json', + 'project-api-key': this.apiKey, + }, + body: JSON.stringify(body), + signal: controller.signal, + }); + + if (!response.ok) { + throw new Error( + `HTTP ${response.status}: ${response.statusText}`, + ); + } + } finally { + clearTimeout(timeoutId); + } + } +} + +export interface LogPayload { + message: string; + level: string; + createdAt: string; + sequenceNumber: number; + namespace?: string; +} + +export interface MetricPayload { + name: string; + value: number; + operation: 'set' | 'change'; + namespace?: string; +} diff --git a/src/types/InitializationParams.ts b/src/types/InitializationParams.ts deleted file mode 100644 index 785dd02..0000000 --- a/src/types/InitializationParams.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type InitializationParams = { - apiKey?: string; - host?: string; - verbose?: boolean; -}; - -export type RequiredInitializationParams = Required; diff --git a/test.ts b/test.ts index f56dcda..aa82b64 100644 --- a/test.ts +++ b/test.ts @@ -1,16 +1,32 @@ // npx ts-node test.ts -import { createLogDash } from './dist/index'; +import { Logdash } from './dist/index'; -const { logger } = createLogDash(); +// Basic usage without API key (logs to console only, queues but won't send) +const logdash = new Logdash(); -logger.error('This is an error message'); -logger.warn('This is a warning message'); -logger.info('This is an info message'); -logger.http('This is an http message'); -logger.verbose('This is a verbose message'); -logger.debug('This is a debug message'); -logger.silly('This is a silly message'); +logdash.error('This is an error message'); +logdash.warn('This is a warning message'); +logdash.info('This is an info message'); +logdash.http('This is an http message'); +logdash.verbose('This is a verbose message'); +logdash.debug('This is a debug message'); +logdash.silly('This is a silly message'); -const { logger: syncLogger } = createLogDash({ apiKey: 'MY_API_KEY' }); +// Usage with API key +const syncedLogdash = new Logdash('MY_API_KEY'); -syncLogger.error('This is a SYNCED error message'); +syncedLogdash.error('This is a SYNCED error message'); + +// Namespaced logging +const authLogger = syncedLogdash.withNamespace('auth'); +authLogger.info('User logged in'); +authLogger.setMetric('login_count', 1); + +// Metrics +syncedLogdash.setMetric('active_users', 42); +syncedLogdash.mutateMetric('requests', 1); + +// Graceful shutdown - wait for all pending items +syncedLogdash.flush().then(() => { + console.log('All logs and metrics flushed!'); +}); diff --git a/tsconfig.lib.json b/tsconfig.lib.json index f19ba45..2d9d1e7 100644 --- a/tsconfig.lib.json +++ b/tsconfig.lib.json @@ -1,28 +1,29 @@ { - "extends": "./tsconfig.json", - "compilerOptions": { - "esModuleInterop": true, - "skipLibCheck": true, - "target": "es5", - "allowJs": true, - "resolveJsonModule": true, - "moduleDetection": "force", - "isolatedModules": true, - "strict": false, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, - "module": "CommonJS", - "outDir": "dist", - "rootDir": "src", - "sourceMap": true, - "declaration": true, - "declarationMap": true - }, - "exclude": [ - "src/**/*.spec.ts", - "node_modules/**/*" - ], - "include": [ - "src/**/*.ts" - ] + "extends": "./tsconfig.json", + "compilerOptions": { + "esModuleInterop": true, + "skipLibCheck": true, + "target": "ES2020", + "allowJs": true, + "resolveJsonModule": true, + "moduleDetection": "force", + "isolatedModules": true, + "strict": false, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": "src", + "sourceMap": true, + "declaration": true, + "declarationMap": true + }, + "exclude": [ + "src/**/*.spec.ts", + "node_modules/**/*" + ], + "include": [ + "src/**/*.ts" + ] } diff --git a/vite.config.ts b/vite.config.ts index 631af93..60ba053 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,24 +1,8 @@ -// @ts-ignore -import { defineConfig } from "vite"; -// @ts-ignore -import swc from "rollup-plugin-swc"; +import { defineConfig } from 'vitest/config'; export default defineConfig({ - plugins: [ - swc({ - jsc: { - parser: { - syntax: "typescript", - tsx: true, - dynamicImport: true, - decorators: true, - }, - target: "es2021", - transform: { - decoratorMetadata: true, - }, - }, - }), - ], - esbuild: false, + test: { + include: ['src/__tests__/**/*.test.ts'], + globals: false, + }, }); From 6f969d034b14d71b8e9558d034a048e60e1a8f0f Mon Sep 17 00:00:00 2001 From: Szymeo Date: Thu, 18 Dec 2025 17:20:35 +0800 Subject: [PATCH 2/4] feat: wip --- .github/workflows/ci.yml | 2 -- src/{Logdash_.ts => LogDash.ts} | 0 src/__tests__/Logdash.test.ts | 2 +- src/index.ts | 4 ++-- 4 files changed, 3 insertions(+), 5 deletions(-) rename src/{Logdash_.ts => LogDash.ts} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b99e81..b7bb444 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,8 +19,6 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - with: - version: 9 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 diff --git a/src/Logdash_.ts b/src/LogDash.ts similarity index 100% rename from src/Logdash_.ts rename to src/LogDash.ts diff --git a/src/__tests__/Logdash.test.ts b/src/__tests__/Logdash.test.ts index 39e2ca2..5069ce6 100644 --- a/src/__tests__/Logdash.test.ts +++ b/src/__tests__/Logdash.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { Logdash } from '../Logdash_.js'; +import { Logdash } from '../LogDash.js'; describe('Logdash', () => { beforeEach(() => { diff --git a/src/index.ts b/src/index.ts index f75a348..185ea66 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ -export { Logdash } from './Logdash_.js'; -export type { LogdashOptions } from './Logdash_.js'; +export { Logdash } from './LogDash.js'; +export type { LogdashOptions } from './LogDash.js'; export { LogLevel } from './types/LogLevel.js'; From 27d598346d26c5ead5f80745f910e0dd82355bad Mon Sep 17 00:00:00 2001 From: Szymeo Date: Thu, 18 Dec 2025 17:21:06 +0800 Subject: [PATCH 3/4] feat: wip --- src/{LogDash.ts => Logdash.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{LogDash.ts => Logdash.ts} (100%) diff --git a/src/LogDash.ts b/src/Logdash.ts similarity index 100% rename from src/LogDash.ts rename to src/Logdash.ts From eaf506169464a984f798d4cc849963c63cabf78c Mon Sep 17 00:00:00 2001 From: Szymeo Date: Thu, 18 Dec 2025 17:22:32 +0800 Subject: [PATCH 4/4] feat: wip --- src/__tests__/Logdash.test.ts | 2 +- src/index.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/__tests__/Logdash.test.ts b/src/__tests__/Logdash.test.ts index 5069ce6..d972d37 100644 --- a/src/__tests__/Logdash.test.ts +++ b/src/__tests__/Logdash.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { Logdash } from '../LogDash.js'; +import { Logdash } from '../Logdash.js'; describe('Logdash', () => { beforeEach(() => { diff --git a/src/index.ts b/src/index.ts index 185ea66..0f12910 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ -export { Logdash } from './LogDash.js'; -export type { LogdashOptions } from './LogDash.js'; +export { Logdash } from './Logdash.js'; +export type { LogdashOptions } from './Logdash.js'; export { LogLevel } from './types/LogLevel.js';