diff --git a/.github/DISCUSSION_TEMPLATE/help.yml b/.github/DISCUSSION_TEMPLATE/help.yml
new file mode 100644
index 00000000..6d32d10a
--- /dev/null
+++ b/.github/DISCUSSION_TEMPLATE/help.yml
@@ -0,0 +1,20 @@
+body:
+ - type: textarea
+ attributes:
+ label: Summary
+ description: What do you need help with?
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Additional information
+ description: Any code snippets, error messages, or dependency details that may be related?
+ render: js
+ validations:
+ required: false
+ - type: input
+ attributes:
+ label: Example
+ description: A link to a minimal reproduction is helpful for collaborative debugging!
+ validations:
+ required: false
diff --git a/.github/DISCUSSION_TEMPLATE/ideas.yml b/.github/DISCUSSION_TEMPLATE/ideas.yml
new file mode 100644
index 00000000..3c81f93e
--- /dev/null
+++ b/.github/DISCUSSION_TEMPLATE/ideas.yml
@@ -0,0 +1,23 @@
+body:
+ - type: textarea
+ attributes:
+ label: Goals
+ description: Short list of what the feature request aims to address?
+ value: |
+ 1.
+ 2.
+ 3.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Background
+ description: Discuss prior art, why do you think this feature is needed? Are there current alternatives?
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Proposal
+ description: How should this feature be implemented? Are you interested in contributing?
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml
new file mode 100644
index 00000000..74854dc2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml
@@ -0,0 +1,39 @@
+name: Bug Report
+description: Create a bug report for the Node SDK
+labels: ["Type: Bug"]
+body:
+ - type: textarea
+ attributes:
+ label: Describe the Bug
+ description: A clear and concise description of what the bug is.
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: Link to the code that reproduces this issue
+ description: |
+ A link to a GitHub repository minimal reproduction. A minimal reproduction code is really helpful to understand the issue.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: To Reproduce
+ description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Expected Behavior
+ description: A clear and concise description of what you expected to happen.
+ validations:
+ required: true
+ - type: markdown
+ attributes:
+ value: Before posting the issue go through the steps you've written down to make sure the steps provided are detailed and clear.
+ - type: markdown
+ attributes:
+ value: Contributors should be able to follow the steps provided in order to reproduce the bug.
+ - type: input
+ attributes:
+ label: What's your node version? (if relevant)
+ description: "Please specify the exact version."
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..09b49e5b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Ask a question
+ url: https://github.com/resend/resend-node/discussions
+ about: Ask questions and discuss with other community members
+ - name: Feature request
+ url: https://github.com/resend/resend-node/discussions/new?category=ideas
+ about: Feature requests should be opened as discussions
diff --git a/.github/scripts/check-pinned-dependencies.mjs b/.github/scripts/check-pinned-dependencies.mjs
new file mode 100644
index 00000000..00798940
--- /dev/null
+++ b/.github/scripts/check-pinned-dependencies.mjs
@@ -0,0 +1,27 @@
+import fs from 'node:fs';
+
+const pkg = JSON.parse(await fs.promises.readFile('package.json', 'utf8'));
+const errors = [];
+
+function isPinned(version) {
+ return /^\d+\.\d+\.\d+(-canary\.\d+)?$/.test(version);
+}
+
+for (const [dep, version] of Object.entries(pkg.dependencies || {})) {
+ if (!isPinned(version)) {
+ errors.push(`Dependency "${dep}" is not pinned: "${version}"`);
+ }
+}
+
+for (const [dep, version] of Object.entries(pkg.devDependencies || {})) {
+ if (!isPinned(version)) {
+ errors.push(`Dev dependency "${dep}" is not pinned: "${version}"`);
+ }
+}
+
+if (errors.length > 0) {
+ console.error(`\n${errors.join('\n')}\n`);
+ process.exit(1);
+} else {
+ console.log('All dependencies are pinned.');
+}
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 3f4d9c24..c66c74c7 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -4,24 +4,22 @@ on:
branches:
- main
pull_request:
+permissions:
+ contents: read
+ pull-requests: read
jobs:
lint:
runs-on: buildjet-4vcpu-ubuntu-2204
container:
- image: node:20
- credentials:
- username: ${{ vars.DOCKER_HUB_USERNAME }}
- password: ${{ secrets.DOCKER_HUB_API_KEY }}
+ image: node:22
+ # credentials:
+ # username: ${{ vars.DOCKER_HUB_USERNAME || '' }}
+ # password: ${{ secrets.DOCKER_HUB_API_KEY || '' }}
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955
- name: pnpm setup
- uses: pnpm/action-setup@v4
- - name: Setup Node
- uses: actions/setup-node@v4
- with:
- node-version: 20
- cache: "pnpm"
+ uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
- name: Install packages
run: pnpm install
- name: Run Lint
diff --git a/.github/workflows/pin-dependencies-check.yml b/.github/workflows/pin-dependencies-check.yml
index 47b6ad5c..ef87c499 100644
--- a/.github/workflows/pin-dependencies-check.yml
+++ b/.github/workflows/pin-dependencies-check.yml
@@ -4,44 +4,20 @@ on:
branches:
- main
pull_request:
+permissions:
+ contents: read
+ pull-requests: read
jobs:
pin-dependencies-check:
runs-on: buildjet-4vcpu-ubuntu-2204
container:
- image: node:20
- credentials:
- username: ${{ vars.DOCKER_HUB_USERNAME }}
- password: ${{ secrets.DOCKER_HUB_API_KEY }}
+ image: node:22
+ # credentials:
+ # username: ${{ vars.DOCKER_HUB_USERNAME || '' }}
+ # password: ${{ secrets.DOCKER_HUB_API_KEY || '' }}
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955
- name: Check for pinned dependencies
run: |
- node -e '
- const fs = require("fs");
- const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
- const errors = [];
-
- function isPinned(version) {
- return /^\d+\.\d+\.\d+(-canary\.\d+)?$/.test(version);
- }
-
- for (const [dep, version] of Object.entries(pkg.dependencies || {})) {
- if (!isPinned(version)) {
- errors.push(`Dependency "${dep}" is not pinned: "${version}"`);
- }
- }
-
- for (const [dep, version] of Object.entries(pkg.devDependencies || {})) {
- if (!isPinned(version)) {
- errors.push(`Dev dependency "${dep}" is not pinned: "${version}"`);
- }
- }
-
- if (errors.length > 0) {
- console.error(`\n${errors.join("\n")}\n`);
- process.exit(1);
- } else {
- console.log("All dependencies are pinned.");
- }
- '
+ node .github/scripts/check-pinned-dependencies.mjs
diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml
index 16b8902b..a5a59a6b 100644
--- a/.github/workflows/pr-title-check.yml
+++ b/.github/workflows/pr-title-check.yml
@@ -2,17 +2,19 @@ name: PR Title Check
on:
pull_request:
types: [opened, edited, synchronize]
+permissions:
+ pull-requests: read
jobs:
pr-title-check:
runs-on: buildjet-4vcpu-ubuntu-2204
container:
- image: node:20
- credentials:
- username: ${{ vars.DOCKER_HUB_USERNAME }}
- password: ${{ secrets.DOCKER_HUB_API_KEY }}
+ image: node:22
+ # credentials:
+ # username: ${{ vars.DOCKER_HUB_USERNAME || '' }}
+ # password: ${{ secrets.DOCKER_HUB_API_KEY || '' }}
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955
- name: Run PR title check
run: |
node .github/scripts/pr-title-check.js
diff --git a/.github/workflows/preview-release.yml b/.github/workflows/preview-release.yml
new file mode 100644
index 00000000..d09bb7bc
--- /dev/null
+++ b/.github/workflows/preview-release.yml
@@ -0,0 +1,40 @@
+
+name: Preview Release
+on:
+ push:
+ branches:
+ - canary
+ - preview-*
+ pull_request:
+permissions:
+ contents: read
+ pull-requests: write
+concurrency: ${{ github.workflow }}-${{ github.ref }}
+jobs:
+ preview-release:
+ runs-on: buildjet-4vcpu-ubuntu-2204
+ permissions:
+ contents: write
+ pull-requests: write
+ container:
+ image: node:22
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: pnpm setup
+ uses: pnpm/action-setup@v4
+ - name: Install packages
+ run: pnpm install --frozen-lockfile
+ - name: Run Build
+ run: pnpm build
+ - name: Find changed files
+ id: changed_files
+ if: github.event_name == 'pull_request'
+ uses: tj-actions/changed-files@2036da178f85576f1940fedb74bb93a36cd89ab7
+ with:
+ files: src/**,pnpm-lock.yaml
+ dir_names: true
+ dir_names_max_depth: 2
+ - name: Publish changed packages to pkg.pr.new
+ if: github.event_name == 'push' || steps.changed_files.outputs.all_changed_and_modified_files != ''
+ run: pnpm dlx pkg-pr-new publish
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index db186314..b4557cd0 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -3,27 +3,24 @@ on:
push:
branches:
- main
+ - canary
pull_request:
+permissions:
+ contents: read
+ pull-requests: read
jobs:
tests:
runs-on: buildjet-4vcpu-ubuntu-2204
container:
- image: node:20
- credentials:
- username: ${{ vars.DOCKER_HUB_USERNAME }}
- password: ${{ secrets.DOCKER_HUB_API_KEY }}
+ image: node:22
+ # credentials:
+ # username: ${{ vars.DOCKER_HUB_USERNAME || '' }}
+ # password: ${{ secrets.DOCKER_HUB_API_KEY || '' }}
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955
- name: pnpm setup
- uses: pnpm/action-setup@v4
- - name: Setup Node
- uses: actions/setup-node@v4
- with:
- node-version: 20
- cache: "pnpm"
- - name: Install Doppler CLI
- uses: dopplerhq/cli-action@v3
+ uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
- name: Install packages
run: pnpm install
- name: Run Tests
diff --git a/biome.jsonc b/biome.jsonc
index 39f4d297..35164366 100644
--- a/biome.jsonc
+++ b/biome.jsonc
@@ -7,9 +7,7 @@
// only run on changed files by default (faster, but happy to remove)
"defaultBranch": "main"
},
- "organizeImports": {
- "enabled": true
- },
+ "assist": { "actions": { "source": { "organizeImports": "on" } } },
"formatter": {
"indentStyle": "space",
"indentWidth": 2,
@@ -24,10 +22,22 @@
"linter": {
"enabled": true,
"rules": {
- "recommended": true
+ "recommended": true,
+ "style": {
+ "noParameterAssign": "error",
+ "useAsConstAssertion": "error",
+ "useDefaultParameterLast": "error",
+ "useEnumInitializers": "error",
+ "useSelfClosingElements": "error",
+ "useSingleVarDeclarator": "error",
+ "noUnusedTemplateLiteral": "error",
+ "useNumberNamespace": "error",
+ "noInferrableTypes": "error",
+ "noUselessElse": "error"
+ }
}
},
"files": {
- "ignore": ["pnpm-lock.yaml"]
+ "includes": ["**", "!**/pnpm-lock.yaml", "!dist"]
}
}
diff --git a/jest.config.ts b/jest.config.ts
deleted file mode 100644
index 5f1618a9..00000000
--- a/jest.config.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import type { JestConfigWithTsJest } from 'ts-jest/';
-
-const config: JestConfigWithTsJest = {
- preset: 'ts-jest',
- clearMocks: true,
- restoreMocks: true,
- verbose: true,
- testEnvironment: 'node',
- setupFiles: ['./jest.setup.ts'],
- prettierPath: null,
-};
-
-export default config;
diff --git a/jest.setup.ts b/jest.setup.ts
deleted file mode 100644
index 03ba3a28..00000000
--- a/jest.setup.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { enableFetchMocks } from 'jest-fetch-mock';
-
-enableFetchMocks();
diff --git a/package.json b/package.json
index 574b37a2..7f709be8 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,13 @@
{
"name": "resend",
- "version": "6.0.1",
+ "version": "6.1.0-canary.1",
"description": "Node.js library for the Resend API",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
- "files": ["dist/**"],
+ "files": [
+ "dist/**"
+ ],
"engines": {
"node": ">=18"
},
@@ -23,13 +25,13 @@
},
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts",
- "test": "jest",
- "test:watch": "jest --watch",
+ "format": "biome format --write .",
"format:apply": "biome check --write .",
"format:check": "biome format .",
- "format": "biome format --write .",
"lint": "biome check .",
- "prepublishOnly": "pnpm run build"
+ "prepublishOnly": "pnpm run build",
+ "test": "vitest run",
+ "test:watch": "vitest"
},
"repository": {
"type": "git",
@@ -50,16 +52,14 @@
}
},
"devDependencies": {
- "@biomejs/biome": "1.9.4",
- "@types/jest": "29.5.14",
- "@types/node": "18.19.86",
- "@types/react": "19.1.2",
- "jest": "29.7.0",
- "jest-fetch-mock": "3.0.3",
- "ts-jest": "29.3.4",
- "ts-node": "10.9.2",
- "tsup": "7.2.0",
- "typescript": "5.8.3"
+ "@biomejs/biome": "2.2.0",
+ "@types/node": "22.17.2",
+ "@types/react": "19.1.10",
+ "pkg-pr-new": "0.0.56",
+ "tsup": "8.5.0",
+ "typescript": "5.9.2",
+ "vitest": "3.2.4",
+ "vitest-fetch-mock": "0.4.5"
},
- "packageManager": "pnpm@10.14.0"
+ "packageManager": "pnpm@10.15.0"
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d15e9666..dfeba2b2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,395 +13,238 @@ importers:
version: 1.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
devDependencies:
'@biomejs/biome':
- specifier: 1.9.4
- version: 1.9.4
- '@types/jest':
- specifier: 29.5.14
- version: 29.5.14
+ specifier: 2.2.0
+ version: 2.2.0
'@types/node':
- specifier: 18.19.86
- version: 18.19.86
+ specifier: 22.17.2
+ version: 22.17.2
'@types/react':
- specifier: 19.1.2
- version: 19.1.2
- jest:
- specifier: 29.7.0
- version: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- jest-fetch-mock:
- specifier: 3.0.3
- version: 3.0.3
- ts-jest:
- specifier: 29.3.4
- version: 29.3.4(@babel/core@7.24.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(esbuild@0.18.20)(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3)))(typescript@5.8.3)
- ts-node:
- specifier: 10.9.2
- version: 10.9.2(@types/node@18.19.86)(typescript@5.8.3)
+ specifier: 19.1.10
+ version: 19.1.10
+ pkg-pr-new:
+ specifier: 0.0.56
+ version: 0.0.56
tsup:
- specifier: 7.2.0
- version: 7.2.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))(typescript@5.8.3)
+ specifier: 8.5.0
+ version: 8.5.0(postcss@8.5.6)(typescript@5.9.2)(yaml@2.4.5)
typescript:
- specifier: 5.8.3
- version: 5.8.3
+ specifier: 5.9.2
+ version: 5.9.2
+ vitest:
+ specifier: 3.2.4
+ version: 3.2.4(@types/node@22.17.2)(yaml@2.4.5)
+ vitest-fetch-mock:
+ specifier: 0.4.5
+ version: 0.4.5(vitest@3.2.4(@types/node@22.17.2)(yaml@2.4.5))
packages:
- '@ampproject/remapping@2.3.0':
- resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
- engines: {node: '>=6.0.0'}
-
- '@babel/code-frame@7.24.7':
- resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/compat-data@7.24.7':
- resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/core@7.24.7':
- resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==}
- engines: {node: '>=6.9.0'}
-
- '@babel/generator@7.24.7':
- resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-compilation-targets@7.24.7':
- resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-environment-visitor@7.24.7':
- resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-function-name@7.24.7':
- resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-hoist-variables@7.24.7':
- resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-imports@7.24.7':
- resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-transforms@7.24.7':
- resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- '@babel/helper-plugin-utils@7.24.7':
- resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-simple-access@7.24.7':
- resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-split-export-declaration@7.24.7':
- resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-string-parser@7.24.7':
- resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-identifier@7.24.7':
- resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-option@7.24.7':
- resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helpers@7.24.7':
- resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/highlight@7.24.7':
- resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/parser@7.24.7':
- resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- '@babel/plugin-syntax-async-generators@7.8.4':
- resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-bigint@7.8.3':
- resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-class-properties@7.12.13':
- resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-import-meta@7.10.4':
- resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-json-strings@7.8.3':
- resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-jsx@7.24.7':
- resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
- resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
- resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-numeric-separator@7.10.4':
- resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3':
- resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3':
- resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-chaining@7.8.3':
- resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-top-level-await@7.14.5':
- resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-typescript@7.24.7':
- resolution: {integrity: sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/template@7.24.7':
- resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==}
- engines: {node: '>=6.9.0'}
-
- '@babel/traverse@7.24.7':
- resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/types@7.24.7':
- resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
- engines: {node: '>=6.9.0'}
-
- '@bcoe/v8-coverage@0.2.3':
- resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
-
- '@biomejs/biome@1.9.4':
- resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
+ '@biomejs/biome@2.2.0':
+ resolution: {integrity: sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw==}
engines: {node: '>=14.21.3'}
hasBin: true
- '@biomejs/cli-darwin-arm64@1.9.4':
- resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==}
+ '@biomejs/cli-darwin-arm64@2.2.0':
+ resolution: {integrity: sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
- '@biomejs/cli-darwin-x64@1.9.4':
- resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==}
+ '@biomejs/cli-darwin-x64@2.2.0':
+ resolution: {integrity: sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
- '@biomejs/cli-linux-arm64-musl@1.9.4':
- resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==}
+ '@biomejs/cli-linux-arm64-musl@2.2.0':
+ resolution: {integrity: sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-arm64@1.9.4':
- resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
+ '@biomejs/cli-linux-arm64@2.2.0':
+ resolution: {integrity: sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-x64-musl@1.9.4':
- resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
+ '@biomejs/cli-linux-x64-musl@2.2.0':
+ resolution: {integrity: sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-linux-x64@1.9.4':
- resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
+ '@biomejs/cli-linux-x64@2.2.0':
+ resolution: {integrity: sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-win32-arm64@1.9.4':
- resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
+ '@biomejs/cli-win32-arm64@2.2.0':
+ resolution: {integrity: sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
- '@biomejs/cli-win32-x64@1.9.4':
- resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==}
+ '@biomejs/cli-win32-x64@2.2.0':
+ resolution: {integrity: sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
- '@cspotcode/source-map-support@0.8.1':
- resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
- engines: {node: '>=12'}
+ '@esbuild/aix-ppc64@0.25.8':
+ resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
- '@esbuild/android-arm64@0.18.20':
- resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
- engines: {node: '>=12'}
+ '@esbuild/android-arm64@0.25.8':
+ resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.18.20':
- resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
- engines: {node: '>=12'}
+ '@esbuild/android-arm@0.25.8':
+ resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==}
+ engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.18.20':
- resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
- engines: {node: '>=12'}
+ '@esbuild/android-x64@0.25.8':
+ resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.18.20':
- resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
- engines: {node: '>=12'}
+ '@esbuild/darwin-arm64@0.25.8':
+ resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.18.20':
- resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
- engines: {node: '>=12'}
+ '@esbuild/darwin-x64@0.25.8':
+ resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.18.20':
- resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
- engines: {node: '>=12'}
+ '@esbuild/freebsd-arm64@0.25.8':
+ resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.18.20':
- resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
- engines: {node: '>=12'}
+ '@esbuild/freebsd-x64@0.25.8':
+ resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.18.20':
- resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
- engines: {node: '>=12'}
+ '@esbuild/linux-arm64@0.25.8':
+ resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.18.20':
- resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
- engines: {node: '>=12'}
+ '@esbuild/linux-arm@0.25.8':
+ resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==}
+ engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.18.20':
- resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
- engines: {node: '>=12'}
+ '@esbuild/linux-ia32@0.25.8':
+ resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==}
+ engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.18.20':
- resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
- engines: {node: '>=12'}
+ '@esbuild/linux-loong64@0.25.8':
+ resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==}
+ engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.18.20':
- resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
- engines: {node: '>=12'}
+ '@esbuild/linux-mips64el@0.25.8':
+ resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==}
+ engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.18.20':
- resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
- engines: {node: '>=12'}
+ '@esbuild/linux-ppc64@0.25.8':
+ resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==}
+ engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.18.20':
- resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
- engines: {node: '>=12'}
+ '@esbuild/linux-riscv64@0.25.8':
+ resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==}
+ engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.18.20':
- resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
- engines: {node: '>=12'}
+ '@esbuild/linux-s390x@0.25.8':
+ resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==}
+ engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.18.20':
- resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
- engines: {node: '>=12'}
+ '@esbuild/linux-x64@0.25.8':
+ resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-x64@0.18.20':
- resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
- engines: {node: '>=12'}
+ '@esbuild/netbsd-arm64@0.25.8':
+ resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.8':
+ resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-x64@0.18.20':
- resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
- engines: {node: '>=12'}
+ '@esbuild/openbsd-arm64@0.25.8':
+ resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.8':
+ resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/sunos-x64@0.18.20':
- resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
- engines: {node: '>=12'}
+ '@esbuild/openharmony-arm64@0.25.8':
+ resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.25.8':
+ resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.18.20':
- resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
- engines: {node: '>=12'}
+ '@esbuild/win32-arm64@0.25.8':
+ resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.18.20':
- resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
- engines: {node: '>=12'}
+ '@esbuild/win32-ia32@0.25.8':
+ resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==}
+ engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.18.20':
- resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
- engines: {node: '>=12'}
+ '@esbuild/win32-x64@0.25.8':
+ resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -409,80 +252,6 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
- '@istanbuljs/load-nyc-config@1.1.0':
- resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
- engines: {node: '>=8'}
-
- '@istanbuljs/schema@0.1.3':
- resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
- engines: {node: '>=8'}
-
- '@jest/console@29.7.0':
- resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/core@29.7.0':
- resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- '@jest/environment@29.7.0':
- resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/expect-utils@29.7.0':
- resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/expect@29.7.0':
- resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/fake-timers@29.7.0':
- resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/globals@29.7.0':
- resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/reporters@29.7.0':
- resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- '@jest/schemas@29.6.3':
- resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/source-map@29.6.3':
- resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-result@29.7.0':
- resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-sequencer@29.7.0':
- resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/transform@29.7.0':
- resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/types@29.6.3':
- resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
'@jridgewell/gen-mapping@0.3.5':
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
engines: {node: '>=6.0.0'}
@@ -495,26 +264,71 @@ packages:
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
engines: {node: '>=6.0.0'}
- '@jridgewell/sourcemap-codec@1.4.15':
- resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ '@jridgewell/sourcemap-codec@1.5.4':
+ resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
- '@jridgewell/trace-mapping@0.3.9':
- resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+ '@jsdevtools/ez-spawn@3.0.4':
+ resolution: {integrity: sha512-f5DRIOZf7wxogefH03RjMPMdBF7ADTWUMoOs9kaJo06EfwF+aFhMZMDZxHg/Xe12hptN9xoZjGso2fdjapBRIA==}
+ engines: {node: '>=10'}
- '@nodelib/fs.scandir@2.1.5':
- resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
- engines: {node: '>= 8'}
+ '@octokit/action@6.1.0':
+ resolution: {integrity: sha512-lo+nHx8kAV86bxvOVOI3vFjX3gXPd/L7guAUbvs3pUvnR2KC+R7yjBkA1uACt4gYhs4LcWP3AXSGQzsbeN2XXw==}
+ engines: {node: '>= 18'}
- '@nodelib/fs.stat@2.0.5':
- resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
- engines: {node: '>= 8'}
+ '@octokit/auth-action@4.1.0':
+ resolution: {integrity: sha512-m+3t7K46IYyMk7Bl6/lF4Rv09GqDZjYmNg8IWycJ2Fa3YE3DE7vQcV6G2hUPmR9NDqenefNJwVtlisMjzymPiQ==}
+ engines: {node: '>= 18'}
- '@nodelib/fs.walk@1.2.8':
- resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
- engines: {node: '>= 8'}
+ '@octokit/auth-token@4.0.0':
+ resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==}
+ engines: {node: '>= 18'}
+
+ '@octokit/core@5.2.2':
+ resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==}
+ engines: {node: '>= 18'}
+
+ '@octokit/endpoint@9.0.6':
+ resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==}
+ engines: {node: '>= 18'}
+
+ '@octokit/graphql@7.1.1':
+ resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==}
+ engines: {node: '>= 18'}
+
+ '@octokit/openapi-types@20.0.0':
+ resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==}
+
+ '@octokit/openapi-types@24.2.0':
+ resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==}
+
+ '@octokit/plugin-paginate-rest@9.2.2':
+ resolution: {integrity: sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ '@octokit/core': '5'
+
+ '@octokit/plugin-rest-endpoint-methods@10.4.1':
+ resolution: {integrity: sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ '@octokit/core': '5'
+
+ '@octokit/request-error@5.1.1':
+ resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==}
+ engines: {node: '>= 18'}
+
+ '@octokit/request@8.4.1':
+ resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==}
+ engines: {node: '>= 18'}
+
+ '@octokit/types@12.6.0':
+ resolution: {integrity: sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==}
+
+ '@octokit/types@13.10.0':
+ resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==}
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
@@ -527,85 +341,158 @@ packages:
react: ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^18.0 || ^19.0 || ^19.0.0-rc
- '@selderee/plugin-htmlparser2@0.11.0':
- resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==}
+ '@rollup/rollup-android-arm-eabi@4.46.2':
+ resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.46.2':
+ resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.46.2':
+ resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.46.2':
+ resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.46.2':
+ resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.46.2':
+ resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.46.2':
+ resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.46.2':
+ resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.46.2':
+ resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.46.2':
+ resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
+ cpu: [arm64]
+ os: [linux]
- '@sinclair/typebox@0.27.8':
- resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
+ '@rollup/rollup-linux-loongarch64-gnu@4.46.2':
+ resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.46.2':
+ resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
+ cpu: [ppc64]
+ os: [linux]
- '@sinonjs/commons@3.0.1':
- resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
+ '@rollup/rollup-linux-riscv64-gnu@4.46.2':
+ resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
+ cpu: [riscv64]
+ os: [linux]
- '@sinonjs/fake-timers@10.3.0':
- resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+ '@rollup/rollup-linux-riscv64-musl@4.46.2':
+ resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
+ cpu: [riscv64]
+ os: [linux]
- '@tsconfig/node10@1.0.11':
- resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
+ '@rollup/rollup-linux-s390x-gnu@4.46.2':
+ resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
+ cpu: [s390x]
+ os: [linux]
- '@tsconfig/node12@1.0.11':
- resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
+ '@rollup/rollup-linux-x64-gnu@4.46.2':
+ resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
+ cpu: [x64]
+ os: [linux]
- '@tsconfig/node14@1.0.3':
- resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
+ '@rollup/rollup-linux-x64-musl@4.46.2':
+ resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
+ cpu: [x64]
+ os: [linux]
- '@tsconfig/node16@1.0.4':
- resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
+ '@rollup/rollup-win32-arm64-msvc@4.46.2':
+ resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==}
+ cpu: [arm64]
+ os: [win32]
- '@types/babel__core@7.20.5':
- resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+ '@rollup/rollup-win32-ia32-msvc@4.46.2':
+ resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==}
+ cpu: [ia32]
+ os: [win32]
- '@types/babel__generator@7.6.8':
- resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
+ '@rollup/rollup-win32-x64-msvc@4.46.2':
+ resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==}
+ cpu: [x64]
+ os: [win32]
- '@types/babel__template@7.4.4':
- resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+ '@selderee/plugin-htmlparser2@0.11.0':
+ resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==}
- '@types/babel__traverse@7.20.6':
- resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==}
+ '@types/chai@5.2.2':
+ resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==}
- '@types/graceful-fs@4.1.9':
- resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
+ '@types/deep-eql@4.0.2':
+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
- '@types/istanbul-lib-coverage@2.0.6':
- resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
- '@types/istanbul-lib-report@3.0.3':
- resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
+ '@types/node@22.17.2':
+ resolution: {integrity: sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==}
- '@types/istanbul-reports@3.0.4':
- resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
+ '@types/react@19.1.10':
+ resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==}
- '@types/jest@29.5.14':
- resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
+ '@vitest/expect@3.2.4':
+ resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
- '@types/node@18.19.86':
- resolution: {integrity: sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==}
+ '@vitest/mocker@3.2.4':
+ resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
- '@types/react@19.1.2':
- resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==}
+ '@vitest/pretty-format@3.2.4':
+ resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
- '@types/stack-utils@2.0.3':
- resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+ '@vitest/runner@3.2.4':
+ resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
- '@types/yargs-parser@21.0.3':
- resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
+ '@vitest/snapshot@3.2.4':
+ resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
- '@types/yargs@17.0.32':
- resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==}
+ '@vitest/spy@3.2.4':
+ resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
- acorn-walk@8.3.2:
- resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
- engines: {node: '>=0.4.0'}
+ '@vitest/utils@3.2.4':
+ resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
- acorn@8.11.3:
- resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
engines: {node: '>=0.4.0'}
hasBin: true
- ansi-escapes@4.3.2:
- resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
- engines: {node: '>=8'}
-
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
@@ -614,18 +501,10 @@ packages:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
- ansi-styles@3.2.1:
- resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
- engines: {node: '>=4'}
-
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
- ansi-styles@5.2.0:
- resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
- engines: {node: '>=10'}
-
ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
@@ -633,149 +512,48 @@ packages:
any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
- anymatch@3.1.3:
- resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
- engines: {node: '>= 8'}
-
- arg@4.1.3:
- resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
-
- argparse@1.0.10:
- resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
-
- array-union@2.1.0:
- resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
- engines: {node: '>=8'}
-
- async@3.2.5:
- resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==}
-
- babel-jest@29.7.0:
- resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.8.0
-
- babel-plugin-istanbul@6.1.1:
- resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
- engines: {node: '>=8'}
-
- babel-plugin-jest-hoist@29.6.3:
- resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- babel-preset-current-node-syntax@1.0.1:
- resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- babel-preset-jest@29.6.3:
- resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.0.0
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- binary-extensions@2.3.0:
- resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
- engines: {node: '>=8'}
-
- brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ before-after-hook@2.2.3:
+ resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==}
brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
- braces@3.0.3:
- resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
- engines: {node: '>=8'}
-
- browserslist@4.23.1:
- resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
- bs-logger@0.2.6:
- resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
- engines: {node: '>= 6'}
-
- bser@2.1.1:
- resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
-
- buffer-from@1.1.2:
- resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
-
- bundle-require@4.2.1:
- resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==}
+ bundle-require@5.1.0:
+ resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
peerDependencies:
- esbuild: '>=0.17'
+ esbuild: '>=0.18'
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
- callsites@3.1.0:
- resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
- engines: {node: '>=6'}
-
- camelcase@5.3.1:
- resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
- engines: {node: '>=6'}
-
- camelcase@6.3.0:
- resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
- engines: {node: '>=10'}
-
- caniuse-lite@1.0.30001632:
- resolution: {integrity: sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==}
-
- chalk@2.4.2:
- resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
- engines: {node: '>=4'}
-
- chalk@4.1.2:
- resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
- engines: {node: '>=10'}
-
- char-regex@1.0.2:
- resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
- engines: {node: '>=10'}
-
- chokidar@3.6.0:
- resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
- engines: {node: '>= 8.10.0'}
-
- ci-info@3.9.0:
- resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
- engines: {node: '>=8'}
-
- cjs-module-lexer@1.3.1:
- resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==}
+ call-me-maybe@1.0.2:
+ resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==}
- cliui@8.0.1:
- resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
- engines: {node: '>=12'}
-
- co@4.6.0:
- resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
- engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
+ chai@5.2.1:
+ resolution: {integrity: sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==}
+ engines: {node: '>=18'}
- collect-v8-coverage@1.0.2:
- resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
+ check-error@2.1.1:
+ resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+ engines: {node: '>= 16'}
- color-convert@1.9.3:
- resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ chokidar@4.0.3:
+ resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+ engines: {node: '>= 14.16.0'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
- color-name@1.1.3:
- resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
-
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
@@ -783,22 +561,12 @@ packages:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
- concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
-
- convert-source-map@2.0.0:
- resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ confbox@0.1.8:
+ resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
- create-jest@29.7.0:
- resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
-
- create-require@1.1.1:
- resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
-
- cross-fetch@3.1.8:
- resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==}
+ consola@3.4.2:
+ resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
+ engines: {node: ^14.18.0 || >=16.10.0}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
@@ -807,8 +575,8 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
- debug@4.3.5:
- resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+ debug@4.4.1:
+ resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
@@ -816,33 +584,20 @@ packages:
supports-color:
optional: true
- dedent@1.5.3:
- resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==}
- peerDependencies:
- babel-plugin-macros: ^3.1.0
- peerDependenciesMeta:
- babel-plugin-macros:
- optional: true
+ decode-uri-component@0.4.1:
+ resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==}
+ engines: {node: '>=14.16'}
+
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+ engines: {node: '>=6'}
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
- detect-newline@3.1.0:
- resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
- engines: {node: '>=8'}
-
- diff-sequences@29.6.3:
- resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- diff@4.0.2:
- resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
- engines: {node: '>=0.3.1'}
-
- dir-glob@3.0.1:
- resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
- engines: {node: '>=8'}
+ deprecation@2.3.1:
+ resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==}
dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
@@ -860,18 +615,6 @@ packages:
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- ejs@3.1.10:
- resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
- engines: {node: '>=0.10.0'}
- hasBin: true
-
- electron-to-chromium@1.4.797:
- resolution: {integrity: sha512-RWMYymqyWwIdCEb7Psag5zyAHirYnB354ZREoF8c5QOHbt8AodF7lwVxGUnu5gzBVjzDo9R3XeTwy7pbvubxGw==}
-
- emittery@0.13.1:
- resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
- engines: {node: '>=12'}
-
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -882,140 +625,53 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
- error-ex@1.3.2:
- resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
-
- esbuild@0.18.20:
- resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
- engines: {node: '>=12'}
- hasBin: true
-
- escalade@3.1.2:
- resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
- engines: {node: '>=6'}
-
- escape-string-regexp@1.0.5:
- resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
- engines: {node: '>=0.8.0'}
-
- escape-string-regexp@2.0.0:
- resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
- engines: {node: '>=8'}
+ es-module-lexer@1.7.0:
+ resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
- esprima@4.0.1:
- resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
- engines: {node: '>=4'}
+ esbuild@0.25.8:
+ resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==}
+ engines: {node: '>=18'}
hasBin: true
- execa@5.1.1:
- resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
- engines: {node: '>=10'}
-
- exit@0.1.2:
- resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
- engines: {node: '>= 0.8.0'}
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
- expect@29.7.0:
- resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ expect-type@1.2.2:
+ resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==}
+ engines: {node: '>=12.0.0'}
fast-deep-equal@2.0.1:
resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
- fast-glob@3.3.2:
- resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
- engines: {node: '>=8.6.0'}
-
- fast-json-stable-stringify@2.1.0:
- resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
-
- fastq@1.17.1:
- resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
-
- fb-watchman@2.0.2:
- resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
-
- filelist@1.0.4:
- resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
+ fdir@6.4.6:
+ resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
- fill-range@7.1.1:
- resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
- engines: {node: '>=8'}
+ filter-obj@5.1.0:
+ resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==}
+ engines: {node: '>=14.16'}
- find-up@4.1.0:
- resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
- engines: {node: '>=8'}
+ fix-dts-default-cjs-exports@1.0.1:
+ resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==}
foreground-child@3.1.1:
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
engines: {node: '>=14'}
- fs.realpath@1.0.0:
- resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
-
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
- function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
-
- gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
-
- get-caller-file@2.0.5:
- resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
- engines: {node: 6.* || 8.* || >= 10.*}
-
- get-package-type@0.1.0:
- resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
- engines: {node: '>=8.0.0'}
-
- get-stream@6.0.1:
- resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
- engines: {node: '>=10'}
-
- glob-parent@5.1.2:
- resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
- engines: {node: '>= 6'}
-
glob@10.4.1:
resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==}
engines: {node: '>=16 || 14 >=14.18'}
hasBin: true
- glob@7.2.3:
- resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
- deprecated: Glob versions prior to v9 are no longer supported
-
- globals@11.12.0:
- resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
- engines: {node: '>=4'}
-
- globby@11.1.0:
- resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
- engines: {node: '>=10'}
-
- graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
-
- has-flag@3.0.0:
- resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
- engines: {node: '>=4'}
-
- has-flag@4.0.0:
- resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
- engines: {node: '>=8'}
-
- hasown@2.0.2:
- resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
- engines: {node: '>= 0.4'}
-
- html-escaper@2.0.2:
- resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
-
html-to-text@9.0.5:
resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==}
engines: {node: '>=14'}
@@ -1023,232 +679,25 @@ packages:
htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
- human-signals@2.1.0:
- resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
- engines: {node: '>=10.17.0'}
-
ignore@5.3.1:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
engines: {node: '>= 4'}
- import-local@3.1.0:
- resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==}
- engines: {node: '>=8'}
- hasBin: true
-
- imurmurhash@0.1.4:
- resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
- engines: {node: '>=0.8.19'}
-
- inflight@1.0.6:
- resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
- deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
-
- inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
-
- is-arrayish@0.2.1:
- resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
-
- is-binary-path@2.1.0:
- resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
- engines: {node: '>=8'}
-
- is-core-module@2.13.1:
- resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
-
- is-extglob@2.1.1:
- resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
- engines: {node: '>=0.10.0'}
-
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
- is-generator-fn@2.1.0:
- resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
- engines: {node: '>=6'}
-
- is-glob@4.0.3:
- resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
- engines: {node: '>=0.10.0'}
-
- is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
-
- is-stream@2.0.1:
- resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
- engines: {node: '>=8'}
+ isbinaryfile@5.0.4:
+ resolution: {integrity: sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==}
+ engines: {node: '>= 18.0.0'}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- istanbul-lib-coverage@3.2.2:
- resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@5.2.1:
- resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@6.0.2:
- resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==}
- engines: {node: '>=10'}
-
- istanbul-lib-report@3.0.1:
- resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
- engines: {node: '>=10'}
-
- istanbul-lib-source-maps@4.0.1:
- resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
- engines: {node: '>=10'}
-
- istanbul-reports@3.1.7:
- resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
- engines: {node: '>=8'}
-
jackspeak@3.4.0:
resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==}
engines: {node: '>=14'}
- jake@10.9.2:
- resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
- engines: {node: '>=10'}
- hasBin: true
-
- jest-changed-files@29.7.0:
- resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-circus@29.7.0:
- resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-cli@29.7.0:
- resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- jest-config@29.7.0:
- resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@types/node': '*'
- ts-node: '>=9.0.0'
- peerDependenciesMeta:
- '@types/node':
- optional: true
- ts-node:
- optional: true
-
- jest-diff@29.7.0:
- resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-docblock@29.7.0:
- resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-each@29.7.0:
- resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-environment-node@29.7.0:
- resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-fetch-mock@3.0.3:
- resolution: {integrity: sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==}
-
- jest-get-type@29.6.3:
- resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-haste-map@29.7.0:
- resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-leak-detector@29.7.0:
- resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-matcher-utils@29.7.0:
- resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-message-util@29.7.0:
- resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-mock@29.7.0:
- resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-pnp-resolver@1.2.3:
- resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
- engines: {node: '>=6'}
- peerDependencies:
- jest-resolve: '*'
- peerDependenciesMeta:
- jest-resolve:
- optional: true
-
- jest-regex-util@29.6.3:
- resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve-dependencies@29.7.0:
- resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve@29.7.0:
- resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runner@29.7.0:
- resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runtime@29.7.0:
- resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-snapshot@29.7.0:
- resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-util@29.7.0:
- resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-validate@29.7.0:
- resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-watcher@29.7.0:
- resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-worker@29.7.0:
- resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest@29.7.0:
- resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
@@ -1256,34 +705,12 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- js-yaml@3.14.1:
- resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
- hasBin: true
-
- jsesc@2.5.2:
- resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
- engines: {node: '>=4'}
- hasBin: true
-
- json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
-
- json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
- hasBin: true
-
- kleur@3.0.3:
- resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
- engines: {node: '>=6'}
+ js-tokens@9.0.1:
+ resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
leac@0.6.0:
resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==}
- leven@3.1.0:
- resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
- engines: {node: '>=6'}
-
lilconfig@3.1.2:
resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
engines: {node: '>=14'}
@@ -1295,13 +722,6 @@ packages:
resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- locate-path@5.0.0:
- resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
- engines: {node: '>=8'}
-
- lodash.memoize@4.1.2:
- resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
-
lodash.sortby@4.7.0:
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
@@ -1309,44 +729,15 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
+ loupe@3.2.0:
+ resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==}
+
lru-cache@10.2.2:
resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
engines: {node: 14 || >=16.14}
- lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
-
- make-dir@4.0.0:
- resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
- engines: {node: '>=10'}
-
- make-error@1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
-
- makeerror@1.0.12:
- resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
-
- merge-stream@2.0.0:
- resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
-
- merge2@1.4.1:
- resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
- engines: {node: '>= 8'}
-
- micromatch@4.0.8:
- resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
- engines: {node: '>=8.6'}
-
- mimic-fn@2.1.0:
- resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
- engines: {node: '>=6'}
-
- minimatch@3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
-
- minimatch@5.1.6:
- resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
- engines: {node: '>=10'}
+ magic-string@0.30.17:
+ resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
minimatch@9.0.4:
resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
@@ -1356,37 +747,19 @@ packages:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
- ms@2.1.2:
- resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+ mlly@1.7.4:
+ resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
- natural-compare@1.4.0:
- resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
-
- node-fetch@2.7.0:
- resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
- engines: {node: 4.x || >=6.0.0}
- peerDependencies:
- encoding: ^0.1.0
- peerDependenciesMeta:
- encoding:
- optional: true
-
- node-int64@0.4.0:
- resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
-
- node-releases@2.0.14:
- resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
-
- normalize-path@3.0.0:
- resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
- engines: {node: '>=0.10.0'}
-
- npm-run-path@4.0.1:
- resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
- engines: {node: '>=8'}
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
@@ -1395,120 +768,93 @@ packages:
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
- onetime@5.1.2:
- resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
- engines: {node: '>=6'}
-
- p-limit@2.3.0:
- resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
- engines: {node: '>=6'}
-
- p-limit@3.1.0:
- resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
- engines: {node: '>=10'}
-
- p-locate@4.1.0:
- resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
- engines: {node: '>=8'}
-
- p-try@2.2.0:
- resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
- engines: {node: '>=6'}
-
- parse-json@5.2.0:
- resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
- engines: {node: '>=8'}
-
parseley@0.12.1:
resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==}
- path-exists@4.0.0:
- resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
- engines: {node: '>=8'}
-
- path-is-absolute@1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
-
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
- path-parse@1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
-
path-scurry@1.11.1:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
- path-type@4.0.0:
- resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
- engines: {node: '>=8'}
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+ pathval@2.0.1:
+ resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
+ engines: {node: '>= 14.16'}
peberminta@0.9.0:
resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==}
- picocolors@1.0.1:
- resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
- picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
pirates@4.0.6:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
- pkg-dir@4.2.0:
- resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
- engines: {node: '>=8'}
+ pkg-pr-new@0.0.56:
+ resolution: {integrity: sha512-QUdWJ5m0IUNIujAIwc03wJ3L1BVCpSK8jm7yIz4F2pkvQ8afVltyl+/tJTPLKs5jcd2gkQZPl71NYwMYplRvaA==}
+ hasBin: true
- postcss-load-config@4.0.2:
- resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
- engines: {node: '>= 14'}
+ pkg-types@1.3.1:
+ resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
+
+ postcss-load-config@6.0.1:
+ resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
+ engines: {node: '>= 18'}
peerDependencies:
+ jiti: '>=1.21.0'
postcss: '>=8.0.9'
- ts-node: '>=9.0.0'
+ tsx: ^4.8.1
+ yaml: ^2.4.2
peerDependenciesMeta:
+ jiti:
+ optional: true
postcss:
optional: true
- ts-node:
+ tsx:
optional: true
+ yaml:
+ optional: true
+
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ engines: {node: ^10 || ^12 || >=14}
prettier@3.5.3:
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
engines: {node: '>=14'}
hasBin: true
- pretty-format@29.7.0:
- resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- promise-polyfill@8.3.0:
- resolution: {integrity: sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==}
-
- prompts@2.4.2:
- resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
- engines: {node: '>= 6'}
-
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
- pure-rand@6.1.0:
- resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
+ query-registry@3.0.1:
+ resolution: {integrity: sha512-M9RxRITi2mHMVPU5zysNjctUT8bAPx6ltEXo/ir9+qmiM47Y7f0Ir3+OxUO5OjYAWdicBQRew7RtHtqUXydqlg==}
+ engines: {node: '>=20'}
- queue-microtask@1.2.3:
- resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ query-string@9.2.2:
+ resolution: {integrity: sha512-pDSIZJ9sFuOp6VnD+5IkakSVf+rICAuuU88Hcsr6AKL0QtxSIfVuKiVP2oahFI7tk3CRSexwV+Ya6MOoTxzg9g==}
+ engines: {node: '>=18'}
+
+ quick-lru@7.1.0:
+ resolution: {integrity: sha512-Pzd/4IFnTb8E+I1P5rbLQoqpUHcXKg48qTYKi4EANg+sTPwGFEMOcYGiiZz6xuQcOMZP7MPsrdAPx+16Q8qahg==}
+ engines: {node: '>=18'}
react-dom@18.3.1:
resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
peerDependencies:
react: ^18.3.1
- react-is@18.3.1:
- resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
-
react-promise-suspense@0.3.4:
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
@@ -1516,62 +862,25 @@ packages:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'}
- readdirp@3.6.0:
- resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
- engines: {node: '>=8.10.0'}
-
- require-directory@2.1.1:
- resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
- engines: {node: '>=0.10.0'}
-
- resolve-cwd@3.0.0:
- resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
- engines: {node: '>=8'}
+ readdirp@4.1.2:
+ resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
+ engines: {node: '>= 14.18.0'}
resolve-from@5.0.0:
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
engines: {node: '>=8'}
- resolve.exports@2.0.2:
- resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==}
- engines: {node: '>=10'}
-
- resolve@1.22.8:
- resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
- hasBin: true
-
- reusify@1.0.4:
- resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
- engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
-
- rollup@3.29.5:
- resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==}
- engines: {node: '>=14.18.0', npm: '>=8.0.0'}
+ rollup@4.46.2:
+ resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
- run-parallel@1.2.0:
- resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
-
scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
selderee@0.11.0:
resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==}
- semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
-
- semver@7.7.1:
- resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
- engines: {node: '>=10'}
- hasBin: true
-
- semver@7.7.2:
- resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
- engines: {node: '>=10'}
- hasBin: true
-
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -1580,41 +889,35 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
- signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
- sisteransi@1.0.5:
- resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
-
- slash@3.0.0:
- resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
- engines: {node: '>=8'}
-
- source-map-support@0.5.13:
- resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
-
- source-map@0.6.1:
- resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
source-map@0.8.0-beta.0:
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
engines: {node: '>= 8'}
+ deprecated: The work that was done in this beta branch won't be included in future versions
- sprintf-js@1.0.3:
- resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+ split-on-first@3.0.0:
+ resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==}
+ engines: {node: '>=12'}
- stack-utils@2.0.6:
- resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
- engines: {node: '>=10'}
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
- string-length@4.0.2:
- resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
- engines: {node: '>=10'}
+ std-env@3.9.0:
+ resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
+
+ string-argv@0.3.2:
+ resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
+ engines: {node: '>=0.6.19'}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
@@ -1632,43 +935,14 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
- strip-bom@4.0.0:
- resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
- engines: {node: '>=8'}
-
- strip-final-newline@2.0.0:
- resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
- engines: {node: '>=6'}
-
- strip-json-comments@3.1.1:
- resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
- engines: {node: '>=8'}
+ strip-literal@3.0.0:
+ resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==}
sucrase@3.35.0:
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
- supports-color@5.5.0:
- resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
- engines: {node: '>=4'}
-
- supports-color@7.2.0:
- resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
- engines: {node: '>=8'}
-
- supports-color@8.1.1:
- resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
- engines: {node: '>=10'}
-
- supports-preserve-symlinks-flag@1.0.0:
- resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
- engines: {node: '>= 0.4'}
-
- test-exclude@6.0.0:
- resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
- engines: {node: '>=8'}
-
thenify-all@1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'}
@@ -1676,19 +950,27 @@ packages:
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
- tmpl@1.0.5:
- resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
- to-fast-properties@2.0.0:
- resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
- engines: {node: '>=4'}
+ tinyexec@0.3.2:
+ resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
+
+ tinyglobby@0.2.14:
+ resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
+ engines: {node: '>=12.0.0'}
- to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
+ tinypool@1.1.1:
+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
- tr46@0.0.3:
- resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ tinyrainbow@2.0.0:
+ resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
+ engines: {node: '>=14.0.0'}
+
+ tinyspy@4.0.3:
+ resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==}
+ engines: {node: '>=14.0.0'}
tr46@1.0.1:
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
@@ -1700,53 +982,18 @@ packages:
ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
- ts-jest@29.3.4:
- resolution: {integrity: sha512-Iqbrm8IXOmV+ggWHOTEbjwyCf2xZlUMv5npExksXohL+tk8va4Fjhb+X2+Rt9NBmgO7bJ8WpnMLOwih/DnMlFA==}
- engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
- hasBin: true
- peerDependencies:
- '@babel/core': '>=7.0.0-beta.0 <8'
- '@jest/transform': ^29.0.0
- '@jest/types': ^29.0.0
- babel-jest: ^29.0.0
- esbuild: '*'
- jest: ^29.0.0
- typescript: '>=4.3 <6'
- peerDependenciesMeta:
- '@babel/core':
- optional: true
- '@jest/transform':
- optional: true
- '@jest/types':
- optional: true
- babel-jest:
- optional: true
- esbuild:
- optional: true
-
- ts-node@10.9.2:
- resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
- hasBin: true
- peerDependencies:
- '@swc/core': '>=1.2.50'
- '@swc/wasm': '>=1.2.50'
- '@types/node': '*'
- typescript: '>=2.7'
- peerDependenciesMeta:
- '@swc/core':
- optional: true
- '@swc/wasm':
- optional: true
-
- tsup@7.2.0:
- resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==}
- engines: {node: '>=16.14'}
+ tsup@8.5.0:
+ resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==}
+ engines: {node: '>=18'}
hasBin: true
peerDependencies:
+ '@microsoft/api-extractor': ^7.36.0
'@swc/core': ^1
postcss: ^8.4.12
- typescript: '>=4.1.0'
+ typescript: '>=4.5.0'
peerDependenciesMeta:
+ '@microsoft/api-extractor':
+ optional: true
'@swc/core':
optional: true
postcss:
@@ -1754,51 +1001,118 @@ packages:
typescript:
optional: true
- type-detect@4.0.8:
- resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+ type-detect@4.1.0:
+ resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==}
engines: {node: '>=4'}
- type-fest@0.21.3:
- resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
- engines: {node: '>=10'}
-
- type-fest@4.41.0:
- resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
- engines: {node: '>=16'}
-
- typescript@5.8.3:
- resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
+ typescript@5.9.2:
+ resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
engines: {node: '>=14.17'}
hasBin: true
- undici-types@5.26.5:
- resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+ ufo@1.6.1:
+ resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
- update-browserslist-db@1.0.16:
- resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
+ undici-types@6.21.0:
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+
+ undici@6.21.3:
+ resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==}
+ engines: {node: '>=18.17'}
+
+ universal-user-agent@6.0.1:
+ resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==}
- v8-compile-cache-lib@3.0.1:
- resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+ url-join@5.0.0:
+ resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ validate-npm-package-name@5.0.1:
+ resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+ vite-node@3.2.4:
+ resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
- v8-to-istanbul@9.2.0:
- resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==}
- engines: {node: '>=10.12.0'}
+ vite@7.1.1:
+ resolution: {integrity: sha512-yJ+Mp7OyV+4S+afWo+QyoL9jFWD11QFH0i5i7JypnfTcA1rmgxCbiA8WwAICDEtZ1Z1hzrVhN8R8rGTqkTY8ZQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ lightningcss: ^1.21.0
+ 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
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
- walker@1.0.8:
- resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+ vitest-fetch-mock@0.4.5:
+ resolution: {integrity: sha512-nhWdCQIGtaSEUVl96pMm0WggyDGPDv5FUy/Q9Hx3cs2RGmh3Q/uRsLClGbdG3kXBkJ3br5yTUjB2MeW25TwdOA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ vitest: '>=2.0.0'
- webidl-conversions@3.0.1:
- resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+ vitest@3.2.4:
+ resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.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.2.4
+ '@vitest/ui': 3.2.4
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/debug':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
webidl-conversions@4.0.2:
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
- whatwg-url@5.0.0:
- resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
-
whatwg-url@7.1.0:
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
@@ -1807,6 +1121,11 @@ packages:
engines: {node: '>= 8'}
hasBin: true
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
+
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
@@ -1818,355 +1137,131 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- write-file-atomic@4.0.2:
- resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-
- y18n@5.0.8:
- resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
- engines: {node: '>=10'}
-
- yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
-
yaml@2.4.5:
resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
engines: {node: '>= 14'}
hasBin: true
- yargs-parser@21.1.1:
- resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
- engines: {node: '>=12'}
-
- yargs@17.7.2:
- resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
- engines: {node: '>=12'}
-
- yn@3.1.1:
- resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
- engines: {node: '>=6'}
+ zod-package-json@1.2.0:
+ resolution: {integrity: sha512-tamtgPM3MkP+obfO2dLr/G+nYoYkpJKmuHdYEy6IXRKfLybruoJ5NUj0lM0LxwOpC9PpoGLbll1ecoeyj43Wsg==}
+ engines: {node: '>=20'}
- yocto-queue@0.1.0:
- resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
- engines: {node: '>=10'}
+ zod@3.25.76:
+ resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
snapshots:
- '@ampproject/remapping@2.3.0':
- dependencies:
- '@jridgewell/gen-mapping': 0.3.5
- '@jridgewell/trace-mapping': 0.3.25
-
- '@babel/code-frame@7.24.7':
- dependencies:
- '@babel/highlight': 7.24.7
- picocolors: 1.0.1
-
- '@babel/compat-data@7.24.7': {}
-
- '@babel/core@7.24.7':
- dependencies:
- '@ampproject/remapping': 2.3.0
- '@babel/code-frame': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/helper-compilation-targets': 7.24.7
- '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
- '@babel/helpers': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/template': 7.24.7
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
- convert-source-map: 2.0.0
- debug: 4.3.5
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- '@babel/generator@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
- '@jridgewell/gen-mapping': 0.3.5
- '@jridgewell/trace-mapping': 0.3.25
- jsesc: 2.5.2
-
- '@babel/helper-compilation-targets@7.24.7':
- dependencies:
- '@babel/compat-data': 7.24.7
- '@babel/helper-validator-option': 7.24.7
- browserslist: 4.23.1
- lru-cache: 5.1.1
- semver: 6.3.1
-
- '@babel/helper-environment-visitor@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
-
- '@babel/helper-function-name@7.24.7':
- dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.7
-
- '@babel/helper-hoist-variables@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
-
- '@babel/helper-module-imports@7.24.7':
- dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-module-imports': 7.24.7
- '@babel/helper-simple-access': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
- '@babel/helper-validator-identifier': 7.24.7
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-plugin-utils@7.24.7': {}
-
- '@babel/helper-simple-access@7.24.7':
- dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-split-export-declaration@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
-
- '@babel/helper-string-parser@7.24.7': {}
-
- '@babel/helper-validator-identifier@7.24.7': {}
-
- '@babel/helper-validator-option@7.24.7': {}
-
- '@babel/helpers@7.24.7':
- dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.7
-
- '@babel/highlight@7.24.7':
- dependencies:
- '@babel/helper-validator-identifier': 7.24.7
- chalk: 2.4.2
- js-tokens: 4.0.0
- picocolors: 1.0.1
-
- '@babel/parser@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
-
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/template@7.24.7':
- dependencies:
- '@babel/code-frame': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
-
- '@babel/traverse@7.24.7':
- dependencies:
- '@babel/code-frame': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-function-name': 7.24.7
- '@babel/helper-hoist-variables': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
- debug: 4.3.5
- globals: 11.12.0
- transitivePeerDependencies:
- - supports-color
+ '@biomejs/biome@2.2.0':
+ optionalDependencies:
+ '@biomejs/cli-darwin-arm64': 2.2.0
+ '@biomejs/cli-darwin-x64': 2.2.0
+ '@biomejs/cli-linux-arm64': 2.2.0
+ '@biomejs/cli-linux-arm64-musl': 2.2.0
+ '@biomejs/cli-linux-x64': 2.2.0
+ '@biomejs/cli-linux-x64-musl': 2.2.0
+ '@biomejs/cli-win32-arm64': 2.2.0
+ '@biomejs/cli-win32-x64': 2.2.0
+
+ '@biomejs/cli-darwin-arm64@2.2.0':
+ optional: true
- '@babel/types@7.24.7':
- dependencies:
- '@babel/helper-string-parser': 7.24.7
- '@babel/helper-validator-identifier': 7.24.7
- to-fast-properties: 2.0.0
+ '@biomejs/cli-darwin-x64@2.2.0':
+ optional: true
- '@bcoe/v8-coverage@0.2.3': {}
+ '@biomejs/cli-linux-arm64-musl@2.2.0':
+ optional: true
- '@biomejs/biome@1.9.4':
- optionalDependencies:
- '@biomejs/cli-darwin-arm64': 1.9.4
- '@biomejs/cli-darwin-x64': 1.9.4
- '@biomejs/cli-linux-arm64': 1.9.4
- '@biomejs/cli-linux-arm64-musl': 1.9.4
- '@biomejs/cli-linux-x64': 1.9.4
- '@biomejs/cli-linux-x64-musl': 1.9.4
- '@biomejs/cli-win32-arm64': 1.9.4
- '@biomejs/cli-win32-x64': 1.9.4
-
- '@biomejs/cli-darwin-arm64@1.9.4':
+ '@biomejs/cli-linux-arm64@2.2.0':
optional: true
- '@biomejs/cli-darwin-x64@1.9.4':
+ '@biomejs/cli-linux-x64-musl@2.2.0':
optional: true
- '@biomejs/cli-linux-arm64-musl@1.9.4':
+ '@biomejs/cli-linux-x64@2.2.0':
optional: true
- '@biomejs/cli-linux-arm64@1.9.4':
+ '@biomejs/cli-win32-arm64@2.2.0':
optional: true
- '@biomejs/cli-linux-x64-musl@1.9.4':
+ '@biomejs/cli-win32-x64@2.2.0':
optional: true
- '@biomejs/cli-linux-x64@1.9.4':
+ '@esbuild/aix-ppc64@0.25.8':
optional: true
- '@biomejs/cli-win32-arm64@1.9.4':
+ '@esbuild/android-arm64@0.25.8':
optional: true
- '@biomejs/cli-win32-x64@1.9.4':
+ '@esbuild/android-arm@0.25.8':
optional: true
- '@cspotcode/source-map-support@0.8.1':
- dependencies:
- '@jridgewell/trace-mapping': 0.3.9
+ '@esbuild/android-x64@0.25.8':
+ optional: true
- '@esbuild/android-arm64@0.18.20':
+ '@esbuild/darwin-arm64@0.25.8':
optional: true
- '@esbuild/android-arm@0.18.20':
+ '@esbuild/darwin-x64@0.25.8':
optional: true
- '@esbuild/android-x64@0.18.20':
+ '@esbuild/freebsd-arm64@0.25.8':
optional: true
- '@esbuild/darwin-arm64@0.18.20':
+ '@esbuild/freebsd-x64@0.25.8':
optional: true
- '@esbuild/darwin-x64@0.18.20':
+ '@esbuild/linux-arm64@0.25.8':
optional: true
- '@esbuild/freebsd-arm64@0.18.20':
+ '@esbuild/linux-arm@0.25.8':
optional: true
- '@esbuild/freebsd-x64@0.18.20':
+ '@esbuild/linux-ia32@0.25.8':
optional: true
- '@esbuild/linux-arm64@0.18.20':
+ '@esbuild/linux-loong64@0.25.8':
optional: true
- '@esbuild/linux-arm@0.18.20':
+ '@esbuild/linux-mips64el@0.25.8':
optional: true
- '@esbuild/linux-ia32@0.18.20':
+ '@esbuild/linux-ppc64@0.25.8':
optional: true
- '@esbuild/linux-loong64@0.18.20':
+ '@esbuild/linux-riscv64@0.25.8':
optional: true
- '@esbuild/linux-mips64el@0.18.20':
+ '@esbuild/linux-s390x@0.25.8':
optional: true
- '@esbuild/linux-ppc64@0.18.20':
+ '@esbuild/linux-x64@0.25.8':
optional: true
- '@esbuild/linux-riscv64@0.18.20':
+ '@esbuild/netbsd-arm64@0.25.8':
optional: true
- '@esbuild/linux-s390x@0.18.20':
+ '@esbuild/netbsd-x64@0.25.8':
optional: true
- '@esbuild/linux-x64@0.18.20':
+ '@esbuild/openbsd-arm64@0.25.8':
optional: true
- '@esbuild/netbsd-x64@0.18.20':
+ '@esbuild/openbsd-x64@0.25.8':
optional: true
- '@esbuild/openbsd-x64@0.18.20':
+ '@esbuild/openharmony-arm64@0.25.8':
optional: true
- '@esbuild/sunos-x64@0.18.20':
+ '@esbuild/sunos-x64@0.25.8':
optional: true
- '@esbuild/win32-arm64@0.18.20':
+ '@esbuild/win32-arm64@0.25.8':
optional: true
- '@esbuild/win32-ia32@0.18.20':
+ '@esbuild/win32-ia32@0.25.8':
optional: true
- '@esbuild/win32-x64@0.18.20':
+ '@esbuild/win32-x64@0.25.8':
optional: true
'@isaacs/cliui@8.0.2':
@@ -2178,1242 +1273,464 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
- '@istanbuljs/load-nyc-config@1.1.0':
- dependencies:
- camelcase: 5.3.1
- find-up: 4.1.0
- get-package-type: 0.1.0
- js-yaml: 3.14.1
- resolve-from: 5.0.0
-
- '@istanbuljs/schema@0.1.3': {}
-
- '@jest/console@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- chalk: 4.1.2
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
-
- '@jest/core@29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/reporters': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- ci-info: 3.9.0
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-resolve-dependencies: 29.7.0
- jest-runner: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- jest-watcher: 29.7.0
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-ansi: 6.0.1
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- '@jest/environment@29.7.0':
- dependencies:
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- jest-mock: 29.7.0
-
- '@jest/expect-utils@29.7.0':
- dependencies:
- jest-get-type: 29.6.3
-
- '@jest/expect@29.7.0':
- dependencies:
- expect: 29.7.0
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/fake-timers@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
- '@sinonjs/fake-timers': 10.3.0
- '@types/node': 18.19.86
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-util: 29.7.0
-
- '@jest/globals@29.7.0':
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/types': 29.6.3
- jest-mock: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/reporters@29.7.0':
- dependencies:
- '@bcoe/v8-coverage': 0.2.3
- '@jest/console': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.25
- '@types/node': 18.19.86
- chalk: 4.1.2
- collect-v8-coverage: 1.0.2
- exit: 0.1.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- istanbul-lib-coverage: 3.2.2
- istanbul-lib-instrument: 6.0.2
- istanbul-lib-report: 3.0.1
- istanbul-lib-source-maps: 4.0.1
- istanbul-reports: 3.1.7
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- jest-worker: 29.7.0
- slash: 3.0.0
- string-length: 4.0.2
- strip-ansi: 6.0.1
- v8-to-istanbul: 9.2.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/schemas@29.6.3':
- dependencies:
- '@sinclair/typebox': 0.27.8
-
- '@jest/source-map@29.6.3':
- dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- callsites: 3.1.0
- graceful-fs: 4.2.11
-
- '@jest/test-result@29.7.0':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/types': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- collect-v8-coverage: 1.0.2
-
- '@jest/test-sequencer@29.7.0':
- dependencies:
- '@jest/test-result': 29.7.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- slash: 3.0.0
-
- '@jest/transform@29.7.0':
- dependencies:
- '@babel/core': 7.24.7
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.25
- babel-plugin-istanbul: 6.1.1
- chalk: 4.1.2
- convert-source-map: 2.0.0
- fast-json-stable-stringify: 2.1.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- micromatch: 4.0.8
- pirates: 4.0.6
- slash: 3.0.0
- write-file-atomic: 4.0.2
- transitivePeerDependencies:
- - supports-color
-
- '@jest/types@29.6.3':
- dependencies:
- '@jest/schemas': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- '@types/istanbul-reports': 3.0.4
- '@types/node': 18.19.86
- '@types/yargs': 17.0.32
- chalk: 4.1.2
-
'@jridgewell/gen-mapping@0.3.5':
dependencies:
'@jridgewell/set-array': 1.2.1
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/sourcemap-codec': 1.5.4
'@jridgewell/trace-mapping': 0.3.25
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/set-array@1.2.1': {}
- '@jridgewell/sourcemap-codec@1.4.15': {}
+ '@jridgewell/sourcemap-codec@1.5.4': {}
'@jridgewell/trace-mapping@0.3.25':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.4.15
-
- '@jridgewell/trace-mapping@0.3.9':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.4.15
-
- '@nodelib/fs.scandir@2.1.5':
- dependencies:
- '@nodelib/fs.stat': 2.0.5
- run-parallel: 1.2.0
-
- '@nodelib/fs.stat@2.0.5': {}
-
- '@nodelib/fs.walk@1.2.8':
- dependencies:
- '@nodelib/fs.scandir': 2.1.5
- fastq: 1.17.1
-
- '@pkgjs/parseargs@0.11.0':
- optional: true
-
- '@react-email/render@1.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
- dependencies:
- html-to-text: 9.0.5
- prettier: 3.5.3
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
- react-promise-suspense: 0.3.4
-
- '@selderee/plugin-htmlparser2@0.11.0':
- dependencies:
- domhandler: 5.0.3
- selderee: 0.11.0
-
- '@sinclair/typebox@0.27.8': {}
-
- '@sinonjs/commons@3.0.1':
- dependencies:
- type-detect: 4.0.8
-
- '@sinonjs/fake-timers@10.3.0':
- dependencies:
- '@sinonjs/commons': 3.0.1
-
- '@tsconfig/node10@1.0.11': {}
-
- '@tsconfig/node12@1.0.11': {}
-
- '@tsconfig/node14@1.0.3': {}
-
- '@tsconfig/node16@1.0.4': {}
-
- '@types/babel__core@7.20.5':
- dependencies:
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
- '@types/babel__generator': 7.6.8
- '@types/babel__template': 7.4.4
- '@types/babel__traverse': 7.20.6
-
- '@types/babel__generator@7.6.8':
- dependencies:
- '@babel/types': 7.24.7
-
- '@types/babel__template@7.4.4':
- dependencies:
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
-
- '@types/babel__traverse@7.20.6':
- dependencies:
- '@babel/types': 7.24.7
+ '@jridgewell/sourcemap-codec': 1.5.4
- '@types/graceful-fs@4.1.9':
+ '@jsdevtools/ez-spawn@3.0.4':
dependencies:
- '@types/node': 18.19.86
-
- '@types/istanbul-lib-coverage@2.0.6': {}
-
- '@types/istanbul-lib-report@3.0.3':
- dependencies:
- '@types/istanbul-lib-coverage': 2.0.6
-
- '@types/istanbul-reports@3.0.4':
- dependencies:
- '@types/istanbul-lib-report': 3.0.3
-
- '@types/jest@29.5.14':
- dependencies:
- expect: 29.7.0
- pretty-format: 29.7.0
-
- '@types/node@18.19.86':
- dependencies:
- undici-types: 5.26.5
-
- '@types/react@19.1.2':
- dependencies:
- csstype: 3.1.3
-
- '@types/stack-utils@2.0.3': {}
-
- '@types/yargs-parser@21.0.3': {}
-
- '@types/yargs@17.0.32':
- dependencies:
- '@types/yargs-parser': 21.0.3
-
- acorn-walk@8.3.2: {}
-
- acorn@8.11.3: {}
-
- ansi-escapes@4.3.2:
- dependencies:
- type-fest: 0.21.3
-
- ansi-regex@5.0.1: {}
-
- ansi-regex@6.0.1: {}
-
- ansi-styles@3.2.1:
- dependencies:
- color-convert: 1.9.3
-
- ansi-styles@4.3.0:
- dependencies:
- color-convert: 2.0.1
-
- ansi-styles@5.2.0: {}
-
- ansi-styles@6.2.1: {}
-
- any-promise@1.3.0: {}
-
- anymatch@3.1.3:
- dependencies:
- normalize-path: 3.0.0
- picomatch: 2.3.1
-
- arg@4.1.3: {}
-
- argparse@1.0.10:
- dependencies:
- sprintf-js: 1.0.3
-
- array-union@2.1.0: {}
-
- async@3.2.5: {}
-
- babel-jest@29.7.0(@babel/core@7.24.7):
- dependencies:
- '@babel/core': 7.24.7
- '@jest/transform': 29.7.0
- '@types/babel__core': 7.20.5
- babel-plugin-istanbul: 6.1.1
- babel-preset-jest: 29.6.3(@babel/core@7.24.7)
- chalk: 4.1.2
- graceful-fs: 4.2.11
- slash: 3.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-istanbul@6.1.1:
- dependencies:
- '@babel/helper-plugin-utils': 7.24.7
- '@istanbuljs/load-nyc-config': 1.1.0
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-instrument: 5.2.1
- test-exclude: 6.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-jest-hoist@29.6.3:
- dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.7
- '@types/babel__core': 7.20.5
- '@types/babel__traverse': 7.20.6
-
- babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.7):
- dependencies:
- '@babel/core': 7.24.7
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7)
- '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.7)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.7)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7)
-
- babel-preset-jest@29.6.3(@babel/core@7.24.7):
- dependencies:
- '@babel/core': 7.24.7
- babel-plugin-jest-hoist: 29.6.3
- babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.7)
-
- balanced-match@1.0.2: {}
-
- binary-extensions@2.3.0: {}
-
- brace-expansion@1.1.11:
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
-
- brace-expansion@2.0.1:
- dependencies:
- balanced-match: 1.0.2
-
- braces@3.0.3:
- dependencies:
- fill-range: 7.1.1
-
- browserslist@4.23.1:
- dependencies:
- caniuse-lite: 1.0.30001632
- electron-to-chromium: 1.4.797
- node-releases: 2.0.14
- update-browserslist-db: 1.0.16(browserslist@4.23.1)
-
- bs-logger@0.2.6:
- dependencies:
- fast-json-stable-stringify: 2.1.0
-
- bser@2.1.1:
- dependencies:
- node-int64: 0.4.0
-
- buffer-from@1.1.2: {}
-
- bundle-require@4.2.1(esbuild@0.18.20):
- dependencies:
- esbuild: 0.18.20
- load-tsconfig: 0.2.5
-
- cac@6.7.14: {}
-
- callsites@3.1.0: {}
-
- camelcase@5.3.1: {}
-
- camelcase@6.3.0: {}
-
- caniuse-lite@1.0.30001632: {}
+ call-me-maybe: 1.0.2
+ cross-spawn: 7.0.6
+ string-argv: 0.3.2
+ type-detect: 4.1.0
- chalk@2.4.2:
+ '@octokit/action@6.1.0':
dependencies:
- ansi-styles: 3.2.1
- escape-string-regexp: 1.0.5
- supports-color: 5.5.0
+ '@octokit/auth-action': 4.1.0
+ '@octokit/core': 5.2.2
+ '@octokit/plugin-paginate-rest': 9.2.2(@octokit/core@5.2.2)
+ '@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.2.2)
+ '@octokit/types': 12.6.0
+ undici: 6.21.3
- chalk@4.1.2:
+ '@octokit/auth-action@4.1.0':
dependencies:
- ansi-styles: 4.3.0
- supports-color: 7.2.0
-
- char-regex@1.0.2: {}
-
- chokidar@3.6.0:
- dependencies:
- anymatch: 3.1.3
- braces: 3.0.3
- glob-parent: 5.1.2
- is-binary-path: 2.1.0
- is-glob: 4.0.3
- normalize-path: 3.0.0
- readdirp: 3.6.0
- optionalDependencies:
- fsevents: 2.3.3
+ '@octokit/auth-token': 4.0.0
+ '@octokit/types': 13.10.0
- ci-info@3.9.0: {}
+ '@octokit/auth-token@4.0.0': {}
- cjs-module-lexer@1.3.1: {}
-
- cliui@8.0.1:
+ '@octokit/core@5.2.2':
dependencies:
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wrap-ansi: 7.0.0
-
- co@4.6.0: {}
+ '@octokit/auth-token': 4.0.0
+ '@octokit/graphql': 7.1.1
+ '@octokit/request': 8.4.1
+ '@octokit/request-error': 5.1.1
+ '@octokit/types': 13.10.0
+ before-after-hook: 2.2.3
+ universal-user-agent: 6.0.1
- collect-v8-coverage@1.0.2: {}
-
- color-convert@1.9.3:
+ '@octokit/endpoint@9.0.6':
dependencies:
- color-name: 1.1.3
+ '@octokit/types': 13.10.0
+ universal-user-agent: 6.0.1
- color-convert@2.0.1:
+ '@octokit/graphql@7.1.1':
dependencies:
- color-name: 1.1.4
+ '@octokit/request': 8.4.1
+ '@octokit/types': 13.10.0
+ universal-user-agent: 6.0.1
- color-name@1.1.3: {}
+ '@octokit/openapi-types@20.0.0': {}
- color-name@1.1.4: {}
-
- commander@4.1.1: {}
-
- concat-map@0.0.1: {}
-
- convert-source-map@2.0.0: {}
-
- create-jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3)):
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- jest-util: 29.7.0
- prompts: 2.4.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- create-require@1.1.1: {}
-
- cross-fetch@3.1.8:
- dependencies:
- node-fetch: 2.7.0
- transitivePeerDependencies:
- - encoding
+ '@octokit/openapi-types@24.2.0': {}
- cross-spawn@7.0.6:
+ '@octokit/plugin-paginate-rest@9.2.2(@octokit/core@5.2.2)':
dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
-
- csstype@3.1.3: {}
+ '@octokit/core': 5.2.2
+ '@octokit/types': 12.6.0
- debug@4.3.5:
+ '@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.2.2)':
dependencies:
- ms: 2.1.2
+ '@octokit/core': 5.2.2
+ '@octokit/types': 12.6.0
- dedent@1.5.3: {}
-
- deepmerge@4.3.1: {}
-
- detect-newline@3.1.0: {}
-
- diff-sequences@29.6.3: {}
-
- diff@4.0.2: {}
-
- dir-glob@3.0.1:
+ '@octokit/request-error@5.1.1':
dependencies:
- path-type: 4.0.0
+ '@octokit/types': 13.10.0
+ deprecation: 2.3.1
+ once: 1.4.0
- dom-serializer@2.0.0:
+ '@octokit/request@8.4.1':
dependencies:
- domelementtype: 2.3.0
- domhandler: 5.0.3
- entities: 4.5.0
+ '@octokit/endpoint': 9.0.6
+ '@octokit/request-error': 5.1.1
+ '@octokit/types': 13.10.0
+ universal-user-agent: 6.0.1
- domelementtype@2.3.0: {}
-
- domhandler@5.0.3:
+ '@octokit/types@12.6.0':
dependencies:
- domelementtype: 2.3.0
+ '@octokit/openapi-types': 20.0.0
- domutils@3.1.0:
+ '@octokit/types@13.10.0':
dependencies:
- dom-serializer: 2.0.0
- domelementtype: 2.3.0
- domhandler: 5.0.3
+ '@octokit/openapi-types': 24.2.0
- eastasianwidth@0.2.0: {}
+ '@pkgjs/parseargs@0.11.0':
+ optional: true
- ejs@3.1.10:
+ '@react-email/render@1.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- jake: 10.9.2
-
- electron-to-chromium@1.4.797: {}
-
- emittery@0.13.1: {}
-
- emoji-regex@8.0.0: {}
-
- emoji-regex@9.2.2: {}
-
- entities@4.5.0: {}
+ html-to-text: 9.0.5
+ prettier: 3.5.3
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ react-promise-suspense: 0.3.4
- error-ex@1.3.2:
- dependencies:
- is-arrayish: 0.2.1
+ '@rollup/rollup-android-arm-eabi@4.46.2':
+ optional: true
- esbuild@0.18.20:
- optionalDependencies:
- '@esbuild/android-arm': 0.18.20
- '@esbuild/android-arm64': 0.18.20
- '@esbuild/android-x64': 0.18.20
- '@esbuild/darwin-arm64': 0.18.20
- '@esbuild/darwin-x64': 0.18.20
- '@esbuild/freebsd-arm64': 0.18.20
- '@esbuild/freebsd-x64': 0.18.20
- '@esbuild/linux-arm': 0.18.20
- '@esbuild/linux-arm64': 0.18.20
- '@esbuild/linux-ia32': 0.18.20
- '@esbuild/linux-loong64': 0.18.20
- '@esbuild/linux-mips64el': 0.18.20
- '@esbuild/linux-ppc64': 0.18.20
- '@esbuild/linux-riscv64': 0.18.20
- '@esbuild/linux-s390x': 0.18.20
- '@esbuild/linux-x64': 0.18.20
- '@esbuild/netbsd-x64': 0.18.20
- '@esbuild/openbsd-x64': 0.18.20
- '@esbuild/sunos-x64': 0.18.20
- '@esbuild/win32-arm64': 0.18.20
- '@esbuild/win32-ia32': 0.18.20
- '@esbuild/win32-x64': 0.18.20
-
- escalade@3.1.2: {}
-
- escape-string-regexp@1.0.5: {}
-
- escape-string-regexp@2.0.0: {}
-
- esprima@4.0.1: {}
-
- execa@5.1.1:
- dependencies:
- cross-spawn: 7.0.6
- get-stream: 6.0.1
- human-signals: 2.1.0
- is-stream: 2.0.1
- merge-stream: 2.0.0
- npm-run-path: 4.0.1
- onetime: 5.1.2
- signal-exit: 3.0.7
- strip-final-newline: 2.0.0
+ '@rollup/rollup-android-arm64@4.46.2':
+ optional: true
- exit@0.1.2: {}
+ '@rollup/rollup-darwin-arm64@4.46.2':
+ optional: true
- expect@29.7.0:
- dependencies:
- '@jest/expect-utils': 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
+ '@rollup/rollup-darwin-x64@4.46.2':
+ optional: true
- fast-deep-equal@2.0.1: {}
+ '@rollup/rollup-freebsd-arm64@4.46.2':
+ optional: true
- fast-glob@3.3.2:
- dependencies:
- '@nodelib/fs.stat': 2.0.5
- '@nodelib/fs.walk': 1.2.8
- glob-parent: 5.1.2
- merge2: 1.4.1
- micromatch: 4.0.8
+ '@rollup/rollup-freebsd-x64@4.46.2':
+ optional: true
- fast-json-stable-stringify@2.1.0: {}
+ '@rollup/rollup-linux-arm-gnueabihf@4.46.2':
+ optional: true
- fastq@1.17.1:
- dependencies:
- reusify: 1.0.4
+ '@rollup/rollup-linux-arm-musleabihf@4.46.2':
+ optional: true
- fb-watchman@2.0.2:
- dependencies:
- bser: 2.1.1
+ '@rollup/rollup-linux-arm64-gnu@4.46.2':
+ optional: true
- filelist@1.0.4:
- dependencies:
- minimatch: 5.1.6
+ '@rollup/rollup-linux-arm64-musl@4.46.2':
+ optional: true
- fill-range@7.1.1:
- dependencies:
- to-regex-range: 5.0.1
+ '@rollup/rollup-linux-loongarch64-gnu@4.46.2':
+ optional: true
- find-up@4.1.0:
- dependencies:
- locate-path: 5.0.0
- path-exists: 4.0.0
+ '@rollup/rollup-linux-ppc64-gnu@4.46.2':
+ optional: true
- foreground-child@3.1.1:
- dependencies:
- cross-spawn: 7.0.6
- signal-exit: 4.1.0
+ '@rollup/rollup-linux-riscv64-gnu@4.46.2':
+ optional: true
- fs.realpath@1.0.0: {}
+ '@rollup/rollup-linux-riscv64-musl@4.46.2':
+ optional: true
- fsevents@2.3.3:
+ '@rollup/rollup-linux-s390x-gnu@4.46.2':
optional: true
- function-bind@1.1.2: {}
+ '@rollup/rollup-linux-x64-gnu@4.46.2':
+ optional: true
- gensync@1.0.0-beta.2: {}
+ '@rollup/rollup-linux-x64-musl@4.46.2':
+ optional: true
- get-caller-file@2.0.5: {}
+ '@rollup/rollup-win32-arm64-msvc@4.46.2':
+ optional: true
- get-package-type@0.1.0: {}
+ '@rollup/rollup-win32-ia32-msvc@4.46.2':
+ optional: true
- get-stream@6.0.1: {}
+ '@rollup/rollup-win32-x64-msvc@4.46.2':
+ optional: true
- glob-parent@5.1.2:
+ '@selderee/plugin-htmlparser2@0.11.0':
dependencies:
- is-glob: 4.0.3
+ domhandler: 5.0.3
+ selderee: 0.11.0
- glob@10.4.1:
+ '@types/chai@5.2.2':
dependencies:
- foreground-child: 3.1.1
- jackspeak: 3.4.0
- minimatch: 9.0.4
- minipass: 7.1.2
- path-scurry: 1.11.1
+ '@types/deep-eql': 4.0.2
- glob@7.2.3:
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
+ '@types/deep-eql@4.0.2': {}
- globals@11.12.0: {}
+ '@types/estree@1.0.8': {}
- globby@11.1.0:
+ '@types/node@22.17.2':
dependencies:
- array-union: 2.1.0
- dir-glob: 3.0.1
- fast-glob: 3.3.2
- ignore: 5.3.1
- merge2: 1.4.1
- slash: 3.0.0
+ undici-types: 6.21.0
- graceful-fs@4.2.11: {}
-
- has-flag@3.0.0: {}
-
- has-flag@4.0.0: {}
-
- hasown@2.0.2:
+ '@types/react@19.1.10':
dependencies:
- function-bind: 1.1.2
-
- html-escaper@2.0.2: {}
+ csstype: 3.1.3
- html-to-text@9.0.5:
+ '@vitest/expect@3.2.4':
dependencies:
- '@selderee/plugin-htmlparser2': 0.11.0
- deepmerge: 4.3.1
- dom-serializer: 2.0.0
- htmlparser2: 8.0.2
- selderee: 0.11.0
+ '@types/chai': 5.2.2
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
+ chai: 5.2.1
+ tinyrainbow: 2.0.0
- htmlparser2@8.0.2:
+ '@vitest/mocker@3.2.4(vite@7.1.1(@types/node@22.17.2)(yaml@2.4.5))':
dependencies:
- domelementtype: 2.3.0
- domhandler: 5.0.3
- domutils: 3.1.0
- entities: 4.5.0
-
- human-signals@2.1.0: {}
-
- ignore@5.3.1: {}
+ '@vitest/spy': 3.2.4
+ estree-walker: 3.0.3
+ magic-string: 0.30.17
+ optionalDependencies:
+ vite: 7.1.1(@types/node@22.17.2)(yaml@2.4.5)
- import-local@3.1.0:
+ '@vitest/pretty-format@3.2.4':
dependencies:
- pkg-dir: 4.2.0
- resolve-cwd: 3.0.0
+ tinyrainbow: 2.0.0
- imurmurhash@0.1.4: {}
-
- inflight@1.0.6:
+ '@vitest/runner@3.2.4':
dependencies:
- once: 1.4.0
- wrappy: 1.0.2
-
- inherits@2.0.4: {}
+ '@vitest/utils': 3.2.4
+ pathe: 2.0.3
+ strip-literal: 3.0.0
- is-arrayish@0.2.1: {}
+ '@vitest/snapshot@3.2.4':
+ dependencies:
+ '@vitest/pretty-format': 3.2.4
+ magic-string: 0.30.17
+ pathe: 2.0.3
- is-binary-path@2.1.0:
+ '@vitest/spy@3.2.4':
dependencies:
- binary-extensions: 2.3.0
+ tinyspy: 4.0.3
- is-core-module@2.13.1:
+ '@vitest/utils@3.2.4':
dependencies:
- hasown: 2.0.2
+ '@vitest/pretty-format': 3.2.4
+ loupe: 3.2.0
+ tinyrainbow: 2.0.0
- is-extglob@2.1.1: {}
+ acorn@8.15.0: {}
- is-fullwidth-code-point@3.0.0: {}
+ ansi-regex@5.0.1: {}
- is-generator-fn@2.1.0: {}
+ ansi-regex@6.0.1: {}
- is-glob@4.0.3:
+ ansi-styles@4.3.0:
dependencies:
- is-extglob: 2.1.1
+ color-convert: 2.0.1
- is-number@7.0.0: {}
+ ansi-styles@6.2.1: {}
- is-stream@2.0.1: {}
+ any-promise@1.3.0: {}
- isexe@2.0.0: {}
+ assertion-error@2.0.1: {}
- istanbul-lib-coverage@3.2.2: {}
+ balanced-match@1.0.2: {}
- istanbul-lib-instrument@5.2.1:
- dependencies:
- '@babel/core': 7.24.7
- '@babel/parser': 7.24.7
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
+ before-after-hook@2.2.3: {}
- istanbul-lib-instrument@6.0.2:
+ brace-expansion@2.0.1:
dependencies:
- '@babel/core': 7.24.7
- '@babel/parser': 7.24.7
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 7.7.1
- transitivePeerDependencies:
- - supports-color
+ balanced-match: 1.0.2
- istanbul-lib-report@3.0.1:
+ bundle-require@5.1.0(esbuild@0.25.8):
dependencies:
- istanbul-lib-coverage: 3.2.2
- make-dir: 4.0.0
- supports-color: 7.2.0
+ esbuild: 0.25.8
+ load-tsconfig: 0.2.5
+
+ cac@6.7.14: {}
- istanbul-lib-source-maps@4.0.1:
+ call-me-maybe@1.0.2: {}
+
+ chai@5.2.1:
dependencies:
- debug: 4.3.5
- istanbul-lib-coverage: 3.2.2
- source-map: 0.6.1
- transitivePeerDependencies:
- - supports-color
+ assertion-error: 2.0.1
+ check-error: 2.1.1
+ deep-eql: 5.0.2
+ loupe: 3.2.0
+ pathval: 2.0.1
+
+ check-error@2.1.1: {}
- istanbul-reports@3.1.7:
+ chokidar@4.0.3:
dependencies:
- html-escaper: 2.0.2
- istanbul-lib-report: 3.0.1
+ readdirp: 4.1.2
- jackspeak@3.4.0:
+ color-convert@2.0.1:
dependencies:
- '@isaacs/cliui': 8.0.2
- optionalDependencies:
- '@pkgjs/parseargs': 0.11.0
+ color-name: 1.1.4
- jake@10.9.2:
- dependencies:
- async: 3.2.5
- chalk: 4.1.2
- filelist: 1.0.4
- minimatch: 3.1.2
-
- jest-changed-files@29.7.0:
- dependencies:
- execa: 5.1.1
- jest-util: 29.7.0
- p-limit: 3.1.0
-
- jest-circus@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- chalk: 4.1.2
- co: 4.6.0
- dedent: 1.5.3
- is-generator-fn: 2.1.0
- jest-each: 29.7.0
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- p-limit: 3.1.0
- pretty-format: 29.7.0
- pure-rand: 6.1.0
- slash: 3.0.0
- stack-utils: 2.0.6
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
+ color-name@1.1.4: {}
- jest-cli@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3)):
- dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- chalk: 4.1.2
- create-jest: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- exit: 0.1.2
- import-local: 3.1.0
- jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- jest-util: 29.7.0
- jest-validate: 29.7.0
- yargs: 17.7.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
+ commander@4.1.1: {}
- jest-config@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3)):
- dependencies:
- '@babel/core': 7.24.7
- '@jest/test-sequencer': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.24.7)
- chalk: 4.1.2
- ci-info: 3.9.0
- deepmerge: 4.3.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-circus: 29.7.0
- jest-environment-node: 29.7.0
- jest-get-type: 29.6.3
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-runner: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- micromatch: 4.0.8
- parse-json: 5.2.0
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-json-comments: 3.1.1
- optionalDependencies:
- '@types/node': 18.19.86
- ts-node: 10.9.2(@types/node@18.19.86)(typescript@5.8.3)
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
+ confbox@0.1.8: {}
- jest-diff@29.7.0:
- dependencies:
- chalk: 4.1.2
- diff-sequences: 29.6.3
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
+ consola@3.4.2: {}
- jest-docblock@29.7.0:
+ cross-spawn@7.0.6:
dependencies:
- detect-newline: 3.1.0
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
- jest-each@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- jest-get-type: 29.6.3
- jest-util: 29.7.0
- pretty-format: 29.7.0
+ csstype@3.1.3: {}
- jest-environment-node@29.7.0:
+ debug@4.4.1:
dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- jest-mock: 29.7.0
- jest-util: 29.7.0
+ ms: 2.1.3
- jest-fetch-mock@3.0.3:
- dependencies:
- cross-fetch: 3.1.8
- promise-polyfill: 8.3.0
- transitivePeerDependencies:
- - encoding
-
- jest-get-type@29.6.3: {}
-
- jest-haste-map@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/graceful-fs': 4.1.9
- '@types/node': 18.19.86
- anymatch: 3.1.3
- fb-watchman: 2.0.2
- graceful-fs: 4.2.11
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- jest-worker: 29.7.0
- micromatch: 4.0.8
- walker: 1.0.8
- optionalDependencies:
- fsevents: 2.3.3
+ decode-uri-component@0.4.1: {}
- jest-leak-detector@29.7.0:
- dependencies:
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
+ deep-eql@5.0.2: {}
+
+ deepmerge@4.3.1: {}
- jest-matcher-utils@29.7.0:
+ deprecation@2.3.1: {}
+
+ dom-serializer@2.0.0:
dependencies:
- chalk: 4.1.2
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
- jest-message-util@29.7.0:
+ domhandler@5.0.3:
dependencies:
- '@babel/code-frame': 7.24.7
- '@jest/types': 29.6.3
- '@types/stack-utils': 2.0.3
- chalk: 4.1.2
- graceful-fs: 4.2.11
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- stack-utils: 2.0.6
+ domelementtype: 2.3.0
- jest-mock@29.7.0:
+ domutils@3.1.0:
dependencies:
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- jest-util: 29.7.0
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
- jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
- optionalDependencies:
- jest-resolve: 29.7.0
+ eastasianwidth@0.2.0: {}
- jest-regex-util@29.6.3: {}
+ emoji-regex@8.0.0: {}
- jest-resolve-dependencies@29.7.0:
- dependencies:
- jest-regex-util: 29.6.3
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
+ emoji-regex@9.2.2: {}
- jest-resolve@29.7.0:
- dependencies:
- chalk: 4.1.2
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
- jest-util: 29.7.0
- jest-validate: 29.7.0
- resolve: 1.22.8
- resolve.exports: 2.0.2
- slash: 3.0.0
-
- jest-runner@29.7.0:
- dependencies:
- '@jest/console': 29.7.0
- '@jest/environment': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- chalk: 4.1.2
- emittery: 0.13.1
- graceful-fs: 4.2.11
- jest-docblock: 29.7.0
- jest-environment-node: 29.7.0
- jest-haste-map: 29.7.0
- jest-leak-detector: 29.7.0
- jest-message-util: 29.7.0
- jest-resolve: 29.7.0
- jest-runtime: 29.7.0
- jest-util: 29.7.0
- jest-watcher: 29.7.0
- jest-worker: 29.7.0
- p-limit: 3.1.0
- source-map-support: 0.5.13
- transitivePeerDependencies:
- - supports-color
+ entities@4.5.0: {}
- jest-runtime@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/globals': 29.7.0
- '@jest/source-map': 29.6.3
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- chalk: 4.1.2
- cjs-module-lexer: 1.3.1
- collect-v8-coverage: 1.0.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
- strip-bom: 4.0.0
- transitivePeerDependencies:
- - supports-color
+ es-module-lexer@1.7.0: {}
- jest-snapshot@29.7.0:
- dependencies:
- '@babel/core': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7)
- '@babel/types': 7.24.7
- '@jest/expect-utils': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.7)
- chalk: 4.1.2
- expect: 29.7.0
- graceful-fs: 4.2.11
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- natural-compare: 1.4.0
- pretty-format: 29.7.0
- semver: 7.7.1
- transitivePeerDependencies:
- - supports-color
+ esbuild@0.25.8:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.8
+ '@esbuild/android-arm': 0.25.8
+ '@esbuild/android-arm64': 0.25.8
+ '@esbuild/android-x64': 0.25.8
+ '@esbuild/darwin-arm64': 0.25.8
+ '@esbuild/darwin-x64': 0.25.8
+ '@esbuild/freebsd-arm64': 0.25.8
+ '@esbuild/freebsd-x64': 0.25.8
+ '@esbuild/linux-arm': 0.25.8
+ '@esbuild/linux-arm64': 0.25.8
+ '@esbuild/linux-ia32': 0.25.8
+ '@esbuild/linux-loong64': 0.25.8
+ '@esbuild/linux-mips64el': 0.25.8
+ '@esbuild/linux-ppc64': 0.25.8
+ '@esbuild/linux-riscv64': 0.25.8
+ '@esbuild/linux-s390x': 0.25.8
+ '@esbuild/linux-x64': 0.25.8
+ '@esbuild/netbsd-arm64': 0.25.8
+ '@esbuild/netbsd-x64': 0.25.8
+ '@esbuild/openbsd-arm64': 0.25.8
+ '@esbuild/openbsd-x64': 0.25.8
+ '@esbuild/openharmony-arm64': 0.25.8
+ '@esbuild/sunos-x64': 0.25.8
+ '@esbuild/win32-arm64': 0.25.8
+ '@esbuild/win32-ia32': 0.25.8
+ '@esbuild/win32-x64': 0.25.8
+
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+
+ expect-type@1.2.2: {}
- jest-util@29.7.0:
+ fast-deep-equal@2.0.1: {}
+
+ fdir@6.4.6(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
+ filter-obj@5.1.0: {}
+
+ fix-dts-default-cjs-exports@1.0.1:
dependencies:
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- chalk: 4.1.2
- ci-info: 3.9.0
- graceful-fs: 4.2.11
- picomatch: 2.3.1
+ magic-string: 0.30.17
+ mlly: 1.7.4
+ rollup: 4.46.2
- jest-validate@29.7.0:
+ foreground-child@3.1.1:
dependencies:
- '@jest/types': 29.6.3
- camelcase: 6.3.0
- chalk: 4.1.2
- jest-get-type: 29.6.3
- leven: 3.1.0
- pretty-format: 29.7.0
+ cross-spawn: 7.0.6
+ signal-exit: 4.1.0
- jest-watcher@29.7.0:
+ fsevents@2.3.3:
+ optional: true
+
+ glob@10.4.1:
dependencies:
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 18.19.86
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- emittery: 0.13.1
- jest-util: 29.7.0
- string-length: 4.0.2
+ foreground-child: 3.1.1
+ jackspeak: 3.4.0
+ minimatch: 9.0.4
+ minipass: 7.1.2
+ path-scurry: 1.11.1
- jest-worker@29.7.0:
+ html-to-text@9.0.5:
dependencies:
- '@types/node': 18.19.86
- jest-util: 29.7.0
- merge-stream: 2.0.0
- supports-color: 8.1.1
+ '@selderee/plugin-htmlparser2': 0.11.0
+ deepmerge: 4.3.1
+ dom-serializer: 2.0.0
+ htmlparser2: 8.0.2
+ selderee: 0.11.0
- jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3)):
+ htmlparser2@8.0.2:
dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- '@jest/types': 29.6.3
- import-local: 3.1.0
- jest-cli: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+ entities: 4.5.0
- joycon@3.1.1: {}
+ ignore@5.3.1: {}
- js-tokens@4.0.0: {}
+ is-fullwidth-code-point@3.0.0: {}
- js-yaml@3.14.1:
- dependencies:
- argparse: 1.0.10
- esprima: 4.0.1
+ isbinaryfile@5.0.4: {}
- jsesc@2.5.2: {}
+ isexe@2.0.0: {}
+
+ jackspeak@3.4.0:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
- json-parse-even-better-errors@2.3.1: {}
+ joycon@3.1.1: {}
- json5@2.2.3: {}
+ js-tokens@4.0.0: {}
- kleur@3.0.3: {}
+ js-tokens@9.0.1: {}
leac@0.6.0: {}
- leven@3.1.0: {}
-
lilconfig@3.1.2: {}
lines-and-columns@1.2.4: {}
load-tsconfig@0.2.5: {}
- locate-path@5.0.0:
- dependencies:
- p-locate: 4.1.0
-
- lodash.memoize@4.1.2: {}
-
lodash.sortby@4.7.0: {}
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
- lru-cache@10.2.2: {}
-
- lru-cache@5.1.1:
- dependencies:
- yallist: 3.1.1
-
- make-dir@4.0.0:
- dependencies:
- semver: 7.7.1
-
- make-error@1.3.6: {}
-
- makeerror@1.0.12:
- dependencies:
- tmpl: 1.0.5
-
- merge-stream@2.0.0: {}
-
- merge2@1.4.1: {}
-
- micromatch@4.0.8:
- dependencies:
- braces: 3.0.3
- picomatch: 2.3.1
-
- mimic-fn@2.1.0: {}
+ loupe@3.2.0: {}
- minimatch@3.1.2:
- dependencies:
- brace-expansion: 1.1.11
+ lru-cache@10.2.2: {}
- minimatch@5.1.6:
+ magic-string@0.30.17:
dependencies:
- brace-expansion: 2.0.1
+ '@jridgewell/sourcemap-codec': 1.5.4
minimatch@9.0.4:
dependencies:
@@ -3421,7 +1738,14 @@ snapshots:
minipass@7.1.2: {}
- ms@2.1.2: {}
+ mlly@1.7.4:
+ dependencies:
+ acorn: 8.15.0
+ pathe: 2.0.3
+ pkg-types: 1.3.1
+ ufo: 1.6.1
+
+ ms@2.1.3: {}
mz@2.7.0:
dependencies:
@@ -3429,21 +1753,7 @@ snapshots:
object-assign: 4.1.1
thenify-all: 1.6.0
- natural-compare@1.4.0: {}
-
- node-fetch@2.7.0:
- dependencies:
- whatwg-url: 5.0.0
-
- node-int64@0.4.0: {}
-
- node-releases@2.0.14: {}
-
- normalize-path@3.0.0: {}
-
- npm-run-path@4.0.1:
- dependencies:
- path-key: 3.1.1
+ nanoid@3.3.11: {}
object-assign@4.1.1: {}
@@ -3451,90 +1761,79 @@ snapshots:
dependencies:
wrappy: 1.0.2
- onetime@5.1.2:
- dependencies:
- mimic-fn: 2.1.0
-
- p-limit@2.3.0:
- dependencies:
- p-try: 2.2.0
-
- p-limit@3.1.0:
- dependencies:
- yocto-queue: 0.1.0
-
- p-locate@4.1.0:
- dependencies:
- p-limit: 2.3.0
-
- p-try@2.2.0: {}
-
- parse-json@5.2.0:
- dependencies:
- '@babel/code-frame': 7.24.7
- error-ex: 1.3.2
- json-parse-even-better-errors: 2.3.1
- lines-and-columns: 1.2.4
-
parseley@0.12.1:
dependencies:
leac: 0.6.0
peberminta: 0.9.0
- path-exists@4.0.0: {}
-
- path-is-absolute@1.0.1: {}
-
path-key@3.1.1: {}
- path-parse@1.0.7: {}
-
path-scurry@1.11.1:
dependencies:
lru-cache: 10.2.2
minipass: 7.1.2
- path-type@4.0.0: {}
+ pathe@2.0.3: {}
+
+ pathval@2.0.1: {}
peberminta@0.9.0: {}
- picocolors@1.0.1: {}
+ picocolors@1.1.1: {}
- picomatch@2.3.1: {}
+ picomatch@4.0.3: {}
pirates@4.0.6: {}
- pkg-dir@4.2.0:
+ pkg-pr-new@0.0.56:
+ dependencies:
+ '@jsdevtools/ez-spawn': 3.0.4
+ '@octokit/action': 6.1.0
+ ignore: 5.3.1
+ isbinaryfile: 5.0.4
+ pkg-types: 1.3.1
+ query-registry: 3.0.1
+ tinyglobby: 0.2.14
+
+ pkg-types@1.3.1:
dependencies:
- find-up: 4.1.0
+ confbox: 0.1.8
+ mlly: 1.7.4
+ pathe: 2.0.3
- postcss-load-config@4.0.2(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3)):
+ postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.4.5):
dependencies:
lilconfig: 3.1.2
- yaml: 2.4.5
optionalDependencies:
- ts-node: 10.9.2(@types/node@18.19.86)(typescript@5.8.3)
-
- prettier@3.5.3: {}
+ postcss: 8.5.6
+ yaml: 2.4.5
- pretty-format@29.7.0:
+ postcss@8.5.6:
dependencies:
- '@jest/schemas': 29.6.3
- ansi-styles: 5.2.0
- react-is: 18.3.1
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
- promise-polyfill@8.3.0: {}
-
- prompts@2.4.2:
- dependencies:
- kleur: 3.0.3
- sisteransi: 1.0.5
+ prettier@3.5.3: {}
punycode@2.3.1: {}
- pure-rand@6.1.0: {}
+ query-registry@3.0.1:
+ dependencies:
+ query-string: 9.2.2
+ quick-lru: 7.1.0
+ url-join: 5.0.0
+ validate-npm-package-name: 5.0.1
+ zod: 3.25.76
+ zod-package-json: 1.2.0
+
+ query-string@9.2.2:
+ dependencies:
+ decode-uri-component: 0.4.1
+ filter-obj: 5.1.0
+ split-on-first: 3.0.0
- queue-microtask@1.2.3: {}
+ quick-lru@7.1.0: {}
react-dom@18.3.1(react@18.3.1):
dependencies:
@@ -3542,8 +1841,6 @@ snapshots:
react: 18.3.1
scheduler: 0.23.2
- react-is@18.3.1: {}
-
react-promise-suspense@0.3.4:
dependencies:
fast-deep-equal: 2.0.1
@@ -3552,36 +1849,36 @@ snapshots:
dependencies:
loose-envify: 1.4.0
- readdirp@3.6.0:
- dependencies:
- picomatch: 2.3.1
-
- require-directory@2.1.1: {}
-
- resolve-cwd@3.0.0:
- dependencies:
- resolve-from: 5.0.0
+ readdirp@4.1.2: {}
resolve-from@5.0.0: {}
- resolve.exports@2.0.2: {}
-
- resolve@1.22.8:
+ rollup@4.46.2:
dependencies:
- is-core-module: 2.13.1
- path-parse: 1.0.7
- supports-preserve-symlinks-flag: 1.0.0
-
- reusify@1.0.4: {}
-
- rollup@3.29.5:
+ '@types/estree': 1.0.8
optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.46.2
+ '@rollup/rollup-android-arm64': 4.46.2
+ '@rollup/rollup-darwin-arm64': 4.46.2
+ '@rollup/rollup-darwin-x64': 4.46.2
+ '@rollup/rollup-freebsd-arm64': 4.46.2
+ '@rollup/rollup-freebsd-x64': 4.46.2
+ '@rollup/rollup-linux-arm-gnueabihf': 4.46.2
+ '@rollup/rollup-linux-arm-musleabihf': 4.46.2
+ '@rollup/rollup-linux-arm64-gnu': 4.46.2
+ '@rollup/rollup-linux-arm64-musl': 4.46.2
+ '@rollup/rollup-linux-loongarch64-gnu': 4.46.2
+ '@rollup/rollup-linux-ppc64-gnu': 4.46.2
+ '@rollup/rollup-linux-riscv64-gnu': 4.46.2
+ '@rollup/rollup-linux-riscv64-musl': 4.46.2
+ '@rollup/rollup-linux-s390x-gnu': 4.46.2
+ '@rollup/rollup-linux-x64-gnu': 4.46.2
+ '@rollup/rollup-linux-x64-musl': 4.46.2
+ '@rollup/rollup-win32-arm64-msvc': 4.46.2
+ '@rollup/rollup-win32-ia32-msvc': 4.46.2
+ '@rollup/rollup-win32-x64-msvc': 4.46.2
fsevents: 2.3.3
- run-parallel@1.2.0:
- dependencies:
- queue-microtask: 1.2.3
-
scheduler@0.23.2:
dependencies:
loose-envify: 1.4.0
@@ -3590,47 +1887,29 @@ snapshots:
dependencies:
parseley: 0.12.1
- semver@6.3.1: {}
-
- semver@7.7.1: {}
-
- semver@7.7.2: {}
-
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
shebang-regex@3.0.0: {}
- signal-exit@3.0.7: {}
+ siginfo@2.0.0: {}
signal-exit@4.1.0: {}
- sisteransi@1.0.5: {}
-
- slash@3.0.0: {}
-
- source-map-support@0.5.13:
- dependencies:
- buffer-from: 1.1.2
- source-map: 0.6.1
-
- source-map@0.6.1: {}
+ source-map-js@1.2.1: {}
source-map@0.8.0-beta.0:
dependencies:
whatwg-url: 7.1.0
- sprintf-js@1.0.3: {}
+ split-on-first@3.0.0: {}
- stack-utils@2.0.6:
- dependencies:
- escape-string-regexp: 2.0.0
+ stackback@0.0.2: {}
- string-length@4.0.2:
- dependencies:
- char-regex: 1.0.2
- strip-ansi: 6.0.1
+ std-env@3.9.0: {}
+
+ string-argv@0.3.2: {}
string-width@4.2.3:
dependencies:
@@ -3652,11 +1931,9 @@ snapshots:
dependencies:
ansi-regex: 6.0.1
- strip-bom@4.0.0: {}
-
- strip-final-newline@2.0.0: {}
-
- strip-json-comments@3.1.1: {}
+ strip-literal@3.0.0:
+ dependencies:
+ js-tokens: 9.0.1
sucrase@3.35.0:
dependencies:
@@ -3668,26 +1945,6 @@ snapshots:
pirates: 4.0.6
ts-interface-checker: 0.1.13
- supports-color@5.5.0:
- dependencies:
- has-flag: 3.0.0
-
- supports-color@7.2.0:
- dependencies:
- has-flag: 4.0.0
-
- supports-color@8.1.1:
- dependencies:
- has-flag: 4.0.0
-
- supports-preserve-symlinks-flag@1.0.0: {}
-
- test-exclude@6.0.0:
- dependencies:
- '@istanbuljs/schema': 0.1.3
- glob: 7.2.3
- minimatch: 3.1.2
-
thenify-all@1.6.0:
dependencies:
thenify: 3.3.1
@@ -3696,15 +1953,20 @@ snapshots:
dependencies:
any-promise: 1.3.0
- tmpl@1.0.5: {}
+ tinybench@2.9.0: {}
- to-fast-properties@2.0.0: {}
+ tinyexec@0.3.2: {}
- to-regex-range@5.0.1:
+ tinyglobby@0.2.14:
dependencies:
- is-number: 7.0.0
+ fdir: 6.4.6(picomatch@4.0.3)
+ picomatch: 4.0.3
+
+ tinypool@1.1.1: {}
+
+ tinyrainbow@2.0.0: {}
- tr46@0.0.3: {}
+ tinyspy@4.0.3: {}
tr46@1.0.1:
dependencies:
@@ -3714,104 +1976,131 @@ snapshots:
ts-interface-checker@0.1.13: {}
- ts-jest@29.3.4(@babel/core@7.24.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(esbuild@0.18.20)(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3)))(typescript@5.8.3):
- dependencies:
- bs-logger: 0.2.6
- ejs: 3.1.10
- fast-json-stable-stringify: 2.1.0
- jest: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
- jest-util: 29.7.0
- json5: 2.2.3
- lodash.memoize: 4.1.2
- make-error: 1.3.6
- semver: 7.7.2
- type-fest: 4.41.0
- typescript: 5.8.3
- yargs-parser: 21.1.1
- optionalDependencies:
- '@babel/core': 7.24.7
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.24.7)
- esbuild: 0.18.20
-
- ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3):
- dependencies:
- '@cspotcode/source-map-support': 0.8.1
- '@tsconfig/node10': 1.0.11
- '@tsconfig/node12': 1.0.11
- '@tsconfig/node14': 1.0.3
- '@tsconfig/node16': 1.0.4
- '@types/node': 18.19.86
- acorn: 8.11.3
- acorn-walk: 8.3.2
- arg: 4.1.3
- create-require: 1.1.1
- diff: 4.0.2
- make-error: 1.3.6
- typescript: 5.8.3
- v8-compile-cache-lib: 3.0.1
- yn: 3.1.1
-
- tsup@7.2.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))(typescript@5.8.3):
- dependencies:
- bundle-require: 4.2.1(esbuild@0.18.20)
+ tsup@8.5.0(postcss@8.5.6)(typescript@5.9.2)(yaml@2.4.5):
+ dependencies:
+ bundle-require: 5.1.0(esbuild@0.25.8)
cac: 6.7.14
- chokidar: 3.6.0
- debug: 4.3.5
- esbuild: 0.18.20
- execa: 5.1.1
- globby: 11.1.0
+ chokidar: 4.0.3
+ consola: 3.4.2
+ debug: 4.4.1
+ esbuild: 0.25.8
+ fix-dts-default-cjs-exports: 1.0.1
joycon: 3.1.1
- postcss-load-config: 4.0.2(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.3))
+ picocolors: 1.1.1
+ postcss-load-config: 6.0.1(postcss@8.5.6)(yaml@2.4.5)
resolve-from: 5.0.0
- rollup: 3.29.5
+ rollup: 4.46.2
source-map: 0.8.0-beta.0
sucrase: 3.35.0
+ tinyexec: 0.3.2
+ tinyglobby: 0.2.14
tree-kill: 1.2.2
optionalDependencies:
- typescript: 5.8.3
+ postcss: 8.5.6
+ typescript: 5.9.2
transitivePeerDependencies:
+ - jiti
- supports-color
- - ts-node
+ - tsx
+ - yaml
- type-detect@4.0.8: {}
+ type-detect@4.1.0: {}
- type-fest@0.21.3: {}
+ typescript@5.9.2: {}
- type-fest@4.41.0: {}
+ ufo@1.6.1: {}
- typescript@5.8.3: {}
+ undici-types@6.21.0: {}
- undici-types@5.26.5: {}
+ undici@6.21.3: {}
- update-browserslist-db@1.0.16(browserslist@4.23.1):
- dependencies:
- browserslist: 4.23.1
- escalade: 3.1.2
- picocolors: 1.0.1
+ universal-user-agent@6.0.1: {}
- v8-compile-cache-lib@3.0.1: {}
+ url-join@5.0.0: {}
- v8-to-istanbul@9.2.0:
- dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- '@types/istanbul-lib-coverage': 2.0.6
- convert-source-map: 2.0.0
+ validate-npm-package-name@5.0.1: {}
- walker@1.0.8:
+ vite-node@3.2.4(@types/node@22.17.2)(yaml@2.4.5):
dependencies:
- makeerror: 1.0.12
+ cac: 6.7.14
+ debug: 4.4.1
+ es-module-lexer: 1.7.0
+ pathe: 2.0.3
+ vite: 7.1.1(@types/node@22.17.2)(yaml@2.4.5)
+ transitivePeerDependencies:
+ - '@types/node'
+ - jiti
+ - less
+ - lightningcss
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - yaml
+
+ vite@7.1.1(@types/node@22.17.2)(yaml@2.4.5):
+ dependencies:
+ esbuild: 0.25.8
+ fdir: 6.4.6(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.6
+ rollup: 4.46.2
+ tinyglobby: 0.2.14
+ optionalDependencies:
+ '@types/node': 22.17.2
+ fsevents: 2.3.3
+ yaml: 2.4.5
- webidl-conversions@3.0.1: {}
+ vitest-fetch-mock@0.4.5(vitest@3.2.4(@types/node@22.17.2)(yaml@2.4.5)):
+ dependencies:
+ vitest: 3.2.4(@types/node@22.17.2)(yaml@2.4.5)
+
+ vitest@3.2.4(@types/node@22.17.2)(yaml@2.4.5):
+ dependencies:
+ '@types/chai': 5.2.2
+ '@vitest/expect': 3.2.4
+ '@vitest/mocker': 3.2.4(vite@7.1.1(@types/node@22.17.2)(yaml@2.4.5))
+ '@vitest/pretty-format': 3.2.4
+ '@vitest/runner': 3.2.4
+ '@vitest/snapshot': 3.2.4
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
+ chai: 5.2.1
+ debug: 4.4.1
+ expect-type: 1.2.2
+ magic-string: 0.30.17
+ pathe: 2.0.3
+ picomatch: 4.0.3
+ std-env: 3.9.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.2
+ tinyglobby: 0.2.14
+ tinypool: 1.1.1
+ tinyrainbow: 2.0.0
+ vite: 7.1.1(@types/node@22.17.2)(yaml@2.4.5)
+ vite-node: 3.2.4(@types/node@22.17.2)(yaml@2.4.5)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 22.17.2
+ transitivePeerDependencies:
+ - jiti
+ - less
+ - lightningcss
+ - msw
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - yaml
webidl-conversions@4.0.2: {}
- whatwg-url@5.0.0:
- dependencies:
- tr46: 0.0.3
- webidl-conversions: 3.0.1
-
whatwg-url@7.1.0:
dependencies:
lodash.sortby: 4.7.0
@@ -3822,6 +2111,11 @@ snapshots:
dependencies:
isexe: 2.0.0
+ why-is-node-running@2.3.0:
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
@@ -3836,29 +2130,11 @@ snapshots:
wrappy@1.0.2: {}
- write-file-atomic@4.0.2:
- dependencies:
- imurmurhash: 0.1.4
- signal-exit: 3.0.7
-
- y18n@5.0.8: {}
-
- yallist@3.1.1: {}
-
- yaml@2.4.5: {}
-
- yargs-parser@21.1.1: {}
+ yaml@2.4.5:
+ optional: true
- yargs@17.7.2:
+ zod-package-json@1.2.0:
dependencies:
- cliui: 8.0.1
- escalade: 3.1.2
- get-caller-file: 2.0.5
- require-directory: 2.1.1
- string-width: 4.2.3
- y18n: 5.0.8
- yargs-parser: 21.1.1
-
- yn@3.1.1: {}
+ zod: 3.25.76
- yocto-queue@0.1.0: {}
+ zod@3.25.76: {}
diff --git a/readme.md b/readme.md
index 146e3d16..e65cda10 100644
--- a/readme.md
+++ b/readme.md
@@ -55,13 +55,15 @@ const resend = new Resend('re_xxxx...xxxxxx');
Send your first email:
```js
-await resend.emails.send({
+const { data } = await resend.emails.send({
from: 'you@example.com',
to: 'user@gmail.com',
replyTo: 'you@example.com',
subject: 'hello world',
text: 'it works!',
});
+
+console.log(`Email ${data.id} has been sent`);
```
> [!NOTE]
@@ -72,13 +74,15 @@ await resend.emails.send({
Send an email custom HTML content:
```js
-await resend.emails.send({
+const { data } = await resend.emails.send({
from: 'you@example.com',
to: 'user@gmail.com',
replyTo: 'you@example.com',
subject: 'hello world',
html: 'it works!',
});
+
+console.log(`Emaill ${data.id} with customer HTML content has been sent.`);
```
## Send email using React
@@ -103,17 +107,19 @@ Then import the template component and pass it to the `react` property.
```jsx
import EmailTemplate from '../components/EmailTemplate';
-await resend.emails.send({
+const { data } = await resend.emails.send({
from: 'you@example.com',
to: 'user@gmail.com',
replyTo: 'you@example.com',
subject: 'hello world',
react: ,
});
+
+console.log(`Email ${data.id} with a React template has been sent`);
```
> [!NOTE]
-> If your endpoint is a JS/TS file, render the template (i.e., pass `EmailTemplate({firstName="John", product="MyApp"})` instead of the component).
+> If your endpoint is a JS/TS file, render the template (i.e., pass `EmailTemplate({ firstName: "John", product: "MyApp" })` instead of the component).
## License
diff --git a/src/api-keys/api-keys.spec.ts b/src/api-keys/api-keys.spec.ts
index ad9f30f5..7764f2bf 100644
--- a/src/api-keys/api-keys.spec.ts
+++ b/src/api-keys/api-keys.spec.ts
@@ -1,6 +1,9 @@
-import { enableFetchMocks } from 'jest-fetch-mock';
import type { ErrorResponse } from '../interfaces';
import { Resend } from '../resend';
+import {
+ mockErrorResponse,
+ mockSuccessResponse,
+} from '../test-utils/mock-fetch';
import type {
CreateApiKeyOptions,
CreateApiKeyResponseSuccess,
@@ -8,11 +11,7 @@ import type {
import type { ListApiKeysResponseSuccess } from './interfaces/list-api-keys.interface';
import type { RemoveApiKeyResponseSuccess } from './interfaces/remove-api-keys.interface';
-enableFetchMocks();
-
describe('API Keys', () => {
- afterEach(() => fetchMock.resetMocks());
-
describe('create', () => {
it('creates an api key', async () => {
const payload: CreateApiKeyOptions = {
@@ -23,12 +22,8 @@ describe('API Keys', () => {
id: '430eed87-632a-4ea6-90db-0aace67ec228',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 201,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -42,6 +37,11 @@ describe('API Keys', () => {
"token": "re_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -55,12 +55,8 @@ describe('API Keys', () => {
name: 'validation_error',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -74,6 +70,11 @@ describe('API Keys', () => {
"message": "String must contain at least 1 character(s)",
"name": "validation_error",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -90,12 +91,8 @@ describe('API Keys', () => {
id: '430eed87-632a-4ea6-90db-0aace67ec228',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 201,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -109,6 +106,11 @@ describe('API Keys', () => {
"token": "re_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -123,12 +125,8 @@ describe('API Keys', () => {
id: '430eed87-632a-4ea6-90db-0aace67ec228',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 201,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -142,6 +140,11 @@ describe('API Keys', () => {
"token": "re_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -152,12 +155,8 @@ describe('API Keys', () => {
message: 'Access must be "full_access" | "sending_access"',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -176,6 +175,11 @@ describe('API Keys', () => {
"message": "Access must be "full_access" | "sending_access"",
"name": "invalid_access",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -271,12 +275,8 @@ describe('API Keys', () => {
created_at: '2023-04-06T23:09:49.093947+00:00',
},
];
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -296,6 +296,11 @@ describe('API Keys', () => {
},
],
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -306,12 +311,8 @@ describe('API Keys', () => {
const response: RemoveApiKeyResponseSuccess = {};
it('removes an api key', async () => {
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -320,6 +321,11 @@ describe('API Keys', () => {
{
"data": {},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -330,12 +336,8 @@ describe('API Keys', () => {
message: 'Something went wrong',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 500,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -349,6 +351,11 @@ describe('API Keys', () => {
"message": "Something went wrong",
"name": "application_error",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -359,12 +366,8 @@ describe('API Keys', () => {
message: 'API key not found',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 404,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -380,6 +383,11 @@ describe('API Keys', () => {
"message": "API key not found",
"name": "not_found",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
diff --git a/src/api-keys/interfaces/create-api-key-options.interface.ts b/src/api-keys/interfaces/create-api-key-options.interface.ts
index 628600a8..59274575 100644
--- a/src/api-keys/interfaces/create-api-key-options.interface.ts
+++ b/src/api-keys/interfaces/create-api-key-options.interface.ts
@@ -1,5 +1,5 @@
import type { PostOptions } from '../../common/interfaces';
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
export interface CreateApiKeyOptions {
name: string;
@@ -14,12 +14,4 @@ export interface CreateApiKeyResponseSuccess {
id: string;
}
-export type CreateApiKeyResponse =
- | {
- data: CreateApiKeyResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type CreateApiKeyResponse = Response;
diff --git a/src/api-keys/interfaces/list-api-keys.interface.ts b/src/api-keys/interfaces/list-api-keys.interface.ts
index 59a14b79..a4696d5a 100644
--- a/src/api-keys/interfaces/list-api-keys.interface.ts
+++ b/src/api-keys/interfaces/list-api-keys.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { ApiKey } from './api-key';
export type ListApiKeysResponseSuccess = Pick<
@@ -6,12 +6,4 @@ export type ListApiKeysResponseSuccess = Pick<
'name' | 'id' | 'created_at'
>[];
-export type ListApiKeysResponse =
- | {
- data: ListApiKeysResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type ListApiKeysResponse = Response;
diff --git a/src/api-keys/interfaces/remove-api-keys.interface.ts b/src/api-keys/interfaces/remove-api-keys.interface.ts
index c299238b..3b6b77dc 100644
--- a/src/api-keys/interfaces/remove-api-keys.interface.ts
+++ b/src/api-keys/interfaces/remove-api-keys.interface.ts
@@ -1,14 +1,6 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
-// biome-ignore lint/complexity/noBannedTypes:
+// biome-ignore lint/complexity/noBannedTypes: allow empty types
export type RemoveApiKeyResponseSuccess = {};
-export type RemoveApiKeyResponse =
- | {
- data: RemoveApiKeyResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type RemoveApiKeyResponse = Response;
diff --git a/src/audiences/audiences.spec.ts b/src/audiences/audiences.spec.ts
index cf42f416..f548e0fe 100644
--- a/src/audiences/audiences.spec.ts
+++ b/src/audiences/audiences.spec.ts
@@ -1,6 +1,9 @@
-import { enableFetchMocks } from 'jest-fetch-mock';
import type { ErrorResponse } from '../interfaces';
import { Resend } from '../resend';
+import {
+ mockErrorResponse,
+ mockSuccessResponse,
+} from '../test-utils/mock-fetch';
import type {
CreateAudienceOptions,
CreateAudienceResponseSuccess,
@@ -9,8 +12,6 @@ import type { GetAudienceResponseSuccess } from './interfaces/get-audience.inter
import type { ListAudiencesResponseSuccess } from './interfaces/list-audiences.interface';
import type { RemoveAudiencesResponseSuccess } from './interfaces/remove-audience.interface';
-enableFetchMocks();
-
describe('Audiences', () => {
afterEach(() => fetchMock.resetMocks());
@@ -23,12 +24,8 @@ describe('Audiences', () => {
object: 'audience',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -42,6 +39,11 @@ describe('Audiences', () => {
"object": "audience",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -53,12 +55,8 @@ describe('Audiences', () => {
message: 'Missing "name" field',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -72,6 +70,11 @@ describe('Audiences', () => {
"message": "Missing "name" field",
"name": "missing_required_field",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -94,12 +97,8 @@ describe('Audiences', () => {
},
],
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -122,6 +121,11 @@ describe('Audiences', () => {
"object": "list",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -135,12 +139,8 @@ describe('Audiences', () => {
message: 'Audience not found',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 404,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -154,6 +154,11 @@ describe('Audiences', () => {
"message": "Audience not found",
"name": "not_found",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -167,12 +172,8 @@ describe('Audiences', () => {
created_at: '2023-06-21T06:10:36.144Z',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -188,6 +189,11 @@ describe('Audiences', () => {
"object": "audience",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -201,12 +207,8 @@ describe('Audiences', () => {
id,
deleted: true,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -219,6 +221,11 @@ describe('Audiences', () => {
"object": "audience",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
diff --git a/src/audiences/interfaces/create-audience-options.interface.ts b/src/audiences/interfaces/create-audience-options.interface.ts
index f8775dba..4bd6ae88 100644
--- a/src/audiences/interfaces/create-audience-options.interface.ts
+++ b/src/audiences/interfaces/create-audience-options.interface.ts
@@ -1,5 +1,5 @@
import type { PostOptions } from '../../common/interfaces';
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Audience } from './audience';
export interface CreateAudienceOptions {
@@ -13,12 +13,4 @@ export interface CreateAudienceResponseSuccess
object: 'audience';
}
-export type CreateAudienceResponse =
- | {
- data: CreateAudienceResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type CreateAudienceResponse = Response;
diff --git a/src/audiences/interfaces/get-audience.interface.ts b/src/audiences/interfaces/get-audience.interface.ts
index 9c08efac..f229a6f9 100644
--- a/src/audiences/interfaces/get-audience.interface.ts
+++ b/src/audiences/interfaces/get-audience.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Audience } from './audience';
export interface GetAudienceResponseSuccess
@@ -6,12 +6,4 @@ export interface GetAudienceResponseSuccess
object: 'audience';
}
-export type GetAudienceResponse =
- | {
- data: GetAudienceResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type GetAudienceResponse = Response;
diff --git a/src/audiences/interfaces/list-audiences.interface.ts b/src/audiences/interfaces/list-audiences.interface.ts
index 86a92bc2..12e1c95f 100644
--- a/src/audiences/interfaces/list-audiences.interface.ts
+++ b/src/audiences/interfaces/list-audiences.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Audience } from './audience';
export type ListAudiencesResponseSuccess = {
@@ -6,12 +6,4 @@ export type ListAudiencesResponseSuccess = {
data: Audience[];
};
-export type ListAudiencesResponse =
- | {
- data: ListAudiencesResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type ListAudiencesResponse = Response;
diff --git a/src/audiences/interfaces/remove-audience.interface.ts b/src/audiences/interfaces/remove-audience.interface.ts
index e82e0b39..97de36a4 100644
--- a/src/audiences/interfaces/remove-audience.interface.ts
+++ b/src/audiences/interfaces/remove-audience.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Audience } from './audience';
export interface RemoveAudiencesResponseSuccess extends Pick {
@@ -6,12 +6,4 @@ export interface RemoveAudiencesResponseSuccess extends Pick {
deleted: boolean;
}
-export type RemoveAudiencesResponse =
- | {
- data: RemoveAudiencesResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type RemoveAudiencesResponse = Response;
diff --git a/src/batch/batch.spec.ts b/src/batch/batch.spec.ts
index 6fa7fecc..6fa90d89 100644
--- a/src/batch/batch.spec.ts
+++ b/src/batch/batch.spec.ts
@@ -1,11 +1,9 @@
-import { enableFetchMocks } from 'jest-fetch-mock';
import { Resend } from '../resend';
-import type {
- CreateBatchOptions,
- CreateBatchSuccessResponse,
-} from './interfaces/create-batch-options.interface';
-
-enableFetchMocks();
+import {
+ mockSuccessResponse,
+ mockSuccessWithStatusCode,
+} from '../test-utils/mock-fetch';
+import type { CreateBatchOptions } from './interfaces/create-batch-options.interface';
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -34,20 +32,20 @@ describe('Batch', () => {
html: 'Hi there
',
},
];
- const response: CreateBatchSuccessResponse = {
- data: [
- { id: 'aabeeefc-bd13-474a-a440-0ee139b3a4cc' },
- { id: 'aebe1c6e-30ad-4257-993b-519f5affa626' },
- { id: 'b2bc2598-f98b-4da4-86c9-7b32881ef394' },
- ],
- };
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
+ mockSuccessResponse(
+ {
+ data: [
+ { id: 'aabeeefc-bd13-474a-a440-0ee139b3a4cc' },
+ { id: 'aebe1c6e-30ad-4257-993b-519f5affa626' },
+ { id: 'b2bc2598-f98b-4da4-86c9-7b32881ef394' },
+ ],
},
- });
+ {
+ headers: {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
+ },
+ },
+ );
const data = await resend.batch.create(payload);
expect(data).toMatchInlineSnapshot(`
@@ -66,26 +64,30 @@ describe('Batch', () => {
],
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
it('does not send the Idempotency-Key header when idempotencyKey is not provided', async () => {
- const response: CreateBatchSuccessResponse = {
- data: [
- {
- id: 'not-idempotent-123',
+ mockSuccessResponse(
+ {
+ data: [
+ {
+ id: 'not-idempotent-123',
+ },
+ ],
+ },
+ {
+ headers: {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
- ],
- };
-
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
- });
+ );
const payload: CreateBatchOptions = [
{
@@ -102,31 +104,28 @@ describe('Batch', () => {
const lastCall = fetchMock.mock.calls[0];
expect(lastCall).toBeDefined();
- //@ts-ignore
- const hasIdempotencyKey = lastCall[1]?.headers.has('Idempotency-Key');
- expect(hasIdempotencyKey).toBeFalsy();
+ const request = lastCall[1];
+ expect(request).toBeDefined();
- //@ts-ignore
- const usedIdempotencyKey = lastCall[1]?.headers.get('Idempotency-Key');
- expect(usedIdempotencyKey).toBeNull();
+ const headers = new Headers(request?.headers);
+ expect(headers.has('Idempotency-Key')).toBeFalsy();
});
it('sends the Idempotency-Key header when idempotencyKey is provided', async () => {
- const response: CreateBatchSuccessResponse = {
- data: [
- {
- id: 'idempotent-123',
+ mockSuccessResponse(
+ {
+ data: [
+ {
+ id: 'idempotent-123',
+ },
+ ],
+ },
+ {
+ headers: {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
- ],
- };
-
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
- });
+ );
const payload: CreateBatchOptions = [
{
@@ -148,11 +147,11 @@ describe('Batch', () => {
// In the mock, headers is an object with key-value pairs
expect(fetchMock.mock.calls[0][1]?.headers).toBeDefined();
- //@ts-ignore
+ //@ts-expect-error
const hasIdempotencyKey = lastCall[1]?.headers.has('Idempotency-Key');
expect(hasIdempotencyKey).toBeTruthy();
- //@ts-ignore
+ //@ts-expect-error
const usedIdempotencyKey = lastCall[1]?.headers.get('Idempotency-Key');
expect(usedIdempotencyKey).toBe(idempotencyKey);
});
@@ -180,21 +179,21 @@ describe('Batch', () => {
html: 'Hi there
',
},
];
- const response: CreateBatchSuccessResponse = {
- data: [
- { id: 'aabeeefc-bd13-474a-a440-0ee139b3a4cc' },
- { id: 'aebe1c6e-30ad-4257-993b-519f5affa626' },
- { id: 'b2bc2598-f98b-4da4-86c9-7b32881ef394' },
- ],
- };
-
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
+
+ mockSuccessResponse(
+ {
+ data: [
+ { id: 'aabeeefc-bd13-474a-a440-0ee139b3a4cc' },
+ { id: 'aebe1c6e-30ad-4257-993b-519f5affa626' },
+ { id: 'b2bc2598-f98b-4da4-86c9-7b32881ef394' },
+ ],
},
- });
+ {
+ headers: {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
+ },
+ },
+ );
const data = await resend.batch.send(payload);
expect(data).toMatchInlineSnapshot(`
@@ -213,26 +212,30 @@ describe('Batch', () => {
],
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
it('does not send the Idempotency-Key header when idempotencyKey is not provided', async () => {
- const response: CreateBatchSuccessResponse = {
- data: [
- {
- id: 'not-idempotent-123',
+ mockSuccessResponse(
+ {
+ data: [
+ {
+ id: 'not-idempotent-123',
+ },
+ ],
+ },
+ {
+ headers: {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
- ],
- };
-
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
- });
+ );
const payload: CreateBatchOptions = [
{
@@ -248,32 +251,27 @@ describe('Batch', () => {
// Inspect the last fetch call and body
const lastCall = fetchMock.mock.calls[0];
expect(lastCall).toBeDefined();
-
- //@ts-ignore
- const hasIdempotencyKey = lastCall[1]?.headers.has('Idempotency-Key');
- expect(hasIdempotencyKey).toBeFalsy();
-
- //@ts-ignore
- const usedIdempotencyKey = lastCall[1]?.headers.get('Idempotency-Key');
- expect(usedIdempotencyKey).toBeNull();
+ const request = lastCall[1];
+ expect(request).toBeDefined();
+ const headers = new Headers(request?.headers);
+ expect(headers.has('Idempotency-Key')).toBe(false);
});
it('sends the Idempotency-Key header when idempotencyKey is provided', async () => {
- const response: CreateBatchSuccessResponse = {
- data: [
- {
- id: 'idempotent-123',
+ mockSuccessResponse(
+ {
+ data: [
+ {
+ id: 'idempotent-123',
+ },
+ ],
+ },
+ {
+ headers: {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
- ],
- };
-
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
- });
+ );
const payload: CreateBatchOptions = [
{
@@ -290,18 +288,91 @@ describe('Batch', () => {
// Inspect the last fetch call and body
const lastCall = fetchMock.mock.calls[0];
expect(lastCall).toBeDefined();
+ const headers = new Headers(lastCall[1]?.headers);
+ expect(headers.has('Idempotency-Key')).toBeTruthy();
+ expect(headers.get('Idempotency-Key')).toBe(idempotencyKey);
+ });
+
+ it('handles batch response with errors field when permissive option is set', async () => {
+ mockSuccessWithStatusCode(
+ {
+ data: [],
+ errors: [{ index: 2, message: 'Invalid email address' }],
+ },
+ 202,
+ {
+ headers: {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
+ },
+ },
+ );
+
+ const payload: CreateBatchOptions = [];
+
+ const result = await resend.batch.create(payload, {
+ batchValidation: 'permissive',
+ });
+
+ // Verify the header was passed correctly
+ const lastCall = fetchMock.mock.calls[0];
+ expect(lastCall).toBeDefined();
+ const request = lastCall[1];
+ expect(request).toBeDefined();
+ const headers = new Headers(request?.headers);
+ expect(headers.get('x-resend-batch-validation')).toBe('permissive');
+
+ expect(result.data).toEqual({
+ data: [],
+ errors: [{ index: 2, message: 'Invalid email address' }],
+ });
+ expect(result.error).toBeNull();
+ });
- // Check if headers contains Idempotency-Key
- // In the mock, headers is an object with key-value pairs
- expect(fetchMock.mock.calls[0][1]?.headers).toBeDefined();
+ it('removes errors field when permissive header is not set (backward compatibility)', async () => {
+ mockSuccessResponse(
+ {
+ data: [
+ { id: 'success-email-1' },
+ { id: 'success-email-2' },
+ { id: 'success-email-3' },
+ ],
+ },
+ {
+ headers: {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
+ },
+ },
+ );
- //@ts-ignore
- const hasIdempotencyKey = lastCall[1]?.headers.has('Idempotency-Key');
- expect(hasIdempotencyKey).toBeTruthy();
+ const payload: CreateBatchOptions = [
+ {
+ from: 'admin@resend.com',
+ to: 'user1@example.com',
+ subject: 'Test 1',
+ html: 'Test 1
',
+ },
+ {
+ from: 'admin@resend.com',
+ to: 'user2@example.com',
+ subject: 'Test 2',
+ html: 'Test 2
',
+ },
+ {
+ from: 'admin@resend.com',
+ to: 'invalid-email',
+ subject: 'Test 3',
+ html: 'Test 3
',
+ },
+ ];
- //@ts-ignore
- const usedIdempotencyKey = lastCall[1]?.headers.get('Idempotency-Key');
- expect(usedIdempotencyKey).toBe(idempotencyKey);
+ const response = await resend.batch.create(payload);
+ // Should not have errors field for backward compatibility
+ expect(response.data).not.toHaveProperty('errors');
+ expect(response.data?.data).toEqual([
+ { id: 'success-email-1' },
+ { id: 'success-email-2' },
+ { id: 'success-email-3' },
+ ]);
});
});
});
diff --git a/src/batch/batch.ts b/src/batch/batch.ts
index 18829170..908934b5 100644
--- a/src/batch/batch.ts
+++ b/src/batch/batch.ts
@@ -1,4 +1,3 @@
-import type * as React from 'react';
import type { EmailApiOptions } from '../common/interfaces/email-api-options.interface';
import { parseEmailToApiOptions } from '../common/utils/parse-email-to-api-options';
import type { Resend } from '../resend';
@@ -13,17 +12,17 @@ export class Batch {
private renderAsync?: (component: React.ReactElement) => Promise;
constructor(private readonly resend: Resend) {}
- async send(
+ async send(
payload: CreateBatchOptions,
- options: CreateBatchRequestOptions = {},
- ): Promise {
+ options?: Options,
+ ): Promise> {
return this.create(payload, options);
}
- async create(
+ async create(
payload: CreateBatchOptions,
- options: CreateBatchRequestOptions = {},
- ): Promise {
+ options?: Options,
+ ): Promise> {
const emails: EmailApiOptions[] = [];
for (const email of payload) {
@@ -32,7 +31,7 @@ export class Batch {
try {
const { renderAsync } = await import('@react-email/render');
this.renderAsync = renderAsync;
- } catch (error) {
+ } catch {
throw new Error(
'Failed to render React component. Make sure to install `@react-email/render`',
);
@@ -46,10 +45,16 @@ export class Batch {
emails.push(parseEmailToApiOptions(email));
}
- const data = await this.resend.post(
+ const data = await this.resend.post>(
'/emails/batch',
emails,
- options,
+ {
+ ...options,
+ headers: {
+ 'x-resend-batch-validation': options?.batchValidation ?? 'strict',
+ ...options?.headers,
+ },
+ },
);
return data;
diff --git a/src/batch/interfaces/create-batch-options.interface.ts b/src/batch/interfaces/create-batch-options.interface.ts
index d19dbe1c..9a9946db 100644
--- a/src/batch/interfaces/create-batch-options.interface.ts
+++ b/src/batch/interfaces/create-batch-options.interface.ts
@@ -1,27 +1,43 @@
import type { PostOptions } from '../../common/interfaces';
import type { IdempotentRequest } from '../../common/interfaces/idempotent-request.interface';
import type { CreateEmailOptions } from '../../emails/interfaces/create-email-options.interface';
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
export type CreateBatchOptions = CreateEmailOptions[];
export interface CreateBatchRequestOptions
extends PostOptions,
- IdempotentRequest {}
+ IdempotentRequest {
+ /**
+ * @default 'strict'
+ */
+ batchValidation?: 'strict' | 'permissive';
+}
-export interface CreateBatchSuccessResponse {
+export type CreateBatchSuccessResponse<
+ Options extends CreateBatchRequestOptions = CreateBatchRequestOptions,
+> = {
data: {
/** The ID of the newly created email. */
id: string;
}[];
-}
-
-export type CreateBatchResponse =
- | {
- data: CreateBatchSuccessResponse;
- error: null;
+} & (Options['batchValidation'] extends 'permissive'
+ ? {
+ /**
+ * Only present when header "x-resend-batch-validation" is set to 'permissive'.
+ */
+ errors: {
+ /**
+ * The index of the failed email in the batch
+ */
+ index: number;
+ /**
+ * The error message for the failed email
+ */
+ message: string;
+ }[]; // This always being an array depends on us doing https://github.com/resend/resend-api/pull/2025/files#r2303897690
}
- | {
- data: null;
- error: ErrorResponse;
- };
+ : Record);
+
+export type CreateBatchResponse =
+ Response>;
diff --git a/src/broadcasts/broadcasts.spec.ts b/src/broadcasts/broadcasts.spec.ts
index 5c6a2310..c7fb0d61 100644
--- a/src/broadcasts/broadcasts.spec.ts
+++ b/src/broadcasts/broadcasts.spec.ts
@@ -1,6 +1,10 @@
-import { enableFetchMocks } from 'jest-fetch-mock';
import type { ErrorResponse } from '../interfaces';
import { Resend } from '../resend';
+import {
+ mockErrorResponse,
+ mockFetchWithRateLimit,
+ mockSuccessResponse,
+} from '../test-utils/mock-fetch';
import type {
CreateBroadcastOptions,
CreateBroadcastResponseSuccess,
@@ -10,8 +14,6 @@ import type { ListBroadcastsResponseSuccess } from './interfaces/list-broadcasts
import type { RemoveBroadcastResponseSuccess } from './interfaces/remove-broadcast.interface';
import type { UpdateBroadcastResponseSuccess } from './interfaces/update-broadcast.interface';
-enableFetchMocks();
-
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
describe('Broadcasts', () => {
@@ -24,10 +26,8 @@ describe('Broadcasts', () => {
message: 'Missing `from` field.',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
+ mockErrorResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -40,6 +40,11 @@ describe('Broadcasts', () => {
"message": "Missing \`from\` field.",
"name": "missing_required_field",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -48,10 +53,8 @@ describe('Broadcasts', () => {
const response: CreateBroadcastResponseSuccess = {
id: '71cdfe68-cf79-473a-a9d7-21f91db6a526',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
+ mockSuccessResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -70,6 +73,11 @@ describe('Broadcasts', () => {
"id": "71cdfe68-cf79-473a-a9d7-21f91db6a526",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -79,12 +87,8 @@ describe('Broadcasts', () => {
id: '124dc0f1-e36c-417c-a65c-e33773abc768',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateBroadcastOptions = {
@@ -100,6 +104,11 @@ describe('Broadcasts', () => {
"id": "124dc0f1-e36c-417c-a65c-e33773abc768",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -109,12 +118,8 @@ describe('Broadcasts', () => {
id: '124dc0f1-e36c-417c-a65c-e33773abc768',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateBroadcastOptions = {
@@ -132,6 +137,11 @@ describe('Broadcasts', () => {
"id": "124dc0f1-e36c-417c-a65c-e33773abc768",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -143,12 +153,8 @@ describe('Broadcasts', () => {
'Invalid `from` field. The email address needs to follow the `email@example.com` or `Name ` format',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateBroadcastOptions = {
@@ -162,14 +168,19 @@ describe('Broadcasts', () => {
const result = resend.broadcasts.create(payload);
await expect(result).resolves.toMatchInlineSnapshot(`
- {
- "data": null,
- "error": {
- "message": "Invalid \`from\` field. The email address needs to follow the \`email@example.com\` or \`Name \` format",
- "name": "invalid_parameter",
- },
- }
- `);
+{
+ "data": null,
+ "error": {
+ "message": "Invalid \`from\` field. The email address needs to follow the \`email@example.com\` or \`Name \` format",
+ "name": "invalid_parameter",
+ },
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
+}
+`);
});
it('returns an error when fetch fails', async () => {
@@ -199,7 +210,7 @@ describe('Broadcasts', () => {
});
it('returns an error when api responds with text payload', async () => {
- fetchMock.mockOnce('local_rate_limited', {
+ mockFetchWithRateLimit('local_rate_limited', {
status: 422,
headers: {
Authorization: 'Bearer re_924b3rjh2387fbewf823',
@@ -233,10 +244,8 @@ describe('Broadcasts', () => {
id: randomBroadcastId,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
+ mockSuccessResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -249,6 +258,11 @@ describe('Broadcasts', () => {
"id": "b01e0de9-7c27-4a53-bf38-2e3f98389a65",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -279,12 +293,8 @@ describe('Broadcasts', () => {
},
],
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -315,6 +325,11 @@ describe('Broadcasts', () => {
"object": "list",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -328,12 +343,8 @@ describe('Broadcasts', () => {
message: 'Broadcast not found',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 404,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -349,6 +360,11 @@ describe('Broadcasts', () => {
"message": "Broadcast not found",
"name": "not_found",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -370,12 +386,8 @@ describe('Broadcasts', () => {
sent_at: null,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -399,6 +411,11 @@ describe('Broadcasts', () => {
"subject": "hello world",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -412,12 +429,8 @@ describe('Broadcasts', () => {
id,
deleted: true,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -432,6 +445,11 @@ describe('Broadcasts', () => {
"object": "broadcast",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -441,12 +459,8 @@ describe('Broadcasts', () => {
it('updates a broadcast', async () => {
const id = 'b01e0de9-7c27-4a53-bf38-2e3f98389a65';
const response: UpdateBroadcastResponseSuccess = { id };
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -459,6 +473,11 @@ describe('Broadcasts', () => {
"id": "b01e0de9-7c27-4a53-bf38-2e3f98389a65",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
diff --git a/src/broadcasts/broadcasts.ts b/src/broadcasts/broadcasts.ts
index 90323b06..6c308992 100644
--- a/src/broadcasts/broadcasts.ts
+++ b/src/broadcasts/broadcasts.ts
@@ -40,7 +40,7 @@ export class Broadcasts {
try {
const { renderAsync } = await import('@react-email/render');
this.renderAsync = renderAsync;
- } catch (error) {
+ } catch {
throw new Error(
'Failed to render React component. Make sure to install `@react-email/render`',
);
@@ -106,6 +106,23 @@ export class Broadcasts {
id: string,
payload: UpdateBroadcastOptions,
): Promise {
+ if (payload.react) {
+ if (!this.renderAsync) {
+ try {
+ const { renderAsync } = await import('@react-email/render');
+ this.renderAsync = renderAsync;
+ } catch {
+ throw new Error(
+ 'Failed to render React component. Make sure to install `@react-email/render`',
+ );
+ }
+ }
+
+ payload.html = await this.renderAsync(
+ payload.react as React.ReactElement,
+ );
+ }
+
const data = await this.resend.patch(
`/broadcasts/${id}`,
{
diff --git a/src/broadcasts/interfaces/create-broadcast-options.interface.ts b/src/broadcasts/interfaces/create-broadcast-options.interface.ts
index 69d6940b..6b36357d 100644
--- a/src/broadcasts/interfaces/create-broadcast-options.interface.ts
+++ b/src/broadcasts/interfaces/create-broadcast-options.interface.ts
@@ -1,7 +1,7 @@
import type * as React from 'react';
import type { PostOptions } from '../../common/interfaces';
import type { RequireAtLeastOne } from '../../common/interfaces/require-at-least-one';
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
interface EmailRenderOptions {
/**
@@ -73,12 +73,4 @@ export interface CreateBroadcastResponseSuccess {
id: string;
}
-export type CreateBroadcastResponse =
- | {
- data: CreateBroadcastResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type CreateBroadcastResponse = Response;
diff --git a/src/broadcasts/interfaces/get-broadcast.interface.ts b/src/broadcasts/interfaces/get-broadcast.interface.ts
index 2b7b2ac0..e456f200 100644
--- a/src/broadcasts/interfaces/get-broadcast.interface.ts
+++ b/src/broadcasts/interfaces/get-broadcast.interface.ts
@@ -1,16 +1,8 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Broadcast } from './broadcast';
export interface GetBroadcastResponseSuccess extends Broadcast {
object: 'broadcast';
}
-export type GetBroadcastResponse =
- | {
- data: GetBroadcastResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type GetBroadcastResponse = Response;
diff --git a/src/broadcasts/interfaces/list-broadcasts.interface.ts b/src/broadcasts/interfaces/list-broadcasts.interface.ts
index fd91e66b..575a756b 100644
--- a/src/broadcasts/interfaces/list-broadcasts.interface.ts
+++ b/src/broadcasts/interfaces/list-broadcasts.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Broadcast } from './broadcast';
export type ListBroadcastsResponseSuccess = {
@@ -15,12 +15,4 @@ export type ListBroadcastsResponseSuccess = {
>[];
};
-export type ListBroadcastsResponse =
- | {
- data: ListBroadcastsResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type ListBroadcastsResponse = Response;
diff --git a/src/broadcasts/interfaces/remove-broadcast.interface.ts b/src/broadcasts/interfaces/remove-broadcast.interface.ts
index 438b4884..1b45e8ce 100644
--- a/src/broadcasts/interfaces/remove-broadcast.interface.ts
+++ b/src/broadcasts/interfaces/remove-broadcast.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Broadcast } from './broadcast';
export interface RemoveBroadcastResponseSuccess extends Pick {
@@ -6,12 +6,4 @@ export interface RemoveBroadcastResponseSuccess extends Pick {
deleted: boolean;
}
-export type RemoveBroadcastResponse =
- | {
- data: RemoveBroadcastResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type RemoveBroadcastResponse = Response;
diff --git a/src/broadcasts/interfaces/send-broadcast-options.interface.ts b/src/broadcasts/interfaces/send-broadcast-options.interface.ts
index 75f79393..1d92a6ae 100644
--- a/src/broadcasts/interfaces/send-broadcast-options.interface.ts
+++ b/src/broadcasts/interfaces/send-broadcast-options.interface.ts
@@ -1,5 +1,5 @@
import type { PostOptions } from '../../common/interfaces';
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
interface SendBroadcastBaseOptions {
/**
@@ -21,12 +21,4 @@ export interface SendBroadcastResponseSuccess {
id: string;
}
-export type SendBroadcastResponse =
- | {
- data: SendBroadcastResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type SendBroadcastResponse = Response;
diff --git a/src/broadcasts/interfaces/update-broadcast.interface.ts b/src/broadcasts/interfaces/update-broadcast.interface.ts
index e458dce2..644be559 100644
--- a/src/broadcasts/interfaces/update-broadcast.interface.ts
+++ b/src/broadcasts/interfaces/update-broadcast.interface.ts
@@ -1,26 +1,19 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
export interface UpdateBroadcastResponseSuccess {
id: string;
}
-export interface UpdateBroadcastOptions {
+export type UpdateBroadcastOptions = {
name?: string;
audienceId?: string;
from?: string;
html?: string;
+ react?: React.ReactNode;
text?: string;
subject?: string;
replyTo?: string[];
previewText?: string;
-}
+};
-export type UpdateBroadcastResponse =
- | {
- data: UpdateBroadcastResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type UpdateBroadcastResponse = Response;
diff --git a/src/common/interfaces/get-option.interface.ts b/src/common/interfaces/get-option.interface.ts
index ded97ff8..78814b2f 100644
--- a/src/common/interfaces/get-option.interface.ts
+++ b/src/common/interfaces/get-option.interface.ts
@@ -1,3 +1,4 @@
export interface GetOptions {
query?: Record;
+ headers?: HeadersInit;
}
diff --git a/src/common/interfaces/patch-option.interface.ts b/src/common/interfaces/patch-option.interface.ts
index 0a40d192..2a21c3db 100644
--- a/src/common/interfaces/patch-option.interface.ts
+++ b/src/common/interfaces/patch-option.interface.ts
@@ -1,3 +1,4 @@
export interface PatchOptions {
query?: { [key: string]: unknown };
+ headers?: HeadersInit;
}
diff --git a/src/common/interfaces/post-option.interface.ts b/src/common/interfaces/post-option.interface.ts
index 2508405b..e56e6762 100644
--- a/src/common/interfaces/post-option.interface.ts
+++ b/src/common/interfaces/post-option.interface.ts
@@ -1,3 +1,4 @@
export interface PostOptions {
query?: { [key: string]: unknown };
+ headers?: HeadersInit;
}
diff --git a/src/common/interfaces/put-option.interface.ts b/src/common/interfaces/put-option.interface.ts
index 92b87a92..506d348e 100644
--- a/src/common/interfaces/put-option.interface.ts
+++ b/src/common/interfaces/put-option.interface.ts
@@ -1,3 +1,4 @@
export interface PutOptions {
query?: { [key: string]: unknown };
+ headers?: HeadersInit;
}
diff --git a/src/common/pagination.spec.ts b/src/common/pagination.spec.ts
new file mode 100644
index 00000000..0fa3218f
--- /dev/null
+++ b/src/common/pagination.spec.ts
@@ -0,0 +1,471 @@
+import {
+ type PageRequestOptions,
+ type PageResponse,
+ PaginatedRequest,
+} from './pagination';
+
+type TestItem = {
+ id: string;
+ name: string;
+ created_at: string;
+};
+
+describe('PaginatedRequest', () => {
+ afterEach(() => fetchMock.resetMocks());
+
+ const createMockFetchPage = (
+ pages: Array<{ data: TestItem[]; has_more: boolean }>,
+ ) => {
+ let pageIndex = 0;
+ return vi.fn(
+ async (_options: PageRequestOptions): Promise> => {
+ const currentPage = pages[pageIndex] || { data: [], has_more: false };
+ pageIndex++;
+
+ return {
+ data: {
+ object: 'list',
+ data: currentPage.data,
+ has_more: currentPage.has_more,
+ },
+ error: null,
+ rateLimiting: {
+ limit: 10,
+ remainingRequests: 9,
+ shouldResetAfter: 60,
+ },
+ };
+ },
+ );
+ };
+
+ const testItems: TestItem[] = [
+ { id: '1', name: 'Item 1', created_at: '2023-01-01T00:00:00Z' },
+ { id: '2', name: 'Item 2', created_at: '2023-01-02T00:00:00Z' },
+ { id: '3', name: 'Item 3', created_at: '2023-01-03T00:00:00Z' },
+ { id: '4', name: 'Item 4', created_at: '2023-01-04T00:00:00Z' },
+ { id: '5', name: 'Item 5', created_at: '2023-01-05T00:00:00Z' },
+ { id: '6', name: 'Item 6', created_at: '2023-01-06T00:00:00Z' },
+ ];
+
+ describe('Promise interface', () => {
+ it('should work with async/await', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0]], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+ const result = await request;
+
+ expect(result.data.data).toEqual([testItems[0]]);
+ expect(result.error).toBeNull();
+ });
+
+ it('should work with try/catch', async () => {
+ const mockFetchPage = vi
+ .fn()
+ .mockRejectedValue(new Error('Network error'));
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+
+ try {
+ await request;
+ expect.fail('Should have thrown an error');
+ } catch (error) {
+ expect(error).toBeInstanceOf(Error);
+ expect((error as Error).message).toBe('Network error');
+ }
+ });
+
+ it('should work with try/catch/finally', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0]], has_more: false },
+ ]);
+ const finallyCallback = vi.fn();
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+
+ try {
+ const result = await request;
+ expect(result.data.data).toEqual([testItems[0]]);
+ } finally {
+ finallyCallback();
+ }
+
+ expect(finallyCallback).toHaveBeenCalled();
+ });
+
+ it('should have correct Symbol.toStringTag', () => {
+ const mockFetchPage = createMockFetchPage([]);
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+
+ expect(request[Symbol.toStringTag]).toBe('PaginatedRequest');
+ });
+ });
+
+ describe('AsyncIterable interface', () => {
+ it('should implement AsyncIterable interface', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0], testItems[1]], has_more: true },
+ { data: [testItems[2]], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 2 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(2);
+ expect(pages[0].data.data).toEqual([testItems[0], testItems[1]]);
+ expect(pages[1].data.data).toEqual([testItems[2]]);
+ });
+
+ it('should stop iteration when has_more is false', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0]], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(1);
+ expect(mockFetchPage).toHaveBeenCalledTimes(1);
+ });
+
+ it('should stop iteration when page data is empty', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0]], has_more: true },
+ { data: [], has_more: true },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(2);
+ expect(pages[1].data.data).toEqual([]);
+ });
+ });
+
+ describe('Pagination options', () => {
+ it('should use after cursor for forward pagination', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0], testItems[1]], has_more: true },
+ { data: [testItems[2]], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, {
+ limit: 2,
+ after: 'initial-cursor',
+ });
+
+ const pages: PageResponse[] = [];
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(mockFetchPage).toHaveBeenCalledTimes(2);
+ expect(mockFetchPage).toHaveBeenNthCalledWith(1, {
+ limit: 2,
+ after: 'initial-cursor',
+ });
+ expect(mockFetchPage).toHaveBeenNthCalledWith(2, {
+ limit: 2,
+ after: testItems[1].id,
+ });
+ });
+
+ it('should use before cursor for backward pagination', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[2], testItems[1]], has_more: true },
+ { data: [testItems[0]], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, {
+ limit: 2,
+ before: 'initial-cursor',
+ });
+
+ const pages: PageResponse[] = [];
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(mockFetchPage).toHaveBeenCalledTimes(2);
+ expect(mockFetchPage).toHaveBeenNthCalledWith(1, {
+ limit: 2,
+ before: 'initial-cursor',
+ });
+ expect(mockFetchPage).toHaveBeenNthCalledWith(2, {
+ limit: 2,
+ before: testItems[2].id,
+ });
+ });
+
+ it('should default to forward pagination when no cursor specified', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0], testItems[1]], has_more: true },
+ { data: [testItems[2]], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 2 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(mockFetchPage).toHaveBeenNthCalledWith(2, {
+ limit: 2,
+ after: testItems[1].id,
+ });
+ });
+ });
+
+ describe('Rate limiting handling', () => {
+ it('should handle rate limit on initial page', async () => {
+ const mockFetchPage = vi
+ .fn()
+ .mockResolvedValueOnce({
+ data: null,
+ error: {
+ name: 'rate_limit_exceeded',
+ message: 'Rate limit exceeded',
+ retryAfter: 0.001, // Very short delay for testing
+ },
+ rateLimiting: {
+ limit: 10,
+ remainingRequests: 0,
+ shouldResetAfter: 60,
+ },
+ })
+ .mockResolvedValueOnce({
+ data: {
+ object: 'list',
+ data: [testItems[0]],
+ has_more: false,
+ },
+ error: null,
+ rateLimiting: {
+ limit: 10,
+ remainingRequests: 9,
+ shouldResetAfter: 60,
+ },
+ });
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(1);
+ expect(pages[0].data?.data).toEqual([testItems[0]]);
+ expect(mockFetchPage).toHaveBeenCalledTimes(2);
+ });
+
+ it('should handle rate limit on subsequent pages', async () => {
+ const mockFetchPage = vi
+ .fn()
+ .mockResolvedValueOnce({
+ data: {
+ object: 'list',
+ data: [testItems[0]],
+ has_more: true,
+ },
+ error: null,
+ rateLimiting: {
+ limit: 10,
+ remainingRequests: 9,
+ shouldResetAfter: 60,
+ },
+ })
+ .mockResolvedValueOnce({
+ data: null,
+ error: {
+ name: 'rate_limit_exceeded',
+ message: 'Rate limit exceeded',
+ retryAfter: 0.001, // Very short delay for testing
+ },
+ rateLimiting: {
+ limit: 10,
+ remainingRequests: 0,
+ shouldResetAfter: 60,
+ },
+ })
+ .mockResolvedValueOnce({
+ data: {
+ object: 'list',
+ data: [testItems[1]],
+ has_more: false,
+ },
+ error: null,
+ rateLimiting: {
+ limit: 10,
+ remainingRequests: 9,
+ shouldResetAfter: 60,
+ },
+ });
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(2);
+ expect(pages[0].data?.data).toEqual([testItems[0]]);
+ expect(pages[1].data?.data).toEqual([testItems[1]]);
+ expect(mockFetchPage).toHaveBeenCalledTimes(3);
+ });
+
+ it('should not wait on first call to getPageRetryingRateLimit when firstWait is 0', async () => {
+ const mockFetchPage = vi.fn().mockResolvedValue({
+ data: { object: 'list', data: [testItems[0]], has_more: false },
+ error: null,
+ rateLimiting: { limit: 10, remainingRequests: 9, shouldResetAfter: 60 },
+ });
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+
+ const pages: PageResponse[] = [];
+ for await (const page of request) {
+ pages.push(page);
+ break; // Only get first page to test this scenario
+ }
+
+ expect(pages).toHaveLength(1);
+ expect(mockFetchPage).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('Error handling', () => {
+ it('should handle non-rate-limit errors in fetchPage', async () => {
+ const mockFetchPage = vi.fn().mockResolvedValue({
+ data: null,
+ error: {
+ name: 'invalid_parameter',
+ message: 'Invalid parameter provided',
+ },
+ rateLimiting: { limit: 10, remainingRequests: 9, shouldResetAfter: 60 },
+ });
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(1);
+ expect(pages[0].error?.name).toBe('invalid_parameter');
+ expect(pages[0].data).toBeNull();
+ });
+
+ it('should handle Promise rejection in fetchPage', async () => {
+ const mockFetchPage = vi
+ .fn()
+ .mockRejectedValue(new Error('Network error'));
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+
+ await expect(async () => {
+ for await (const _page of request) {
+ // This should throw
+ }
+ }).rejects.toThrow('Network error');
+ });
+ });
+
+ describe('Edge cases', () => {
+ it('should handle empty first page', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 10 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(1);
+ expect(pages[0].data?.data).toEqual([]);
+ expect(pages[0].data?.has_more).toBe(false);
+ });
+
+ it('should handle single item across multiple pages', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0]], has_more: true },
+ { data: [testItems[1]], has_more: true },
+ { data: [testItems[2]], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+ const pages: PageResponse[] = [];
+
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(3);
+ expect(pages[0].data?.data).toEqual([testItems[0]]);
+ expect(pages[1].data?.data).toEqual([testItems[1]]);
+ expect(pages[2].data?.data).toEqual([testItems[2]]);
+ });
+
+ it('should handle mixed Promise and AsyncIterable usage', async () => {
+ const mockFetchPage = createMockFetchPage([
+ { data: [testItems[0]], has_more: true },
+ { data: [testItems[1]], has_more: false },
+ ]);
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 1 });
+
+ // First use as Promise
+ const firstPage = await request;
+ expect(firstPage.data.data).toEqual([testItems[0]]);
+
+ // Then use as AsyncIterable (should start fresh iteration)
+ const pages: PageResponse[] = [];
+ for await (const page of request) {
+ pages.push(page);
+ }
+
+ expect(pages).toHaveLength(2);
+ expect(pages[0].data?.data).toEqual([testItems[0]]);
+ expect(pages[1].data?.data).toEqual([testItems[1]]);
+ });
+ });
+
+ describe('Type constraints', () => {
+ it('should work with objects that have id property', async () => {
+ type CustomItem = { id: string; value: number };
+ const customItems: CustomItem[] = [
+ { id: 'a1', value: 10 },
+ { id: 'b2', value: 20 },
+ ];
+
+ const mockFetchPage = vi.fn().mockResolvedValue({
+ data: { object: 'list', data: customItems, has_more: false },
+ error: null,
+ rateLimiting: { limit: 10, remainingRequests: 9, shouldResetAfter: 60 },
+ });
+
+ const request = new PaginatedRequest(mockFetchPage, { limit: 10 });
+ const result = await request;
+
+ expect(result.data.data).toEqual(customItems);
+ });
+ });
+});
diff --git a/src/common/pagination.ts b/src/common/pagination.ts
new file mode 100644
index 00000000..2b2426ba
--- /dev/null
+++ b/src/common/pagination.ts
@@ -0,0 +1,106 @@
+import type { Response } from '../interfaces';
+
+export type PageResponse = Response<{
+ object: 'list';
+ data: Array;
+ has_more: boolean;
+}>;
+
+export type PageRequestOptions = {
+ limit?: number;
+} & ({ after?: string; before?: never } | { before?: string; after?: never });
+
+export class PaginatedRequest
+ implements Promise>, AsyncIterable>
+{
+ private readonly initialPagePromise: Promise>;
+
+ constructor(
+ private readonly fetchPage: (
+ options: PageRequestOptions,
+ ) => Promise>,
+ private readonly options: PageRequestOptions,
+ ) {
+ this.initialPagePromise = fetchPage(options);
+ }
+
+ // biome-ignore lint/suspicious/noThenProperty: this class implements Promise
+ then, TResult2 = never>(
+ onfulfilled?:
+ | ((value: PageResponse) => TResult1 | PromiseLike)
+ | null
+ | undefined,
+ onrejected?:
+ | ((reason: unknown) => TResult2 | PromiseLike)
+ | null
+ | undefined,
+ ): Promise {
+ return this.initialPagePromise.then(onfulfilled, onrejected);
+ }
+
+ catch(
+ onrejected?:
+ | ((reason: unknown) => TResult | PromiseLike)
+ | null
+ | undefined,
+ ): Promise | TResult> {
+ return this.initialPagePromise.catch(onrejected);
+ }
+
+ finally(
+ onfinally?: (() => void) | null | undefined,
+ ): Promise> {
+ return this.initialPagePromise.finally(onfinally);
+ }
+
+ [Symbol.toStringTag] = 'PaginatedRequest';
+
+ private async getPageRetryingRateLimit(
+ firstWait: number,
+ options: PageRequestOptions,
+ ): Promise> {
+ if (firstWait > 0) {
+ await sleep(firstWait);
+ }
+
+ let page = await this.fetchPage(options);
+ while (page.error?.name === 'rate_limit_exceeded') {
+ const retryAfter = page.error.retryAfter;
+ await sleep(retryAfter);
+ page = await this.fetchPage(options);
+ }
+
+ return page;
+ }
+
+ private async *iterator(): AsyncIterator> {
+ let page = await this.initialPagePromise;
+ if (page.error?.name === 'rate_limit_exceeded') {
+ page = await this.getPageRetryingRateLimit(
+ page.error.retryAfter,
+ this.options,
+ );
+ }
+ yield page;
+
+ const options = { ...this.options };
+ while (page.data?.has_more && page.data.data.length > 0) {
+ if (options.before) {
+ options.before = page.data.data[0].id;
+ } else {
+ options.after = page.data.data[page.data.data.length - 1].id;
+ }
+
+ page = await this.getPageRetryingRateLimit(0, options);
+ yield page;
+ }
+ }
+
+ [Symbol.asyncIterator](): AsyncIterator> {
+ return this.iterator();
+ }
+}
+
+async function sleep(seconds: number): Promise {
+ return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
+}
diff --git a/src/contacts/contacts.spec.ts b/src/contacts/contacts.spec.ts
index 20d182a5..87355fdb 100644
--- a/src/contacts/contacts.spec.ts
+++ b/src/contacts/contacts.spec.ts
@@ -1,6 +1,9 @@
-import { enableFetchMocks } from 'jest-fetch-mock';
import type { ErrorResponse } from '../interfaces';
import { Resend } from '../resend';
+import {
+ mockErrorResponse,
+ mockSuccessResponse,
+} from '../test-utils/mock-fetch';
import type {
CreateContactOptions,
CreateContactResponseSuccess,
@@ -19,8 +22,6 @@ import type {
} from './interfaces/remove-contact.interface';
import type { UpdateContactOptions } from './interfaces/update-contact.interface';
-enableFetchMocks();
-
describe('Contacts', () => {
afterEach(() => fetchMock.resetMocks());
@@ -35,12 +36,8 @@ describe('Contacts', () => {
id: '3deaccfb-f47f-440a-8875-ea14b1716b43',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -53,6 +50,11 @@ describe('Contacts', () => {
"object": "contact",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -67,12 +69,8 @@ describe('Contacts', () => {
message: 'Missing `email` field.',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -86,6 +84,11 @@ describe('Contacts', () => {
"message": "Missing \`email\` field.",
"name": "missing_required_field",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -117,12 +120,8 @@ describe('Contacts', () => {
},
],
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -153,6 +152,11 @@ describe('Contacts', () => {
"object": "list",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -166,12 +170,8 @@ describe('Contacts', () => {
message: 'Contact not found',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 404,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -189,6 +189,11 @@ describe('Contacts', () => {
"message": "Contact not found",
"name": "not_found",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -205,12 +210,8 @@ describe('Contacts', () => {
unsubscribed: false,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -232,6 +233,11 @@ describe('Contacts', () => {
"unsubscribed": false,
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -247,12 +253,8 @@ describe('Contacts', () => {
unsubscribed: false,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -274,6 +276,11 @@ describe('Contacts', () => {
"unsubscribed": false,
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -290,12 +297,8 @@ describe('Contacts', () => {
id: '3d4a472d-bc6d-4dd2-aa9d-d3d50ce87223',
object: 'contact',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -309,6 +312,11 @@ describe('Contacts', () => {
"object": "contact",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -321,12 +329,8 @@ describe('Contacts', () => {
object: 'contact',
deleted: true,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -344,6 +348,11 @@ describe('Contacts', () => {
"object": "contact",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -354,12 +363,8 @@ describe('Contacts', () => {
object: 'contact',
deleted: true,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -370,15 +375,20 @@ describe('Contacts', () => {
await expect(
resend.contacts.remove(options),
).resolves.toMatchInlineSnapshot(`
- {
- "data": {
- "contact": "acme@example.com",
- "deleted": true,
- "object": "contact",
- },
- "error": null,
- }
- `);
+{
+ "data": {
+ "contact": "acme@example.com",
+ "deleted": true,
+ "object": "contact",
+ },
+ "error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
+}
+`);
});
});
});
diff --git a/src/contacts/contacts.ts b/src/contacts/contacts.ts
index 5fefa506..b3c21158 100644
--- a/src/contacts/contacts.ts
+++ b/src/contacts/contacts.ts
@@ -57,6 +57,7 @@ export class Contacts {
if (!options.id && !options.email) {
return {
data: null,
+ rateLimiting: null,
error: {
message: 'Missing `id` or `email` field.',
name: 'missing_required_field',
@@ -70,10 +71,11 @@ export class Contacts {
return data;
}
- async update(payload: UpdateContactOptions): Promise {
- if (!payload.id && !payload.email) {
+ async update(options: UpdateContactOptions): Promise {
+ if (!options.id && !options.email) {
return {
data: null,
+ rateLimiting: null,
error: {
message: 'Missing `id` or `email` field.',
name: 'missing_required_field',
@@ -82,11 +84,11 @@ export class Contacts {
}
const data = await this.resend.patch(
- `/audiences/${payload.audienceId}/contacts/${payload?.email ? payload?.email : payload?.id}`,
+ `/audiences/${options.audienceId}/contacts/${options?.email ? options?.email : options?.id}`,
{
- unsubscribed: payload.unsubscribed,
- first_name: payload.firstName,
- last_name: payload.lastName,
+ unsubscribed: options.unsubscribed,
+ first_name: options.firstName,
+ last_name: options.lastName,
},
);
return data;
@@ -96,6 +98,7 @@ export class Contacts {
if (!payload.id && !payload.email) {
return {
data: null,
+ rateLimiting: null,
error: {
message: 'Missing `id` or `email` field.',
name: 'missing_required_field',
diff --git a/src/contacts/interfaces/contact.ts b/src/contacts/interfaces/contact.ts
index 3bcdc521..56ecd1b7 100644
--- a/src/contacts/interfaces/contact.ts
+++ b/src/contacts/interfaces/contact.ts
@@ -6,3 +6,33 @@ export interface Contact {
last_name?: string;
unsubscribed: boolean;
}
+
+export type SelectingField =
+ | {
+ /**
+ * The contact id.
+ *
+ * @link https://resend.com/docs/api-reference/contacts/delete-contact#body-parameters
+ */
+ id: string;
+ /**
+ * The contact email.
+ *
+ * @link https://resend.com/docs/api-reference/contacts/delete-contact#body-parameters
+ */
+ email?: undefined | null;
+ }
+ | {
+ /**
+ * The contact id.
+ *
+ * @link https://resend.com/docs/api-reference/contacts/delete-contact#body-parameters
+ */
+ id?: undefined | null;
+ /**
+ * The contact email.
+ *
+ * @link https://resend.com/docs/api-reference/contacts/delete-contact#body-parameters
+ */
+ email: string;
+ };
diff --git a/src/contacts/interfaces/create-contact-options.interface.ts b/src/contacts/interfaces/create-contact-options.interface.ts
index ff73f25b..49304acd 100644
--- a/src/contacts/interfaces/create-contact-options.interface.ts
+++ b/src/contacts/interfaces/create-contact-options.interface.ts
@@ -1,5 +1,5 @@
import type { PostOptions } from '../../common/interfaces';
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Contact } from './contact';
export interface CreateContactOptions {
@@ -16,12 +16,4 @@ export interface CreateContactResponseSuccess extends Pick {
object: 'contact';
}
-export type CreateContactResponse =
- | {
- data: CreateContactResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type CreateContactResponse = Response;
diff --git a/src/contacts/interfaces/get-contact.interface.ts b/src/contacts/interfaces/get-contact.interface.ts
index 95e4cf6a..2ed90a5e 100644
--- a/src/contacts/interfaces/get-contact.interface.ts
+++ b/src/contacts/interfaces/get-contact.interface.ts
@@ -1,11 +1,9 @@
-import type { ErrorResponse } from '../../interfaces';
-import type { Contact } from './contact';
+import type { Response } from '../../interfaces';
+import type { Contact, SelectingField } from './contact';
-export interface GetContactOptions {
+export type GetContactOptions = {
audienceId: string;
- id?: string;
- email?: string;
-}
+} & SelectingField;
export interface GetContactResponseSuccess
extends Pick<
@@ -15,12 +13,4 @@ export interface GetContactResponseSuccess
object: 'contact';
}
-export type GetContactResponse =
- | {
- data: GetContactResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type GetContactResponse = Response;
diff --git a/src/contacts/interfaces/list-contacts.interface.ts b/src/contacts/interfaces/list-contacts.interface.ts
index a3970786..8b71b435 100644
--- a/src/contacts/interfaces/list-contacts.interface.ts
+++ b/src/contacts/interfaces/list-contacts.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Contact } from './contact';
export interface ListContactsOptions {
@@ -10,12 +10,4 @@ export interface ListContactsResponseSuccess {
data: Contact[];
}
-export type ListContactsResponse =
- | {
- data: ListContactsResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type ListContactsResponse = Response;
diff --git a/src/contacts/interfaces/remove-contact.interface.ts b/src/contacts/interfaces/remove-contact.interface.ts
index aedf40ba..dd7d117f 100644
--- a/src/contacts/interfaces/remove-contact.interface.ts
+++ b/src/contacts/interfaces/remove-contact.interface.ts
@@ -1,4 +1,5 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
+import type { SelectingField } from './contact';
export type RemoveContactsResponseSuccess = {
object: 'contact';
@@ -6,31 +7,8 @@ export type RemoveContactsResponseSuccess = {
contact: string;
};
-interface RemoveByOptions {
- /**
- * The contact id.
- *
- * @link https://resend.com/docs/api-reference/contacts/delete-contact#body-parameters
- */
- id?: string;
- /**
- * The contact email.
- *
- * @link https://resend.com/docs/api-reference/contacts/delete-contact#body-parameters
- */
- email?: string;
-}
-
-export interface RemoveContactOptions extends RemoveByOptions {
+export type RemoveContactOptions = SelectingField & {
audienceId: string;
-}
+};
-export type RemoveContactsResponse =
- | {
- data: RemoveContactsResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type RemoveContactsResponse = Response;
diff --git a/src/contacts/interfaces/update-contact.interface.ts b/src/contacts/interfaces/update-contact.interface.ts
index 8a5d98e6..51a903c4 100644
--- a/src/contacts/interfaces/update-contact.interface.ts
+++ b/src/contacts/interfaces/update-contact.interface.ts
@@ -1,28 +1,15 @@
-import type { ErrorResponse } from '../../interfaces';
-import type { Contact } from './contact';
+import type { Response } from '../../interfaces';
+import type { Contact, SelectingField } from './contact';
-interface UpdateContactBaseOptions {
- id?: string;
- email?: string;
-}
-
-export interface UpdateContactOptions extends UpdateContactBaseOptions {
+export type UpdateContactOptions = {
audienceId: string;
unsubscribed?: boolean;
firstName?: string;
lastName?: string;
-}
+} & SelectingField;
export type UpdateContactResponseSuccess = Pick & {
object: 'contact';
};
-export type UpdateContactResponse =
- | {
- data: UpdateContactResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type UpdateContactResponse = Response;
diff --git a/src/domains/domains.spec.ts b/src/domains/domains.spec.ts
index 369f9c68..083378bb 100644
--- a/src/domains/domains.spec.ts
+++ b/src/domains/domains.spec.ts
@@ -1,6 +1,9 @@
-import { enableFetchMocks } from 'jest-fetch-mock';
import type { ErrorResponse } from '../interfaces';
import { Resend } from '../resend';
+import {
+ mockErrorResponse,
+ mockSuccessResponse,
+} from '../test-utils/mock-fetch';
import type {
CreateDomainOptions,
CreateDomainResponseSuccess,
@@ -12,8 +15,6 @@ import type { RemoveDomainsResponseSuccess } from './interfaces/remove-domain.in
import type { UpdateDomainsResponseSuccess } from './interfaces/update-domain.interface';
import type { VerifyDomainsResponseSuccess } from './interfaces/verify-domain.interface';
-enableFetchMocks();
-
describe('Domains', () => {
afterEach(() => fetchMock.resetMocks());
@@ -69,12 +70,8 @@ describe('Domains', () => {
],
region: 'us-east-1',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateDomainOptions = { name: 'resend.com' };
@@ -134,6 +131,11 @@ describe('Domains', () => {
"status": "not_started",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -144,12 +146,8 @@ describe('Domains', () => {
message: 'Missing "name" field',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateDomainOptions = {
@@ -167,6 +165,11 @@ describe('Domains', () => {
"message": "Missing "name" field",
"name": "missing_required_field",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -234,57 +237,12 @@ describe('Domains', () => {
resend.domains.create(payload),
).resolves.toMatchInlineSnapshot(`
{
- "data": {
- "created_at": "2023-04-07T22:48:33.420498+00:00",
- "id": "3d4a472d-bc6d-4dd2-aa9d-d3d50ce87222",
- "name": "resend.com",
- "records": [
- {
- "name": "bounces",
- "priority": 10,
- "record": "SPF",
- "status": "not_started",
- "ttl": "Auto",
- "type": "MX",
- "value": "feedback-smtp.eu-west-1.com",
- },
- {
- "name": "bounces",
- "record": "SPF",
- "status": "not_started",
- "ttl": "Auto",
- "type": "TXT",
- "value": ""v=spf1 include:com ~all"",
- },
- {
- "name": "nu22pfdfqaxdybogtw3ebaokmalv5mxg._domainkey",
- "record": "DKIM",
- "status": "not_started",
- "ttl": "Auto",
- "type": "CNAME",
- "value": "nu22pfdfqaxdybogtw3ebaokmalv5mxg.dkim.com.",
- },
- {
- "name": "qklz5ozk742hhql3vmekdu3pr4f5ggsj._domainkey",
- "record": "DKIM",
- "status": "not_started",
- "ttl": "Auto",
- "type": "CNAME",
- "value": "qklz5ozk742hhql3vmekdu3pr4f5ggsj.dkim.com.",
- },
- {
- "name": "eeaemodxoao5hxwjvhywx4bo5mswjw6v._domainkey",
- "record": "DKIM",
- "status": "not_started",
- "ttl": "Auto",
- "type": "CNAME",
- "value": "eeaemodxoao5hxwjvhywx4bo5mswjw6v.dkim.com.",
- },
- ],
- "region": "eu-west-1",
- "status": "not_started",
+ "data": null,
+ "error": {
+ "message": "Unable to fetch data. The request could not be resolved.",
+ "name": "application_error",
},
- "error": null,
+ "rateLimiting": null,
}
`);
});
@@ -295,12 +253,8 @@ describe('Domains', () => {
message: 'Region must be "us-east-1" | "eu-west-1" | "sa-east-1"',
};
- fetchMock.mockOnce(JSON.stringify(errorResponse), {
- status: 422,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(errorResponse, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -317,6 +271,11 @@ describe('Domains', () => {
"message": "Region must be "us-east-1" | "eu-west-1" | "sa-east-1"",
"name": "invalid_region",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -359,12 +318,8 @@ describe('Domains', () => {
region: 'us-east-1',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateDomainOptions = {
@@ -412,6 +367,11 @@ describe('Domains', () => {
"status": "not_started",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -438,12 +398,8 @@ describe('Domains', () => {
},
],
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -469,6 +425,11 @@ describe('Domains', () => {
],
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -482,12 +443,8 @@ describe('Domains', () => {
message: 'Domain not found',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 404,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -501,6 +458,11 @@ describe('Domains', () => {
"message": "Domain not found",
"name": "not_found",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -544,12 +506,8 @@ describe('Domains', () => {
],
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -592,6 +550,11 @@ describe('Domains', () => {
"status": "not_started",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -605,12 +568,8 @@ describe('Domains', () => {
id,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -627,6 +586,11 @@ describe('Domains', () => {
"object": "domain",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -639,12 +603,8 @@ describe('Domains', () => {
object: 'domain',
id,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -656,6 +616,11 @@ describe('Domains', () => {
"object": "domain",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -669,12 +634,8 @@ describe('Domains', () => {
id,
deleted: true,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -687,6 +648,11 @@ describe('Domains', () => {
"object": "domain",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
diff --git a/src/domains/interfaces/create-domain-options.interface.ts b/src/domains/interfaces/create-domain-options.interface.ts
index 13ba9562..ce278e95 100644
--- a/src/domains/interfaces/create-domain-options.interface.ts
+++ b/src/domains/interfaces/create-domain-options.interface.ts
@@ -1,5 +1,5 @@
import type { PostOptions } from '../../common/interfaces';
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Domain, DomainRecords, DomainRegion } from './domain';
export interface CreateDomainOptions {
@@ -15,12 +15,4 @@ export interface CreateDomainResponseSuccess
records: DomainRecords[];
}
-export type CreateDomainResponse =
- | {
- data: CreateDomainResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type CreateDomainResponse = Response;
diff --git a/src/domains/interfaces/get-domain.interface.ts b/src/domains/interfaces/get-domain.interface.ts
index 6c79410f..1b86eab3 100644
--- a/src/domains/interfaces/get-domain.interface.ts
+++ b/src/domains/interfaces/get-domain.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Domain, DomainRecords } from './domain';
export interface GetDomainResponseSuccess
@@ -7,12 +7,4 @@ export interface GetDomainResponseSuccess
records: DomainRecords[];
}
-export type GetDomainResponse =
- | {
- data: GetDomainResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type GetDomainResponse = Response;
diff --git a/src/domains/interfaces/list-domains.interface.ts b/src/domains/interfaces/list-domains.interface.ts
index fcba8ab9..af6a5604 100644
--- a/src/domains/interfaces/list-domains.interface.ts
+++ b/src/domains/interfaces/list-domains.interface.ts
@@ -1,14 +1,6 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Domain } from './domain';
export type ListDomainsResponseSuccess = { data: Domain[] };
-export type ListDomainsResponse =
- | {
- data: ListDomainsResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type ListDomainsResponse = Response;
diff --git a/src/domains/interfaces/remove-domain.interface.ts b/src/domains/interfaces/remove-domain.interface.ts
index 7c11f64d..aa1cb266 100644
--- a/src/domains/interfaces/remove-domain.interface.ts
+++ b/src/domains/interfaces/remove-domain.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Domain } from './domain';
export type RemoveDomainsResponseSuccess = Pick & {
@@ -6,12 +6,4 @@ export type RemoveDomainsResponseSuccess = Pick & {
deleted: boolean;
};
-export type RemoveDomainsResponse =
- | {
- data: RemoveDomainsResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type RemoveDomainsResponse = Response;
diff --git a/src/domains/interfaces/update-domain.interface.ts b/src/domains/interfaces/update-domain.interface.ts
index c07333eb..9b36b90e 100644
--- a/src/domains/interfaces/update-domain.interface.ts
+++ b/src/domains/interfaces/update-domain.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Domain } from './domain';
export interface UpdateDomainsOptions {
@@ -12,12 +12,4 @@ export type UpdateDomainsResponseSuccess = Pick & {
object: 'domain';
};
-export type UpdateDomainsResponse =
- | {
- data: UpdateDomainsResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type UpdateDomainsResponse = Response;
diff --git a/src/domains/interfaces/verify-domain.interface.ts b/src/domains/interfaces/verify-domain.interface.ts
index 069b9193..6bb420b9 100644
--- a/src/domains/interfaces/verify-domain.interface.ts
+++ b/src/domains/interfaces/verify-domain.interface.ts
@@ -1,16 +1,8 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
import type { Domain } from './domain';
export type VerifyDomainsResponseSuccess = Pick & {
object: 'domain';
};
-export type VerifyDomainsResponse =
- | {
- data: VerifyDomainsResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type VerifyDomainsResponse = Response;
diff --git a/src/emails/emails.spec.ts b/src/emails/emails.spec.ts
index c71fe78e..2acf2523 100644
--- a/src/emails/emails.spec.ts
+++ b/src/emails/emails.spec.ts
@@ -1,13 +1,16 @@
-import { enableFetchMocks } from 'jest-fetch-mock';
import type { ErrorResponse } from '../interfaces';
import { Resend } from '../resend';
+import {
+ mockErrorResponse,
+ mockFetchWithRateLimit,
+ mockSuccessResponse,
+} from '../test-utils/mock-fetch';
import type {
CreateEmailOptions,
CreateEmailResponseSuccess,
} from './interfaces/create-email-options.interface';
import type { GetEmailResponseSuccess } from './interfaces/get-email-options.interface';
-
-enableFetchMocks();
+import type { ListEmailsResponseSuccess } from './interfaces/list-emails-options.interface';
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
@@ -21,10 +24,8 @@ describe('Emails', () => {
message: 'Missing `from` field.',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
+ mockErrorResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -38,6 +39,11 @@ describe('Emails', () => {
"message": "Missing \`from\` field.",
"name": "missing_required_field",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -47,10 +53,8 @@ describe('Emails', () => {
id: 'not-idempotent-123',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
+ mockSuccessResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -67,15 +71,11 @@ describe('Emails', () => {
// Inspect the last fetch call and body
const lastCall = fetchMock.mock.calls[0];
expect(lastCall).toBeDefined();
+ const request = lastCall[1];
+ expect(request).toBeDefined();
- console.log('debug:', lastCall[1]?.headers);
- //@ts-ignore
- const hasIdempotencyKey = lastCall[1]?.headers.has('Idempotency-Key');
- expect(hasIdempotencyKey).toBeFalsy();
-
- //@ts-ignore
- const usedIdempotencyKey = lastCall[1]?.headers.get('Idempotency-Key');
- expect(usedIdempotencyKey).toBeNull();
+ const headers = new Headers(request?.headers);
+ expect(headers.has('Idempotency-Key')).toBe(false);
});
it('sends the Idempotency-Key header when idempotencyKey is provided', async () => {
@@ -83,10 +83,8 @@ describe('Emails', () => {
id: 'idempotent-123',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
+ mockSuccessResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -105,17 +103,9 @@ describe('Emails', () => {
const lastCall = fetchMock.mock.calls[0];
expect(lastCall).toBeDefined();
- // Check if headers contains Idempotency-Key
- // In the mock, headers is an object with key-value pairs
- expect(fetchMock.mock.calls[0][1]?.headers).toBeDefined();
-
- //@ts-ignore
- const hasIdempotencyKey = lastCall[1]?.headers.has('Idempotency-Key');
- expect(hasIdempotencyKey).toBeTruthy();
-
- //@ts-ignore
- const usedIdempotencyKey = lastCall[1]?.headers.get('Idempotency-Key');
- expect(usedIdempotencyKey).toBe(idempotencyKey);
+ const headers = new Headers(lastCall[1]?.headers);
+ expect(headers.has('Idempotency-Key')).toBe(true);
+ expect(headers.get('Idempotency-Key')).toBe(idempotencyKey);
});
});
@@ -124,10 +114,8 @@ describe('Emails', () => {
const response: CreateEmailResponseSuccess = {
id: '71cdfe68-cf79-473a-a9d7-21f91db6a526',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
+ mockSuccessResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -146,6 +134,11 @@ describe('Emails', () => {
"id": "71cdfe68-cf79-473a-a9d7-21f91db6a526",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -155,12 +148,8 @@ describe('Emails', () => {
id: '124dc0f1-e36c-417c-a65c-e33773abc768',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateEmailOptions = {
@@ -176,6 +165,11 @@ describe('Emails', () => {
"id": "124dc0f1-e36c-417c-a65c-e33773abc768",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -185,12 +179,8 @@ describe('Emails', () => {
id: '124dc0f1-e36c-417c-a65c-e33773abc768',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateEmailOptions = {
@@ -208,6 +198,11 @@ describe('Emails', () => {
"id": "124dc0f1-e36c-417c-a65c-e33773abc768",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -217,12 +212,8 @@ describe('Emails', () => {
id: '124dc0f1-e36c-417c-a65c-e33773abc768',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateEmailOptions = {
@@ -240,6 +231,11 @@ describe('Emails', () => {
"id": "124dc0f1-e36c-417c-a65c-e33773abc768",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -249,12 +245,8 @@ describe('Emails', () => {
id: '124dc0f1-e36c-417c-a65c-e33773abc768',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateEmailOptions = {
@@ -272,6 +264,11 @@ describe('Emails', () => {
"id": "124dc0f1-e36c-417c-a65c-e33773abc768",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -281,12 +278,8 @@ describe('Emails', () => {
id: '124dc0f1-e36c-417c-a65c-e33773abc768',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockSuccessResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateEmailOptions = {
@@ -306,6 +299,11 @@ describe('Emails', () => {
"id": "124dc0f1-e36c-417c-a65c-e33773abc768",
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -317,12 +315,8 @@ describe('Emails', () => {
'Invalid `from` field. The email address needs to follow the `email@example.com` or `Name ` format',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 422,
- headers: {
- 'content-type': 'application/json',
- Authorization: 'Bearer re_924b3rjh2387fbewf823',
- },
+ mockErrorResponse(response, {
+ headers: { Authorization: 'Bearer re_924b3rjh2387fbewf823' },
});
const payload: CreateEmailOptions = {
@@ -336,14 +330,19 @@ describe('Emails', () => {
const result = resend.emails.send(payload);
await expect(result).resolves.toMatchInlineSnapshot(`
- {
- "data": null,
- "error": {
- "message": "Invalid \`from\` field. The email address needs to follow the \`email@example.com\` or \`Name \` format",
- "name": "invalid_parameter",
- },
- }
- `);
+{
+ "data": null,
+ "error": {
+ "message": "Invalid \`from\` field. The email address needs to follow the \`email@example.com\` or \`Name \` format",
+ "name": "invalid_parameter",
+ },
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
+}
+`);
});
it('returns an error when fetch fails', async () => {
@@ -373,7 +372,7 @@ describe('Emails', () => {
});
it('returns an error when api responds with text payload', async () => {
- fetchMock.mockOnce('local_rate_limited', {
+ mockFetchWithRateLimit('local_rate_limited', {
status: 422,
headers: {
Authorization: 'Bearer re_924b3rjh2387fbewf823',
@@ -408,10 +407,8 @@ describe('Emails', () => {
message: 'Email not found',
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 404,
+ mockErrorResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -427,6 +424,11 @@ describe('Emails', () => {
"message": "Email not found",
"name": "not_found",
},
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -450,10 +452,8 @@ describe('Emails', () => {
scheduled_at: null,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
+ mockSuccessResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -480,6 +480,11 @@ describe('Emails', () => {
],
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
@@ -501,10 +506,8 @@ describe('Emails', () => {
scheduled_at: null,
};
- fetchMock.mockOnce(JSON.stringify(response), {
- status: 200,
+ mockSuccessResponse(response, {
headers: {
- 'content-type': 'application/json',
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
},
});
@@ -534,9 +537,113 @@ describe('Emails', () => {
],
},
"error": null,
+ "rateLimiting": {
+ "limit": 2,
+ "remainingRequests": 2,
+ "shouldResetAfter": 1,
+ },
}
`);
});
});
});
+
+ describe('list', () => {
+ const response: ListEmailsResponseSuccess = {
+ object: 'list',
+ has_more: false,
+ data: [
+ {
+ id: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
+ to: ['zeno@resend.com'],
+ from: 'bu@resend.com',
+ created_at: '2023-04-07T23:13:52.669661+00:00',
+ subject: 'Test email',
+ bcc: null,
+ cc: null,
+ reply_to: null,
+ last_event: 'delivered',
+ scheduled_at: null,
+ },
+ ],
+ };
+ const headers = {
+ Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
+ };
+
+ describe('when no pagination options provided', () => {
+ it('calls endpoint without query params and return the response', async () => {
+ mockSuccessResponse(response, {
+ headers,
+ });
+
+ const result = await resend.emails.list();
+ expect(result).toEqual({
+ data: response,
+ error: null,
+ rateLimiting: {
+ limit: 2,
+ remainingRequests: 2,
+ shouldResetAfter: 1,
+ },
+ });
+ expect(fetchMock.mock.calls[0][0]).toBe(
+ 'https://api.resend.com/emails',
+ );
+ });
+ });
+
+ describe('when pagination options are provided', () => {
+ it('calls endpoint passing limit param and return the response', async () => {
+ mockSuccessResponse(response, { headers });
+ const result = await resend.emails.list({ limit: 10 });
+ expect(result).toEqual({
+ data: response,
+ error: null,
+ rateLimiting: {
+ limit: 2,
+ remainingRequests: 2,
+ shouldResetAfter: 1,
+ },
+ });
+ expect(fetchMock.mock.calls[0][0]).toBe(
+ 'https://api.resend.com/emails?limit=10',
+ );
+ });
+
+ it('calls endpoint passing after param and return the response', async () => {
+ mockSuccessResponse(response, { headers });
+ const result = await resend.emails.list({ after: 'cursor123' });
+ expect(result).toEqual({
+ data: response,
+ error: null,
+ rateLimiting: {
+ limit: 2,
+ remainingRequests: 2,
+ shouldResetAfter: 1,
+ },
+ });
+ expect(fetchMock.mock.calls[0][0]).toBe(
+ 'https://api.resend.com/emails?after=cursor123',
+ );
+ });
+
+ it('calls endpoint passing before param and return the response', async () => {
+ mockSuccessResponse(response, { headers });
+ const result = await resend.emails.list({ before: 'cursor123' });
+ expect(result).toEqual({
+ data: response,
+ error: null,
+ rateLimiting: {
+ limit: 2,
+ remainingRequests: 2,
+ shouldResetAfter: 1,
+ },
+ });
+ expect(fetchMock.mock.calls[0][0]).toBe(
+ 'https://api.resend.com/emails?before=cursor123',
+ );
+ });
+ });
+ });
});
diff --git a/src/emails/emails.ts b/src/emails/emails.ts
index 23c13b0c..0a5c4ce2 100644
--- a/src/emails/emails.ts
+++ b/src/emails/emails.ts
@@ -1,4 +1,5 @@
import type * as React from 'react';
+import { PaginatedRequest } from '../common/pagination';
import { parseEmailToApiOptions } from '../common/utils/parse-email-to-api-options';
import type { Resend } from '../resend';
import type {
@@ -15,6 +16,11 @@ import type {
GetEmailResponse,
GetEmailResponseSuccess,
} from './interfaces/get-email-options.interface';
+import type {
+ ListEmail,
+ ListEmailsOptions,
+ ListEmailsResponseSuccess,
+} from './interfaces/list-emails-options.interface';
import type {
UpdateEmailOptions,
UpdateEmailResponse,
@@ -41,7 +47,7 @@ export class Emails {
try {
const { renderAsync } = await import('@react-email/render');
this.renderAsync = renderAsync;
- } catch (error) {
+ } catch {
throw new Error(
'Failed to render React component. Make sure to install `@react-email/render`',
);
@@ -70,6 +76,30 @@ export class Emails {
return data;
}
+ list(options: ListEmailsOptions = {}): PaginatedRequest {
+ const fetchPage = async (options: ListEmailsOptions) => {
+ const searchParams = new URLSearchParams();
+
+ if (options.limit !== undefined) {
+ searchParams.set('limit', options.limit.toString());
+ }
+
+ if ('after' in options && options.after !== undefined) {
+ searchParams.set('after', options.after);
+ }
+
+ if ('before' in options && options.before !== undefined) {
+ searchParams.set('before', options.before);
+ }
+
+ const queryString = searchParams.toString();
+ const url = queryString ? `/emails?${queryString}` : '/emails';
+ return this.resend.get(url);
+ };
+
+ return new PaginatedRequest(fetchPage, options);
+ }
+
async update(payload: UpdateEmailOptions): Promise {
const data = await this.resend.patch(
`/emails/${payload.id}`,
diff --git a/src/emails/interfaces/cancel-email-options.interface.ts b/src/emails/interfaces/cancel-email-options.interface.ts
index c34fbf2d..e7ff6ff8 100644
--- a/src/emails/interfaces/cancel-email-options.interface.ts
+++ b/src/emails/interfaces/cancel-email-options.interface.ts
@@ -1,16 +1,8 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
export interface CancelEmailResponseSuccess {
object: 'email';
id: string;
}
-export type CancelEmailResponse =
- | {
- data: CancelEmailResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type CancelEmailResponse = Response;
diff --git a/src/emails/interfaces/create-email-options.interface.ts b/src/emails/interfaces/create-email-options.interface.ts
index 11db678a..509ff88f 100644
--- a/src/emails/interfaces/create-email-options.interface.ts
+++ b/src/emails/interfaces/create-email-options.interface.ts
@@ -2,7 +2,7 @@ import type * as React from 'react';
import type { PostOptions } from '../../common/interfaces';
import type { IdempotentRequest } from '../../common/interfaces/idempotent-request.interface';
import type { RequireAtLeastOne } from '../../common/interfaces/require-at-least-one';
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
interface EmailRenderOptions {
/**
@@ -101,15 +101,7 @@ export interface CreateEmailResponseSuccess {
id: string;
}
-export type CreateEmailResponse =
- | {
- data: CreateEmailResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type CreateEmailResponse = Response;
export interface Attachment {
/** Content of an attached file. */
diff --git a/src/emails/interfaces/get-email-options.interface.ts b/src/emails/interfaces/get-email-options.interface.ts
index 1d83248a..4c840a4a 100644
--- a/src/emails/interfaces/get-email-options.interface.ts
+++ b/src/emails/interfaces/get-email-options.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
export interface GetEmailResponseSuccess {
bcc: string[] | null;
@@ -28,12 +28,4 @@ export interface GetEmailResponseSuccess {
object: 'email';
}
-export type GetEmailResponse =
- | {
- data: GetEmailResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type GetEmailResponse = Response;
diff --git a/src/emails/interfaces/list-emails-options.interface.ts b/src/emails/interfaces/list-emails-options.interface.ts
new file mode 100644
index 00000000..1adabd6e
--- /dev/null
+++ b/src/emails/interfaces/list-emails-options.interface.ts
@@ -0,0 +1,36 @@
+import type { Response } from '../../interfaces';
+import type { GetEmailResponseSuccess } from './get-email-options.interface';
+
+// Pagination options using cursor-based approach
+export type ListEmailsOptions = {
+ /**
+ * Maximum number of emails to return (1-100, default: 20)
+ */
+ limit?: number;
+} & (
+ | {
+ /**
+ * Get emails after this cursor (cannot be used with 'before')
+ */
+ after?: string;
+ }
+ | {
+ /**
+ * Get emails before this cursor (cannot be used with 'after')
+ */
+ before?: string;
+ }
+);
+
+export type ListEmail = Omit<
+ GetEmailResponseSuccess,
+ 'html' | 'text' | 'tags' | 'object'
+>;
+
+export type ListEmailsResponseSuccess = {
+ object: 'list';
+ has_more: boolean;
+ data: ListEmail[];
+};
+
+export type ListEmailsResponse = Response;
diff --git a/src/emails/interfaces/update-email-options.interface.ts b/src/emails/interfaces/update-email-options.interface.ts
index 89d04637..b3184539 100644
--- a/src/emails/interfaces/update-email-options.interface.ts
+++ b/src/emails/interfaces/update-email-options.interface.ts
@@ -1,4 +1,4 @@
-import type { ErrorResponse } from '../../interfaces';
+import type { Response } from '../../interfaces';
export interface UpdateEmailOptions {
id: string;
@@ -10,12 +10,4 @@ export interface UpdateEmailResponseSuccess {
object: 'email';
}
-export type UpdateEmailResponse =
- | {
- data: UpdateEmailResponseSuccess;
- error: null;
- }
- | {
- data: null;
- error: ErrorResponse;
- };
+export type UpdateEmailResponse = Response;
diff --git a/src/index.ts b/src/index.ts
index de508132..9cd7c1ed 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,3 @@
-export { Resend } from './resend';
-export { ErrorResponse } from './interfaces';
export * from './api-keys/interfaces/create-api-key-options.interface';
export * from './api-keys/interfaces/list-api-keys.interface';
export * from './api-keys/interfaces/remove-api-keys.interface';
@@ -7,9 +5,9 @@ export * from './audiences/interfaces/create-audience-options.interface';
export * from './audiences/interfaces/get-audience.interface';
export * from './audiences/interfaces/list-audiences.interface';
export * from './audiences/interfaces/remove-audience.interface';
+export * from './batch/interfaces/create-batch-options.interface';
export * from './broadcasts/interfaces/create-broadcast-options.interface';
export * from './broadcasts/interfaces/send-broadcast-options.interface';
-export * from './batch/interfaces/create-batch-options.interface';
export * from './contacts/interfaces/create-contact-options.interface';
export * from './contacts/interfaces/get-contact.interface';
export * from './contacts/interfaces/list-contacts.interface';
@@ -23,3 +21,5 @@ export * from './domains/interfaces/update-domain.interface';
export * from './domains/interfaces/verify-domain.interface';
export * from './emails/interfaces/create-email-options.interface';
export * from './emails/interfaces/get-email-options.interface';
+export { ErrorResponse } from './interfaces';
+export { Resend } from './resend';
diff --git a/src/interfaces.ts b/src/interfaces.ts
index f3843d9e..15861c5e 100644
--- a/src/interfaces.ts
+++ b/src/interfaces.ts
@@ -1,3 +1,5 @@
+import type { RateLimit } from './rate-limiting';
+
export const RESEND_ERROR_CODES_BY_KEY = {
missing_required_field: 422,
invalid_idempotency_key: 400,
@@ -19,9 +21,32 @@ export const RESEND_ERROR_CODES_BY_KEY = {
export type RESEND_ERROR_CODE_KEY = keyof typeof RESEND_ERROR_CODES_BY_KEY;
-export interface ErrorResponse {
+export type RateLimitExceededErrorResponse = {
message: string;
- name: RESEND_ERROR_CODE_KEY;
-}
+ name: Extract;
+ /**
+ * Time in seconds.
+ */
+ retryAfter: number;
+};
+
+export type ErrorResponse =
+ | {
+ message: string;
+ name: Exclude;
+ }
+ | RateLimitExceededErrorResponse;
+
+export type Response =
+ | {
+ data: Data;
+ rateLimiting: RateLimit;
+ error: null;
+ }
+ | {
+ data: null;
+ rateLimiting: RateLimit | null;
+ error: ErrorResponse;
+ };
export type Tag = { name: string; value: string };
diff --git a/src/rate-limiting.ts b/src/rate-limiting.ts
new file mode 100644
index 00000000..31ee1537
--- /dev/null
+++ b/src/rate-limiting.ts
@@ -0,0 +1,44 @@
+import type { RateLimitExceededErrorResponse } from './interfaces';
+
+export type RateLimit = {
+ /**
+ * The maximum amount of requests that can be made in the time window of {@link RateLimit.shouldResetAfter}.
+ */
+ limit: number;
+ /**
+ * The amount of requests that can still be made before hitting {@link RateLimit.limit}.
+ *
+ * Resets after the seconds in {@link RateLimit.shouldResetAfter} go by.
+ */
+ remainingRequests: number;
+ /**
+ * The number of seconds after which the rate limiting will reset,
+ * and {@link RateLimit.remainingRequests} goes back to the value of
+ * {@link RateLimit.limit}.
+ *
+ * @see {@link RateLimitExceededErrorResponse.retryAfter}
+ */
+ shouldResetAfter: number;
+};
+
+export function parseRateLimit(headers: Headers): RateLimit {
+ const limitHeader = headers.get('ratelimit-limit');
+ const remainingHeader = headers.get('ratelimit-remaining');
+ const resetHeader = headers.get('ratelimit-reset');
+
+ if (!limitHeader || !remainingHeader || !resetHeader) {
+ throw new Error(
+ "The rate limit headers are not present in the response, something must've gone wrong, please email us at support@resend.com",
+ );
+ }
+
+ const limit = Number.parseInt(limitHeader, 10);
+ const remaining = Number.parseInt(remainingHeader, 10);
+ const reset = Number.parseInt(resetHeader, 10);
+
+ return {
+ limit,
+ remainingRequests: remaining,
+ shouldResetAfter: reset,
+ };
+}
diff --git a/src/resend.ts b/src/resend.ts
index fb547964..9b90c983 100644
--- a/src/resend.ts
+++ b/src/resend.ts
@@ -9,7 +9,8 @@ import type { PatchOptions } from './common/interfaces/patch-option.interface';
import { Contacts } from './contacts/contacts';
import { Domains } from './domains/domains';
import { Emails } from './emails/emails';
-import type { ErrorResponse } from './interfaces';
+import type { ErrorResponse, Response } from './interfaces';
+import { parseRateLimit } from './rate-limiting';
const defaultBaseUrl = 'https://api.resend.com';
const defaultUserAgent = `resend-node:${version}`;
@@ -53,21 +54,28 @@ export class Resend {
});
}
- async fetchRequest(
- path: string,
- options = {},
- ): Promise<{ data: T; error: null } | { data: null; error: ErrorResponse }> {
+ async fetchRequest(path: string, options = {}): Promise> {
try {
const response = await fetch(`${baseUrl}${path}`, options);
+ const rateLimiting = parseRateLimit(response.headers);
+
if (!response.ok) {
try {
const rawError = await response.text();
- return { data: null, error: JSON.parse(rawError) };
+ const error: ErrorResponse = JSON.parse(rawError);
+ if (error.name === 'rate_limit_exceeded' && response.status === 429) {
+ const retryAfterHeader = response.headers.get('retry-after');
+ if (retryAfterHeader) {
+ error.retryAfter = Number.parseInt(retryAfterHeader, 10);
+ }
+ }
+ return { data: null, rateLimiting, error };
} catch (err) {
if (err instanceof SyntaxError) {
return {
data: null,
+ rateLimiting,
error: {
name: 'application_error',
message:
@@ -82,18 +90,23 @@ export class Resend {
};
if (err instanceof Error) {
- return { data: null, error: { ...error, message: err.message } };
+ return {
+ data: null,
+ rateLimiting: rateLimiting,
+ error: { ...error, message: err.message },
+ };
}
- return { data: null, error };
+ return { data: null, rateLimiting, error };
}
}
const data = await response.json();
- return { data, error: null };
- } catch (error) {
+ return { data, rateLimiting, error: null };
+ } catch {
return {
data: null,
+ rateLimiting: null,
error: {
name: 'application_error',
message: 'Unable to fetch data. The request could not be resolved.',
@@ -108,48 +121,69 @@ export class Resend {
options: PostOptions & IdempotentRequest = {},
) {
const headers = new Headers(this.headers);
-
+ if (options.headers) {
+ for (const [key, value] of new Headers(options.headers).entries()) {
+ headers.set(key, value);
+ }
+ }
if (options.idempotencyKey) {
headers.set('Idempotency-Key', options.idempotencyKey);
}
-
const requestOptions = {
method: 'POST',
- headers: headers,
body: JSON.stringify(entity),
...options,
+ headers,
};
return this.fetchRequest(path, requestOptions);
}
async get(path: string, options: GetOptions = {}) {
+ const headers = new Headers(this.headers);
+ if (options.headers) {
+ for (const [key, value] of new Headers(options.headers).entries()) {
+ headers.set(key, value);
+ }
+ }
const requestOptions = {
method: 'GET',
- headers: this.headers,
...options,
+ headers,
};
return this.fetchRequest(path, requestOptions);
}
async put(path: string, entity: unknown, options: PutOptions = {}) {
+ const headers = new Headers(this.headers);
+ if (options.headers) {
+ for (const [key, value] of new Headers(options.headers).entries()) {
+ headers.set(key, value);
+ }
+ }
const requestOptions = {
method: 'PUT',
- headers: this.headers,
body: JSON.stringify(entity),
...options,
+ headers,
};
return this.fetchRequest(path, requestOptions);
}
async patch(path: string, entity: unknown, options: PatchOptions = {}) {
+ const headers = new Headers(this.headers);
+ if (options.headers) {
+ for (const [key, value] of new Headers(options.headers).entries()) {
+ headers.set(key, value);
+ }
+ }
const requestOptions = {
method: 'PATCH',
- headers: this.headers,
body: JSON.stringify(entity),
...options,
+ headers,
};
return this.fetchRequest(path, requestOptions);
@@ -158,7 +192,6 @@ export class Resend {
async delete(path: string, query?: unknown) {
const requestOptions = {
method: 'DELETE',
- headers: this.headers,
body: JSON.stringify(query),
};
diff --git a/src/test-utils/mock-fetch.ts b/src/test-utils/mock-fetch.ts
new file mode 100644
index 00000000..6a276a46
--- /dev/null
+++ b/src/test-utils/mock-fetch.ts
@@ -0,0 +1,90 @@
+import type { MockParams } from 'vitest-fetch-mock';
+
+export interface MockFetchOptions extends MockParams {
+ rateLimiting?: {
+ limit?: number;
+ remaining?: number;
+ reset?: number;
+ };
+}
+
+/**
+ * Mock fetch response with rate limiting headers included by default
+ */
+export function mockFetchWithRateLimit(
+ body: string,
+ options: MockFetchOptions = {},
+): void {
+ const {
+ rateLimiting = {},
+ headers = {},
+ status = 200,
+ ...restOptions
+ } = options;
+
+ const defaultRateLimit = {
+ limit: 2,
+ remaining: 2,
+ reset: 1, // Fixed timestamp for consistent tests
+ };
+
+ const rateLimitHeaders = {
+ 'ratelimit-limit': String(rateLimiting.limit ?? defaultRateLimit.limit),
+ 'ratelimit-remaining': String(
+ rateLimiting.remaining ?? defaultRateLimit.remaining,
+ ),
+ 'ratelimit-reset': String(rateLimiting.reset ?? defaultRateLimit.reset),
+ };
+
+ const allHeaders = {
+ 'content-type': 'application/json',
+ ...rateLimitHeaders,
+ ...headers,
+ };
+
+ fetchMock.mockOnce(body, {
+ status,
+ headers: allHeaders,
+ ...restOptions,
+ });
+}
+
+/**
+ * Mock successful response with rate limiting headers
+ */
+export function mockSuccessResponse(
+ data: T,
+ options: MockFetchOptions = {},
+): void {
+ mockFetchWithRateLimit(JSON.stringify(data), {
+ status: 200,
+ ...options,
+ });
+}
+
+/**
+ * Mock successful response with a custom status code
+ */
+export function mockSuccessWithStatusCode(
+ data: T,
+ status: number,
+ options: MockFetchOptions = {},
+): void {
+ mockFetchWithRateLimit(JSON.stringify(data), {
+ status,
+ ...options,
+ });
+}
+
+/**
+ * Mock error response with rate limiting headers
+ */
+export function mockErrorResponse(
+ error: { name: string; message: string },
+ options: MockFetchOptions = {},
+): void {
+ mockFetchWithRateLimit(JSON.stringify(error), {
+ status: 422,
+ ...options,
+ });
+}
diff --git a/tsconfig.json b/tsconfig.json
index 3adad82d..ba75ca8f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,18 +2,21 @@
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"alwaysStrict": true,
+ "declaration": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
+ "module": "commonjs",
"moduleResolution": "node",
+ "noEmit": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
+ "skipLibCheck": true,
+ "outDir": "build",
"resolveJsonModule": true,
+ "strict": true,
"target": "es6",
- "module": "commonjs",
- "declaration": true,
- "outDir": "build",
- "strict": true
+ "types": ["vitest/globals"]
},
"include": ["src"]
}
diff --git a/vitest.config.mts b/vitest.config.mts
new file mode 100644
index 00000000..d0d7ba2e
--- /dev/null
+++ b/vitest.config.mts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ globals: true,
+ environment: 'node',
+ setupFiles: ['vitest.setup.mts'],
+ },
+});
diff --git a/vitest.setup.mts b/vitest.setup.mts
new file mode 100644
index 00000000..baac05c8
--- /dev/null
+++ b/vitest.setup.mts
@@ -0,0 +1,6 @@
+import { vi } from 'vitest';
+import createFetchMock from 'vitest-fetch-mock';
+
+const fetchMocker = createFetchMock(vi);
+
+fetchMocker.enableMocks();