diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 763301fc..00000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist/ -node_modules/ \ No newline at end of file diff --git a/.eslintrc-examples.js b/.eslintrc-examples.js deleted file mode 100644 index 0bcdc76e..00000000 --- a/.eslintrc-examples.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - ignorePatterns: ["examples/disabled_deno-prerecorded/index.js"], - root: true, - extends: ["eslint:recommended"], - parserOptions: { - ecmaVersion: 2020, - }, - env: { - node: true, - es6: true, - }, - rules: { - "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], - }, -}; diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 682da4f8..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,26 +0,0 @@ -// .eslintrc.js -module.exports = { - root: true, - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint"], - extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - rules: { - // TODO: Enable these once we've fixed the issues - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unsafe-function-type": "off", - - // Prevent Node.js built-in module imports without type-only - "no-restricted-imports": [ - "error", - { - patterns: [ - { - group: ["stream", "fs", "path", "crypto", "os", "child_process", "url", "util"], - message: - 'Node.js built-in modules should use type-only imports. Use: import type { ... } from "..."', - }, - ], - }, - ], - }, -}; diff --git a/.fern/metadata.json b/.fern/metadata.json new file mode 100644 index 00000000..5988344b --- /dev/null +++ b/.fern/metadata.json @@ -0,0 +1,20 @@ +{ + "cliVersion": "1.10.2", + "generatorName": "fernapi/fern-typescript-node-sdk", + "generatorVersion": "3.32.0", + "generatorConfig": { + "allowCustomFetcher": true, + "enableInlineTypes": true, + "includeApiReference": true, + "namespaceExport": "Deepgram", + "noSerdeLayer": true, + "shouldGenerateWebsocketClients": true, + "skipResponseValidation": true, + "fileResponseType": "binary-response", + "generateWireTests": true, + "extraDevDependencies": { + "playwright": "^1.56.1", + "@playwright/test": "^1.56.1" + } + } +} diff --git a/.fernignore b/.fernignore new file mode 100644 index 00000000..35916e25 --- /dev/null +++ b/.fernignore @@ -0,0 +1,10 @@ +# Specify files that shouldn't be modified by Fern + +# Manual tests used in development +tests/manual/ + +# README has been modified since the generated default output +README.md + +# We created our own websocket-reference.md because Fern didn't generate websocket clients in reference.md +websocket-reference.md \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 67b5e5f4..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,6 +0,0 @@ -# Global code owners - these users will be requested for review on all API SPEC PRs -# DX TEAM Members -* @lukeocodes - -# Future Reference: you can also specify owners for specific paths if needed: -# /src/ @username1 @username2 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index e52c98d5..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: Bug report -about: Something is occurring that I think is wrong -title: '' -labels: "\U0001F41B bug" -assignees: '' - ---- - -## What is the current behavior? - -> What's happening that seems wrong? - -## Steps to reproduce - -> To make it faster to diagnose the root problem. Tell us how can we reproduce the bug. - -## Expected behavior - -> What would you expect to happen when following the steps above? - -## Please tell us about your environment - -> We want to make sure the problem isn't specific to your operating system or programming language. - -- **Operating System/Version:** Windows 10 -- **Language:** [all | TypeScript | Python | PHP | etc] -- **Browser:** Chrome - -## Other information - -> Anything else we should know? (e.g. detailed explanation, stack-traces, related issues, suggestions how to fix, links for us to have context, eg. stack overflow, codepen, etc) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index b19bf489..00000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,6 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Deepgram Developer Community - url: https://github.com/orgs/deepgram/discussions - - name: Deepgram on Twitter - url: https://twitter.com/DeepgramAI diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index a0d6b36d..00000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -name: Feature Request -about: I think X would be a cool addition or change. -title: '' -labels: "✨ enhancement" -assignees: '' - ---- - -## Proposed changes - -> Provide a detailed description of the change or addition you are proposing - -## Context - -> Why is this change important to you? How would you use it? How can it benefit other users? - -## Possible Implementation - -> Not obligatory, but suggest an idea for implementing addition or change - -## Other information - -> Anything else we should know? (e.g. detailed explanation, related issues, links for us to have context, eg. stack overflow, codepen, etc) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 16753583..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,30 +0,0 @@ -## Proposed changes - - - -## Types of changes - -What types of changes does your code introduce to the community JavaScript SDK? -_Put an `x` in the boxes that apply_ - -- [ ] Bugfix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Documentation update or tests (if none of the other choices apply) - -## Checklist - -_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._ - -- [ ] I have read the [CONTRIBUTING](../CONTRIBUTING.md) doc -- [ ] I have lint'ed all of my code using repo standards -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] I have added necessary documentation (if appropriate) - -## Further comments - - diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md deleted file mode 100644 index 69f01d8c..00000000 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ /dev/null @@ -1,27 +0,0 @@ -## Proposed changes - -Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. - -## Types of changes - -What types of changes does your code introduce to the Vonage for Visual Studio Code extension? -_Put an `x` in the boxes that apply_ - -- [ ] Bugfix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Documentation update or tests (if none of the other choices apply) - -## Checklist - -_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._ - -- [ ] I have read the [CONTRIBUTING](../../CONTRIBUTING.md) doc -- [ ] Lint and unit tests pass locally with my changes -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] I have added necessary documentation (if appropriate) -- [ ] Any dependent changes have been merged and published in downstream modules - -## Further comments - -If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml deleted file mode 100644 index c05a4de8..00000000 --- a/.github/workflows/CI.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: CI - -on: - pull_request: - branches: - - main - - next - - rc - - beta - - alpha - paths-ignore: - - "docs/**" - - "**/*.md" - - ".prettierrc" - - "**/*ignore" - push: - branches: - - main - - next - - rc - - beta - - alpha - paths-ignore: - - "docs/**" - - "**/*.md" - - ".prettierrc" - - "**/*ignore" - -jobs: - test: - name: Test / OS ${{ matrix.os }} / Node ${{ matrix.node }} - strategy: - matrix: - os: [ubuntu-latest] - node: ["18", "22"] - - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v3 - - - name: Install pnpm - uses: pnpm/action-setup@v2 - with: - version: latest - - - name: Set up Node - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node }} - cache: "pnpm" - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Lint files - run: pnpm run lint - - - name: Validate build - run: pnpm run build - - - name: Run tests - run: pnpm run test:coverage - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/browser-build-test.yml b/.github/workflows/browser-build-test.yml deleted file mode 100644 index 94f1d50d..00000000 --- a/.github/workflows/browser-build-test.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Browser Build Test - -on: - pull_request: - paths: - - "src/**" - - "package.json" - - "webpack.config.js" - - "tsconfig*.json" - workflow_dispatch: - -jobs: - browser-build-test: - name: Test Browser Builds - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Install pnpm - uses: pnpm/action-setup@v2 - with: - version: latest - - - name: Set up Node - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: "pnpm" - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build library - run: pnpm run build - - - name: Test with Vite - run: | - cd /tmp - npm create vite@latest test-app -- --template react-ts -y - cd test-app - npm install - npm install $GITHUB_WORKSPACE - echo "import { createClient } from '@deepgram/sdk';" > src/test.ts - echo "const client = createClient('test-key');" >> src/test.ts - echo "console.log('Deepgram client created:', client);" >> src/test.ts - echo "export { client };" >> src/test.ts - npm run build - - - name: Test with Create React App - run: | - cd /tmp - npx create-react-app test-cra --template typescript - cd test-cra - npm install $GITHUB_WORKSPACE - echo "import { createClient } from '@deepgram/sdk';" > src/test.ts - echo "const client = createClient('test-key');" >> src/test.ts - echo "console.log('Deepgram client created:', client);" >> src/test.ts - echo "export { client };" >> src/test.ts - npm run build - - - name: Test with plain webpack - run: | - cd /tmp - mkdir webpack-test && cd webpack-test - npm init -y - npm install webpack webpack-cli typescript ts-loader - npm install $GITHUB_WORKSPACE - echo "import { createClient } from '@deepgram/sdk';" > index.ts - echo "const client = createClient('test-key');" >> index.ts - echo "console.log('Deepgram client created:', client);" >> index.ts - echo '{"compilerOptions": {"target": "es5", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true}}' > tsconfig.json - echo "module.exports = { entry: './index.ts', module: { rules: [{ test: /\.ts$/, use: 'ts-loader' }] }, resolve: { extensions: ['.ts', '.js'] } };" > webpack.config.js - npx webpack --mode production diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..5834b384 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: ci + +on: [push] + +jobs: + compile: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up node + uses: actions/setup-node@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Install dependencies + run: pnpm install + + - name: Compile + run: pnpm build + + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up node + uses: actions/setup-node@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Install dependencies + run: pnpm install + + - name: Test + run: pnpm test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 00c4a235..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Release - -on: - push: - branches: - - main - - next - - rc - - beta - - alpha - workflow_dispatch: - -jobs: - release: - name: Release - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Install pnpm - uses: pnpm/action-setup@v2 - with: - version: latest - - - name: Set up Node - uses: actions/setup-node@v3 - with: - node-version-file: ".nvmrc" - cache: "pnpm" - - - name: Install dependencies and build - run: | - pnpm install --frozen-lockfile - pnpm run build - - - name: Create a release - run: pnpm dlx semantic-release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index ea94053f..72271e04 100644 --- a/.gitignore +++ b/.gitignore @@ -1,107 +1,3 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* +node_modules .DS_Store - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and *not* Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -docs/v2 +/dist \ No newline at end of file diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc deleted file mode 100644 index feb7e523..00000000 --- a/.markdownlint.jsonc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "default": true, - "line-length": false, - "no-bare-urls": false, - "no-duplicate-heading": false -} diff --git a/.npmignore b/.npmignore deleted file mode 100644 index e876efb8..00000000 --- a/.npmignore +++ /dev/null @@ -1,27 +0,0 @@ -*.log -npm-debug.log* - -# Coverage directory used by tools like istanbul -coverage -.nyc_output - -# Dependency directories -node_modules - -# npm package lock -package-lock.json -yarn.lock - -# project files -src -test -examples -example-next-js -umd_temp -CHANGELOG.md -.travis.yml -.editorconfig -.eslintignore -.eslintrc -.babelrc -.gitignore \ No newline at end of file diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 47ec7e17..00000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -node-options=--no-deprecation diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 728f7de5..00000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -22.9.0 diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 2c0e30b9..00000000 --- a/.prettierignore +++ /dev/null @@ -1,5 +0,0 @@ -.expo -.next -node_modules -package-lock.json -docker* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 466e1ad4..00000000 --- a/.prettierrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "trailingComma": "es5", - "tabWidth": 2, - "printWidth": 100 -} diff --git a/.releaserc.json b/.releaserc.json deleted file mode 100644 index 9ddd6c82..00000000 --- a/.releaserc.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "branches": [ - { "name": "main" }, - { "name": "next", "channel": "next", "prerelease": true }, - { "name": "rc", "channel": "rc", "prerelease": true }, - { "name": "beta", "channel": "beta", "prerelease": true }, - { "name": "alpha", "channel": "alpha", "prerelease": true } - ], - "plugins": [ - [ - "semantic-release-plugin-update-version-in-files", - { - "files": [ - "src/lib/version.ts", - "dist/main/lib/version.js", - "dist/main/lib/version.d.ts", - "dist/module/lib/version.js", - "dist/module/lib/version.d.ts", - "dist/umd/supabase.js" - ], - "placeholder": "0.0.0-automated" - } - ], - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/npm", - [ - "@semantic-release/github", - { - "successComment": false, - "releasedLabels": false, - "failTitle": false, - "addReleases": false - } - ] - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index bcadbc14..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "markdown.extension.toc.omittedFromToc": { - "README.md": ["# Deepgram JavaScript SDK"] - } -} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index f30c4563..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,131 +0,0 @@ -# Code of Conduct - -The Deepgram developer community is filled with amazing, clever and creative people, and we're excited for you to join us. Our goal is to create safe and inclusive spaces, have meaningful conversations, and explore ways to make sure that every voice is heard and understood. - -## Being a Good Community Member - -Because we prioritize creating a safe space for our members, we believe in actively working on how we, as individuals, can ensure a positive community environment through our own actions and mindsets. - -Every supportive community starts with each member. We feel it’s important to be open to others, respectful, and supportive. As part of the Deepgram community, please begin by thinking carefully about and agreeing with the following statements: - -- I will be welcoming to everyone at the table; -- I will be patient and open to learning from everyone around me; -- I will treat everyone with respect, because they deserve it; -- I will be mindful of the needs and boundaries of others; - -We strive to create a space where we learn and grow together. Here are some other key things you can do to make the community great: - -### BE HUMBLE - -People come from all different places, and it’s best not to make assumptions about what they think or feel. Approach others with curiosity and openness. We **all** have a lot to learn from each other. - -### BE HELPFUL - -If someone asks for help, consider jumping in. You don’t have to be an expert to talk through a problem, suggest a resource, or help find a solution. We all have something to contribute. - -### ENCOURAGE OTHERS - -There’s no one path to have a career in technology or to this community. Let’s engage others in ways that create opportunities for learning and fun for all of us. - -## Our Pledge - -Everyone who participates in our community must agree to abide by our Code of Conduct. By agreeing, you help create a welcoming, respectful, and friendly community based on respect and trust. We are committed to creating a harassment-free community. - -These rules will be strictly enforced in any and all of our official spaces, including direct messages, social media, and physical and virtual events. Everyone who participates in these spaces is required to agree to this community code. We also ask and expect community members to observe these rules anywhere the community is meeting (for example, online chats on unofficial platforms or event after-parties). - -## Our Standards - -### BE RESPECTFUL - -Exercise consideration and respect in your speech and actions. Be willing to accept and give feedback gracefully. - -Don’t make offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, race, ethnicity, immigration status, religion, experience level, socioeconomic status, nationality, or other identity markers. - -Additionally, don’t insult or demean others. This includes making unwelcome comments about a person’s lifestyle choices and practices, including things related to diet, health, parenting, drugs, or employment. It’s not okay to insult or demean others if it’s "just a joke." - -### BE WELCOMING AND OPEN - -Encourage others, be supportive and willing to listen, and be willing to learn from others’ perspectives and experiences. Lead with empathy and kindness. - -Don’t engage in gatekeeping behaviors, like questioning the intelligence or knowledge of others as a way to prove their credentials. And don’t exclude people for prejudicial reasons. - -### RESPECT PRIVACY - -Do not publish private communications without consent. Additionally, never disclose private aspects of a person’s personal identity without consent, except as necessary to protect them from intentional abuse. - -### RESPECT PERSONAL BOUNDARIES - -Do not introduce gratuitous or off-topic sexual images, languages, or behavior in spaces where they are not appropriate. Never make physical contact or simulated physical contact without consent or after a request to stop. Additionally, do not continue to message others about anything if they ask you to stop or leave them alone. - -#### BE A GOOD NEIGHBOR - -Contribute to the community in a positive and thoughtful way. Consider what’s best for the overall community. Do not make threats of violence, intimidate others, incite violence or intimidation against others, incite self-harm, stalk, follow, or otherwise harass others. Be mindful of your surroundings and of your fellow participants. - -Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential. - -## Additional rules for online spaces - -For Deepgram’s official online spaces, like our YouTube & Twitch chats, we have some additional rules. Any of the following behaviors can result in a ban without warning. - -### DON'T SPAM - -Don't spam. We'll ban you. - -### KEEP IT LEGAL - -If it’s illegal, it’s not allowed on our websites or in our online spaces. Please don’t share links to pirated material or other nefarious things. - -### NO TROLLING - -Please be earnest. Don’t use excessive sarcasm to annoy or undermine other people. And don’t bait them with bad faith comments or abuse. - -### PORNOGRAPHY AND OTHER NSFW STUFF - -Please don’t post it or link to it. It doesn’t belong in our online spaces. - -### FOUL AND GRAPHIC LANGUAGE - -Please do not use excessive curse words. Additionally, do not use graphic sexual or violent language — again, think of our spaces as places for people of all ages. - -## Enforcement & Reporting - -If you are being harassed by a member of the Deepgram developer community, if you observe someone else being harassed, or you experience actions or behaviors that are contrary to our Code of Conduct, please report the behavior using our [Code of Conduct Report Form](https://developers.deepgram.com/code-of-conduct/report-form/). - -### Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: - -#### 1. Correction - -**_Community Impact:_** Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. - -**_Consequence:_** A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. - -#### 2. Warning - -**_Community Impact:_** A violation through a single incident or series of actions. - -**_Consequence:_** A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. - -#### 3. Temporary Ban - -**_Community Impact:_** A serious violation of community standards, including sustained inappropriate behavior. - -**_Consequence:_** A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. - -#### 4. Permanent Ban - -**_Community Impact:_** Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. - -**_Consequence:_** A permanent ban from any sort of public interaction within the community. - -## Attribution - -This Code of Conduct is adapted from: - -- Contributor Covenant, version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct -- https://eventhandler.community/conduct/, which itself is inspired by Quest, who in turn provides credit to Scripto, the #botALLY Code of Conduct, the LGBTQ in Tech code of Conduct, and the XOXO Code of Conduct. - -Community Impact Guidelines, which were copied from InnerSource Commons, were inspired by Mozilla’s code of conduct enforcement ladder. - -For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af130273..fe5bc2f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,50 +1,133 @@ -# Contributing Guidelines - -Want to contribute to this project? We ❤️ it! - -Here are a few types of contributions that we would be interested in hearing about. - -- Bug fixes - - If you find a bug, please first report it using Github Issues. - - Issues that have already been identified as a bug will be labeled `🐛 bug`. - - If you'd like to submit a fix for a bug, send a Pull Request from your own fork and mention the Issue number. - - Include a test that isolates the bug and verifies that it was fixed. -- New Features - - If you'd like to accomplish something in the extension that it doesn't already do, describe the problem in a new Github Issue. - - Issues that have been identified as a feature request will be labeled `✨ enhancement`. - - If you'd like to implement the new feature, please wait for feedback from the project maintainers before spending - too much time writing the code. In some cases, `✨ enhancement`s may not align well with the project objectives at - the time. -- Tests, Documentation, Miscellaneous - - If you think the test coverage could be improved, the documentation could be clearer, you've got an alternative - implementation of something that may have more advantages, or any other change we would still be glad hear about - it. - - If its a trivial change, go ahead and send a Pull Request with the changes you have in mind - - If not, open a Github Issue to discuss the idea first. -- Snippets - - To add snippets: - - Add a directory in the `snippets` folder with the name of the language. - - Add one or more files in the language directory with snippets. - - Update the `package.json` to include the snippets you added. - -We also welcome anyone to work on any existing issues with the `👋🏽 good first issue` tag. - -## Requirements - -For a contribution to be accepted: - -- The test suite must be complete and pass -- Code must follow existing styling conventions -- Commit messages must be descriptive. Related issues should be mentioned by number. - -If the contribution doesn't meet these criteria, a maintainer will discuss it with you on the Issue. You can still -continue to add more commits to the branch you have sent the Pull Request from. - -## How To - -1. Fork this repository on GitHub. -1. Clone/fetch your fork to your local development machine. -1. Create a new branch (e.g. `issue-12`, `feat.add_foo`, etc) and check it out. -1. Make your changes and commit them. (Did the tests pass? No linting errors?) -1. Push your new branch to your fork. (e.g. `git push myname issue-12`) -1. Open a Pull Request from your new branch to the original fork's `main` branch. +# Contributing + +Thanks for your interest in contributing to this SDK! This document provides guidelines for contributing to the project. + +## Getting Started + +### Prerequisites + +- Node.js 20 or higher +- pnpm package manager + +### Installation + +Install the project dependencies: + +```bash +pnpm install +``` + +### Building + +Build the project: + +```bash +pnpm build +``` + +### Testing + +Run the test suite: + +```bash +pnpm test +``` + +Run specific test types: +- `pnpm test:unit` - Run unit tests +- `pnpm test:wire` - Run wire/integration tests + +### Linting and Formatting + +Check code style: + +```bash +pnpm run lint +pnpm run format:check +``` + +Fix code style issues: + +```bash +pnpm run lint:fix +pnpm run format:fix +``` + +Or use the combined check command: + +```bash +pnpm run check:fix +``` + +## About Generated Code + +**Important**: Most files in this SDK are automatically generated by [Fern](https://buildwithfern.com) from the API definition. Direct modifications to generated files will be overwritten the next time the SDK is generated. + +### Generated Files + +The following directories contain generated code: +- `src/api/` - API client classes and types +- `src/serialization/` - Serialization/deserialization logic +- Most TypeScript files in `src/` + +### How to Customize + +If you need to customize the SDK, you have two options: + +#### Option 1: Use `.fernignore` + +For custom code that should persist across SDK regenerations: + +1. Create a `.fernignore` file in the project root +2. Add file patterns for files you want to preserve (similar to `.gitignore` syntax) +3. Add your custom code to those files + +Files listed in `.fernignore` will not be overwritten when the SDK is regenerated. + +For more information, see the [Fern documentation on custom code](https://buildwithfern.com/learn/sdks/overview/custom-code). + +#### Option 2: Contribute to the Generator + +If you want to change how code is generated for all users of this SDK: + +1. The TypeScript SDK generator lives in the [Fern repository](https://github.com/fern-api/fern) +2. Generator code is located at `generators/typescript/sdk/` +3. Follow the [Fern contributing guidelines](https://github.com/fern-api/fern/blob/main/CONTRIBUTING.md) +4. Submit a pull request with your changes to the generator + +This approach is best for: +- Bug fixes in generated code +- New features that would benefit all users +- Improvements to code generation patterns + +## Making Changes + +### Workflow + +1. Create a new branch for your changes +2. Make your modifications +3. Run tests to ensure nothing breaks: `pnpm test` +4. Run linting and formatting: `pnpm run check:fix` +5. Build the project: `pnpm build` +6. Commit your changes with a clear commit message +7. Push your branch and create a pull request + +### Commit Messages + +Write clear, descriptive commit messages that explain what changed and why. + +### Code Style + +This project uses automated code formatting and linting. Run `pnpm run check:fix` before committing to ensure your code meets the project's style guidelines. + +## Questions or Issues? + +If you have questions or run into issues: + +1. Check the [Fern documentation](https://buildwithfern.com) +2. Search existing [GitHub issues](https://github.com/fern-api/fern/issues) +3. Open a new issue if your question hasn't been addressed + +## License + +By contributing to this project, you agree that your contributions will be licensed under the same license as the project. diff --git a/LICENSE b/LICENSE index 458cd0d3..853b289d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Deepgram +Copyright (c) 2025 Deepgram. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 80795d56..067b7dfa 100644 --- a/README.md +++ b/README.md @@ -1,1067 +1,676 @@ -# Deepgram JavaScript SDK - -[![Static Badge](https://img.shields.io/badge/%24__-Discord-blue?logo=discord&logoColor=white&link=https%3A%2F%2Fdiscord.gg%2Fdeepgram)](https://discord.gg/deepgram) [![CI](https://github.com/deepgram/node-sdk/actions/workflows/CI.yml/badge.svg)](https://github.com/deepgram/node-sdk/actions/workflows/CI.yml) [![npm (scoped)](https://img.shields.io/npm/v/@deepgram/sdk)](https://www.npmjs.com/package/@deepgram/sdk) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg?style=flat-rounded)](CODE_OF_CONDUCT.md) - -> 🎯 **Development Setup**: This project uses [Corepack](https://nodejs.org/api/corepack.html) for package manager consistency. Run `corepack enable` once, then use `pnpm` commands normally. See [DEVELOPMENT.md](./DEVELOPMENT.md) for details. - - - -- [Documentation](#documentation) -- [Migrating from earlier versions](#migrating-from-earlier-versions) - - [V2 to V3](#v2-to-v3) - - [V3.\* to V3.4](#v3-to-v34) - - [V3.\* to V4](#v3-to-v4) -- [Installation](#installation) - - [UMD](#umd) - - [ESM](#esm) -- [Authentication](#authentication) - - [1. API Key Authentication (Recommended)](#1-api-key-authentication-recommended) - - [2. Access Token Authentication](#2-access-token-authentication) - - [3. Proxy Authentication](#3-proxy-authentication) - - [Getting Credentials](#getting-credentials) - - [API Keys](#api-keys) - - [Access Tokens](#access-tokens) - - [Environment Variables](#environment-variables) - - [Getting an API Key](#getting-an-api-key) -- [Scoped Configuration](#scoped-configuration) - - [Global Defaults](#global-defaults) - - [Namespace-specific Configurations](#namespace-specific-configurations) - - [Transport Options](#transport-options) - - [Examples](#examples) - - [Change the API url used for all SDK methods](#change-the-api-url-used-for-all-sdk-methods) - - [Change the API url used for the Voice Agent websocket](#change-the-api-url-used-for-the-voice-agent-websocket) - - [Change the API url used for transcription only](#change-the-api-url-used-for-transcription-only) - - [Override fetch transmitter](#override-fetch-transmitter) - - [Proxy requests in the browser](#proxy-requests-in-the-browser) - - [Set custom headers for fetch](#set-custom-headers-for-fetch) -- [Browser Usage](#browser-usage) -- [Transcription](#transcription) - - [Remote Files](#remote-files) - - [Local Files](#local-files) - - [Callbacks / Async](#callbacks--async) - - [Live Transcription (WebSocket)](#live-transcription-websocket) - - [Captions](#captions) -- [Voice Agent](#voice-agent) -- [Text to Speech](#text-to-speech) - - [Single-Request](#single-request) - - [Continuous Text Stream (WebSocket)](#continuous-text-stream-websocket) -- [Text Intelligence](#text-intelligence) -- [Token Management](#token-management) - - [Get Token Details](#get-token-details) - - [Grant Access Token](#grant-access-token) -- [Projects](#projects) - - [Get Projects](#get-projects) - - [Get Project](#get-project) - - [Update Project](#update-project) - - [Delete Project](#delete-project) -- [Keys](#keys) - - [List Keys](#list-keys) - - [Get Key](#get-key) - - [Create Key](#create-key) - - [Delete Key](#delete-key) -- [Members](#members) - - [Get Members](#get-members) - - [Remove Member](#remove-member) -- [Scopes](#scopes) - - [Get Member Scopes](#get-member-scopes) - - [Update Scope](#update-scope) -- [Invitations](#invitations) - - [List Invites](#list-invites) - - [Send Invite](#send-invite) - - [Delete Invite](#delete-invite) - - [Leave Project](#leave-project) -- [Usage](#usage) - - [Get All Requests](#get-all-requests) - - [Get Request](#get-request) - - [Summarize Usage](#summarize-usage) - - [Get Fields](#get-fields) - - [Summarize Usage (Deprecated)](#summarize-usage-1) -- [Billing](#billing) - - [Get All Balances](#get-all-balances) - - [Get Balance](#get-balance) -- [Models](#models) - - [Get All Models](#get-all-models) - - [Get All Project Models](#get-all-project-models) - - [Get Model](#get-model) -- [On-Prem APIs](#on-prem-apis) - - [List On-Prem credentials](#list-on-prem-credentials) - - [Get On-Prem credentials](#get-on-prem-credentials) - - [Create On-Prem credentials](#create-on-prem-credentials) - - [Delete On-Prem credentials](#delete-on-prem-credentials) -- [Backwards Compatibility](#backwards-compatibility) -- [Development and Contributing](#development-and-contributing) - - [Debugging and making changes locally](#debugging-and-making-changes-locally) -- [Getting Help](#getting-help) - +# Deepgram TypeScript SDK -## Documentation - -You can learn more about the Deepgram API at [developers.deepgram.com](https://developers.deepgram.com/docs). - -## Migrating from earlier versions - -### V2 to V3 +![Built with Fern](https://img.shields.io/badge/%F0%9F%8C%BF-Built%20with%20Fern-brightgreen) +[![NPM version](https://img.shields.io/npm/v/@deepgram/sdk)](https://www.npmjs.com/package/@deepgram/sdk) +[![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE) -We have published [a migration guide on our docs](https://developers.deepgram.com/docs/js-sdk-v2-to-v3-migration-guide), showing how to move from v2 to v3. +The official TypeScript SDK for Deepgram's automated speech recognition, text-to-speech, and language understanding APIs. Power your applications with world-class speech and Language AI models. -### V3.\* to V3.4 +## Documentation -We recommend using only documented interfaces, as we strictly follow semantic versioning (semver) and breaking changes may occur for undocumented interfaces. To ensure compatibility, consider pinning your versions if you need to use undocumented interfaces. +Comprehensive API documentation and guides are available at [developers.deepgram.com](https://developers.deepgram.com). -### V3.\* to V4 +### Migrating From Earlier Versions -The Voice Agent interfaces have been updated to use the new Voice Agent V1 API. Please refer to our [Documentation](https://developers.deepgram.com/docs/voice-agent-v1-migration) on Migration to new V1 Agent API. +- [v2 to v3+](./docs/Migrating-v2-to-v3.md) +- [v3+ to v5](./docs/Migrating-v3-to-v5.md) (current) ## Installation -You can install this SDK directly from [[npm](https://www.npmjs.com/package/@deepgram/sdk)](https://www.npmjs.com/package/@deepgram/sdk). - -```bash -npm install @deepgram/sdk -``` - -or - -```bash -pnpm install @deepgram/sdk -``` - -or +Install the Deepgram TypeScript SDK using npm: -```bash -yarn add @deepgram/sdk +```sh +npm i -s @deepgram/sdk ``` -### UMD - -You can now use plain ` -``` +## Reference -or even: +- **[API Reference](./reference.md)** - Complete reference for all SDK methods and parameters +- **[WebSocket Reference](./websockets-reference.md)** - Detailed documentation for real-time WebSocket connections -```html - -``` - -Then you can use it from a global deepgram variable: - -```html - -``` - -### ESM +## Usage -You can now use type="module" ` +const client = new DeepgramClient({ apiKey: "YOUR_API_KEY" }); +await client.listen.v1.media.transcribeFile(createReadStream("path/to/file"), {}); ``` ## Authentication -The Deepgram SDK supports three authentication methods: +The Deepgram SDK supports two authentication methods: -### 1. API Key Authentication (Recommended) + -### 2. Access Token Authentication +### API Key Authentication -Uses `Bearer` scheme in Authorization header. Access tokens are temporary (30-second TTL) and must be obtained using an API key. +Use your Deepgram API key for server-side applications: -```js -import { createClient } from "@deepgram/sdk"; +```typescript +import { DeepgramClient } from "@deepgram/sdk"; -// Must use accessToken property in options object -const deepgramClient = createClient({ accessToken: "YOUR_ACCESS_TOKEN" }); +// Explicit API key +const client = new DeepgramClient({ apiKey: "YOUR_API_KEY" }); -// Or use environment variable (DEEPGRAM_ACCESS_TOKEN) -const deepgramClient = createClient(); -``` - -### 3. Proxy Authentication - -For browser environments or custom proxy setups. Pass `"proxy"` as the API key. - -```js -import { createClient } from "@deepgram/sdk"; - -const deepgramClient = createClient("proxy", { - global: { fetch: { options: { proxy: { url: "http://localhost:8080" } } } }, -}); +// Or via environment variable DEEPGRAM_API_KEY +const client = new DeepgramClient(); ``` -> **Important**: Your proxy must set the `Authorization: token DEEPGRAM_API_KEY` header and forward requests to Deepgram's API. - -### Getting Credentials - -#### API Keys - -Create API keys via the Management API: - -```js -const { result, error } = await deepgramClient.manage.createProjectKey(projectId, { - comment: "My API key", - scopes: ["usage:write"], -}); -``` - -**Endpoint**: `POST https://api.deepgram.com/v1/projects/:projectId/keys` - -#### Access Tokens - -Generate temporary access tokens (requires existing API key): - -```js -const { result, error } = await deepgramClient.auth.grantToken(); -// Returns: { access_token: string, expires_in: 30 } -``` - -**Endpoint**: `POST https://api.deepgram.com/v1/auth/grant` - ### Environment Variables -The SDK automatically checks for credentials in this priority order: - -1. `DEEPGRAM_ACCESS_TOKEN` (highest priority) -2. `DEEPGRAM_API_KEY` (fallback) - -### Getting an API Key - -🔑 To access the Deepgram API you will need a [free Deepgram API Key](https://console.deepgram.com/signup?jump=keys). - -## Scoped Configuration - -The SDK supports scoped configuration. You'll be able to configure various aspects of each namespace of the SDK from the initialization. Below outlines a flexible and customizable configuration system for the Deepgram SDK. Here's how the namespace configuration works: - -### Global Defaults - -- The `global` namespace serves as the foundational configuration applicable across all other namespaces unless overridden. -- Includes general settings like URL and headers applicable for all API calls. -- If no specific configurations are provided for other namespaces, the `global` defaults are used. - -### Namespace-specific Configurations - -- Each namespace (`listen`, `manage`, `onprem`, `read`, `speak`) can have its specific configurations which override the `global` settings within their respective scopes. -- Allows for detailed control over different parts of the application interacting with various Deepgram API endpoints. - -### Transport Options - -- Configurations for both `fetch` and `websocket` can be specified under each namespace, allowing different transport mechanisms for different operations. -- For example, the `fetch` configuration can have its own URL and proxy settings distinct from the `websocket`. -- The generic interfaces define a structure for transport options which include a client (like a `fetch` or `WebSocket` instance) and associated options (like headers, URL, proxy settings). - -This configuration system enables robust customization where defaults provide a foundation, but every aspect of the client's interaction with the API can be finely controlled and tailored to specific needs through namespace-specific settings. This enhances the maintainability and scalability of the application by localizing configurations to their relevant contexts. - -### Examples +The SDK automatically discovers credentials from these environment variables: -#### Change the API url used for all SDK methods + -Useful for using different API environments (for e.g. beta). +- `DEEPGRAM_API_KEY` - Your Deepgram API key -```js -import { createClient } from "@deepgram/sdk"; -// - or - -// const { createClient } = require("@deepgram/sdk"); +**Precedence:** Explicit parameters > Environment variables -const deepgramClient = createClient(DEEPGRAM_API_KEY, { - global: { fetch: { options: { url: "https://api.beta.deepgram.com" } } }, -}); -``` - -#### Change the API url used for the Voice Agent websocket - -Useful for using a voice agent proxy (for e.g. 3rd party provider auth). - -```js -import { createClient } from "@deepgram/sdk"; -// - or - -// const { createClient } = require("@deepgram/sdk"); - -const deepgramClient = createClient(DEEPGRAM_API_KEY, { - global: { websocket: { options: { url: "ws://localhost:8080" } } }, -}); -``` - -#### Change the API url used for transcription only - -Useful for on-prem installations. Only affects requests to `/listen` endpoints. - -```js -import { createClient } from "@deepgram/sdk"; -// - or - -// const { createClient } = require("@deepgram/sdk"); - -const deepgramClient = createClient(DEEPGRAM_API_KEY, { - listen: { fetch: { options: { url: "http://localhost:8080" } } }, -}); -``` +## Request And Response Types -#### Override fetch transmitter +The SDK exports all request and response types as TypeScript interfaces. Simply import them with the +following namespace: -Useful for providing a custom http client. +```typescript +import { Deepgram } from "@deepgram/sdk"; -```js -import { createClient } from "@deepgram/sdk"; -// - or - -// const { createClient } = require("@deepgram/sdk"); - -const yourFetch = async () => { - return Response("...etc"); +const request: Deepgram.GrantV1Request = { + ... }; - -const deepgramClient = createClient(DEEPGRAM_API_KEY, { - global: { fetch: { client: yourFetch } }, -}); -``` - -#### Proxy requests in the browser - -This SDK now works in the browser. If you'd like to make REST-based requests (pre-recorded transcription, on-premise, and management requests), then you'll need to use a proxy as we do not support custom CORS origins on our API. To set up your proxy, you configure the SDK like so: - -```js -import { createClient } from "@deepgram/sdk"; - -const deepgramClient = createClient("proxy", { - global: { fetch: { options: { proxy: { url: "http://localhost:8080" } } } }, -}); -``` - -> Important: You must pass `"proxy"` as your API key, and use the proxy to set the `Authorization` header to your Deepgram API key. - -Your proxy service should replace the Authorization header with `Authorization: token ` and return results verbatim to the SDK. - -Check out our example Node-based proxy here: [Deepgram Node Proxy](https://github.com/deepgram-devs/deepgram-node-proxy). - -#### Set custom headers for fetch - -Useful for many things. - -```js -import { createClient } from "@deepgram/sdk"; - -const deepgramClient = createClient({ - global: { fetch: { options: { headers: { "x-custom-header": "foo" } } } }, -}); -``` - -## Browser Usage - -The SDK works in modern browsers with some considerations: - -### WebSocket Features (Full Support) - -- **Live Transcription**: ✅ Direct connection to `wss://api.deepgram.com` -- **Voice Agent**: ✅ Direct connection to `wss://agent.deepgram.com` -- **Live Text-to-Speech**: ✅ Direct connection to `wss://api.deepgram.com` - -### REST API Features (Proxy Required) - -- **Pre-recorded Transcription**: ⚠️ Requires proxy due to CORS -- **Text Intelligence**: ⚠️ Requires proxy due to CORS -- **Management APIs**: ⚠️ Requires proxy due to CORS - -### Setup Options - -#### Option 1: CDN (UMD) - -```html - - -``` - -#### Option 2: CDN (ESM) - -```html - -``` - -#### Option 3: Proxy for REST APIs - -See [proxy requests in the browser](#proxy-requests-in-the-browser) for REST API access. - -## Transcription - -### Remote Files - -Transcribe audio from a URL. - -```js -const { result, error } = await deepgramClient.listen.prerecorded.transcribeUrl( - { url: "https://dpgr.am/spacewalk.wav" }, - { - model: "nova-3", - // pre-recorded transcription options - } -); -``` - -**API Endpoint**: `POST https://api.deepgram.com/v1/listen` - -[See our API reference for more info](https://developers.deepgram.com/reference/speech-to-text-api/listen). - -### Local Files - -Transcribe audio from a file. - -```js -const { result, error } = await deepgramClient.listen.prerecorded.transcribeFile( - fs.createReadStream("./examples/spacewalk.wav"), - { - model: "nova-3", - // pre-recorded transcription options - } -); ``` -**API Endpoint**: `POST https://api.deepgram.com/v1/listen` - -[See our API reference for more info](https://developers.deepgram.com/reference/speech-to-text-api/listen). - -### Callbacks / Async +## Exception Handling -We have a `Callback` version of both `transcribeFile` and `transcribeUrl`, which simply takes a `CallbackUrl` class. +When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error +will be thrown. -```js -import { CallbackUrl } from "@deepgram/sdk"; +```typescript +import { DeepgramError } from "@deepgram/sdk"; -const { result, error } = await deepgramClient.listen.prerecorded.transcribeUrlCallback( - { url: "https://dpgr.am/spacewalk.wav" }, - new CallbackUrl("http://callback/endpoint"), - { - model: "nova-3", - // pre-recorded transcription options - } -); +try { + await client.listen.v1.media.transcribeFile(...); +} catch (err) { + if (err instanceof DeepgramError) { + console.log(err.statusCode); + console.log(err.message); + console.log(err.body); + console.log(err.rawResponse); + } +} ``` -**API Endpoint**: `POST https://api.deepgram.com/v1/listen?callback=http://callback/endpoint` +## File Uploads -[See our API reference for more info](https://developers.deepgram.com/reference/speech-to-text-api/listen). +You can upload files using the client: -### Live Transcription (WebSocket) +```typescript +import { createReadStream } from "fs"; -Connect to our websocket and transcribe live streaming audio. - -```js -const deepgramConnection = deepgramClient.listen.live({ - model: "nova-3", - // live transcription options -}); - -deepgramConnection.on(LiveTranscriptionEvents.Open, () => { - deepgramConnection.on(LiveTranscriptionEvents.Transcript, (data) => { - console.log(data); - }); - - source.addListener("got-some-audio", async (event) => { - deepgramConnection.send(event.raw_audio_data); - }); -}); +await client.listen.v1.media.transcribeFile(createReadStream("path/to/file"), ...); +await client.listen.v1.media.transcribeFile(new ReadableStream(), ...); +await client.listen.v1.media.transcribeFile(Buffer.from('binary data'), ...); +await client.listen.v1.media.transcribeFile(new Blob(['binary data'], { type: 'audio/mpeg' }), ...); +await client.listen.v1.media.transcribeFile(new File(['binary data'], 'file.mp3'), ...); +await client.listen.v1.media.transcribeFile(new ArrayBuffer(8), ...); +await client.listen.v1.media.transcribeFile(new Uint8Array([0, 1, 2]), ...); ``` -**WebSocket Endpoint**: `wss://api.deepgram.com/v1/listen` - -[See our API reference for more info](https://developers.deepgram.com/reference/speech-to-text-api/listen-streaming). +The client accepts a variety of types for file upload parameters: -### Captions +- Stream types: `fs.ReadStream`, `stream.Readable`, and `ReadableStream` +- Buffered types: `Buffer`, `Blob`, `File`, `ArrayBuffer`, `ArrayBufferView`, and `Uint8Array` -Convert deepgram transcriptions to captions. +### Metadata -```js -import { webvtt, srt } from "@deepgram/sdk"; +You can configure metadata when uploading a file: -const { result, error } = await deepgramClient.listen.prerecorded.transcribeUrl({ - model: "nova-3", - // pre-recorded transcription options -}); - -const vttResult = webvtt(result); -const srtResult = srt(result); +```typescript +const file: Uploadable.WithMetadata = { + data: createReadStream("path/to/file"), + filename: "my-file", // optional + contentType: "audio/mpeg", // optional + contentLength: 1949, // optional +}; ``` -[See our standalone captions library for more information](https://github.com/deepgram/deepgram-node-captions). - -## Voice Agent - -Configure a Voice Agent. - -```js -import { AgentEvents } from "@deepgram/sdk"; - -// Create an agent connection -const deepgramConnection = deepgramClient.agent(); - -// Set up event handlers -deepgramConnection.on(AgentEvents.Open, () => { - console.log("Connection opened"); +Alternatively, you can upload a file directly from a file path: - // Set up event handlers - deepgramConnection.on(AgentEvents.ConversationText, (data) => { - console.log(data); - }); - - // other events - - // Configure the agent once connection is established - deepgramConnection.configure({ - // agent configuration - }); - - // etc... -}); +```typescript +const file: Uploadable.FromPath = { + path: "path/to/file", + filename: "my-file", // optional + contentType: "audio/mpeg", // optional + contentLength: 1949, // optional +}; ``` -**WebSocket Endpoint**: `wss://agent.deepgram.com/v1/agent/converse` - -[See our API reference for more info](https://developers.deepgram.com/reference/voice-agent-api/agent). +The metadata is used to set the `Content-Length`, `Content-Type`, and `Content-Disposition` headers. If not provided, the client will attempt to determine them automatically. +For example, `fs.ReadStream` has a `path` property which the SDK uses to retrieve the file size from the filesystem without loading it into memory. -## Text to Speech +## Binary Response -### Single-Request +You can consume binary data from endpoints using the `BinaryResponse` type which lets you choose how to consume the data: -Convert text into speech using the REST API. - -```js -const { result } = await deepgramClient.speak.request( - { text }, - { - model: "aura-2-thalia-en", - // text to speech options - } -); +```typescript +const response = await client.speak.v1.audio.generate(...); +const stream: ReadableStream = response.stream(); +// const arrayBuffer: ArrayBuffer = await response.arrayBuffer(); +// const blob: Blob = response.blob(); +// const bytes: Uint8Array = response.bytes(); +// You can only use the response body once, so you must choose one of the above methods. +// If you want to check if the response body has been used, you can use the following property. +const bodyUsed = response.bodyUsed; ``` -**API Endpoint**: `POST https://api.deepgram.com/v1/speak` - -[See our API reference for more info](https://developers.deepgram.com/reference/text-to-speech-api/speak). +
+Save binary response to a file -### Continuous Text Stream (WebSocket) +
+
+Node.js -Connect to our websocket and send a continuous text stream to generate speech. - -```js -const deepgramConnection = deepgramClient.speak.live({ - model: "aura-2-thalia-en", - // live text to speech options -}); +
+
+ReadableStream (most-efficient) -deepgramConnection.on(LiveTTSEvents.Open, () => { - console.log("Connection opened"); +```ts +import { createWriteStream } from 'fs'; +import { Readable } from 'stream'; +import { pipeline } from 'stream/promises'; - // Send text data for TTS synthesis - deepgramConnection.sendText(text); +const response = await client.speak.v1.audio.generate(...); - // Send Flush message to the server after sending the text - deepgramConnection.flush(); +const stream = response.stream(); +const nodeStream = Readable.fromWeb(stream); +const writeStream = createWriteStream('path/to/file'); - deepgramConnection.on(LiveTTSEvents.Close, () => { - console.log("Connection closed"); - }); -}); +await pipeline(nodeStream, writeStream); ``` -**WebSocket Endpoint**: `wss://api.deepgram.com/v1/speak` - -[See our API reference for more info](https://developers.deepgram.com/reference/text-to-speech-api/speak-streaming). +
+
-## Text Intelligence +
+
+ArrayBuffer -Analyze text using our intelligence AI features. +```ts +import { writeFile } from 'fs/promises'; -```js -const text = `The history of the phrase 'The quick brown fox jumps over the -lazy dog'. The earliest known appearance of the phrase was in The Boston -Journal...`; +const response = await client.speak.v1.audio.generate(...); -const { result, error } = await deepgramClient.read.analyzeText( - { text }, - { - language: "en", - // text intelligence options - } -); +const arrayBuffer = await response.arrayBuffer(); +await writeFile('path/to/file', Buffer.from(arrayBuffer)); ``` -**API Endpoint**: `POST https://api.deepgram.com/v1/read` - -[See our API reference for more info](https://developers.deepgram.com/reference/text-intelligence-api/text-read). +
+
-## Token Management +
+
+Blob -### Get Token Details +```ts +import { writeFile } from 'fs/promises'; -Retrieves the details of the current authentication token. +const response = await client.speak.v1.audio.generate(...); -```js -const { result, error } = await deepgramClient.manage.getTokenDetails(); +const blob = await response.blob(); +const arrayBuffer = await blob.arrayBuffer(); +await writeFile('output.bin', Buffer.from(arrayBuffer)); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/auth/token` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/authentication) +
+
+Bytes (UIntArray8) -### Grant Access Token +```ts +import { writeFile } from 'fs/promises'; -Creates a temporary access token with a 30-second TTL. Requires an existing API key for authentication. +const response = await client.speak.v1.audio.generate(...); -```js -// Create a temporary access token -const { result, error } = await deepgramClient.auth.grantToken(); -// Returns: { access_token: string, expires_in: 30 } - -// Use the access token in a new client instance -const tempClient = createClient({ accessToken: result.access_token }); +const bytes = await response.bytes(); +await writeFile('path/to/file', bytes); ``` -**API Endpoint**: `POST https://api.deepgram.com/v1/auth/grant` - -> **Important**: You _must_ pass an `accessToken` property to use a temporary token. Passing the token as a raw string will treat it as an API key and use the incorrect authorization scheme. - -[See our API reference for more info](https://developers.deepgram.com/reference/token-based-auth-api/grant-token). - -## Projects - -### Get Projects - -Returns all projects accessible by the API key. +
+
-```js -const { result, error } = await deepgramClient.manage.getProjects(); -``` - -**API Endpoint**: `GET https://api.deepgram.com/v1/projects` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/get-projects). +
+
+Bun -### Get Project +
+
+ReadableStream (most-efficient) -Retrieves a specific project based on the provided project_id. +```ts +const response = await client.speak.v1.audio.generate(...); -```js -const { result, error } = await deepgramClient.manage.getProject(projectId); +const stream = response.stream(); +await Bun.write('path/to/file', stream); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/get-project). +
+
+ArrayBuffer -### Update Project +```ts +const response = await client.speak.v1.audio.generate(...); -Update a project. - -```js -const { result, error } = await deepgramClient.manage.updateProject(projectId, options); +const arrayBuffer = await response.arrayBuffer(); +await Bun.write('path/to/file', arrayBuffer); ``` -**API Endpoint**: `PATCH https://api.deepgram.com/v1/projects/:projectId` - -[See our API reference for more info](https://developers.deepgram.com/reference/update-project). +
+
-### Delete Project +
+
+Blob -Delete a project. +```ts +const response = await client.speak.v1.audio.generate(...); -```js -const { error } = await deepgramClient.manage.deleteProject(projectId); +const blob = await response.blob(); +await Bun.write('path/to/file', blob); ``` -**API Endpoint**: `DELETE https://api.deepgram.com/v1/projects/:projectId` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/delete-project). +
+
+Bytes (UIntArray8) -## Keys +```ts +const response = await client.speak.v1.audio.generate(...); -### List Keys - -Retrieves all keys associated with the provided project_id. - -```js -const { result, error } = await deepgramClient.manage.getProjectKeys(projectId); +const bytes = await response.bytes(); +await Bun.write('path/to/file', bytes); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/keys` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/list-keys). +
+
-### Get Key +
+
+Deno -Retrieves a specific key associated with the provided project_id. +
+
+ReadableStream (most-efficient) -```js -const { result, error } = await deepgramClient.manage.getProjectKey(projectId, projectKeyId); -``` +```ts +const response = await client.speak.v1.audio.generate(...); -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/keys/:keyId` - -[See our API reference for more info](https://developers.deepgram.com/reference/get-key). - -### Create Key - -Creates an API key with the provided scopes. - -```js -const { result, error } = await deepgramClient.manage.createProjectKey(projectId, { - comment: "My API key", - scopes: ["usage:write"], // Required: array of scope strings - tags: ["production"], // Optional: array of tag strings - time_to_live_in_seconds: 86400, // Optional: TTL in seconds - // OR use expiration_date: "2024-12-31T23:59:59Z" // Optional: ISO date string -}); +const stream = response.stream(); +const file = await Deno.open('path/to/file', { write: true, create: true }); +await stream.pipeTo(file.writable); ``` -**API Endpoint**: `POST https://api.deepgram.com/v1/projects/:projectId/keys` - -[See our API reference for more info](https://developers.deepgram.com/reference/create-key). +
+
-### Delete Key +
+
+ArrayBuffer -Deletes a specific key associated with the provided project_id. +```ts +const response = await client.speak.v1.audio.generate(...); -```js -const { error } = await deepgramClient.manage.deleteProjectKey(projectId, projectKeyId); +const arrayBuffer = await response.arrayBuffer(); +await Deno.writeFile('path/to/file', new Uint8Array(arrayBuffer)); ``` -**API Endpoint**: `DELETE https://api.deepgram.com/v1/projects/:projectId/keys/:keyId` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/delete-key). +
+
+Blob -## Members +```ts +const response = await client.speak.v1.audio.generate(...); -### Get Members - -Retrieves account objects for all of the accounts in the specified project_id. - -```js -const { result, error } = await deepgramClient.manage.getProjectMembers(projectId); +const blob = await response.blob(); +const arrayBuffer = await blob.arrayBuffer(); +await Deno.writeFile('path/to/file', new Uint8Array(arrayBuffer)); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/members` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/get-members). +
+
+Bytes (UIntArray8) -### Remove Member +```ts +const response = await client.speak.v1.audio.generate(...); -Removes member account for specified member_id. - -```js -const { error } = await deepgramClient.manage.removeProjectMember(projectId, projectMemberId); +const bytes = await response.bytes(); +await Deno.writeFile('path/to/file', bytes); ``` -**API Endpoint**: `DELETE https://api.deepgram.com/v1/projects/:projectId/members/:memberId` - -[See our API reference for more info](https://developers.deepgram.com/reference/remove-member). - -## Scopes - -### Get Member Scopes - -Retrieves scopes of the specified member in the specified project. +
+
-```js -const { result, error } = await deepgramClient.manage.getProjectMemberScopes( - projectId, - projectMemberId -); -``` +
+
-**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/members/:memberId/scopes` +
+
+Browser -[See our API reference for more info](https://developers.deepgram.com/reference/get-member-scopes). +
+
+Blob (most-efficient) -### Update Scope +```ts +const response = await client.speak.v1.audio.generate(...); -Updates the scope for the specified member in the specified project. +const blob = await response.blob(); +const url = URL.createObjectURL(blob); -```js -const { result, error } = await deepgramClient.manage.updateProjectMemberScope( - projectId, - projectMemberId, - options -); +// trigger download +const a = document.createElement('a'); +a.href = url; +a.download = 'filename'; +a.click(); +URL.revokeObjectURL(url); ``` -**API Endpoint**: `PUT https://api.deepgram.com/v1/projects/:projectId/members/:memberId/scopes` - -[See our API reference for more info](https://developers.deepgram.com/reference/update-scope). +
+
-## Invitations +
+
+ReadableStream -### List Invites +```ts +const response = await client.speak.v1.audio.generate(...); -Retrieves all invitations associated with the provided project_id. - -```js -const { result, error } = await deepgramClient.manage.getProjectInvites(projectId); -``` +const stream = response.stream(); +const reader = stream.getReader(); +const chunks = []; -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/invites` +while (true) { + const { done, value } = await reader.read(); + if (done) break; + chunks.push(value); +} -[See our API reference for more info](https://developers.deepgram.com/reference/list-invites). +const blob = new Blob(chunks); +const url = URL.createObjectURL(blob); -### Send Invite - -Sends an invitation to the provided email address. - -```js -const { result, error } = await deepgramClient.manage.sendProjectInvite(projectId, options); +// trigger download +const a = document.createElement('a'); +a.href = url; +a.download = 'filename'; +a.click(); +URL.revokeObjectURL(url); ``` -**API Endpoint**: `POST https://api.deepgram.com/v1/projects/:projectId/invites` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/send-invites). +
+
+ArrayBuffer -### Delete Invite +```ts +const response = await client.speak.v1.audio.generate(...); -Removes the specified invitation from the project. +const arrayBuffer = await response.arrayBuffer(); +const blob = new Blob([arrayBuffer]); +const url = URL.createObjectURL(blob); -```js -const { error } = await deepgramClient.manage.deleteProjectInvite(projectId, email); +// trigger download +const a = document.createElement('a'); +a.href = url; +a.download = 'filename'; +a.click(); +URL.revokeObjectURL(url); ``` -**API Endpoint**: `DELETE https://api.deepgram.com/v1/projects/:projectId/invites/:email` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/delete-invite). +
+
+Bytes (UIntArray8) -### Leave Project +```ts +const response = await client.speak.v1.audio.generate(...); -Removes the authenticated user from the project. +const bytes = await response.bytes(); +const blob = new Blob([bytes]); +const url = URL.createObjectURL(blob); -```js -const { result, error } = await deepgramClient.manage.leaveProject(projectId); +// trigger download +const a = document.createElement('a'); +a.href = url; +a.download = 'filename'; +a.click(); +URL.revokeObjectURL(url); ``` -**API Endpoint**: `DELETE https://api.deepgram.com/v1/projects/:projectId/leave` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/leave-project). +
+
-## Usage +
+ -### Get All Requests +
+Convert binary response to text -Retrieves all requests associated with the provided project_id based on the provided options. +
+
+ReadableStream -```js -const { result, error } = await deepgramClient.manage.getProjectUsageRequests(projectId, options); -``` - -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/requests` - -### Get Request - -Retrieves a specific request associated with the provided project_id. +```ts +const response = await client.speak.v1.audio.generate(...); -```js -const { result, error } = await deepgramClient.manage.getProjectUsageRequest(projectId, requestId); +const stream = response.stream(); +const text = await new Response(stream).text(); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/requests/:requestId` +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/get-request). +
+
+ArrayBuffer -### Summarize Usage +```ts +const response = await client.speak.v1.audio.generate(...); -Retrieves usage associated with the provided project_id based on the provided options. - -```js -const { result, error } = await deepgramClient.manage.getProjectUsageSummary(projectId, options); +const arrayBuffer = await response.arrayBuffer(); +const text = new TextDecoder().decode(arrayBuffer); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/usage` - -[See our API reference for more info](https://developers.deepgram.com/reference/summarize-usage). +
+
-### Get Fields +
+
+Blob -Lists the features, models, tags, languages, and processing method used for requests in the specified project. +```ts +const response = await client.speak.v1.audio.generate(...); -```js -const { result, error } = await deepgramClient.manage.getProjectUsageFields(projectId, options); +const blob = await response.blob(); +const text = await blob.text(); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/usage/fields` - -[See our API reference for more info](https://developers.deepgram.com/reference/get-fields). +
+
-### Summarize Usage +
+
+Bytes (UIntArray8) -`Deprecated` Retrieves the usage for a specific project. Use Get Project Usage Breakdown for a more comprehensive usage summary. +```ts +const response = await client.speak.v1.audio.generate(...); -```js -const { result, error } = await deepgramClient.manage.getProjectUsage(projectId, options); +const bytes = await response.bytes(); +const text = new TextDecoder().decode(bytes); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/usage` (deprecated) +
+
-[See our API reference for more info](https://developers.deepgram.com/reference/management-api/usage/get). +
-## Billing +## Advanced -### Get All Balances +### Additional Headers -Retrieves the list of balance info for the specified project. +If you would like to send additional headers as part of the request, use the `headers` request option. -```js -const { result, error } = await deepgramClient.manage.getProjectBalances(projectId); +```typescript +const response = await client.listen.v1.media.transcribeFile(..., { + headers: { + 'X-Custom-Header': 'custom value' + } +}); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/balances` - -[See our API reference for more info](https://developers.deepgram.com/reference/get-all-balances). - -### Get Balance +### Additional Query String Parameters -Retrieves the balance info for the specified project and balance_id. +If you would like to send additional query string parameters as part of the request, use the `queryParams` request option. -```js -const { result, error } = await deepgramClient.manage.getProjectBalance(projectId, balanceId); +```typescript +const response = await client.listen.v1.media.transcribeFile(..., { + queryParams: { + 'customQueryParamKey': 'custom query param value' + } +}); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/balances/:balanceId` - -[See our API reference for more info](https://developers.deepgram.com/reference/get-balance). +### Retries -## Models +The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long +as the request is deemed retryable and the number of retry attempts has not grown larger than the configured +retry limit (default: 2). -### Get All Models +A request is deemed retryable when any of the following HTTP status codes is returned: -Retrieves all models available globally. +- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) +- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) +- [5XX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) (Internal Server Errors) -```js -const { result, error } = await deepgramClient.models.getAll(); -``` +Use the `maxRetries` request option to configure this behavior. -**API Endpoint**: `GET https://api.deepgram.com/v1/models` - -### Get All Project Models - -Retrieves all models available for a given project. - -```js -const { result, error } = await deepgramClient.manage.getAllModels(projectId, {}); +```typescript +const response = await client.listen.v1.media.transcribeFile(..., { + maxRetries: 0 // override maxRetries at the request level +}); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/models` +### Timeouts -[See our API reference for more info](https://developers.deepgram.com/reference/management-api/projects/list-models). +The SDK defaults to a 60 second timeout. Use the `timeoutInSeconds` option to configure this behavior. -### Get Model - -Retrieves details of a specific model. - -```js -const { result, error } = await deepgramClient.manage.getModel(projectId, modelId); +```typescript +const response = await client.listen.v1.media.transcribeFile(..., { + timeoutInSeconds: 30 // override timeout to 30s +}); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/models/:modelId` +### Aborting Requests -[See our API reference for more info](https://developers.deepgram.com/reference/management-api/models/get) +The SDK allows users to abort requests at any point by passing in an abort signal. -## On-Prem APIs - -### List On-Prem credentials - -Lists sets of distribution credentials for the specified project. - -```js -const { result, error } = await deepgramClient.onprem.listCredentials(projectId); +```typescript +const controller = new AbortController(); +const response = await client.listen.v1.media.transcribeFile(..., { + abortSignal: controller.signal +}); +controller.abort(); // aborts the request ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/onprem/distribution/credentials` - -[See our API reference for more info](https://developers.deepgram.com/reference/self-hosted-api/list-credentials) +### Access Raw Response Data -### Get On-Prem credentials +The SDK provides access to raw response data, including headers, through the `.withRawResponse()` method. +The `.withRawResponse()` method returns a promise that results to an object with a `data` and a `rawResponse` property. -Returns a set of distribution credentials for the specified project. +```typescript +const { data, rawResponse } = await client.listen.v1.media.transcribeFile(...).withRawResponse(); -```js -const { result, error } = await deepgramClient.onprem.getCredentials(projectId, credentialId); +console.log(data); +console.log(rawResponse.headers['X-My-Header']); ``` -**API Endpoint**: `GET https://api.deepgram.com/v1/projects/:projectId/onprem/distribution/credentials/:credentialsId` - -[See our API reference for more info](https://developers.deepgram.com/reference/self-hosted-api/get-credentials) +### Runtime Compatibility -### Create On-Prem credentials +The SDK works in the following runtimes: -Creates a set of distribution credentials for the specified project. +- Node.js 18+ +- Vercel +- Cloudflare Workers +- Deno v1.25+ +- Bun 1.0+ +- React Native -```js -const { result, error } = await deepgramClient.onprem.createCredentials(projectId, options); -``` - -**API Endpoint**: `POST https://api.deepgram.com/v1/projects/:projectId/onprem/distribution/credentials` +### Customizing Fetch Client -[See our API reference for more info](https://developers.deepgram.com/reference/self-hosted-api/create-credentials) +The SDK provides a way for you to customize the underlying HTTP client / Fetch function. If you're running in an +unsupported environment, this provides a way for you to break glass and ensure the SDK works. -### Delete On-Prem credentials +```typescript +import { DeepgramClient } from "@deepgram/sdk"; -Deletes a set of distribution credentials for the specified project. - -```js -const { result, error } = await deepgramClient.onprem.deleteCredentials(projectId, credentialId); +const client = new DeepgramClient({ + ... + fetcher: // provide your implementation here +}); ``` -**API Endpoint**: `DELETE https://api.deepgram.com/v1/projects/:projectId/onprem/distribution/credentials/:credentialsId` - -[See our API reference for more info](https://developers.deepgram.com/reference/self-hosted-api/delete-credentials) - -## Backwards Compatibility - -Older SDK versions will receive Priority 1 (P1) bug support only. Security issues, both in our code and dependencies, are promptly addressed. Significant bugs without clear workarounds are also given priority attention. - -## Development and Contributing - -Interested in contributing? We ❤️ pull requests! - -To make sure our community is safe for all, be sure to review and agree to our -[Code of Conduct](./CODE_OF_CONDUCT.md). Then see the -[Contribution](./CONTRIBUTING.md) guidelines for more information. - -### Debugging and making changes locally - -If you want to make local changes to the SDK and run the [`examples/`](./examples/), you'll need to `pnpm build` first, to ensure that your changes are included in the examples that are running. - -## Getting Help +## Contributing -We love to hear from you so if you have questions, comments or find a bug in the -project, let us know! You can either: +While we value open-source contributions to this SDK, this library is generated programmatically. +Additions made directly to this library would have to be moved over to our generation code, +otherwise they would be overwritten upon the next generated release. Feel free to open a PR as +a proof of concept, but know that we will not be able to merge it as-is. We suggest opening +an issue first to discuss with us! -- [Open an issue in this repository](https://github.com/deepgram/deepgram-node-sdk/issues/new) -- [Join the Deepgram Discord Community](https://discord.gg/xWRaCDBtW4) -- [Join the Deepgram Github Discussions Community](https://github.com/orgs/deepgram/discussions) +On the other hand, contributions to the README are always very welcome! diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index a8e6c01b..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,20 +0,0 @@ -# Security Policy - -## Supported Versions - -Use this section to tell people about which versions of your project are -currently being supported with security updates. - -| Version | Supported | -| ------- | ------------------ | -| 3.3.x | :white_check_mark: | -| 2.4.x | :white_check_mark: | -| < 2.4.x | :x: | - -## Reporting a Vulnerability - -Use this section to tell people how to report a vulnerability. - -Tell them where to go, how often they can expect to get an update on a -reported vulnerability, what to expect if the vulnerability is accepted or -declined, etc. diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..a777468e --- /dev/null +++ b/biome.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.1/schema.json", + "root": true, + "vcs": { + "enabled": false + }, + "files": { + "ignoreUnknown": true, + "includes": [ + "**", + "!!dist", + "!!**/dist", + "!!lib", + "!!**/lib", + "!!_tmp_*", + "!!**/_tmp_*", + "!!*.tmp", + "!!**/*.tmp", + "!!.tmp/", + "!!**/.tmp/", + "!!*.log", + "!!**/*.log", + "!!**/.DS_Store", + "!!**/Thumbs.db" + ] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 120 + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + }, + "linter": { + "rules": { + "style": { + "useNodejsImportProtocol": "off" + }, + "suspicious": { + "noAssignInExpressions": "warn", + "noUselessEscapeInString": { + "level": "warn", + "fix": "none", + "options": {} + }, + "noThenProperty": "warn", + "useIterableCallbackReturn": "warn", + "noShadowRestrictedNames": "warn", + "noTsIgnore": { + "level": "warn", + "fix": "none", + "options": {} + }, + "noConfusingVoidType": { + "level": "warn", + "fix": "none", + "options": {} + } + } + } + } +} diff --git a/commitlint.config.js b/commitlint.config.js deleted file mode 100644 index 5073c20d..00000000 --- a/commitlint.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = { extends: ["@commitlint/config-conventional"] }; diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 186389a2..00000000 --- a/examples/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Examples - -This directory contains examples for using the Deepgram JS SDK. - -## Setup - -First, build the SDK from the root of the project: - -```bash -pnpm run build -``` - -## Running the Examples - -Each example has its own `README.md` with instructions on how to run it. Be sure to add your Deepgram API key to the example file before running it. diff --git a/examples/browser-live/README.md b/examples/browser-live/README.md deleted file mode 100644 index d95026f5..00000000 --- a/examples/browser-live/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Live Transcription (Browser) - -This example demonstrates how to transcribe a live audio stream in the browser using the Deepgram JS SDK. - -## Setup - -1. From the root of the project, start a local web server: - - ```bash - npx http-server . - ``` - -2. Open your browser to the following URL: - - [http://localhost:8080/examples/browser-live/](http://localhost:8080/examples/browser-live/) - -3. Add your `DEEPGRAM_API_KEY` as a query string parameter to the URL. - - For example: `http://localhost:8080/examples/browser-live/?key=YOUR_DEEPGRAM_API_KEY` - -## Usage - -Once the page is loaded with your API key, you can use the "Start" and "Stop" buttons to control the live transcription. diff --git a/examples/browser-live/index.html b/examples/browser-live/index.html deleted file mode 100644 index 886d380f..00000000 --- a/examples/browser-live/index.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - Deepgram Live Transcription - - - -

Live Transcription

- - -

-
-    
-    
-  
-
diff --git a/examples/browser-prerecorded/README.md b/examples/browser-prerecorded/README.md
deleted file mode 100644
index 0a65688d..00000000
--- a/examples/browser-prerecorded/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Prerecorded Transcription (Browser)
-
-This example demonstrates how to transcribe a prerecorded audio file in the browser using the Deepgram JS SDK.
-
-## Setup
-
-1.  From the root of the project, start a local web server:
-
-    ```bash
-    npx http-server .
-    ```
-
-2.  Open your browser to the following URL:
-
-    [http://localhost:8080/examples/browser-prerecorded/](http://localhost:8080/examples/browser-prerecorded/)
-
-3.  Add your `DEEPGRAM_API_KEY` as a query string parameter to the URL.
-
-    For example: `http://localhost:8080/examples/browser-prerecorded/?key=YOUR_DEEPGRAM_API_KEY`
-
-## Usage
-
-Once the page is loaded with your API key, you can click the "Transcribe" button to see the transcription results in the console.
diff --git a/examples/browser-prerecorded/index.html b/examples/browser-prerecorded/index.html
deleted file mode 100644
index 268d373f..00000000
--- a/examples/browser-prerecorded/index.html
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-  
-    Deepgram Prerecorded Transcription
-  
-
-  
-    

Prerecorded Transcription

-

Open the console to see the transcription results.

- - - - - - diff --git a/examples/nasa.mp4 b/examples/nasa.mp4 deleted file mode 100644 index 021dd52a..00000000 Binary files a/examples/nasa.mp4 and /dev/null differ diff --git a/examples/node-agent-live/.gitignore b/examples/node-agent-live/.gitignore deleted file mode 100644 index e2278d77..00000000 --- a/examples/node-agent-live/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -chatlog.txt -output-*.wav -node_modules -.env diff --git a/examples/node-agent-live/README.md b/examples/node-agent-live/README.md deleted file mode 100644 index 8cb2ad03..00000000 --- a/examples/node-agent-live/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Live Agent - -This example demonstrates how to use the Deepgram JS SDK to interact with a live agent. - -## Setup - -1. Make sure you have a `.env` file with your `DEEPGRAM_API_KEY`. -2. Install the dependencies: - - ```bash - pnpm install - ``` - -## Usage - -Run the example with the following command: - -```bash -pnpm start -``` diff --git a/examples/node-agent-live/index.js b/examples/node-agent-live/index.js deleted file mode 100644 index e93aa141..00000000 --- a/examples/node-agent-live/index.js +++ /dev/null @@ -1,131 +0,0 @@ -/* eslint-env node */ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, no-console */ - -const { createClient, AgentEvents } = require("../../dist/main/index"); -const fetch = require("cross-fetch"); -require("dotenv").config(); - -console.log("🔑 API Key loaded successfully"); - -const agent = async () => { - // Checks for API key - if (!process.env.DEEPGRAM_API_KEY) { - console.error("❌ Error: DEEPGRAM_API_KEY environment variable is required"); - console.log("💡 Run with: DEEPGRAM_API_KEY=your_api_key_here npm start"); - process.exit(1); - } - - console.log("🚀 Starting Deepgram Agent Live example..."); - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - - console.log("📞 Connecting to Deepgram Agent API..."); - const connection = deepgram.agent(); - - // Error handler - connection.on(AgentEvents.Error, (error) => { - if (error.code === 'CLIENT_MESSAGE_TIMEOUT') { - console.log("⏰ Agent session timed out"); - } else { - console.error("❌ Agent error:", error.description || error.message); - } - }); - - connection.on(AgentEvents.Open, () => { - console.log("✅ Connected to Deepgram Agent"); - console.log("⚙️ Configuring agent with tags and providers..."); - - const config = { - // Agent tags for filtered searching and analytics - tags: ["live-agent-test", "nodejs-example"], - agent: { - listen: { - provider: { - type: "deepgram", - model: "nova-3" - } - }, - speak: { - provider: { - type: "deepgram", - model: "aura-asteria-en" - } - }, - greeting: "Hello! I'm a Deepgram voice agent. How can I help you today?" - }, - }; - - connection.configure(config); - }); - - connection.on(AgentEvents.SettingsApplied, () => { - console.log("⚙️ Agent configuration applied successfully"); - console.log("🏷️ Tags:", ["live-agent-test", "nodejs-example"]); - console.log("🎵 Starting 15-second audio demo..."); - startAudioStream(); - }); - - function startAudioStream() { - fetch("http://stream.live.vc.bbcmedia.co.uk/bbc_world_service") - .then((r) => r.body) - .then((res) => { - console.log("🔊 Streaming live audio to agent..."); - - let isStreamActive = true; - - // Stop stream after 15 seconds - setTimeout(() => { - isStreamActive = false; - res.destroy(); - console.log("⏹️ Audio stream stopped after 15 seconds"); - console.log("🎯 Agent tags demo completed successfully!"); - console.log("📊 Tags used: ['live-agent-test', 'nodejs-example']"); - - // Close connection after a brief delay - setTimeout(() => { - connection.disconnect(); - }, 2000); - }, 15000); - - res.on("readable", () => { - if (!isStreamActive) return; - - const chunk = res.read(); - if (chunk) { - connection.send(chunk); - } - }); - - res.on("error", (error) => { - if (isStreamActive) { - console.error("❌ Audio stream error:", error); - } - }); - }) - .catch((error) => { - console.error("❌ Failed to fetch audio stream:", error); - }); - } - - // Agent conversation events - connection.on(AgentEvents.ConversationText, (data) => { - console.log(`💬 ${data.role}: ${data.content}`); - }); - - connection.on(AgentEvents.UserStartedSpeaking, () => { - console.log("🎤 User speaking detected"); - }); - - connection.on(AgentEvents.AgentThinking, () => { - console.log("🤔 Agent processing..."); - }); - - connection.on(AgentEvents.AgentStartedSpeaking, () => { - console.log("🗨️ Agent responding"); - }); - - connection.on(AgentEvents.Close, () => { - console.log("👋 Agent session ended"); - }); -}; - -agent(); diff --git a/examples/node-agent-live/package.json b/examples/node-agent-live/package.json deleted file mode 100644 index 147ddb98..00000000 --- a/examples/node-agent-live/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "deepgram-node-agent-live-example", - "version": "1.0.0", - "description": "A simple example of using the Deepgram JS SDK to interact with a live agent in Node.js.", - "main": "index.js", - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "dotenv": "^16.3.1" - } -} diff --git a/examples/node-live-token/.gitignore b/examples/node-live-token/.gitignore deleted file mode 100644 index 37d7e734..00000000 --- a/examples/node-live-token/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.env diff --git a/examples/node-live-token/README.md b/examples/node-live-token/README.md deleted file mode 100644 index 81c0ff31..00000000 --- a/examples/node-live-token/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Live Transcription with a Temporary Token - -This example demonstrates how to transcribe a live audio stream using a temporary token with the Deepgram JS SDK. - -## Setup - -1. Make sure you have a `.env` file with your `DEEPGRAM_API_KEY` to generate the token. -2. Install the dependencies: - - ```bash - pnpm install - ``` - -## Usage - -Run the example with the following command: - -```bash -pnpm start -``` diff --git a/examples/node-live-token/index.js b/examples/node-live-token/index.js deleted file mode 100644 index a784e20b..00000000 --- a/examples/node-live-token/index.js +++ /dev/null @@ -1,57 +0,0 @@ -/* eslint-env node */ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, no-console */ - -const { createClient, LiveTranscriptionEvents } = require("../../dist/main/index"); -const fetch = require("cross-fetch"); -require("dotenv").config(); - -const live = async () => { - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - - // First, generate a temporary token with 60 second TTL - console.log("🔍 Requesting token with ttl_seconds: 60"); - const { result: token, error } = await deepgram.auth.grantToken({ - ttl_seconds: 60, - }); - - if (error) { - console.error("❌ Failed to generate token:", error); - return; - } - - // Log successful token generation - console.log("✅ Token generated successfully!"); - console.log(` • Expires in: ${token.expires_in} seconds`); - console.log(` • Token preview: ${token.access_token.substring(0, 20)}...`); - console.log(""); - - // Now, use the temporary token to create a new client - // Note: Must use 'accessToken' property, not 'key' - const deepgramWithToken = createClient({ accessToken: token.access_token }); - console.log("✅ Client created with temporary token - ready for live transcription!"); - const connection = deepgramWithToken.listen.live({ - model: "nova-3", - }); - - connection.on(LiveTranscriptionEvents.Open, () => { - console.log("Connection opened."); - - fetch("http://stream.live.vc.bbcmedia.co.uk/bbc_world_service") - .then((r) => r.body) - .then((res) => { - res.on("readable", () => { - connection.send(res.read()); - }); - }); - - connection.on(LiveTranscriptionEvents.Transcript, (data) => { - console.log(data.channel.alternatives[0].transcript); - }); - - connection.on(LiveTranscriptionEvents.Close, () => { - console.log("Connection closed."); - }); - }); -}; - -live(); diff --git a/examples/node-live-token/package.json b/examples/node-live-token/package.json deleted file mode 100644 index 952ad7bb..00000000 --- a/examples/node-live-token/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "deepgram-node-live-token-example", - "version": "1.0.0", - "description": "A simple example of using a temporary token to transcribe a live audio stream in Node.js.", - "main": "index.js", - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "dotenv": "^16.3.1" - } -} diff --git a/examples/node-live/.gitignore b/examples/node-live/.gitignore deleted file mode 100644 index 37d7e734..00000000 --- a/examples/node-live/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.env diff --git a/examples/node-live/README.md b/examples/node-live/README.md deleted file mode 100644 index 1b75efcd..00000000 --- a/examples/node-live/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Live Transcription - -This example demonstrates how to transcribe a live audio stream using the Deepgram JS SDK. - -## Setup - -1. Make sure you have a `.env` file with your `DEEPGRAM_API_KEY`. -2. Install the dependencies: - - ```bash - pnpm install - ``` - -## Usage - -Run the example with the following command: - -```bash -pnpm start -``` diff --git a/examples/node-live/index.js b/examples/node-live/index.js deleted file mode 100644 index 64087563..00000000 --- a/examples/node-live/index.js +++ /dev/null @@ -1,35 +0,0 @@ -/* eslint-env node */ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, no-console */ - -const { createClient, LiveTranscriptionEvents } = require("../../dist/main/index"); -const fetch = require("cross-fetch"); -require("dotenv").config(); - -const live = async () => { - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - const connection = deepgram.listen.live({ - model: "nova-3", - }); - - connection.on(LiveTranscriptionEvents.Open, () => { - console.log("Connection opened."); - - fetch("http://stream.live.vc.bbcmedia.co.uk/bbc_world_service") - .then((r) => r.body) - .then((res) => { - res.on("readable", () => { - connection.send(res.read()); - }); - }); - - connection.on(LiveTranscriptionEvents.Transcript, (data) => { - console.log(data.channel.alternatives[0].transcript); - }); - - connection.on(LiveTranscriptionEvents.Close, () => { - console.log("Connection closed."); - }); - }); -}; - -live(); diff --git a/examples/node-live/package.json b/examples/node-live/package.json deleted file mode 100644 index e0205c30..00000000 --- a/examples/node-live/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "deepgram-node-live-example", - "version": "1.0.0", - "description": "A simple example of using the Deepgram JS SDK to transcribe a live audio stream in Node.js.", - "main": "index.js", - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "dotenv": "^16.3.1" - } -} diff --git a/examples/node-prerecorded/.gitignore b/examples/node-prerecorded/.gitignore deleted file mode 100644 index 37d7e734..00000000 --- a/examples/node-prerecorded/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.env diff --git a/examples/node-prerecorded/README.md b/examples/node-prerecorded/README.md deleted file mode 100644 index 48d96033..00000000 --- a/examples/node-prerecorded/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Prerecorded Transcription - -This example demonstrates how to transcribe a prerecorded audio file using the Deepgram JS SDK. - -## Setup - -1. Make sure you have a `.env` file with your `DEEPGRAM_API_KEY`. -2. Install the dependencies: - - ```bash - pnpm install - ``` - -## Usage - -Run the example with the following command: - -```bash -pnpm start -``` diff --git a/examples/node-prerecorded/index.js b/examples/node-prerecorded/index.js deleted file mode 100644 index aeb5ac5a..00000000 --- a/examples/node-prerecorded/index.js +++ /dev/null @@ -1,120 +0,0 @@ -/* eslint-env node */ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, no-console */ - -const { createClient } = require("../../dist/main/index"); -const { readFileSync } = require("fs"); -const { resolve } = require("path"); -require("dotenv").config(); - -const transcribeUrlAuthWithFactory = async () => { - console.log("transcribing url with auth factory"); - - const authFactory = async () => { - const deepgramTokenClient = createClient(process.env.DEEPGRAM_API_KEY); - - const { result: tokenResult, error: tokenError } = await deepgramTokenClient.auth.grantToken(); - - if (tokenError) console.error(tokenError); - if (!tokenError) return tokenResult.access_token; - }; - - const deepgramClient = createClient({ accessToken: authFactory }); - - console.log("Transcribing URL", "https://dpgr.am/spacewalk.wav"); - const { result, error } = await deepgramClient.listen.prerecorded.transcribeUrl( - { - url: "https://dpgr.am/spacewalk.wav", - }, - { - model: "nova-3", - } - ); - - if (error) console.error(error); - if (!error) console.dir(result, { depth: 1 }); -}; - -const transcribeUrlWithAccessToken = async () => { - console.log("transcribing url with access token"); - - const deepgramTokenClient = createClient(process.env.DEEPGRAM_API_KEY); - - const { result: tokenResult, error: tokenError } = await deepgramTokenClient.auth.grantToken(); - - if (tokenError) console.error(tokenError); - - const deepgramClient = createClient({ accessToken: tokenResult.access_token }); - - console.log("Transcribing URL", "https://dpgr.am/spacewalk.wav"); - const { result, error } = await deepgramClient.listen.prerecorded.transcribeUrl( - { - url: "https://dpgr.am/spacewalk.wav", - }, - { - model: "nova-3", - } - ); - - if (error) console.error(error); - if (!error) console.dir(result, { depth: 1 }); -}; - -const transcribeUrl = async () => { - console.log("transcribing url with api key"); - - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - - console.log("Transcribing URL", "https://dpgr.am/spacewalk.wav"); - const { result, error } = await deepgram.listen.prerecorded.transcribeUrl( - { - url: "https://dpgr.am/spacewalk.wav", - }, - { - model: "nova-3", - } - ); - - if (error) console.error(error); - if (!error) console.dir(result, { depth: 1 }); -}; - -const transcribeFile = async () => { - console.log("transcribing file with api key"); - - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - - const filePath = resolve(__dirname, "../spacewalk.wav"); - console.log(filePath); - const file = readFileSync(filePath); - - console.log("Transcribing file", file); - const { result, error } = await deepgram.listen.prerecorded.transcribeFile(file, { - model: "nova-3", - }); - - if (error) console.error(error); - if (!error) console.dir(result, { depth: 1 }); -}; - -const transcribe = async () => { - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - const audio = readFileSync(resolve(__dirname, "../spacewalk.wav")); - - const { result, error } = await deepgram.listen.prerecorded.transcribeFile(audio, { - model: "nova-3", - }); - - if (error) { - console.error(error); - } else { - console.log(result.results.channels[0].alternatives[0].transcript); - } -}; - -(async () => { - await transcribeUrl(); - await transcribeFile(); - await transcribeUrlAuthWithFactory(); - await transcribeUrlWithAccessToken(); - await transcribe(); -})(); diff --git a/examples/node-prerecorded/package.json b/examples/node-prerecorded/package.json deleted file mode 100644 index f04ae89f..00000000 --- a/examples/node-prerecorded/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "deepgram-node-prerecorded-example", - "version": "1.0.0", - "description": "A simple example of using the Deepgram JS SDK to transcribe a prerecorded audio file in Node.js.", - "main": "index.js", - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "dotenv": "^16.3.1" - } -} diff --git a/examples/node-read/.gitignore b/examples/node-read/.gitignore deleted file mode 100644 index 37d7e734..00000000 --- a/examples/node-read/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.env diff --git a/examples/node-read/README.md b/examples/node-read/README.md deleted file mode 100644 index 9d9519d2..00000000 --- a/examples/node-read/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Read (Text Analysis) - -This example demonstrates how to analyze text using the Deepgram JS SDK. - -## Setup - -1. Make sure you have a `.env` file with your `DEEPGRAM_API_KEY`. -2. Install the dependencies: - - ```bash - pnpm install - ``` - -## Usage - -Run the example with the following command: - -```bash -pnpm start -``` diff --git a/examples/node-read/index.js b/examples/node-read/index.js deleted file mode 100644 index 78eca5a9..00000000 --- a/examples/node-read/index.js +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-env node */ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, no-console */ - -const { createClient } = require("../../dist/main/index"); -require("dotenv").config(); - -const analyze = async () => { - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - const text = "Hello, world!"; - - const { result, error } = await deepgram.read.analyzeText( - { text }, - { - model: "nova-3", - } - ); - - if (error) { - console.error(error); - } else { - console.dir(result, { depth: null }); - } -}; - -analyze(); diff --git a/examples/node-read/package.json b/examples/node-read/package.json deleted file mode 100644 index 2bf05686..00000000 --- a/examples/node-read/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "deepgram-node-read-example", - "version": "1.0.0", - "description": "A simple example of using the Deepgram JS SDK to analyze text in Node.js.", - "main": "index.js", - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "dotenv": "^16.3.1" - } -} diff --git a/examples/node-speak-live/.gitignore b/examples/node-speak-live/.gitignore deleted file mode 100644 index 7444d06a..00000000 --- a/examples/node-speak-live/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -.env -output.mp3 diff --git a/examples/node-speak-live/README.md b/examples/node-speak-live/README.md deleted file mode 100644 index 9bbdeafd..00000000 --- a/examples/node-speak-live/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Live Speak (Text-to-Speech) - -This example demonstrates how to synthesize speech from a live text stream using the Deepgram JS SDK. - -## Setup - -1. Make sure you have a `.env` file with your `DEEPGRAM_API_KEY`. -2. Install the dependencies: - - ```bash - pnpm install - ``` - -## Usage - -Run the example with the following command: - -```bash -pnpm start -``` diff --git a/examples/node-speak-live/index.js b/examples/node-speak-live/index.js deleted file mode 100644 index a19e0690..00000000 --- a/examples/node-speak-live/index.js +++ /dev/null @@ -1,38 +0,0 @@ -/* eslint-env node */ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, no-console */ - -const { createClient, LiveTTSEvents } = require("../../dist/main/index"); -const { writeFileSync } = require("fs"); -const { resolve } = require("path"); -require("dotenv").config(); - -const speak = async () => { - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - const connection = deepgram.speak.live({ - model: "aura-asteria-en", - }); - - const audioChunks = []; - - connection.on(LiveTTSEvents.Open, () => { - console.log("Connection opened."); - connection.sendText("Hello, world! This is a live text-to-speech test."); - connection.sendText("This is a second sentence."); - connection.finish(); - }); - - connection.on(LiveTTSEvents.Audio, (audio) => { - console.log("Received audio chunk."); - audioChunks.push(audio); - }); - - connection.on(LiveTTSEvents.Close, () => { - console.log("Connection closed."); - const buffer = Buffer.concat(audioChunks); - const filePath = resolve(__dirname, "output.mp3"); - writeFileSync(filePath, buffer); - console.log(`Audio file saved to ${filePath}`); - }); -}; - -speak(); diff --git a/examples/node-speak-live/package.json b/examples/node-speak-live/package.json deleted file mode 100644 index 23ada3f6..00000000 --- a/examples/node-speak-live/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "deepgram-node-speak-live-example", - "version": "1.0.0", - "description": "A simple example of using the Deepgram JS SDK to synthesize speech from a live text stream in Node.js.", - "main": "index.js", - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "dotenv": "^16.3.1" - } -} diff --git a/examples/node-speak/.gitignore b/examples/node-speak/.gitignore deleted file mode 100644 index 7444d06a..00000000 --- a/examples/node-speak/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -.env -output.mp3 diff --git a/examples/node-speak/README.md b/examples/node-speak/README.md deleted file mode 100644 index e009a4d8..00000000 --- a/examples/node-speak/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Speak (Text-to-Speech) - -This example demonstrates how to synthesize speech from text using the Deepgram JS SDK. - -## Setup - -1. Make sure you have a `.env` file with your `DEEPGRAM_API_KEY`. -2. Install the dependencies: - - ```bash - pnpm install - ``` - -## Usage - -Run the example with the following command: - -```bash -pnpm start -``` diff --git a/examples/node-speak/index.js b/examples/node-speak/index.js deleted file mode 100644 index fea1211a..00000000 --- a/examples/node-speak/index.js +++ /dev/null @@ -1,43 +0,0 @@ -/* eslint-env node */ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, no-console */ - -const { createClient } = require("../../dist/main/index"); -const { writeFileSync } = require("fs"); -const { resolve } = require("path"); -require("dotenv").config(); - -const speak = async () => { - const deepgram = createClient(process.env.DEEPGRAM_API_KEY); - const text = "Hello, world! This is a test of the Deepgram JS SDK."; - - const response = await deepgram.speak.request( - { text }, - { - model: "aura-asteria-en", - } - ); - - const stream = await response.getStream(); - const headers = await response.getHeaders(); - - if (stream) { - const buffer = await new Promise((resolve, reject) => { - const chunks = []; - stream.on("data", (chunk) => chunks.push(chunk)); - stream.on("end", () => resolve(Buffer.concat(chunks))); - stream.on("error", reject); - }); - - const filePath = resolve(__dirname, "output.mp3"); - writeFileSync(filePath, buffer); - console.log(`Audio file saved to ${filePath}`); - } else { - console.error("Error: Could not get audio stream."); - } - - if (headers) { - console.log("Headers:", headers); - } -}; - -speak(); diff --git a/examples/node-speak/package.json b/examples/node-speak/package.json deleted file mode 100644 index eec5d6a6..00000000 --- a/examples/node-speak/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "deepgram-node-speak-example", - "version": "1.0.0", - "description": "A simple example of using the Deepgram JS SDK to synthesize speech in Node.js.", - "main": "index.js", - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "dotenv": "^16.3.1" - } -} diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 3f2adae4..00000000 --- a/jest.config.js +++ /dev/null @@ -1,53 +0,0 @@ -/** @type {import('jest').Config} */ -/* eslint-env node */ -module.exports = { - preset: "ts-jest", - testEnvironment: "node", - - // Test file patterns - testMatch: ["/tests/**/*.test.ts", "/tests/**/*.spec.ts"], - - // Module path mapping - moduleNameMapper: { - "^@/(.*)$": "/src/$1", - "^@deepgram/sdk$": "/src/index.ts", - }, - - // Setup files - setupFilesAfterEnv: ["/tests/setup.ts"], - - // Coverage configuration - collectCoverageFrom: [ - "src/**/*.ts", - "!src/**/*.d.ts", - "!src/**/index.ts", - "!src/**/__tests__/**", - "!src/**/__mocks__/**", - ], - - coverageDirectory: "coverage", - coverageReporters: ["text", "lcov", "html", "json"], - - // Test timeout - testTimeout: 10000, - - // Transform configuration - transform: { - "^.+\\.ts$": [ - "ts-jest", - { - tsconfig: "tsconfig.json", - }, - ], - }, - - // Module file extensions - moduleFileExtensions: ["ts", "js", "json"], - - // Clear mocks between tests - clearMocks: true, - restoreMocks: true, - - // Detect open handles to identify resource leaks - detectOpenHandles: true, -}; diff --git a/package.json b/package.json index 07a760ec..5516e639 100644 --- a/package.json +++ b/package.json @@ -1,117 +1,72 @@ { - "name": "@deepgram/sdk", - "version": "0.0.0-automated", - "description": "Isomorphic Javascript client for Deepgram", - "keywords": [ - "javascript", - "typescript", - "deepgram", - "asr", - "speech", - "sdk" - ], - "packageManager": "pnpm@10.12.1", - "homepage": "https://github.com/deepgram/deepgram-js-sdk", - "bugs": "https://github.com/deepgram/deepgram-js-sdk/issues", - "license": "MIT", - "author": { - "name": "Deepgram DevRel Team", - "email": "devrel@deepgram.com" - }, - "contributors": [ - "Brian Barrow", - "Brian Hillis", - "Luke Oliff", - "Michael Jolley", - "Sandra Rodgers", - "Shir Goldberg" - ], - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=18.0.0" - }, - "main": "dist/main/index.js", - "module": "dist/module/index.js", - "types": "dist/module/index.d.ts", - "sideEffects": false, - "repository": "deepgram/deepgram-js-sdk", - "scripts": { - "clean": "rimraf dist docs/v2", - "format": "prettier --write \"src/**/*.ts\"", - "build": "run-s clean format build:*", - "build:main": "tsc -p tsconfig.json", - "build:module": "tsc -p tsconfig.module.json", - "build:umd": "webpack --mode=production", - "lint": "run-s lint:*", - "lint:js": "eslint -c .eslintrc-examples.js examples --max-warnings 0", - "lint:md": "markdownlint **/*.md *.md", - "lint:yml": "yamllint .github/workflows", - "lint:ts": "eslint src --max-warnings 0", - "watch": "nodemon -e ts --watch src --exec \"npm run build\"", - "docs": "typedoc --entryPoints src/index.ts --out docs/ --includes src/packages/**/*.ts --emit none", - "docs:json": "typedoc --entryPoints src/index.ts --includes src/packages/**/*.ts --json docs/spec.json --emit none", - "test": "jest", - "test:unit": "jest --testPathPattern=tests/unit", - "test:e2e": "jest --testPathPattern=tests/e2e", - "test:e2e:offline": "node scripts/test-offline.js", - "test:watch": "jest --watch", - "test:coverage": "jest --coverage", - "test:ci": "jest --ci --coverage --watchAll=false" - }, - "dependencies": { - "@deepgram/captions": "^1.1.1", - "@types/node": "^18.19.39", - "cross-fetch": "^3.1.5", - "deepmerge": "^4.3.1", - "events": "^3.3.0", - "ws": "^8.17.0" - }, - "devDependencies": { - "@commitlint/cli": "^17.6.7", - "@commitlint/config-conventional": "^17.6.7", - "@types/jest": "^29.5.12", - "@types/ws": "^8.5.10", - "@typescript-eslint/eslint-plugin": "^8.7.0", - "@typescript-eslint/parser": "^8.7.0", - "buffer": "^6.0.3", - "cross-env": "^7.0.3", - "dotenv": "^16.5.0", - "eslint": "^8.57.1", - "husky": "^4.3.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "markdownlint": "^0.35.0", - "markdownlint-cli": "^0.42.0", - "nodemon": "^3.0.1", - "npm-run-all": "^4.1.5", - "prettier": "^2.5.1", - "pretty-quick": "^3.1.3", - "rimraf": "^3.0.2", - "semantic-release-plugin-update-version-in-files": "^1.1.0", - "stream-browserify": "^3.0.0", - "ts-jest": "^29.1.2", - "ts-loader": "^8.0.11", - "ts-node": "^10.9.1", - "typedoc": "^0.22.16", - "typescript": "^4.5.5", - "url": "^0.11.4", - "util": "^0.12.5", - "webpack": "^5.69.1", - "webpack-cli": "^4.9.2", - "yaml-lint": "^1.7.0" - }, - "overrides": { - "es5-ext": "0.10.53" - }, - "husky": { - "hooks": { - "pre-commit": "pretty-quick --staged", - "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" - } - }, - "jsdelivr": "dist/umd/deepgram.js", - "unpkg": "dist/umd/deepgram.js" + "name": "@deepgram/sdk", + "version": "4.11.3", + "private": false, + "repository": "github:deepgram/deepgram-js-sdk", + "license": "MIT", + "type": "commonjs", + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.mjs", + "types": "./dist/cjs/index.d.ts", + "exports": { + ".": { + "types": "./dist/cjs/index.d.ts", + "import": { + "types": "./dist/esm/index.d.mts", + "default": "./dist/esm/index.mjs" + }, + "require": { + "types": "./dist/cjs/index.d.ts", + "default": "./dist/cjs/index.js" + }, + "default": "./dist/cjs/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "dist", + "reference.md", + "README.md", + "LICENSE" + ], + "scripts": { + "format": "biome format --write --skip-parse-errors --no-errors-on-unmatched --max-diagnostics=none", + "format:check": "biome format --skip-parse-errors --no-errors-on-unmatched --max-diagnostics=none", + "lint": "biome lint --skip-parse-errors --no-errors-on-unmatched --max-diagnostics=none", + "lint:fix": "biome lint --fix --unsafe --skip-parse-errors --no-errors-on-unmatched --max-diagnostics=none", + "check": "biome check --skip-parse-errors --no-errors-on-unmatched --max-diagnostics=none", + "check:fix": "biome check --fix --unsafe --skip-parse-errors --no-errors-on-unmatched --max-diagnostics=none", + "build": "pnpm build:cjs && pnpm build:esm", + "build:cjs": "tsc --project ./tsconfig.cjs.json", + "build:esm": "tsc --project ./tsconfig.esm.json && node scripts/rename-to-esm-files.js dist/esm", + "test": "vitest", + "test:unit": "vitest --project unit", + "test:wire": "vitest --project wire" + }, + "dependencies": { + "ws": "^8.16.0" + }, + "devDependencies": { + "webpack": "^5.97.1", + "ts-loader": "^9.5.1", + "@types/ws": "^8.5.10", + "vitest": "^3.2.4", + "msw": "2.11.2", + "@types/node": "^18.19.70", + "typescript": "~5.7.2", + "@biomejs/biome": "2.3.1", + "playwright": "^1.56.1", + "@playwright/test": "^1.56.1" + }, + "browser": { + "fs": false, + "os": false, + "path": false, + "stream": false + }, + "packageManager": "pnpm@10.20.0", + "engines": { + "node": ">=18.0.0" + }, + "sideEffects": false } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e021df84..e9aa7b09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,1275 +1,567 @@ -lockfileVersion: "9.0" +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: + .: dependencies: - "@deepgram/captions": - specifier: ^1.1.1 - version: 1.2.0 - "@types/node": - specifier: ^18.19.39 - version: 18.19.112 - cross-fetch: - specifier: ^3.1.5 - version: 3.2.0 - deepmerge: - specifier: ^4.3.1 - version: 4.3.1 - events: - specifier: ^3.3.0 - version: 3.3.0 ws: - specifier: ^8.17.0 - version: 8.18.2 + specifier: ^8.16.0 + version: 8.18.3 devDependencies: - "@commitlint/cli": - specifier: ^17.6.7 - version: 17.8.1 - "@commitlint/config-conventional": - specifier: ^17.6.7 - version: 17.8.1 - "@types/jest": - specifier: ^29.5.12 - version: 29.5.14 - "@types/ws": + '@biomejs/biome': + specifier: 2.3.1 + version: 2.3.1 + '@playwright/test': + specifier: ^1.56.1 + version: 1.56.1 + '@types/node': + specifier: ^18.19.70 + version: 18.19.130 + '@types/ws': specifier: ^8.5.10 version: 8.18.1 - "@typescript-eslint/eslint-plugin": - specifier: ^8.7.0 - version: 8.34.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5) - "@typescript-eslint/parser": - specifier: ^8.7.0 - version: 8.34.0(eslint@8.57.1)(typescript@4.9.5) - buffer: - specifier: ^6.0.3 - version: 6.0.3 - cross-env: - specifier: ^7.0.3 - version: 7.0.3 - dotenv: - specifier: ^16.5.0 - version: 16.5.0 - eslint: - specifier: ^8.57.1 - version: 8.57.1 - husky: - specifier: ^4.3.0 - version: 4.3.8 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - jest-environment-jsdom: - specifier: ^29.7.0 - version: 29.7.0 - markdownlint: - specifier: ^0.35.0 - version: 0.35.0 - markdownlint-cli: - specifier: ^0.42.0 - version: 0.42.0 - nodemon: - specifier: ^3.0.1 - version: 3.1.10 - npm-run-all: - specifier: ^4.1.5 - version: 4.1.5 - prettier: - specifier: ^2.5.1 - version: 2.8.8 - pretty-quick: - specifier: ^3.1.3 - version: 3.3.1(prettier@2.8.8) - rimraf: - specifier: ^3.0.2 - version: 3.0.2 - semantic-release-plugin-update-version-in-files: - specifier: ^1.1.0 - version: 1.1.0 - stream-browserify: - specifier: ^3.0.0 - version: 3.0.0 - ts-jest: - specifier: ^29.1.2 - version: 29.4.0(@babel/core@7.27.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)))(typescript@4.9.5) + msw: + specifier: 2.11.2 + version: 2.11.2(@types/node@18.19.130)(typescript@5.7.3) + playwright: + specifier: ^1.56.1 + version: 1.56.1 ts-loader: - specifier: ^8.0.11 - version: 8.4.0(typescript@4.9.5)(webpack@5.99.9) - ts-node: - specifier: ^10.9.1 - version: 10.9.2(@types/node@18.19.112)(typescript@4.9.5) - typedoc: - specifier: ^0.22.16 - version: 0.22.18(typescript@4.9.5) + specifier: ^9.5.1 + version: 9.5.4(typescript@5.7.3)(webpack@5.103.0) typescript: - specifier: ^4.5.5 - version: 4.9.5 - url: - specifier: ^0.11.4 - version: 0.11.4 - util: - specifier: ^0.12.5 - version: 0.12.5 + specifier: ~5.7.2 + version: 5.7.3 + vitest: + specifier: ^3.2.4 + version: 3.2.4(@types/node@18.19.130)(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(terser@5.44.1) webpack: - specifier: ^5.69.1 - version: 5.99.9(webpack-cli@4.10.0) - webpack-cli: - specifier: ^4.9.2 - version: 4.10.0(webpack@5.99.9) - yaml-lint: - specifier: ^1.7.0 - version: 1.7.0 + specifier: ^5.97.1 + version: 5.103.0 packages: - "@ampproject/remapping@2.3.0": - resolution: - { - integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==, - } - engines: { node: ">=6.0.0" } - - "@babel/code-frame@7.27.1": - resolution: - { - integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==, - } - engines: { node: ">=6.9.0" } - - "@babel/compat-data@7.27.5": - resolution: - { - integrity: sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==, - } - engines: { node: ">=6.9.0" } - - "@babel/core@7.27.4": - resolution: - { - integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==, - } - engines: { node: ">=6.9.0" } - - "@babel/generator@7.27.5": - resolution: - { - integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-compilation-targets@7.27.2": - resolution: - { - integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-module-imports@7.27.1": - resolution: - { - integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-module-transforms@7.27.3": - resolution: - { - integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==, - } - engines: { node: ">=6.9.0" } - peerDependencies: - "@babel/core": ^7.0.0 - - "@babel/helper-plugin-utils@7.27.1": - resolution: - { - integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-string-parser@7.27.1": - resolution: - { - integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-validator-identifier@7.27.1": - resolution: - { - integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-validator-option@7.27.1": - resolution: - { - integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==, - } - engines: { node: ">=6.9.0" } - - "@babel/helpers@7.27.6": - resolution: - { - integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==, - } - engines: { node: ">=6.9.0" } - - "@babel/parser@7.27.5": - resolution: - { - integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==, - } - engines: { node: ">=6.0.0" } + + '@biomejs/biome@2.3.1': + resolution: {integrity: sha512-A29evf1R72V5bo4o2EPxYMm5mtyGvzp2g+biZvRFx29nWebGyyeOSsDWGx3tuNNMFRepGwxmA9ZQ15mzfabK2w==} + engines: {node: '>=14.21.3'} hasBin: true - "@babel/plugin-syntax-async-generators@7.8.4": - resolution: - { - integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==, - } - peerDependencies: - "@babel/core": ^7.0.0-0 + '@biomejs/cli-darwin-arm64@2.3.1': + resolution: {integrity: sha512-ombSf3MnTUueiYGN1SeI9tBCsDUhpWzOwS63Dove42osNh0PfE1cUtHFx6eZ1+MYCCLwXzlFlYFdrJ+U7h6LcA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] - "@babel/plugin-syntax-bigint@7.8.3": - resolution: - { - integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==, - } - peerDependencies: - "@babel/core": ^7.0.0-0 + '@biomejs/cli-darwin-x64@2.3.1': + resolution: {integrity: sha512-pcOfwyoQkrkbGvXxRvZNe5qgD797IowpJPovPX5biPk2FwMEV+INZqfCaz4G5bVq9hYnjwhRMamg11U4QsRXrQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] - "@babel/plugin-syntax-class-properties@7.12.13": - resolution: - { - integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==, - } - peerDependencies: - "@babel/core": ^7.0.0-0 - - "@babel/plugin-syntax-class-static-block@7.14.5": - resolution: - { - integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==, - } - engines: { node: ">=6.9.0" } - peerDependencies: - "@babel/core": ^7.0.0-0 - - "@babel/plugin-syntax-import-attributes@7.27.1": - resolution: - { - integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==, - } - engines: { node: ">=6.9.0" } - peerDependencies: - "@babel/core": ^7.0.0-0 + '@biomejs/cli-linux-arm64-musl@2.3.1': + resolution: {integrity: sha512-+DZYv8l7FlUtTrWs1Tdt1KcNCAmRO87PyOnxKGunbWm5HKg1oZBSbIIPkjrCtDZaeqSG1DiGx7qF+CPsquQRcg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@2.3.1': + resolution: {integrity: sha512-td5O8pFIgLs8H1sAZsD6v+5quODihyEw4nv2R8z7swUfIK1FKk+15e4eiYVLcAE4jUqngvh4j3JCNgg0Y4o4IQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@2.3.1': + resolution: {integrity: sha512-Y3Ob4nqgv38Mh+6EGHltuN+Cq8aj/gyMTJYzkFZV2AEj+9XzoXB9VNljz9pjfFNHUxvLEV4b55VWyxozQTBaUQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@2.3.1': + resolution: {integrity: sha512-PYWgEO7up7XYwSAArOpzsVCiqxBCXy53gsReAb1kKYIyXaoAlhBaBMvxR/k2Rm9aTuZ662locXUmPk/Aj+Xu+Q==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@2.3.1': + resolution: {integrity: sha512-RHIG/zgo+69idUqVvV3n8+j58dKYABRpMyDmfWu2TITC+jwGPiEaT0Q3RKD+kQHiS80mpBrST0iUGeEXT0bU9A==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@2.3.1': + resolution: {integrity: sha512-izl30JJ5Dp10mi90Eko47zhxE6pYyWPcnX1NQxKpL/yMhXxf95oLTzfpu4q+MDBh/gemNqyJEwjBpe0MT5iWPA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@bundled-es-modules/cookie@2.0.1': + resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} + + '@bundled-es-modules/statuses@1.0.1': + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] - "@babel/plugin-syntax-import-meta@7.10.4": - resolution: - { - integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==, - } - peerDependencies: - "@babel/core": ^7.0.0-0 + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] - "@babel/plugin-syntax-json-strings@7.8.3": - resolution: - { - integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==, - } + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} + engines: {node: '>=18'} peerDependencies: - "@babel/core": ^7.0.0-0 - - "@babel/plugin-syntax-jsx@7.27.1": - resolution: - { - integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==, - } - engines: { node: ">=6.9.0" } - peerDependencies: - "@babel/core": ^7.0.0-0 + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - "@babel/plugin-syntax-logical-assignment-operators@7.10.4": - resolution: - { - integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==, - } + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} peerDependencies: - "@babel/core": ^7.0.0-0 + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - "@babel/plugin-syntax-nullish-coalescing-operator@7.8.3": - resolution: - { - integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==, - } - peerDependencies: - "@babel/core": ^7.0.0-0 + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} - "@babel/plugin-syntax-numeric-separator@7.10.4": - resolution: - { - integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==, - } + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} peerDependencies: - "@babel/core": ^7.0.0-0 + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - "@babel/plugin-syntax-object-rest-spread@7.8.3": - resolution: - { - integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==, - } - peerDependencies: - "@babel/core": ^7.0.0-0 + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - "@babel/plugin-syntax-optional-catch-binding@7.8.3": - resolution: - { - integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==, - } - peerDependencies: - "@babel/core": ^7.0.0-0 + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.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-private-property-in-object@7.14.5": - resolution: - { - integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==, - } - engines: { node: ">=6.9.0" } - 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.27.1": - resolution: - { - integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==, - } - engines: { node: ">=6.9.0" } - peerDependencies: - "@babel/core": ^7.0.0-0 - - "@babel/template@7.27.2": - resolution: - { - integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==, - } - engines: { node: ">=6.9.0" } - - "@babel/traverse@7.27.4": - resolution: - { - integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==, - } - engines: { node: ">=6.9.0" } - - "@babel/types@7.27.6": - resolution: - { - integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==, - } - engines: { node: ">=6.9.0" } - - "@bcoe/v8-coverage@0.2.3": - resolution: - { - integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==, - } - - "@commitlint/cli@17.8.1": - resolution: - { - integrity: sha512-ay+WbzQesE0Rv4EQKfNbSMiJJ12KdKTDzIt0tcK4k11FdsWmtwP0Kp1NWMOUswfIWo6Eb7p7Ln721Nx9FLNBjg==, - } - engines: { node: ">=v14" } + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@mswjs/interceptors@0.39.8': + resolution: {integrity: sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==} + engines: {node: '>=18'} + + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + + '@playwright/test@1.56.1': + resolution: {integrity: sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==} + engines: {node: '>=18'} hasBin: true - "@commitlint/config-conventional@17.8.1": - resolution: - { - integrity: sha512-NxCOHx1kgneig3VLauWJcDWS40DVjg7nKOpBEEK9E5fjJpQqLCilcnKkIIjdBH98kEO1q3NpE5NSrZ2kl/QGJg==, - } - engines: { node: ">=v14" } - - "@commitlint/config-validator@17.8.1": - resolution: - { - integrity: sha512-UUgUC+sNiiMwkyiuIFR7JG2cfd9t/7MV8VB4TZ+q02ZFkHoduUS4tJGsCBWvBOGD9Btev6IecPMvlWUfJorkEA==, - } - engines: { node: ">=v14" } - - "@commitlint/ensure@17.8.1": - resolution: - { - integrity: sha512-xjafwKxid8s1K23NFpL8JNo6JnY/ysetKo8kegVM7c8vs+kWLP8VrQq+NbhgVlmCojhEDbzQKp4eRXSjVOGsow==, - } - engines: { node: ">=v14" } - - "@commitlint/execute-rule@17.8.1": - resolution: - { - integrity: sha512-JHVupQeSdNI6xzA9SqMF+p/JjrHTcrJdI02PwesQIDCIGUrv04hicJgCcws5nzaoZbROapPs0s6zeVHoxpMwFQ==, - } - engines: { node: ">=v14" } - - "@commitlint/format@17.8.1": - resolution: - { - integrity: sha512-f3oMTyZ84M9ht7fb93wbCKmWxO5/kKSbwuYvS867duVomoOsgrgljkGGIztmT/srZnaiGbaK8+Wf8Ik2tSr5eg==, - } - engines: { node: ">=v14" } - - "@commitlint/is-ignored@17.8.1": - resolution: - { - integrity: sha512-UshMi4Ltb4ZlNn4F7WtSEugFDZmctzFpmbqvpyxD3la510J+PLcnyhf9chs7EryaRFJMdAKwsEKfNK0jL/QM4g==, - } - engines: { node: ">=v14" } - - "@commitlint/lint@17.8.1": - resolution: - { - integrity: sha512-aQUlwIR1/VMv2D4GXSk7PfL5hIaFSfy6hSHV94O8Y27T5q+DlDEgd/cZ4KmVI+MWKzFfCTiTuWqjfRSfdRllCA==, - } - engines: { node: ">=v14" } - - "@commitlint/load@17.8.1": - resolution: - { - integrity: sha512-iF4CL7KDFstP1kpVUkT8K2Wl17h2yx9VaR1ztTc8vzByWWcbO/WaKwxsnCOqow9tVAlzPfo1ywk9m2oJ9ucMqA==, - } - engines: { node: ">=v14" } - - "@commitlint/message@17.8.1": - resolution: - { - integrity: sha512-6bYL1GUQsD6bLhTH3QQty8pVFoETfFQlMn2Nzmz3AOLqRVfNNtXBaSY0dhZ0dM6A2MEq4+2d7L/2LP8TjqGRkA==, - } - engines: { node: ">=v14" } - - "@commitlint/parse@17.8.1": - resolution: - { - integrity: sha512-/wLUickTo0rNpQgWwLPavTm7WbwkZoBy3X8PpkUmlSmQJyWQTj0m6bDjiykMaDt41qcUbfeFfaCvXfiR4EGnfw==, - } - engines: { node: ">=v14" } - - "@commitlint/read@17.8.1": - resolution: - { - integrity: sha512-Fd55Oaz9irzBESPCdMd8vWWgxsW3OWR99wOntBDHgf9h7Y6OOHjWEdS9Xzen1GFndqgyoaFplQS5y7KZe0kO2w==, - } - engines: { node: ">=v14" } - - "@commitlint/resolve-extends@17.8.1": - resolution: - { - integrity: sha512-W/ryRoQ0TSVXqJrx5SGkaYuAaE/BUontL1j1HsKckvM6e5ZaG0M9126zcwL6peKSuIetJi7E87PRQF8O86EW0Q==, - } - engines: { node: ">=v14" } - - "@commitlint/rules@17.8.1": - resolution: - { - integrity: sha512-2b7OdVbN7MTAt9U0vKOYKCDsOvESVXxQmrvuVUZ0rGFMCrCPJWWP1GJ7f0lAypbDAhaGb8zqtdOr47192LBrIA==, - } - engines: { node: ">=v14" } - - "@commitlint/to-lines@17.8.1": - resolution: - { - integrity: sha512-LE0jb8CuR/mj6xJyrIk8VLz03OEzXFgLdivBytoooKO5xLt5yalc8Ma5guTWobw998sbR3ogDd+2jed03CFmJA==, - } - engines: { node: ">=v14" } - - "@commitlint/top-level@17.8.1": - resolution: - { - integrity: sha512-l6+Z6rrNf5p333SHfEte6r+WkOxGlWK4bLuZKbtf/2TXRN+qhrvn1XE63VhD8Oe9oIHQ7F7W1nG2k/TJFhx2yA==, - } - engines: { node: ">=v14" } - - "@commitlint/types@17.8.1": - resolution: - { - integrity: sha512-PXDQXkAmiMEG162Bqdh9ChML/GJZo6vU+7F03ALKDK8zYc6SuAr47LjG7hGYRqUOz+WK0dU7bQ0xzuqFMdxzeQ==, - } - engines: { node: ">=v14" } - - "@cspotcode/source-map-support@0.8.1": - resolution: - { - integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, - } - engines: { node: ">=12" } - - "@deepgram/captions@1.2.0": - resolution: - { - integrity: sha512-8B1C/oTxTxyHlSFubAhNRgCbQ2SQ5wwvtlByn8sDYZvdDtdn/VE2yEPZ4BvUnrKWmsbTQY6/ooLV+9Ka2qmDSQ==, - } - engines: { node: ">=18.0.0" } - - "@discoveryjs/json-ext@0.5.7": - resolution: - { - integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==, - } - engines: { node: ">=10.0.0" } - - "@eslint-community/eslint-utils@4.7.0": - resolution: - { - integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - "@eslint-community/regexpp@4.12.1": - resolution: - { - integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==, - } - engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } - - "@eslint/eslintrc@2.1.4": - resolution: - { - integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - - "@eslint/js@8.57.1": - resolution: - { - integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - - "@humanwhocodes/config-array@0.13.0": - resolution: - { - integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==, - } - engines: { node: ">=10.10.0" } - deprecated: Use @eslint/config-array instead - - "@humanwhocodes/module-importer@1.0.1": - resolution: - { - integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, - } - engines: { node: ">=12.22" } - - "@humanwhocodes/object-schema@2.0.3": - resolution: - { - integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==, - } - deprecated: Use @eslint/object-schema instead - - "@isaacs/balanced-match@4.0.1": - resolution: - { - integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==, - } - engines: { node: 20 || >=22 } - - "@isaacs/brace-expansion@5.0.0": - resolution: - { - integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==, - } - engines: { node: 20 || >=22 } - - "@isaacs/cliui@8.0.2": - 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 + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + cpu: [arm] + os: [android] - "@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 + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + cpu: [arm64] + os: [android] - "@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.8": - resolution: - { - integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==, - } - engines: { node: ">=6.0.0" } - - "@jridgewell/resolve-uri@3.1.2": - resolution: - { - integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, - } - engines: { node: ">=6.0.0" } - - "@jridgewell/set-array@1.2.1": - resolution: - { - integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==, - } - engines: { node: ">=6.0.0" } - - "@jridgewell/source-map@0.3.6": - resolution: - { - integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==, - } - - "@jridgewell/sourcemap-codec@1.5.0": - resolution: - { - integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==, - } - - "@jridgewell/trace-mapping@0.3.25": - resolution: - { - integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==, - } - - "@jridgewell/trace-mapping@0.3.9": - resolution: - { - integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, - } - - "@nodelib/fs.scandir@2.1.5": - resolution: - { - integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, - } - engines: { node: ">= 8" } - - "@nodelib/fs.stat@2.0.5": - resolution: - { - integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, - } - engines: { node: ">= 8" } - - "@nodelib/fs.walk@1.2.8": - resolution: - { - integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, - } - engines: { node: ">= 8" } - - "@sinclair/typebox@0.27.8": - resolution: - { - integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==, - } - - "@sinonjs/commons@3.0.1": - resolution: - { - integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==, - } - - "@sinonjs/fake-timers@10.3.0": - resolution: - { - integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==, - } - - "@tootallnate/once@2.0.0": - resolution: - { - integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==, - } - engines: { node: ">= 10" } - - "@tsconfig/node10@1.0.11": - resolution: - { - integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==, - } - - "@tsconfig/node12@1.0.11": - resolution: - { - integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==, - } - - "@tsconfig/node14@1.0.3": - resolution: - { - integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==, - } - - "@tsconfig/node16@1.0.4": - resolution: - { - integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==, - } - - "@types/babel__core@7.20.5": - resolution: - { - integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, - } - - "@types/babel__generator@7.27.0": - resolution: - { - integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==, - } - - "@types/babel__template@7.4.4": - resolution: - { - integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, - } - - "@types/babel__traverse@7.20.7": - resolution: - { - integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==, - } - - "@types/eslint-scope@3.7.7": - resolution: - { - integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==, - } - - "@types/eslint@9.6.1": - resolution: - { - integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==, - } - - "@types/estree@1.0.8": - resolution: - { - integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, - } - - "@types/graceful-fs@4.1.9": - resolution: - { - integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==, - } - - "@types/istanbul-lib-coverage@2.0.6": - resolution: - { - integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==, - } - - "@types/istanbul-lib-report@3.0.3": - resolution: - { - integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==, - } - - "@types/istanbul-reports@3.0.4": - resolution: - { - integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==, - } - - "@types/jest@29.5.14": - resolution: - { - integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==, - } - - "@types/jsdom@20.0.1": - resolution: - { - integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==, - } - - "@types/json-schema@7.0.15": - resolution: - { - integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, - } - - "@types/minimist@1.2.5": - resolution: - { - integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==, - } - - "@types/node@18.19.112": - resolution: - { - integrity: sha512-i+Vukt9POdS/MBI7YrrkkI5fMfwFtOjphSmt4WXYLfwqsfr6z/HdCx7LqT9M7JktGob8WNgj8nFB4TbGNE4Cog==, - } - - "@types/node@20.5.1": - resolution: - { - integrity: sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==, - } - - "@types/normalize-package-data@2.4.4": - resolution: - { - integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==, - } - - "@types/parse-json@4.0.2": - resolution: - { - integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==, - } - - "@types/stack-utils@2.0.3": - resolution: - { - integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==, - } - - "@types/tough-cookie@4.0.5": - resolution: - { - integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==, - } - - "@types/ws@8.18.1": - resolution: - { - integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==, - } - - "@types/yargs-parser@21.0.3": - resolution: - { - integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==, - } - - "@types/yargs@17.0.33": - resolution: - { - integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==, - } - - "@typescript-eslint/eslint-plugin@8.34.0": - resolution: - { - integrity: sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - "@typescript-eslint/parser": ^8.34.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <5.9.0" - - "@typescript-eslint/parser@8.34.0": - resolution: - { - integrity: sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <5.9.0" - - "@typescript-eslint/project-service@8.34.0": - resolution: - { - integrity: sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - typescript: ">=4.8.4 <5.9.0" - - "@typescript-eslint/scope-manager@8.34.0": - resolution: - { - integrity: sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - "@typescript-eslint/tsconfig-utils@8.34.0": - resolution: - { - integrity: sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - typescript: ">=4.8.4 <5.9.0" - - "@typescript-eslint/type-utils@8.34.0": - resolution: - { - integrity: sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <5.9.0" - - "@typescript-eslint/types@8.34.0": - resolution: - { - integrity: sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - "@typescript-eslint/typescript-estree@8.34.0": - resolution: - { - integrity: sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - typescript: ">=4.8.4 <5.9.0" - - "@typescript-eslint/utils@8.34.0": - resolution: - { - integrity: sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <5.9.0" - - "@typescript-eslint/visitor-keys@8.34.0": - resolution: - { - integrity: sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - "@ungap/structured-clone@1.3.0": - resolution: - { - integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==, - } - - "@webassemblyjs/ast@1.14.1": - resolution: - { - integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==, - } - - "@webassemblyjs/floating-point-hex-parser@1.13.2": - resolution: - { - integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==, - } - - "@webassemblyjs/helper-api-error@1.13.2": - resolution: - { - integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==, - } - - "@webassemblyjs/helper-buffer@1.14.1": - resolution: - { - integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==, - } - - "@webassemblyjs/helper-numbers@1.13.2": - resolution: - { - integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==, - } - - "@webassemblyjs/helper-wasm-bytecode@1.13.2": - resolution: - { - integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==, - } - - "@webassemblyjs/helper-wasm-section@1.14.1": - resolution: - { - integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==, - } - - "@webassemblyjs/ieee754@1.13.2": - resolution: - { - integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==, - } - - "@webassemblyjs/leb128@1.13.2": - resolution: - { - integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==, - } - - "@webassemblyjs/utf8@1.13.2": - resolution: - { - integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==, - } - - "@webassemblyjs/wasm-edit@1.14.1": - resolution: - { - integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==, - } - - "@webassemblyjs/wasm-gen@1.14.1": - resolution: - { - integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==, - } - - "@webassemblyjs/wasm-opt@1.14.1": - resolution: - { - integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==, - } - - "@webassemblyjs/wasm-parser@1.14.1": - resolution: - { - integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==, - } - - "@webassemblyjs/wast-printer@1.14.1": - resolution: - { - integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==, - } - - "@webpack-cli/configtest@1.2.0": - resolution: - { - integrity: sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==, - } - peerDependencies: - webpack: 4.x.x || 5.x.x - webpack-cli: 4.x.x - - "@webpack-cli/info@1.5.0": - resolution: - { - integrity: sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==, - } - peerDependencies: - webpack-cli: 4.x.x + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + cpu: [x64] + os: [win32] + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - "@webpack-cli/serve@1.7.0": - resolution: - { - integrity: sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==, - } + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: - webpack-cli: 4.x.x - webpack-dev-server: "*" + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 peerDependenciesMeta: - webpack-dev-server: + msw: + optional: true + vite: optional: true - "@xtuc/ieee754@1.2.0": - resolution: - { - integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==, - } - - "@xtuc/long@4.2.2": - resolution: - { - integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==, - } - - JSONStream@1.3.5: - resolution: - { - integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==, - } - hasBin: true + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - abab@2.0.6: - resolution: - { - integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==, - } - deprecated: Use your platform's native atob() and btoa() methods instead - - acorn-globals@7.0.1: - resolution: - { - integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==, - } - - acorn-jsx@5.3.2: - resolution: - { - integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, - } - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - acorn-walk@8.3.4: - resolution: - { - integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==, - } - engines: { node: ">=0.4.0" } + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} + peerDependencies: + acorn: ^8.14.0 acorn@8.15.0: - resolution: - { - integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==, - } - engines: { node: ">=0.4.0" } + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} hasBin: true - agent-base@6.0.2: - resolution: - { - integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==, - } - engines: { node: ">= 6.0.0" } - ajv-formats@2.1.1: - resolution: - { - integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==, - } + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: ajv: ^8.0.0 peerDependenciesMeta: @@ -1277,7894 +569,1379 @@ packages: optional: true ajv-keywords@5.1.0: - resolution: - { - integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==, - } + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} peerDependencies: ajv: ^8.8.2 - ajv@6.12.6: - resolution: - { - integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, - } - ajv@8.17.1: - resolution: - { - integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==, - } - - ansi-escapes@4.3.2: - resolution: - { - integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} ansi-regex@5.0.1: - resolution: - { - integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, - } - engines: { node: ">=8" } - - ansi-regex@6.1.0: - resolution: - { - integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==, - } - engines: { node: ">=12" } - - ansi-styles@3.2.1: - resolution: - { - integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} 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" } - - 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==, - } - - argparse@2.0.1: - resolution: - { - integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, - } - - array-buffer-byte-length@1.0.2: - resolution: - { - integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==, - } - engines: { node: ">= 0.4" } - - array-ify@1.0.0: - resolution: - { - integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==, - } - - array-union@2.1.0: - resolution: - { - integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==, - } - engines: { node: ">=8" } - - arraybuffer.prototype.slice@1.0.4: - resolution: - { - integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==, - } - engines: { node: ">= 0.4" } - - arrify@1.0.1: - resolution: - { - integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==, - } - engines: { node: ">=0.10.0" } - - async-function@1.0.0: - resolution: - { - integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==, - } - engines: { node: ">= 0.4" } - - async@3.2.6: - resolution: - { - integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==, - } - - asynckit@0.4.0: - resolution: - { - integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, - } - - available-typed-arrays@1.0.7: - resolution: - { - integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==, - } - engines: { node: ">= 0.4" } - - 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.1.0: - resolution: - { - integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==, - } - 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 - - balanced-match@1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, - } - - base64-js@1.5.1: - resolution: - { - integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, - } - - big.js@5.2.2: - resolution: - { - integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==, - } - - binary-extensions@2.3.0: - resolution: - { - integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, - } - engines: { node: ">=8" } - - brace-expansion@1.1.12: - resolution: - { - integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==, - } - - brace-expansion@2.0.2: - resolution: - { - integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==, - } + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} - braces@3.0.3: - resolution: - { - integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, - } - engines: { node: ">=8" } - - browserslist@4.25.0: - resolution: - { - integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==, - } - engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + baseline-browser-mapping@2.8.29: + resolution: {integrity: sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==} hasBin: true - bs-logger@0.2.6: - resolution: - { - integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==, - } - engines: { node: ">= 6" } + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} - bser@2.1.1: - resolution: - { - integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==, - } + browserslist@4.28.0: + resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true buffer-from@1.1.2: - resolution: - { - integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, - } - - buffer@6.0.3: - resolution: - { - integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==, - } - - call-bind-apply-helpers@1.0.2: - resolution: - { - integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, - } - engines: { node: ">= 0.4" } - - call-bind@1.0.8: - resolution: - { - integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==, - } - engines: { node: ">= 0.4" } - - call-bound@1.0.4: - resolution: - { - integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, - } - engines: { node: ">= 0.4" } - - callsites@3.1.0: - resolution: - { - integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, - } - engines: { node: ">=6" } - - camelcase-keys@6.2.2: - resolution: - { - integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==, - } - engines: { node: ">=8" } - - 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.30001723: - resolution: - { - integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==, - } - - chalk@2.4.2: - resolution: - { - integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + caniuse-lite@1.0.30001756: + resolution: {integrity: sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} 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" } + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} chrome-trace-event@1.0.4: - resolution: - { - integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==, - } - engines: { node: ">=6.0" } - - ci-info@2.0.0: - resolution: - { - integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==, - } - - ci-info@3.9.0: - resolution: - { - integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==, - } - engines: { node: ">=8" } - - cjs-module-lexer@1.4.3: - resolution: - { - integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==, - } - - cliui@7.0.4: - resolution: - { - integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==, - } + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} cliui@8.0.1: - resolution: - { - integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, - } - engines: { node: ">=12" } - - clone-deep@4.0.1: - resolution: - { - integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==, - } - engines: { node: ">=6" } - - co@4.6.0: - resolution: - { - integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==, - } - engines: { iojs: ">= 1.0.0", node: ">= 0.12.0" } - - collect-v8-coverage@1.0.2: - resolution: - { - integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==, - } - - color-convert@1.9.3: - resolution: - { - integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, - } + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} 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==, - } + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} color-name@1.1.4: - resolution: - { - integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, - } - - colorette@2.0.20: - resolution: - { - integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==, - } - - combined-stream@1.0.8: - resolution: - { - integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, - } - engines: { node: ">= 0.8" } - - commander@12.1.0: - resolution: - { - integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} commander@2.20.3: - resolution: - { - integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, - } - - commander@7.2.0: - resolution: - { - integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==, - } - engines: { node: ">= 10" } - - compare-func@2.0.0: - resolution: - { - integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==, - } - - compare-versions@3.6.0: - resolution: - { - integrity: sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==, - } - - concat-map@0.0.1: - resolution: - { - integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, - } - - consola@2.15.3: - resolution: - { - integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==, - } - - conventional-changelog-angular@6.0.0: - resolution: - { - integrity: sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==, - } - engines: { node: ">=14" } - - conventional-changelog-conventionalcommits@6.1.0: - resolution: - { - integrity: sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==, - } - engines: { node: ">=14" } - - conventional-commits-parser@4.0.0: - resolution: - { - integrity: sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==, - } - engines: { node: ">=14" } - hasBin: true - - convert-source-map@2.0.0: - resolution: - { - integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, - } - - core-util-is@1.0.3: - resolution: - { - integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, - } - - cosmiconfig-typescript-loader@4.4.0: - resolution: - { - integrity: sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw==, - } - engines: { node: ">=v14.21.3" } - peerDependencies: - "@types/node": "*" - cosmiconfig: ">=7" - ts-node: ">=10" - typescript: ">=4" - - cosmiconfig@7.1.0: - resolution: - { - integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==, - } - engines: { node: ">=10" } - - cosmiconfig@8.3.6: - resolution: - { - integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==, - } - engines: { node: ">=14" } - peerDependencies: - typescript: ">=4.9.5" - peerDependenciesMeta: - typescript: - optional: true - - create-jest@29.7.0: - resolution: - { - integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - hasBin: true + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - create-require@1.1.1: - resolution: - { - integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==, - } - - cross-env@7.0.3: - resolution: - { - integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==, - } - engines: { node: ">=10.14", npm: ">=6", yarn: ">=1" } - hasBin: true + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} - cross-fetch@3.2.0: - resolution: - { - integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==, - } - - cross-spawn@6.0.6: - resolution: - { - integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==, - } - engines: { node: ">=4.8" } - - cross-spawn@7.0.6: - resolution: - { - integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, - } - engines: { node: ">= 8" } - - cssom@0.3.8: - resolution: - { - integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==, - } - - cssom@0.5.0: - resolution: - { - integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==, - } - - cssstyle@2.3.0: - resolution: - { - integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==, - } - engines: { node: ">=8" } - - dargs@7.0.0: - resolution: - { - integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==, - } - engines: { node: ">=8" } - - data-urls@3.0.2: - resolution: - { - integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==, - } - engines: { node: ">=12" } - - data-view-buffer@1.0.2: - resolution: - { - integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==, - } - engines: { node: ">= 0.4" } - - data-view-byte-length@1.0.2: - resolution: - { - integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==, - } - engines: { node: ">= 0.4" } - - data-view-byte-offset@1.0.1: - resolution: - { - integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==, - } - engines: { node: ">= 0.4" } - - dayjs@1.11.13: - resolution: - { - integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==, - } - - debug@4.4.1: - resolution: - { - integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==, - } - engines: { node: ">=6.0" } + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} peerDependencies: - supports-color: "*" + supports-color: '*' peerDependenciesMeta: supports-color: optional: true - decamelize-keys@1.1.1: - resolution: - { - integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==, - } - engines: { node: ">=0.10.0" } - - decamelize@1.2.0: - resolution: - { - integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==, - } - engines: { node: ">=0.10.0" } - - decimal.js@10.5.0: - resolution: - { - integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==, - } - - dedent@1.6.0: - resolution: - { - integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==, - } - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - - deep-extend@0.6.0: - resolution: - { - integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==, - } - engines: { node: ">=4.0.0" } - - deep-is@0.1.4: - resolution: - { - integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, - } - - deepmerge@4.3.1: - resolution: - { - integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==, - } - engines: { node: ">=0.10.0" } - - define-data-property@1.1.4: - resolution: - { - integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, - } - engines: { node: ">= 0.4" } - - define-properties@1.2.1: - resolution: - { - integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, - } - engines: { node: ">= 0.4" } - - delayed-stream@1.0.0: - resolution: - { - integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, - } - engines: { node: ">=0.4.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" } - - doctrine@3.0.0: - resolution: - { - integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==, - } - engines: { node: ">=6.0.0" } - - domexception@4.0.0: - resolution: - { - integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==, - } - engines: { node: ">=12" } - deprecated: Use your platform's native DOMException instead - - dot-prop@5.3.0: - resolution: - { - integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==, - } - engines: { node: ">=8" } - - dotenv@16.5.0: - resolution: - { - integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==, - } - engines: { node: ">=12" } - - dunder-proto@1.0.1: - resolution: - { - integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, - } - engines: { node: ">= 0.4" } - - 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.5.167: - resolution: - { - integrity: sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==, - } + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} - emittery@0.13.1: - resolution: - { - integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==, - } - engines: { node: ">=12" } + electron-to-chromium@1.5.256: + resolution: {integrity: sha512-uqYq1IQhpXXLX+HgiXdyOZml7spy4xfy42yPxcCCRjswp0fYM2X+JwCON07lqnpLEGVCj739B7Yr+FngmHBMEQ==} emoji-regex@8.0.0: - resolution: - { - integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, - } - - emoji-regex@9.2.2: - resolution: - { - integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, - } - - emojis-list@3.0.0: - resolution: - { - integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==, - } - engines: { node: ">= 4" } - - end-of-stream@1.4.4: - resolution: - { - integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, - } - - enhanced-resolve@4.5.0: - resolution: - { - integrity: sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==, - } - engines: { node: ">=6.9.0" } - - enhanced-resolve@5.18.1: - resolution: - { - integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==, - } - engines: { node: ">=10.13.0" } - - entities@4.5.0: - resolution: - { - integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, - } - engines: { node: ">=0.12" } - - entities@6.0.1: - resolution: - { - integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==, - } - engines: { node: ">=0.12" } - - envinfo@7.14.0: - resolution: - { - integrity: sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==, - } - engines: { node: ">=4" } - hasBin: true - - errno@0.1.8: - resolution: - { - integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==, - } - hasBin: true + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - error-ex@1.3.2: - resolution: - { - integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, - } - - es-abstract@1.24.0: - resolution: - { - integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==, - } - engines: { node: ">= 0.4" } - - es-define-property@1.0.1: - resolution: - { - integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, - } - engines: { node: ">= 0.4" } - - es-errors@1.3.0: - resolution: - { - integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, - } - engines: { node: ">= 0.4" } + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} es-module-lexer@1.7.0: - resolution: - { - integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==, - } - - es-object-atoms@1.1.1: - resolution: - { - integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, - } - engines: { node: ">= 0.4" } - - es-set-tostringtag@2.1.0: - resolution: - { - integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, - } - engines: { node: ">= 0.4" } - - es-to-primitive@1.3.0: - resolution: - { - integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==, - } - engines: { node: ">= 0.4" } - - escalade@3.2.0: - resolution: - { - integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, - } - 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" } - - escape-string-regexp@4.0.0: - resolution: - { - integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, - } - engines: { node: ">=10" } - - escodegen@2.1.0: - resolution: - { - integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==, - } - engines: { node: ">=6.0" } - hasBin: true + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - eslint-scope@5.1.1: - resolution: - { - integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==, - } - engines: { node: ">=8.0.0" } - - eslint-scope@7.2.2: - resolution: - { - integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - - eslint-visitor-keys@3.4.3: - resolution: - { - integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - - eslint-visitor-keys@4.2.1: - resolution: - { - integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==, - } - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - - eslint@8.57.1: - resolution: - { - integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} hasBin: true - espree@9.6.1: - resolution: - { - integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - - esprima@4.0.1: - resolution: - { - integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==, - } - engines: { node: ">=4" } - hasBin: true + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} - esquery@1.6.0: - resolution: - { - integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==, - } - engines: { node: ">=0.10" } + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} esrecurse@4.3.0: - resolution: - { - integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, - } - engines: { node: ">=4.0" } + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} estraverse@4.3.0: - resolution: - { - integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==, - } - engines: { node: ">=4.0" } + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} estraverse@5.3.0: - resolution: - { - integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, - } - engines: { node: ">=4.0" } - - esutils@2.0.3: - resolution: - { - integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} events@3.3.0: - resolution: - { - integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, - } - engines: { node: ">=0.8.x" } - - execa@4.1.0: - resolution: - { - integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==, - } - engines: { node: ">=10" } - - 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" } - - expect@29.7.0: - resolution: - { - integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} fast-deep-equal@3.1.3: - resolution: - { - integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, - } - - fast-glob@3.3.3: - resolution: - { - integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, - } - engines: { node: ">=8.6.0" } - - fast-json-stable-stringify@2.1.0: - resolution: - { - integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, - } - - fast-levenshtein@2.0.6: - resolution: - { - integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, - } - - fast-uri@3.0.6: - resolution: - { - integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==, - } - - fastest-levenshtein@1.0.16: - resolution: - { - integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==, - } - engines: { node: ">= 4.9.1" } - - fastq@1.19.1: - resolution: - { - integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==, - } - - fb-watchman@2.0.2: - resolution: - { - integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==, - } - - file-entry-cache@6.0.1: - resolution: - { - integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==, - } - engines: { node: ^10.12.0 || >=12.0.0 } - - filelist@1.0.4: - resolution: - { - integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==, - } + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true fill-range@7.1.1: - resolution: - { - integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, - } - engines: { node: ">=8" } - - find-up@4.1.0: - resolution: - { - integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==, - } - engines: { node: ">=8" } - - find-up@5.0.0: - resolution: - { - integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, - } - engines: { node: ">=10" } - - find-versions@4.0.0: - resolution: - { - integrity: sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==, - } - engines: { node: ">=10" } - - flat-cache@3.2.0: - resolution: - { - integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==, - } - engines: { node: ^10.12.0 || >=12.0.0 } - - flat@5.0.2: - resolution: - { - integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==, - } - hasBin: true + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} - flatted@3.3.3: - resolution: - { - integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==, - } - - for-each@0.3.5: - resolution: - { - integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==, - } - engines: { node: ">= 0.4" } - - foreground-child@3.3.1: - resolution: - { - integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, - } - engines: { node: ">=14" } - - form-data@4.0.3: - resolution: - { - integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==, - } - engines: { node: ">= 6" } - - fs-extra@11.3.0: - resolution: - { - integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==, - } - engines: { node: ">=14.14" } - - fs.realpath@1.0.0: - resolution: - { - integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, - } + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] fsevents@2.3.3: - resolution: - { - integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, - } - engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + 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==, - } - - function.prototype.name@1.1.8: - resolution: - { - integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==, - } - engines: { node: ">= 0.4" } - - functions-have-names@1.2.3: - resolution: - { - integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, - } - - 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-intrinsic@1.3.0: - resolution: - { - integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, - } - engines: { node: ">= 0.4" } - - get-package-type@0.1.0: - resolution: - { - integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==, - } - engines: { node: ">=8.0.0" } - - get-proto@1.0.1: - resolution: - { - integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, - } - engines: { node: ">= 0.4" } - - get-stdin@9.0.0: - resolution: - { - integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==, - } - engines: { node: ">=12" } - - get-stream@5.2.0: - resolution: - { - integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==, - } - engines: { node: ">=8" } - - get-stream@6.0.1: - resolution: - { - integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, - } - engines: { node: ">=10" } - - get-symbol-description@1.1.0: - resolution: - { - integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==, - } - engines: { node: ">= 0.4" } - - git-raw-commits@2.0.11: - resolution: - { - integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==, - } - engines: { node: ">=10" } - hasBin: true - - glob-parent@5.1.2: - resolution: - { - integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, - } - engines: { node: ">= 6" } - - glob-parent@6.0.2: - resolution: - { - integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, - } - engines: { node: ">=10.13.0" } + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} glob-to-regexp@0.4.1: - resolution: - { - integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==, - } - - glob@11.0.3: - resolution: - { - integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==, - } - engines: { node: 20 || >=22 } - hasBin: true - - glob@7.2.3: - resolution: - { - integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, - } - deprecated: Glob versions prior to v9 are no longer supported - - glob@8.1.0: - resolution: - { - integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==, - } - engines: { node: ">=12" } - deprecated: Glob versions prior to v9 are no longer supported - - global-dirs@0.1.1: - resolution: - { - integrity: sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==, - } - engines: { node: ">=4" } - - globals@11.12.0: - resolution: - { - integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==, - } - engines: { node: ">=4" } - - globals@13.24.0: - resolution: - { - integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==, - } - engines: { node: ">=8" } - - globalthis@1.0.4: - resolution: - { - integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==, - } - engines: { node: ">= 0.4" } - - globby@11.1.0: - resolution: - { - integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==, - } - engines: { node: ">=10" } - - gopd@1.2.0: - resolution: - { - integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} graceful-fs@4.2.11: - resolution: - { - integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, - } - - graphemer@1.4.0: - resolution: - { - integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, - } - - hard-rejection@2.1.0: - resolution: - { - integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==, - } - engines: { node: ">=6" } - - has-bigints@1.1.0: - resolution: - { - integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==, - } - engines: { node: ">= 0.4" } - - has-flag@3.0.0: - resolution: - { - integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - has-flag@4.0.0: - resolution: - { - integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, - } - engines: { node: ">=8" } - - has-property-descriptors@1.0.2: - resolution: - { - integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, - } - - has-proto@1.2.0: - resolution: - { - integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==, - } - engines: { node: ">= 0.4" } - - has-symbols@1.1.0: - resolution: - { - integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, - } - engines: { node: ">= 0.4" } - - has-tostringtag@1.0.2: - resolution: - { - integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, - } - engines: { node: ">= 0.4" } - - hasown@2.0.2: - resolution: - { - integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, - } - engines: { node: ">= 0.4" } - - hosted-git-info@2.8.9: - resolution: - { - integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==, - } - - hosted-git-info@4.1.0: - resolution: - { - integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==, - } - engines: { node: ">=10" } - - html-encoding-sniffer@3.0.0: - resolution: - { - integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==, - } - engines: { node: ">=12" } - - html-escaper@2.0.2: - resolution: - { - integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==, - } - - http-proxy-agent@5.0.0: - resolution: - { - integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==, - } - engines: { node: ">= 6" } - - https-proxy-agent@5.0.1: - resolution: - { - integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==, - } - engines: { node: ">= 6" } - - human-signals@1.1.1: - resolution: - { - integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==, - } - engines: { node: ">=8.12.0" } - - human-signals@2.1.0: - resolution: - { - integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==, - } - engines: { node: ">=10.17.0" } - - husky@4.3.8: - resolution: - { - integrity: sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==, - } - engines: { node: ">=10" } - hasBin: true + graphql@16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - iconv-lite@0.6.3: - resolution: - { - integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==, - } - engines: { node: ">=0.10.0" } - - ieee754@1.2.1: - resolution: - { - integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, - } - - ignore-by-default@1.0.1: - resolution: - { - integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==, - } - - ignore@5.3.2: - resolution: - { - integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, - } - engines: { node: ">= 4" } - - ignore@6.0.2: - resolution: - { - integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==, - } - engines: { node: ">= 4" } - - ignore@7.0.5: - resolution: - { - integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==, - } - engines: { node: ">= 4" } - - import-fresh@3.3.1: - resolution: - { - integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, - } - engines: { node: ">=6" } - - import-local@3.2.0: - resolution: - { - integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==, - } - engines: { node: ">=8" } - hasBin: true + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} - imurmurhash@0.1.4: - resolution: - { - integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, - } - engines: { node: ">=0.8.19" } - - indent-string@4.0.0: - resolution: - { - integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, - } - engines: { node: ">=8" } - - 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==, - } - - ini@1.3.8: - resolution: - { - integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, - } - - ini@2.0.0: - resolution: - { - integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==, - } - engines: { node: ">=10" } - - ini@4.1.3: - resolution: - { - integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } - - internal-slot@1.1.0: - resolution: - { - integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==, - } - engines: { node: ">= 0.4" } - - interpret@2.2.0: - resolution: - { - integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==, - } - engines: { node: ">= 0.10" } - - is-arguments@1.2.0: - resolution: - { - integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==, - } - engines: { node: ">= 0.4" } - - is-array-buffer@3.0.5: - resolution: - { - integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==, - } - engines: { node: ">= 0.4" } - - is-arrayish@0.2.1: - resolution: - { - integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, - } - - is-async-function@2.1.1: - resolution: - { - integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==, - } - engines: { node: ">= 0.4" } - - is-bigint@1.1.0: - resolution: - { - integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==, - } - engines: { node: ">= 0.4" } - - is-binary-path@2.1.0: - resolution: - { - integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, - } - engines: { node: ">=8" } - - is-boolean-object@1.2.2: - resolution: - { - integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==, - } - engines: { node: ">= 0.4" } - - is-callable@1.2.7: - resolution: - { - integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, - } - engines: { node: ">= 0.4" } - - is-core-module@2.16.1: - resolution: - { - integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==, - } - engines: { node: ">= 0.4" } - - is-data-view@1.0.2: - resolution: - { - integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==, - } - engines: { node: ">= 0.4" } - - is-date-object@1.1.0: - resolution: - { - integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==, - } - engines: { node: ">= 0.4" } - - is-extglob@2.1.1: - resolution: - { - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, - } - engines: { node: ">=0.10.0" } - - is-finalizationregistry@1.1.1: - resolution: - { - integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==, - } - engines: { node: ">= 0.4" } + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} 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-generator-function@1.1.0: - resolution: - { - integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==, - } - engines: { node: ">= 0.4" } - - is-glob@4.0.3: - resolution: - { - integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, - } - engines: { node: ">=0.10.0" } - - is-map@2.0.3: - resolution: - { - integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==, - } - engines: { node: ">= 0.4" } - - is-negative-zero@2.0.3: - resolution: - { - integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==, - } - engines: { node: ">= 0.4" } - - is-number-object@1.1.1: - resolution: - { - integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==, - } - engines: { node: ">= 0.4" } - - is-number@7.0.0: - resolution: - { - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, - } - engines: { node: ">=0.12.0" } - - is-obj@2.0.0: - resolution: - { - integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==, - } - engines: { node: ">=8" } - - is-path-inside@3.0.3: - resolution: - { - integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==, - } - engines: { node: ">=8" } - - is-plain-obj@1.1.0: - resolution: - { - integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==, - } - engines: { node: ">=0.10.0" } - - is-plain-object@2.0.4: - resolution: - { - integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==, - } - engines: { node: ">=0.10.0" } - - is-potential-custom-element-name@1.0.1: - resolution: - { - integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==, - } - - is-regex@1.2.1: - resolution: - { - integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==, - } - engines: { node: ">= 0.4" } - - is-set@2.0.3: - resolution: - { - integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==, - } - engines: { node: ">= 0.4" } - - is-shared-array-buffer@1.0.4: - resolution: - { - integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==, - } - engines: { node: ">= 0.4" } - - is-stream@2.0.1: - resolution: - { - integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, - } - engines: { node: ">=8" } - - is-string@1.1.1: - resolution: - { - integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==, - } - engines: { node: ">= 0.4" } - - is-symbol@1.1.1: - resolution: - { - integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==, - } - engines: { node: ">= 0.4" } - - is-text-path@1.0.1: - resolution: - { - integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==, - } - engines: { node: ">=0.10.0" } - - is-typed-array@1.1.15: - resolution: - { - integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==, - } - engines: { node: ">= 0.4" } - - is-weakmap@2.0.2: - resolution: - { - integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==, - } - engines: { node: ">= 0.4" } - - is-weakref@1.1.1: - resolution: - { - integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==, - } - engines: { node: ">= 0.4" } - - is-weakset@2.0.4: - resolution: - { - integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==, - } - engines: { node: ">= 0.4" } - - isarray@1.0.0: - resolution: - { - integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, - } - - isarray@2.0.5: - resolution: - { - integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, - } - - isexe@2.0.0: - resolution: - { - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, - } - - isobject@3.0.1: - resolution: - { - integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==, - } - engines: { node: ">=0.10.0" } - - 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.3: - resolution: - { - integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==, - } - 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@4.1.1: - resolution: - { - integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==, - } - engines: { node: 20 || >=22 } - - 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 + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} - 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-jsdom@29.7.0: - resolution: - { - integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - - jest-environment-node@29.7.0: - resolution: - { - integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==, - } - engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - - 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 + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} - 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 } + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} jest-worker@27.5.1: - resolution: - { - integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==, - } - engines: { node: ">= 10.13.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 - - js-tokens@4.0.0: - resolution: - { - integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, - } - - js-yaml@3.14.1: - resolution: - { - integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==, - } - hasBin: true - - js-yaml@4.1.0: - resolution: - { - integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, - } - hasBin: true + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} - jsdom@20.0.3: - resolution: - { - integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==, - } - engines: { node: ">=14" } - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - - jsesc@3.1.0: - resolution: - { - integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, - } - engines: { node: ">=6" } - hasBin: true - - json-buffer@3.0.1: - resolution: - { - integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, - } - - json-parse-better-errors@1.0.2: - resolution: - { - integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==, - } + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} json-parse-even-better-errors@2.3.1: - resolution: - { - integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, - } - - json-schema-traverse@0.4.1: - resolution: - { - integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, - } + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} json-schema-traverse@1.0.0: - resolution: - { - integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, - } - - json-stable-stringify-without-jsonify@1.0.1: - resolution: - { - integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, - } - - json5@2.2.3: - resolution: - { - integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, - } - engines: { node: ">=6" } - hasBin: true - - jsonc-parser@3.3.1: - resolution: - { - integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==, - } - - jsonfile@6.1.0: - resolution: - { - integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==, - } - - jsonparse@1.3.1: - resolution: - { - integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==, - } - engines: { "0": node >= 0.2.0 } - - jsonpointer@5.0.1: - resolution: - { - integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==, - } - engines: { node: ">=0.10.0" } - - keyv@4.5.4: - resolution: - { - integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, - } - - kind-of@6.0.3: - resolution: - { - integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==, - } - engines: { node: ">=0.10.0" } - - kleur@3.0.3: - resolution: - { - integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, - } - engines: { node: ">=6" } - - leven@3.1.0: - resolution: - { - integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==, - } - engines: { node: ">=6" } - - levn@0.4.1: - resolution: - { - integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, - } - engines: { node: ">= 0.8.0" } - - lines-and-columns@1.2.4: - resolution: - { - integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, - } - - linkify-it@5.0.0: - resolution: - { - integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==, - } - - load-json-file@4.0.0: - resolution: - { - integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==, - } - engines: { node: ">=4" } - - loader-runner@4.3.0: - resolution: - { - integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==, - } - engines: { node: ">=6.11.5" } - - loader-utils@2.0.4: - resolution: - { - integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==, - } - engines: { node: ">=8.9.0" } - - locate-path@5.0.0: - resolution: - { - integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==, - } - engines: { node: ">=8" } - - locate-path@6.0.0: - resolution: - { - integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, - } - engines: { node: ">=10" } - - lodash.camelcase@4.3.0: - resolution: - { - integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==, - } - - lodash.isfunction@3.0.9: - resolution: - { - integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==, - } - - lodash.isplainobject@4.0.6: - resolution: - { - integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==, - } - - lodash.kebabcase@4.1.1: - resolution: - { - integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==, - } - - lodash.memoize@4.1.2: - resolution: - { - integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==, - } - - lodash.merge@4.6.2: - resolution: - { - integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, - } - - lodash.mergewith@4.6.2: - resolution: - { - integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==, - } - - lodash.snakecase@4.1.1: - resolution: - { - integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==, - } - - lodash.startcase@4.4.0: - resolution: - { - integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==, - } - - lodash.uniq@4.5.0: - resolution: - { - integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==, - } - - lodash.upperfirst@4.3.1: - resolution: - { - integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==, - } - - lodash@4.17.21: - resolution: - { - integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, - } - - lru-cache@11.1.0: - resolution: - { - integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==, - } - engines: { node: 20 || >=22 } - - lru-cache@5.1.1: - resolution: - { - integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, - } - - lru-cache@6.0.0: - resolution: - { - integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, - } - engines: { node: ">=10" } - - lunr@2.3.9: - resolution: - { - integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==, - } - - 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==, - } - - map-obj@1.0.1: - resolution: - { - integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==, - } - engines: { node: ">=0.10.0" } - - map-obj@4.3.0: - resolution: - { - integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==, - } - engines: { node: ">=8" } - - markdown-it@14.1.0: - resolution: - { - integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==, - } - hasBin: true + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - markdownlint-cli@0.42.0: - resolution: - { - integrity: sha512-AjkzhhZa3TmEGi/CE2Wpmny69x1IrzqK2gPB0k8SmNMRgnSAJfyEO5FgZdWTHtJ6Nrdv5FWt5c4C5pkG6Dk30A==, - } - engines: { node: ">=18" } - hasBin: true + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} + engines: {node: '>=6.11.5'} - markdownlint-micromark@0.1.10: - resolution: - { - integrity: sha512-no5ZfdqAdWGxftCLlySHSgddEjyW4kui4z7amQcGsSKfYC5v/ou+8mIQVyg9KQMeEZLNtz9OPDTj7nnTnoR4FQ==, - } - engines: { node: ">=18" } - - markdownlint@0.35.0: - resolution: - { - integrity: sha512-wgp8yesWjFBL7bycA3hxwHRdsZGJhjhyP1dSxKVKrza0EPFYtn+mHtkVy6dvP1kGSjovyG5B8yNP6Frj0UFUJg==, - } - engines: { node: ">=18" } - - marked@4.3.0: - resolution: - { - integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==, - } - engines: { node: ">= 12" } - hasBin: true + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - math-intrinsics@1.1.0: - resolution: - { - integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, - } - engines: { node: ">= 0.4" } - - mdurl@2.0.0: - resolution: - { - integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==, - } - - memory-fs@0.5.0: - resolution: - { - integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==, - } - engines: { node: ">=4.3.0 <5.0.0 || >=5.10" } - - memorystream@0.3.1: - resolution: - { - integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==, - } - engines: { node: ">= 0.10.0" } - - meow@8.1.2: - resolution: - { - integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==, - } - engines: { node: ">=10" } + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} 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" } + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} micromatch@4.0.8: - resolution: - { - integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, - } - engines: { node: ">=8.6" } + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} mime-db@1.52.0: - resolution: - { - integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, - } - engines: { node: ">= 0.6" } + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} mime-types@2.1.35: - resolution: - { - integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, - } - engines: { node: ">= 0.6" } - - mimic-fn@2.1.0: - resolution: - { - integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, - } - engines: { node: ">=6" } - - min-indent@1.0.1: - resolution: - { - integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==, - } - engines: { node: ">=4" } - - minimatch@10.0.3: - resolution: - { - integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==, - } - engines: { node: 20 || >=22 } - - minimatch@3.1.2: - resolution: - { - integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, - } - - minimatch@5.1.6: - resolution: - { - integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==, - } - engines: { node: ">=10" } - - minimatch@9.0.5: - resolution: - { - integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, - } - engines: { node: ">=16 || 14 >=14.17" } - - minimist-options@4.1.0: - resolution: - { - integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==, - } - engines: { node: ">= 6" } - - minimist@1.2.8: - resolution: - { - integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, - } - - minipass@7.1.2: - resolution: - { - integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==, - } - engines: { node: ">=16 || 14 >=14.17" } - - mri@1.2.0: - resolution: - { - integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} ms@2.1.3: - resolution: - { - integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, - } - - natural-compare@1.4.0: - resolution: - { - integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, - } - - nconf@0.12.1: - resolution: - { - integrity: sha512-p2cfF+B3XXacQdswUYWZ0w6Vld0832A/tuqjLBu3H1sfUcby4N2oVbGhyuCkZv+t3iY3aiFEj7gZGqax9Q2c1w==, - } - engines: { node: ">= 0.4.0" } + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - neo-async@2.6.2: - resolution: - { - integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, - } - - nice-try@1.0.5: - resolution: - { - integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==, - } - - node-fetch@2.7.0: - resolution: - { - integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==, - } - engines: { node: 4.x || >=6.0.0 } + msw@2.11.2: + resolution: {integrity: sha512-MI54hLCsrMwiflkcqlgYYNJJddY5/+S0SnONvhv1owOplvqohKSQyGejpNdUGyCwgs4IH7PqaNbPw/sKOEze9Q==} + engines: {node: '>=18'} + hasBin: true peerDependencies: - encoding: ^0.1.0 + typescript: '>= 4.8.x' peerDependenciesMeta: - encoding: + typescript: optional: true - node-int64@0.4.0: - resolution: - { - integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==, - } - - node-releases@2.0.19: - resolution: - { - integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==, - } - - nodemon@3.1.10: - resolution: - { - integrity: sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==, - } - engines: { node: ">=10" } - hasBin: true + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} - normalize-package-data@2.5.0: - resolution: - { - integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==, - } - - normalize-package-data@3.0.3: - resolution: - { - integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==, - } - engines: { node: ">=10" } - - normalize-path@3.0.0: - resolution: - { - integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, - } - engines: { node: ">=0.10.0" } - - npm-run-all@4.1.5: - resolution: - { - integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==, - } - engines: { node: ">= 4" } + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - npm-run-path@4.0.1: - resolution: - { - integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, - } - engines: { node: ">=8" } - - nwsapi@2.2.20: - resolution: - { - integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==, - } - - object-inspect@1.13.4: - resolution: - { - integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==, - } - engines: { node: ">= 0.4" } - - object-keys@1.1.1: - resolution: - { - integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, - } - engines: { node: ">= 0.4" } - - object.assign@4.1.7: - resolution: - { - integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==, - } - engines: { node: ">= 0.4" } - - 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" } - - opencollective-postinstall@2.0.3: - resolution: - { - integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==, - } - hasBin: true + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - optionator@0.9.4: - resolution: - { - integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, - } - engines: { node: ">= 0.8.0" } - - own-keys@1.0.1: - resolution: - { - integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==, - } - engines: { node: ">= 0.4" } - - 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-locate@5.0.0: - resolution: - { - integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, - } - engines: { node: ">=10" } - - p-try@2.2.0: - resolution: - { - integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==, - } - engines: { node: ">=6" } - - package-json-from-dist@1.0.1: - resolution: - { - integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, - } - - parent-module@1.0.1: - resolution: - { - integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, - } - engines: { node: ">=6" } - - parse-json@4.0.0: - resolution: - { - integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==, - } - engines: { node: ">=4" } - - parse-json@5.2.0: - resolution: - { - integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, - } - engines: { node: ">=8" } - - parse5@7.3.0: - resolution: - { - integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==, - } - - 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@2.0.1: - resolution: - { - integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==, - } - engines: { node: ">=4" } - - 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@2.0.0: - resolution: - { - integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==, - } - engines: { node: 20 || >=22 } - - path-type@3.0.0: - resolution: - { - integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==, - } - engines: { node: ">=4" } - - path-type@4.0.0: - resolution: - { - integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, - } - engines: { node: ">=8" } + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + 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'} picocolors@1.1.1: - resolution: - { - integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, - } + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: - resolution: - { - integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, - } - engines: { node: ">=8.6" } - - picomatch@3.0.1: - resolution: - { - integrity: sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==, - } - engines: { node: ">=10" } - - pidtree@0.3.1: - resolution: - { - integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==, - } - engines: { node: ">=0.10" } - hasBin: true + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} - pify@3.0.0: - resolution: - { - integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==, - } - engines: { node: ">=4" } - - pirates@4.0.7: - resolution: - { - integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, - } - engines: { node: ">= 6" } - - pkg-dir@4.2.0: - resolution: - { - integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==, - } - engines: { node: ">=8" } - - pkg-dir@5.0.0: - resolution: - { - integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==, - } - engines: { node: ">=10" } - - please-upgrade-node@3.2.0: - resolution: - { - integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==, - } - - possible-typed-array-names@1.1.0: - resolution: - { - integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==, - } - engines: { node: ">= 0.4" } - - prelude-ls@1.2.1: - resolution: - { - integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, - } - engines: { node: ">= 0.8.0" } - - prettier@2.8.8: - resolution: - { - integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==, - } - engines: { node: ">=10.13.0" } + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + playwright-core@1.56.1: + resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} + engines: {node: '>=18'} 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 } - - pretty-quick@3.3.1: - resolution: - { - integrity: sha512-3b36UXfYQ+IXXqex6mCca89jC8u0mYLqFAN5eTQKoXO6oCQYcIVYZEB/5AlBHI7JPYygReM2Vv6Vom/Gln7fBg==, - } - engines: { node: ">=10.13" } + playwright@1.56.1: + resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==} + engines: {node: '>=18'} hasBin: true - peerDependencies: - prettier: ^2.0.0 - - process-nextick-args@2.0.1: - resolution: - { - integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, - } - - prompts@2.4.2: - resolution: - { - integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, - } - engines: { node: ">= 6" } - - prr@1.0.1: - resolution: - { - integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==, - } - - psl@1.15.0: - resolution: - { - integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==, - } - - pstree.remy@1.1.8: - resolution: - { - integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==, - } - - pump@3.0.3: - resolution: - { - integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==, - } - - punycode.js@2.3.1: - resolution: - { - integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==, - } - engines: { node: ">=6" } - - punycode@1.4.1: - resolution: - { - integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==, - } - - punycode@2.3.1: - resolution: - { - integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, - } - engines: { node: ">=6" } - - pure-rand@6.1.0: - resolution: - { - integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==, - } - - qs@6.14.0: - resolution: - { - integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==, - } - engines: { node: ">=0.6" } - - querystringify@2.2.0: - resolution: - { - integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==, - } - - queue-microtask@1.2.3: - resolution: - { - integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, - } - - quick-lru@4.0.1: - resolution: - { - integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==, - } - engines: { node: ">=8" } + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} randombytes@2.1.0: - resolution: - { - integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==, - } - - react-is@18.3.1: - resolution: - { - integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, - } - - read-pkg-up@7.0.1: - resolution: - { - integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==, - } - engines: { node: ">=8" } - - read-pkg@3.0.0: - resolution: - { - integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==, - } - engines: { node: ">=4" } - - read-pkg@5.2.0: - resolution: - { - integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==, - } - engines: { node: ">=8" } - - readable-stream@2.3.8: - resolution: - { - integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, - } - - readable-stream@3.6.2: - resolution: - { - integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, - } - engines: { node: ">= 6" } - - readdirp@3.6.0: - resolution: - { - integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, - } - engines: { node: ">=8.10.0" } - - rechoir@0.7.1: - resolution: - { - integrity: sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==, - } - engines: { node: ">= 0.10" } - - redent@3.0.0: - resolution: - { - integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==, - } - engines: { node: ">=8" } - - reflect.getprototypeof@1.0.10: - resolution: - { - integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==, - } - engines: { node: ">= 0.4" } - - regexp.prototype.flags@1.5.4: - resolution: - { - integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} require-directory@2.1.1: - resolution: - { - integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} require-from-string@2.0.2: - resolution: - { - integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, - } - engines: { node: ">=0.10.0" } - - requires-port@1.0.0: - resolution: - { - integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==, - } - - resolve-cwd@3.0.0: - resolution: - { - integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==, - } - engines: { node: ">=8" } - - resolve-from@4.0.0: - resolution: - { - integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, - } - engines: { node: ">=4" } - - resolve-from@5.0.0: - resolution: - { - integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, - } - engines: { node: ">=8" } - - resolve-global@1.0.0: - resolution: - { - integrity: sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==, - } - engines: { node: ">=8" } - - resolve.exports@2.0.3: - resolution: - { - integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==, - } - engines: { node: ">=10" } - - resolve@1.22.10: - resolution: - { - integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==, - } - engines: { node: ">= 0.4" } - hasBin: true + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} - reusify@1.1.0: - resolution: - { - integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, - } - engines: { iojs: ">=1.0.0", node: ">=0.10.0" } - - rimraf@3.0.2: - resolution: - { - integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, - } - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true + rettime@0.7.0: + resolution: {integrity: sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==} - run-con@1.3.2: - resolution: - { - integrity: sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==, - } + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - run-parallel@1.2.0: - resolution: - { - integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, - } - - safe-array-concat@1.1.3: - resolution: - { - integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==, - } - engines: { node: ">=0.4" } - - safe-buffer@5.1.2: - resolution: - { - integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, - } - safe-buffer@5.2.1: - resolution: - { - integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, - } - - safe-push-apply@1.0.0: - resolution: - { - integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==, - } - engines: { node: ">= 0.4" } - - safe-regex-test@1.1.0: - resolution: - { - integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==, - } - engines: { node: ">= 0.4" } - - safer-buffer@2.1.2: - resolution: - { - integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, - } - - saxes@6.0.0: - resolution: - { - integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==, - } - engines: { node: ">=v12.22.7" } - - schema-utils@4.3.2: - resolution: - { - integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==, - } - engines: { node: ">= 10.13.0" } - - secure-keys@1.0.0: - resolution: - { - integrity: sha512-nZi59hW3Sl5P3+wOO89eHBAAGwmCPd2aE1+dLZV5MO+ItQctIvAqihzaAXIQhvtH4KJPxM080HsnqltR2y8cWg==, - } - - semantic-release-plugin-update-version-in-files@1.1.0: - resolution: - { - integrity: sha512-OWBrved3Rr0w3YP4iID81MhG9qhGrG+XtxdO9VMhKJ9qte3yBdMz5cSxDiPE/uhnGJQF00fqQetY3yhHFGabWw==, - } - - semver-compare@1.0.0: - resolution: - { - integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==, - } - - semver-regex@3.1.4: - resolution: - { - integrity: sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==, - } - engines: { node: ">=8" } - - semver@5.7.2: - resolution: - { - integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==, - } - hasBin: true - - semver@6.3.1: - resolution: - { - integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, - } - hasBin: true + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - semver@7.5.4: - resolution: - { - integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==, - } - engines: { node: ">=10" } - hasBin: true + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} - semver@7.7.2: - resolution: - { - integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==, - } - engines: { node: ">=10" } + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} hasBin: true serialize-javascript@6.0.2: - resolution: - { - integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==, - } - - set-function-length@1.2.2: - resolution: - { - integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, - } - engines: { node: ">= 0.4" } - - set-function-name@2.0.2: - resolution: - { - integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==, - } - engines: { node: ">= 0.4" } - - set-proto@1.0.0: - resolution: - { - integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==, - } - engines: { node: ">= 0.4" } - - shallow-clone@3.0.1: - resolution: - { - integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==, - } - engines: { node: ">=8" } - - shebang-command@1.2.0: - resolution: - { - integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==, - } - engines: { node: ">=0.10.0" } - - shebang-command@2.0.0: - resolution: - { - integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, - } - engines: { node: ">=8" } - - shebang-regex@1.0.0: - resolution: - { - integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==, - } - engines: { node: ">=0.10.0" } - - shebang-regex@3.0.0: - resolution: - { - integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, - } - engines: { node: ">=8" } - - shell-quote@1.8.3: - resolution: - { - integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==, - } - engines: { node: ">= 0.4" } - - shiki@0.10.1: - resolution: - { - integrity: sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==, - } - - side-channel-list@1.0.0: - resolution: - { - integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==, - } - engines: { node: ">= 0.4" } - - side-channel-map@1.0.1: - resolution: - { - integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, - } - engines: { node: ">= 0.4" } - - side-channel-weakmap@1.0.2: - resolution: - { - integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==, - } - engines: { node: ">= 0.4" } - - side-channel@1.1.0: - resolution: - { - integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, - } - engines: { node: ">= 0.4" } - - signal-exit@3.0.7: - resolution: - { - integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, - } + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} signal-exit@4.1.0: - resolution: - { - integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, - } - engines: { node: ">=14" } - - simple-update-notifier@2.0.0: - resolution: - { - integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==, - } - engines: { node: ">=10" } - - sisteransi@1.0.5: - resolution: - { - integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, - } - - slash@3.0.0: - resolution: - { - integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==, - } - engines: { node: ">=8" } - - smol-toml@1.3.4: - resolution: - { - integrity: sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==, - } - engines: { node: ">= 18" } - - source-map-support@0.5.13: - resolution: - { - integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==, - } + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} source-map-support@0.5.21: - resolution: - { - integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, - } + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} source-map@0.6.1: - resolution: - { - integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, - } - engines: { node: ">=0.10.0" } - - spdx-correct@3.2.0: - resolution: - { - integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==, - } - - spdx-exceptions@2.5.0: - resolution: - { - integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==, - } - - spdx-expression-parse@3.0.1: - resolution: - { - integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==, - } - - spdx-license-ids@3.0.21: - resolution: - { - integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==, - } - - split2@3.2.2: - resolution: - { - integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==, - } - - sprintf-js@1.0.3: - resolution: - { - integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, - } - - stack-utils@2.0.6: - resolution: - { - integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==, - } - engines: { node: ">=10" } - - stop-iteration-iterator@1.1.0: - resolution: - { - integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==, - } - engines: { node: ">= 0.4" } - - stream-browserify@3.0.0: - resolution: - { - integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==, - } - - string-length@4.0.2: - resolution: - { - integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} string-width@4.2.3: - resolution: - { - integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, - } - engines: { node: ">=8" } - - string-width@5.1.2: - resolution: - { - integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, - } - engines: { node: ">=12" } - - string.prototype.padend@3.1.6: - resolution: - { - integrity: sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==, - } - engines: { node: ">= 0.4" } - - string.prototype.trim@1.2.10: - resolution: - { - integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==, - } - engines: { node: ">= 0.4" } - - string.prototype.trimend@1.0.9: - resolution: - { - integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==, - } - engines: { node: ">= 0.4" } - - string.prototype.trimstart@1.0.8: - resolution: - { - integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==, - } - engines: { node: ">= 0.4" } - - string_decoder@1.1.1: - resolution: - { - integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, - } - - string_decoder@1.3.0: - resolution: - { - integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, - } + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} strip-ansi@6.0.1: - resolution: - { - integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, - } - engines: { node: ">=8" } - - strip-ansi@7.1.0: - resolution: - { - integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==, - } - engines: { node: ">=12" } - - strip-bom@3.0.0: - resolution: - { - integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, - } - engines: { node: ">=4" } - - 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-indent@3.0.0: - resolution: - { - integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==, - } - engines: { node: ">=8" } - - strip-json-comments@3.1.1: - resolution: - { - integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, - } - engines: { node: ">=8" } - - supports-color@5.5.0: - resolution: - { - integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} supports-color@7.2.0: - resolution: - { - integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, - } - engines: { node: ">=8" } + 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" } - - symbol-tree@3.2.4: - resolution: - { - integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==, - } - - tapable@1.1.3: - resolution: - { - integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==, - } - engines: { node: ">=6" } - - tapable@2.2.2: - resolution: - { - integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} terser-webpack-plugin@5.3.14: - resolution: - { - integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==, - } - engines: { node: ">= 10.13.0" } + resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + engines: {node: '>= 10.13.0'} peerDependencies: - "@swc/core": "*" - esbuild: "*" - uglify-js: "*" + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' webpack: ^5.1.0 peerDependenciesMeta: - "@swc/core": + '@swc/core': optional: true esbuild: optional: true uglify-js: optional: true - terser@5.42.0: - resolution: - { - integrity: sha512-UYCvU9YQW2f/Vwl+P0GfhxJxbUGLwd+5QrrGgLajzWAtC/23AX0vcise32kkP7Eu0Wu9VlzzHAXkLObgjQfFlQ==, - } - engines: { node: ">=10" } + terser@5.44.1: + resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + engines: {node: '>=10'} hasBin: true - test-exclude@6.0.0: - resolution: - { - integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==, - } - engines: { node: ">=8" } - - text-extensions@1.9.0: - resolution: - { - integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==, - } - engines: { node: ">=0.10" } - - text-table@0.2.0: - resolution: - { - integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==, - } - - through2@4.0.2: - resolution: - { - integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==, - } - - through@2.3.8: - resolution: - { - integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==, - } - - tmpl@1.0.5: - resolution: - { - integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==, - } + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + tldts-core@7.0.18: + resolution: {integrity: sha512-jqJC13oP4FFAahv4JT/0WTDrCF9Okv7lpKtOZUGPLiAnNbACcSg8Y8T+Z9xthOmRBqi/Sob4yi0TE0miRCvF7Q==} + + tldts@7.0.18: + resolution: {integrity: sha512-lCcgTAgMxQ1JKOWrVGo6E69Ukbnx4Gc1wiYLRf6J5NN4HRYJtCby1rPF8rkQ4a6qqoFBK5dvjJ1zJ0F7VfDSvw==} + hasBin: true to-regex-range@5.0.1: - resolution: - { - integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, - } - engines: { node: ">=8.0" } - - touch@3.1.1: - resolution: - { - integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==, - } + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tough-cookie@6.0.0: + resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + engines: {node: '>=16'} + + ts-loader@9.5.4: + resolution: {integrity: sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + typescript: '*' + webpack: ^5.0.0 + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} hasBin: true - tough-cookie@4.1.4: - resolution: - { - integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==, - } - engines: { node: ">=6" } - - tr46@0.0.3: - resolution: - { - integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, - } - - tr46@3.0.0: - resolution: - { - integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==, - } - engines: { node: ">=12" } - - trim-newlines@3.0.1: - resolution: - { - integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==, - } - engines: { node: ">=8" } - - ts-api-utils@2.1.0: - resolution: - { - integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==, - } - engines: { node: ">=18.12" } + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + hasBin: true peerDependencies: - typescript: ">=4.8.4" - - ts-jest@29.4.0: - resolution: - { - integrity: sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==, - } - engines: { node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0 } + browserslist: '>= 4.21.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 + + vite@7.2.2: + resolution: {integrity: sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - "@babel/core": ">=7.0.0-beta.0 <8" - "@jest/transform": ^29.0.0 || ^30.0.0 - "@jest/types": ^29.0.0 || ^30.0.0 - babel-jest: ^29.0.0 || ^30.0.0 - esbuild: "*" - jest: ^29.0.0 || ^30.0.0 - jest-util: ^29.0.0 || ^30.0.0 - typescript: ">=4.3 <6" + '@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: - "@babel/core": + '@types/node': optional: true - "@jest/transform": + jiti: optional: true - "@jest/types": + less: optional: true - babel-jest: + lightningcss: optional: true - esbuild: + sass: optional: true - jest-util: + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: optional: true - ts-loader@8.4.0: - resolution: - { - integrity: sha512-6nFY3IZ2//mrPc+ImY3hNWx1vCHyEhl6V+wLmL4CZcm6g1CqX7UKrkc6y0i4FwcfOhxyMPCfaEvh20f4r9GNpw==, - } - engines: { node: ">=10.0.0" } - peerDependencies: - typescript: "*" - webpack: "*" - - ts-node@10.9.2: - resolution: - { - integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==, - } + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - "@swc/core": ">=1.2.50" - "@swc/wasm": ">=1.2.50" - "@types/node": "*" - typescript: ">=2.7" + '@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: - "@swc/core": + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': optional: true - "@swc/wasm": + '@vitest/browser': optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + watchpack@2.4.4: + resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + engines: {node: '>=10.13.0'} - tslib@2.8.1: - resolution: - { - integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, - } - - type-check@0.4.0: - resolution: - { - integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, - } - engines: { node: ">= 0.8.0" } - - type-detect@4.0.8: - resolution: - { - integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==, - } - engines: { node: ">=4" } - - type-fest@0.18.1: - resolution: - { - integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==, - } - engines: { node: ">=10" } - - type-fest@0.20.2: - resolution: - { - integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==, - } - engines: { node: ">=10" } - - type-fest@0.21.3: - resolution: - { - integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, - } - engines: { node: ">=10" } - - type-fest@0.6.0: - resolution: - { - integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==, - } - engines: { node: ">=8" } - - type-fest@0.8.1: - resolution: - { - integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==, - } - engines: { node: ">=8" } + webpack-sources@3.3.3: + resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + engines: {node: '>=10.13.0'} - type-fest@4.41.0: - resolution: - { - integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==, - } - engines: { node: ">=16" } - - typed-array-buffer@1.0.3: - resolution: - { - integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==, - } - engines: { node: ">= 0.4" } - - typed-array-byte-length@1.0.3: - resolution: - { - integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==, - } - engines: { node: ">= 0.4" } - - typed-array-byte-offset@1.0.4: - resolution: - { - integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==, - } - engines: { node: ">= 0.4" } - - typed-array-length@1.0.7: - resolution: - { - integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==, - } - engines: { node: ">= 0.4" } - - typedoc@0.22.18: - resolution: - { - integrity: sha512-NK9RlLhRUGMvc6Rw5USEYgT4DVAUFk7IF7Q6MYfpJ88KnTZP7EneEa4RcP+tX1auAcz7QT1Iy0bUSZBYYHdoyA==, - } - engines: { node: ">= 12.10.0" } + webpack@5.103.0: + resolution: {integrity: sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==} + engines: {node: '>=10.13.0'} hasBin: true peerDependencies: - typescript: 4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x || 4.7.x - - typescript@4.9.5: - resolution: - { - integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==, - } - engines: { node: ">=4.2.0" } + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} hasBin: true - uc.micro@2.1.0: - resolution: - { - integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==, - } - - unbox-primitive@1.1.0: - resolution: - { - integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==, - } - engines: { node: ">= 0.4" } - - undefsafe@2.0.5: - resolution: - { - integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==, - } + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} - undici-types@5.26.5: - resolution: - { - integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==, - } - - universalify@0.2.0: - resolution: - { - integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==, - } - engines: { node: ">= 4.0.0" } - - universalify@2.0.1: - resolution: - { - integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==, - } - engines: { node: ">= 10.0.0" } - - update-browserslist-db@1.1.3: - resolution: - { - integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==, - } - hasBin: true - peerDependencies: - browserslist: ">= 4.21.0" - - uri-js@4.4.1: - resolution: - { - integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, - } - - url-parse@1.5.10: - resolution: - { - integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==, - } - - url@0.11.4: - resolution: - { - integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==, - } - engines: { node: ">= 0.4" } - - util-deprecate@1.0.2: - resolution: - { - integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, - } - - util@0.12.5: - resolution: - { - integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==, - } - - v8-compile-cache-lib@3.0.1: - resolution: - { - integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==, - } - - v8-to-istanbul@9.3.0: - resolution: - { - integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==, - } - engines: { node: ">=10.12.0" } - - validate-npm-package-license@3.0.4: - resolution: - { - integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==, - } - - vscode-oniguruma@1.7.0: - resolution: - { - integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==, - } - - vscode-textmate@5.2.0: - resolution: - { - integrity: sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==, - } - - w3c-xmlserializer@4.0.0: - resolution: - { - integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==, - } - engines: { node: ">=14" } - - walker@1.0.8: - resolution: - { - integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==, - } + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} - watchpack@2.4.4: - resolution: - { - integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==, - } - engines: { node: ">=10.13.0" } - - webidl-conversions@3.0.1: - resolution: - { - integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, - } - - webidl-conversions@7.0.0: - resolution: - { - integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==, - } - engines: { node: ">=12" } - - webpack-cli@4.10.0: - resolution: - { - integrity: sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==, - } - engines: { node: ">=10.13.0" } - hasBin: true - peerDependencies: - "@webpack-cli/generators": "*" - "@webpack-cli/migrate": "*" - webpack: 4.x.x || 5.x.x - webpack-bundle-analyzer: "*" - webpack-dev-server: "*" - peerDependenciesMeta: - "@webpack-cli/generators": - optional: true - "@webpack-cli/migrate": - optional: true - webpack-bundle-analyzer: - optional: true - webpack-dev-server: - optional: true - - webpack-merge@5.10.0: - resolution: - { - integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==, - } - engines: { node: ">=10.0.0" } - - webpack-sources@3.3.2: - resolution: - { - integrity: sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==, - } - engines: { node: ">=10.13.0" } - - webpack@5.99.9: - resolution: - { - integrity: sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==, - } - engines: { node: ">=10.13.0" } - hasBin: true - peerDependencies: - webpack-cli: "*" - peerDependenciesMeta: - webpack-cli: - optional: true - - whatwg-encoding@2.0.0: - resolution: - { - integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==, - } - engines: { node: ">=12" } - - whatwg-mimetype@3.0.0: - resolution: - { - integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==, - } - engines: { node: ">=12" } - - whatwg-url@11.0.0: - resolution: - { - integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==, - } - engines: { node: ">=12" } - - whatwg-url@5.0.0: - resolution: - { - integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, - } - - which-boxed-primitive@1.1.1: - resolution: - { - integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==, - } - engines: { node: ">= 0.4" } - - which-builtin-type@1.2.1: - resolution: - { - integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==, - } - engines: { node: ">= 0.4" } - - which-collection@1.0.2: - resolution: - { - integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==, - } - engines: { node: ">= 0.4" } - - which-pm-runs@1.1.0: - resolution: - { - integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==, - } - engines: { node: ">=4" } - - which-typed-array@1.1.19: - resolution: - { - integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==, - } - engines: { node: ">= 0.4" } - - which@1.3.1: - resolution: - { - integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==, - } - hasBin: true - - which@2.0.2: - resolution: - { - integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, - } - engines: { node: ">= 8" } - hasBin: true - - wildcard@2.0.1: - resolution: - { - integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==, - } - - word-wrap@1.2.5: - resolution: - { - integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, - } - engines: { node: ">=0.10.0" } - - wrap-ansi@7.0.0: - resolution: - { - integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, - } - engines: { node: ">=10" } - - wrap-ansi@8.1.0: - resolution: - { - integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, - } - engines: { node: ">=12" } - - 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 } - - ws@8.18.2: - resolution: - { - integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==, - } - engines: { node: ">=10.0.0" } + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" + utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - xml-name-validator@4.0.0: - resolution: - { - integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==, - } - engines: { node: ">=12" } - - xmlchars@2.2.0: - resolution: - { - integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==, - } - y18n@5.0.8: - resolution: - { - integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, - } - engines: { node: ">=10" } - - yallist@3.1.1: - resolution: - { - integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, - } - - yallist@4.0.0: - resolution: - { - integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, - } - - yaml-lint@1.7.0: - resolution: - { - integrity: sha512-zeBC/kskKQo4zuoGQ+IYjw6C9a/YILr2SXoEZA9jM0COrSwvwVbfTiFegT8qYBSBgOwLMWGL8sY137tOmFXGnQ==, - } - hasBin: true - - yaml@1.10.2: - resolution: - { - integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==, - } - engines: { node: ">= 6" } - - yargs-parser@20.2.9: - resolution: - { - integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} yargs-parser@21.1.1: - resolution: - { - integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, - } - engines: { node: ">=12" } - - yargs@16.2.0: - resolution: - { - integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==, - } - engines: { node: ">=10" } + 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" } - - yocto-queue@0.1.0: - resolution: - { - integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, - } - engines: { node: ">=10" } - -snapshots: - "@ampproject/remapping@2.3.0": - dependencies: - "@jridgewell/gen-mapping": 0.3.8 - "@jridgewell/trace-mapping": 0.3.25 + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} - "@babel/code-frame@7.27.1": - dependencies: - "@babel/helper-validator-identifier": 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} - "@babel/compat-data@7.27.5": {} - - "@babel/core@7.27.4": - dependencies: - "@ampproject/remapping": 2.3.0 - "@babel/code-frame": 7.27.1 - "@babel/generator": 7.27.5 - "@babel/helper-compilation-targets": 7.27.2 - "@babel/helper-module-transforms": 7.27.3(@babel/core@7.27.4) - "@babel/helpers": 7.27.6 - "@babel/parser": 7.27.5 - "@babel/template": 7.27.2 - "@babel/traverse": 7.27.4 - "@babel/types": 7.27.6 - convert-source-map: 2.0.0 - debug: 4.4.1(supports-color@5.5.0) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color +snapshots: - "@babel/generator@7.27.5": - dependencies: - "@babel/parser": 7.27.5 - "@babel/types": 7.27.6 - "@jridgewell/gen-mapping": 0.3.8 - "@jridgewell/trace-mapping": 0.3.25 - jsesc: 3.1.0 + '@biomejs/biome@2.3.1': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.3.1 + '@biomejs/cli-darwin-x64': 2.3.1 + '@biomejs/cli-linux-arm64': 2.3.1 + '@biomejs/cli-linux-arm64-musl': 2.3.1 + '@biomejs/cli-linux-x64': 2.3.1 + '@biomejs/cli-linux-x64-musl': 2.3.1 + '@biomejs/cli-win32-arm64': 2.3.1 + '@biomejs/cli-win32-x64': 2.3.1 + + '@biomejs/cli-darwin-arm64@2.3.1': + optional: true - "@babel/helper-compilation-targets@7.27.2": - dependencies: - "@babel/compat-data": 7.27.5 - "@babel/helper-validator-option": 7.27.1 - browserslist: 4.25.0 - lru-cache: 5.1.1 - semver: 6.3.1 + '@biomejs/cli-darwin-x64@2.3.1': + optional: true - "@babel/helper-module-imports@7.27.1": - dependencies: - "@babel/traverse": 7.27.4 - "@babel/types": 7.27.6 - transitivePeerDependencies: - - supports-color + '@biomejs/cli-linux-arm64-musl@2.3.1': + optional: true - "@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-module-imports": 7.27.1 - "@babel/helper-validator-identifier": 7.27.1 - "@babel/traverse": 7.27.4 - transitivePeerDependencies: - - supports-color + '@biomejs/cli-linux-arm64@2.3.1': + optional: true - "@babel/helper-plugin-utils@7.27.1": {} + '@biomejs/cli-linux-x64-musl@2.3.1': + optional: true - "@babel/helper-string-parser@7.27.1": {} + '@biomejs/cli-linux-x64@2.3.1': + optional: true - "@babel/helper-validator-identifier@7.27.1": {} + '@biomejs/cli-win32-arm64@2.3.1': + optional: true - "@babel/helper-validator-option@7.27.1": {} + '@biomejs/cli-win32-x64@2.3.1': + optional: true - "@babel/helpers@7.27.6": + '@bundled-es-modules/cookie@2.0.1': dependencies: - "@babel/template": 7.27.2 - "@babel/types": 7.27.6 + cookie: 0.7.2 - "@babel/parser@7.27.5": + '@bundled-es-modules/statuses@1.0.1': dependencies: - "@babel/types": 7.27.6 + statuses: 2.0.2 - "@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/aix-ppc64@0.25.12': + optional: true - "@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/android-arm64@0.25.12': + optional: true - "@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/android-arm@0.25.12': + optional: true - "@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/android-x64@0.25.12': + optional: true - "@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/darwin-arm64@0.25.12': + optional: true - "@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/darwin-x64@0.25.12': + optional: true - "@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/freebsd-arm64@0.25.12': + optional: true - "@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/freebsd-x64@0.25.12': + optional: true - "@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-arm64@0.25.12': + optional: true - "@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-arm@0.25.12': + optional: true - "@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-ia32@0.25.12': + optional: true - "@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-loong64@0.25.12': + optional: true - "@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-mips64el@0.25.12': + optional: true - "@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-ppc64@0.25.12': + optional: true - "@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-riscv64@0.25.12': + optional: true - "@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-s390x@0.25.12': + optional: true - "@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4)": - dependencies: - "@babel/core": 7.27.4 - "@babel/helper-plugin-utils": 7.27.1 + '@esbuild/linux-x64@0.25.12': + optional: true - "@babel/template@7.27.2": - dependencies: - "@babel/code-frame": 7.27.1 - "@babel/parser": 7.27.5 - "@babel/types": 7.27.6 + '@esbuild/netbsd-arm64@0.25.12': + optional: true - "@babel/traverse@7.27.4": - dependencies: - "@babel/code-frame": 7.27.1 - "@babel/generator": 7.27.5 - "@babel/parser": 7.27.5 - "@babel/template": 7.27.2 - "@babel/types": 7.27.6 - debug: 4.4.1(supports-color@5.5.0) - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@esbuild/netbsd-x64@0.25.12': + optional: true - "@babel/types@7.27.6": - dependencies: - "@babel/helper-string-parser": 7.27.1 - "@babel/helper-validator-identifier": 7.27.1 + '@esbuild/openbsd-arm64@0.25.12': + optional: true - "@bcoe/v8-coverage@0.2.3": {} + '@esbuild/openbsd-x64@0.25.12': + optional: true - "@commitlint/cli@17.8.1": - dependencies: - "@commitlint/format": 17.8.1 - "@commitlint/lint": 17.8.1 - "@commitlint/load": 17.8.1 - "@commitlint/read": 17.8.1 - "@commitlint/types": 17.8.1 - execa: 5.1.1 - lodash.isfunction: 3.0.9 - resolve-from: 5.0.0 - resolve-global: 1.0.0 - yargs: 17.7.2 - transitivePeerDependencies: - - "@swc/core" - - "@swc/wasm" + '@esbuild/openharmony-arm64@0.25.12': + optional: true - "@commitlint/config-conventional@17.8.1": - dependencies: - conventional-changelog-conventionalcommits: 6.1.0 + '@esbuild/sunos-x64@0.25.12': + optional: true - "@commitlint/config-validator@17.8.1": - dependencies: - "@commitlint/types": 17.8.1 - ajv: 8.17.1 + '@esbuild/win32-arm64@0.25.12': + optional: true - "@commitlint/ensure@17.8.1": - dependencies: - "@commitlint/types": 17.8.1 - lodash.camelcase: 4.3.0 - lodash.kebabcase: 4.1.1 - lodash.snakecase: 4.1.1 - lodash.startcase: 4.4.0 - lodash.upperfirst: 4.3.1 + '@esbuild/win32-ia32@0.25.12': + optional: true - "@commitlint/execute-rule@17.8.1": {} + '@esbuild/win32-x64@0.25.12': + optional: true - "@commitlint/format@17.8.1": - dependencies: - "@commitlint/types": 17.8.1 - chalk: 4.1.2 + '@inquirer/ansi@1.0.2': {} - "@commitlint/is-ignored@17.8.1": + '@inquirer/confirm@5.1.21(@types/node@18.19.130)': dependencies: - "@commitlint/types": 17.8.1 - semver: 7.5.4 + '@inquirer/core': 10.3.2(@types/node@18.19.130) + '@inquirer/type': 3.0.10(@types/node@18.19.130) + optionalDependencies: + '@types/node': 18.19.130 - "@commitlint/lint@17.8.1": + '@inquirer/core@10.3.2(@types/node@18.19.130)': dependencies: - "@commitlint/is-ignored": 17.8.1 - "@commitlint/parse": 17.8.1 - "@commitlint/rules": 17.8.1 - "@commitlint/types": 17.8.1 + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@18.19.130) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 18.19.130 - "@commitlint/load@17.8.1": - dependencies: - "@commitlint/config-validator": 17.8.1 - "@commitlint/execute-rule": 17.8.1 - "@commitlint/resolve-extends": 17.8.1 - "@commitlint/types": 17.8.1 - "@types/node": 20.5.1 - chalk: 4.1.2 - cosmiconfig: 8.3.6(typescript@4.9.5) - cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@4.9.5))(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5))(typescript@4.9.5) - lodash.isplainobject: 4.0.6 - lodash.merge: 4.6.2 - lodash.uniq: 4.5.0 - resolve-from: 5.0.0 - ts-node: 10.9.2(@types/node@20.5.1)(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - "@swc/core" - - "@swc/wasm" + '@inquirer/figures@1.0.15': {} - "@commitlint/message@17.8.1": {} + '@inquirer/type@3.0.10(@types/node@18.19.130)': + optionalDependencies: + '@types/node': 18.19.130 - "@commitlint/parse@17.8.1": + '@jridgewell/gen-mapping@0.3.13': dependencies: - "@commitlint/types": 17.8.1 - conventional-changelog-angular: 6.0.0 - conventional-commits-parser: 4.0.0 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 - "@commitlint/read@17.8.1": - dependencies: - "@commitlint/top-level": 17.8.1 - "@commitlint/types": 17.8.1 - fs-extra: 11.3.0 - git-raw-commits: 2.0.11 - minimist: 1.2.8 + '@jridgewell/resolve-uri@3.1.2': {} - "@commitlint/resolve-extends@17.8.1": - dependencies: - "@commitlint/config-validator": 17.8.1 - "@commitlint/types": 17.8.1 - import-fresh: 3.3.1 - lodash.mergewith: 4.6.2 - resolve-from: 5.0.0 - resolve-global: 1.0.0 - - "@commitlint/rules@17.8.1": + '@jridgewell/source-map@0.3.11': dependencies: - "@commitlint/ensure": 17.8.1 - "@commitlint/message": 17.8.1 - "@commitlint/to-lines": 17.8.1 - "@commitlint/types": 17.8.1 - execa: 5.1.1 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - "@commitlint/to-lines@17.8.1": {} + '@jridgewell/sourcemap-codec@1.5.5': {} - "@commitlint/top-level@17.8.1": + '@jridgewell/trace-mapping@0.3.31': dependencies: - find-up: 5.0.0 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - "@commitlint/types@17.8.1": + '@mswjs/interceptors@0.39.8': dependencies: - chalk: 4.1.2 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 - "@cspotcode/source-map-support@0.8.1": - dependencies: - "@jridgewell/trace-mapping": 0.3.9 + '@open-draft/deferred-promise@2.2.0': {} - "@deepgram/captions@1.2.0": + '@open-draft/logger@0.3.0': dependencies: - dayjs: 1.11.13 + is-node-process: 1.2.0 + outvariant: 1.4.3 - "@discoveryjs/json-ext@0.5.7": {} + '@open-draft/until@2.1.0': {} - "@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)": + '@playwright/test@1.56.1': dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 + playwright: 1.56.1 - "@eslint-community/regexpp@4.12.1": {} + '@rollup/rollup-android-arm-eabi@4.53.3': + optional: true - "@eslint/eslintrc@2.1.4": - dependencies: - ajv: 6.12.6 - debug: 4.4.1(supports-color@5.5.0) - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color + '@rollup/rollup-android-arm64@4.53.3': + optional: true - "@eslint/js@8.57.1": {} + '@rollup/rollup-darwin-arm64@4.53.3': + optional: true - "@humanwhocodes/config-array@0.13.0": - dependencies: - "@humanwhocodes/object-schema": 2.0.3 - debug: 4.4.1(supports-color@5.5.0) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@rollup/rollup-darwin-x64@4.53.3': + optional: true - "@humanwhocodes/module-importer@1.0.1": {} + '@rollup/rollup-freebsd-arm64@4.53.3': + optional: true - "@humanwhocodes/object-schema@2.0.3": {} + '@rollup/rollup-freebsd-x64@4.53.3': + optional: true - "@isaacs/balanced-match@4.0.1": {} + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + optional: true - "@isaacs/brace-expansion@5.0.0": - dependencies: - "@isaacs/balanced-match": 4.0.1 + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + optional: true - "@isaacs/cliui@8.0.2": - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - 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 + '@rollup/rollup-linux-arm64-gnu@4.53.3': + optional: true - "@istanbuljs/schema@0.1.3": {} + '@rollup/rollup-linux-arm64-musl@4.53.3': + optional: true - "@jest/console@29.7.0": - dependencies: - "@jest/types": 29.6.3 - "@types/node": 18.19.112 - chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 + '@rollup/rollup-linux-loong64-gnu@4.53.3': + optional: true - "@jest/core@29.7.0(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5))": - 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.112 - 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.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - 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 + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + optional: true - "@jest/environment@29.7.0": - dependencies: - "@jest/fake-timers": 29.7.0 - "@jest/types": 29.6.3 - "@types/node": 18.19.112 - jest-mock: 29.7.0 + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + optional: true - "@jest/expect-utils@29.7.0": - dependencies: - jest-get-type: 29.6.3 + '@rollup/rollup-linux-riscv64-musl@4.53.3': + optional: true - "@jest/expect@29.7.0": - dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color + '@rollup/rollup-linux-s390x-gnu@4.53.3': + optional: true - "@jest/fake-timers@29.7.0": - dependencies: - "@jest/types": 29.6.3 - "@sinonjs/fake-timers": 10.3.0 - "@types/node": 18.19.112 - 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 + '@rollup/rollup-linux-x64-gnu@4.53.3': + optional: true - "@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.112 - 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.3 - 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.3.0 - transitivePeerDependencies: - - supports-color + '@rollup/rollup-linux-x64-musl@4.53.3': + optional: true - "@jest/schemas@29.6.3": - dependencies: - "@sinclair/typebox": 0.27.8 + '@rollup/rollup-openharmony-arm64@4.53.3': + optional: true - "@jest/source-map@29.6.3": - dependencies: - "@jridgewell/trace-mapping": 0.3.25 - callsites: 3.1.0 - graceful-fs: 4.2.11 + '@rollup/rollup-win32-arm64-msvc@4.53.3': + optional: true - "@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 + '@rollup/rollup-win32-ia32-msvc@4.53.3': + optional: true - "@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 + '@rollup/rollup-win32-x64-gnu@4.53.3': + optional: true - "@jest/transform@29.7.0": + '@rollup/rollup-win32-x64-msvc@4.53.3': + optional: true + + '@types/chai@5.2.3': dependencies: - "@babel/core": 7.27.4 - "@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.7 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/cookie@0.6.0': {} - "@jest/types@29.6.3": + '@types/deep-eql@4.0.2': {} + + '@types/eslint-scope@3.7.7': dependencies: - "@jest/schemas": 29.6.3 - "@types/istanbul-lib-coverage": 2.0.6 - "@types/istanbul-reports": 3.0.4 - "@types/node": 18.19.112 - "@types/yargs": 17.0.33 - chalk: 4.1.2 + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 - "@jridgewell/gen-mapping@0.3.8": + '@types/eslint@9.6.1': dependencies: - "@jridgewell/set-array": 1.2.1 - "@jridgewell/sourcemap-codec": 1.5.0 - "@jridgewell/trace-mapping": 0.3.25 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 - "@jridgewell/resolve-uri@3.1.2": {} + '@types/estree@1.0.8': {} - "@jridgewell/set-array@1.2.1": {} + '@types/json-schema@7.0.15': {} - "@jridgewell/source-map@0.3.6": + '@types/node@18.19.130': dependencies: - "@jridgewell/gen-mapping": 0.3.8 - "@jridgewell/trace-mapping": 0.3.25 + undici-types: 5.26.5 - "@jridgewell/sourcemap-codec@1.5.0": {} + '@types/statuses@2.0.6': {} - "@jridgewell/trace-mapping@0.3.25": + '@types/ws@8.18.1': dependencies: - "@jridgewell/resolve-uri": 3.1.2 - "@jridgewell/sourcemap-codec": 1.5.0 + '@types/node': 18.19.130 - "@jridgewell/trace-mapping@0.3.9": + '@vitest/expect@3.2.4': dependencies: - "@jridgewell/resolve-uri": 3.1.2 - "@jridgewell/sourcemap-codec": 1.5.0 + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 - "@nodelib/fs.scandir@2.1.5": + '@vitest/mocker@3.2.4(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(vite@7.2.2(@types/node@18.19.130)(terser@5.44.1))': dependencies: - "@nodelib/fs.stat": 2.0.5 - run-parallel: 1.2.0 - - "@nodelib/fs.stat@2.0.5": {} + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + msw: 2.11.2(@types/node@18.19.130)(typescript@5.7.3) + vite: 7.2.2(@types/node@18.19.130)(terser@5.44.1) - "@nodelib/fs.walk@1.2.8": + '@vitest/pretty-format@3.2.4': dependencies: - "@nodelib/fs.scandir": 2.1.5 - fastq: 1.19.1 - - "@sinclair/typebox@0.27.8": {} + tinyrainbow: 2.0.0 - "@sinonjs/commons@3.0.1": + '@vitest/runner@3.2.4': dependencies: - type-detect: 4.0.8 + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.1.0 - "@sinonjs/fake-timers@10.3.0": + '@vitest/snapshot@3.2.4': dependencies: - "@sinonjs/commons": 3.0.1 + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.21 + pathe: 2.0.3 - "@tootallnate/once@2.0.0": {} + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.4 - "@tsconfig/node10@1.0.11": {} + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 - "@tsconfig/node12@1.0.11": {} + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - "@tsconfig/node14@1.0.3": {} + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - "@tsconfig/node16@1.0.4": {} + '@webassemblyjs/helper-api-error@1.13.2': {} - "@types/babel__core@7.20.5": - dependencies: - "@babel/parser": 7.27.5 - "@babel/types": 7.27.6 - "@types/babel__generator": 7.27.0 - "@types/babel__template": 7.4.4 - "@types/babel__traverse": 7.20.7 + '@webassemblyjs/helper-buffer@1.14.1': {} - "@types/babel__generator@7.27.0": + '@webassemblyjs/helper-numbers@1.13.2': dependencies: - "@babel/types": 7.27.6 + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 - "@types/babel__template@7.4.4": - dependencies: - "@babel/parser": 7.27.5 - "@babel/types": 7.27.6 + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - "@types/babel__traverse@7.20.7": + '@webassemblyjs/helper-wasm-section@1.14.1': dependencies: - "@babel/types": 7.27.6 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 - "@types/eslint-scope@3.7.7": + '@webassemblyjs/ieee754@1.13.2': dependencies: - "@types/eslint": 9.6.1 - "@types/estree": 1.0.8 + '@xtuc/ieee754': 1.2.0 - "@types/eslint@9.6.1": + '@webassemblyjs/leb128@1.13.2': dependencies: - "@types/estree": 1.0.8 - "@types/json-schema": 7.0.15 + '@xtuc/long': 4.2.2 - "@types/estree@1.0.8": {} + '@webassemblyjs/utf8@1.13.2': {} - "@types/graceful-fs@4.1.9": + '@webassemblyjs/wasm-edit@1.14.1': dependencies: - "@types/node": 18.19.112 - - "@types/istanbul-lib-coverage@2.0.6": {} + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 - "@types/istanbul-lib-report@3.0.3": + '@webassemblyjs/wasm-gen@1.14.1': dependencies: - "@types/istanbul-lib-coverage": 2.0.6 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - "@types/istanbul-reports@3.0.4": + '@webassemblyjs/wasm-opt@1.14.1': dependencies: - "@types/istanbul-lib-report": 3.0.3 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 - "@types/jest@29.5.14": + '@webassemblyjs/wasm-parser@1.14.1': dependencies: - expect: 29.7.0 - pretty-format: 29.7.0 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - "@types/jsdom@20.0.1": + '@webassemblyjs/wast-printer@1.14.1': dependencies: - "@types/node": 18.19.112 - "@types/tough-cookie": 4.0.5 - parse5: 7.3.0 + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 - "@types/json-schema@7.0.15": {} + '@xtuc/ieee754@1.2.0': {} - "@types/minimist@1.2.5": {} + '@xtuc/long@4.2.2': {} - "@types/node@18.19.112": + acorn-import-phases@1.0.4(acorn@8.15.0): dependencies: - undici-types: 5.26.5 + acorn: 8.15.0 - "@types/node@20.5.1": {} + acorn@8.15.0: {} - "@types/normalize-package-data@2.4.4": {} + ajv-formats@2.1.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 - "@types/parse-json@4.0.2": {} + ajv-keywords@5.1.0(ajv@8.17.1): + dependencies: + ajv: 8.17.1 + fast-deep-equal: 3.1.3 - "@types/stack-utils@2.0.3": {} + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 - "@types/tough-cookie@4.0.5": {} + ansi-regex@5.0.1: {} - "@types/ws@8.18.1": + ansi-styles@4.3.0: dependencies: - "@types/node": 18.19.112 + color-convert: 2.0.1 - "@types/yargs-parser@21.0.3": {} + assertion-error@2.0.1: {} - "@types/yargs@17.0.33": - dependencies: - "@types/yargs-parser": 21.0.3 + baseline-browser-mapping@2.8.29: {} - "@typescript-eslint/eslint-plugin@8.34.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5)": + braces@3.0.3: dependencies: - "@eslint-community/regexpp": 4.12.1 - "@typescript-eslint/parser": 8.34.0(eslint@8.57.1)(typescript@4.9.5) - "@typescript-eslint/scope-manager": 8.34.0 - "@typescript-eslint/type-utils": 8.34.0(eslint@8.57.1)(typescript@4.9.5) - "@typescript-eslint/utils": 8.34.0(eslint@8.57.1)(typescript@4.9.5) - "@typescript-eslint/visitor-keys": 8.34.0 - eslint: 8.57.1 - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color + fill-range: 7.1.1 - "@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@4.9.5)": + browserslist@4.28.0: dependencies: - "@typescript-eslint/scope-manager": 8.34.0 - "@typescript-eslint/types": 8.34.0 - "@typescript-eslint/typescript-estree": 8.34.0(typescript@4.9.5) - "@typescript-eslint/visitor-keys": 8.34.0 - debug: 4.4.1(supports-color@5.5.0) - eslint: 8.57.1 - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color + baseline-browser-mapping: 2.8.29 + caniuse-lite: 1.0.30001756 + electron-to-chromium: 1.5.256 + node-releases: 2.0.27 + update-browserslist-db: 1.1.4(browserslist@4.28.0) - "@typescript-eslint/project-service@8.34.0(typescript@4.9.5)": - dependencies: - "@typescript-eslint/tsconfig-utils": 8.34.0(typescript@4.9.5) - "@typescript-eslint/types": 8.34.0 - debug: 4.4.1(supports-color@5.5.0) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color + buffer-from@1.1.2: {} - "@typescript-eslint/scope-manager@8.34.0": - dependencies: - "@typescript-eslint/types": 8.34.0 - "@typescript-eslint/visitor-keys": 8.34.0 + cac@6.7.14: {} - "@typescript-eslint/tsconfig-utils@8.34.0(typescript@4.9.5)": + caniuse-lite@1.0.30001756: {} + + chai@5.3.3: dependencies: - typescript: 4.9.5 + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 - "@typescript-eslint/type-utils@8.34.0(eslint@8.57.1)(typescript@4.9.5)": + chalk@4.1.2: dependencies: - "@typescript-eslint/typescript-estree": 8.34.0(typescript@4.9.5) - "@typescript-eslint/utils": 8.34.0(eslint@8.57.1)(typescript@4.9.5) - debug: 4.4.1(supports-color@5.5.0) - eslint: 8.57.1 - ts-api-utils: 2.1.0(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color + ansi-styles: 4.3.0 + supports-color: 7.2.0 - "@typescript-eslint/types@8.34.0": {} + check-error@2.1.1: {} - "@typescript-eslint/typescript-estree@8.34.0(typescript@4.9.5)": - dependencies: - "@typescript-eslint/project-service": 8.34.0(typescript@4.9.5) - "@typescript-eslint/tsconfig-utils": 8.34.0(typescript@4.9.5) - "@typescript-eslint/types": 8.34.0 - "@typescript-eslint/visitor-keys": 8.34.0 - debug: 4.4.1(supports-color@5.5.0) - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color + chrome-trace-event@1.0.4: {} - "@typescript-eslint/utils@8.34.0(eslint@8.57.1)(typescript@4.9.5)": - dependencies: - "@eslint-community/eslint-utils": 4.7.0(eslint@8.57.1) - "@typescript-eslint/scope-manager": 8.34.0 - "@typescript-eslint/types": 8.34.0 - "@typescript-eslint/typescript-estree": 8.34.0(typescript@4.9.5) - eslint: 8.57.1 - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color + cli-width@4.1.0: {} - "@typescript-eslint/visitor-keys@8.34.0": + cliui@8.0.1: dependencies: - "@typescript-eslint/types": 8.34.0 - eslint-visitor-keys: 4.2.1 - - "@ungap/structured-clone@1.3.0": {} + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 - "@webassemblyjs/ast@1.14.1": + color-convert@2.0.1: dependencies: - "@webassemblyjs/helper-numbers": 1.13.2 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 + color-name: 1.1.4 - "@webassemblyjs/floating-point-hex-parser@1.13.2": {} + color-name@1.1.4: {} - "@webassemblyjs/helper-api-error@1.13.2": {} + commander@2.20.3: {} - "@webassemblyjs/helper-buffer@1.14.1": {} + cookie@0.7.2: {} - "@webassemblyjs/helper-numbers@1.13.2": + debug@4.4.3: dependencies: - "@webassemblyjs/floating-point-hex-parser": 1.13.2 - "@webassemblyjs/helper-api-error": 1.13.2 - "@xtuc/long": 4.2.2 + ms: 2.1.3 - "@webassemblyjs/helper-wasm-bytecode@1.13.2": {} + deep-eql@5.0.2: {} - "@webassemblyjs/helper-wasm-section@1.14.1": - dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-buffer": 1.14.1 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 - "@webassemblyjs/wasm-gen": 1.14.1 + electron-to-chromium@1.5.256: {} - "@webassemblyjs/ieee754@1.13.2": - dependencies: - "@xtuc/ieee754": 1.2.0 + emoji-regex@8.0.0: {} - "@webassemblyjs/leb128@1.13.2": - dependencies: - "@xtuc/long": 4.2.2 - - "@webassemblyjs/utf8@1.13.2": {} - - "@webassemblyjs/wasm-edit@1.14.1": - dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-buffer": 1.14.1 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 - "@webassemblyjs/helper-wasm-section": 1.14.1 - "@webassemblyjs/wasm-gen": 1.14.1 - "@webassemblyjs/wasm-opt": 1.14.1 - "@webassemblyjs/wasm-parser": 1.14.1 - "@webassemblyjs/wast-printer": 1.14.1 - - "@webassemblyjs/wasm-gen@1.14.1": - dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 - "@webassemblyjs/ieee754": 1.13.2 - "@webassemblyjs/leb128": 1.13.2 - "@webassemblyjs/utf8": 1.13.2 - - "@webassemblyjs/wasm-opt@1.14.1": - dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-buffer": 1.14.1 - "@webassemblyjs/wasm-gen": 1.14.1 - "@webassemblyjs/wasm-parser": 1.14.1 - - "@webassemblyjs/wasm-parser@1.14.1": - dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-api-error": 1.13.2 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 - "@webassemblyjs/ieee754": 1.13.2 - "@webassemblyjs/leb128": 1.13.2 - "@webassemblyjs/utf8": 1.13.2 - - "@webassemblyjs/wast-printer@1.14.1": - dependencies: - "@webassemblyjs/ast": 1.14.1 - "@xtuc/long": 4.2.2 - - "@webpack-cli/configtest@1.2.0(webpack-cli@4.10.0)(webpack@5.99.9)": - dependencies: - webpack: 5.99.9(webpack-cli@4.10.0) - webpack-cli: 4.10.0(webpack@5.99.9) - - "@webpack-cli/info@1.5.0(webpack-cli@4.10.0)": - dependencies: - envinfo: 7.14.0 - webpack-cli: 4.10.0(webpack@5.99.9) - - "@webpack-cli/serve@1.7.0(webpack-cli@4.10.0)": - dependencies: - webpack-cli: 4.10.0(webpack@5.99.9) - - "@xtuc/ieee754@1.2.0": {} - - "@xtuc/long@4.2.2": {} - - JSONStream@1.3.5: - dependencies: - jsonparse: 1.3.1 - through: 2.3.8 - - abab@2.0.6: {} - - acorn-globals@7.0.1: - dependencies: - acorn: 8.15.0 - acorn-walk: 8.3.4 - - acorn-jsx@5.3.2(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} - - agent-base@6.0.2: - dependencies: - debug: 4.4.1(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - - ajv-formats@2.1.1(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 - - ajv-keywords@5.1.0(ajv@8.17.1): - dependencies: - ajv: 8.17.1 - fast-deep-equal: 3.1.3 - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.0.6 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - - ansi-regex@5.0.1: {} - - ansi-regex@6.1.0: {} - - 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: {} - - 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 - - argparse@2.0.1: {} - - array-buffer-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - - array-ify@1.0.0: {} - - array-union@2.1.0: {} - - arraybuffer.prototype.slice@1.0.4: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - is-array-buffer: 3.0.5 - - arrify@1.0.1: {} - - async-function@1.0.0: {} - - async@3.2.6: {} - - asynckit@0.4.0: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - babel-jest@29.7.0(@babel/core@7.27.4): - dependencies: - "@babel/core": 7.27.4 - "@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.27.4) - 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.27.1 - "@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.27.2 - "@babel/types": 7.27.6 - "@types/babel__core": 7.20.5 - "@types/babel__traverse": 7.20.7 - - babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.4): - dependencies: - "@babel/core": 7.27.4 - "@babel/plugin-syntax-async-generators": 7.8.4(@babel/core@7.27.4) - "@babel/plugin-syntax-bigint": 7.8.3(@babel/core@7.27.4) - "@babel/plugin-syntax-class-properties": 7.12.13(@babel/core@7.27.4) - "@babel/plugin-syntax-class-static-block": 7.14.5(@babel/core@7.27.4) - "@babel/plugin-syntax-import-attributes": 7.27.1(@babel/core@7.27.4) - "@babel/plugin-syntax-import-meta": 7.10.4(@babel/core@7.27.4) - "@babel/plugin-syntax-json-strings": 7.8.3(@babel/core@7.27.4) - "@babel/plugin-syntax-logical-assignment-operators": 7.10.4(@babel/core@7.27.4) - "@babel/plugin-syntax-nullish-coalescing-operator": 7.8.3(@babel/core@7.27.4) - "@babel/plugin-syntax-numeric-separator": 7.10.4(@babel/core@7.27.4) - "@babel/plugin-syntax-object-rest-spread": 7.8.3(@babel/core@7.27.4) - "@babel/plugin-syntax-optional-catch-binding": 7.8.3(@babel/core@7.27.4) - "@babel/plugin-syntax-optional-chaining": 7.8.3(@babel/core@7.27.4) - "@babel/plugin-syntax-private-property-in-object": 7.14.5(@babel/core@7.27.4) - "@babel/plugin-syntax-top-level-await": 7.14.5(@babel/core@7.27.4) - - babel-preset-jest@29.6.3(@babel/core@7.27.4): - dependencies: - "@babel/core": 7.27.4 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.4) - - balanced-match@1.0.2: {} - - base64-js@1.5.1: {} - - big.js@5.2.2: {} - - binary-extensions@2.3.0: {} - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.25.0: - dependencies: - caniuse-lite: 1.0.30001723 - electron-to-chromium: 1.5.167 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.25.0) - - 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: {} - - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - - camelcase-keys@6.2.2: - dependencies: - camelcase: 5.3.1 - map-obj: 4.3.0 - quick-lru: 4.0.1 - - camelcase@5.3.1: {} - - camelcase@6.3.0: {} - - caniuse-lite@1.0.30001723: {} - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - chalk@4.1.2: - 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 - - chrome-trace-event@1.0.4: {} - - ci-info@2.0.0: {} - - ci-info@3.9.0: {} - - cjs-module-lexer@1.4.3: {} - - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - clone-deep@4.0.1: - dependencies: - is-plain-object: 2.0.4 - kind-of: 6.0.3 - shallow-clone: 3.0.1 - - co@4.6.0: {} - - collect-v8-coverage@1.0.2: {} - - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.3: {} - - color-name@1.1.4: {} - - colorette@2.0.20: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - commander@12.1.0: {} - - commander@2.20.3: {} - - commander@7.2.0: {} - - compare-func@2.0.0: - dependencies: - array-ify: 1.0.0 - dot-prop: 5.3.0 - - compare-versions@3.6.0: {} - - concat-map@0.0.1: {} - - consola@2.15.3: {} - - conventional-changelog-angular@6.0.0: - dependencies: - compare-func: 2.0.0 - - conventional-changelog-conventionalcommits@6.1.0: - dependencies: - compare-func: 2.0.0 - - conventional-commits-parser@4.0.0: - dependencies: - JSONStream: 1.3.5 - is-text-path: 1.0.1 - meow: 8.1.2 - split2: 3.2.2 - - convert-source-map@2.0.0: {} - - core-util-is@1.0.3: {} - - cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@4.9.5))(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5))(typescript@4.9.5): - dependencies: - "@types/node": 20.5.1 - cosmiconfig: 8.3.6(typescript@4.9.5) - ts-node: 10.9.2(@types/node@18.19.112)(typescript@4.9.5) - typescript: 4.9.5 - - cosmiconfig@7.1.0: - dependencies: - "@types/parse-json": 4.0.2 - import-fresh: 3.3.1 - parse-json: 5.2.0 - path-type: 4.0.0 - yaml: 1.10.2 - - cosmiconfig@8.3.6(typescript@4.9.5): - dependencies: - import-fresh: 3.3.1 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - optionalDependencies: - typescript: 4.9.5 - - create-jest@29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)): - 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.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - 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-env@7.0.3: - dependencies: - cross-spawn: 7.0.6 - - cross-fetch@3.2.0: - dependencies: - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - cross-spawn@6.0.6: - dependencies: - nice-try: 1.0.5 - path-key: 2.0.1 - semver: 5.7.2 - shebang-command: 1.2.0 - which: 1.3.1 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - cssom@0.3.8: {} - - cssom@0.5.0: {} - - cssstyle@2.3.0: - dependencies: - cssom: 0.3.8 - - dargs@7.0.0: {} - - data-urls@3.0.2: - dependencies: - abab: 2.0.6 - whatwg-mimetype: 3.0.0 - whatwg-url: 11.0.0 - - data-view-buffer@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-offset@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - dayjs@1.11.13: {} - - debug@4.4.1(supports-color@5.5.0): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 5.5.0 - - decamelize-keys@1.1.1: - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - - decamelize@1.2.0: {} - - decimal.js@10.5.0: {} - - dedent@1.6.0: {} - - deep-extend@0.6.0: {} - - deep-is@0.1.4: {} - - deepmerge@4.3.1: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - delayed-stream@1.0.0: {} - - detect-newline@3.1.0: {} - - diff-sequences@29.6.3: {} - - diff@4.0.2: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - domexception@4.0.0: - dependencies: - webidl-conversions: 7.0.0 - - dot-prop@5.3.0: - dependencies: - is-obj: 2.0.0 - - dotenv@16.5.0: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - eastasianwidth@0.2.0: {} - - ejs@3.1.10: - dependencies: - jake: 10.9.2 - - electron-to-chromium@1.5.167: {} - - emittery@0.13.1: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - emojis-list@3.0.0: {} - - end-of-stream@1.4.4: - dependencies: - once: 1.4.0 - - enhanced-resolve@4.5.0: - dependencies: - graceful-fs: 4.2.11 - memory-fs: 0.5.0 - tapable: 1.1.3 - - enhanced-resolve@5.18.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.2.2 - - entities@4.5.0: {} - - entities@6.0.1: {} - - envinfo@7.14.0: {} - - errno@0.1.8: - dependencies: - prr: 1.0.1 - - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - - es-abstract@1.24.0: - dependencies: - array-buffer-byte-length: 1.0.2 - arraybuffer.prototype.slice: 1.0.4 - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - data-view-buffer: 1.0.2 - data-view-byte-length: 1.0.2 - data-view-byte-offset: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - get-symbol-description: 1.1.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - internal-slot: 1.1.0 - is-array-buffer: 3.0.5 - is-callable: 1.2.7 - is-data-view: 1.0.2 - is-negative-zero: 2.0.3 - is-regex: 1.2.1 - is-set: 2.0.3 - is-shared-array-buffer: 1.0.4 - is-string: 1.1.1 - is-typed-array: 1.1.15 - is-weakref: 1.1.1 - math-intrinsics: 1.1.0 - object-inspect: 1.13.4 - object-keys: 1.1.1 - object.assign: 4.1.7 - own-keys: 1.0.1 - regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 - safe-push-apply: 1.0.0 - safe-regex-test: 1.1.0 - set-proto: 1.0.0 - stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.3 - typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 - unbox-primitive: 1.1.0 - which-typed-array: 1.1.19 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-module-lexer@1.7.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - es-to-primitive@1.3.0: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - - escalade@3.2.0: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@2.0.0: {} - - escape-string-regexp@4.0.0: {} - - escodegen@2.1.0: - dependencies: - esprima: 4.0.1 - estraverse: 5.3.0 - esutils: 2.0.3 - optionalDependencies: - source-map: 0.6.1 - - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint@8.57.1: - dependencies: - "@eslint-community/eslint-utils": 4.7.0(eslint@8.57.1) - "@eslint-community/regexpp": 4.12.1 - "@eslint/eslintrc": 2.1.4 - "@eslint/js": 8.57.1 - "@humanwhocodes/config-array": 0.13.0 - "@humanwhocodes/module-importer": 1.0.1 - "@nodelib/fs.walk": 1.2.8 - "@ungap/structured-clone": 1.3.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1(supports-color@5.5.0) - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - espree@9.6.1: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 3.4.3 - - esprima@4.0.1: {} - - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@4.3.0: {} - - estraverse@5.3.0: {} - - esutils@2.0.3: {} - - events@3.3.0: {} - - execa@4.1.0: - dependencies: - cross-spawn: 7.0.6 - get-stream: 5.2.0 - human-signals: 1.1.1 - 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 - - 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 - - exit@0.1.2: {} - - 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 - - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.3: - 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 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-uri@3.0.6: {} - - fastest-levenshtein@1.0.16: {} - - fastq@1.19.1: - dependencies: - reusify: 1.1.0 - - fb-watchman@2.0.2: - dependencies: - bser: 2.1.1 - - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - - filelist@1.0.4: - dependencies: - minimatch: 5.1.6 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - find-versions@4.0.0: - dependencies: - semver-regex: 3.1.4 - - flat-cache@3.2.0: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - rimraf: 3.0.2 - - flat@5.0.2: {} - - flatted@3.3.3: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - form-data@4.0.3: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - fs-extra@11.3.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs.realpath@1.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - function.prototype.name@1.1.8: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - functions-have-names: 1.2.3 - hasown: 2.0.2 - is-callable: 1.2.7 - - functions-have-names@1.2.3: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-package-type@0.1.0: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-stdin@9.0.0: {} - - get-stream@5.2.0: - dependencies: - pump: 3.0.3 - - get-stream@6.0.1: {} - - get-symbol-description@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - - git-raw-commits@2.0.11: - dependencies: - dargs: 7.0.0 - lodash: 4.17.21 - meow: 8.1.2 - split2: 3.2.2 - through2: 4.0.2 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob-to-regexp@0.4.1: {} - - glob@11.0.3: - dependencies: - foreground-child: 3.3.1 - jackspeak: 4.1.1 - minimatch: 10.0.3 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.0 - - 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 - - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - global-dirs@0.1.1: - dependencies: - ini: 1.3.8 - - globals@11.12.0: {} - - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - hard-rejection@2.1.0: {} - - has-bigints@1.1.0: {} - - has-flag@3.0.0: {} - - has-flag@4.0.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-proto@1.2.0: - dependencies: - dunder-proto: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - hosted-git-info@2.8.9: {} - - hosted-git-info@4.1.0: - dependencies: - lru-cache: 6.0.0 - - html-encoding-sniffer@3.0.0: - dependencies: - whatwg-encoding: 2.0.0 - - html-escaper@2.0.2: {} - - http-proxy-agent@5.0.0: - dependencies: - "@tootallnate/once": 2.0.0 - agent-base: 6.0.2 - debug: 4.4.1(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.1(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - - human-signals@1.1.1: {} - - human-signals@2.1.0: {} - - husky@4.3.8: - dependencies: - chalk: 4.1.2 - ci-info: 2.0.0 - compare-versions: 3.6.0 - cosmiconfig: 7.1.0 - find-versions: 4.0.0 - opencollective-postinstall: 2.0.3 - pkg-dir: 5.0.0 - please-upgrade-node: 3.2.0 - slash: 3.0.0 - which-pm-runs: 1.1.0 - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - ieee754@1.2.1: {} - - ignore-by-default@1.0.1: {} - - ignore@5.3.2: {} - - ignore@6.0.2: {} - - ignore@7.0.5: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - import-local@3.2.0: - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 - - imurmurhash@0.1.4: {} - - indent-string@4.0.0: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ini@1.3.8: {} - - ini@2.0.0: {} - - ini@4.1.3: {} - - internal-slot@1.1.0: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.1.0 - - interpret@2.2.0: {} - - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-array-buffer@3.0.5: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - is-arrayish@0.2.1: {} - - is-async-function@2.1.1: - dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-bigint@1.1.0: - dependencies: - has-bigints: 1.1.0 - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-boolean-object@1.2.2: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-callable@1.2.7: {} - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-data-view@1.0.2: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-typed-array: 1.1.15 - - is-date-object@1.1.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-extglob@2.1.1: {} - - is-finalizationregistry@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-fullwidth-code-point@3.0.0: {} - - is-generator-fn@2.1.0: {} - - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-map@2.0.3: {} - - is-negative-zero@2.0.3: {} - - is-number-object@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-number@7.0.0: {} - - is-obj@2.0.0: {} - - is-path-inside@3.0.3: {} - - is-plain-obj@1.1.0: {} - - is-plain-object@2.0.4: - dependencies: - isobject: 3.0.1 - - is-potential-custom-element-name@1.0.1: {} - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-set@2.0.3: {} - - is-shared-array-buffer@1.0.4: - dependencies: - call-bound: 1.0.4 - - is-stream@2.0.1: {} - - is-string@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-symbol@1.1.1: - dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 - - is-text-path@1.0.1: - dependencies: - text-extensions: 1.9.0 - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.19 - - is-weakmap@2.0.2: {} - - is-weakref@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-weakset@2.0.4: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - isarray@1.0.0: {} - - isarray@2.0.5: {} - - isexe@2.0.0: {} - - isobject@3.0.1: {} - - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-instrument@5.2.1: - dependencies: - "@babel/core": 7.27.4 - "@babel/parser": 7.27.5 - "@istanbuljs/schema": 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - istanbul-lib-instrument@6.0.3: - dependencies: - "@babel/core": 7.27.4 - "@babel/parser": 7.27.5 - "@istanbuljs/schema": 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 7.7.2 - transitivePeerDependencies: - - supports-color - - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-lib-source-maps@4.0.1: - dependencies: - debug: 4.4.1(supports-color@5.5.0) - istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - - istanbul-reports@3.1.7: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - - jackspeak@4.1.1: - dependencies: - "@isaacs/cliui": 8.0.2 - - jake@10.9.2: - dependencies: - async: 3.2.6 - 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.112 - chalk: 4.1.2 - co: 4.6.0 - dedent: 1.6.0 - 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 - - jest-cli@29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)): - dependencies: - "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - "@jest/test-result": 29.7.0 - "@jest/types": 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - "@types/node" - - babel-plugin-macros - - supports-color - - ts-node - - jest-config@29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)): - dependencies: - "@babel/core": 7.27.4 - "@jest/test-sequencer": 29.7.0 - "@jest/types": 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.4) - 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.112 - ts-node: 10.9.2(@types/node@18.19.112)(typescript@4.9.5) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - 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 - - jest-docblock@29.7.0: - dependencies: - detect-newline: 3.1.0 - - 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 - - jest-environment-jsdom@29.7.0: - dependencies: - "@jest/environment": 29.7.0 - "@jest/fake-timers": 29.7.0 - "@jest/types": 29.6.3 - "@types/jsdom": 20.0.1 - "@types/node": 18.19.112 - jest-mock: 29.7.0 - jest-util: 29.7.0 - jsdom: 20.0.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - jest-environment-node@29.7.0: - dependencies: - "@jest/environment": 29.7.0 - "@jest/fake-timers": 29.7.0 - "@jest/types": 29.6.3 - "@types/node": 18.19.112 - jest-mock: 29.7.0 - jest-util: 29.7.0 - - 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.112 - 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 - - jest-leak-detector@29.7.0: - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - - jest-matcher-utils@29.7.0: - dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - - jest-message-util@29.7.0: - dependencies: - "@babel/code-frame": 7.27.1 - "@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 - - jest-mock@29.7.0: - dependencies: - "@jest/types": 29.6.3 - "@types/node": 18.19.112 - jest-util: 29.7.0 - - jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - optionalDependencies: - jest-resolve: 29.7.0 - - jest-regex-util@29.6.3: {} - - jest-resolve-dependencies@29.7.0: - dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - - 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.10 - resolve.exports: 2.0.3 - 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.112 - 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 - - 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.112 - chalk: 4.1.2 - cjs-module-lexer: 1.4.3 - 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 - - jest-snapshot@29.7.0: - dependencies: - "@babel/core": 7.27.4 - "@babel/generator": 7.27.5 - "@babel/plugin-syntax-jsx": 7.27.1(@babel/core@7.27.4) - "@babel/plugin-syntax-typescript": 7.27.1(@babel/core@7.27.4) - "@babel/types": 7.27.6 - "@jest/expect-utils": 29.7.0 - "@jest/transform": 29.7.0 - "@jest/types": 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.4) - 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.2 - transitivePeerDependencies: - - supports-color - - jest-util@29.7.0: - dependencies: - "@jest/types": 29.6.3 - "@types/node": 18.19.112 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - - jest-validate@29.7.0: - 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 - - jest-watcher@29.7.0: - dependencies: - "@jest/test-result": 29.7.0 - "@jest/types": 29.6.3 - "@types/node": 18.19.112 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.13.1 - jest-util: 29.7.0 - string-length: 4.0.2 - - jest-worker@27.5.1: - dependencies: - "@types/node": 18.19.112 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - jest-worker@29.7.0: - dependencies: - "@types/node": 18.19.112 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - jest@29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)): - dependencies: - "@jest/core": 29.7.0(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - "@jest/types": 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - transitivePeerDependencies: - - "@types/node" - - babel-plugin-macros - - supports-color - - ts-node - - js-tokens@4.0.0: {} - - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - jsdom@20.0.3: - dependencies: - abab: 2.0.6 - acorn: 8.15.0 - acorn-globals: 7.0.1 - cssom: 0.5.0 - cssstyle: 2.3.0 - data-urls: 3.0.2 - decimal.js: 10.5.0 - domexception: 4.0.0 - escodegen: 2.1.0 - form-data: 4.0.3 - html-encoding-sniffer: 3.0.0 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 - is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.20 - parse5: 7.3.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 4.1.4 - w3c-xmlserializer: 4.0.0 - webidl-conversions: 7.0.0 - whatwg-encoding: 2.0.0 - whatwg-mimetype: 3.0.0 - whatwg-url: 11.0.0 - ws: 8.18.2 - xml-name-validator: 4.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-parse-better-errors@1.0.2: {} - - json-parse-even-better-errors@2.3.1: {} - - json-schema-traverse@0.4.1: {} - - json-schema-traverse@1.0.0: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@2.2.3: {} - - jsonc-parser@3.3.1: {} - - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - jsonparse@1.3.1: {} - - jsonpointer@5.0.1: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - kind-of@6.0.3: {} - - kleur@3.0.3: {} - - leven@3.1.0: {} - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - lines-and-columns@1.2.4: {} - - linkify-it@5.0.0: - dependencies: - uc.micro: 2.1.0 - - load-json-file@4.0.0: + enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 - parse-json: 4.0.0 - pify: 3.0.0 - strip-bom: 3.0.0 - - loader-runner@4.3.0: {} - - loader-utils@2.0.4: - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 2.2.3 - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.camelcase@4.3.0: {} - - lodash.isfunction@3.0.9: {} - - lodash.isplainobject@4.0.6: {} - - lodash.kebabcase@4.1.1: {} - - lodash.memoize@4.1.2: {} - - lodash.merge@4.6.2: {} - - lodash.mergewith@4.6.2: {} - - lodash.snakecase@4.1.1: {} - - lodash.startcase@4.4.0: {} - - lodash.uniq@4.5.0: {} - - lodash.upperfirst@4.3.1: {} - - lodash@4.17.21: {} - - lru-cache@11.1.0: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - lunr@2.3.9: {} - - make-dir@4.0.0: - dependencies: - semver: 7.7.2 - - make-error@1.3.6: {} - - makeerror@1.0.12: - dependencies: - tmpl: 1.0.5 - - map-obj@1.0.1: {} - - map-obj@4.3.0: {} - - markdown-it@14.1.0: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - - markdownlint-cli@0.42.0: - dependencies: - commander: 12.1.0 - get-stdin: 9.0.0 - glob: 11.0.3 - ignore: 6.0.2 - js-yaml: 4.1.0 - jsonc-parser: 3.3.1 - jsonpointer: 5.0.1 - markdownlint: 0.35.0 - minimatch: 10.0.3 - run-con: 1.3.2 - smol-toml: 1.3.4 - - markdownlint-micromark@0.1.10: {} - - markdownlint@0.35.0: - dependencies: - markdown-it: 14.1.0 - markdownlint-micromark: 0.1.10 - - marked@4.3.0: {} - - math-intrinsics@1.1.0: {} - - mdurl@2.0.0: {} - - memory-fs@0.5.0: - dependencies: - errno: 0.1.8 - readable-stream: 2.3.8 - - memorystream@0.3.1: {} - - meow@8.1.2: - dependencies: - "@types/minimist": 1.2.5 - camelcase-keys: 6.2.2 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 3.0.3 - read-pkg-up: 7.0.1 - redent: 3.0.0 - trim-newlines: 3.0.1 - type-fest: 0.18.1 - yargs-parser: 20.2.9 - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mimic-fn@2.1.0: {} - - min-indent@1.0.1: {} - - minimatch@10.0.3: - dependencies: - "@isaacs/brace-expansion": 5.0.0 - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.12 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.2 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 - - minimist-options@4.1.0: - dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - - minimist@1.2.8: {} - - minipass@7.1.2: {} - - mri@1.2.0: {} - - ms@2.1.3: {} - - natural-compare@1.4.0: {} - - nconf@0.12.1: - dependencies: - async: 3.2.6 - ini: 2.0.0 - secure-keys: 1.0.0 - yargs: 16.2.0 - - neo-async@2.6.2: {} - - nice-try@1.0.5: {} - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-int64@0.4.0: {} - - node-releases@2.0.19: {} - - nodemon@3.1.10: - dependencies: - chokidar: 3.6.0 - debug: 4.4.1(supports-color@5.5.0) - ignore-by-default: 1.0.1 - minimatch: 3.1.2 - pstree.remy: 1.1.8 - semver: 7.7.2 - simple-update-notifier: 2.0.0 - supports-color: 5.5.0 - touch: 3.1.1 - undefsafe: 2.0.5 - - normalize-package-data@2.5.0: - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.10 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - - normalize-package-data@3.0.3: - dependencies: - hosted-git-info: 4.1.0 - is-core-module: 2.16.1 - semver: 7.7.2 - validate-npm-package-license: 3.0.4 - - normalize-path@3.0.0: {} - - npm-run-all@4.1.5: - dependencies: - ansi-styles: 3.2.1 - chalk: 2.4.2 - cross-spawn: 6.0.6 - memorystream: 0.3.1 - minimatch: 3.1.2 - pidtree: 0.3.1 - read-pkg: 3.0.0 - shell-quote: 1.8.3 - string.prototype.padend: 3.1.6 - - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - - nwsapi@2.2.20: {} - - object-inspect@1.13.4: {} - - object-keys@1.1.1: {} - - object.assign@4.1.7: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - opencollective-postinstall@2.0.3: {} - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - own-keys@1.0.1: - dependencies: - get-intrinsic: 1.3.0 - object-keys: 1.1.1 - safe-push-apply: 1.0.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-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-try@2.2.0: {} - - package-json-from-dist@1.0.1: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-json@4.0.0: - dependencies: - error-ex: 1.3.2 - json-parse-better-errors: 1.0.2 - - parse-json@5.2.0: - dependencies: - "@babel/code-frame": 7.27.1 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - path-exists@4.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@2.0.1: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - path-scurry@2.0.0: - dependencies: - lru-cache: 11.1.0 - minipass: 7.1.2 - - path-type@3.0.0: - dependencies: - pify: 3.0.0 - - path-type@4.0.0: {} - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} + tapable: 2.3.0 - picomatch@3.0.1: {} - - pidtree@0.3.1: {} - - pify@3.0.0: {} - - pirates@4.0.7: {} - - pkg-dir@4.2.0: - dependencies: - find-up: 4.1.0 - - pkg-dir@5.0.0: - dependencies: - find-up: 5.0.0 - - please-upgrade-node@3.2.0: - dependencies: - semver-compare: 1.0.0 - - possible-typed-array-names@1.1.0: {} - - prelude-ls@1.2.1: {} - - prettier@2.8.8: {} - - pretty-format@29.7.0: - dependencies: - "@jest/schemas": 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - pretty-quick@3.3.1(prettier@2.8.8): - dependencies: - execa: 4.1.0 - find-up: 4.1.0 - ignore: 5.3.2 - mri: 1.2.0 - picocolors: 1.1.1 - picomatch: 3.0.1 - prettier: 2.8.8 - tslib: 2.8.1 - - process-nextick-args@2.0.1: {} - - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - - prr@1.0.1: {} - - psl@1.15.0: - dependencies: - punycode: 2.3.1 - - pstree.remy@1.1.8: {} - - pump@3.0.3: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - - punycode.js@2.3.1: {} - - punycode@1.4.1: {} - - punycode@2.3.1: {} - - pure-rand@6.1.0: {} - - qs@6.14.0: - dependencies: - side-channel: 1.1.0 + es-module-lexer@1.7.0: {} - querystringify@2.2.0: {} + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 - queue-microtask@1.2.3: {} + escalade@3.2.0: {} - quick-lru@4.0.1: {} + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 - randombytes@2.1.0: + esrecurse@4.3.0: dependencies: - safe-buffer: 5.2.1 + estraverse: 5.3.0 - react-is@18.3.1: {} + estraverse@4.3.0: {} - read-pkg-up@7.0.1: - dependencies: - find-up: 4.1.0 - read-pkg: 5.2.0 - type-fest: 0.8.1 + estraverse@5.3.0: {} - read-pkg@3.0.0: + estree-walker@3.0.3: dependencies: - load-json-file: 4.0.0 - normalize-package-data: 2.5.0 - path-type: 3.0.0 + '@types/estree': 1.0.8 - read-pkg@5.2.0: - dependencies: - "@types/normalize-package-data": 2.4.4 - normalize-package-data: 2.5.0 - parse-json: 5.2.0 - type-fest: 0.6.0 + events@3.3.0: {} - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 + expect-type@1.2.2: {} - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 + fast-deep-equal@3.1.3: {} - rechoir@0.7.1: - dependencies: - resolve: 1.22.10 + fast-uri@3.1.0: {} - redent@3.0.0: - dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 - reflect.getprototypeof@1.0.10: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - which-builtin-type: 1.2.1 - - regexp.prototype.flags@1.5.4: + fill-range@7.1.1: dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 + to-regex-range: 5.0.1 - require-directory@2.1.1: {} + fsevents@2.3.2: + optional: true - require-from-string@2.0.2: {} + fsevents@2.3.3: + optional: true - requires-port@1.0.0: {} + get-caller-file@2.0.5: {} - resolve-cwd@3.0.0: - dependencies: - resolve-from: 5.0.0 + glob-to-regexp@0.4.1: {} - resolve-from@4.0.0: {} + graceful-fs@4.2.11: {} - resolve-from@5.0.0: {} + graphql@16.12.0: {} - resolve-global@1.0.0: - dependencies: - global-dirs: 0.1.1 + has-flag@4.0.0: {} - resolve.exports@2.0.3: {} + headers-polyfill@4.0.3: {} - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 + is-fullwidth-code-point@3.0.0: {} - reusify@1.1.0: {} + is-node-process@1.2.0: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 + is-number@7.0.0: {} - run-con@1.3.2: + jest-worker@27.5.1: dependencies: - deep-extend: 0.6.0 - ini: 4.1.3 - minimist: 1.2.8 - strip-json-comments: 3.1.1 + '@types/node': 18.19.130 + merge-stream: 2.0.0 + supports-color: 8.1.1 - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 + js-tokens@9.0.1: {} - safe-array-concat@1.1.3: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - isarray: 2.0.5 + json-parse-even-better-errors@2.3.1: {} - safe-buffer@5.1.2: {} + json-schema-traverse@1.0.0: {} - safe-buffer@5.2.1: {} + loader-runner@4.3.1: {} - safe-push-apply@1.0.0: - dependencies: - es-errors: 1.3.0 - isarray: 2.0.5 + loupe@3.2.1: {} - safe-regex-test@1.1.0: + magic-string@0.30.21: dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.5 - safer-buffer@2.1.2: {} + merge-stream@2.0.0: {} - saxes@6.0.0: + micromatch@4.0.8: dependencies: - xmlchars: 2.2.0 + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} - schema-utils@4.3.2: + mime-types@2.1.35: dependencies: - "@types/json-schema": 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) + mime-db: 1.52.0 - secure-keys@1.0.0: {} + ms@2.1.3: {} - semantic-release-plugin-update-version-in-files@1.1.0: - dependencies: - debug: 4.4.1(supports-color@5.5.0) - glob: 7.2.3 + msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3): + dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@inquirer/confirm': 5.1.21(@types/node@18.19.130) + '@mswjs/interceptors': 0.39.8 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.6 + graphql: 16.12.0 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.7.0 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.0 + type-fest: 4.41.0 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.7.3 transitivePeerDependencies: - - supports-color + - '@types/node' - semver-compare@1.0.0: {} + mute-stream@2.0.0: {} - semver-regex@3.1.4: {} + nanoid@3.3.11: {} - semver@5.7.2: {} + neo-async@2.6.2: {} - semver@6.3.1: {} + node-releases@2.0.27: {} - semver@7.5.4: - dependencies: - lru-cache: 6.0.0 + outvariant@1.4.3: {} - semver@7.7.2: {} + path-to-regexp@6.3.0: {} - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 + pathe@2.0.3: {} - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 + pathval@2.0.1: {} - set-proto@1.0.0: - dependencies: - dunder-proto: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 + picocolors@1.1.1: {} + + picomatch@2.3.1: {} - shallow-clone@3.0.1: + picomatch@4.0.3: {} + + playwright-core@1.56.1: {} + + playwright@1.56.1: dependencies: - kind-of: 6.0.3 + playwright-core: 1.56.1 + optionalDependencies: + fsevents: 2.3.2 - shebang-command@1.2.0: + postcss@8.5.6: dependencies: - shebang-regex: 1.0.0 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 - shebang-command@2.0.0: + randombytes@2.1.0: dependencies: - shebang-regex: 3.0.0 + safe-buffer: 5.2.1 - shebang-regex@1.0.0: {} + require-directory@2.1.1: {} - shebang-regex@3.0.0: {} + require-from-string@2.0.2: {} - shell-quote@1.8.3: {} + rettime@0.7.0: {} - shiki@0.10.1: + rollup@4.53.3: dependencies: - jsonc-parser: 3.3.1 - vscode-oniguruma: 1.7.0 - vscode-textmate: 5.2.0 + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 + fsevents: 2.3.3 - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 + safe-buffer@5.2.1: {} - side-channel-map@1.0.1: + schema-utils@4.3.3: dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 + '@types/json-schema': 7.0.15 + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + ajv-keywords: 5.1.0(ajv@8.17.1) - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 + semver@7.7.3: {} - side-channel@1.1.0: + serialize-javascript@6.0.2: dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 + randombytes: 2.1.0 - signal-exit@3.0.7: {} + siginfo@2.0.0: {} signal-exit@4.1.0: {} - simple-update-notifier@2.0.0: - dependencies: - semver: 7.7.2 - - sisteransi@1.0.5: {} - - slash@3.0.0: {} - - smol-toml@1.3.4: {} - - source-map-support@0.5.13: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 + source-map-js@1.2.1: {} source-map-support@0.5.21: dependencies: @@ -9173,44 +1950,15 @@ snapshots: source-map@0.6.1: {} - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.21 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.21 - - spdx-license-ids@3.0.21: {} - - split2@3.2.2: - dependencies: - readable-stream: 3.6.2 - - sprintf-js@1.0.3: {} + source-map@0.7.6: {} - stack-utils@2.0.6: - dependencies: - escape-string-regexp: 2.0.0 + stackback@0.0.2: {} - stop-iteration-iterator@1.1.0: - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 + statuses@2.0.2: {} - stream-browserify@3.0.0: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 + std-env@3.10.0: {} - string-length@4.0.2: - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 + strict-event-emitter@0.5.1: {} string-width@4.2.3: dependencies: @@ -9218,73 +1966,13 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - string.prototype.padend@3.1.6: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - - string.prototype.trim@1.2.10: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-data-property: 1.1.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - has-property-descriptors: 1.0.2 - - string.prototype.trimend@1.0.9: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string.prototype.trimstart@1.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.1.0 - - strip-bom@3.0.0: {} - - strip-bom@4.0.0: {} - - strip-final-newline@2.0.0: {} - - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - - strip-json-comments@3.1.1: {} - - supports-color@5.5.0: + strip-literal@3.1.0: dependencies: - has-flag: 3.0.0 + js-tokens: 9.0.1 supports-color@7.2.0: dependencies: @@ -9294,411 +1982,199 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-preserve-symlinks-flag@1.0.0: {} - - symbol-tree@3.2.4: {} - - tapable@1.1.3: {} - - tapable@2.2.2: {} + tapable@2.3.0: {} - terser-webpack-plugin@5.3.14(webpack@5.99.9): + terser-webpack-plugin@5.3.14(webpack@5.103.0): dependencies: - "@jridgewell/trace-mapping": 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 - terser: 5.42.0 - webpack: 5.99.9(webpack-cli@4.10.0) + terser: 5.44.1 + webpack: 5.103.0 - terser@5.42.0: + terser@5.44.1: dependencies: - "@jridgewell/source-map": 0.3.6 + '@jridgewell/source-map': 0.3.11 acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 - test-exclude@6.0.0: - dependencies: - "@istanbuljs/schema": 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - - text-extensions@1.9.0: {} + tinybench@2.9.0: {} - text-table@0.2.0: {} + tinyexec@0.3.2: {} - through2@4.0.2: + tinyglobby@0.2.15: dependencies: - readable-stream: 3.6.2 - - through@2.3.8: {} - - tmpl@1.0.5: {} + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 + tinypool@1.1.1: {} - touch@3.1.1: {} + tinyrainbow@2.0.0: {} - tough-cookie@4.1.4: - dependencies: - psl: 1.15.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 + tinyspy@4.0.4: {} - tr46@0.0.3: {} + tldts-core@7.0.18: {} - tr46@3.0.0: + tldts@7.0.18: dependencies: - punycode: 2.3.1 + tldts-core: 7.0.18 - trim-newlines@3.0.1: {} - - ts-api-utils@2.1.0(typescript@4.9.5): + to-regex-range@5.0.1: dependencies: - typescript: 4.9.5 + is-number: 7.0.0 - ts-jest@29.4.0(@babel/core@7.27.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@18.19.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)))(typescript@4.9.5): + tough-cookie@6.0.0: 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.112)(ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5)) - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.7.2 - type-fest: 4.41.0 - typescript: 4.9.5 - yargs-parser: 21.1.1 - optionalDependencies: - "@babel/core": 7.27.4 - "@jest/transform": 29.7.0 - "@jest/types": 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.4) - jest-util: 29.7.0 + tldts: 7.0.18 - ts-loader@8.4.0(typescript@4.9.5)(webpack@5.99.9): + ts-loader@9.5.4(typescript@5.7.3)(webpack@5.103.0): dependencies: chalk: 4.1.2 - enhanced-resolve: 4.5.0 - loader-utils: 2.0.4 + enhanced-resolve: 5.18.3 micromatch: 4.0.8 - semver: 7.7.2 - typescript: 4.9.5 - webpack: 5.99.9(webpack-cli@4.10.0) - - ts-node@10.9.2(@types/node@18.19.112)(typescript@4.9.5): - 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.112 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 4.9.5 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5): - 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": 20.5.1 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 4.9.5 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - tslib@2.8.1: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-detect@4.0.8: {} - - type-fest@0.18.1: {} - - type-fest@0.20.2: {} - - type-fest@0.21.3: {} - - type-fest@0.6.0: {} - - type-fest@0.8.1: {} + semver: 7.7.3 + source-map: 0.7.6 + typescript: 5.7.3 + webpack: 5.103.0 type-fest@4.41.0: {} - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typed-array-byte-length@1.0.3: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - - typed-array-byte-offset@1.0.4: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.10 - - typed-array-length@1.0.7: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 - - typedoc@0.22.18(typescript@4.9.5): - dependencies: - glob: 8.1.0 - lunr: 2.3.9 - marked: 4.3.0 - minimatch: 5.1.6 - shiki: 0.10.1 - typescript: 4.9.5 - - typescript@4.9.5: {} - - uc.micro@2.1.0: {} - - unbox-primitive@1.1.0: - dependencies: - call-bound: 1.0.4 - has-bigints: 1.1.0 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.1 - - undefsafe@2.0.5: {} + typescript@5.7.3: {} undici-types@5.26.5: {} - universalify@0.2.0: {} - - universalify@2.0.1: {} - - update-browserslist-db@1.1.3(browserslist@4.25.0): + update-browserslist-db@1.1.4(browserslist@4.28.0): dependencies: - browserslist: 4.25.0 + browserslist: 4.28.0 escalade: 3.2.0 picocolors: 1.1.1 - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - - url@0.11.4: - dependencies: - punycode: 1.4.1 - qs: 6.14.0 - - util-deprecate@1.0.2: {} - - util@0.12.5: - dependencies: - inherits: 2.0.4 - is-arguments: 1.2.0 - is-generator-function: 1.1.0 - is-typed-array: 1.1.15 - which-typed-array: 1.1.19 - - v8-compile-cache-lib@3.0.1: {} - - v8-to-istanbul@9.3.0: - dependencies: - "@jridgewell/trace-mapping": 0.3.25 - "@types/istanbul-lib-coverage": 2.0.6 - convert-source-map: 2.0.0 - - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - - vscode-oniguruma@1.7.0: {} - - vscode-textmate@5.2.0: {} - - w3c-xmlserializer@4.0.0: + vite-node@3.2.4(@types/node@18.19.130)(terser@5.44.1): dependencies: - xml-name-validator: 4.0.0 - - walker@1.0.8: - dependencies: - makeerror: 1.0.12 + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.2.2(@types/node@18.19.130)(terser@5.44.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.2.2(@types/node@18.19.130)(terser@5.44.1): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 18.19.130 + fsevents: 2.3.3 + terser: 5.44.1 + + vitest@3.2.4(@types/node@18.19.130)(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(terser@5.44.1): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(vite@7.2.2(@types/node@18.19.130)(terser@5.44.1)) + '@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.3.3 + debug: 4.4.3 + expect-type: 1.2.2 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.2.2(@types/node@18.19.130)(terser@5.44.1) + vite-node: 3.2.4(@types/node@18.19.130)(terser@5.44.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 18.19.130 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml watchpack@2.4.4: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - webidl-conversions@3.0.1: {} - - webidl-conversions@7.0.0: {} - - webpack-cli@4.10.0(webpack@5.99.9): - dependencies: - "@discoveryjs/json-ext": 0.5.7 - "@webpack-cli/configtest": 1.2.0(webpack-cli@4.10.0)(webpack@5.99.9) - "@webpack-cli/info": 1.5.0(webpack-cli@4.10.0) - "@webpack-cli/serve": 1.7.0(webpack-cli@4.10.0) - colorette: 2.0.20 - commander: 7.2.0 - cross-spawn: 7.0.6 - fastest-levenshtein: 1.0.16 - import-local: 3.2.0 - interpret: 2.2.0 - rechoir: 0.7.1 - webpack: 5.99.9(webpack-cli@4.10.0) - webpack-merge: 5.10.0 - - webpack-merge@5.10.0: - dependencies: - clone-deep: 4.0.1 - flat: 5.0.2 - wildcard: 2.0.1 + webpack-sources@3.3.3: {} - webpack-sources@3.3.2: {} - - webpack@5.99.9(webpack-cli@4.10.0): + webpack@5.103.0: dependencies: - "@types/eslint-scope": 3.7.7 - "@types/estree": 1.0.8 - "@types/json-schema": 7.0.15 - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/wasm-edit": 1.14.1 - "@webassemblyjs/wasm-parser": 1.14.1 + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.15.0 - browserslist: 4.25.0 + acorn-import-phases: 1.0.4(acorn@8.15.0) + browserslist: 4.28.0 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.1 + enhanced-resolve: 5.18.3 es-module-lexer: 1.7.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 + loader-runner: 4.3.1 mime-types: 2.1.35 neo-async: 2.6.2 - schema-utils: 4.3.2 - tapable: 2.2.2 - terser-webpack-plugin: 5.3.14(webpack@5.99.9) + schema-utils: 4.3.3 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.14(webpack@5.103.0) watchpack: 2.4.4 - webpack-sources: 3.3.2 - optionalDependencies: - webpack-cli: 4.10.0(webpack@5.99.9) + webpack-sources: 3.3.3 transitivePeerDependencies: - - "@swc/core" + - '@swc/core' - esbuild - uglify-js - whatwg-encoding@2.0.0: - dependencies: - iconv-lite: 0.6.3 - - whatwg-mimetype@3.0.0: {} - - whatwg-url@11.0.0: - dependencies: - tr46: 3.0.0 - webidl-conversions: 7.0.0 - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which-boxed-primitive@1.1.1: - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - - which-builtin-type@1.2.1: - dependencies: - call-bound: 1.0.4 - function.prototype.name: 1.1.8 - has-tostringtag: 1.0.2 - is-async-function: 2.1.1 - is-date-object: 1.1.0 - is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.0 - is-regex: 1.2.1 - is-weakref: 1.1.1 - isarray: 2.0.5 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.19 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - - which-pm-runs@1.1.0: {} - - which-typed-array@1.1.19: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - - which@1.3.1: + why-is-node-running@2.3.0: dependencies: - isexe: 2.0.0 + siginfo: 2.0.0 + stackback: 0.0.2 - which@2.0.2: + wrap-ansi@6.2.0: dependencies: - isexe: 2.0.0 - - wildcard@2.0.1: {} - - word-wrap@1.2.5: {} + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 wrap-ansi@7.0.0: dependencies: @@ -9706,54 +2182,12 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - wrappy@1.0.2: {} - - write-file-atomic@4.0.2: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - - ws@8.18.2: {} - - xml-name-validator@4.0.0: {} - - xmlchars@2.2.0: {} + ws@8.18.3: {} y18n@5.0.8: {} - yallist@3.1.1: {} - - yallist@4.0.0: {} - - yaml-lint@1.7.0: - dependencies: - consola: 2.15.3 - globby: 11.1.0 - js-yaml: 4.1.0 - nconf: 0.12.1 - - yaml@1.10.2: {} - - yargs-parser@20.2.9: {} - yargs-parser@21.1.1: {} - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -9764,6 +2198,4 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yn@3.1.1: {} - - yocto-queue@0.1.0: {} + yoctocolors-cjs@2.1.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..6e4c3951 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1 @@ +packages: ['.'] \ No newline at end of file diff --git a/reference.md b/reference.md new file mode 100644 index 00000000..78cd2be8 --- /dev/null +++ b/reference.md @@ -0,0 +1,2931 @@ +# Reference +## Agent V1 Settings Think Models +
client.agent.v1.settings.think.models.list() -> Deepgram.AgentThinkModelsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves the available think models that can be used for AI agent processing +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.agent.v1.settings.think.models.list(); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**requestOptions:** `ModelsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Auth V1 Tokens +
client.auth.v1.tokens.grant({ ...params }) -> Deepgram.GrantV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Generates a temporary JSON Web Token (JWT) with a 30-second (by default) TTL and usage::write permission for core voice APIs, requiring an API key with Member or higher authorization. Tokens created with this endpoint will not work with the Manage APIs. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.auth.v1.tokens.grant(); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Deepgram.auth.v1.GrantV1Request` + +
+
+ +
+
+ +**requestOptions:** `TokensClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Listen V1 Media +
client.listen.v1.media.transcribeUrl({ ...params }) -> Deepgram.MediaTranscribeResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Transcribe audio and video using Deepgram's speech-to-text REST API +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.listen.v1.media.transcribeUrl({ + callback: "callback", + callback_method: "POST", + extra: "extra", + sentiment: true, + summarize: "v2", + tag: "tag", + topics: true, + custom_topic: "custom_topic", + custom_topic_mode: "extended", + intents: true, + custom_intent: "custom_intent", + custom_intent_mode: "extended", + detect_entities: true, + detect_language: true, + diarize: true, + dictation: true, + encoding: "linear16", + filler_words: true, + keywords: "keywords", + language: "language", + measurements: true, + model: "nova-3", + multichannel: true, + numerals: true, + paragraphs: true, + profanity_filter: true, + punctuate: true, + redact: "redact", + replace: "replace", + search: "search", + smart_format: true, + utterances: true, + utt_split: 1.1, + version: "latest", + mip_opt_out: true, + url: "https://dpgr.am/spacewalk.wav" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Deepgram.listen.v1.ListenV1RequestUrl` + +
+
+ +
+
+ +**requestOptions:** `MediaClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.listen.v1.media.transcribeFile(uploadable, { ...params }) -> Deepgram.MediaTranscribeResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Transcribe audio and video using Deepgram's speech-to-text REST API +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.listen.v1.media.transcribeFile(createReadStream("path/to/file"), {}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**uploadable:** `core.file.Uploadable` + +
+
+ +
+
+ +**request:** `Deepgram.listen.v1.MediaTranscribeRequestOctetStream` + +
+
+ +
+
+ +**requestOptions:** `MediaClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Models +
client.manage.v1.models.list({ ...params }) -> Deepgram.ListModelsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns metadata on all the latest public models. To retrieve custom models, use Get Project Models. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.models.list({ + include_outdated: true +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.ModelsListRequest` + +
+
+ +
+
+ +**requestOptions:** `ModelsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.models.get(model_id) -> Deepgram.GetModelV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns metadata for a specific public model +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.models.get("af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**model_id:** `string` — The specific UUID of the model + +
+
+ +
+
+ +**requestOptions:** `ModelsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects +
client.manage.v1.projects.list() -> Deepgram.ListProjectsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves basic information about the projects associated with the API key +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.list(); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**requestOptions:** `ProjectsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.get(project_id, { ...params }) -> Deepgram.GetProjectV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves information about the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.get("123456-7890-1234-5678-901234", { + limit: 1.1, + page: 1.1 +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.ProjectsGetRequest` + +
+
+ +
+
+ +**requestOptions:** `ProjectsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.delete(project_id) -> Deepgram.DeleteProjectV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Deletes the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.delete("123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**requestOptions:** `ProjectsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.update(project_id, { ...params }) -> Deepgram.UpdateProjectV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Updates the name or other properties of an existing project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.update("123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.UpdateProjectV1Request` + +
+
+ +
+
+ +**requestOptions:** `ProjectsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.leave(project_id) -> Deepgram.LeaveProjectV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Removes the authenticated account from the specific project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.leave("123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**requestOptions:** `ProjectsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Keys +
client.manage.v1.projects.keys.list(project_id, { ...params }) -> Deepgram.ListProjectKeysV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves all API keys associated with the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.keys.list("123456-7890-1234-5678-901234", { + status: "active" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.KeysListRequest` + +
+
+ +
+
+ +**requestOptions:** `KeysClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.keys.create(project_id, { ...params }) -> Deepgram.CreateKeyV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Creates a new API key with specified settings for the project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.keys.create("project_id", { + "key": "value" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.CreateKeyV1RequestOne` + +
+
+ +
+
+ +**requestOptions:** `KeysClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.keys.get(project_id, key_id) -> Deepgram.GetProjectKeyV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves information about a specified API key +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.keys.get("123456-7890-1234-5678-901234", "123456789012345678901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**key_id:** `string` — The unique identifier of the API key + +
+
+ +
+
+ +**requestOptions:** `KeysClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.keys.delete(project_id, key_id) -> Deepgram.DeleteProjectKeyV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Deletes an API key for a specific project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.keys.delete("123456-7890-1234-5678-901234", "123456789012345678901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**key_id:** `string` — The unique identifier of the API key + +
+
+ +
+
+ +**requestOptions:** `KeysClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Members +
client.manage.v1.projects.members.list(project_id) -> Deepgram.ListProjectMembersV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves a list of members for a given project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.members.list("123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**requestOptions:** `MembersClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.members.delete(project_id, member_id) -> Deepgram.DeleteProjectMemberV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Removes a member from the project using their unique member ID +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.members.delete("123456-7890-1234-5678-901234", "123456789012345678901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**member_id:** `string` — The unique identifier of the Member + +
+
+ +
+
+ +**requestOptions:** `MembersClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Models +
client.manage.v1.projects.models.list(project_id, { ...params }) -> Deepgram.ListModelsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns metadata on all the latest models that a specific project has access to, including non-public models +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.models.list("123456-7890-1234-5678-901234", { + include_outdated: true +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.ModelsListRequest` + +
+
+ +
+
+ +**requestOptions:** `ModelsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.models.get(project_id, model_id) -> Deepgram.GetModelV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns metadata for a specific model +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.models.get("123456-7890-1234-5678-901234", "af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**model_id:** `string` — The specific UUID of the model + +
+
+ +
+
+ +**requestOptions:** `ModelsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Requests +
client.manage.v1.projects.requests.list(project_id, { ...params }) -> Deepgram.ListProjectRequestsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Generates a list of requests for a specific project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.requests.list("123456-7890-1234-5678-901234", { + start: "2024-01-15T09:30:00Z", + end: "2024-01-15T09:30:00Z", + limit: 1.1, + page: 1.1, + accessor: "12345678-1234-1234-1234-123456789012", + request_id: "12345678-1234-1234-1234-123456789012", + deployment: "hosted", + endpoint: "listen", + method: "sync", + status: "succeeded" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.RequestsListRequest` + +
+
+ +
+
+ +**requestOptions:** `RequestsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.requests.get(project_id, request_id) -> Deepgram.GetProjectRequestV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves a specific request for a specific project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.requests.get("123456-7890-1234-5678-901234", "123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request_id:** `string` — The unique identifier of the request + +
+
+ +
+
+ +**requestOptions:** `RequestsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Usage +
client.manage.v1.projects.usage.get(project_id, { ...params }) -> Deepgram.UsageV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves the usage for a specific project. Use Get Project Usage Breakdown for a more comprehensive usage summary. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.usage.get("123456-7890-1234-5678-901234", { + start: "start", + end: "end", + accessor: "12345678-1234-1234-1234-123456789012", + alternatives: true, + callback_method: true, + callback: true, + channels: true, + custom_intent_mode: true, + custom_intent: true, + custom_topic_mode: true, + custom_topic: true, + deployment: "hosted", + detect_entities: true, + detect_language: true, + diarize: true, + dictation: true, + encoding: true, + endpoint: "listen", + extra: true, + filler_words: true, + intents: true, + keyterm: true, + keywords: true, + language: true, + measurements: true, + method: "sync", + model: "6f548761-c9c0-429a-9315-11a1d28499c8", + multichannel: true, + numerals: true, + paragraphs: true, + profanity_filter: true, + punctuate: true, + redact: true, + replace: true, + sample_rate: true, + search: true, + sentiment: true, + smart_format: true, + summarize: true, + tag: "tag1", + topics: true, + utt_split: true, + utterances: true, + version: true +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.UsageGetRequest` + +
+
+ +
+
+ +**requestOptions:** `UsageClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Billing Balances +
client.manage.v1.projects.billing.balances.list(project_id) -> Deepgram.ListProjectBalancesV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Generates a list of outstanding balances for the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.billing.balances.list("123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**requestOptions:** `BalancesClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.billing.balances.get(project_id, balance_id) -> Deepgram.GetProjectBalanceV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves details about the specified balance +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.billing.balances.get("123456-7890-1234-5678-901234", "123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**balance_id:** `string` — The unique identifier of the balance + +
+
+ +
+
+ +**requestOptions:** `BalancesClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Billing Breakdown +
client.manage.v1.projects.billing.breakdown.list(project_id, { ...params }) -> Deepgram.BillingBreakdownV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves the billing summary for a specific project, with various filter options or by grouping options. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.billing.breakdown.list("123456-7890-1234-5678-901234", { + start: "start", + end: "end", + accessor: "12345678-1234-1234-1234-123456789012", + deployment: "hosted", + tag: "tag1", + line_item: "streaming::nova-3" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.billing.BreakdownListRequest` + +
+
+ +
+
+ +**requestOptions:** `BreakdownClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Billing Fields +
client.manage.v1.projects.billing.fields.list(project_id, { ...params }) -> Deepgram.ListBillingFieldsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Lists the accessors, deployment types, tags, and line items used for billing data in the specified time period. Use this endpoint if you want to filter your results from the Billing Breakdown endpoint and want to know what filters are available. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.billing.fields.list("123456-7890-1234-5678-901234", { + start: "start", + end: "end" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.billing.FieldsListRequest` + +
+
+ +
+
+ +**requestOptions:** `FieldsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Billing Purchases +
client.manage.v1.projects.billing.purchases.list(project_id, { ...params }) -> Deepgram.ListProjectPurchasesV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns the original purchased amount on an order transaction +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.billing.purchases.list("123456-7890-1234-5678-901234", { + limit: 1.1 +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.billing.PurchasesListRequest` + +
+
+ +
+
+ +**requestOptions:** `PurchasesClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Members Invites +
client.manage.v1.projects.members.invites.list(project_id) -> Deepgram.ListProjectInvitesV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Generates a list of invites for a specific project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.members.invites.list("123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**requestOptions:** `InvitesClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.members.invites.create(project_id, { ...params }) -> Deepgram.CreateProjectInviteV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Generates an invite for a specific project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.members.invites.create("123456-7890-1234-5678-901234", { + email: "email", + scope: "scope" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.members.CreateProjectInviteV1Request` + +
+
+ +
+
+ +**requestOptions:** `InvitesClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.members.invites.delete(project_id, email) -> Deepgram.DeleteProjectInviteV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Deletes an invite for a specific project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.members.invites.delete("123456-7890-1234-5678-901234", "john.doe@example.com"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**email:** `string` — The email address of the member + +
+
+ +
+
+ +**requestOptions:** `InvitesClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Members Scopes +
client.manage.v1.projects.members.scopes.list(project_id, member_id) -> Deepgram.ListProjectMemberScopesV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves a list of scopes for a specific member +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.members.scopes.list("123456-7890-1234-5678-901234", "123456789012345678901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**member_id:** `string` — The unique identifier of the Member + +
+
+ +
+
+ +**requestOptions:** `ScopesClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.manage.v1.projects.members.scopes.update(project_id, member_id, { ...params }) -> Deepgram.UpdateProjectMemberScopesV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Updates the scopes for a specific member +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.members.scopes.update("123456-7890-1234-5678-901234", "123456789012345678901234", { + scope: "admin" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**member_id:** `string` — The unique identifier of the Member + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.members.UpdateProjectMemberScopesV1Request` + +
+
+ +
+
+ +**requestOptions:** `ScopesClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Usage Breakdown +
client.manage.v1.projects.usage.breakdown.get(project_id, { ...params }) -> Deepgram.UsageBreakdownV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves the usage breakdown for a specific project, with various filter options by API feature or by groupings. Setting a feature (e.g. diarize) to true includes requests that used that feature, while false excludes requests that used it. Multiple true filters are combined with OR logic, while false filters use AND logic. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.usage.breakdown.get("123456-7890-1234-5678-901234", { + start: "start", + end: "end", + grouping: "accessor", + accessor: "12345678-1234-1234-1234-123456789012", + alternatives: true, + callback_method: true, + callback: true, + channels: true, + custom_intent_mode: true, + custom_intent: true, + custom_topic_mode: true, + custom_topic: true, + deployment: "hosted", + detect_entities: true, + detect_language: true, + diarize: true, + dictation: true, + encoding: true, + endpoint: "listen", + extra: true, + filler_words: true, + intents: true, + keyterm: true, + keywords: true, + language: true, + measurements: true, + method: "sync", + model: "6f548761-c9c0-429a-9315-11a1d28499c8", + multichannel: true, + numerals: true, + paragraphs: true, + profanity_filter: true, + punctuate: true, + redact: true, + replace: true, + sample_rate: true, + search: true, + sentiment: true, + smart_format: true, + summarize: true, + tag: "tag1", + topics: true, + utt_split: true, + utterances: true, + version: true +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.usage.BreakdownGetRequest` + +
+
+ +
+
+ +**requestOptions:** `BreakdownClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Manage V1 Projects Usage Fields +
client.manage.v1.projects.usage.fields.list(project_id, { ...params }) -> Deepgram.UsageFieldsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Lists the features, models, tags, languages, and processing method used for requests in the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.manage.v1.projects.usage.fields.list("123456-7890-1234-5678-901234", { + start: "start", + end: "end" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.manage.v1.projects.usage.FieldsListRequest` + +
+
+ +
+
+ +**requestOptions:** `FieldsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Read V1 Text +
client.read.v1.text.analyze({ ...params }) -> Deepgram.ReadV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Analyze text content using Deepgrams text analysis API +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.read.v1.text.analyze({ + callback: "callback", + callback_method: "POST", + sentiment: true, + summarize: "v2", + tag: "tag", + topics: true, + custom_topic: "custom_topic", + custom_topic_mode: "extended", + intents: true, + custom_intent: "custom_intent", + custom_intent_mode: "extended", + language: "language", + body: { + url: "url" + } +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Deepgram.read.v1.TextAnalyzeRequest` + +
+
+ +
+
+ +**requestOptions:** `TextClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## SelfHosted V1 DistributionCredentials +
client.selfHosted.v1.distributionCredentials.list(project_id) -> Deepgram.ListProjectDistributionCredentialsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Lists sets of distribution credentials for the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.selfHosted.v1.distributionCredentials.list("123456-7890-1234-5678-901234"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**requestOptions:** `DistributionCredentialsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.selfHosted.v1.distributionCredentials.create(project_id, { ...params }) -> Deepgram.CreateProjectDistributionCredentialsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Creates a set of distribution credentials for the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.selfHosted.v1.distributionCredentials.create("123456-7890-1234-5678-901234", { + provider: "quay" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**request:** `Deepgram.selfHosted.v1.CreateProjectDistributionCredentialsV1Request` + +
+
+ +
+
+ +**requestOptions:** `DistributionCredentialsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.selfHosted.v1.distributionCredentials.get(project_id, distribution_credentials_id) -> Deepgram.GetProjectDistributionCredentialsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns a set of distribution credentials for the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.selfHosted.v1.distributionCredentials.get("123456-7890-1234-5678-901234", "8b36cfd0-472f-4a21-833f-2d6343c3a2f3"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**distribution_credentials_id:** `string` — The UUID of the distribution credentials + +
+
+ +
+
+ +**requestOptions:** `DistributionCredentialsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.selfHosted.v1.distributionCredentials.delete(project_id, distribution_credentials_id) -> Deepgram.GetProjectDistributionCredentialsV1Response +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Deletes a set of distribution credentials for the specified project +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.selfHosted.v1.distributionCredentials.delete("123456-7890-1234-5678-901234", "8b36cfd0-472f-4a21-833f-2d6343c3a2f3"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `string` — The unique identifier of the project + +
+
+ +
+
+ +**distribution_credentials_id:** `string` — The UUID of the distribution credentials + +
+
+ +
+
+ +**requestOptions:** `DistributionCredentialsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +## Speak V1 Audio +
client.speak.v1.audio.generate({ ...params }) -> core.BinaryResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Convert text into natural-sounding speech using Deepgram's TTS REST API +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.speak.v1.audio.generate({ + text: "text" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Deepgram.speak.v1.SpeakV1Request` + +
+
+ +
+
+ +**requestOptions:** `AudioClient.RequestOptions` + +
+
+
+
+ + +
+
+
diff --git a/scripts/rename-to-esm-files.js b/scripts/rename-to-esm-files.js new file mode 100644 index 00000000..dc1df1cb --- /dev/null +++ b/scripts/rename-to-esm-files.js @@ -0,0 +1,123 @@ +#!/usr/bin/env node + +const fs = require("fs").promises; +const path = require("path"); + +const extensionMap = { + ".js": ".mjs", + ".d.ts": ".d.mts", +}; +const oldExtensions = Object.keys(extensionMap); + +async function findFiles(rootPath) { + const files = []; + + async function scan(directory) { + const entries = await fs.readdir(directory, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(directory, entry.name); + + if (entry.isDirectory()) { + if (entry.name !== "node_modules" && !entry.name.startsWith(".")) { + await scan(fullPath); + } + } else if (entry.isFile()) { + if (oldExtensions.some((ext) => entry.name.endsWith(ext))) { + files.push(fullPath); + } + } + } + } + + await scan(rootPath); + return files; +} + +async function updateFiles(files) { + const updatedFiles = []; + for (const file of files) { + const updated = await updateFileContents(file); + updatedFiles.push(updated); + } + + console.log(`Updated imports in ${updatedFiles.length} files.`); +} + +async function updateFileContents(file) { + const content = await fs.readFile(file, "utf8"); + + let newContent = content; + // Update each extension type defined in the map + for (const [oldExt, newExt] of Object.entries(extensionMap)) { + // Handle static imports/exports + const staticRegex = new RegExp(`(import|export)(.+from\\s+['"])(\\.\\.?\\/[^'"]+)(\\${oldExt})(['"])`, "g"); + newContent = newContent.replace(staticRegex, `$1$2$3${newExt}$5`); + + // Handle dynamic imports (yield import, await import, regular import()) + const dynamicRegex = new RegExp( + `(yield\\s+import|await\\s+import|import)\\s*\\(\\s*['"](\\.\\.\?\\/[^'"]+)(\\${oldExt})['"]\\s*\\)`, + "g", + ); + newContent = newContent.replace(dynamicRegex, `$1("$2${newExt}")`); + } + + if (content !== newContent) { + await fs.writeFile(file, newContent, "utf8"); + return true; + } + return false; +} + +async function renameFiles(files) { + let counter = 0; + for (const file of files) { + const ext = oldExtensions.find((ext) => file.endsWith(ext)); + const newExt = extensionMap[ext]; + + if (newExt) { + const newPath = file.slice(0, -ext.length) + newExt; + await fs.rename(file, newPath); + counter++; + } + } + + console.log(`Renamed ${counter} files.`); +} + +async function main() { + try { + const targetDir = process.argv[2]; + if (!targetDir) { + console.error("Please provide a target directory"); + process.exit(1); + } + + const targetPath = path.resolve(targetDir); + const targetStats = await fs.stat(targetPath); + + if (!targetStats.isDirectory()) { + console.error("The provided path is not a directory"); + process.exit(1); + } + + console.log(`Scanning directory: ${targetDir}`); + + const files = await findFiles(targetDir); + + if (files.length === 0) { + console.log("No matching files found."); + process.exit(0); + } + + console.log(`Found ${files.length} files.`); + await updateFiles(files); + await renameFiles(files); + console.log("\nDone!"); + } catch (error) { + console.error("An error occurred:", error.message); + process.exit(1); + } +} + +main(); diff --git a/scripts/test-offline.js b/scripts/test-offline.js deleted file mode 100755 index d3466165..00000000 --- a/scripts/test-offline.js +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env node - -/* eslint-env node */ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */ - -/** - * Test script to verify e2e tests work properly offline - * This script simulates offline conditions and runs the tests - */ - -const { spawn } = require("child_process"); - -console.log("🧪 Testing Deepgram JS SDK e2e tests in offline mode\n"); - -// Environment variables to ensure offline testing -const env = { - ...process.env, - JEST_SILENT: "false", - NODE_ENV: "test", - // Remove any real API key to force mock usage - DEEPGRAM_API_KEY: "mock-api-key-for-offline-testing", -}; - -// Test command -const testCommand = "npm"; -const testArgs = ["test", "--", "tests/e2e/", "--verbose"]; - -console.log("🎭 Running e2e tests with mocked API calls..."); -console.log(`Command: ${testCommand} ${testArgs.join(" ")}\n`); - -const testProcess = spawn(testCommand, testArgs, { - env, - stdio: "inherit", - shell: true, -}); - -testProcess.on("close", (code) => { - if (code === 0) { - console.log("\n✅ All e2e tests passed in offline mode!"); - console.log("🎉 Your tests are properly configured to work without internet connection."); - console.log("\n💡 To run tests with real API calls (for updating snapshots):"); - console.log(" npm test -- tests/e2e/ --updateSnapshot"); - console.log("\n🔧 To force real API calls without updating snapshots:"); - console.log(" DEEPGRAM_FORCE_REAL_API=true npm test -- tests/e2e/"); - } else { - console.log(`\n❌ Tests failed with exit code ${code}`); - console.log("🔍 This indicates there might be network dependencies that need to be mocked."); - } -}); - -testProcess.on("error", (error) => { - console.error("❌ Failed to run tests:", error); - process.exit(1); -}); diff --git a/src/BaseClient.ts b/src/BaseClient.ts new file mode 100644 index 00000000..b12df511 --- /dev/null +++ b/src/BaseClient.ts @@ -0,0 +1,56 @@ +// This file was auto-generated by Fern from our API Definition. + +import { mergeHeaders } from "./core/headers.js"; +import * as core from "./core/index.js"; +import type * as environments from "./environments.js"; + +export interface BaseClientOptions { + environment?: core.Supplier; + /** Specify a custom URL to connect the client to. */ + baseUrl?: core.Supplier; + apiKey?: core.Supplier; + /** Additional headers to include in requests. */ + headers?: Record | null | undefined>; + /** The default maximum time to wait for a response in seconds. */ + timeoutInSeconds?: number; + /** The default number of times to retry the request. Defaults to 2. */ + maxRetries?: number; + /** Provide a custom fetch implementation. Useful for platforms that don't have a built-in fetch or need a custom implementation. */ + fetch?: typeof fetch; + fetcher?: core.FetchFunction; + /** Configure logging for the client. */ + logging?: core.logging.LogConfig | core.logging.Logger; +} + +export interface BaseRequestOptions { + /** The maximum time to wait for a response in seconds. */ + timeoutInSeconds?: number; + /** The number of times to retry the request. Defaults to 2. */ + maxRetries?: number; + /** A hook to abort the request. */ + abortSignal?: AbortSignal; + /** Additional query string parameters to include in the request. */ + queryParams?: Record; + /** Additional headers to include in the request. */ + headers?: Record | null | undefined>; +} + +export function normalizeClientOptions(options: T): T { + const headers = mergeHeaders( + { + "X-Fern-Language": "JavaScript", + "X-Fern-SDK-Name": "@deepgram/sdk", + "X-Fern-SDK-Version": "4.11.3", + "User-Agent": "@deepgram/sdk/4.11.3", + "X-Fern-Runtime": core.RUNTIME.type, + "X-Fern-Runtime-Version": core.RUNTIME.version, + }, + options?.headers, + ); + + return { + ...options, + logging: core.logging.createLogger(options?.logging), + headers, + } as T; +} diff --git a/src/Client.ts b/src/Client.ts new file mode 100644 index 00000000..1905f62e --- /dev/null +++ b/src/Client.ts @@ -0,0 +1,60 @@ +// This file was auto-generated by Fern from our API Definition. + +import { AgentClient } from "./api/resources/agent/client/Client.js"; +import { AuthClient } from "./api/resources/auth/client/Client.js"; +import { ListenClient } from "./api/resources/listen/client/Client.js"; +import { ManageClient } from "./api/resources/manage/client/Client.js"; +import { ReadClient } from "./api/resources/read/client/Client.js"; +import { SelfHostedClient } from "./api/resources/selfHosted/client/Client.js"; +import { SpeakClient } from "./api/resources/speak/client/Client.js"; +import type { BaseClientOptions, BaseRequestOptions } from "./BaseClient.js"; +import { normalizeClientOptions } from "./BaseClient.js"; + +export declare namespace DeepgramClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class DeepgramClient { + protected readonly _options: DeepgramClient.Options; + protected _agent: AgentClient | undefined; + protected _auth: AuthClient | undefined; + protected _listen: ListenClient | undefined; + protected _manage: ManageClient | undefined; + protected _read: ReadClient | undefined; + protected _selfHosted: SelfHostedClient | undefined; + protected _speak: SpeakClient | undefined; + + constructor(options: DeepgramClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get agent(): AgentClient { + return (this._agent ??= new AgentClient(this._options)); + } + + public get auth(): AuthClient { + return (this._auth ??= new AuthClient(this._options)); + } + + public get listen(): ListenClient { + return (this._listen ??= new ListenClient(this._options)); + } + + public get manage(): ManageClient { + return (this._manage ??= new ManageClient(this._options)); + } + + public get read(): ReadClient { + return (this._read ??= new ReadClient(this._options)); + } + + public get selfHosted(): SelfHostedClient { + return (this._selfHosted ??= new SelfHostedClient(this._options)); + } + + public get speak(): SpeakClient { + return (this._speak ??= new SpeakClient(this._options)); + } +} diff --git a/src/DeepgramClient.ts b/src/DeepgramClient.ts deleted file mode 100644 index 5f7bc99a..00000000 --- a/src/DeepgramClient.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { DeepgramVersionError } from "./lib/errors"; -import { - AbstractClient, - AgentLiveClient, - AuthRestClient, - ListenClient, - ManageClient, - ReadClient, - OnPremClient, - SelfHostedRestClient, - SpeakClient, - ModelsRestClient, -} from "./packages"; - -/** - * The DeepgramClient class provides access to various Deepgram API clients, including ListenClient, ManageClient, SelfHostedRestClient, ReadClient, and SpeakClient. - * - * @see https://github.com/deepgram/deepgram-js-sdk - */ -export default class DeepgramClient extends AbstractClient { - /** - * Returns a new instance of the AuthRestClient, which provides access to the Deepgram API's temporary token endpoints. - * - * @returns {AuthRestClient} A new instance of the AuthRestClient. - * @see https://developers.deepgram.com/reference/token-based-auth-api/grant-token - */ - get auth(): AuthRestClient { - return new AuthRestClient(this.options); - } - /** - * Returns a new instance of the ListenClient, which provides access to the Deepgram API's listening functionality. - * - * @returns {ListenClient} A new instance of the ListenClient. - */ - get listen(): ListenClient { - return new ListenClient(this.options); - } - - /** - * Returns a new instance of the ManageClient, which provides access to the Deepgram API's management functionality. - * - * @returns {ManageClient} A new instance of the ManageClient. - */ - get manage(): ManageClient { - return new ManageClient(this.options); - } - - /** - * Returns a new instance of the ModelsRestClient, which provides access to the Deepgram API's model functionality. - * - * @returns {ModelsRestClient} A new instance of the ModelsRestClient. - */ - get models(): ModelsRestClient { - return new ModelsRestClient(this.options); - } - - /** - * Returns a new instance of the SelfHostedRestClient, which provides access to the Deepgram API's self-hosted functionality. - * - * @returns {OnPremClient} A new instance of the SelfHostedRestClient named as OnPremClient. - * @deprecated use selfhosted() instead - */ - get onprem(): OnPremClient { - return this.selfhosted; - } - - /** - * Returns a new instance of the SelfHostedRestClient, which provides access to the Deepgram API's self-hosted functionality. - * - * @returns {SelfHostedRestClient} A new instance of the SelfHostedRestClient. - */ - get selfhosted(): SelfHostedRestClient { - return new SelfHostedRestClient(this.options); - } - - /** - * Returns a new instance of the ReadClient, which provides access to the Deepgram API's reading functionality. - * - * @returns {ReadClient} A new instance of the ReadClient. - */ - get read(): ReadClient { - return new ReadClient(this.options); - } - - /** - * Returns a new instance of the SpeakClient, which provides access to the Deepgram API's speaking functionality. - * - * @returns {SpeakClient} A new instance of the SpeakClient. - */ - get speak(): SpeakClient { - return new SpeakClient(this.options); - } - - /** - * Returns a new instance of the AgentLiveClient, which provides access to Deepgram's Voice Agent API. - * - * @returns {AgentLiveClient} A new instance of the AgentLiveClient. - * @beta - */ - public agent(endpoint: string = "/:version/agent/converse"): AgentLiveClient { - return new AgentLiveClient(this.options, endpoint); - } - - /** - * @deprecated - * @see https://dpgr.am/js-v3 - */ - get transcription(): any { - throw new DeepgramVersionError(); - } - - /** - * @deprecated - * @see https://dpgr.am/js-v3 - */ - get projects(): any { - throw new DeepgramVersionError(); - } - - /** - * @deprecated - * @see https://dpgr.am/js-v3 - */ - get keys(): any { - throw new DeepgramVersionError(); - } - - /** - * @deprecated - * @see https://dpgr.am/js-v3 - */ - get members(): any { - throw new DeepgramVersionError(); - } - - /** - * @deprecated - * @see https://dpgr.am/js-v3 - */ - get scopes(): any { - throw new DeepgramVersionError(); - } - - /** - * @deprecated - * @see https://dpgr.am/js-v3 - */ - get invitation(): any { - throw new DeepgramVersionError(); - } - - /** - * @deprecated - * @see https://dpgr.am/js-v3 - */ - get usage(): any { - throw new DeepgramVersionError(); - } - - /** - * @deprecated - * @see https://dpgr.am/js-v3 - */ - get billing(): any { - throw new DeepgramVersionError(); - } -} diff --git a/src/api/errors/BadRequestError.ts b/src/api/errors/BadRequestError.ts new file mode 100644 index 00000000..984dafd8 --- /dev/null +++ b/src/api/errors/BadRequestError.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as core from "../../core/index.js"; +import * as errors from "../../errors/index.js"; + +export class BadRequestError extends errors.DeepgramError { + constructor(body?: unknown, rawResponse?: core.RawResponse) { + super({ + message: "BadRequestError", + statusCode: 400, + body: body, + rawResponse: rawResponse, + }); + Object.setPrototypeOf(this, BadRequestError.prototype); + } +} diff --git a/src/api/errors/index.ts b/src/api/errors/index.ts new file mode 100644 index 00000000..db9ee322 --- /dev/null +++ b/src/api/errors/index.ts @@ -0,0 +1 @@ +export * from "./BadRequestError.js"; diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 00000000..6ed44b0b --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,3 @@ +export * from "./errors/index.js"; +export * from "./resources/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/agent/client/Client.ts b/src/api/resources/agent/client/Client.ts new file mode 100644 index 00000000..e34419f4 --- /dev/null +++ b/src/api/resources/agent/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../BaseClient.js"; +import { V1Client } from "../resources/v1/client/Client.js"; + +export declare namespace AgentClient { + export interface Options extends BaseClientOptions {} +} + +export class AgentClient { + protected readonly _options: AgentClient.Options; + protected _v1: V1Client | undefined; + + constructor(options: AgentClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get v1(): V1Client { + return (this._v1 ??= new V1Client(this._options)); + } +} diff --git a/src/api/resources/agent/client/index.ts b/src/api/resources/agent/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/agent/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/agent/index.ts b/src/api/resources/agent/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/agent/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/agent/resources/index.ts b/src/api/resources/agent/resources/index.ts new file mode 100644 index 00000000..96368d86 --- /dev/null +++ b/src/api/resources/agent/resources/index.ts @@ -0,0 +1,2 @@ +export * as v1 from "./v1/index.js"; +export * from "./v1/types/index.js"; diff --git a/src/api/resources/agent/resources/v1/client/Client.ts b/src/api/resources/agent/resources/v1/client/Client.ts new file mode 100644 index 00000000..47c8f8f7 --- /dev/null +++ b/src/api/resources/agent/resources/v1/client/Client.ts @@ -0,0 +1,67 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../core/headers.js"; +import * as core from "../../../../../../core/index.js"; +import * as environments from "../../../../../../environments.js"; +import { SettingsClient } from "../resources/settings/client/Client.js"; +import { V1Socket } from "./Socket.js"; + +export declare namespace V1Client { + export interface Options extends BaseClientOptions {} + + export interface ConnectArgs { + Authorization: string; + /** Arbitrary headers to send with the websocket connect request. */ + headers?: Record; + /** Enable debug mode on the websocket. Defaults to false. */ + debug?: boolean; + /** Number of reconnect attempts. Defaults to 30. */ + reconnectAttempts?: number; + } +} + +export class V1Client { + protected readonly _options: V1Client.Options; + protected _settings: SettingsClient | undefined; + + constructor(options: V1Client.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get settings(): SettingsClient { + return (this._settings ??= new SettingsClient(this._options)); + } + + public async connect(args: V1Client.ConnectArgs): Promise { + const { headers, debug, reconnectAttempts } = args; + const _headers: Record = mergeHeaders( + mergeOnlyDefinedHeaders({ + ...(await this._getCustomAuthorizationHeaders()), + Authorization: args.Authorization, + }), + headers, + ); + const socket = new core.ReconnectingWebSocket({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).agent, + "/v1/agent/converse", + ), + protocols: [], + queryParameters: {}, + headers: _headers, + options: { debug: debug ?? false, maxRetries: reconnectAttempts ?? 30 }, + }); + return new V1Socket({ socket }); + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/agent/resources/v1/client/Socket.ts b/src/api/resources/agent/resources/v1/client/Socket.ts new file mode 100644 index 00000000..3cd6b52c --- /dev/null +++ b/src/api/resources/agent/resources/v1/client/Socket.ts @@ -0,0 +1,194 @@ +// This file was auto-generated by Fern from our API Definition. + +import * as core from "../../../../../../core/index.js"; +import { fromJson, toJson } from "../../../../../../core/json.js"; +import type * as Deepgram from "../../../../../index.js"; + +export declare namespace V1Socket { + export interface Args { + socket: core.ReconnectingWebSocket; + } + + export type Response = + | Deepgram.agent.AgentV1ReceiveFunctionCallResponse + | Deepgram.agent.AgentV1PromptUpdated + | Deepgram.agent.AgentV1SpeakUpdated + | Deepgram.agent.AgentV1InjectionRefused + | Deepgram.agent.AgentV1Welcome + | Deepgram.agent.AgentV1SettingsApplied + | Deepgram.agent.AgentV1ConversationText + | Deepgram.agent.AgentV1UserStartedSpeaking + | Deepgram.agent.AgentV1AgentThinking + | Deepgram.agent.AgentV1FunctionCallRequest + | Deepgram.agent.AgentV1AgentStartedSpeaking + | Deepgram.agent.AgentV1AgentAudioDone + | Deepgram.agent.AgentV1Error + | Deepgram.agent.AgentV1Warning + | string; + type EventHandlers = { + open?: () => void; + message?: (message: Response) => void; + close?: (event: core.CloseEvent) => void; + error?: (error: Error) => void; + }; +} + +export class V1Socket { + public readonly socket: core.ReconnectingWebSocket; + protected readonly eventHandlers: V1Socket.EventHandlers = {}; + private handleOpen: () => void = () => { + this.eventHandlers.open?.(); + }; + private handleMessage: (event: { data: string }) => void = (event) => { + const data = fromJson(event.data); + + this.eventHandlers.message?.(data as V1Socket.Response); + }; + private handleClose: (event: core.CloseEvent) => void = (event) => { + this.eventHandlers.close?.(event); + }; + private handleError: (event: core.ErrorEvent) => void = (event) => { + const message = event.message; + this.eventHandlers.error?.(new Error(message)); + }; + + constructor(args: V1Socket.Args) { + this.socket = args.socket; + this.socket.addEventListener("open", this.handleOpen); + this.socket.addEventListener("message", this.handleMessage); + this.socket.addEventListener("close", this.handleClose); + this.socket.addEventListener("error", this.handleError); + } + + /** The current state of the connection; this is one of the readyState constants. */ + get readyState(): number { + return this.socket.readyState; + } + + /** + * @param event - The event to attach to. + * @param callback - The callback to run when the event is triggered. + * Usage: + * ```typescript + * this.on('open', () => { + * console.log('The websocket is open'); + * }); + * ``` + */ + public on(event: T, callback: V1Socket.EventHandlers[T]): void { + this.eventHandlers[event] = callback; + } + + public sendAgentV1Settings(message: Deepgram.agent.AgentV1Settings): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendAgentV1UpdateSpeak(message: Deepgram.agent.AgentV1UpdateSpeak): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendAgentV1InjectUserMessage(message: Deepgram.agent.AgentV1InjectUserMessage): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendAgentV1InjectAgentMessage(message: Deepgram.agent.AgentV1InjectAgentMessage): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendAgentV1SendFunctionCallResponse(message: Deepgram.agent.AgentV1SendFunctionCallResponse): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendAgentV1KeepAlive(message: Deepgram.agent.AgentV1KeepAlive): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendAgentV1UpdatePrompt(message: Deepgram.agent.AgentV1UpdatePrompt): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendAgentV1Media(message: string): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + /** Connect to the websocket and register event handlers. */ + public connect(): V1Socket { + this.socket.reconnect(); + + this.socket.addEventListener("open", this.handleOpen); + this.socket.addEventListener("message", this.handleMessage); + this.socket.addEventListener("close", this.handleClose); + this.socket.addEventListener("error", this.handleError); + + return this; + } + + /** Close the websocket and unregister event handlers. */ + public close(): void { + this.socket.close(); + + this.handleClose({ code: 1000 } as CloseEvent); + + this.socket.removeEventListener("open", this.handleOpen); + this.socket.removeEventListener("message", this.handleMessage); + this.socket.removeEventListener("close", this.handleClose); + this.socket.removeEventListener("error", this.handleError); + } + + /** Returns a promise that resolves when the websocket is open. */ + public async waitForOpen(): Promise { + if (this.socket.readyState === core.ReconnectingWebSocket.OPEN) { + return this.socket; + } + + return new Promise((resolve, reject) => { + this.socket.addEventListener("open", () => { + resolve(this.socket); + }); + + this.socket.addEventListener("error", (event: unknown) => { + reject(event); + }); + }); + } + + /** Asserts that the websocket is open. */ + private assertSocketIsOpen(): void { + if (!this.socket) { + throw new Error("Socket is not connected."); + } + + if (this.socket.readyState !== core.ReconnectingWebSocket.OPEN) { + throw new Error("Socket is not open."); + } + } + + /** Send a binary payload to the websocket. */ + protected sendBinary(payload: ArrayBufferLike | Blob | ArrayBufferView): void { + this.socket.send(payload); + } + + /** Send a JSON payload to the websocket. */ + protected sendJson( + payload: + | Deepgram.agent.AgentV1Settings + | Deepgram.agent.AgentV1UpdateSpeak + | Deepgram.agent.AgentV1InjectUserMessage + | Deepgram.agent.AgentV1InjectAgentMessage + | Deepgram.agent.AgentV1SendFunctionCallResponse + | Deepgram.agent.AgentV1KeepAlive + | Deepgram.agent.AgentV1UpdatePrompt + | string, + ): void { + const jsonPayload = toJson(payload); + this.socket.send(jsonPayload); + } +} diff --git a/src/api/resources/agent/resources/v1/client/index.ts b/src/api/resources/agent/resources/v1/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/agent/resources/v1/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/agent/resources/v1/index.ts b/src/api/resources/agent/resources/v1/index.ts new file mode 100644 index 00000000..0ef16e76 --- /dev/null +++ b/src/api/resources/agent/resources/v1/index.ts @@ -0,0 +1,3 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/agent/resources/v1/resources/index.ts b/src/api/resources/agent/resources/v1/resources/index.ts new file mode 100644 index 00000000..5d08c463 --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/index.ts @@ -0,0 +1 @@ +export * as settings from "./settings/index.js"; diff --git a/src/api/resources/agent/resources/v1/resources/settings/client/Client.ts b/src/api/resources/agent/resources/v1/resources/settings/client/Client.ts new file mode 100644 index 00000000..0ab7f31e --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../BaseClient.js"; +import { ThinkClient } from "../resources/think/client/Client.js"; + +export declare namespace SettingsClient { + export interface Options extends BaseClientOptions {} +} + +export class SettingsClient { + protected readonly _options: SettingsClient.Options; + protected _think: ThinkClient | undefined; + + constructor(options: SettingsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get think(): ThinkClient { + return (this._think ??= new ThinkClient(this._options)); + } +} diff --git a/src/api/resources/agent/resources/v1/resources/settings/client/index.ts b/src/api/resources/agent/resources/v1/resources/settings/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/agent/resources/v1/resources/settings/index.ts b/src/api/resources/agent/resources/v1/resources/settings/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/agent/resources/v1/resources/settings/resources/index.ts b/src/api/resources/agent/resources/v1/resources/settings/resources/index.ts new file mode 100644 index 00000000..48db7d4c --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/resources/index.ts @@ -0,0 +1 @@ +export * as think from "./think/index.js"; diff --git a/src/api/resources/agent/resources/v1/resources/settings/resources/think/client/Client.ts b/src/api/resources/agent/resources/v1/resources/settings/resources/think/client/Client.ts new file mode 100644 index 00000000..fdde89d2 --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/resources/think/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { ModelsClient } from "../resources/models/client/Client.js"; + +export declare namespace ThinkClient { + export interface Options extends BaseClientOptions {} +} + +export class ThinkClient { + protected readonly _options: ThinkClient.Options; + protected _models: ModelsClient | undefined; + + constructor(options: ThinkClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get models(): ModelsClient { + return (this._models ??= new ModelsClient(this._options)); + } +} diff --git a/src/api/resources/agent/resources/v1/resources/settings/resources/think/client/index.ts b/src/api/resources/agent/resources/v1/resources/settings/resources/think/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/resources/think/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/agent/resources/v1/resources/settings/resources/think/index.ts b/src/api/resources/agent/resources/v1/resources/settings/resources/think/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/resources/think/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/index.ts b/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/index.ts new file mode 100644 index 00000000..4920fabe --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/index.ts @@ -0,0 +1 @@ +export * as models from "./models/index.js"; diff --git a/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/client/Client.ts b/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/client/Client.ts new file mode 100644 index 00000000..088e648a --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/client/Client.ts @@ -0,0 +1,106 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace ModelsClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class ModelsClient { + protected readonly _options: ModelsClient.Options; + + constructor(options: ModelsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Retrieves the available think models that can be used for AI agent processing + * + * @param {ModelsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.agent.v1.settings.think.models.list() + */ + public list( + requestOptions?: ModelsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(requestOptions)); + } + + private async __list( + requestOptions?: ModelsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).agent, + "v1/agent/settings/think/models", + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.AgentThinkModelsV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/agent/settings/think/models.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/client/index.ts b/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/index.ts b/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/agent/resources/v1/resources/settings/resources/think/resources/models/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/agent/resources/v1/types/AgentV1AgentAudioDone.ts b/src/api/resources/agent/resources/v1/types/AgentV1AgentAudioDone.ts new file mode 100644 index 00000000..53beee81 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1AgentAudioDone.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1AgentAudioDone { + /** Message type identifier indicating the agent has finished sending audio */ + type: "AgentAudioDone"; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1AgentStartedSpeaking.ts b/src/api/resources/agent/resources/v1/types/AgentV1AgentStartedSpeaking.ts new file mode 100644 index 00000000..90a4c532 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1AgentStartedSpeaking.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1AgentStartedSpeaking { + /** Message type identifier for agent started speaking */ + type: "AgentStartedSpeaking"; + /** Seconds from receiving the user's utterance to producing the agent's reply */ + total_latency: number; + /** The portion of total latency attributable to text-to-speech */ + tts_latency: number; + /** The portion of total latency attributable to text-to-text (usually an LLM) */ + ttt_latency: number; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1AgentThinking.ts b/src/api/resources/agent/resources/v1/types/AgentV1AgentThinking.ts new file mode 100644 index 00000000..40d00b2d --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1AgentThinking.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1AgentThinking { + /** Message type identifier for agent thinking */ + type: "AgentThinking"; + /** The text of the agent's thought process */ + content: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1ConversationText.ts b/src/api/resources/agent/resources/v1/types/AgentV1ConversationText.ts new file mode 100644 index 00000000..2f556719 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1ConversationText.ts @@ -0,0 +1,19 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1ConversationText { + /** Message type identifier for conversation text */ + type: "ConversationText"; + /** Identifies who spoke the statement */ + role: AgentV1ConversationText.Role; + /** The actual statement that was spoken */ + content: string; +} + +export namespace AgentV1ConversationText { + /** Identifies who spoke the statement */ + export const Role = { + User: "user", + Assistant: "assistant", + } as const; + export type Role = (typeof Role)[keyof typeof Role]; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1Error.ts b/src/api/resources/agent/resources/v1/types/AgentV1Error.ts new file mode 100644 index 00000000..c76a5d51 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1Error.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1Error { + /** Message type identifier for error responses */ + type: "Error"; + /** A description of what went wrong */ + description: string; + /** Error code identifying the type of error */ + code: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1FunctionCallRequest.ts b/src/api/resources/agent/resources/v1/types/AgentV1FunctionCallRequest.ts new file mode 100644 index 00000000..77fe40f6 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1FunctionCallRequest.ts @@ -0,0 +1,25 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1FunctionCallRequest { + /** Message type identifier for function call requests */ + type: "FunctionCallRequest"; + /** Array of functions to be called */ + functions: AgentV1FunctionCallRequest.Functions.Item[]; +} + +export namespace AgentV1FunctionCallRequest { + export type Functions = Functions.Item[]; + + export namespace Functions { + export interface Item { + /** Unique identifier for the function call */ + id: string; + /** The name of the function to call */ + name: string; + /** JSON string containing the function arguments */ + arguments: string; + /** Whether the function should be executed client-side */ + client_side: boolean; + } + } +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1InjectAgentMessage.ts b/src/api/resources/agent/resources/v1/types/AgentV1InjectAgentMessage.ts new file mode 100644 index 00000000..34853f9a --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1InjectAgentMessage.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1InjectAgentMessage { + /** Message type identifier for injecting an agent message */ + type: "InjectAgentMessage"; + /** The statement that the agent should say */ + message: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1InjectUserMessage.ts b/src/api/resources/agent/resources/v1/types/AgentV1InjectUserMessage.ts new file mode 100644 index 00000000..61abc2a2 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1InjectUserMessage.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1InjectUserMessage { + /** Message type identifier for injecting a user message */ + type: "InjectUserMessage"; + /** The specific phrase or statement the agent should respond to */ + content: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1InjectionRefused.ts b/src/api/resources/agent/resources/v1/types/AgentV1InjectionRefused.ts new file mode 100644 index 00000000..8267b3a7 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1InjectionRefused.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1InjectionRefused { + /** Message type identifier for injection refused */ + type: "InjectionRefused"; + /** Details about why the injection was refused */ + message: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1KeepAlive.ts b/src/api/resources/agent/resources/v1/types/AgentV1KeepAlive.ts new file mode 100644 index 00000000..c2d249ee --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1KeepAlive.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Send a control message to the agent + */ +export interface AgentV1KeepAlive { + /** Message type identifier */ + type: "KeepAlive"; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1PromptUpdated.ts b/src/api/resources/agent/resources/v1/types/AgentV1PromptUpdated.ts new file mode 100644 index 00000000..95086e63 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1PromptUpdated.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1PromptUpdated { + /** Message type identifier for prompt update confirmation */ + type: "PromptUpdated"; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1ReceiveFunctionCallResponse.ts b/src/api/resources/agent/resources/v1/types/AgentV1ReceiveFunctionCallResponse.ts new file mode 100644 index 00000000..1f76a65e --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1ReceiveFunctionCallResponse.ts @@ -0,0 +1,30 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Function call response message used bidirectionally: + * + * • **Client → Server**: Response after client executes a function + * marked as client_side: true + * • **Server → Client**: Response after server executes a function + * marked as client_side: false + * + * The same message structure serves both directions, enabling a unified + * interface for function call responses regardless of execution location. + */ +export interface AgentV1ReceiveFunctionCallResponse { + /** Message type identifier for function call responses */ + type: "FunctionCallResponse"; + /** + * The unique identifier for the function call. + * + * • **Required for client responses**: Should match the id from + * the corresponding `FunctionCallRequest` + * • **Optional for server responses**: Server may omit when responding + * to internal function executions + */ + id?: string; + /** The name of the function being called */ + name: string; + /** The content or result of the function call */ + content: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1SendFunctionCallResponse.ts b/src/api/resources/agent/resources/v1/types/AgentV1SendFunctionCallResponse.ts new file mode 100644 index 00000000..e6f035e9 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1SendFunctionCallResponse.ts @@ -0,0 +1,30 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Function call response message used bidirectionally: + * + * • **Client → Server**: Response after client executes a function + * marked as client_side: true + * • **Server → Client**: Response after server executes a function + * marked as client_side: false + * + * The same message structure serves both directions, enabling a unified + * interface for function call responses regardless of execution location. + */ +export interface AgentV1SendFunctionCallResponse { + /** Message type identifier for function call responses */ + type: "FunctionCallResponse"; + /** + * The unique identifier for the function call. + * + * • **Required for client responses**: Should match the id from + * the corresponding `FunctionCallRequest` + * • **Optional for server responses**: Server may omit when responding + * to internal function executions + */ + id?: string; + /** The name of the function being called */ + name: string; + /** The content or result of the function call */ + content: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1Settings.ts b/src/api/resources/agent/resources/v1/types/AgentV1Settings.ts new file mode 100644 index 00000000..e89a0afb --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1Settings.ts @@ -0,0 +1,277 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../index.js"; + +export interface AgentV1Settings { + type: "Settings"; + /** Tags to associate with the request */ + tags?: string[]; + /** To enable experimental features */ + experimental?: boolean; + flags?: AgentV1Settings.Flags; + /** To opt out of Deepgram Model Improvement Program */ + mip_opt_out?: boolean; + audio: AgentV1Settings.Audio; + agent: AgentV1Settings.Agent; +} + +export namespace AgentV1Settings { + export interface Flags { + /** Enable or disable history message reporting */ + history?: boolean; + } + + export interface Audio { + /** Audio input configuration settings. If omitted, defaults to encoding=linear16 and sample_rate=24000. Higher sample rates like 44100 Hz provide better audio quality. */ + input?: Audio.Input; + /** Audio output configuration settings */ + output?: Audio.Output; + } + + export namespace Audio { + /** + * Audio input configuration settings. If omitted, defaults to encoding=linear16 and sample_rate=24000. Higher sample rates like 44100 Hz provide better audio quality. + */ + export interface Input { + /** Audio encoding format */ + encoding: Input.Encoding; + /** Sample rate in Hz. Common values are 16000, 24000, 44100, 48000 */ + sample_rate: number; + } + + export namespace Input { + /** Audio encoding format */ + export const Encoding = { + Linear16: "linear16", + Linear32: "linear32", + Flac: "flac", + Alaw: "alaw", + Mulaw: "mulaw", + AmrNb: "amr-nb", + AmrWb: "amr-wb", + Opus: "opus", + OggOpus: "ogg-opus", + Speex: "speex", + G729: "g729", + } as const; + export type Encoding = (typeof Encoding)[keyof typeof Encoding]; + } + + /** + * Audio output configuration settings + */ + export interface Output { + /** Audio encoding format for streaming TTS output */ + encoding?: Output.Encoding; + /** Sample rate in Hz */ + sample_rate?: number; + /** Audio bitrate in bits per second */ + bitrate?: number; + /** Audio container format. If omitted, defaults to 'none' */ + container?: string; + } + + export namespace Output { + /** Audio encoding format for streaming TTS output */ + export const Encoding = { + Linear16: "linear16", + Mulaw: "mulaw", + Alaw: "alaw", + } as const; + export type Encoding = (typeof Encoding)[keyof typeof Encoding]; + } + } + + export interface Agent { + /** Agent language */ + language?: string; + /** Conversation context including the history of messages and function calls */ + context?: Agent.Context; + listen?: Agent.Listen; + think?: Agent.Think; + speak?: Agent.Speak; + /** Optional message that agent will speak at the start */ + greeting?: string; + } + + export namespace Agent { + /** + * Conversation context including the history of messages and function calls + */ + export interface Context { + /** Conversation history as a list of messages and function calls */ + messages?: Context.Messages.Item[]; + } + + export namespace Context { + export type Messages = Messages.Item[]; + + export namespace Messages { + /** + * A message here is either a conversational message or a function call + */ + export type Item = + /** + * Conversation text as part of the conversation history */ + | { + type: "History"; + role: "user" | "assistant"; + content: string; + } + /** + * Client-side or server-side function call request and response as part of the conversation history */ + | { + type: "History"; + function_calls: { + id: string; + name: string; + client_side: boolean; + arguments: string; + response: string; + }[]; + }; + } + } + + export interface Listen { + provider?: Listen.Provider; + } + + export namespace Listen { + export interface Provider { + /** Provider type for speech-to-text */ + type: "deepgram"; + /** Model to use for speech to text */ + model?: string; + /** Prompt key-term recognition (nova-3 'en' only) */ + keyterms?: string[]; + /** Applies smart formatting to improve transcript readability (Deepgram providers only) */ + smart_format?: boolean; + } + } + + export interface Think { + provider: Think.Provider; + /** Optional for non-Deepgram LLM providers. When present, must include url field and headers object */ + endpoint?: Think.Endpoint; + functions?: Think.Functions.Item[]; + prompt?: string; + /** Specifies the number of characters retained in context between user messages, agent responses, and function calls. This setting is only configurable when a custom think endpoint is used */ + context_length?: Think.ContextLength; + } + + export namespace Think { + export type Provider = + | { + type?: "open_ai" | undefined; + model?: + | ( + | "gpt-5" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "gpt-4o" + | "gpt-4o-mini" + ) + | undefined; + temperature?: number | undefined; + } + | { + type?: "aws_bedrock" | undefined; + model?: + | ("anthropic/claude-3-5-sonnet-20240620-v1:0" | "anthropic/claude-3-5-haiku-20240307-v1:0") + | undefined; + temperature?: number | undefined; + credentials?: + | { + type?: ("sts" | "iam") | undefined; + region?: string | undefined; + access_key_id?: string | undefined; + secret_access_key?: string | undefined; + session_token?: string | undefined; + } + | undefined; + } + | { + type?: "anthropic" | undefined; + model?: ("claude-3-5-haiku-latest" | "claude-sonnet-4-20250514") | undefined; + temperature?: number | undefined; + } + | { + type?: "google" | undefined; + model?: ("gemini-2.0-flash" | "gemini-2.0-flash-lite" | "gemini-2.5-flash") | undefined; + temperature?: number | undefined; + } + | { + type?: "groq" | undefined; + model?: "openai/gpt-oss-20b" | undefined; + temperature?: number | undefined; + }; + + /** + * Optional for non-Deepgram LLM providers. When present, must include url field and headers object + */ + export interface Endpoint { + /** Custom LLM endpoint URL */ + url?: string; + /** Custom headers for the endpoint */ + headers?: Record; + } + + export type Functions = Functions.Item[]; + + export namespace Functions { + export interface Item { + /** Function name */ + name?: string; + /** Function description */ + description?: string; + /** Function parameters */ + parameters?: Record; + /** The Function endpoint to call. if not passed, function is called client-side */ + endpoint?: Item.Endpoint; + } + + export namespace Item { + /** + * The Function endpoint to call. if not passed, function is called client-side + */ + export interface Endpoint { + /** Endpoint URL */ + url?: string; + /** HTTP method */ + method?: string; + headers?: Record; + } + } + } + + /** + * Specifies the number of characters retained in context between user messages, agent responses, and function calls. This setting is only configurable when a custom think endpoint is used + */ + export type ContextLength = "max" | number; + } + + export type Speak = + | { + provider: Deepgram.agent.AgentV1SettingsAgentSpeakEndpointProvider; + endpoint?: + | { + url?: string | undefined; + headers?: Record | undefined; + } + | undefined; + } + | { + provider: Deepgram.agent.AgentV1SettingsAgentSpeakOneItemProvider; + endpoint?: + | { + url?: string | undefined; + headers?: Record | undefined; + } + | undefined; + }[]; + } +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1SettingsAgentSpeakEndpointProvider.ts b/src/api/resources/agent/resources/v1/types/AgentV1SettingsAgentSpeakEndpointProvider.ts new file mode 100644 index 00000000..b824b6a3 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1SettingsAgentSpeakEndpointProvider.ts @@ -0,0 +1,207 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../index.js"; + +export type AgentV1SettingsAgentSpeakEndpointProvider = + | Deepgram.agent.AgentV1SettingsAgentSpeakEndpointProvider.Deepgram + | Deepgram.agent.AgentV1SettingsAgentSpeakEndpointProvider.ElevenLabs + | Deepgram.agent.AgentV1SettingsAgentSpeakEndpointProvider.Cartesia + | Deepgram.agent.AgentV1SettingsAgentSpeakEndpointProvider.OpenAi + | Deepgram.agent.AgentV1SettingsAgentSpeakEndpointProvider.AwsPolly; + +export namespace AgentV1SettingsAgentSpeakEndpointProvider { + export interface Deepgram { + type: "deepgram"; + /** Deepgram TTS model */ + model: AgentV1SettingsAgentSpeakEndpointProviderDeepgram.Model; + } + + export namespace AgentV1SettingsAgentSpeakEndpointProviderDeepgram { + /** Deepgram TTS model */ + export const Model = { + AuraAsteriaEn: "aura-asteria-en", + AuraLunaEn: "aura-luna-en", + AuraStellaEn: "aura-stella-en", + AuraAthenaEn: "aura-athena-en", + AuraHeraEn: "aura-hera-en", + AuraOrionEn: "aura-orion-en", + AuraArcasEn: "aura-arcas-en", + AuraPerseusEn: "aura-perseus-en", + AuraAngusEn: "aura-angus-en", + AuraOrpheusEn: "aura-orpheus-en", + AuraHeliosEn: "aura-helios-en", + AuraZeusEn: "aura-zeus-en", + Aura2AmaltheaEn: "aura-2-amalthea-en", + Aura2AndromedaEn: "aura-2-andromeda-en", + Aura2ApolloEn: "aura-2-apollo-en", + Aura2ArcasEn: "aura-2-arcas-en", + Aura2AriesEn: "aura-2-aries-en", + Aura2AsteriaEn: "aura-2-asteria-en", + Aura2AthenaEn: "aura-2-athena-en", + Aura2AtlasEn: "aura-2-atlas-en", + Aura2AuroraEn: "aura-2-aurora-en", + Aura2CallistaEn: "aura-2-callista-en", + Aura2CoraEn: "aura-2-cora-en", + Aura2CordeliaEn: "aura-2-cordelia-en", + Aura2DeliaEn: "aura-2-delia-en", + Aura2DracoEn: "aura-2-draco-en", + Aura2ElectraEn: "aura-2-electra-en", + Aura2HarmoniaEn: "aura-2-harmonia-en", + Aura2HelenaEn: "aura-2-helena-en", + Aura2HeraEn: "aura-2-hera-en", + Aura2HermesEn: "aura-2-hermes-en", + Aura2HyperionEn: "aura-2-hyperion-en", + Aura2IrisEn: "aura-2-iris-en", + Aura2JanusEn: "aura-2-janus-en", + Aura2JunoEn: "aura-2-juno-en", + Aura2JupiterEn: "aura-2-jupiter-en", + Aura2LunaEn: "aura-2-luna-en", + Aura2MarsEn: "aura-2-mars-en", + Aura2MinervaEn: "aura-2-minerva-en", + Aura2NeptuneEn: "aura-2-neptune-en", + Aura2OdysseusEn: "aura-2-odysseus-en", + Aura2OpheliaEn: "aura-2-ophelia-en", + Aura2OrionEn: "aura-2-orion-en", + Aura2OrpheusEn: "aura-2-orpheus-en", + Aura2PandoraEn: "aura-2-pandora-en", + Aura2PhoebeEn: "aura-2-phoebe-en", + Aura2PlutoEn: "aura-2-pluto-en", + Aura2SaturnEn: "aura-2-saturn-en", + Aura2SeleneEn: "aura-2-selene-en", + Aura2ThaliaEn: "aura-2-thalia-en", + Aura2TheiaEn: "aura-2-theia-en", + Aura2VestaEn: "aura-2-vesta-en", + Aura2ZeusEn: "aura-2-zeus-en", + Aura2SirioEs: "aura-2-sirio-es", + Aura2NestorEs: "aura-2-nestor-es", + Aura2CarinaEs: "aura-2-carina-es", + Aura2CelesteEs: "aura-2-celeste-es", + Aura2AlvaroEs: "aura-2-alvaro-es", + Aura2DianaEs: "aura-2-diana-es", + Aura2AquilaEs: "aura-2-aquila-es", + Aura2SelenaEs: "aura-2-selena-es", + Aura2EstrellaEs: "aura-2-estrella-es", + Aura2JavierEs: "aura-2-javier-es", + } as const; + export type Model = (typeof Model)[keyof typeof Model]; + } + + export interface ElevenLabs { + type: "eleven_labs"; + /** Eleven Labs model ID */ + model_id: AgentV1SettingsAgentSpeakEndpointProviderElevenLabs.ModelId; + /** Eleven Labs optional language code */ + language_code?: string; + } + + export namespace AgentV1SettingsAgentSpeakEndpointProviderElevenLabs { + /** Eleven Labs model ID */ + export const ModelId = { + ElevenTurboV25: "eleven_turbo_v2_5", + ElevenMonolingualV1: "eleven_monolingual_v1", + ElevenMultilingualV2: "eleven_multilingual_v2", + } as const; + export type ModelId = (typeof ModelId)[keyof typeof ModelId]; + } + + export interface Cartesia { + type: "cartesia"; + /** Cartesia model ID */ + model_id: AgentV1SettingsAgentSpeakEndpointProviderCartesia.ModelId; + voice: AgentV1SettingsAgentSpeakEndpointProviderCartesia.Voice; + /** Cartesia language code */ + language?: string; + } + + export namespace AgentV1SettingsAgentSpeakEndpointProviderCartesia { + /** Cartesia model ID */ + export const ModelId = { + Sonic2: "sonic-2", + SonicMultilingual: "sonic-multilingual", + } as const; + export type ModelId = (typeof ModelId)[keyof typeof ModelId]; + + export interface Voice { + /** Cartesia voice mode */ + mode: string; + /** Cartesia voice ID */ + id: string; + } + } + + export interface OpenAi { + type: "open_ai"; + /** OpenAI TTS model */ + model: AgentV1SettingsAgentSpeakEndpointProviderOpenAi.Model; + /** OpenAI voice */ + voice: AgentV1SettingsAgentSpeakEndpointProviderOpenAi.Voice; + } + + export namespace AgentV1SettingsAgentSpeakEndpointProviderOpenAi { + /** OpenAI TTS model */ + export const Model = { + Tts1: "tts-1", + Tts1Hd: "tts-1-hd", + } as const; + export type Model = (typeof Model)[keyof typeof Model]; + /** OpenAI voice */ + export const Voice = { + Alloy: "alloy", + Echo: "echo", + Fable: "fable", + Onyx: "onyx", + Nova: "nova", + Shimmer: "shimmer", + } as const; + export type Voice = (typeof Voice)[keyof typeof Voice]; + } + + export interface AwsPolly { + type: "aws_polly"; + /** AWS Polly voice name */ + voice: AgentV1SettingsAgentSpeakEndpointProviderAwsPolly.Voice; + /** Language code (e.g., "en-US") */ + language_code: string; + engine: AgentV1SettingsAgentSpeakEndpointProviderAwsPolly.Engine; + credentials: AgentV1SettingsAgentSpeakEndpointProviderAwsPolly.Credentials; + } + + export namespace AgentV1SettingsAgentSpeakEndpointProviderAwsPolly { + /** AWS Polly voice name */ + export const Voice = { + Matthew: "Matthew", + Joanna: "Joanna", + Amy: "Amy", + Emma: "Emma", + Brian: "Brian", + Arthur: "Arthur", + Aria: "Aria", + Ayanda: "Ayanda", + } as const; + export type Voice = (typeof Voice)[keyof typeof Voice]; + export const Engine = { + Generative: "generative", + LongForm: "long-form", + Standard: "standard", + Neural: "neural", + } as const; + export type Engine = (typeof Engine)[keyof typeof Engine]; + + export interface Credentials { + type: Credentials.Type; + region: string; + access_key_id: string; + secret_access_key: string; + /** Required for STS only */ + session_token?: string; + } + + export namespace Credentials { + export const Type = { + Sts: "sts", + Iam: "iam", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; + } + } +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1SettingsAgentSpeakOneItemProvider.ts b/src/api/resources/agent/resources/v1/types/AgentV1SettingsAgentSpeakOneItemProvider.ts new file mode 100644 index 00000000..9ebc5d5c --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1SettingsAgentSpeakOneItemProvider.ts @@ -0,0 +1,207 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../index.js"; + +export type AgentV1SettingsAgentSpeakOneItemProvider = + | Deepgram.agent.AgentV1SettingsAgentSpeakOneItemProvider.Deepgram + | Deepgram.agent.AgentV1SettingsAgentSpeakOneItemProvider.ElevenLabs + | Deepgram.agent.AgentV1SettingsAgentSpeakOneItemProvider.Cartesia + | Deepgram.agent.AgentV1SettingsAgentSpeakOneItemProvider.OpenAi + | Deepgram.agent.AgentV1SettingsAgentSpeakOneItemProvider.AwsPolly; + +export namespace AgentV1SettingsAgentSpeakOneItemProvider { + export interface Deepgram { + type: "deepgram"; + /** Deepgram TTS model */ + model: AgentV1SettingsAgentSpeakOneItemProviderDeepgram.Model; + } + + export namespace AgentV1SettingsAgentSpeakOneItemProviderDeepgram { + /** Deepgram TTS model */ + export const Model = { + AuraAsteriaEn: "aura-asteria-en", + AuraLunaEn: "aura-luna-en", + AuraStellaEn: "aura-stella-en", + AuraAthenaEn: "aura-athena-en", + AuraHeraEn: "aura-hera-en", + AuraOrionEn: "aura-orion-en", + AuraArcasEn: "aura-arcas-en", + AuraPerseusEn: "aura-perseus-en", + AuraAngusEn: "aura-angus-en", + AuraOrpheusEn: "aura-orpheus-en", + AuraHeliosEn: "aura-helios-en", + AuraZeusEn: "aura-zeus-en", + Aura2AmaltheaEn: "aura-2-amalthea-en", + Aura2AndromedaEn: "aura-2-andromeda-en", + Aura2ApolloEn: "aura-2-apollo-en", + Aura2ArcasEn: "aura-2-arcas-en", + Aura2AriesEn: "aura-2-aries-en", + Aura2AsteriaEn: "aura-2-asteria-en", + Aura2AthenaEn: "aura-2-athena-en", + Aura2AtlasEn: "aura-2-atlas-en", + Aura2AuroraEn: "aura-2-aurora-en", + Aura2CallistaEn: "aura-2-callista-en", + Aura2CoraEn: "aura-2-cora-en", + Aura2CordeliaEn: "aura-2-cordelia-en", + Aura2DeliaEn: "aura-2-delia-en", + Aura2DracoEn: "aura-2-draco-en", + Aura2ElectraEn: "aura-2-electra-en", + Aura2HarmoniaEn: "aura-2-harmonia-en", + Aura2HelenaEn: "aura-2-helena-en", + Aura2HeraEn: "aura-2-hera-en", + Aura2HermesEn: "aura-2-hermes-en", + Aura2HyperionEn: "aura-2-hyperion-en", + Aura2IrisEn: "aura-2-iris-en", + Aura2JanusEn: "aura-2-janus-en", + Aura2JunoEn: "aura-2-juno-en", + Aura2JupiterEn: "aura-2-jupiter-en", + Aura2LunaEn: "aura-2-luna-en", + Aura2MarsEn: "aura-2-mars-en", + Aura2MinervaEn: "aura-2-minerva-en", + Aura2NeptuneEn: "aura-2-neptune-en", + Aura2OdysseusEn: "aura-2-odysseus-en", + Aura2OpheliaEn: "aura-2-ophelia-en", + Aura2OrionEn: "aura-2-orion-en", + Aura2OrpheusEn: "aura-2-orpheus-en", + Aura2PandoraEn: "aura-2-pandora-en", + Aura2PhoebeEn: "aura-2-phoebe-en", + Aura2PlutoEn: "aura-2-pluto-en", + Aura2SaturnEn: "aura-2-saturn-en", + Aura2SeleneEn: "aura-2-selene-en", + Aura2ThaliaEn: "aura-2-thalia-en", + Aura2TheiaEn: "aura-2-theia-en", + Aura2VestaEn: "aura-2-vesta-en", + Aura2ZeusEn: "aura-2-zeus-en", + Aura2SirioEs: "aura-2-sirio-es", + Aura2NestorEs: "aura-2-nestor-es", + Aura2CarinaEs: "aura-2-carina-es", + Aura2CelesteEs: "aura-2-celeste-es", + Aura2AlvaroEs: "aura-2-alvaro-es", + Aura2DianaEs: "aura-2-diana-es", + Aura2AquilaEs: "aura-2-aquila-es", + Aura2SelenaEs: "aura-2-selena-es", + Aura2EstrellaEs: "aura-2-estrella-es", + Aura2JavierEs: "aura-2-javier-es", + } as const; + export type Model = (typeof Model)[keyof typeof Model]; + } + + export interface ElevenLabs { + type: "eleven_labs"; + /** Eleven Labs model ID */ + model_id: AgentV1SettingsAgentSpeakOneItemProviderElevenLabs.ModelId; + /** Eleven Labs optional language code */ + language_code?: string; + } + + export namespace AgentV1SettingsAgentSpeakOneItemProviderElevenLabs { + /** Eleven Labs model ID */ + export const ModelId = { + ElevenTurboV25: "eleven_turbo_v2_5", + ElevenMonolingualV1: "eleven_monolingual_v1", + ElevenMultilingualV2: "eleven_multilingual_v2", + } as const; + export type ModelId = (typeof ModelId)[keyof typeof ModelId]; + } + + export interface Cartesia { + type: "cartesia"; + /** Cartesia model ID */ + model_id: AgentV1SettingsAgentSpeakOneItemProviderCartesia.ModelId; + voice: AgentV1SettingsAgentSpeakOneItemProviderCartesia.Voice; + /** Cartesia language code */ + language?: string; + } + + export namespace AgentV1SettingsAgentSpeakOneItemProviderCartesia { + /** Cartesia model ID */ + export const ModelId = { + Sonic2: "sonic-2", + SonicMultilingual: "sonic-multilingual", + } as const; + export type ModelId = (typeof ModelId)[keyof typeof ModelId]; + + export interface Voice { + /** Cartesia voice mode */ + mode: string; + /** Cartesia voice ID */ + id: string; + } + } + + export interface OpenAi { + type: "open_ai"; + /** OpenAI TTS model */ + model: AgentV1SettingsAgentSpeakOneItemProviderOpenAi.Model; + /** OpenAI voice */ + voice: AgentV1SettingsAgentSpeakOneItemProviderOpenAi.Voice; + } + + export namespace AgentV1SettingsAgentSpeakOneItemProviderOpenAi { + /** OpenAI TTS model */ + export const Model = { + Tts1: "tts-1", + Tts1Hd: "tts-1-hd", + } as const; + export type Model = (typeof Model)[keyof typeof Model]; + /** OpenAI voice */ + export const Voice = { + Alloy: "alloy", + Echo: "echo", + Fable: "fable", + Onyx: "onyx", + Nova: "nova", + Shimmer: "shimmer", + } as const; + export type Voice = (typeof Voice)[keyof typeof Voice]; + } + + export interface AwsPolly { + type: "aws_polly"; + /** AWS Polly voice name */ + voice: AgentV1SettingsAgentSpeakOneItemProviderAwsPolly.Voice; + /** Language code (e.g., "en-US") */ + language_code: string; + engine: AgentV1SettingsAgentSpeakOneItemProviderAwsPolly.Engine; + credentials: AgentV1SettingsAgentSpeakOneItemProviderAwsPolly.Credentials; + } + + export namespace AgentV1SettingsAgentSpeakOneItemProviderAwsPolly { + /** AWS Polly voice name */ + export const Voice = { + Matthew: "Matthew", + Joanna: "Joanna", + Amy: "Amy", + Emma: "Emma", + Brian: "Brian", + Arthur: "Arthur", + Aria: "Aria", + Ayanda: "Ayanda", + } as const; + export type Voice = (typeof Voice)[keyof typeof Voice]; + export const Engine = { + Generative: "generative", + LongForm: "long-form", + Standard: "standard", + Neural: "neural", + } as const; + export type Engine = (typeof Engine)[keyof typeof Engine]; + + export interface Credentials { + type: Credentials.Type; + region: string; + access_key_id: string; + secret_access_key: string; + /** Required for STS only */ + session_token?: string; + } + + export namespace Credentials { + export const Type = { + Sts: "sts", + Iam: "iam", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; + } + } +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1SettingsApplied.ts b/src/api/resources/agent/resources/v1/types/AgentV1SettingsApplied.ts new file mode 100644 index 00000000..0784c379 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1SettingsApplied.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1SettingsApplied { + /** Message type identifier for settings applied confirmation */ + type: "SettingsApplied"; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1SpeakUpdated.ts b/src/api/resources/agent/resources/v1/types/AgentV1SpeakUpdated.ts new file mode 100644 index 00000000..d89590c2 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1SpeakUpdated.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1SpeakUpdated { + /** Message type identifier for speak update confirmation */ + type: "SpeakUpdated"; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1UpdatePrompt.ts b/src/api/resources/agent/resources/v1/types/AgentV1UpdatePrompt.ts new file mode 100644 index 00000000..c7f5f88f --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1UpdatePrompt.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1UpdatePrompt { + /** Message type identifier for prompt update request */ + type: "UpdatePrompt"; + /** The new system prompt to be used by the agent */ + prompt: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1UpdateSpeak.ts b/src/api/resources/agent/resources/v1/types/AgentV1UpdateSpeak.ts new file mode 100644 index 00000000..e25afda3 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1UpdateSpeak.ts @@ -0,0 +1,39 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../index.js"; + +export interface AgentV1UpdateSpeak { + /** Message type identifier for updating the speak model */ + type: "UpdateSpeak"; + /** Configuration for the speak model. Optional, defaults to latest deepgram TTS model */ + speak: AgentV1UpdateSpeak.Speak; +} + +export namespace AgentV1UpdateSpeak { + /** + * Configuration for the speak model. Optional, defaults to latest deepgram TTS model + */ + export interface Speak { + provider: Deepgram.agent.AgentV1UpdateSpeakSpeakProvider; + /** + * Optional if provider is Deepgram. Required for non-Deepgram TTS providers. + * When present, must include url field and headers object. Valid schemes are https and wss with wss only supported for Eleven Labs. + */ + endpoint?: Speak.Endpoint; + } + + export namespace Speak { + /** + * Optional if provider is Deepgram. Required for non-Deepgram TTS providers. + * When present, must include url field and headers object. Valid schemes are https and wss with wss only supported for Eleven Labs. + */ + export interface Endpoint { + /** + * Custom TTS endpoint URL. Cannot contain `output_format` or `model_id` query + * parameters when the provider is Eleven Labs. + */ + url?: string; + headers?: Record; + } + } +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1UpdateSpeakSpeakProvider.ts b/src/api/resources/agent/resources/v1/types/AgentV1UpdateSpeakSpeakProvider.ts new file mode 100644 index 00000000..c1ab8aac --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1UpdateSpeakSpeakProvider.ts @@ -0,0 +1,207 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../index.js"; + +export type AgentV1UpdateSpeakSpeakProvider = + | Deepgram.agent.AgentV1UpdateSpeakSpeakProvider.Deepgram + | Deepgram.agent.AgentV1UpdateSpeakSpeakProvider.ElevenLabs + | Deepgram.agent.AgentV1UpdateSpeakSpeakProvider.Cartesia + | Deepgram.agent.AgentV1UpdateSpeakSpeakProvider.OpenAi + | Deepgram.agent.AgentV1UpdateSpeakSpeakProvider.AwsPolly; + +export namespace AgentV1UpdateSpeakSpeakProvider { + export interface Deepgram { + type: "deepgram"; + /** Deepgram TTS model */ + model: AgentV1UpdateSpeakSpeakProviderDeepgram.Model; + } + + export namespace AgentV1UpdateSpeakSpeakProviderDeepgram { + /** Deepgram TTS model */ + export const Model = { + AuraAsteriaEn: "aura-asteria-en", + AuraLunaEn: "aura-luna-en", + AuraStellaEn: "aura-stella-en", + AuraAthenaEn: "aura-athena-en", + AuraHeraEn: "aura-hera-en", + AuraOrionEn: "aura-orion-en", + AuraArcasEn: "aura-arcas-en", + AuraPerseusEn: "aura-perseus-en", + AuraAngusEn: "aura-angus-en", + AuraOrpheusEn: "aura-orpheus-en", + AuraHeliosEn: "aura-helios-en", + AuraZeusEn: "aura-zeus-en", + Aura2AmaltheaEn: "aura-2-amalthea-en", + Aura2AndromedaEn: "aura-2-andromeda-en", + Aura2ApolloEn: "aura-2-apollo-en", + Aura2ArcasEn: "aura-2-arcas-en", + Aura2AriesEn: "aura-2-aries-en", + Aura2AsteriaEn: "aura-2-asteria-en", + Aura2AthenaEn: "aura-2-athena-en", + Aura2AtlasEn: "aura-2-atlas-en", + Aura2AuroraEn: "aura-2-aurora-en", + Aura2CallistaEn: "aura-2-callista-en", + Aura2CoraEn: "aura-2-cora-en", + Aura2CordeliaEn: "aura-2-cordelia-en", + Aura2DeliaEn: "aura-2-delia-en", + Aura2DracoEn: "aura-2-draco-en", + Aura2ElectraEn: "aura-2-electra-en", + Aura2HarmoniaEn: "aura-2-harmonia-en", + Aura2HelenaEn: "aura-2-helena-en", + Aura2HeraEn: "aura-2-hera-en", + Aura2HermesEn: "aura-2-hermes-en", + Aura2HyperionEn: "aura-2-hyperion-en", + Aura2IrisEn: "aura-2-iris-en", + Aura2JanusEn: "aura-2-janus-en", + Aura2JunoEn: "aura-2-juno-en", + Aura2JupiterEn: "aura-2-jupiter-en", + Aura2LunaEn: "aura-2-luna-en", + Aura2MarsEn: "aura-2-mars-en", + Aura2MinervaEn: "aura-2-minerva-en", + Aura2NeptuneEn: "aura-2-neptune-en", + Aura2OdysseusEn: "aura-2-odysseus-en", + Aura2OpheliaEn: "aura-2-ophelia-en", + Aura2OrionEn: "aura-2-orion-en", + Aura2OrpheusEn: "aura-2-orpheus-en", + Aura2PandoraEn: "aura-2-pandora-en", + Aura2PhoebeEn: "aura-2-phoebe-en", + Aura2PlutoEn: "aura-2-pluto-en", + Aura2SaturnEn: "aura-2-saturn-en", + Aura2SeleneEn: "aura-2-selene-en", + Aura2ThaliaEn: "aura-2-thalia-en", + Aura2TheiaEn: "aura-2-theia-en", + Aura2VestaEn: "aura-2-vesta-en", + Aura2ZeusEn: "aura-2-zeus-en", + Aura2SirioEs: "aura-2-sirio-es", + Aura2NestorEs: "aura-2-nestor-es", + Aura2CarinaEs: "aura-2-carina-es", + Aura2CelesteEs: "aura-2-celeste-es", + Aura2AlvaroEs: "aura-2-alvaro-es", + Aura2DianaEs: "aura-2-diana-es", + Aura2AquilaEs: "aura-2-aquila-es", + Aura2SelenaEs: "aura-2-selena-es", + Aura2EstrellaEs: "aura-2-estrella-es", + Aura2JavierEs: "aura-2-javier-es", + } as const; + export type Model = (typeof Model)[keyof typeof Model]; + } + + export interface ElevenLabs { + type: "eleven_labs"; + /** Eleven Labs model ID */ + model_id: AgentV1UpdateSpeakSpeakProviderElevenLabs.ModelId; + /** Eleven Labs optional language code */ + language_code?: string; + } + + export namespace AgentV1UpdateSpeakSpeakProviderElevenLabs { + /** Eleven Labs model ID */ + export const ModelId = { + ElevenTurboV25: "eleven_turbo_v2_5", + ElevenMonolingualV1: "eleven_monolingual_v1", + ElevenMultilingualV2: "eleven_multilingual_v2", + } as const; + export type ModelId = (typeof ModelId)[keyof typeof ModelId]; + } + + export interface Cartesia { + type: "cartesia"; + /** Cartesia model ID */ + model_id: AgentV1UpdateSpeakSpeakProviderCartesia.ModelId; + voice: AgentV1UpdateSpeakSpeakProviderCartesia.Voice; + /** Cartesia language code */ + language?: string; + } + + export namespace AgentV1UpdateSpeakSpeakProviderCartesia { + /** Cartesia model ID */ + export const ModelId = { + Sonic2: "sonic-2", + SonicMultilingual: "sonic-multilingual", + } as const; + export type ModelId = (typeof ModelId)[keyof typeof ModelId]; + + export interface Voice { + /** Cartesia voice mode */ + mode: string; + /** Cartesia voice ID */ + id: string; + } + } + + export interface OpenAi { + type: "open_ai"; + /** OpenAI TTS model */ + model: AgentV1UpdateSpeakSpeakProviderOpenAi.Model; + /** OpenAI voice */ + voice: AgentV1UpdateSpeakSpeakProviderOpenAi.Voice; + } + + export namespace AgentV1UpdateSpeakSpeakProviderOpenAi { + /** OpenAI TTS model */ + export const Model = { + Tts1: "tts-1", + Tts1Hd: "tts-1-hd", + } as const; + export type Model = (typeof Model)[keyof typeof Model]; + /** OpenAI voice */ + export const Voice = { + Alloy: "alloy", + Echo: "echo", + Fable: "fable", + Onyx: "onyx", + Nova: "nova", + Shimmer: "shimmer", + } as const; + export type Voice = (typeof Voice)[keyof typeof Voice]; + } + + export interface AwsPolly { + type: "aws_polly"; + /** AWS Polly voice name */ + voice: AgentV1UpdateSpeakSpeakProviderAwsPolly.Voice; + /** Language code (e.g., "en-US") */ + language_code: string; + engine: AgentV1UpdateSpeakSpeakProviderAwsPolly.Engine; + credentials: AgentV1UpdateSpeakSpeakProviderAwsPolly.Credentials; + } + + export namespace AgentV1UpdateSpeakSpeakProviderAwsPolly { + /** AWS Polly voice name */ + export const Voice = { + Matthew: "Matthew", + Joanna: "Joanna", + Amy: "Amy", + Emma: "Emma", + Brian: "Brian", + Arthur: "Arthur", + Aria: "Aria", + Ayanda: "Ayanda", + } as const; + export type Voice = (typeof Voice)[keyof typeof Voice]; + export const Engine = { + Generative: "generative", + LongForm: "long-form", + Standard: "standard", + Neural: "neural", + } as const; + export type Engine = (typeof Engine)[keyof typeof Engine]; + + export interface Credentials { + type: Credentials.Type; + region: string; + access_key_id: string; + secret_access_key: string; + /** Required for STS only */ + session_token?: string; + } + + export namespace Credentials { + export const Type = { + Sts: "sts", + Iam: "iam", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; + } + } +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1UserStartedSpeaking.ts b/src/api/resources/agent/resources/v1/types/AgentV1UserStartedSpeaking.ts new file mode 100644 index 00000000..7c466b63 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1UserStartedSpeaking.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1UserStartedSpeaking { + /** Message type identifier indicating that the user has begun speaking */ + type: "UserStartedSpeaking"; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1Warning.ts b/src/api/resources/agent/resources/v1/types/AgentV1Warning.ts new file mode 100644 index 00000000..9273daec --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1Warning.ts @@ -0,0 +1,13 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Notifies the client of non-fatal errors or warnings + */ +export interface AgentV1Warning { + /** Message type identifier for warnings */ + type: "Warning"; + /** Description of the warning */ + description: string; + /** Warning code identifier */ + code: string; +} diff --git a/src/api/resources/agent/resources/v1/types/AgentV1Welcome.ts b/src/api/resources/agent/resources/v1/types/AgentV1Welcome.ts new file mode 100644 index 00000000..899f4cc9 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/AgentV1Welcome.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentV1Welcome { + /** Message type identifier for welcome message */ + type: "Welcome"; + /** Unique identifier for the request */ + request_id: string; +} diff --git a/src/api/resources/agent/resources/v1/types/index.ts b/src/api/resources/agent/resources/v1/types/index.ts new file mode 100644 index 00000000..f04541b2 --- /dev/null +++ b/src/api/resources/agent/resources/v1/types/index.ts @@ -0,0 +1,24 @@ +export * from "./AgentV1AgentAudioDone.js"; +export * from "./AgentV1AgentStartedSpeaking.js"; +export * from "./AgentV1AgentThinking.js"; +export * from "./AgentV1ConversationText.js"; +export * from "./AgentV1Error.js"; +export * from "./AgentV1FunctionCallRequest.js"; +export * from "./AgentV1InjectAgentMessage.js"; +export * from "./AgentV1InjectionRefused.js"; +export * from "./AgentV1InjectUserMessage.js"; +export * from "./AgentV1KeepAlive.js"; +export * from "./AgentV1PromptUpdated.js"; +export * from "./AgentV1ReceiveFunctionCallResponse.js"; +export * from "./AgentV1SendFunctionCallResponse.js"; +export * from "./AgentV1Settings.js"; +export * from "./AgentV1SettingsAgentSpeakEndpointProvider.js"; +export * from "./AgentV1SettingsAgentSpeakOneItemProvider.js"; +export * from "./AgentV1SettingsApplied.js"; +export * from "./AgentV1SpeakUpdated.js"; +export * from "./AgentV1UpdatePrompt.js"; +export * from "./AgentV1UpdateSpeak.js"; +export * from "./AgentV1UpdateSpeakSpeakProvider.js"; +export * from "./AgentV1UserStartedSpeaking.js"; +export * from "./AgentV1Warning.js"; +export * from "./AgentV1Welcome.js"; diff --git a/src/api/resources/auth/client/Client.ts b/src/api/resources/auth/client/Client.ts new file mode 100644 index 00000000..78d032be --- /dev/null +++ b/src/api/resources/auth/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../BaseClient.js"; +import { V1Client } from "../resources/v1/client/Client.js"; + +export declare namespace AuthClient { + export interface Options extends BaseClientOptions {} +} + +export class AuthClient { + protected readonly _options: AuthClient.Options; + protected _v1: V1Client | undefined; + + constructor(options: AuthClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get v1(): V1Client { + return (this._v1 ??= new V1Client(this._options)); + } +} diff --git a/src/api/resources/auth/client/index.ts b/src/api/resources/auth/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/auth/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/auth/index.ts b/src/api/resources/auth/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/auth/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/auth/resources/index.ts b/src/api/resources/auth/resources/index.ts new file mode 100644 index 00000000..c6b56d24 --- /dev/null +++ b/src/api/resources/auth/resources/index.ts @@ -0,0 +1 @@ +export * as v1 from "./v1/index.js"; diff --git a/src/api/resources/auth/resources/v1/client/Client.ts b/src/api/resources/auth/resources/v1/client/Client.ts new file mode 100644 index 00000000..a9259f61 --- /dev/null +++ b/src/api/resources/auth/resources/v1/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../BaseClient.js"; +import { TokensClient } from "../resources/tokens/client/Client.js"; + +export declare namespace V1Client { + export interface Options extends BaseClientOptions {} +} + +export class V1Client { + protected readonly _options: V1Client.Options; + protected _tokens: TokensClient | undefined; + + constructor(options: V1Client.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get tokens(): TokensClient { + return (this._tokens ??= new TokensClient(this._options)); + } +} diff --git a/src/api/resources/auth/resources/v1/client/index.ts b/src/api/resources/auth/resources/v1/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/auth/resources/v1/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/auth/resources/v1/index.ts b/src/api/resources/auth/resources/v1/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/auth/resources/v1/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/auth/resources/v1/resources/index.ts b/src/api/resources/auth/resources/v1/resources/index.ts new file mode 100644 index 00000000..c6bd5167 --- /dev/null +++ b/src/api/resources/auth/resources/v1/resources/index.ts @@ -0,0 +1,2 @@ +export * from "./tokens/client/requests/index.js"; +export * as tokens from "./tokens/index.js"; diff --git a/src/api/resources/auth/resources/v1/resources/tokens/client/Client.ts b/src/api/resources/auth/resources/v1/resources/tokens/client/Client.ts new file mode 100644 index 00000000..6d913377 --- /dev/null +++ b/src/api/resources/auth/resources/v1/resources/tokens/client/Client.ts @@ -0,0 +1,110 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../index.js"; + +export declare namespace TokensClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class TokensClient { + protected readonly _options: TokensClient.Options; + + constructor(options: TokensClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Generates a temporary JSON Web Token (JWT) with a 30-second (by default) TTL and usage::write permission for core voice APIs, requiring an API key with Member or higher authorization. Tokens created with this endpoint will not work with the Manage APIs. + * + * @param {Deepgram.auth.v1.GrantV1Request} request + * @param {TokensClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.auth.v1.tokens.grant() + */ + public grant( + request: Deepgram.auth.v1.GrantV1Request = {}, + requestOptions?: TokensClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__grant(request, requestOptions)); + } + + private async __grant( + request: Deepgram.auth.v1.GrantV1Request = {}, + requestOptions?: TokensClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + "v1/auth/grant", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryParameters: requestOptions?.queryParams, + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.GrantV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling POST /v1/auth/grant."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/auth/resources/v1/resources/tokens/client/index.ts b/src/api/resources/auth/resources/v1/resources/tokens/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/auth/resources/v1/resources/tokens/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/auth/resources/v1/resources/tokens/client/requests/GrantV1Request.ts b/src/api/resources/auth/resources/v1/resources/tokens/client/requests/GrantV1Request.ts new file mode 100644 index 00000000..73881f69 --- /dev/null +++ b/src/api/resources/auth/resources/v1/resources/tokens/client/requests/GrantV1Request.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * {} + */ +export interface GrantV1Request { + /** Time to live in seconds for the token. Defaults to 30 seconds. */ + ttl_seconds?: number; +} diff --git a/src/api/resources/auth/resources/v1/resources/tokens/client/requests/index.ts b/src/api/resources/auth/resources/v1/resources/tokens/client/requests/index.ts new file mode 100644 index 00000000..40281c44 --- /dev/null +++ b/src/api/resources/auth/resources/v1/resources/tokens/client/requests/index.ts @@ -0,0 +1 @@ +export type { GrantV1Request } from "./GrantV1Request.js"; diff --git a/src/api/resources/auth/resources/v1/resources/tokens/index.ts b/src/api/resources/auth/resources/v1/resources/tokens/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/auth/resources/v1/resources/tokens/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/index.ts b/src/api/resources/index.ts new file mode 100644 index 00000000..3d31b15f --- /dev/null +++ b/src/api/resources/index.ts @@ -0,0 +1,7 @@ +export * as agent from "./agent/index.js"; +export * as auth from "./auth/index.js"; +export * as listen from "./listen/index.js"; +export * as manage from "./manage/index.js"; +export * as read from "./read/index.js"; +export * as selfHosted from "./selfHosted/index.js"; +export * as speak from "./speak/index.js"; diff --git a/src/api/resources/listen/client/Client.ts b/src/api/resources/listen/client/Client.ts new file mode 100644 index 00000000..f8814fc5 --- /dev/null +++ b/src/api/resources/listen/client/Client.ts @@ -0,0 +1,28 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../BaseClient.js"; +import { V1Client } from "../resources/v1/client/Client.js"; +import { V2Client } from "../resources/v2/client/Client.js"; + +export declare namespace ListenClient { + export interface Options extends BaseClientOptions {} +} + +export class ListenClient { + protected readonly _options: ListenClient.Options; + protected _v1: V1Client | undefined; + protected _v2: V2Client | undefined; + + constructor(options: ListenClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get v1(): V1Client { + return (this._v1 ??= new V1Client(this._options)); + } + + public get v2(): V2Client { + return (this._v2 ??= new V2Client(this._options)); + } +} diff --git a/src/api/resources/listen/client/index.ts b/src/api/resources/listen/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/listen/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/listen/index.ts b/src/api/resources/listen/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/listen/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/listen/resources/index.ts b/src/api/resources/listen/resources/index.ts new file mode 100644 index 00000000..c5abd973 --- /dev/null +++ b/src/api/resources/listen/resources/index.ts @@ -0,0 +1,4 @@ +export * as v1 from "./v1/index.js"; +export * from "./v1/types/index.js"; +export * as v2 from "./v2/index.js"; +export * from "./v2/types/index.js"; diff --git a/src/api/resources/listen/resources/v1/client/Client.ts b/src/api/resources/listen/resources/v1/client/Client.ts new file mode 100644 index 00000000..cf2ad87e --- /dev/null +++ b/src/api/resources/listen/resources/v1/client/Client.ts @@ -0,0 +1,231 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../core/headers.js"; +import * as core from "../../../../../../core/index.js"; +import * as environments from "../../../../../../environments.js"; +import { MediaClient } from "../resources/media/client/Client.js"; +import { V1Socket } from "./Socket.js"; + +export declare namespace V1Client { + export interface Options extends BaseClientOptions {} + + export interface ConnectArgs { + callback?: string | undefined; + callback_method?: string | undefined; + channels?: string | undefined; + diarize?: string | undefined; + dictation?: string | undefined; + encoding?: string | undefined; + endpointing?: string | undefined; + extra?: string | undefined; + interim_results?: string | undefined; + keyterm?: string | undefined; + keywords?: string | undefined; + language?: string | undefined; + mip_opt_out?: string | undefined; + model: string; + multichannel?: string | undefined; + numerals?: string | undefined; + profanity_filter?: string | undefined; + punctuate?: string | undefined; + redact?: string | undefined; + replace?: string | undefined; + sample_rate?: string | undefined; + search?: string | undefined; + smart_format?: string | undefined; + tag?: string | undefined; + utterance_end_ms?: string | undefined; + vad_events?: string | undefined; + version?: string | undefined; + Authorization: string; + /** Arbitrary headers to send with the websocket connect request. */ + headers?: Record; + /** Enable debug mode on the websocket. Defaults to false. */ + debug?: boolean; + /** Number of reconnect attempts. Defaults to 30. */ + reconnectAttempts?: number; + } +} + +export class V1Client { + protected readonly _options: V1Client.Options; + protected _media: MediaClient | undefined; + + constructor(options: V1Client.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get media(): MediaClient { + return (this._media ??= new MediaClient(this._options)); + } + + public async connect(args: V1Client.ConnectArgs): Promise { + const { + callback, + callback_method, + channels, + diarize, + dictation, + encoding, + endpointing, + extra, + interim_results, + keyterm, + keywords, + language, + mip_opt_out, + model, + multichannel, + numerals, + profanity_filter, + punctuate, + redact, + replace, + sample_rate, + search, + smart_format, + tag, + utterance_end_ms, + vad_events, + version, + headers, + debug, + reconnectAttempts, + } = args; + const _queryParams: Record = {}; + if (callback != null) { + _queryParams.callback = callback; + } + + if (callback_method != null) { + _queryParams.callback_method = callback_method; + } + + if (channels != null) { + _queryParams.channels = channels; + } + + if (diarize != null) { + _queryParams.diarize = diarize; + } + + if (dictation != null) { + _queryParams.dictation = dictation; + } + + if (encoding != null) { + _queryParams.encoding = encoding; + } + + if (endpointing != null) { + _queryParams.endpointing = endpointing; + } + + if (extra != null) { + _queryParams.extra = extra; + } + + if (interim_results != null) { + _queryParams.interim_results = interim_results; + } + + if (keyterm != null) { + _queryParams.keyterm = keyterm; + } + + if (keywords != null) { + _queryParams.keywords = keywords; + } + + if (language != null) { + _queryParams.language = language; + } + + if (mip_opt_out != null) { + _queryParams.mip_opt_out = mip_opt_out; + } + + _queryParams.model = model; + if (multichannel != null) { + _queryParams.multichannel = multichannel; + } + + if (numerals != null) { + _queryParams.numerals = numerals; + } + + if (profanity_filter != null) { + _queryParams.profanity_filter = profanity_filter; + } + + if (punctuate != null) { + _queryParams.punctuate = punctuate; + } + + if (redact != null) { + _queryParams.redact = redact; + } + + if (replace != null) { + _queryParams.replace = replace; + } + + if (sample_rate != null) { + _queryParams.sample_rate = sample_rate; + } + + if (search != null) { + _queryParams.search = search; + } + + if (smart_format != null) { + _queryParams.smart_format = smart_format; + } + + if (tag != null) { + _queryParams.tag = tag; + } + + if (utterance_end_ms != null) { + _queryParams.utterance_end_ms = utterance_end_ms; + } + + if (vad_events != null) { + _queryParams.vad_events = vad_events; + } + + if (version != null) { + _queryParams.version = version; + } + + const _headers: Record = mergeHeaders( + mergeOnlyDefinedHeaders({ + ...(await this._getCustomAuthorizationHeaders()), + Authorization: args.Authorization, + }), + headers, + ); + const socket = new core.ReconnectingWebSocket({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).production, + "/v1/listen", + ), + protocols: [], + queryParameters: _queryParams, + headers: _headers, + options: { debug: debug ?? false, maxRetries: reconnectAttempts ?? 30 }, + }); + return new V1Socket({ socket }); + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/listen/resources/v1/client/Socket.ts b/src/api/resources/listen/resources/v1/client/Socket.ts new file mode 100644 index 00000000..392d9182 --- /dev/null +++ b/src/api/resources/listen/resources/v1/client/Socket.ts @@ -0,0 +1,159 @@ +// This file was auto-generated by Fern from our API Definition. + +import * as core from "../../../../../../core/index.js"; +import { fromJson, toJson } from "../../../../../../core/json.js"; +import type * as Deepgram from "../../../../../index.js"; + +export declare namespace V1Socket { + export interface Args { + socket: core.ReconnectingWebSocket; + } + + export type Response = + | Deepgram.listen.ListenV1Results + | Deepgram.listen.ListenV1Metadata + | Deepgram.listen.ListenV1UtteranceEnd + | Deepgram.listen.ListenV1SpeechStarted; + type EventHandlers = { + open?: () => void; + message?: (message: Response) => void; + close?: (event: core.CloseEvent) => void; + error?: (error: Error) => void; + }; +} + +export class V1Socket { + public readonly socket: core.ReconnectingWebSocket; + protected readonly eventHandlers: V1Socket.EventHandlers = {}; + private handleOpen: () => void = () => { + this.eventHandlers.open?.(); + }; + private handleMessage: (event: { data: string }) => void = (event) => { + const data = fromJson(event.data); + + this.eventHandlers.message?.(data as V1Socket.Response); + }; + private handleClose: (event: core.CloseEvent) => void = (event) => { + this.eventHandlers.close?.(event); + }; + private handleError: (event: core.ErrorEvent) => void = (event) => { + const message = event.message; + this.eventHandlers.error?.(new Error(message)); + }; + + constructor(args: V1Socket.Args) { + this.socket = args.socket; + this.socket.addEventListener("open", this.handleOpen); + this.socket.addEventListener("message", this.handleMessage); + this.socket.addEventListener("close", this.handleClose); + this.socket.addEventListener("error", this.handleError); + } + + /** The current state of the connection; this is one of the readyState constants. */ + get readyState(): number { + return this.socket.readyState; + } + + /** + * @param event - The event to attach to. + * @param callback - The callback to run when the event is triggered. + * Usage: + * ```typescript + * this.on('open', () => { + * console.log('The websocket is open'); + * }); + * ``` + */ + public on(event: T, callback: V1Socket.EventHandlers[T]): void { + this.eventHandlers[event] = callback; + } + + public sendListenV1Media(message: string): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendListenV1Finalize(message: Deepgram.listen.ListenV1Finalize): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendListenV1CloseStream(message: Deepgram.listen.ListenV1CloseStream): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendListenV1KeepAlive(message: Deepgram.listen.ListenV1KeepAlive): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + /** Connect to the websocket and register event handlers. */ + public connect(): V1Socket { + this.socket.reconnect(); + + this.socket.addEventListener("open", this.handleOpen); + this.socket.addEventListener("message", this.handleMessage); + this.socket.addEventListener("close", this.handleClose); + this.socket.addEventListener("error", this.handleError); + + return this; + } + + /** Close the websocket and unregister event handlers. */ + public close(): void { + this.socket.close(); + + this.handleClose({ code: 1000 } as CloseEvent); + + this.socket.removeEventListener("open", this.handleOpen); + this.socket.removeEventListener("message", this.handleMessage); + this.socket.removeEventListener("close", this.handleClose); + this.socket.removeEventListener("error", this.handleError); + } + + /** Returns a promise that resolves when the websocket is open. */ + public async waitForOpen(): Promise { + if (this.socket.readyState === core.ReconnectingWebSocket.OPEN) { + return this.socket; + } + + return new Promise((resolve, reject) => { + this.socket.addEventListener("open", () => { + resolve(this.socket); + }); + + this.socket.addEventListener("error", (event: unknown) => { + reject(event); + }); + }); + } + + /** Asserts that the websocket is open. */ + private assertSocketIsOpen(): void { + if (!this.socket) { + throw new Error("Socket is not connected."); + } + + if (this.socket.readyState !== core.ReconnectingWebSocket.OPEN) { + throw new Error("Socket is not open."); + } + } + + /** Send a binary payload to the websocket. */ + protected sendBinary(payload: ArrayBufferLike | Blob | ArrayBufferView): void { + this.socket.send(payload); + } + + /** Send a JSON payload to the websocket. */ + protected sendJson( + payload: + | string + | Deepgram.listen.ListenV1Finalize + | Deepgram.listen.ListenV1CloseStream + | Deepgram.listen.ListenV1KeepAlive, + ): void { + const jsonPayload = toJson(payload); + this.socket.send(jsonPayload); + } +} diff --git a/src/api/resources/listen/resources/v1/client/index.ts b/src/api/resources/listen/resources/v1/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/listen/resources/v1/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/listen/resources/v1/index.ts b/src/api/resources/listen/resources/v1/index.ts new file mode 100644 index 00000000..0ef16e76 --- /dev/null +++ b/src/api/resources/listen/resources/v1/index.ts @@ -0,0 +1,3 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/listen/resources/v1/resources/index.ts b/src/api/resources/listen/resources/v1/resources/index.ts new file mode 100644 index 00000000..4e08efd8 --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/index.ts @@ -0,0 +1,3 @@ +export * from "./media/client/requests/index.js"; +export * as media from "./media/index.js"; +export * from "./media/types/index.js"; diff --git a/src/api/resources/listen/resources/v1/resources/media/client/Client.ts b/src/api/resources/listen/resources/v1/resources/media/client/Client.ts new file mode 100644 index 00000000..7eb7299b --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/client/Client.ts @@ -0,0 +1,635 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../index.js"; + +export declare namespace MediaClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class MediaClient { + protected readonly _options: MediaClient.Options; + + constructor(options: MediaClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Transcribe audio and video using Deepgram's speech-to-text REST API + * + * @param {Deepgram.listen.v1.ListenV1RequestUrl} request + * @param {MediaClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.listen.v1.media.transcribeUrl({ + * callback: "callback", + * callback_method: "POST", + * extra: "extra", + * sentiment: true, + * summarize: "v2", + * tag: "tag", + * topics: true, + * custom_topic: "custom_topic", + * custom_topic_mode: "extended", + * intents: true, + * custom_intent: "custom_intent", + * custom_intent_mode: "extended", + * detect_entities: true, + * detect_language: true, + * diarize: true, + * dictation: true, + * encoding: "linear16", + * filler_words: true, + * keywords: "keywords", + * language: "language", + * measurements: true, + * model: "nova-3", + * multichannel: true, + * numerals: true, + * paragraphs: true, + * profanity_filter: true, + * punctuate: true, + * redact: "redact", + * replace: "replace", + * search: "search", + * smart_format: true, + * utterances: true, + * utt_split: 1.1, + * version: "latest", + * mip_opt_out: true, + * url: "https://dpgr.am/spacewalk.wav" + * }) + */ + public transcribeUrl( + request: Deepgram.listen.v1.ListenV1RequestUrl, + requestOptions?: MediaClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__transcribeUrl(request, requestOptions)); + } + + private async __transcribeUrl( + request: Deepgram.listen.v1.ListenV1RequestUrl, + requestOptions?: MediaClient.RequestOptions, + ): Promise> { + const { + callback, + callback_method: callbackMethod, + extra, + sentiment, + summarize, + tag, + topics, + custom_topic: customTopic, + custom_topic_mode: customTopicMode, + intents, + custom_intent: customIntent, + custom_intent_mode: customIntentMode, + detect_entities: detectEntities, + detect_language: detectLanguage, + diarize, + dictation, + encoding, + filler_words: fillerWords, + keyterm, + keywords, + language, + measurements, + model, + multichannel, + numerals, + paragraphs, + profanity_filter: profanityFilter, + punctuate, + redact, + replace, + search, + smart_format: smartFormat, + utterances, + utt_split: uttSplit, + version, + mip_opt_out: mipOptOut, + ..._body + } = request; + const _queryParams: Record = {}; + if (callback != null) { + _queryParams.callback = callback; + } + + if (callbackMethod != null) { + _queryParams.callback_method = callbackMethod; + } + + if (extra != null) { + if (Array.isArray(extra)) { + _queryParams.extra = extra.map((item) => item); + } else { + _queryParams.extra = extra; + } + } + + if (sentiment != null) { + _queryParams.sentiment = sentiment.toString(); + } + + if (summarize != null) { + _queryParams.summarize = summarize; + } + + if (tag != null) { + if (Array.isArray(tag)) { + _queryParams.tag = tag.map((item) => item); + } else { + _queryParams.tag = tag; + } + } + + if (topics != null) { + _queryParams.topics = topics.toString(); + } + + if (customTopic != null) { + if (Array.isArray(customTopic)) { + _queryParams.custom_topic = customTopic.map((item) => item); + } else { + _queryParams.custom_topic = customTopic; + } + } + + if (customTopicMode != null) { + _queryParams.custom_topic_mode = customTopicMode; + } + + if (intents != null) { + _queryParams.intents = intents.toString(); + } + + if (customIntent != null) { + if (Array.isArray(customIntent)) { + _queryParams.custom_intent = customIntent.map((item) => item); + } else { + _queryParams.custom_intent = customIntent; + } + } + + if (customIntentMode != null) { + _queryParams.custom_intent_mode = customIntentMode; + } + + if (detectEntities != null) { + _queryParams.detect_entities = detectEntities.toString(); + } + + if (detectLanguage != null) { + _queryParams.detect_language = detectLanguage.toString(); + } + + if (diarize != null) { + _queryParams.diarize = diarize.toString(); + } + + if (dictation != null) { + _queryParams.dictation = dictation.toString(); + } + + if (encoding != null) { + _queryParams.encoding = encoding; + } + + if (fillerWords != null) { + _queryParams.filler_words = fillerWords.toString(); + } + + if (keyterm != null) { + if (Array.isArray(keyterm)) { + _queryParams.keyterm = keyterm.map((item) => item); + } else { + _queryParams.keyterm = keyterm; + } + } + + if (keywords != null) { + if (Array.isArray(keywords)) { + _queryParams.keywords = keywords.map((item) => item); + } else { + _queryParams.keywords = keywords; + } + } + + if (language != null) { + _queryParams.language = language; + } + + if (measurements != null) { + _queryParams.measurements = measurements.toString(); + } + + if (model != null) { + _queryParams.model = model; + } + + if (multichannel != null) { + _queryParams.multichannel = multichannel.toString(); + } + + if (numerals != null) { + _queryParams.numerals = numerals.toString(); + } + + if (paragraphs != null) { + _queryParams.paragraphs = paragraphs.toString(); + } + + if (profanityFilter != null) { + _queryParams.profanity_filter = profanityFilter.toString(); + } + + if (punctuate != null) { + _queryParams.punctuate = punctuate.toString(); + } + + if (redact != null) { + _queryParams.redact = redact; + } + + if (replace != null) { + if (Array.isArray(replace)) { + _queryParams.replace = replace.map((item) => item); + } else { + _queryParams.replace = replace; + } + } + + if (search != null) { + if (Array.isArray(search)) { + _queryParams.search = search.map((item) => item); + } else { + _queryParams.search = search; + } + } + + if (smartFormat != null) { + _queryParams.smart_format = smartFormat.toString(); + } + + if (utterances != null) { + _queryParams.utterances = utterances.toString(); + } + + if (uttSplit != null) { + _queryParams.utt_split = uttSplit.toString(); + } + + if (version != null) { + _queryParams.version = version; + } + + if (mipOptOut != null) { + _queryParams.mip_opt_out = mipOptOut.toString(); + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + "v1/listen", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + requestType: "json", + body: _body, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.listen.v1.MediaTranscribeResponse, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling POST /v1/listen."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Transcribe audio and video using Deepgram's speech-to-text REST API + * + * @param {core.file.Uploadable} uploadable + * @param {Deepgram.listen.v1.MediaTranscribeRequestOctetStream} request + * @param {MediaClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * import { createReadStream } from "fs"; + * await client.listen.v1.media.transcribeFile(createReadStream("path/to/file"), {}) + */ + public transcribeFile( + uploadable: core.file.Uploadable, + request: Deepgram.listen.v1.MediaTranscribeRequestOctetStream, + requestOptions?: MediaClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__transcribeFile(uploadable, request, requestOptions)); + } + + private async __transcribeFile( + uploadable: core.file.Uploadable, + request: Deepgram.listen.v1.MediaTranscribeRequestOctetStream, + requestOptions?: MediaClient.RequestOptions, + ): Promise> { + const _queryParams: Record = {}; + if (request.callback != null) { + _queryParams.callback = request.callback; + } + + if (request.callback_method != null) { + _queryParams.callback_method = request.callback_method; + } + + if (request.extra != null) { + if (Array.isArray(request.extra)) { + _queryParams.extra = request.extra.map((item) => item); + } else { + _queryParams.extra = request.extra; + } + } + + if (request.sentiment != null) { + _queryParams.sentiment = request.sentiment.toString(); + } + + if (request.summarize != null) { + _queryParams.summarize = request.summarize; + } + + if (request.tag != null) { + if (Array.isArray(request.tag)) { + _queryParams.tag = request.tag.map((item) => item); + } else { + _queryParams.tag = request.tag; + } + } + + if (request.topics != null) { + _queryParams.topics = request.topics.toString(); + } + + if (request.custom_topic != null) { + if (Array.isArray(request.custom_topic)) { + _queryParams.custom_topic = request.custom_topic.map((item) => item); + } else { + _queryParams.custom_topic = request.custom_topic; + } + } + + if (request.custom_topic_mode != null) { + _queryParams.custom_topic_mode = request.custom_topic_mode; + } + + if (request.intents != null) { + _queryParams.intents = request.intents.toString(); + } + + if (request.custom_intent != null) { + if (Array.isArray(request.custom_intent)) { + _queryParams.custom_intent = request.custom_intent.map((item) => item); + } else { + _queryParams.custom_intent = request.custom_intent; + } + } + + if (request.custom_intent_mode != null) { + _queryParams.custom_intent_mode = request.custom_intent_mode; + } + + if (request.detect_entities != null) { + _queryParams.detect_entities = request.detect_entities.toString(); + } + + if (request.detect_language != null) { + _queryParams.detect_language = request.detect_language.toString(); + } + + if (request.diarize != null) { + _queryParams.diarize = request.diarize.toString(); + } + + if (request.dictation != null) { + _queryParams.dictation = request.dictation.toString(); + } + + if (request.encoding != null) { + _queryParams.encoding = request.encoding; + } + + if (request.filler_words != null) { + _queryParams.filler_words = request.filler_words.toString(); + } + + if (request.keyterm != null) { + if (Array.isArray(request.keyterm)) { + _queryParams.keyterm = request.keyterm.map((item) => item); + } else { + _queryParams.keyterm = request.keyterm; + } + } + + if (request.keywords != null) { + if (Array.isArray(request.keywords)) { + _queryParams.keywords = request.keywords.map((item) => item); + } else { + _queryParams.keywords = request.keywords; + } + } + + if (request.language != null) { + _queryParams.language = request.language; + } + + if (request.measurements != null) { + _queryParams.measurements = request.measurements.toString(); + } + + if (request.model != null) { + _queryParams.model = request.model; + } + + if (request.multichannel != null) { + _queryParams.multichannel = request.multichannel.toString(); + } + + if (request.numerals != null) { + _queryParams.numerals = request.numerals.toString(); + } + + if (request.paragraphs != null) { + _queryParams.paragraphs = request.paragraphs.toString(); + } + + if (request.profanity_filter != null) { + _queryParams.profanity_filter = request.profanity_filter.toString(); + } + + if (request.punctuate != null) { + _queryParams.punctuate = request.punctuate.toString(); + } + + if (request.redact != null) { + _queryParams.redact = request.redact; + } + + if (request.replace != null) { + if (Array.isArray(request.replace)) { + _queryParams.replace = request.replace.map((item) => item); + } else { + _queryParams.replace = request.replace; + } + } + + if (request.search != null) { + if (Array.isArray(request.search)) { + _queryParams.search = request.search.map((item) => item); + } else { + _queryParams.search = request.search; + } + } + + if (request.smart_format != null) { + _queryParams.smart_format = request.smart_format.toString(); + } + + if (request.utterances != null) { + _queryParams.utterances = request.utterances.toString(); + } + + if (request.utt_split != null) { + _queryParams.utt_split = request.utt_split.toString(); + } + + if (request.version != null) { + _queryParams.version = request.version; + } + + if (request.mip_opt_out != null) { + _queryParams.mip_opt_out = request.mip_opt_out.toString(); + } + + const _binaryUploadRequest = await core.file.toBinaryUploadRequest(uploadable); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + _binaryUploadRequest.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + "v1/listen", + ), + method: "POST", + headers: _headers, + contentType: "application/octet-stream", + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + requestType: "bytes", + duplex: "half", + body: _binaryUploadRequest.body, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.listen.v1.MediaTranscribeResponse, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling POST /v1/listen."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/listen/resources/v1/resources/media/client/index.ts b/src/api/resources/listen/resources/v1/resources/media/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/listen/resources/v1/resources/media/client/requests/ListenV1RequestUrl.ts b/src/api/resources/listen/resources/v1/resources/media/client/requests/ListenV1RequestUrl.ts new file mode 100644 index 00000000..b48547fa --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/client/requests/ListenV1RequestUrl.ts @@ -0,0 +1,120 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../index.js"; + +/** + * @example + * { + * callback: "callback", + * callback_method: "POST", + * extra: "extra", + * sentiment: true, + * summarize: "v2", + * tag: "tag", + * topics: true, + * custom_topic: "custom_topic", + * custom_topic_mode: "extended", + * intents: true, + * custom_intent: "custom_intent", + * custom_intent_mode: "extended", + * detect_entities: true, + * detect_language: true, + * diarize: true, + * dictation: true, + * encoding: "linear16", + * filler_words: true, + * keywords: "keywords", + * language: "language", + * measurements: true, + * model: "nova-3", + * multichannel: true, + * numerals: true, + * paragraphs: true, + * profanity_filter: true, + * punctuate: true, + * redact: "redact", + * replace: "replace", + * search: "search", + * smart_format: true, + * utterances: true, + * utt_split: 1.1, + * version: "latest", + * mip_opt_out: true, + * url: "https://dpgr.am/spacewalk.wav" + * } + */ +export interface ListenV1RequestUrl { + /** URL to which we'll make the callback request */ + callback?: string; + /** HTTP method by which the callback request will be made */ + callback_method?: Deepgram.listen.v1.MediaTranscribeRequestCallbackMethod; + /** Arbitrary key-value pairs that are attached to the API response for usage in downstream processing */ + extra?: string | string[]; + /** Recognizes the sentiment throughout a transcript or text */ + sentiment?: boolean; + /** Summarize content. For Listen API, supports string version option. For Read API, accepts boolean only. */ + summarize?: Deepgram.listen.v1.MediaTranscribeRequestSummarize; + /** Label your requests for the purpose of identification during usage reporting */ + tag?: string | string[]; + /** Detect topics throughout a transcript or text */ + topics?: boolean; + /** Custom topics you want the model to detect within your input audio or text if present Submit up to `100`. */ + custom_topic?: string | string[]; + /** Sets how the model will interpret strings submitted to the `custom_topic` param. When `strict`, the model will only return topics submitted using the `custom_topic` param. When `extended`, the model will return its own detected topics in addition to those submitted using the `custom_topic` param */ + custom_topic_mode?: Deepgram.listen.v1.MediaTranscribeRequestCustomTopicMode; + /** Recognizes speaker intent throughout a transcript or text */ + intents?: boolean; + /** Custom intents you want the model to detect within your input audio if present */ + custom_intent?: string | string[]; + /** Sets how the model will interpret intents submitted to the `custom_intent` param. When `strict`, the model will only return intents submitted using the `custom_intent` param. When `extended`, the model will return its own detected intents in the `custom_intent` param. */ + custom_intent_mode?: Deepgram.listen.v1.MediaTranscribeRequestCustomIntentMode; + /** Identifies and extracts key entities from content in submitted audio */ + detect_entities?: boolean; + /** Identifies the dominant language spoken in submitted audio */ + detect_language?: boolean; + /** Recognize speaker changes. Each word in the transcript will be assigned a speaker number starting at 0 */ + diarize?: boolean; + /** Dictation mode for controlling formatting with dictated speech */ + dictation?: boolean; + /** Specify the expected encoding of your submitted audio */ + encoding?: Deepgram.listen.v1.MediaTranscribeRequestEncoding; + /** Filler Words can help transcribe interruptions in your audio, like "uh" and "um" */ + filler_words?: boolean; + /** Key term prompting can boost or suppress specialized terminology and brands. Only compatible with Nova-3 */ + keyterm?: string | string[]; + /** Keywords can boost or suppress specialized terminology and brands */ + keywords?: string | string[]; + /** The [BCP-47 language tag](https://tools.ietf.org/html/bcp47) that hints at the primary spoken language. Depending on the Model and API endpoint you choose only certain languages are available */ + language?: string; + /** Spoken measurements will be converted to their corresponding abbreviations */ + measurements?: boolean; + /** AI model used to process submitted audio */ + model?: Deepgram.listen.v1.MediaTranscribeRequestModel; + /** Transcribe each audio channel independently */ + multichannel?: boolean; + /** Numerals converts numbers from written format to numerical format */ + numerals?: boolean; + /** Splits audio into paragraphs to improve transcript readability */ + paragraphs?: boolean; + /** Profanity Filter looks for recognized profanity and converts it to the nearest recognized non-profane word or removes it from the transcript completely */ + profanity_filter?: boolean; + /** Add punctuation and capitalization to the transcript */ + punctuate?: boolean; + /** Redaction removes sensitive information from your transcripts */ + redact?: string; + /** Search for terms or phrases in submitted audio and replaces them */ + replace?: string | string[]; + /** Search for terms or phrases in submitted audio */ + search?: string | string[]; + /** Apply formatting to transcript output. When set to true, additional formatting will be applied to transcripts to improve readability */ + smart_format?: boolean; + /** Segments speech into meaningful semantic units */ + utterances?: boolean; + /** Seconds to wait before detecting a pause between words in submitted audio */ + utt_split?: number; + /** Version of an AI model to use */ + version?: Deepgram.listen.v1.MediaTranscribeRequestVersion; + /** Opts out requests from the Deepgram Model Improvement Program. Refer to our Docs for pricing impacts before setting this to true. https://dpgr.am/deepgram-mip */ + mip_opt_out?: boolean; + url: string; +} diff --git a/src/api/resources/listen/resources/v1/resources/media/client/requests/MediaTranscribeRequestOctetStream.ts b/src/api/resources/listen/resources/v1/resources/media/client/requests/MediaTranscribeRequestOctetStream.ts new file mode 100644 index 00000000..d7025478 --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/client/requests/MediaTranscribeRequestOctetStream.ts @@ -0,0 +1,85 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../index.js"; + +/** + * @example + * {} + * + * @example + * {} + */ +export interface MediaTranscribeRequestOctetStream { + /** URL to which we'll make the callback request */ + callback?: string; + /** HTTP method by which the callback request will be made */ + callback_method?: Deepgram.listen.v1.MediaTranscribeRequestCallbackMethod; + /** Arbitrary key-value pairs that are attached to the API response for usage in downstream processing */ + extra?: string | string[]; + /** Recognizes the sentiment throughout a transcript or text */ + sentiment?: boolean; + /** Summarize content. For Listen API, supports string version option. For Read API, accepts boolean only. */ + summarize?: Deepgram.listen.v1.MediaTranscribeRequestSummarize; + /** Label your requests for the purpose of identification during usage reporting */ + tag?: string | string[]; + /** Detect topics throughout a transcript or text */ + topics?: boolean; + /** Custom topics you want the model to detect within your input audio or text if present Submit up to `100`. */ + custom_topic?: string | string[]; + /** Sets how the model will interpret strings submitted to the `custom_topic` param. When `strict`, the model will only return topics submitted using the `custom_topic` param. When `extended`, the model will return its own detected topics in addition to those submitted using the `custom_topic` param */ + custom_topic_mode?: Deepgram.listen.v1.MediaTranscribeRequestCustomTopicMode; + /** Recognizes speaker intent throughout a transcript or text */ + intents?: boolean; + /** Custom intents you want the model to detect within your input audio if present */ + custom_intent?: string | string[]; + /** Sets how the model will interpret intents submitted to the `custom_intent` param. When `strict`, the model will only return intents submitted using the `custom_intent` param. When `extended`, the model will return its own detected intents in the `custom_intent` param. */ + custom_intent_mode?: Deepgram.listen.v1.MediaTranscribeRequestCustomIntentMode; + /** Identifies and extracts key entities from content in submitted audio */ + detect_entities?: boolean; + /** Identifies the dominant language spoken in submitted audio */ + detect_language?: boolean; + /** Recognize speaker changes. Each word in the transcript will be assigned a speaker number starting at 0 */ + diarize?: boolean; + /** Dictation mode for controlling formatting with dictated speech */ + dictation?: boolean; + /** Specify the expected encoding of your submitted audio */ + encoding?: Deepgram.listen.v1.MediaTranscribeRequestEncoding; + /** Filler Words can help transcribe interruptions in your audio, like "uh" and "um" */ + filler_words?: boolean; + /** Key term prompting can boost or suppress specialized terminology and brands. Only compatible with Nova-3 */ + keyterm?: string | string[]; + /** Keywords can boost or suppress specialized terminology and brands */ + keywords?: string | string[]; + /** The [BCP-47 language tag](https://tools.ietf.org/html/bcp47) that hints at the primary spoken language. Depending on the Model and API endpoint you choose only certain languages are available */ + language?: string; + /** Spoken measurements will be converted to their corresponding abbreviations */ + measurements?: boolean; + /** AI model used to process submitted audio */ + model?: Deepgram.listen.v1.MediaTranscribeRequestModel; + /** Transcribe each audio channel independently */ + multichannel?: boolean; + /** Numerals converts numbers from written format to numerical format */ + numerals?: boolean; + /** Splits audio into paragraphs to improve transcript readability */ + paragraphs?: boolean; + /** Profanity Filter looks for recognized profanity and converts it to the nearest recognized non-profane word or removes it from the transcript completely */ + profanity_filter?: boolean; + /** Add punctuation and capitalization to the transcript */ + punctuate?: boolean; + /** Redaction removes sensitive information from your transcripts */ + redact?: string; + /** Search for terms or phrases in submitted audio and replaces them */ + replace?: string | string[]; + /** Search for terms or phrases in submitted audio */ + search?: string | string[]; + /** Apply formatting to transcript output. When set to true, additional formatting will be applied to transcripts to improve readability */ + smart_format?: boolean; + /** Segments speech into meaningful semantic units */ + utterances?: boolean; + /** Seconds to wait before detecting a pause between words in submitted audio */ + utt_split?: number; + /** Version of an AI model to use */ + version?: Deepgram.listen.v1.MediaTranscribeRequestVersion; + /** Opts out requests from the Deepgram Model Improvement Program. Refer to our Docs for pricing impacts before setting this to true. https://dpgr.am/deepgram-mip */ + mip_opt_out?: boolean; +} diff --git a/src/api/resources/listen/resources/v1/resources/media/client/requests/index.ts b/src/api/resources/listen/resources/v1/resources/media/client/requests/index.ts new file mode 100644 index 00000000..da3f43d5 --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/client/requests/index.ts @@ -0,0 +1,2 @@ +export type { ListenV1RequestUrl } from "./ListenV1RequestUrl.js"; +export type { MediaTranscribeRequestOctetStream } from "./MediaTranscribeRequestOctetStream.js"; diff --git a/src/api/resources/listen/resources/v1/resources/media/index.ts b/src/api/resources/listen/resources/v1/resources/media/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCallbackMethod.ts b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCallbackMethod.ts new file mode 100644 index 00000000..7948f223 --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCallbackMethod.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const MediaTranscribeRequestCallbackMethod = { + Post: "POST", + Put: "PUT", +} as const; +export type MediaTranscribeRequestCallbackMethod = + (typeof MediaTranscribeRequestCallbackMethod)[keyof typeof MediaTranscribeRequestCallbackMethod]; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCustomIntentMode.ts b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCustomIntentMode.ts new file mode 100644 index 00000000..4ccfdd3d --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCustomIntentMode.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const MediaTranscribeRequestCustomIntentMode = { + Extended: "extended", + Strict: "strict", +} as const; +export type MediaTranscribeRequestCustomIntentMode = + (typeof MediaTranscribeRequestCustomIntentMode)[keyof typeof MediaTranscribeRequestCustomIntentMode]; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCustomTopicMode.ts b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCustomTopicMode.ts new file mode 100644 index 00000000..114a063a --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestCustomTopicMode.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const MediaTranscribeRequestCustomTopicMode = { + Extended: "extended", + Strict: "strict", +} as const; +export type MediaTranscribeRequestCustomTopicMode = + (typeof MediaTranscribeRequestCustomTopicMode)[keyof typeof MediaTranscribeRequestCustomTopicMode]; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestEncoding.ts b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestEncoding.ts new file mode 100644 index 00000000..2d228b6d --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestEncoding.ts @@ -0,0 +1,14 @@ +// This file was auto-generated by Fern from our API Definition. + +export const MediaTranscribeRequestEncoding = { + Linear16: "linear16", + Flac: "flac", + Mulaw: "mulaw", + AmrNb: "amr-nb", + AmrWb: "amr-wb", + Opus: "opus", + Speex: "speex", + G729: "g729", +} as const; +export type MediaTranscribeRequestEncoding = + (typeof MediaTranscribeRequestEncoding)[keyof typeof MediaTranscribeRequestEncoding]; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestModel.ts b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestModel.ts new file mode 100644 index 00000000..dc5eee97 --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestModel.ts @@ -0,0 +1,35 @@ +// This file was auto-generated by Fern from our API Definition. + +export const MediaTranscribeRequestModel = { + Nova3: "nova-3", + Nova3General: "nova-3-general", + Nova3Medical: "nova-3-medical", + Nova2: "nova-2", + Nova2General: "nova-2-general", + Nova2Meeting: "nova-2-meeting", + Nova2Finance: "nova-2-finance", + Nova2Conversationalai: "nova-2-conversationalai", + Nova2Voicemail: "nova-2-voicemail", + Nova2Video: "nova-2-video", + Nova2Medical: "nova-2-medical", + Nova2Drivethru: "nova-2-drivethru", + Nova2Automotive: "nova-2-automotive", + Nova: "nova", + NovaGeneral: "nova-general", + NovaPhonecall: "nova-phonecall", + NovaMedical: "nova-medical", + Enhanced: "enhanced", + EnhancedGeneral: "enhanced-general", + EnhancedMeeting: "enhanced-meeting", + EnhancedPhonecall: "enhanced-phonecall", + EnhancedFinance: "enhanced-finance", + Base: "base", + Meeting: "meeting", + Phonecall: "phonecall", + Finance: "finance", + Conversationalai: "conversationalai", + Voicemail: "voicemail", + Video: "video", +} as const; +export type MediaTranscribeRequestModel = + (typeof MediaTranscribeRequestModel)[keyof typeof MediaTranscribeRequestModel]; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestSummarize.ts b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestSummarize.ts new file mode 100644 index 00000000..87a06137 --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestSummarize.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const MediaTranscribeRequestSummarize = { + V2: "v2", + V1: "v1", +} as const; +export type MediaTranscribeRequestSummarize = + (typeof MediaTranscribeRequestSummarize)[keyof typeof MediaTranscribeRequestSummarize]; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestVersion.ts b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestVersion.ts new file mode 100644 index 00000000..8528fa1f --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeRequestVersion.ts @@ -0,0 +1,7 @@ +// This file was auto-generated by Fern from our API Definition. + +export const MediaTranscribeRequestVersion = { + Latest: "latest", +} as const; +export type MediaTranscribeRequestVersion = + (typeof MediaTranscribeRequestVersion)[keyof typeof MediaTranscribeRequestVersion]; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeResponse.ts b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeResponse.ts new file mode 100644 index 00000000..975493ee --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/MediaTranscribeResponse.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../index.js"; + +export type MediaTranscribeResponse = Deepgram.ListenV1Response | Deepgram.ListenV1AcceptedResponse; diff --git a/src/api/resources/listen/resources/v1/resources/media/types/index.ts b/src/api/resources/listen/resources/v1/resources/media/types/index.ts new file mode 100644 index 00000000..679a19c0 --- /dev/null +++ b/src/api/resources/listen/resources/v1/resources/media/types/index.ts @@ -0,0 +1,8 @@ +export * from "./MediaTranscribeRequestCallbackMethod.js"; +export * from "./MediaTranscribeRequestCustomIntentMode.js"; +export * from "./MediaTranscribeRequestCustomTopicMode.js"; +export * from "./MediaTranscribeRequestEncoding.js"; +export * from "./MediaTranscribeRequestModel.js"; +export * from "./MediaTranscribeRequestSummarize.js"; +export * from "./MediaTranscribeRequestVersion.js"; +export * from "./MediaTranscribeResponse.js"; diff --git a/src/api/resources/listen/resources/v1/types/ListenV1CloseStream.ts b/src/api/resources/listen/resources/v1/types/ListenV1CloseStream.ts new file mode 100644 index 00000000..4254d530 --- /dev/null +++ b/src/api/resources/listen/resources/v1/types/ListenV1CloseStream.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1CloseStream { + /** Message type identifier */ + type: ListenV1CloseStream.Type; +} + +export namespace ListenV1CloseStream { + /** Message type identifier */ + export const Type = { + Finalize: "Finalize", + CloseStream: "CloseStream", + KeepAlive: "KeepAlive", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/listen/resources/v1/types/ListenV1Finalize.ts b/src/api/resources/listen/resources/v1/types/ListenV1Finalize.ts new file mode 100644 index 00000000..3f4eefd5 --- /dev/null +++ b/src/api/resources/listen/resources/v1/types/ListenV1Finalize.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1Finalize { + /** Message type identifier */ + type: ListenV1Finalize.Type; +} + +export namespace ListenV1Finalize { + /** Message type identifier */ + export const Type = { + Finalize: "Finalize", + CloseStream: "CloseStream", + KeepAlive: "KeepAlive", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/listen/resources/v1/types/ListenV1KeepAlive.ts b/src/api/resources/listen/resources/v1/types/ListenV1KeepAlive.ts new file mode 100644 index 00000000..c29ace8b --- /dev/null +++ b/src/api/resources/listen/resources/v1/types/ListenV1KeepAlive.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1KeepAlive { + /** Message type identifier */ + type: ListenV1KeepAlive.Type; +} + +export namespace ListenV1KeepAlive { + /** Message type identifier */ + export const Type = { + Finalize: "Finalize", + CloseStream: "CloseStream", + KeepAlive: "KeepAlive", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/listen/resources/v1/types/ListenV1Metadata.ts b/src/api/resources/listen/resources/v1/types/ListenV1Metadata.ts new file mode 100644 index 00000000..6775d37e --- /dev/null +++ b/src/api/resources/listen/resources/v1/types/ListenV1Metadata.ts @@ -0,0 +1,18 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1Metadata { + /** Message type identifier */ + type: "Metadata"; + /** The transaction key */ + transaction_key: string; + /** The request ID */ + request_id: string; + /** The sha256 */ + sha256: string; + /** The created */ + created: string; + /** The duration */ + duration: number; + /** The channels */ + channels: number; +} diff --git a/src/api/resources/listen/resources/v1/types/ListenV1Results.ts b/src/api/resources/listen/resources/v1/types/ListenV1Results.ts new file mode 100644 index 00000000..34902519 --- /dev/null +++ b/src/api/resources/listen/resources/v1/types/ListenV1Results.ts @@ -0,0 +1,83 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1Results { + /** Message type identifier */ + type: "Results"; + /** The index of the channel */ + channel_index: number[]; + /** The duration of the transcription */ + duration: number; + /** The start time of the transcription */ + start: number; + /** Whether the transcription is final */ + is_final?: boolean; + /** Whether the transcription is speech final */ + speech_final?: boolean; + channel: ListenV1Results.Channel; + metadata: ListenV1Results.Metadata; + /** Whether the transcription is from a finalize message */ + from_finalize?: boolean; +} + +export namespace ListenV1Results { + export interface Channel { + alternatives: Channel.Alternatives.Item[]; + } + + export namespace Channel { + export type Alternatives = Alternatives.Item[]; + + export namespace Alternatives { + export interface Item { + /** The transcript of the transcription */ + transcript: string; + /** The confidence of the transcription */ + confidence: number; + languages: string[]; + words: Item.Words.Item[]; + } + + export namespace Item { + export type Words = Words.Item[]; + + export namespace Words { + export interface Item { + /** The word of the transcription */ + word: string; + /** The start time of the word */ + start: number; + /** The end time of the word */ + end: number; + /** The confidence of the word */ + confidence: number; + /** The language of the word */ + language: string; + /** The punctuated word of the word */ + punctuated_word: string; + /** The speaker of the word */ + speaker?: number; + } + } + } + } + } + + export interface Metadata { + /** The request ID */ + request_id: string; + model_info: Metadata.ModelInfo; + /** The model UUID */ + model_uuid: string; + } + + export namespace Metadata { + export interface ModelInfo { + /** The name of the model */ + name: string; + /** The version of the model */ + version: string; + /** The arch of the model */ + arch: string; + } + } +} diff --git a/src/api/resources/listen/resources/v1/types/ListenV1SpeechStarted.ts b/src/api/resources/listen/resources/v1/types/ListenV1SpeechStarted.ts new file mode 100644 index 00000000..9a7269c9 --- /dev/null +++ b/src/api/resources/listen/resources/v1/types/ListenV1SpeechStarted.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1SpeechStarted { + /** Message type identifier */ + type: "SpeechStarted"; + /** The channel */ + channel: number[]; + /** The timestamp */ + timestamp: number; +} diff --git a/src/api/resources/listen/resources/v1/types/ListenV1UtteranceEnd.ts b/src/api/resources/listen/resources/v1/types/ListenV1UtteranceEnd.ts new file mode 100644 index 00000000..260ad7e3 --- /dev/null +++ b/src/api/resources/listen/resources/v1/types/ListenV1UtteranceEnd.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1UtteranceEnd { + /** Message type identifier */ + type: "UtteranceEnd"; + /** The channel */ + channel: number[]; + /** The last word end */ + last_word_end: number; +} diff --git a/src/api/resources/listen/resources/v1/types/index.ts b/src/api/resources/listen/resources/v1/types/index.ts new file mode 100644 index 00000000..3d556069 --- /dev/null +++ b/src/api/resources/listen/resources/v1/types/index.ts @@ -0,0 +1,7 @@ +export * from "./ListenV1CloseStream.js"; +export * from "./ListenV1Finalize.js"; +export * from "./ListenV1KeepAlive.js"; +export * from "./ListenV1Metadata.js"; +export * from "./ListenV1Results.js"; +export * from "./ListenV1SpeechStarted.js"; +export * from "./ListenV1UtteranceEnd.js"; diff --git a/src/api/resources/listen/resources/v2/client/Client.ts b/src/api/resources/listen/resources/v2/client/Client.ts new file mode 100644 index 00000000..8da2498a --- /dev/null +++ b/src/api/resources/listen/resources/v2/client/Client.ts @@ -0,0 +1,117 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../core/headers.js"; +import * as core from "../../../../../../core/index.js"; +import * as environments from "../../../../../../environments.js"; +import { V2Socket } from "./Socket.js"; + +export declare namespace V2Client { + export interface Options extends BaseClientOptions {} + + export interface ConnectArgs { + model: string; + encoding?: string | undefined; + sample_rate?: string | undefined; + eager_eot_threshold?: string | undefined; + eot_threshold?: string | undefined; + eot_timeout_ms?: string | undefined; + keyterm?: string | undefined; + mip_opt_out?: string | undefined; + tag?: string | undefined; + Authorization: string; + /** Arbitrary headers to send with the websocket connect request. */ + headers?: Record; + /** Enable debug mode on the websocket. Defaults to false. */ + debug?: boolean; + /** Number of reconnect attempts. Defaults to 30. */ + reconnectAttempts?: number; + } +} + +export class V2Client { + protected readonly _options: V2Client.Options; + + constructor(options: V2Client.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public async connect(args: V2Client.ConnectArgs): Promise { + const { + model, + encoding, + sample_rate, + eager_eot_threshold, + eot_threshold, + eot_timeout_ms, + keyterm, + mip_opt_out, + tag, + headers, + debug, + reconnectAttempts, + } = args; + const _queryParams: Record = {}; + _queryParams.model = model; + if (encoding != null) { + _queryParams.encoding = encoding; + } + + if (sample_rate != null) { + _queryParams.sample_rate = sample_rate; + } + + if (eager_eot_threshold != null) { + _queryParams.eager_eot_threshold = eager_eot_threshold; + } + + if (eot_threshold != null) { + _queryParams.eot_threshold = eot_threshold; + } + + if (eot_timeout_ms != null) { + _queryParams.eot_timeout_ms = eot_timeout_ms; + } + + if (keyterm != null) { + _queryParams.keyterm = keyterm; + } + + if (mip_opt_out != null) { + _queryParams.mip_opt_out = mip_opt_out; + } + + if (tag != null) { + _queryParams.tag = tag; + } + + const _headers: Record = mergeHeaders( + mergeOnlyDefinedHeaders({ + ...(await this._getCustomAuthorizationHeaders()), + Authorization: args.Authorization, + }), + headers, + ); + const socket = new core.ReconnectingWebSocket({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).production, + "/v2/listen", + ), + protocols: [], + queryParameters: _queryParams, + headers: _headers, + options: { debug: debug ?? false, maxRetries: reconnectAttempts ?? 30 }, + }); + return new V2Socket({ socket }); + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/listen/resources/v2/client/Socket.ts b/src/api/resources/listen/resources/v2/client/Socket.ts new file mode 100644 index 00000000..2ea674db --- /dev/null +++ b/src/api/resources/listen/resources/v2/client/Socket.ts @@ -0,0 +1,142 @@ +// This file was auto-generated by Fern from our API Definition. + +import * as core from "../../../../../../core/index.js"; +import { fromJson, toJson } from "../../../../../../core/json.js"; +import type * as Deepgram from "../../../../../index.js"; + +export declare namespace V2Socket { + export interface Args { + socket: core.ReconnectingWebSocket; + } + + export type Response = + | Deepgram.listen.ListenV2Connected + | Deepgram.listen.ListenV2TurnInfo + | Deepgram.listen.ListenV2FatalError; + type EventHandlers = { + open?: () => void; + message?: (message: Response) => void; + close?: (event: core.CloseEvent) => void; + error?: (error: Error) => void; + }; +} + +export class V2Socket { + public readonly socket: core.ReconnectingWebSocket; + protected readonly eventHandlers: V2Socket.EventHandlers = {}; + private handleOpen: () => void = () => { + this.eventHandlers.open?.(); + }; + private handleMessage: (event: { data: string }) => void = (event) => { + const data = fromJson(event.data); + + this.eventHandlers.message?.(data as V2Socket.Response); + }; + private handleClose: (event: core.CloseEvent) => void = (event) => { + this.eventHandlers.close?.(event); + }; + private handleError: (event: core.ErrorEvent) => void = (event) => { + const message = event.message; + this.eventHandlers.error?.(new Error(message)); + }; + + constructor(args: V2Socket.Args) { + this.socket = args.socket; + this.socket.addEventListener("open", this.handleOpen); + this.socket.addEventListener("message", this.handleMessage); + this.socket.addEventListener("close", this.handleClose); + this.socket.addEventListener("error", this.handleError); + } + + /** The current state of the connection; this is one of the readyState constants. */ + get readyState(): number { + return this.socket.readyState; + } + + /** + * @param event - The event to attach to. + * @param callback - The callback to run when the event is triggered. + * Usage: + * ```typescript + * this.on('open', () => { + * console.log('The websocket is open'); + * }); + * ``` + */ + public on(event: T, callback: V2Socket.EventHandlers[T]): void { + this.eventHandlers[event] = callback; + } + + public sendListenV2Media(message: string): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendListenV2CloseStream(message: Deepgram.listen.ListenV2CloseStream): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + /** Connect to the websocket and register event handlers. */ + public connect(): V2Socket { + this.socket.reconnect(); + + this.socket.addEventListener("open", this.handleOpen); + this.socket.addEventListener("message", this.handleMessage); + this.socket.addEventListener("close", this.handleClose); + this.socket.addEventListener("error", this.handleError); + + return this; + } + + /** Close the websocket and unregister event handlers. */ + public close(): void { + this.socket.close(); + + this.handleClose({ code: 1000 } as CloseEvent); + + this.socket.removeEventListener("open", this.handleOpen); + this.socket.removeEventListener("message", this.handleMessage); + this.socket.removeEventListener("close", this.handleClose); + this.socket.removeEventListener("error", this.handleError); + } + + /** Returns a promise that resolves when the websocket is open. */ + public async waitForOpen(): Promise { + if (this.socket.readyState === core.ReconnectingWebSocket.OPEN) { + return this.socket; + } + + return new Promise((resolve, reject) => { + this.socket.addEventListener("open", () => { + resolve(this.socket); + }); + + this.socket.addEventListener("error", (event: unknown) => { + reject(event); + }); + }); + } + + /** Asserts that the websocket is open. */ + private assertSocketIsOpen(): void { + if (!this.socket) { + throw new Error("Socket is not connected."); + } + + if (this.socket.readyState !== core.ReconnectingWebSocket.OPEN) { + throw new Error("Socket is not open."); + } + } + + /** Send a binary payload to the websocket. */ + protected sendBinary(payload: ArrayBufferLike | Blob | ArrayBufferView): void { + this.socket.send(payload); + } + + /** Send a JSON payload to the websocket. */ + protected sendJson(payload: string | Deepgram.listen.ListenV2CloseStream): void { + const jsonPayload = toJson(payload); + this.socket.send(jsonPayload); + } +} diff --git a/src/api/resources/listen/resources/v2/client/index.ts b/src/api/resources/listen/resources/v2/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/listen/resources/v2/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/listen/resources/v2/index.ts b/src/api/resources/listen/resources/v2/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/listen/resources/v2/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/listen/resources/v2/types/ListenV2CloseStream.ts b/src/api/resources/listen/resources/v2/types/ListenV2CloseStream.ts new file mode 100644 index 00000000..164c96a2 --- /dev/null +++ b/src/api/resources/listen/resources/v2/types/ListenV2CloseStream.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV2CloseStream { + /** Message type identifier */ + type: ListenV2CloseStream.Type; +} + +export namespace ListenV2CloseStream { + /** Message type identifier */ + export const Type = { + Finalize: "Finalize", + CloseStream: "CloseStream", + KeepAlive: "KeepAlive", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/listen/resources/v2/types/ListenV2Connected.ts b/src/api/resources/listen/resources/v2/types/ListenV2Connected.ts new file mode 100644 index 00000000..48edf01f --- /dev/null +++ b/src/api/resources/listen/resources/v2/types/ListenV2Connected.ts @@ -0,0 +1,14 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV2Connected { + /** Message type identifier */ + type: "Connected"; + /** The unique identifier of the request */ + request_id: string; + /** + * Starts at `0` and increments for each message the server sends + * to the client. This includes messages of other types, like + * `TurnInfo` messages. + */ + sequence_id: number; +} diff --git a/src/api/resources/listen/resources/v2/types/ListenV2FatalError.ts b/src/api/resources/listen/resources/v2/types/ListenV2FatalError.ts new file mode 100644 index 00000000..4782b6d9 --- /dev/null +++ b/src/api/resources/listen/resources/v2/types/ListenV2FatalError.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV2FatalError { + /** Message type identifier */ + type: "Error"; + /** + * Starts at `0` and increments for each message the server sends + * to the client. This includes messages of other types, like + * `Connected` messages. + */ + sequence_id: number; + /** A string code describing the error, e.g. `INTERNAL_SERVER_ERROR` */ + code: string; + /** Prose description of the error */ + description: string; +} diff --git a/src/api/resources/listen/resources/v2/types/ListenV2TurnInfo.ts b/src/api/resources/listen/resources/v2/types/ListenV2TurnInfo.ts new file mode 100644 index 00000000..abdcd869 --- /dev/null +++ b/src/api/resources/listen/resources/v2/types/ListenV2TurnInfo.ts @@ -0,0 +1,64 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Describes the current turn and latest state of the turn + */ +export interface ListenV2TurnInfo { + type: "TurnInfo"; + /** The unique identifier of the request */ + request_id: string; + /** Starts at `0` and increments for each message the server sends to the client. This includes messages of other types, like `Connected` messages. */ + sequence_id: number; + /** + * The type of event being reported. + * + * - **Update** - Additional audio has been transcribed, but the turn state hasn't changed + * - **StartOfTurn** - The user has begun speaking for the first time in the turn + * - **EagerEndOfTurn** - The system has moderate confidence that the user has finished speaking for the turn. This is an opportunity to begin preparing an agent reply + * - **TurnResumed** - The system detected that speech had ended and therefore sent an **EagerEndOfTurn** event, but speech is actually continuing for this turn + * - **EndOfTurn** - The user has finished speaking for the turn + */ + event: ListenV2TurnInfo.Event; + /** The index of the current turn */ + turn_index: number; + /** Start time in seconds of the audio range that was transcribed */ + audio_window_start: number; + /** End time in seconds of the audio range that was transcribed */ + audio_window_end: number; + /** Text that was said over the course of the current turn */ + transcript: string; + /** The words in the `transcript` */ + words: ListenV2TurnInfo.Words.Item[]; + /** Confidence that no more speech is coming in this turn */ + end_of_turn_confidence: number; +} + +export namespace ListenV2TurnInfo { + /** + * The type of event being reported. + * + * - **Update** - Additional audio has been transcribed, but the turn state hasn't changed + * - **StartOfTurn** - The user has begun speaking for the first time in the turn + * - **EagerEndOfTurn** - The system has moderate confidence that the user has finished speaking for the turn. This is an opportunity to begin preparing an agent reply + * - **TurnResumed** - The system detected that speech had ended and therefore sent an **EagerEndOfTurn** event, but speech is actually continuing for this turn + * - **EndOfTurn** - The user has finished speaking for the turn + */ + export const Event = { + Update: "Update", + StartOfTurn: "StartOfTurn", + EagerEndOfTurn: "EagerEndOfTurn", + TurnResumed: "TurnResumed", + EndOfTurn: "EndOfTurn", + } as const; + export type Event = (typeof Event)[keyof typeof Event]; + export type Words = Words.Item[]; + + export namespace Words { + export interface Item { + /** The individual punctuated, properly-cased word from the transcript */ + word: string; + /** Confidence that this word was transcribed correctly */ + confidence: number; + } + } +} diff --git a/src/api/resources/listen/resources/v2/types/index.ts b/src/api/resources/listen/resources/v2/types/index.ts new file mode 100644 index 00000000..c7c89438 --- /dev/null +++ b/src/api/resources/listen/resources/v2/types/index.ts @@ -0,0 +1,4 @@ +export * from "./ListenV2CloseStream.js"; +export * from "./ListenV2Connected.js"; +export * from "./ListenV2FatalError.js"; +export * from "./ListenV2TurnInfo.js"; diff --git a/src/api/resources/manage/client/Client.ts b/src/api/resources/manage/client/Client.ts new file mode 100644 index 00000000..8664908c --- /dev/null +++ b/src/api/resources/manage/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../BaseClient.js"; +import { V1Client } from "../resources/v1/client/Client.js"; + +export declare namespace ManageClient { + export interface Options extends BaseClientOptions {} +} + +export class ManageClient { + protected readonly _options: ManageClient.Options; + protected _v1: V1Client | undefined; + + constructor(options: ManageClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get v1(): V1Client { + return (this._v1 ??= new V1Client(this._options)); + } +} diff --git a/src/api/resources/manage/client/index.ts b/src/api/resources/manage/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/manage/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/manage/index.ts b/src/api/resources/manage/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/manage/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/manage/resources/index.ts b/src/api/resources/manage/resources/index.ts new file mode 100644 index 00000000..c6b56d24 --- /dev/null +++ b/src/api/resources/manage/resources/index.ts @@ -0,0 +1 @@ +export * as v1 from "./v1/index.js"; diff --git a/src/api/resources/manage/resources/v1/client/Client.ts b/src/api/resources/manage/resources/v1/client/Client.ts new file mode 100644 index 00000000..83cbd545 --- /dev/null +++ b/src/api/resources/manage/resources/v1/client/Client.ts @@ -0,0 +1,28 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../BaseClient.js"; +import { ModelsClient } from "../resources/models/client/Client.js"; +import { ProjectsClient } from "../resources/projects/client/Client.js"; + +export declare namespace V1Client { + export interface Options extends BaseClientOptions {} +} + +export class V1Client { + protected readonly _options: V1Client.Options; + protected _models: ModelsClient | undefined; + protected _projects: ProjectsClient | undefined; + + constructor(options: V1Client.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get models(): ModelsClient { + return (this._models ??= new ModelsClient(this._options)); + } + + public get projects(): ProjectsClient { + return (this._projects ??= new ProjectsClient(this._options)); + } +} diff --git a/src/api/resources/manage/resources/v1/client/index.ts b/src/api/resources/manage/resources/v1/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/manage/resources/v1/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/manage/resources/v1/index.ts b/src/api/resources/manage/resources/v1/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/manage/resources/v1/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/index.ts b/src/api/resources/manage/resources/v1/resources/index.ts new file mode 100644 index 00000000..bde8d7a0 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/index.ts @@ -0,0 +1,4 @@ +export * from "./models/client/requests/index.js"; +export * as models from "./models/index.js"; +export * from "./projects/client/requests/index.js"; +export * as projects from "./projects/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/models/client/Client.ts b/src/api/resources/manage/resources/v1/resources/models/client/Client.ts new file mode 100644 index 00000000..684fbafd --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/models/client/Client.ts @@ -0,0 +1,194 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../index.js"; + +export declare namespace ModelsClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class ModelsClient { + protected readonly _options: ModelsClient.Options; + + constructor(options: ModelsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Returns metadata on all the latest public models. To retrieve custom models, use Get Project Models. + * + * @param {Deepgram.manage.v1.ModelsListRequest} request + * @param {ModelsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.models.list({ + * include_outdated: true + * }) + */ + public list( + request: Deepgram.manage.v1.ModelsListRequest = {}, + requestOptions?: ModelsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(request, requestOptions)); + } + + private async __list( + request: Deepgram.manage.v1.ModelsListRequest = {}, + requestOptions?: ModelsClient.RequestOptions, + ): Promise> { + const { include_outdated: includeOutdated } = request; + const _queryParams: Record = {}; + if (includeOutdated != null) { + _queryParams.include_outdated = includeOutdated.toString(); + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + "v1/models", + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.ListModelsV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling GET /v1/models."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Returns metadata for a specific public model + * + * @param {string} model_id - The specific UUID of the model + * @param {ModelsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.models.get("af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291") + */ + public get( + model_id: string, + requestOptions?: ModelsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__get(model_id, requestOptions)); + } + + private async __get( + model_id: string, + requestOptions?: ModelsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/models/${core.url.encodePathParam(model_id)}`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.GetModelV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling GET /v1/models/{model_id}."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/models/client/index.ts b/src/api/resources/manage/resources/v1/resources/models/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/models/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/models/client/requests/ModelsListRequest.ts b/src/api/resources/manage/resources/v1/resources/models/client/requests/ModelsListRequest.ts new file mode 100644 index 00000000..b2183044 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/models/client/requests/ModelsListRequest.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * include_outdated: true + * } + */ +export interface ModelsListRequest { + /** returns non-latest versions of models */ + include_outdated?: boolean; +} diff --git a/src/api/resources/manage/resources/v1/resources/models/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/models/client/requests/index.ts new file mode 100644 index 00000000..7197c55a --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/models/client/requests/index.ts @@ -0,0 +1 @@ +export type { ModelsListRequest } from "./ModelsListRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/models/index.ts b/src/api/resources/manage/resources/v1/resources/models/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/models/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/client/Client.ts new file mode 100644 index 00000000..f8ea4aa7 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/client/Client.ts @@ -0,0 +1,482 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../index.js"; +import { BillingClient } from "../resources/billing/client/Client.js"; +import { KeysClient } from "../resources/keys/client/Client.js"; +import { MembersClient } from "../resources/members/client/Client.js"; +import { ModelsClient } from "../resources/models/client/Client.js"; +import { RequestsClient } from "../resources/requests/client/Client.js"; +import { UsageClient } from "../resources/usage/client/Client.js"; + +export declare namespace ProjectsClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class ProjectsClient { + protected readonly _options: ProjectsClient.Options; + protected _keys: KeysClient | undefined; + protected _members: MembersClient | undefined; + protected _models: ModelsClient | undefined; + protected _requests: RequestsClient | undefined; + protected _usage: UsageClient | undefined; + protected _billing: BillingClient | undefined; + + constructor(options: ProjectsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get keys(): KeysClient { + return (this._keys ??= new KeysClient(this._options)); + } + + public get members(): MembersClient { + return (this._members ??= new MembersClient(this._options)); + } + + public get models(): ModelsClient { + return (this._models ??= new ModelsClient(this._options)); + } + + public get requests(): RequestsClient { + return (this._requests ??= new RequestsClient(this._options)); + } + + public get usage(): UsageClient { + return (this._usage ??= new UsageClient(this._options)); + } + + public get billing(): BillingClient { + return (this._billing ??= new BillingClient(this._options)); + } + + /** + * Retrieves basic information about the projects associated with the API key + * + * @param {ProjectsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.list() + */ + public list( + requestOptions?: ProjectsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(requestOptions)); + } + + private async __list( + requestOptions?: ProjectsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + "v1/projects", + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.ListProjectsV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling GET /v1/projects."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Retrieves information about the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.ProjectsGetRequest} request + * @param {ProjectsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.get("123456-7890-1234-5678-901234", { + * limit: 1.1, + * page: 1.1 + * }) + */ + public get( + project_id: string, + request: Deepgram.manage.v1.ProjectsGetRequest = {}, + requestOptions?: ProjectsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__get(project_id, request, requestOptions)); + } + + private async __get( + project_id: string, + request: Deepgram.manage.v1.ProjectsGetRequest = {}, + requestOptions?: ProjectsClient.RequestOptions, + ): Promise> { + const { limit, page } = request; + const _queryParams: Record = {}; + if (limit != null) { + _queryParams.limit = limit.toString(); + } + + if (page != null) { + _queryParams.page = page.toString(); + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.GetProjectV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling GET /v1/projects/{project_id}."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Deletes the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {ProjectsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.delete("123456-7890-1234-5678-901234") + */ + public delete( + project_id: string, + requestOptions?: ProjectsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__delete(project_id, requestOptions)); + } + + private async __delete( + project_id: string, + requestOptions?: ProjectsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}`, + ), + method: "DELETE", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.DeleteProjectV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling DELETE /v1/projects/{project_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Updates the name or other properties of an existing project + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.UpdateProjectV1Request} request + * @param {ProjectsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.update("123456-7890-1234-5678-901234") + */ + public update( + project_id: string, + request: Deepgram.manage.v1.UpdateProjectV1Request = {}, + requestOptions?: ProjectsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__update(project_id, request, requestOptions)); + } + + private async __update( + project_id: string, + request: Deepgram.manage.v1.UpdateProjectV1Request = {}, + requestOptions?: ProjectsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}`, + ), + method: "PATCH", + headers: _headers, + contentType: "application/json", + queryParameters: requestOptions?.queryParams, + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.UpdateProjectV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling PATCH /v1/projects/{project_id}."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Removes the authenticated account from the specific project + * + * @param {string} project_id - The unique identifier of the project + * @param {ProjectsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.leave("123456-7890-1234-5678-901234") + */ + public leave( + project_id: string, + requestOptions?: ProjectsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__leave(project_id, requestOptions)); + } + + private async __leave( + project_id: string, + requestOptions?: ProjectsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/leave`, + ), + method: "DELETE", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.LeaveProjectV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling DELETE /v1/projects/{project_id}/leave.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/client/requests/ProjectsGetRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/client/requests/ProjectsGetRequest.ts new file mode 100644 index 00000000..e23b4151 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/client/requests/ProjectsGetRequest.ts @@ -0,0 +1,15 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * limit: 1.1, + * page: 1.1 + * } + */ +export interface ProjectsGetRequest { + /** Number of results to return per page. Default 10. Range [1,1000] */ + limit?: number; + /** Navigate and return the results to retrieve specific portions of information of the response */ + page?: number; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/client/requests/UpdateProjectV1Request.ts b/src/api/resources/manage/resources/v1/resources/projects/client/requests/UpdateProjectV1Request.ts new file mode 100644 index 00000000..27fa8c69 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/client/requests/UpdateProjectV1Request.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * {} + */ +export interface UpdateProjectV1Request { + /** The name of the project */ + name?: string; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/client/requests/index.ts new file mode 100644 index 00000000..901e9d30 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/client/requests/index.ts @@ -0,0 +1,2 @@ +export type { ProjectsGetRequest } from "./ProjectsGetRequest.js"; +export type { UpdateProjectV1Request } from "./UpdateProjectV1Request.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/index.ts b/src/api/resources/manage/resources/v1/resources/projects/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/client/Client.ts new file mode 100644 index 00000000..468cecba --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/client/Client.ts @@ -0,0 +1,40 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { BalancesClient } from "../resources/balances/client/Client.js"; +import { BreakdownClient } from "../resources/breakdown/client/Client.js"; +import { FieldsClient } from "../resources/fields/client/Client.js"; +import { PurchasesClient } from "../resources/purchases/client/Client.js"; + +export declare namespace BillingClient { + export interface Options extends BaseClientOptions {} +} + +export class BillingClient { + protected readonly _options: BillingClient.Options; + protected _balances: BalancesClient | undefined; + protected _breakdown: BreakdownClient | undefined; + protected _fields: FieldsClient | undefined; + protected _purchases: PurchasesClient | undefined; + + constructor(options: BillingClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get balances(): BalancesClient { + return (this._balances ??= new BalancesClient(this._options)); + } + + public get breakdown(): BreakdownClient { + return (this._breakdown ??= new BreakdownClient(this._options)); + } + + public get fields(): FieldsClient { + return (this._fields ??= new FieldsClient(this._options)); + } + + public get purchases(): PurchasesClient { + return (this._purchases ??= new PurchasesClient(this._options)); + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/client/Client.ts new file mode 100644 index 00000000..a157fe18 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/client/Client.ts @@ -0,0 +1,196 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace BalancesClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class BalancesClient { + protected readonly _options: BalancesClient.Options; + + constructor(options: BalancesClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Generates a list of outstanding balances for the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {BalancesClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.billing.balances.list("123456-7890-1234-5678-901234") + */ + public list( + project_id: string, + requestOptions?: BalancesClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, requestOptions)); + } + + private async __list( + project_id: string, + requestOptions?: BalancesClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/balances`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.ListProjectBalancesV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/balances.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Retrieves details about the specified balance + * + * @param {string} project_id - The unique identifier of the project + * @param {string} balance_id - The unique identifier of the balance + * @param {BalancesClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.billing.balances.get("123456-7890-1234-5678-901234", "123456-7890-1234-5678-901234") + */ + public get( + project_id: string, + balance_id: string, + requestOptions?: BalancesClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__get(project_id, balance_id, requestOptions)); + } + + private async __get( + project_id: string, + balance_id: string, + requestOptions?: BalancesClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/balances/${core.url.encodePathParam(balance_id)}`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.GetProjectBalanceV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/balances/{balance_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/balances/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/Client.ts new file mode 100644 index 00000000..8e45b970 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/Client.ts @@ -0,0 +1,153 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace BreakdownClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class BreakdownClient { + protected readonly _options: BreakdownClient.Options; + + constructor(options: BreakdownClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Retrieves the billing summary for a specific project, with various filter options or by grouping options. + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.billing.BreakdownListRequest} request + * @param {BreakdownClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.billing.breakdown.list("123456-7890-1234-5678-901234", { + * start: "start", + * end: "end", + * accessor: "12345678-1234-1234-1234-123456789012", + * deployment: "hosted", + * tag: "tag1", + * line_item: "streaming::nova-3" + * }) + */ + public list( + project_id: string, + request: Deepgram.manage.v1.projects.billing.BreakdownListRequest = {}, + requestOptions?: BreakdownClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, request, requestOptions)); + } + + private async __list( + project_id: string, + request: Deepgram.manage.v1.projects.billing.BreakdownListRequest = {}, + requestOptions?: BreakdownClient.RequestOptions, + ): Promise> { + const { start, end, accessor, deployment, tag, line_item: lineItem, grouping } = request; + const _queryParams: Record = {}; + if (start != null) { + _queryParams.start = start; + } + + if (end != null) { + _queryParams.end = end; + } + + if (accessor != null) { + _queryParams.accessor = accessor; + } + + if (deployment != null) { + _queryParams.deployment = deployment; + } + + if (tag != null) { + _queryParams.tag = tag; + } + + if (lineItem != null) { + _queryParams.line_item = lineItem; + } + + if (grouping != null) { + if (Array.isArray(grouping)) { + _queryParams.grouping = grouping.map((item) => item); + } else { + _queryParams.grouping = grouping; + } + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/billing/breakdown`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.BillingBreakdownV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/billing/breakdown.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/requests/BreakdownListRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/requests/BreakdownListRequest.ts new file mode 100644 index 00000000..45daed42 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/requests/BreakdownListRequest.ts @@ -0,0 +1,33 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../../../../../index.js"; + +/** + * @example + * { + * start: "start", + * end: "end", + * accessor: "12345678-1234-1234-1234-123456789012", + * deployment: "hosted", + * tag: "tag1", + * line_item: "streaming::nova-3" + * } + */ +export interface BreakdownListRequest { + /** Start date of the requested date range. Format accepted is YYYY-MM-DD */ + start?: string; + /** End date of the requested date range. Format accepted is YYYY-MM-DD */ + end?: string; + /** Filter for requests where a specific accessor was used */ + accessor?: string; + /** Filter for requests where a specific deployment was used */ + deployment?: Deepgram.manage.v1.projects.billing.BreakdownListRequestDeployment; + /** Filter for requests where a specific tag was used */ + tag?: string; + /** Filter requests by line item (e.g. streaming::nova-3) */ + line_item?: string; + /** Group billing breakdown by one or more dimensions (accessor, deployment, line_item, tags) */ + grouping?: + | Deepgram.manage.v1.projects.billing.BreakdownListRequestGroupingItem + | Deepgram.manage.v1.projects.billing.BreakdownListRequestGroupingItem[]; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/requests/index.ts new file mode 100644 index 00000000..68887545 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/client/requests/index.ts @@ -0,0 +1 @@ +export type { BreakdownListRequest } from "./BreakdownListRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/BreakdownListRequestDeployment.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/BreakdownListRequestDeployment.ts new file mode 100644 index 00000000..ebd7c775 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/BreakdownListRequestDeployment.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Deployment type for the requests */ +export const BreakdownListRequestDeployment = { + Hosted: "hosted", + Beta: "beta", + SelfHosted: "self-hosted", +} as const; +export type BreakdownListRequestDeployment = + (typeof BreakdownListRequestDeployment)[keyof typeof BreakdownListRequestDeployment]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/BreakdownListRequestGroupingItem.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/BreakdownListRequestGroupingItem.ts new file mode 100644 index 00000000..63cacb46 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/BreakdownListRequestGroupingItem.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export const BreakdownListRequestGroupingItem = { + Accessor: "accessor", + Deployment: "deployment", + LineItem: "line_item", + Tags: "tags", +} as const; +export type BreakdownListRequestGroupingItem = + (typeof BreakdownListRequestGroupingItem)[keyof typeof BreakdownListRequestGroupingItem]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/index.ts new file mode 100644 index 00000000..da00a52b --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/breakdown/types/index.ts @@ -0,0 +1,2 @@ +export * from "./BreakdownListRequestDeployment.js"; +export * from "./BreakdownListRequestGroupingItem.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/Client.ts new file mode 100644 index 00000000..3299150b --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/Client.ts @@ -0,0 +1,125 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace FieldsClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class FieldsClient { + protected readonly _options: FieldsClient.Options; + + constructor(options: FieldsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Lists the accessors, deployment types, tags, and line items used for billing data in the specified time period. Use this endpoint if you want to filter your results from the Billing Breakdown endpoint and want to know what filters are available. + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.billing.FieldsListRequest} request + * @param {FieldsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.billing.fields.list("123456-7890-1234-5678-901234", { + * start: "start", + * end: "end" + * }) + */ + public list( + project_id: string, + request: Deepgram.manage.v1.projects.billing.FieldsListRequest = {}, + requestOptions?: FieldsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, request, requestOptions)); + } + + private async __list( + project_id: string, + request: Deepgram.manage.v1.projects.billing.FieldsListRequest = {}, + requestOptions?: FieldsClient.RequestOptions, + ): Promise> { + const { start, end } = request; + const _queryParams: Record = {}; + if (start != null) { + _queryParams.start = start; + } + + if (end != null) { + _queryParams.end = end; + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/billing/fields`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.ListBillingFieldsV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/billing/fields.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/requests/FieldsListRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/requests/FieldsListRequest.ts new file mode 100644 index 00000000..d72af8d9 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/requests/FieldsListRequest.ts @@ -0,0 +1,15 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * start: "start", + * end: "end" + * } + */ +export interface FieldsListRequest { + /** Start date of the requested date range. Format accepted is YYYY-MM-DD */ + start?: string; + /** End date of the requested date range. Format accepted is YYYY-MM-DD */ + end?: string; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/requests/index.ts new file mode 100644 index 00000000..35ea45ea --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/client/requests/index.ts @@ -0,0 +1 @@ +export type { FieldsListRequest } from "./FieldsListRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/fields/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/index.ts new file mode 100644 index 00000000..7bbb6f0b --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/index.ts @@ -0,0 +1,8 @@ +export * as balances from "./balances/index.js"; +export * from "./breakdown/client/requests/index.js"; +export * as breakdown from "./breakdown/index.js"; +export * from "./breakdown/types/index.js"; +export * from "./fields/client/requests/index.js"; +export * as fields from "./fields/index.js"; +export * from "./purchases/client/requests/index.js"; +export * as purchases from "./purchases/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/Client.ts new file mode 100644 index 00000000..681db19d --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/Client.ts @@ -0,0 +1,123 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace PurchasesClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class PurchasesClient { + protected readonly _options: PurchasesClient.Options; + + constructor(options: PurchasesClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Returns the original purchased amount on an order transaction + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.billing.PurchasesListRequest} request + * @param {PurchasesClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.billing.purchases.list("123456-7890-1234-5678-901234", { + * limit: 1.1 + * }) + */ + public list( + project_id: string, + request: Deepgram.manage.v1.projects.billing.PurchasesListRequest = {}, + requestOptions?: PurchasesClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, request, requestOptions)); + } + + private async __list( + project_id: string, + request: Deepgram.manage.v1.projects.billing.PurchasesListRequest = {}, + requestOptions?: PurchasesClient.RequestOptions, + ): Promise> { + const { limit } = request; + const _queryParams: Record = {}; + if (limit != null) { + _queryParams.limit = limit.toString(); + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/purchases`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.ListProjectPurchasesV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/purchases.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/requests/PurchasesListRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/requests/PurchasesListRequest.ts new file mode 100644 index 00000000..cdcb6f5c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/requests/PurchasesListRequest.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * limit: 1.1 + * } + */ +export interface PurchasesListRequest { + /** Number of results to return per page. Default 10. Range [1,1000] */ + limit?: number; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/requests/index.ts new file mode 100644 index 00000000..df5a759a --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/client/requests/index.ts @@ -0,0 +1 @@ +export type { PurchasesListRequest } from "./PurchasesListRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/billing/resources/purchases/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/index.ts new file mode 100644 index 00000000..e8368d6c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/index.ts @@ -0,0 +1,13 @@ +export * as billing from "./billing/index.js"; +export * from "./keys/client/requests/index.js"; +export * as keys from "./keys/index.js"; +export * from "./keys/types/index.js"; +export * as members from "./members/index.js"; +export * from "./models/client/requests/index.js"; +export * as models from "./models/index.js"; +export * from "./requests/client/requests/index.js"; +export * as requests from "./requests/index.js"; +export * from "./requests/types/index.js"; +export * from "./usage/client/requests/index.js"; +export * as usage from "./usage/index.js"; +export * from "./usage/types/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/Client.ts new file mode 100644 index 00000000..e05c1391 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/Client.ts @@ -0,0 +1,377 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../index.js"; + +export declare namespace KeysClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class KeysClient { + protected readonly _options: KeysClient.Options; + + constructor(options: KeysClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Retrieves all API keys associated with the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.KeysListRequest} request + * @param {KeysClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.keys.list("123456-7890-1234-5678-901234", { + * status: "active" + * }) + */ + public list( + project_id: string, + request: Deepgram.manage.v1.projects.KeysListRequest = {}, + requestOptions?: KeysClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, request, requestOptions)); + } + + private async __list( + project_id: string, + request: Deepgram.manage.v1.projects.KeysListRequest = {}, + requestOptions?: KeysClient.RequestOptions, + ): Promise> { + const { status } = request; + const _queryParams: Record = {}; + if (status != null) { + _queryParams.status = status; + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/keys`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.ListProjectKeysV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/keys.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Creates a new API key with specified settings for the project + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.CreateKeyV1RequestOne} request + * @param {KeysClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.keys.create("project_id", { + * "key": "value" + * }) + */ + public create( + project_id: string, + request?: Deepgram.CreateKeyV1RequestOne, + requestOptions?: KeysClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__create(project_id, request, requestOptions)); + } + + private async __create( + project_id: string, + request?: Deepgram.CreateKeyV1RequestOne, + requestOptions?: KeysClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/keys`, + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryParameters: requestOptions?.queryParams, + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.CreateKeyV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling POST /v1/projects/{project_id}/keys.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Retrieves information about a specified API key + * + * @param {string} project_id - The unique identifier of the project + * @param {string} key_id - The unique identifier of the API key + * @param {KeysClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.keys.get("123456-7890-1234-5678-901234", "123456789012345678901234") + */ + public get( + project_id: string, + key_id: string, + requestOptions?: KeysClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__get(project_id, key_id, requestOptions)); + } + + private async __get( + project_id: string, + key_id: string, + requestOptions?: KeysClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/keys/${core.url.encodePathParam(key_id)}`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.GetProjectKeyV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/keys/{key_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Deletes an API key for a specific project + * + * @param {string} project_id - The unique identifier of the project + * @param {string} key_id - The unique identifier of the API key + * @param {KeysClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.keys.delete("123456-7890-1234-5678-901234", "123456789012345678901234") + */ + public delete( + project_id: string, + key_id: string, + requestOptions?: KeysClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__delete(project_id, key_id, requestOptions)); + } + + private async __delete( + project_id: string, + key_id: string, + requestOptions?: KeysClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/keys/${core.url.encodePathParam(key_id)}`, + ), + method: "DELETE", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.DeleteProjectKeyV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling DELETE /v1/projects/{project_id}/keys/{key_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/requests/KeysListRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/requests/KeysListRequest.ts new file mode 100644 index 00000000..97cc0a93 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/requests/KeysListRequest.ts @@ -0,0 +1,14 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../../../index.js"; + +/** + * @example + * { + * status: "active" + * } + */ +export interface KeysListRequest { + /** Only return keys with a specific status */ + status?: Deepgram.manage.v1.projects.KeysListRequestStatus; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/requests/index.ts new file mode 100644 index 00000000..eed0c195 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/client/requests/index.ts @@ -0,0 +1 @@ +export type { KeysListRequest } from "./KeysListRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/keys/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/keys/types/KeysListRequestStatus.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/types/KeysListRequestStatus.ts new file mode 100644 index 00000000..3104824d --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/types/KeysListRequestStatus.ts @@ -0,0 +1,7 @@ +// This file was auto-generated by Fern from our API Definition. + +export const KeysListRequestStatus = { + Active: "active", + Expired: "expired", +} as const; +export type KeysListRequestStatus = (typeof KeysListRequestStatus)[keyof typeof KeysListRequestStatus]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/keys/types/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/types/index.ts new file mode 100644 index 00000000..2d99304b --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/keys/types/index.ts @@ -0,0 +1 @@ +export * from "./KeysListRequestStatus.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/client/Client.ts new file mode 100644 index 00000000..2c4e2f6f --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/client/Client.ts @@ -0,0 +1,211 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../index.js"; +import { InvitesClient } from "../resources/invites/client/Client.js"; +import { ScopesClient } from "../resources/scopes/client/Client.js"; + +export declare namespace MembersClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class MembersClient { + protected readonly _options: MembersClient.Options; + protected _invites: InvitesClient | undefined; + protected _scopes: ScopesClient | undefined; + + constructor(options: MembersClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get invites(): InvitesClient { + return (this._invites ??= new InvitesClient(this._options)); + } + + public get scopes(): ScopesClient { + return (this._scopes ??= new ScopesClient(this._options)); + } + + /** + * Retrieves a list of members for a given project + * + * @param {string} project_id - The unique identifier of the project + * @param {MembersClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.members.list("123456-7890-1234-5678-901234") + */ + public list( + project_id: string, + requestOptions?: MembersClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, requestOptions)); + } + + private async __list( + project_id: string, + requestOptions?: MembersClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/members`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.ListProjectMembersV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/members.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Removes a member from the project using their unique member ID + * + * @param {string} project_id - The unique identifier of the project + * @param {string} member_id - The unique identifier of the Member + * @param {MembersClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.members.delete("123456-7890-1234-5678-901234", "123456789012345678901234") + */ + public delete( + project_id: string, + member_id: string, + requestOptions?: MembersClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__delete(project_id, member_id, requestOptions)); + } + + private async __delete( + project_id: string, + member_id: string, + requestOptions?: MembersClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/members/${core.url.encodePathParam(member_id)}`, + ), + method: "DELETE", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.DeleteProjectMemberV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling DELETE /v1/projects/{project_id}/members/{member_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/index.ts new file mode 100644 index 00000000..ec0d1d84 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/index.ts @@ -0,0 +1,4 @@ +export * from "./invites/client/requests/index.js"; +export * as invites from "./invites/index.js"; +export * from "./scopes/client/requests/index.js"; +export * as scopes from "./scopes/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/Client.ts new file mode 100644 index 00000000..e7d60284 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/Client.ts @@ -0,0 +1,292 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace InvitesClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class InvitesClient { + protected readonly _options: InvitesClient.Options; + + constructor(options: InvitesClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Generates a list of invites for a specific project + * + * @param {string} project_id - The unique identifier of the project + * @param {InvitesClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.members.invites.list("123456-7890-1234-5678-901234") + */ + public list( + project_id: string, + requestOptions?: InvitesClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, requestOptions)); + } + + private async __list( + project_id: string, + requestOptions?: InvitesClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/invites`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.ListProjectInvitesV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/invites.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Generates an invite for a specific project + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.members.CreateProjectInviteV1Request} request + * @param {InvitesClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.members.invites.create("123456-7890-1234-5678-901234", { + * email: "email", + * scope: "scope" + * }) + */ + public create( + project_id: string, + request: Deepgram.manage.v1.projects.members.CreateProjectInviteV1Request, + requestOptions?: InvitesClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__create(project_id, request, requestOptions)); + } + + private async __create( + project_id: string, + request: Deepgram.manage.v1.projects.members.CreateProjectInviteV1Request, + requestOptions?: InvitesClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/invites`, + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryParameters: requestOptions?.queryParams, + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.CreateProjectInviteV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling POST /v1/projects/{project_id}/invites.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Deletes an invite for a specific project + * + * @param {string} project_id - The unique identifier of the project + * @param {string} email - The email address of the member + * @param {InvitesClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.members.invites.delete("123456-7890-1234-5678-901234", "john.doe@example.com") + */ + public delete( + project_id: string, + email: string, + requestOptions?: InvitesClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__delete(project_id, email, requestOptions)); + } + + private async __delete( + project_id: string, + email: string, + requestOptions?: InvitesClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/invites/${core.url.encodePathParam(email)}`, + ), + method: "DELETE", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.DeleteProjectInviteV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling DELETE /v1/projects/{project_id}/invites/{email}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/requests/CreateProjectInviteV1Request.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/requests/CreateProjectInviteV1Request.ts new file mode 100644 index 00000000..6fe9bd0a --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/requests/CreateProjectInviteV1Request.ts @@ -0,0 +1,15 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * email: "email", + * scope: "scope" + * } + */ +export interface CreateProjectInviteV1Request { + /** The email address of the invitee */ + email: string; + /** The scope of the invitee */ + scope: string; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/requests/index.ts new file mode 100644 index 00000000..49ad1b42 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/client/requests/index.ts @@ -0,0 +1 @@ +export type { CreateProjectInviteV1Request } from "./CreateProjectInviteV1Request.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/invites/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/Client.ts new file mode 100644 index 00000000..923091ff --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/Client.ts @@ -0,0 +1,210 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace ScopesClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class ScopesClient { + protected readonly _options: ScopesClient.Options; + + constructor(options: ScopesClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Retrieves a list of scopes for a specific member + * + * @param {string} project_id - The unique identifier of the project + * @param {string} member_id - The unique identifier of the Member + * @param {ScopesClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.members.scopes.list("123456-7890-1234-5678-901234", "123456789012345678901234") + */ + public list( + project_id: string, + member_id: string, + requestOptions?: ScopesClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, member_id, requestOptions)); + } + + private async __list( + project_id: string, + member_id: string, + requestOptions?: ScopesClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/members/${core.url.encodePathParam(member_id)}/scopes`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.ListProjectMemberScopesV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/members/{member_id}/scopes.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Updates the scopes for a specific member + * + * @param {string} project_id - The unique identifier of the project + * @param {string} member_id - The unique identifier of the Member + * @param {Deepgram.manage.v1.projects.members.UpdateProjectMemberScopesV1Request} request + * @param {ScopesClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.members.scopes.update("123456-7890-1234-5678-901234", "123456789012345678901234", { + * scope: "admin" + * }) + */ + public update( + project_id: string, + member_id: string, + request: Deepgram.manage.v1.projects.members.UpdateProjectMemberScopesV1Request, + requestOptions?: ScopesClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__update(project_id, member_id, request, requestOptions)); + } + + private async __update( + project_id: string, + member_id: string, + request: Deepgram.manage.v1.projects.members.UpdateProjectMemberScopesV1Request, + requestOptions?: ScopesClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/members/${core.url.encodePathParam(member_id)}/scopes`, + ), + method: "PUT", + headers: _headers, + contentType: "application/json", + queryParameters: requestOptions?.queryParams, + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.UpdateProjectMemberScopesV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling PUT /v1/projects/{project_id}/members/{member_id}/scopes.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/requests/UpdateProjectMemberScopesV1Request.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/requests/UpdateProjectMemberScopesV1Request.ts new file mode 100644 index 00000000..a1ae9416 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/requests/UpdateProjectMemberScopesV1Request.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * scope: "admin" + * } + */ +export interface UpdateProjectMemberScopesV1Request { + /** A scope to update */ + scope: string; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/requests/index.ts new file mode 100644 index 00000000..c5864e8b --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/client/requests/index.ts @@ -0,0 +1 @@ +export type { UpdateProjectMemberScopesV1Request } from "./UpdateProjectMemberScopesV1Request.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/members/resources/scopes/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/Client.ts new file mode 100644 index 00000000..59841f0e --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/Client.ts @@ -0,0 +1,204 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../index.js"; + +export declare namespace ModelsClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class ModelsClient { + protected readonly _options: ModelsClient.Options; + + constructor(options: ModelsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Returns metadata on all the latest models that a specific project has access to, including non-public models + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.ModelsListRequest} request + * @param {ModelsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.models.list("123456-7890-1234-5678-901234", { + * include_outdated: true + * }) + */ + public list( + project_id: string, + request: Deepgram.manage.v1.projects.ModelsListRequest = {}, + requestOptions?: ModelsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, request, requestOptions)); + } + + private async __list( + project_id: string, + request: Deepgram.manage.v1.projects.ModelsListRequest = {}, + requestOptions?: ModelsClient.RequestOptions, + ): Promise> { + const { include_outdated: includeOutdated } = request; + const _queryParams: Record = {}; + if (includeOutdated != null) { + _queryParams.include_outdated = includeOutdated.toString(); + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/models`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.ListModelsV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/models.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Returns metadata for a specific model + * + * @param {string} project_id - The unique identifier of the project + * @param {string} model_id - The specific UUID of the model + * @param {ModelsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.models.get("123456-7890-1234-5678-901234", "af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291") + */ + public get( + project_id: string, + model_id: string, + requestOptions?: ModelsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__get(project_id, model_id, requestOptions)); + } + + private async __get( + project_id: string, + model_id: string, + requestOptions?: ModelsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/models/${core.url.encodePathParam(model_id)}`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.GetModelV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/models/{model_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/requests/ModelsListRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/requests/ModelsListRequest.ts new file mode 100644 index 00000000..b2183044 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/requests/ModelsListRequest.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * include_outdated: true + * } + */ +export interface ModelsListRequest { + /** returns non-latest versions of models */ + include_outdated?: boolean; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/requests/index.ts new file mode 100644 index 00000000..7197c55a --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/models/client/requests/index.ts @@ -0,0 +1 @@ +export type { ModelsListRequest } from "./ModelsListRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/models/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/models/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/models/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/Client.ts new file mode 100644 index 00000000..a41e8a15 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/Client.ts @@ -0,0 +1,263 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../index.js"; + +export declare namespace RequestsClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class RequestsClient { + protected readonly _options: RequestsClient.Options; + + constructor(options: RequestsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Generates a list of requests for a specific project + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.RequestsListRequest} request + * @param {RequestsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.requests.list("123456-7890-1234-5678-901234", { + * start: "2024-01-15T09:30:00Z", + * end: "2024-01-15T09:30:00Z", + * limit: 1.1, + * page: 1.1, + * accessor: "12345678-1234-1234-1234-123456789012", + * request_id: "12345678-1234-1234-1234-123456789012", + * deployment: "hosted", + * endpoint: "listen", + * method: "sync", + * status: "succeeded" + * }) + */ + public list( + project_id: string, + request: Deepgram.manage.v1.projects.RequestsListRequest = {}, + requestOptions?: RequestsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, request, requestOptions)); + } + + private async __list( + project_id: string, + request: Deepgram.manage.v1.projects.RequestsListRequest = {}, + requestOptions?: RequestsClient.RequestOptions, + ): Promise> { + const { + start, + end, + limit, + page, + accessor, + request_id: requestId, + deployment, + endpoint, + method, + status, + } = request; + const _queryParams: Record = {}; + if (start != null) { + _queryParams.start = start; + } + + if (end != null) { + _queryParams.end = end; + } + + if (limit != null) { + _queryParams.limit = limit.toString(); + } + + if (page != null) { + _queryParams.page = page.toString(); + } + + if (accessor != null) { + _queryParams.accessor = accessor; + } + + if (requestId != null) { + _queryParams.request_id = requestId; + } + + if (deployment != null) { + _queryParams.deployment = deployment; + } + + if (endpoint != null) { + _queryParams.endpoint = endpoint; + } + + if (method != null) { + _queryParams.method = method; + } + + if (status != null) { + _queryParams.status = status; + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/requests`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.ListProjectRequestsV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/requests.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Retrieves a specific request for a specific project + * + * @param {string} project_id - The unique identifier of the project + * @param {string} request_id - The unique identifier of the request + * @param {RequestsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.requests.get("123456-7890-1234-5678-901234", "123456-7890-1234-5678-901234") + */ + public get( + project_id: string, + request_id: string, + requestOptions?: RequestsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__get(project_id, request_id, requestOptions)); + } + + private async __get( + project_id: string, + request_id: string, + requestOptions?: RequestsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/requests/${core.url.encodePathParam(request_id)}`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.GetProjectRequestV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/requests/{request_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/requests/RequestsListRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/requests/RequestsListRequest.ts new file mode 100644 index 00000000..17d40de5 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/requests/RequestsListRequest.ts @@ -0,0 +1,41 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../../../index.js"; + +/** + * @example + * { + * start: "2024-01-15T09:30:00Z", + * end: "2024-01-15T09:30:00Z", + * limit: 1.1, + * page: 1.1, + * accessor: "12345678-1234-1234-1234-123456789012", + * request_id: "12345678-1234-1234-1234-123456789012", + * deployment: "hosted", + * endpoint: "listen", + * method: "sync", + * status: "succeeded" + * } + */ +export interface RequestsListRequest { + /** Start date of the requested date range. Formats accepted are YYYY-MM-DD, YYYY-MM-DDTHH:MM:SS, or YYYY-MM-DDTHH:MM:SS+HH:MM */ + start?: string; + /** End date of the requested date range. Formats accepted are YYYY-MM-DD, YYYY-MM-DDTHH:MM:SS, or YYYY-MM-DDTHH:MM:SS+HH:MM */ + end?: string; + /** Number of results to return per page. Default 10. Range [1,1000] */ + limit?: number; + /** Navigate and return the results to retrieve specific portions of information of the response */ + page?: number; + /** Filter for requests where a specific accessor was used */ + accessor?: string; + /** Filter for a specific request id */ + request_id?: string; + /** Filter for requests where a specific deployment was used */ + deployment?: Deepgram.manage.v1.projects.RequestsListRequestDeployment; + /** Filter for requests where a specific endpoint was used */ + endpoint?: Deepgram.manage.v1.projects.RequestsListRequestEndpoint; + /** Filter for requests where a specific method was used */ + method?: Deepgram.manage.v1.projects.RequestsListRequestMethod; + /** Filter for requests that succeeded (status code < 300) or failed (status code >=400) */ + status?: Deepgram.manage.v1.projects.RequestsListRequestStatus; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/requests/index.ts new file mode 100644 index 00000000..8c9f754b --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/client/requests/index.ts @@ -0,0 +1 @@ +export type { RequestsListRequest } from "./RequestsListRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestDeployment.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestDeployment.ts new file mode 100644 index 00000000..be9d0361 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestDeployment.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Deployment type for the requests */ +export const RequestsListRequestDeployment = { + Hosted: "hosted", + Beta: "beta", + SelfHosted: "self-hosted", +} as const; +export type RequestsListRequestDeployment = + (typeof RequestsListRequestDeployment)[keyof typeof RequestsListRequestDeployment]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestEndpoint.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestEndpoint.ts new file mode 100644 index 00000000..b50dd80b --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestEndpoint.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export const RequestsListRequestEndpoint = { + Listen: "listen", + Read: "read", + Speak: "speak", + Agent: "agent", +} as const; +export type RequestsListRequestEndpoint = + (typeof RequestsListRequestEndpoint)[keyof typeof RequestsListRequestEndpoint]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestMethod.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestMethod.ts new file mode 100644 index 00000000..9cb05a4a --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestMethod.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Method type for the request */ +export const RequestsListRequestMethod = { + Sync: "sync", + Async: "async", + Streaming: "streaming", +} as const; +export type RequestsListRequestMethod = (typeof RequestsListRequestMethod)[keyof typeof RequestsListRequestMethod]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestStatus.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestStatus.ts new file mode 100644 index 00000000..564c48da --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/RequestsListRequestStatus.ts @@ -0,0 +1,7 @@ +// This file was auto-generated by Fern from our API Definition. + +export const RequestsListRequestStatus = { + Succeeded: "succeeded", + Failed: "failed", +} as const; +export type RequestsListRequestStatus = (typeof RequestsListRequestStatus)[keyof typeof RequestsListRequestStatus]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/index.ts new file mode 100644 index 00000000..fec800d1 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/requests/types/index.ts @@ -0,0 +1,4 @@ +export * from "./RequestsListRequestDeployment.js"; +export * from "./RequestsListRequestEndpoint.js"; +export * from "./RequestsListRequestMethod.js"; +export * from "./RequestsListRequestStatus.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/Client.ts new file mode 100644 index 00000000..fa916a98 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/Client.ts @@ -0,0 +1,392 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../index.js"; +import { BreakdownClient } from "../resources/breakdown/client/Client.js"; +import { FieldsClient } from "../resources/fields/client/Client.js"; + +export declare namespace UsageClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class UsageClient { + protected readonly _options: UsageClient.Options; + protected _breakdown: BreakdownClient | undefined; + protected _fields: FieldsClient | undefined; + + constructor(options: UsageClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get breakdown(): BreakdownClient { + return (this._breakdown ??= new BreakdownClient(this._options)); + } + + public get fields(): FieldsClient { + return (this._fields ??= new FieldsClient(this._options)); + } + + /** + * Retrieves the usage for a specific project. Use Get Project Usage Breakdown for a more comprehensive usage summary. + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.UsageGetRequest} request + * @param {UsageClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.usage.get("123456-7890-1234-5678-901234", { + * start: "start", + * end: "end", + * accessor: "12345678-1234-1234-1234-123456789012", + * alternatives: true, + * callback_method: true, + * callback: true, + * channels: true, + * custom_intent_mode: true, + * custom_intent: true, + * custom_topic_mode: true, + * custom_topic: true, + * deployment: "hosted", + * detect_entities: true, + * detect_language: true, + * diarize: true, + * dictation: true, + * encoding: true, + * endpoint: "listen", + * extra: true, + * filler_words: true, + * intents: true, + * keyterm: true, + * keywords: true, + * language: true, + * measurements: true, + * method: "sync", + * model: "6f548761-c9c0-429a-9315-11a1d28499c8", + * multichannel: true, + * numerals: true, + * paragraphs: true, + * profanity_filter: true, + * punctuate: true, + * redact: true, + * replace: true, + * sample_rate: true, + * search: true, + * sentiment: true, + * smart_format: true, + * summarize: true, + * tag: "tag1", + * topics: true, + * utt_split: true, + * utterances: true, + * version: true + * }) + */ + public get( + project_id: string, + request: Deepgram.manage.v1.projects.UsageGetRequest = {}, + requestOptions?: UsageClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__get(project_id, request, requestOptions)); + } + + private async __get( + project_id: string, + request: Deepgram.manage.v1.projects.UsageGetRequest = {}, + requestOptions?: UsageClient.RequestOptions, + ): Promise> { + const { + start, + end, + accessor, + alternatives, + callback_method: callbackMethod, + callback, + channels, + custom_intent_mode: customIntentMode, + custom_intent: customIntent, + custom_topic_mode: customTopicMode, + custom_topic: customTopic, + deployment, + detect_entities: detectEntities, + detect_language: detectLanguage, + diarize, + dictation, + encoding, + endpoint, + extra, + filler_words: fillerWords, + intents, + keyterm, + keywords, + language, + measurements, + method, + model, + multichannel, + numerals, + paragraphs, + profanity_filter: profanityFilter, + punctuate, + redact, + replace, + sample_rate: sampleRate, + search, + sentiment, + smart_format: smartFormat, + summarize, + tag, + topics, + utt_split: uttSplit, + utterances, + version, + } = request; + const _queryParams: Record = {}; + if (start != null) { + _queryParams.start = start; + } + + if (end != null) { + _queryParams.end = end; + } + + if (accessor != null) { + _queryParams.accessor = accessor; + } + + if (alternatives != null) { + _queryParams.alternatives = alternatives.toString(); + } + + if (callbackMethod != null) { + _queryParams.callback_method = callbackMethod.toString(); + } + + if (callback != null) { + _queryParams.callback = callback.toString(); + } + + if (channels != null) { + _queryParams.channels = channels.toString(); + } + + if (customIntentMode != null) { + _queryParams.custom_intent_mode = customIntentMode.toString(); + } + + if (customIntent != null) { + _queryParams.custom_intent = customIntent.toString(); + } + + if (customTopicMode != null) { + _queryParams.custom_topic_mode = customTopicMode.toString(); + } + + if (customTopic != null) { + _queryParams.custom_topic = customTopic.toString(); + } + + if (deployment != null) { + _queryParams.deployment = deployment; + } + + if (detectEntities != null) { + _queryParams.detect_entities = detectEntities.toString(); + } + + if (detectLanguage != null) { + _queryParams.detect_language = detectLanguage.toString(); + } + + if (diarize != null) { + _queryParams.diarize = diarize.toString(); + } + + if (dictation != null) { + _queryParams.dictation = dictation.toString(); + } + + if (encoding != null) { + _queryParams.encoding = encoding.toString(); + } + + if (endpoint != null) { + _queryParams.endpoint = endpoint; + } + + if (extra != null) { + _queryParams.extra = extra.toString(); + } + + if (fillerWords != null) { + _queryParams.filler_words = fillerWords.toString(); + } + + if (intents != null) { + _queryParams.intents = intents.toString(); + } + + if (keyterm != null) { + _queryParams.keyterm = keyterm.toString(); + } + + if (keywords != null) { + _queryParams.keywords = keywords.toString(); + } + + if (language != null) { + _queryParams.language = language.toString(); + } + + if (measurements != null) { + _queryParams.measurements = measurements.toString(); + } + + if (method != null) { + _queryParams.method = method; + } + + if (model != null) { + _queryParams.model = model; + } + + if (multichannel != null) { + _queryParams.multichannel = multichannel.toString(); + } + + if (numerals != null) { + _queryParams.numerals = numerals.toString(); + } + + if (paragraphs != null) { + _queryParams.paragraphs = paragraphs.toString(); + } + + if (profanityFilter != null) { + _queryParams.profanity_filter = profanityFilter.toString(); + } + + if (punctuate != null) { + _queryParams.punctuate = punctuate.toString(); + } + + if (redact != null) { + _queryParams.redact = redact.toString(); + } + + if (replace != null) { + _queryParams.replace = replace.toString(); + } + + if (sampleRate != null) { + _queryParams.sample_rate = sampleRate.toString(); + } + + if (search != null) { + _queryParams.search = search.toString(); + } + + if (sentiment != null) { + _queryParams.sentiment = sentiment.toString(); + } + + if (smartFormat != null) { + _queryParams.smart_format = smartFormat.toString(); + } + + if (summarize != null) { + _queryParams.summarize = summarize.toString(); + } + + if (tag != null) { + _queryParams.tag = tag; + } + + if (topics != null) { + _queryParams.topics = topics.toString(); + } + + if (uttSplit != null) { + _queryParams.utt_split = uttSplit.toString(); + } + + if (utterances != null) { + _queryParams.utterances = utterances.toString(); + } + + if (version != null) { + _queryParams.version = version.toString(); + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/usage`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.UsageV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/usage.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/requests/UsageGetRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/requests/UsageGetRequest.ts new file mode 100644 index 00000000..492709d3 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/requests/UsageGetRequest.ts @@ -0,0 +1,143 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../../../index.js"; + +/** + * @example + * { + * start: "start", + * end: "end", + * accessor: "12345678-1234-1234-1234-123456789012", + * alternatives: true, + * callback_method: true, + * callback: true, + * channels: true, + * custom_intent_mode: true, + * custom_intent: true, + * custom_topic_mode: true, + * custom_topic: true, + * deployment: "hosted", + * detect_entities: true, + * detect_language: true, + * diarize: true, + * dictation: true, + * encoding: true, + * endpoint: "listen", + * extra: true, + * filler_words: true, + * intents: true, + * keyterm: true, + * keywords: true, + * language: true, + * measurements: true, + * method: "sync", + * model: "6f548761-c9c0-429a-9315-11a1d28499c8", + * multichannel: true, + * numerals: true, + * paragraphs: true, + * profanity_filter: true, + * punctuate: true, + * redact: true, + * replace: true, + * sample_rate: true, + * search: true, + * sentiment: true, + * smart_format: true, + * summarize: true, + * tag: "tag1", + * topics: true, + * utt_split: true, + * utterances: true, + * version: true + * } + */ +export interface UsageGetRequest { + /** Start date of the requested date range. Format accepted is YYYY-MM-DD */ + start?: string; + /** End date of the requested date range. Format accepted is YYYY-MM-DD */ + end?: string; + /** Filter for requests where a specific accessor was used */ + accessor?: string; + /** Filter for requests where alternatives were used */ + alternatives?: boolean; + /** Filter for requests where callback method was used */ + callback_method?: boolean; + /** Filter for requests where callback was used */ + callback?: boolean; + /** Filter for requests where channels were used */ + channels?: boolean; + /** Filter for requests where custom intent mode was used */ + custom_intent_mode?: boolean; + /** Filter for requests where custom intent was used */ + custom_intent?: boolean; + /** Filter for requests where custom topic mode was used */ + custom_topic_mode?: boolean; + /** Filter for requests where custom topic was used */ + custom_topic?: boolean; + /** Filter for requests where a specific deployment was used */ + deployment?: Deepgram.manage.v1.projects.UsageGetRequestDeployment; + /** Filter for requests where detect entities was used */ + detect_entities?: boolean; + /** Filter for requests where detect language was used */ + detect_language?: boolean; + /** Filter for requests where diarize was used */ + diarize?: boolean; + /** Filter for requests where dictation was used */ + dictation?: boolean; + /** Filter for requests where encoding was used */ + encoding?: boolean; + /** Filter for requests where a specific endpoint was used */ + endpoint?: Deepgram.manage.v1.projects.UsageGetRequestEndpoint; + /** Filter for requests where extra was used */ + extra?: boolean; + /** Filter for requests where filler words was used */ + filler_words?: boolean; + /** Filter for requests where intents was used */ + intents?: boolean; + /** Filter for requests where keyterm was used */ + keyterm?: boolean; + /** Filter for requests where keywords was used */ + keywords?: boolean; + /** Filter for requests where language was used */ + language?: boolean; + /** Filter for requests where measurements were used */ + measurements?: boolean; + /** Filter for requests where a specific method was used */ + method?: Deepgram.manage.v1.projects.UsageGetRequestMethod; + /** Filter for requests where a specific model uuid was used */ + model?: string; + /** Filter for requests where multichannel was used */ + multichannel?: boolean; + /** Filter for requests where numerals were used */ + numerals?: boolean; + /** Filter for requests where paragraphs were used */ + paragraphs?: boolean; + /** Filter for requests where profanity filter was used */ + profanity_filter?: boolean; + /** Filter for requests where punctuate was used */ + punctuate?: boolean; + /** Filter for requests where redact was used */ + redact?: boolean; + /** Filter for requests where replace was used */ + replace?: boolean; + /** Filter for requests where sample rate was used */ + sample_rate?: boolean; + /** Filter for requests where search was used */ + search?: boolean; + /** Filter for requests where sentiment was used */ + sentiment?: boolean; + /** Filter for requests where smart format was used */ + smart_format?: boolean; + /** Filter for requests where summarize was used */ + summarize?: boolean; + /** Filter for requests where a specific tag was used */ + tag?: string; + /** Filter for requests where topics was used */ + topics?: boolean; + /** Filter for requests where utt split was used */ + utt_split?: boolean; + /** Filter for requests where utterances was used */ + utterances?: boolean; + /** Filter for requests where version was used */ + version?: boolean; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/requests/index.ts new file mode 100644 index 00000000..6a2dfd92 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/client/requests/index.ts @@ -0,0 +1 @@ +export type { UsageGetRequest } from "./UsageGetRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/index.ts new file mode 100644 index 00000000..0ef16e76 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/index.ts @@ -0,0 +1,3 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/Client.ts new file mode 100644 index 00000000..1c96660a --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/Client.ts @@ -0,0 +1,386 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace BreakdownClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class BreakdownClient { + protected readonly _options: BreakdownClient.Options; + + constructor(options: BreakdownClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Retrieves the usage breakdown for a specific project, with various filter options by API feature or by groupings. Setting a feature (e.g. diarize) to true includes requests that used that feature, while false excludes requests that used it. Multiple true filters are combined with OR logic, while false filters use AND logic. + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.usage.BreakdownGetRequest} request + * @param {BreakdownClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.usage.breakdown.get("123456-7890-1234-5678-901234", { + * start: "start", + * end: "end", + * grouping: "accessor", + * accessor: "12345678-1234-1234-1234-123456789012", + * alternatives: true, + * callback_method: true, + * callback: true, + * channels: true, + * custom_intent_mode: true, + * custom_intent: true, + * custom_topic_mode: true, + * custom_topic: true, + * deployment: "hosted", + * detect_entities: true, + * detect_language: true, + * diarize: true, + * dictation: true, + * encoding: true, + * endpoint: "listen", + * extra: true, + * filler_words: true, + * intents: true, + * keyterm: true, + * keywords: true, + * language: true, + * measurements: true, + * method: "sync", + * model: "6f548761-c9c0-429a-9315-11a1d28499c8", + * multichannel: true, + * numerals: true, + * paragraphs: true, + * profanity_filter: true, + * punctuate: true, + * redact: true, + * replace: true, + * sample_rate: true, + * search: true, + * sentiment: true, + * smart_format: true, + * summarize: true, + * tag: "tag1", + * topics: true, + * utt_split: true, + * utterances: true, + * version: true + * }) + */ + public get( + project_id: string, + request: Deepgram.manage.v1.projects.usage.BreakdownGetRequest = {}, + requestOptions?: BreakdownClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__get(project_id, request, requestOptions)); + } + + private async __get( + project_id: string, + request: Deepgram.manage.v1.projects.usage.BreakdownGetRequest = {}, + requestOptions?: BreakdownClient.RequestOptions, + ): Promise> { + const { + start, + end, + grouping, + accessor, + alternatives, + callback_method: callbackMethod, + callback, + channels, + custom_intent_mode: customIntentMode, + custom_intent: customIntent, + custom_topic_mode: customTopicMode, + custom_topic: customTopic, + deployment, + detect_entities: detectEntities, + detect_language: detectLanguage, + diarize, + dictation, + encoding, + endpoint, + extra, + filler_words: fillerWords, + intents, + keyterm, + keywords, + language, + measurements, + method, + model, + multichannel, + numerals, + paragraphs, + profanity_filter: profanityFilter, + punctuate, + redact, + replace, + sample_rate: sampleRate, + search, + sentiment, + smart_format: smartFormat, + summarize, + tag, + topics, + utt_split: uttSplit, + utterances, + version, + } = request; + const _queryParams: Record = {}; + if (start != null) { + _queryParams.start = start; + } + + if (end != null) { + _queryParams.end = end; + } + + if (grouping != null) { + _queryParams.grouping = grouping; + } + + if (accessor != null) { + _queryParams.accessor = accessor; + } + + if (alternatives != null) { + _queryParams.alternatives = alternatives.toString(); + } + + if (callbackMethod != null) { + _queryParams.callback_method = callbackMethod.toString(); + } + + if (callback != null) { + _queryParams.callback = callback.toString(); + } + + if (channels != null) { + _queryParams.channels = channels.toString(); + } + + if (customIntentMode != null) { + _queryParams.custom_intent_mode = customIntentMode.toString(); + } + + if (customIntent != null) { + _queryParams.custom_intent = customIntent.toString(); + } + + if (customTopicMode != null) { + _queryParams.custom_topic_mode = customTopicMode.toString(); + } + + if (customTopic != null) { + _queryParams.custom_topic = customTopic.toString(); + } + + if (deployment != null) { + _queryParams.deployment = deployment; + } + + if (detectEntities != null) { + _queryParams.detect_entities = detectEntities.toString(); + } + + if (detectLanguage != null) { + _queryParams.detect_language = detectLanguage.toString(); + } + + if (diarize != null) { + _queryParams.diarize = diarize.toString(); + } + + if (dictation != null) { + _queryParams.dictation = dictation.toString(); + } + + if (encoding != null) { + _queryParams.encoding = encoding.toString(); + } + + if (endpoint != null) { + _queryParams.endpoint = endpoint; + } + + if (extra != null) { + _queryParams.extra = extra.toString(); + } + + if (fillerWords != null) { + _queryParams.filler_words = fillerWords.toString(); + } + + if (intents != null) { + _queryParams.intents = intents.toString(); + } + + if (keyterm != null) { + _queryParams.keyterm = keyterm.toString(); + } + + if (keywords != null) { + _queryParams.keywords = keywords.toString(); + } + + if (language != null) { + _queryParams.language = language.toString(); + } + + if (measurements != null) { + _queryParams.measurements = measurements.toString(); + } + + if (method != null) { + _queryParams.method = method; + } + + if (model != null) { + _queryParams.model = model; + } + + if (multichannel != null) { + _queryParams.multichannel = multichannel.toString(); + } + + if (numerals != null) { + _queryParams.numerals = numerals.toString(); + } + + if (paragraphs != null) { + _queryParams.paragraphs = paragraphs.toString(); + } + + if (profanityFilter != null) { + _queryParams.profanity_filter = profanityFilter.toString(); + } + + if (punctuate != null) { + _queryParams.punctuate = punctuate.toString(); + } + + if (redact != null) { + _queryParams.redact = redact.toString(); + } + + if (replace != null) { + _queryParams.replace = replace.toString(); + } + + if (sampleRate != null) { + _queryParams.sample_rate = sampleRate.toString(); + } + + if (search != null) { + _queryParams.search = search.toString(); + } + + if (sentiment != null) { + _queryParams.sentiment = sentiment.toString(); + } + + if (smartFormat != null) { + _queryParams.smart_format = smartFormat.toString(); + } + + if (summarize != null) { + _queryParams.summarize = summarize.toString(); + } + + if (tag != null) { + _queryParams.tag = tag; + } + + if (topics != null) { + _queryParams.topics = topics.toString(); + } + + if (uttSplit != null) { + _queryParams.utt_split = uttSplit.toString(); + } + + if (utterances != null) { + _queryParams.utterances = utterances.toString(); + } + + if (version != null) { + _queryParams.version = version.toString(); + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/usage/breakdown`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.UsageBreakdownV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/usage/breakdown.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/requests/BreakdownGetRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/requests/BreakdownGetRequest.ts new file mode 100644 index 00000000..9e300981 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/requests/BreakdownGetRequest.ts @@ -0,0 +1,146 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../../../../../index.js"; + +/** + * @example + * { + * start: "start", + * end: "end", + * grouping: "accessor", + * accessor: "12345678-1234-1234-1234-123456789012", + * alternatives: true, + * callback_method: true, + * callback: true, + * channels: true, + * custom_intent_mode: true, + * custom_intent: true, + * custom_topic_mode: true, + * custom_topic: true, + * deployment: "hosted", + * detect_entities: true, + * detect_language: true, + * diarize: true, + * dictation: true, + * encoding: true, + * endpoint: "listen", + * extra: true, + * filler_words: true, + * intents: true, + * keyterm: true, + * keywords: true, + * language: true, + * measurements: true, + * method: "sync", + * model: "6f548761-c9c0-429a-9315-11a1d28499c8", + * multichannel: true, + * numerals: true, + * paragraphs: true, + * profanity_filter: true, + * punctuate: true, + * redact: true, + * replace: true, + * sample_rate: true, + * search: true, + * sentiment: true, + * smart_format: true, + * summarize: true, + * tag: "tag1", + * topics: true, + * utt_split: true, + * utterances: true, + * version: true + * } + */ +export interface BreakdownGetRequest { + /** Start date of the requested date range. Format accepted is YYYY-MM-DD */ + start?: string; + /** End date of the requested date range. Format accepted is YYYY-MM-DD */ + end?: string; + /** Common usage grouping parameters */ + grouping?: Deepgram.manage.v1.projects.usage.BreakdownGetRequestGrouping; + /** Filter for requests where a specific accessor was used */ + accessor?: string; + /** Filter for requests where alternatives were used */ + alternatives?: boolean; + /** Filter for requests where callback method was used */ + callback_method?: boolean; + /** Filter for requests where callback was used */ + callback?: boolean; + /** Filter for requests where channels were used */ + channels?: boolean; + /** Filter for requests where custom intent mode was used */ + custom_intent_mode?: boolean; + /** Filter for requests where custom intent was used */ + custom_intent?: boolean; + /** Filter for requests where custom topic mode was used */ + custom_topic_mode?: boolean; + /** Filter for requests where custom topic was used */ + custom_topic?: boolean; + /** Filter for requests where a specific deployment was used */ + deployment?: Deepgram.manage.v1.projects.usage.BreakdownGetRequestDeployment; + /** Filter for requests where detect entities was used */ + detect_entities?: boolean; + /** Filter for requests where detect language was used */ + detect_language?: boolean; + /** Filter for requests where diarize was used */ + diarize?: boolean; + /** Filter for requests where dictation was used */ + dictation?: boolean; + /** Filter for requests where encoding was used */ + encoding?: boolean; + /** Filter for requests where a specific endpoint was used */ + endpoint?: Deepgram.manage.v1.projects.usage.BreakdownGetRequestEndpoint; + /** Filter for requests where extra was used */ + extra?: boolean; + /** Filter for requests where filler words was used */ + filler_words?: boolean; + /** Filter for requests where intents was used */ + intents?: boolean; + /** Filter for requests where keyterm was used */ + keyterm?: boolean; + /** Filter for requests where keywords was used */ + keywords?: boolean; + /** Filter for requests where language was used */ + language?: boolean; + /** Filter for requests where measurements were used */ + measurements?: boolean; + /** Filter for requests where a specific method was used */ + method?: Deepgram.manage.v1.projects.usage.BreakdownGetRequestMethod; + /** Filter for requests where a specific model uuid was used */ + model?: string; + /** Filter for requests where multichannel was used */ + multichannel?: boolean; + /** Filter for requests where numerals were used */ + numerals?: boolean; + /** Filter for requests where paragraphs were used */ + paragraphs?: boolean; + /** Filter for requests where profanity filter was used */ + profanity_filter?: boolean; + /** Filter for requests where punctuate was used */ + punctuate?: boolean; + /** Filter for requests where redact was used */ + redact?: boolean; + /** Filter for requests where replace was used */ + replace?: boolean; + /** Filter for requests where sample rate was used */ + sample_rate?: boolean; + /** Filter for requests where search was used */ + search?: boolean; + /** Filter for requests where sentiment was used */ + sentiment?: boolean; + /** Filter for requests where smart format was used */ + smart_format?: boolean; + /** Filter for requests where summarize was used */ + summarize?: boolean; + /** Filter for requests where a specific tag was used */ + tag?: string; + /** Filter for requests where topics was used */ + topics?: boolean; + /** Filter for requests where utt split was used */ + utt_split?: boolean; + /** Filter for requests where utterances was used */ + utterances?: boolean; + /** Filter for requests where version was used */ + version?: boolean; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/requests/index.ts new file mode 100644 index 00000000..3c23886e --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/client/requests/index.ts @@ -0,0 +1 @@ +export type { BreakdownGetRequest } from "./BreakdownGetRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestDeployment.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestDeployment.ts new file mode 100644 index 00000000..fcd546d7 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestDeployment.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Deployment type for the requests */ +export const BreakdownGetRequestDeployment = { + Hosted: "hosted", + Beta: "beta", + SelfHosted: "self-hosted", +} as const; +export type BreakdownGetRequestDeployment = + (typeof BreakdownGetRequestDeployment)[keyof typeof BreakdownGetRequestDeployment]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestEndpoint.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestEndpoint.ts new file mode 100644 index 00000000..df20577b --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestEndpoint.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export const BreakdownGetRequestEndpoint = { + Listen: "listen", + Read: "read", + Speak: "speak", + Agent: "agent", +} as const; +export type BreakdownGetRequestEndpoint = + (typeof BreakdownGetRequestEndpoint)[keyof typeof BreakdownGetRequestEndpoint]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestGrouping.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestGrouping.ts new file mode 100644 index 00000000..f5cdb10e --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestGrouping.ts @@ -0,0 +1,13 @@ +// This file was auto-generated by Fern from our API Definition. + +export const BreakdownGetRequestGrouping = { + Accessor: "accessor", + Endpoint: "endpoint", + FeatureSet: "feature_set", + Models: "models", + Method: "method", + Tags: "tags", + Deployment: "deployment", +} as const; +export type BreakdownGetRequestGrouping = + (typeof BreakdownGetRequestGrouping)[keyof typeof BreakdownGetRequestGrouping]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestMethod.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestMethod.ts new file mode 100644 index 00000000..fe955b10 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/BreakdownGetRequestMethod.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Method type for the request */ +export const BreakdownGetRequestMethod = { + Sync: "sync", + Async: "async", + Streaming: "streaming", +} as const; +export type BreakdownGetRequestMethod = (typeof BreakdownGetRequestMethod)[keyof typeof BreakdownGetRequestMethod]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/index.ts new file mode 100644 index 00000000..56882fb8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/breakdown/types/index.ts @@ -0,0 +1,4 @@ +export * from "./BreakdownGetRequestDeployment.js"; +export * from "./BreakdownGetRequestEndpoint.js"; +export * from "./BreakdownGetRequestGrouping.js"; +export * from "./BreakdownGetRequestMethod.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/Client.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/Client.ts new file mode 100644 index 00000000..4565fea2 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/Client.ts @@ -0,0 +1,125 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../../../../../index.js"; + +export declare namespace FieldsClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class FieldsClient { + protected readonly _options: FieldsClient.Options; + + constructor(options: FieldsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Lists the features, models, tags, languages, and processing method used for requests in the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.manage.v1.projects.usage.FieldsListRequest} request + * @param {FieldsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.manage.v1.projects.usage.fields.list("123456-7890-1234-5678-901234", { + * start: "start", + * end: "end" + * }) + */ + public list( + project_id: string, + request: Deepgram.manage.v1.projects.usage.FieldsListRequest = {}, + requestOptions?: FieldsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, request, requestOptions)); + } + + private async __list( + project_id: string, + request: Deepgram.manage.v1.projects.usage.FieldsListRequest = {}, + requestOptions?: FieldsClient.RequestOptions, + ): Promise> { + const { start, end } = request; + const _queryParams: Record = {}; + if (start != null) { + _queryParams.start = start; + } + + if (end != null) { + _queryParams.end = end; + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/usage/fields`, + ), + method: "GET", + headers: _headers, + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.UsageFieldsV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/usage/fields.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/requests/FieldsListRequest.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/requests/FieldsListRequest.ts new file mode 100644 index 00000000..d72af8d9 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/requests/FieldsListRequest.ts @@ -0,0 +1,15 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * start: "start", + * end: "end" + * } + */ +export interface FieldsListRequest { + /** Start date of the requested date range. Format accepted is YYYY-MM-DD */ + start?: string; + /** End date of the requested date range. Format accepted is YYYY-MM-DD */ + end?: string; +} diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/requests/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/requests/index.ts new file mode 100644 index 00000000..35ea45ea --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/client/requests/index.ts @@ -0,0 +1 @@ +export type { FieldsListRequest } from "./FieldsListRequest.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/index.ts new file mode 100644 index 00000000..914b8c3c --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/fields/index.ts @@ -0,0 +1 @@ +export * from "./client/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/index.ts new file mode 100644 index 00000000..5fd9a9a1 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/resources/index.ts @@ -0,0 +1,5 @@ +export * from "./breakdown/client/requests/index.js"; +export * as breakdown from "./breakdown/index.js"; +export * from "./breakdown/types/index.js"; +export * from "./fields/client/requests/index.js"; +export * as fields from "./fields/index.js"; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestDeployment.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestDeployment.ts new file mode 100644 index 00000000..759a85f2 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestDeployment.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Deployment type for the requests */ +export const UsageGetRequestDeployment = { + Hosted: "hosted", + Beta: "beta", + SelfHosted: "self-hosted", +} as const; +export type UsageGetRequestDeployment = (typeof UsageGetRequestDeployment)[keyof typeof UsageGetRequestDeployment]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestEndpoint.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestEndpoint.ts new file mode 100644 index 00000000..46975809 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestEndpoint.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +export const UsageGetRequestEndpoint = { + Listen: "listen", + Read: "read", + Speak: "speak", + Agent: "agent", +} as const; +export type UsageGetRequestEndpoint = (typeof UsageGetRequestEndpoint)[keyof typeof UsageGetRequestEndpoint]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestMethod.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestMethod.ts new file mode 100644 index 00000000..5739ceb2 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/UsageGetRequestMethod.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Method type for the request */ +export const UsageGetRequestMethod = { + Sync: "sync", + Async: "async", + Streaming: "streaming", +} as const; +export type UsageGetRequestMethod = (typeof UsageGetRequestMethod)[keyof typeof UsageGetRequestMethod]; diff --git a/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/index.ts b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/index.ts new file mode 100644 index 00000000..57208132 --- /dev/null +++ b/src/api/resources/manage/resources/v1/resources/projects/resources/usage/types/index.ts @@ -0,0 +1,3 @@ +export * from "./UsageGetRequestDeployment.js"; +export * from "./UsageGetRequestEndpoint.js"; +export * from "./UsageGetRequestMethod.js"; diff --git a/src/api/resources/read/client/Client.ts b/src/api/resources/read/client/Client.ts new file mode 100644 index 00000000..d10fdc4c --- /dev/null +++ b/src/api/resources/read/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../BaseClient.js"; +import { V1Client } from "../resources/v1/client/Client.js"; + +export declare namespace ReadClient { + export interface Options extends BaseClientOptions {} +} + +export class ReadClient { + protected readonly _options: ReadClient.Options; + protected _v1: V1Client | undefined; + + constructor(options: ReadClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get v1(): V1Client { + return (this._v1 ??= new V1Client(this._options)); + } +} diff --git a/src/api/resources/read/client/index.ts b/src/api/resources/read/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/read/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/read/index.ts b/src/api/resources/read/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/read/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/read/resources/index.ts b/src/api/resources/read/resources/index.ts new file mode 100644 index 00000000..c6b56d24 --- /dev/null +++ b/src/api/resources/read/resources/index.ts @@ -0,0 +1 @@ +export * as v1 from "./v1/index.js"; diff --git a/src/api/resources/read/resources/v1/client/Client.ts b/src/api/resources/read/resources/v1/client/Client.ts new file mode 100644 index 00000000..057dcec2 --- /dev/null +++ b/src/api/resources/read/resources/v1/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../BaseClient.js"; +import { TextClient } from "../resources/text/client/Client.js"; + +export declare namespace V1Client { + export interface Options extends BaseClientOptions {} +} + +export class V1Client { + protected readonly _options: V1Client.Options; + protected _text: TextClient | undefined; + + constructor(options: V1Client.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get text(): TextClient { + return (this._text ??= new TextClient(this._options)); + } +} diff --git a/src/api/resources/read/resources/v1/client/index.ts b/src/api/resources/read/resources/v1/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/read/resources/v1/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/read/resources/v1/index.ts b/src/api/resources/read/resources/v1/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/read/resources/v1/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/read/resources/v1/resources/index.ts b/src/api/resources/read/resources/v1/resources/index.ts new file mode 100644 index 00000000..dfe1bfa0 --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/index.ts @@ -0,0 +1,3 @@ +export * from "./text/client/requests/index.js"; +export * as text from "./text/index.js"; +export * from "./text/types/index.js"; diff --git a/src/api/resources/read/resources/v1/resources/text/client/Client.ts b/src/api/resources/read/resources/v1/resources/text/client/Client.ts new file mode 100644 index 00000000..03c32bb6 --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/client/Client.ts @@ -0,0 +1,202 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../index.js"; + +export declare namespace TextClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class TextClient { + protected readonly _options: TextClient.Options; + + constructor(options: TextClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Analyze text content using Deepgrams text analysis API + * + * @param {Deepgram.read.v1.TextAnalyzeRequest} request + * @param {TextClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.read.v1.text.analyze({ + * callback: "callback", + * callback_method: "POST", + * sentiment: true, + * summarize: "v2", + * tag: "tag", + * topics: true, + * custom_topic: "custom_topic", + * custom_topic_mode: "extended", + * intents: true, + * custom_intent: "custom_intent", + * custom_intent_mode: "extended", + * language: "language", + * body: { + * url: "url" + * } + * }) + */ + public analyze( + request: Deepgram.read.v1.TextAnalyzeRequest, + requestOptions?: TextClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__analyze(request, requestOptions)); + } + + private async __analyze( + request: Deepgram.read.v1.TextAnalyzeRequest, + requestOptions?: TextClient.RequestOptions, + ): Promise> { + const { + callback, + callback_method: callbackMethod, + sentiment, + summarize, + tag, + topics, + custom_topic: customTopic, + custom_topic_mode: customTopicMode, + intents, + custom_intent: customIntent, + custom_intent_mode: customIntentMode, + language, + body: _body, + } = request; + const _queryParams: Record = {}; + if (callback != null) { + _queryParams.callback = callback; + } + + if (callbackMethod != null) { + _queryParams.callback_method = callbackMethod; + } + + if (sentiment != null) { + _queryParams.sentiment = sentiment.toString(); + } + + if (summarize != null) { + _queryParams.summarize = summarize; + } + + if (tag != null) { + if (Array.isArray(tag)) { + _queryParams.tag = tag.map((item) => item); + } else { + _queryParams.tag = tag; + } + } + + if (topics != null) { + _queryParams.topics = topics.toString(); + } + + if (customTopic != null) { + if (Array.isArray(customTopic)) { + _queryParams.custom_topic = customTopic.map((item) => item); + } else { + _queryParams.custom_topic = customTopic; + } + } + + if (customTopicMode != null) { + _queryParams.custom_topic_mode = customTopicMode; + } + + if (intents != null) { + _queryParams.intents = intents.toString(); + } + + if (customIntent != null) { + if (Array.isArray(customIntent)) { + _queryParams.custom_intent = customIntent.map((item) => item); + } else { + _queryParams.custom_intent = customIntent; + } + } + + if (customIntentMode != null) { + _queryParams.custom_intent_mode = customIntentMode; + } + + if (language != null) { + _queryParams.language = language; + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + "v1/read", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + requestType: "json", + body: _body, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Deepgram.ReadV1Response, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling POST /v1/read."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/read/resources/v1/resources/text/client/index.ts b/src/api/resources/read/resources/v1/resources/text/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/read/resources/v1/resources/text/client/requests/TextAnalyzeRequest.ts b/src/api/resources/read/resources/v1/resources/text/client/requests/TextAnalyzeRequest.ts new file mode 100644 index 00000000..7f099725 --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/client/requests/TextAnalyzeRequest.ts @@ -0,0 +1,51 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../index.js"; + +/** + * @example + * { + * callback: "callback", + * callback_method: "POST", + * sentiment: true, + * summarize: "v2", + * tag: "tag", + * topics: true, + * custom_topic: "custom_topic", + * custom_topic_mode: "extended", + * intents: true, + * custom_intent: "custom_intent", + * custom_intent_mode: "extended", + * language: "language", + * body: { + * url: "url" + * } + * } + */ +export interface TextAnalyzeRequest { + /** URL to which we'll make the callback request */ + callback?: string; + /** HTTP method by which the callback request will be made */ + callback_method?: Deepgram.read.v1.TextAnalyzeRequestCallbackMethod; + /** Recognizes the sentiment throughout a transcript or text */ + sentiment?: boolean; + /** Summarize content. For Listen API, supports string version option. For Read API, accepts boolean only. */ + summarize?: Deepgram.read.v1.TextAnalyzeRequestSummarize; + /** Label your requests for the purpose of identification during usage reporting */ + tag?: string | string[]; + /** Detect topics throughout a transcript or text */ + topics?: boolean; + /** Custom topics you want the model to detect within your input audio or text if present Submit up to `100`. */ + custom_topic?: string | string[]; + /** Sets how the model will interpret strings submitted to the `custom_topic` param. When `strict`, the model will only return topics submitted using the `custom_topic` param. When `extended`, the model will return its own detected topics in addition to those submitted using the `custom_topic` param */ + custom_topic_mode?: Deepgram.read.v1.TextAnalyzeRequestCustomTopicMode; + /** Recognizes speaker intent throughout a transcript or text */ + intents?: boolean; + /** Custom intents you want the model to detect within your input audio if present */ + custom_intent?: string | string[]; + /** Sets how the model will interpret intents submitted to the `custom_intent` param. When `strict`, the model will only return intents submitted using the `custom_intent` param. When `extended`, the model will return its own detected intents in the `custom_intent` param. */ + custom_intent_mode?: Deepgram.read.v1.TextAnalyzeRequestCustomIntentMode; + /** The [BCP-47 language tag](https://tools.ietf.org/html/bcp47) that hints at the primary spoken language. Depending on the Model and API endpoint you choose only certain languages are available */ + language?: string; + body: Deepgram.ReadV1Request; +} diff --git a/src/api/resources/read/resources/v1/resources/text/client/requests/index.ts b/src/api/resources/read/resources/v1/resources/text/client/requests/index.ts new file mode 100644 index 00000000..ab8756ec --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/client/requests/index.ts @@ -0,0 +1 @@ +export type { TextAnalyzeRequest } from "./TextAnalyzeRequest.js"; diff --git a/src/api/resources/read/resources/v1/resources/text/index.ts b/src/api/resources/read/resources/v1/resources/text/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCallbackMethod.ts b/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCallbackMethod.ts new file mode 100644 index 00000000..843a58e4 --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCallbackMethod.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const TextAnalyzeRequestCallbackMethod = { + Post: "POST", + Put: "PUT", +} as const; +export type TextAnalyzeRequestCallbackMethod = + (typeof TextAnalyzeRequestCallbackMethod)[keyof typeof TextAnalyzeRequestCallbackMethod]; diff --git a/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCustomIntentMode.ts b/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCustomIntentMode.ts new file mode 100644 index 00000000..3806ccd4 --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCustomIntentMode.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const TextAnalyzeRequestCustomIntentMode = { + Extended: "extended", + Strict: "strict", +} as const; +export type TextAnalyzeRequestCustomIntentMode = + (typeof TextAnalyzeRequestCustomIntentMode)[keyof typeof TextAnalyzeRequestCustomIntentMode]; diff --git a/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCustomTopicMode.ts b/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCustomTopicMode.ts new file mode 100644 index 00000000..2f26f070 --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestCustomTopicMode.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const TextAnalyzeRequestCustomTopicMode = { + Extended: "extended", + Strict: "strict", +} as const; +export type TextAnalyzeRequestCustomTopicMode = + (typeof TextAnalyzeRequestCustomTopicMode)[keyof typeof TextAnalyzeRequestCustomTopicMode]; diff --git a/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestSummarize.ts b/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestSummarize.ts new file mode 100644 index 00000000..72f2412c --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/types/TextAnalyzeRequestSummarize.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const TextAnalyzeRequestSummarize = { + V2: "v2", + V1: "v1", +} as const; +export type TextAnalyzeRequestSummarize = + (typeof TextAnalyzeRequestSummarize)[keyof typeof TextAnalyzeRequestSummarize]; diff --git a/src/api/resources/read/resources/v1/resources/text/types/index.ts b/src/api/resources/read/resources/v1/resources/text/types/index.ts new file mode 100644 index 00000000..4d03536a --- /dev/null +++ b/src/api/resources/read/resources/v1/resources/text/types/index.ts @@ -0,0 +1,4 @@ +export * from "./TextAnalyzeRequestCallbackMethod.js"; +export * from "./TextAnalyzeRequestCustomIntentMode.js"; +export * from "./TextAnalyzeRequestCustomTopicMode.js"; +export * from "./TextAnalyzeRequestSummarize.js"; diff --git a/src/api/resources/selfHosted/client/Client.ts b/src/api/resources/selfHosted/client/Client.ts new file mode 100644 index 00000000..1eba4eb0 --- /dev/null +++ b/src/api/resources/selfHosted/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../BaseClient.js"; +import { V1Client } from "../resources/v1/client/Client.js"; + +export declare namespace SelfHostedClient { + export interface Options extends BaseClientOptions {} +} + +export class SelfHostedClient { + protected readonly _options: SelfHostedClient.Options; + protected _v1: V1Client | undefined; + + constructor(options: SelfHostedClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get v1(): V1Client { + return (this._v1 ??= new V1Client(this._options)); + } +} diff --git a/src/api/resources/selfHosted/client/index.ts b/src/api/resources/selfHosted/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/selfHosted/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/selfHosted/index.ts b/src/api/resources/selfHosted/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/selfHosted/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/selfHosted/resources/index.ts b/src/api/resources/selfHosted/resources/index.ts new file mode 100644 index 00000000..c6b56d24 --- /dev/null +++ b/src/api/resources/selfHosted/resources/index.ts @@ -0,0 +1 @@ +export * as v1 from "./v1/index.js"; diff --git a/src/api/resources/selfHosted/resources/v1/client/Client.ts b/src/api/resources/selfHosted/resources/v1/client/Client.ts new file mode 100644 index 00000000..b1c31ac5 --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../BaseClient.js"; +import { DistributionCredentialsClient } from "../resources/distributionCredentials/client/Client.js"; + +export declare namespace V1Client { + export interface Options extends BaseClientOptions {} +} + +export class V1Client { + protected readonly _options: V1Client.Options; + protected _distributionCredentials: DistributionCredentialsClient | undefined; + + constructor(options: V1Client.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get distributionCredentials(): DistributionCredentialsClient { + return (this._distributionCredentials ??= new DistributionCredentialsClient(this._options)); + } +} diff --git a/src/api/resources/selfHosted/resources/v1/client/index.ts b/src/api/resources/selfHosted/resources/v1/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/selfHosted/resources/v1/index.ts b/src/api/resources/selfHosted/resources/v1/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/Client.ts b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/Client.ts new file mode 100644 index 00000000..0b654ac6 --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/Client.ts @@ -0,0 +1,396 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../index.js"; + +export declare namespace DistributionCredentialsClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class DistributionCredentialsClient { + protected readonly _options: DistributionCredentialsClient.Options; + + constructor(options: DistributionCredentialsClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Lists sets of distribution credentials for the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {DistributionCredentialsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.selfHosted.v1.distributionCredentials.list("123456-7890-1234-5678-901234") + */ + public list( + project_id: string, + requestOptions?: DistributionCredentialsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__list(project_id, requestOptions)); + } + + private async __list( + project_id: string, + requestOptions?: DistributionCredentialsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/self-hosted/distribution/credentials`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.ListProjectDistributionCredentialsV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/self-hosted/distribution/credentials.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Creates a set of distribution credentials for the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {Deepgram.selfHosted.v1.CreateProjectDistributionCredentialsV1Request} request + * @param {DistributionCredentialsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.selfHosted.v1.distributionCredentials.create("123456-7890-1234-5678-901234", { + * provider: "quay" + * }) + */ + public create( + project_id: string, + request: Deepgram.selfHosted.v1.CreateProjectDistributionCredentialsV1Request = {}, + requestOptions?: DistributionCredentialsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__create(project_id, request, requestOptions)); + } + + private async __create( + project_id: string, + request: Deepgram.selfHosted.v1.CreateProjectDistributionCredentialsV1Request = {}, + requestOptions?: DistributionCredentialsClient.RequestOptions, + ): Promise> { + const { scopes, provider, ..._body } = request; + const _queryParams: Record = {}; + if (scopes != null) { + if (Array.isArray(scopes)) { + _queryParams.scopes = scopes.map((item) => item); + } else { + _queryParams.scopes = scopes; + } + } + + if (provider != null) { + _queryParams.provider = provider; + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/self-hosted/distribution/credentials`, + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + requestType: "json", + body: _body, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.CreateProjectDistributionCredentialsV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling POST /v1/projects/{project_id}/self-hosted/distribution/credentials.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Returns a set of distribution credentials for the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {string} distribution_credentials_id - The UUID of the distribution credentials + * @param {DistributionCredentialsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.selfHosted.v1.distributionCredentials.get("123456-7890-1234-5678-901234", "8b36cfd0-472f-4a21-833f-2d6343c3a2f3") + */ + public get( + project_id: string, + distribution_credentials_id: string, + requestOptions?: DistributionCredentialsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise( + this.__get(project_id, distribution_credentials_id, requestOptions), + ); + } + + private async __get( + project_id: string, + distribution_credentials_id: string, + requestOptions?: DistributionCredentialsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/self-hosted/distribution/credentials/${core.url.encodePathParam(distribution_credentials_id)}`, + ), + method: "GET", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.GetProjectDistributionCredentialsV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling GET /v1/projects/{project_id}/self-hosted/distribution/credentials/{distribution_credentials_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + /** + * Deletes a set of distribution credentials for the specified project + * + * @param {string} project_id - The unique identifier of the project + * @param {string} distribution_credentials_id - The UUID of the distribution credentials + * @param {DistributionCredentialsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Deepgram.BadRequestError} + * + * @example + * await client.selfHosted.v1.distributionCredentials.delete("123456-7890-1234-5678-901234", "8b36cfd0-472f-4a21-833f-2d6343c3a2f3") + */ + public delete( + project_id: string, + distribution_credentials_id: string, + requestOptions?: DistributionCredentialsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise( + this.__delete(project_id, distribution_credentials_id, requestOptions), + ); + } + + private async __delete( + project_id: string, + distribution_credentials_id: string, + requestOptions?: DistributionCredentialsClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + `v1/projects/${core.url.encodePathParam(project_id)}/self-hosted/distribution/credentials/${core.url.encodePathParam(distribution_credentials_id)}`, + ), + method: "DELETE", + headers: _headers, + queryParameters: requestOptions?.queryParams, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: _response.body as Deepgram.GetProjectDistributionCredentialsV1Response, + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError( + "Timeout exceeded when calling DELETE /v1/projects/{project_id}/self-hosted/distribution/credentials/{distribution_credentials_id}.", + ); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/index.ts b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/requests/CreateProjectDistributionCredentialsV1Request.ts b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/requests/CreateProjectDistributionCredentialsV1Request.ts new file mode 100644 index 00000000..84b12016 --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/requests/CreateProjectDistributionCredentialsV1Request.ts @@ -0,0 +1,20 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../index.js"; + +/** + * @example + * { + * provider: "quay" + * } + */ +export interface CreateProjectDistributionCredentialsV1Request { + /** List of permission scopes for the credentials */ + scopes?: + | Deepgram.selfHosted.v1.DistributionCredentialsCreateRequestScopesItem + | Deepgram.selfHosted.v1.DistributionCredentialsCreateRequestScopesItem[]; + /** The provider of the distribution service */ + provider?: "quay"; + /** Optional comment about the credentials */ + comment?: string; +} diff --git a/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/requests/index.ts b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/requests/index.ts new file mode 100644 index 00000000..efbfebad --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/client/requests/index.ts @@ -0,0 +1 @@ +export type { CreateProjectDistributionCredentialsV1Request } from "./CreateProjectDistributionCredentialsV1Request.js"; diff --git a/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/index.ts b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/types/DistributionCredentialsCreateRequestScopesItem.ts b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/types/DistributionCredentialsCreateRequestScopesItem.ts new file mode 100644 index 00000000..7c3218af --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/types/DistributionCredentialsCreateRequestScopesItem.ts @@ -0,0 +1,14 @@ +// This file was auto-generated by Fern from our API Definition. + +export const DistributionCredentialsCreateRequestScopesItem = { + SelfHostedProducts: "self-hosted:products", + SelfHostedProductApi: "self-hosted:product:api", + SelfHostedProductEngine: "self-hosted:product:engine", + SelfHostedProductLicenseProxy: "self-hosted:product:license-proxy", + SelfHostedProductDgtools: "self-hosted:product:dgtools", + SelfHostedProductBilling: "self-hosted:product:billing", + SelfHostedProductHotpepper: "self-hosted:product:hotpepper", + SelfHostedProductMetricsServer: "self-hosted:product:metrics-server", +} as const; +export type DistributionCredentialsCreateRequestScopesItem = + (typeof DistributionCredentialsCreateRequestScopesItem)[keyof typeof DistributionCredentialsCreateRequestScopesItem]; diff --git a/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/types/index.ts b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/types/index.ts new file mode 100644 index 00000000..74d8a642 --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/resources/distributionCredentials/types/index.ts @@ -0,0 +1 @@ +export * from "./DistributionCredentialsCreateRequestScopesItem.js"; diff --git a/src/api/resources/selfHosted/resources/v1/resources/index.ts b/src/api/resources/selfHosted/resources/v1/resources/index.ts new file mode 100644 index 00000000..3a018695 --- /dev/null +++ b/src/api/resources/selfHosted/resources/v1/resources/index.ts @@ -0,0 +1,3 @@ +export * from "./distributionCredentials/client/requests/index.js"; +export * as distributionCredentials from "./distributionCredentials/index.js"; +export * from "./distributionCredentials/types/index.js"; diff --git a/src/api/resources/speak/client/Client.ts b/src/api/resources/speak/client/Client.ts new file mode 100644 index 00000000..ea436dc0 --- /dev/null +++ b/src/api/resources/speak/client/Client.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../BaseClient.js"; +import { V1Client } from "../resources/v1/client/Client.js"; + +export declare namespace SpeakClient { + export interface Options extends BaseClientOptions {} +} + +export class SpeakClient { + protected readonly _options: SpeakClient.Options; + protected _v1: V1Client | undefined; + + constructor(options: SpeakClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get v1(): V1Client { + return (this._v1 ??= new V1Client(this._options)); + } +} diff --git a/src/api/resources/speak/client/index.ts b/src/api/resources/speak/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/speak/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/speak/index.ts b/src/api/resources/speak/index.ts new file mode 100644 index 00000000..9eb1192d --- /dev/null +++ b/src/api/resources/speak/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; diff --git a/src/api/resources/speak/resources/index.ts b/src/api/resources/speak/resources/index.ts new file mode 100644 index 00000000..96368d86 --- /dev/null +++ b/src/api/resources/speak/resources/index.ts @@ -0,0 +1,2 @@ +export * as v1 from "./v1/index.js"; +export * from "./v1/types/index.js"; diff --git a/src/api/resources/speak/resources/v1/client/Client.ts b/src/api/resources/speak/resources/v1/client/Client.ts new file mode 100644 index 00000000..668161cd --- /dev/null +++ b/src/api/resources/speak/resources/v1/client/Client.ts @@ -0,0 +1,88 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions } from "../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../core/headers.js"; +import * as core from "../../../../../../core/index.js"; +import * as environments from "../../../../../../environments.js"; +import { AudioClient } from "../resources/audio/client/Client.js"; +import { V1Socket } from "./Socket.js"; + +export declare namespace V1Client { + export interface Options extends BaseClientOptions {} + + export interface ConnectArgs { + encoding?: string | undefined; + mip_opt_out?: string | undefined; + model?: string | undefined; + sample_rate?: string | undefined; + Authorization: string; + /** Arbitrary headers to send with the websocket connect request. */ + headers?: Record; + /** Enable debug mode on the websocket. Defaults to false. */ + debug?: boolean; + /** Number of reconnect attempts. Defaults to 30. */ + reconnectAttempts?: number; + } +} + +export class V1Client { + protected readonly _options: V1Client.Options; + protected _audio: AudioClient | undefined; + + constructor(options: V1Client.Options = {}) { + this._options = normalizeClientOptions(options); + } + + public get audio(): AudioClient { + return (this._audio ??= new AudioClient(this._options)); + } + + public async connect(args: V1Client.ConnectArgs): Promise { + const { encoding, mip_opt_out, model, sample_rate, headers, debug, reconnectAttempts } = args; + const _queryParams: Record = {}; + if (encoding != null) { + _queryParams.encoding = encoding; + } + + if (mip_opt_out != null) { + _queryParams.mip_opt_out = mip_opt_out; + } + + if (model != null) { + _queryParams.model = model; + } + + if (sample_rate != null) { + _queryParams.sample_rate = sample_rate; + } + + const _headers: Record = mergeHeaders( + mergeOnlyDefinedHeaders({ + ...(await this._getCustomAuthorizationHeaders()), + Authorization: args.Authorization, + }), + headers, + ); + const socket = new core.ReconnectingWebSocket({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).production, + "/v1/speak", + ), + protocols: [], + queryParameters: _queryParams, + headers: _headers, + options: { debug: debug ?? false, maxRetries: reconnectAttempts ?? 30 }, + }); + return new V1Socket({ socket }); + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/speak/resources/v1/client/Socket.ts b/src/api/resources/speak/resources/v1/client/Socket.ts new file mode 100644 index 00000000..300afda1 --- /dev/null +++ b/src/api/resources/speak/resources/v1/client/Socket.ts @@ -0,0 +1,160 @@ +// This file was auto-generated by Fern from our API Definition. + +import * as core from "../../../../../../core/index.js"; +import { fromJson, toJson } from "../../../../../../core/json.js"; +import type * as Deepgram from "../../../../../index.js"; + +export declare namespace V1Socket { + export interface Args { + socket: core.ReconnectingWebSocket; + } + + export type Response = + | string + | Deepgram.speak.SpeakV1Metadata + | Deepgram.speak.SpeakV1Flushed + | Deepgram.speak.SpeakV1Cleared + | Deepgram.speak.SpeakV1Warning; + type EventHandlers = { + open?: () => void; + message?: (message: Response) => void; + close?: (event: core.CloseEvent) => void; + error?: (error: Error) => void; + }; +} + +export class V1Socket { + public readonly socket: core.ReconnectingWebSocket; + protected readonly eventHandlers: V1Socket.EventHandlers = {}; + private handleOpen: () => void = () => { + this.eventHandlers.open?.(); + }; + private handleMessage: (event: { data: string }) => void = (event) => { + const data = fromJson(event.data); + + this.eventHandlers.message?.(data as V1Socket.Response); + }; + private handleClose: (event: core.CloseEvent) => void = (event) => { + this.eventHandlers.close?.(event); + }; + private handleError: (event: core.ErrorEvent) => void = (event) => { + const message = event.message; + this.eventHandlers.error?.(new Error(message)); + }; + + constructor(args: V1Socket.Args) { + this.socket = args.socket; + this.socket.addEventListener("open", this.handleOpen); + this.socket.addEventListener("message", this.handleMessage); + this.socket.addEventListener("close", this.handleClose); + this.socket.addEventListener("error", this.handleError); + } + + /** The current state of the connection; this is one of the readyState constants. */ + get readyState(): number { + return this.socket.readyState; + } + + /** + * @param event - The event to attach to. + * @param callback - The callback to run when the event is triggered. + * Usage: + * ```typescript + * this.on('open', () => { + * console.log('The websocket is open'); + * }); + * ``` + */ + public on(event: T, callback: V1Socket.EventHandlers[T]): void { + this.eventHandlers[event] = callback; + } + + public sendSpeakV1Text(message: Deepgram.speak.SpeakV1Text): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendSpeakV1Flush(message: Deepgram.speak.SpeakV1Flush): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendSpeakV1Clear(message: Deepgram.speak.SpeakV1Clear): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + public sendSpeakV1Close(message: Deepgram.speak.SpeakV1Close): void { + this.assertSocketIsOpen(); + this.sendJson(message); + } + + /** Connect to the websocket and register event handlers. */ + public connect(): V1Socket { + this.socket.reconnect(); + + this.socket.addEventListener("open", this.handleOpen); + this.socket.addEventListener("message", this.handleMessage); + this.socket.addEventListener("close", this.handleClose); + this.socket.addEventListener("error", this.handleError); + + return this; + } + + /** Close the websocket and unregister event handlers. */ + public close(): void { + this.socket.close(); + + this.handleClose({ code: 1000 } as CloseEvent); + + this.socket.removeEventListener("open", this.handleOpen); + this.socket.removeEventListener("message", this.handleMessage); + this.socket.removeEventListener("close", this.handleClose); + this.socket.removeEventListener("error", this.handleError); + } + + /** Returns a promise that resolves when the websocket is open. */ + public async waitForOpen(): Promise { + if (this.socket.readyState === core.ReconnectingWebSocket.OPEN) { + return this.socket; + } + + return new Promise((resolve, reject) => { + this.socket.addEventListener("open", () => { + resolve(this.socket); + }); + + this.socket.addEventListener("error", (event: unknown) => { + reject(event); + }); + }); + } + + /** Asserts that the websocket is open. */ + private assertSocketIsOpen(): void { + if (!this.socket) { + throw new Error("Socket is not connected."); + } + + if (this.socket.readyState !== core.ReconnectingWebSocket.OPEN) { + throw new Error("Socket is not open."); + } + } + + /** Send a binary payload to the websocket. */ + protected sendBinary(payload: ArrayBufferLike | Blob | ArrayBufferView): void { + this.socket.send(payload); + } + + /** Send a JSON payload to the websocket. */ + protected sendJson( + payload: + | Deepgram.speak.SpeakV1Text + | Deepgram.speak.SpeakV1Flush + | Deepgram.speak.SpeakV1Clear + | Deepgram.speak.SpeakV1Close, + ): void { + const jsonPayload = toJson(payload); + this.socket.send(jsonPayload); + } +} diff --git a/src/api/resources/speak/resources/v1/client/index.ts b/src/api/resources/speak/resources/v1/client/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/api/resources/speak/resources/v1/client/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/api/resources/speak/resources/v1/index.ts b/src/api/resources/speak/resources/v1/index.ts new file mode 100644 index 00000000..0ef16e76 --- /dev/null +++ b/src/api/resources/speak/resources/v1/index.ts @@ -0,0 +1,3 @@ +export * from "./client/index.js"; +export * from "./resources/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/speak/resources/v1/resources/audio/client/Client.ts b/src/api/resources/speak/resources/v1/resources/audio/client/Client.ts new file mode 100644 index 00000000..ef5e19d2 --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/client/Client.ts @@ -0,0 +1,157 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../../../../../BaseClient.js"; +import { normalizeClientOptions } from "../../../../../../../../BaseClient.js"; +import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../../../../../core/headers.js"; +import * as core from "../../../../../../../../core/index.js"; +import * as environments from "../../../../../../../../environments.js"; +import * as errors from "../../../../../../../../errors/index.js"; +import * as Deepgram from "../../../../../../../index.js"; + +export declare namespace AudioClient { + export interface Options extends BaseClientOptions {} + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class AudioClient { + protected readonly _options: AudioClient.Options; + + constructor(options: AudioClient.Options = {}) { + this._options = normalizeClientOptions(options); + } + + /** + * Convert text into natural-sounding speech using Deepgram's TTS REST API + * @throws {@link Deepgram.BadRequestError} + */ + public generate( + request: Deepgram.speak.v1.SpeakV1Request, + requestOptions?: AudioClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__generate(request, requestOptions)); + } + + private async __generate( + request: Deepgram.speak.v1.SpeakV1Request, + requestOptions?: AudioClient.RequestOptions, + ): Promise> { + const { + callback, + callback_method: callbackMethod, + mip_opt_out: mipOptOut, + tag, + bit_rate: bitRate, + container, + encoding, + model, + sample_rate: sampleRate, + ..._body + } = request; + const _queryParams: Record = {}; + if (callback != null) { + _queryParams.callback = callback; + } + + if (callbackMethod != null) { + _queryParams.callback_method = callbackMethod; + } + + if (mipOptOut != null) { + _queryParams.mip_opt_out = mipOptOut.toString(); + } + + if (tag != null) { + if (Array.isArray(tag)) { + _queryParams.tag = tag.map((item) => item); + } else { + _queryParams.tag = tag; + } + } + + if (bitRate != null) { + _queryParams.bit_rate = bitRate.toString(); + } + + if (container != null) { + _queryParams.container = container; + } + + if (encoding != null) { + _queryParams.encoding = encoding; + } + + if (model != null) { + _queryParams.model = model; + } + + if (sampleRate != null) { + _queryParams.sample_rate = sampleRate.toString(); + } + + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + this._options?.headers, + mergeOnlyDefinedHeaders({ ...(await this._getCustomAuthorizationHeaders()) }), + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + ( + (await core.Supplier.get(this._options.environment)) ?? + environments.DeepgramEnvironment.Production + ).base, + "v1/speak", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryParameters: { ..._queryParams, ...requestOptions?.queryParams }, + requestType: "json", + body: _body, + responseType: "binary-response", + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Deepgram.BadRequestError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.DeepgramError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + rawResponse: _response.rawResponse, + }); + case "timeout": + throw new errors.DeepgramTimeoutError("Timeout exceeded when calling POST /v1/speak."); + case "unknown": + throw new errors.DeepgramError({ + message: _response.error.errorMessage, + rawResponse: _response.rawResponse, + }); + } + } + + protected async _getCustomAuthorizationHeaders(): Promise> { + const apiKeyValue = (await core.Supplier.get(this._options.apiKey)) ?? process?.env.DEEPGRAM_API_KEY; + return { Authorization: `Token ${apiKeyValue}` }; + } +} diff --git a/src/api/resources/speak/resources/v1/resources/audio/client/index.ts b/src/api/resources/speak/resources/v1/resources/audio/client/index.ts new file mode 100644 index 00000000..195f9aa8 --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/speak/resources/v1/resources/audio/client/requests/SpeakV1Request.ts b/src/api/resources/speak/resources/v1/resources/audio/client/requests/SpeakV1Request.ts new file mode 100644 index 00000000..9a2e399e --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/client/requests/SpeakV1Request.ts @@ -0,0 +1,32 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../../../../../../../../index.js"; + +/** + * @example + * { + * text: "text" + * } + */ +export interface SpeakV1Request { + /** URL to which we'll make the callback request */ + callback?: string; + /** HTTP method by which the callback request will be made */ + callback_method?: Deepgram.speak.v1.AudioGenerateRequestCallbackMethod; + /** Opts out requests from the Deepgram Model Improvement Program. Refer to our Docs for pricing impacts before setting this to true. https://dpgr.am/deepgram-mip */ + mip_opt_out?: boolean; + /** Label your requests for the purpose of identification during usage reporting */ + tag?: string | string[]; + /** The bitrate of the audio in bits per second. Choose from predefined ranges or specific values based on the encoding type. */ + bit_rate?: number; + /** Container specifies the file format wrapper for the output audio. The available options depend on the encoding type. */ + container?: Deepgram.speak.v1.AudioGenerateRequestContainer; + /** Encoding allows you to specify the expected encoding of your audio output */ + encoding?: Deepgram.speak.v1.AudioGenerateRequestEncoding; + /** AI model used to process submitted text */ + model?: Deepgram.speak.v1.AudioGenerateRequestModel; + /** Sample Rate specifies the sample rate for the output audio. Based on the encoding, different sample rates are supported. For some encodings, the sample rate is not configurable */ + sample_rate?: number; + /** The text content to be converted to speech */ + text: string; +} diff --git a/src/api/resources/speak/resources/v1/resources/audio/client/requests/index.ts b/src/api/resources/speak/resources/v1/resources/audio/client/requests/index.ts new file mode 100644 index 00000000..9ac2ca0f --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/client/requests/index.ts @@ -0,0 +1 @@ +export type { SpeakV1Request } from "./SpeakV1Request.js"; diff --git a/src/api/resources/speak/resources/v1/resources/audio/index.ts b/src/api/resources/speak/resources/v1/resources/audio/index.ts new file mode 100644 index 00000000..d9adb1af --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestCallbackMethod.ts b/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestCallbackMethod.ts new file mode 100644 index 00000000..f3cf56c1 --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestCallbackMethod.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const AudioGenerateRequestCallbackMethod = { + Post: "POST", + Put: "PUT", +} as const; +export type AudioGenerateRequestCallbackMethod = + (typeof AudioGenerateRequestCallbackMethod)[keyof typeof AudioGenerateRequestCallbackMethod]; diff --git a/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestContainer.ts b/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestContainer.ts new file mode 100644 index 00000000..ff855e72 --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestContainer.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +export const AudioGenerateRequestContainer = { + None: "none", + Wav: "wav", + Ogg: "ogg", +} as const; +export type AudioGenerateRequestContainer = + (typeof AudioGenerateRequestContainer)[keyof typeof AudioGenerateRequestContainer]; diff --git a/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestEncoding.ts b/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestEncoding.ts new file mode 100644 index 00000000..2e500cd9 --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestEncoding.ts @@ -0,0 +1,13 @@ +// This file was auto-generated by Fern from our API Definition. + +export const AudioGenerateRequestEncoding = { + Linear16: "linear16", + Flac: "flac", + Mulaw: "mulaw", + Alaw: "alaw", + Mp3: "mp3", + Opus: "opus", + Aac: "aac", +} as const; +export type AudioGenerateRequestEncoding = + (typeof AudioGenerateRequestEncoding)[keyof typeof AudioGenerateRequestEncoding]; diff --git a/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestModel.ts b/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestModel.ts new file mode 100644 index 00000000..4ac480c0 --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/types/AudioGenerateRequestModel.ts @@ -0,0 +1,68 @@ +// This file was auto-generated by Fern from our API Definition. + +export const AudioGenerateRequestModel = { + AuraAsteriaEn: "aura-asteria-en", + AuraLunaEn: "aura-luna-en", + AuraStellaEn: "aura-stella-en", + AuraAthenaEn: "aura-athena-en", + AuraHeraEn: "aura-hera-en", + AuraOrionEn: "aura-orion-en", + AuraArcasEn: "aura-arcas-en", + AuraPerseusEn: "aura-perseus-en", + AuraAngusEn: "aura-angus-en", + AuraOrpheusEn: "aura-orpheus-en", + AuraHeliosEn: "aura-helios-en", + AuraZeusEn: "aura-zeus-en", + Aura2AmaltheaEn: "aura-2-amalthea-en", + Aura2AndromedaEn: "aura-2-andromeda-en", + Aura2ApolloEn: "aura-2-apollo-en", + Aura2ArcasEn: "aura-2-arcas-en", + Aura2AriesEn: "aura-2-aries-en", + Aura2AsteriaEn: "aura-2-asteria-en", + Aura2AthenaEn: "aura-2-athena-en", + Aura2AtlasEn: "aura-2-atlas-en", + Aura2AuroraEn: "aura-2-aurora-en", + Aura2CallistaEn: "aura-2-callista-en", + Aura2CordeliaEn: "aura-2-cordelia-en", + Aura2CoraEn: "aura-2-cora-en", + Aura2DeliaEn: "aura-2-delia-en", + Aura2DracoEn: "aura-2-draco-en", + Aura2ElectraEn: "aura-2-electra-en", + Aura2HarmoniaEn: "aura-2-harmonia-en", + Aura2HelenaEn: "aura-2-helena-en", + Aura2HeraEn: "aura-2-hera-en", + Aura2HermesEn: "aura-2-hermes-en", + Aura2HyperionEn: "aura-2-hyperion-en", + Aura2IrisEn: "aura-2-iris-en", + Aura2JanusEn: "aura-2-janus-en", + Aura2JunoEn: "aura-2-juno-en", + Aura2JupiterEn: "aura-2-jupiter-en", + Aura2LunaEn: "aura-2-luna-en", + Aura2MarsEn: "aura-2-mars-en", + Aura2MinervaEn: "aura-2-minerva-en", + Aura2NeptuneEn: "aura-2-neptune-en", + Aura2OdysseusEn: "aura-2-odysseus-en", + Aura2OpheliaEn: "aura-2-ophelia-en", + Aura2OrionEn: "aura-2-orion-en", + Aura2OrpheusEn: "aura-2-orpheus-en", + Aura2PandoraEn: "aura-2-pandora-en", + Aura2PhoebeEn: "aura-2-phoebe-en", + Aura2PlutoEn: "aura-2-pluto-en", + Aura2SaturnEn: "aura-2-saturn-en", + Aura2SeleneEn: "aura-2-selene-en", + Aura2ThaliaEn: "aura-2-thalia-en", + Aura2TheiaEn: "aura-2-theia-en", + Aura2VestaEn: "aura-2-vesta-en", + Aura2ZeusEn: "aura-2-zeus-en", + Aura2SirioEs: "aura-2-sirio-es", + Aura2NestorEs: "aura-2-nestor-es", + Aura2CarinaEs: "aura-2-carina-es", + Aura2CelesteEs: "aura-2-celeste-es", + Aura2AlvaroEs: "aura-2-alvaro-es", + Aura2DianaEs: "aura-2-diana-es", + Aura2AquilaEs: "aura-2-aquila-es", + Aura2SelenaEs: "aura-2-selena-es", + Aura2EstrellaEs: "aura-2-estrella-es", + Aura2JavierEs: "aura-2-javier-es", +} as const; +export type AudioGenerateRequestModel = (typeof AudioGenerateRequestModel)[keyof typeof AudioGenerateRequestModel]; diff --git a/src/api/resources/speak/resources/v1/resources/audio/types/index.ts b/src/api/resources/speak/resources/v1/resources/audio/types/index.ts new file mode 100644 index 00000000..f62341ab --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/audio/types/index.ts @@ -0,0 +1,4 @@ +export * from "./AudioGenerateRequestCallbackMethod.js"; +export * from "./AudioGenerateRequestContainer.js"; +export * from "./AudioGenerateRequestEncoding.js"; +export * from "./AudioGenerateRequestModel.js"; diff --git a/src/api/resources/speak/resources/v1/resources/index.ts b/src/api/resources/speak/resources/v1/resources/index.ts new file mode 100644 index 00000000..d1047f1a --- /dev/null +++ b/src/api/resources/speak/resources/v1/resources/index.ts @@ -0,0 +1,3 @@ +export * from "./audio/client/requests/index.js"; +export * as audio from "./audio/index.js"; +export * from "./audio/types/index.js"; diff --git a/src/api/resources/speak/resources/v1/types/SpeakV1Clear.ts b/src/api/resources/speak/resources/v1/types/SpeakV1Clear.ts new file mode 100644 index 00000000..37bc5670 --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/SpeakV1Clear.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface SpeakV1Clear { + /** Message type identifier */ + type: SpeakV1Clear.Type; +} + +export namespace SpeakV1Clear { + /** Message type identifier */ + export const Type = { + Flush: "Flush", + Clear: "Clear", + Close: "Close", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/speak/resources/v1/types/SpeakV1Cleared.ts b/src/api/resources/speak/resources/v1/types/SpeakV1Cleared.ts new file mode 100644 index 00000000..5d9ecb2c --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/SpeakV1Cleared.ts @@ -0,0 +1,17 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface SpeakV1Cleared { + /** Message type identifier */ + type: SpeakV1Cleared.Type; + /** The sequence ID of the response */ + sequence_id: number; +} + +export namespace SpeakV1Cleared { + /** Message type identifier */ + export const Type = { + Flushed: "Flushed", + Cleared: "Cleared", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/speak/resources/v1/types/SpeakV1Close.ts b/src/api/resources/speak/resources/v1/types/SpeakV1Close.ts new file mode 100644 index 00000000..375800c8 --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/SpeakV1Close.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface SpeakV1Close { + /** Message type identifier */ + type: SpeakV1Close.Type; +} + +export namespace SpeakV1Close { + /** Message type identifier */ + export const Type = { + Flush: "Flush", + Clear: "Clear", + Close: "Close", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/speak/resources/v1/types/SpeakV1Flush.ts b/src/api/resources/speak/resources/v1/types/SpeakV1Flush.ts new file mode 100644 index 00000000..dd872220 --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/SpeakV1Flush.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface SpeakV1Flush { + /** Message type identifier */ + type: SpeakV1Flush.Type; +} + +export namespace SpeakV1Flush { + /** Message type identifier */ + export const Type = { + Flush: "Flush", + Clear: "Clear", + Close: "Close", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/speak/resources/v1/types/SpeakV1Flushed.ts b/src/api/resources/speak/resources/v1/types/SpeakV1Flushed.ts new file mode 100644 index 00000000..5e70ccb6 --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/SpeakV1Flushed.ts @@ -0,0 +1,17 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface SpeakV1Flushed { + /** Message type identifier */ + type: SpeakV1Flushed.Type; + /** The sequence ID of the response */ + sequence_id: number; +} + +export namespace SpeakV1Flushed { + /** Message type identifier */ + export const Type = { + Flushed: "Flushed", + Cleared: "Cleared", + } as const; + export type Type = (typeof Type)[keyof typeof Type]; +} diff --git a/src/api/resources/speak/resources/v1/types/SpeakV1Metadata.ts b/src/api/resources/speak/resources/v1/types/SpeakV1Metadata.ts new file mode 100644 index 00000000..20576eab --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/SpeakV1Metadata.ts @@ -0,0 +1,14 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface SpeakV1Metadata { + /** Message type identifier */ + type: "Metadata"; + /** Unique identifier for the request */ + request_id: string; + /** Name of the model being used */ + model_name: string; + /** Version of the model being used */ + model_version: string; + /** Unique identifier for the model */ + model_uuid: string; +} diff --git a/src/api/resources/speak/resources/v1/types/SpeakV1Text.ts b/src/api/resources/speak/resources/v1/types/SpeakV1Text.ts new file mode 100644 index 00000000..65fb3b6a --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/SpeakV1Text.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface SpeakV1Text { + /** Message type identifier */ + type: "Speak"; + /** The input text to be converted to speech */ + text: string; +} diff --git a/src/api/resources/speak/resources/v1/types/SpeakV1Warning.ts b/src/api/resources/speak/resources/v1/types/SpeakV1Warning.ts new file mode 100644 index 00000000..ead60ff8 --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/SpeakV1Warning.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface SpeakV1Warning { + /** Message type identifier */ + type: "Warning"; + /** A description of what went wrong */ + description: string; + /** Error code identifying the type of error */ + code: string; +} diff --git a/src/api/resources/speak/resources/v1/types/index.ts b/src/api/resources/speak/resources/v1/types/index.ts new file mode 100644 index 00000000..0f1783b8 --- /dev/null +++ b/src/api/resources/speak/resources/v1/types/index.ts @@ -0,0 +1,8 @@ +export * from "./SpeakV1Clear.js"; +export * from "./SpeakV1Cleared.js"; +export * from "./SpeakV1Close.js"; +export * from "./SpeakV1Flush.js"; +export * from "./SpeakV1Flushed.js"; +export * from "./SpeakV1Metadata.js"; +export * from "./SpeakV1Text.js"; +export * from "./SpeakV1Warning.js"; diff --git a/src/api/types/AgentThinkModelsV1Response.ts b/src/api/types/AgentThinkModelsV1Response.ts new file mode 100644 index 00000000..c5b9f47e --- /dev/null +++ b/src/api/types/AgentThinkModelsV1Response.ts @@ -0,0 +1,56 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface AgentThinkModelsV1Response { + models: AgentThinkModelsV1Response.Models.Item[]; +} + +export namespace AgentThinkModelsV1Response { + export type Models = Models.Item[]; + + export namespace Models { + export type Item = + /** + * OpenAI models */ + | { + id: + | "gpt-5" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "gpt-4o" + | "gpt-4o-mini"; + name: string; + provider: "open_ai"; + } + /** + * Anthropic models */ + | { + id: "claude-3-5-haiku-latest" | "claude-sonnet-4-20250514"; + name: string; + provider: "anthropic"; + } + /** + * Google models */ + | { + id: "gemini-2.5-flash" | "gemini-2.0-flash" | "gemini-2.0-flash-lite"; + name: string; + provider: "google"; + } + /** + * Groq models */ + | { + id: "openai/gpt-oss-20b"; + name: string; + provider: "groq"; + } + /** + * AWS Bedrock models (custom models accepted) */ + | { + id: string; + name: string; + provider: "aws_bedrock"; + }; + } +} diff --git a/src/api/types/BillingBreakdownV1Response.ts b/src/api/types/BillingBreakdownV1Response.ts new file mode 100644 index 00000000..2560c5c9 --- /dev/null +++ b/src/api/types/BillingBreakdownV1Response.ts @@ -0,0 +1,46 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface BillingBreakdownV1Response { + /** Start date of the billing summmary period */ + start: string; + /** End date of the billing summary period */ + end: string; + resolution: BillingBreakdownV1Response.Resolution; + results: BillingBreakdownV1Response.Results.Item[]; +} + +export namespace BillingBreakdownV1Response { + export interface Resolution { + /** Time unit for the resolution */ + units: string; + /** Amount of units */ + amount: number; + } + + export type Results = Results.Item[]; + + export namespace Results { + export interface Item { + /** USD cost of the billing for this grouping */ + dollars: number; + grouping: Item.Grouping; + } + + export namespace Item { + export interface Grouping { + /** Start date for this group */ + start?: string; + /** End date for this group */ + end?: string; + /** Optional accessor identifier, null unless grouped by accessor. */ + accessor?: string; + /** Optional deployment identifier, null unless grouped by deployment. */ + deployment?: string; + /** Optional line item identifier, null unless grouped by line item. */ + line_item?: string; + /** Optional list of tags, null unless grouped by tags. */ + tags?: string[]; + } + } + } +} diff --git a/src/api/types/CreateKeyV1RequestOne.ts b/src/api/types/CreateKeyV1RequestOne.ts new file mode 100644 index 00000000..d4d79107 --- /dev/null +++ b/src/api/types/CreateKeyV1RequestOne.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type CreateKeyV1RequestOne = unknown; diff --git a/src/api/types/CreateKeyV1Response.ts b/src/api/types/CreateKeyV1Response.ts new file mode 100644 index 00000000..6b4dfce1 --- /dev/null +++ b/src/api/types/CreateKeyV1Response.ts @@ -0,0 +1,19 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * API key created + */ +export interface CreateKeyV1Response { + /** The unique identifier of the API key */ + api_key_id?: string; + /** The API key */ + key?: string; + /** A comment for the API key */ + comment?: string; + /** The scopes for the API key */ + scopes?: string[]; + /** The tags for the API key */ + tags?: string[]; + /** The expiration date of the API key */ + expiration_date?: string; +} diff --git a/src/api/types/CreateProjectDistributionCredentialsV1Response.ts b/src/api/types/CreateProjectDistributionCredentialsV1Response.ts new file mode 100644 index 00000000..116662a1 --- /dev/null +++ b/src/api/types/CreateProjectDistributionCredentialsV1Response.ts @@ -0,0 +1,28 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface CreateProjectDistributionCredentialsV1Response { + member: CreateProjectDistributionCredentialsV1Response.Member; + distribution_credentials: CreateProjectDistributionCredentialsV1Response.DistributionCredentials; +} + +export namespace CreateProjectDistributionCredentialsV1Response { + export interface Member { + /** Unique identifier for the member */ + member_id: string; + /** Email address of the member */ + email: string; + } + + export interface DistributionCredentials { + /** Unique identifier for the distribution credentials */ + distribution_credentials_id: string; + /** The provider of the distribution service */ + provider: string; + /** Optional comment about the credentials */ + comment?: string; + /** List of permission scopes for the credentials */ + scopes: string[]; + /** Timestamp when the credentials were created */ + created: string; + } +} diff --git a/src/api/types/CreateProjectInviteV1Response.ts b/src/api/types/CreateProjectInviteV1Response.ts new file mode 100644 index 00000000..95fbfbea --- /dev/null +++ b/src/api/types/CreateProjectInviteV1Response.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface CreateProjectInviteV1Response { + /** confirmation message */ + message?: string; +} diff --git a/src/api/types/DeleteProjectInviteV1Response.ts b/src/api/types/DeleteProjectInviteV1Response.ts new file mode 100644 index 00000000..6efceff0 --- /dev/null +++ b/src/api/types/DeleteProjectInviteV1Response.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface DeleteProjectInviteV1Response { + /** confirmation message */ + message?: string; +} diff --git a/src/api/types/DeleteProjectKeyV1Response.ts b/src/api/types/DeleteProjectKeyV1Response.ts new file mode 100644 index 00000000..a2cd0864 --- /dev/null +++ b/src/api/types/DeleteProjectKeyV1Response.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface DeleteProjectKeyV1Response { + message?: string; +} diff --git a/src/api/types/DeleteProjectMemberV1Response.ts b/src/api/types/DeleteProjectMemberV1Response.ts new file mode 100644 index 00000000..686ec2a0 --- /dev/null +++ b/src/api/types/DeleteProjectMemberV1Response.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface DeleteProjectMemberV1Response { + /** confirmation message */ + message?: string; +} diff --git a/src/api/types/DeleteProjectV1Response.ts b/src/api/types/DeleteProjectV1Response.ts new file mode 100644 index 00000000..40b89594 --- /dev/null +++ b/src/api/types/DeleteProjectV1Response.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface DeleteProjectV1Response { + /** Confirmation message */ + message?: string; +} diff --git a/src/api/types/ErrorResponse.ts b/src/api/types/ErrorResponse.ts new file mode 100644 index 00000000..dfddd4c4 --- /dev/null +++ b/src/api/types/ErrorResponse.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export type ErrorResponse = + | Deepgram.ErrorResponseTextError + | Deepgram.ErrorResponseLegacyError + | Deepgram.ErrorResponseModernError; diff --git a/src/api/types/ErrorResponseLegacyError.ts b/src/api/types/ErrorResponseLegacyError.ts new file mode 100644 index 00000000..eff1a6f9 --- /dev/null +++ b/src/api/types/ErrorResponseLegacyError.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ErrorResponseLegacyError { + /** The error code */ + err_code?: string; + /** The error message */ + err_msg?: string; + /** The request ID */ + request_id?: string; +} diff --git a/src/api/types/ErrorResponseModernError.ts b/src/api/types/ErrorResponseModernError.ts new file mode 100644 index 00000000..e000b42a --- /dev/null +++ b/src/api/types/ErrorResponseModernError.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ErrorResponseModernError { + /** The category of the error */ + category?: string; + /** A message about the error */ + message?: string; + /** A description of the error */ + details?: string; + /** The unique identifier of the request */ + request_id?: string; +} diff --git a/src/api/types/ErrorResponseTextError.ts b/src/api/types/ErrorResponseTextError.ts new file mode 100644 index 00000000..c7d34a39 --- /dev/null +++ b/src/api/types/ErrorResponseTextError.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ErrorResponseTextError = string; diff --git a/src/api/types/GetModelV1Response.ts b/src/api/types/GetModelV1Response.ts new file mode 100644 index 00000000..835ff0c1 --- /dev/null +++ b/src/api/types/GetModelV1Response.ts @@ -0,0 +1,33 @@ +// This file was auto-generated by Fern from our API Definition. + +export type GetModelV1Response = + | { + name?: string | undefined; + canonical_name?: string | undefined; + architecture?: string | undefined; + languages?: string[] | undefined; + version?: string | undefined; + uuid?: string | undefined; + batch?: boolean | undefined; + streaming?: boolean | undefined; + formatted_output?: boolean | undefined; + } + | { + name?: string | undefined; + canonical_name?: string | undefined; + architecture?: string | undefined; + languages?: string[] | undefined; + version?: string | undefined; + uuid?: string | undefined; + metadata?: + | { + accent?: string | undefined; + age?: string | undefined; + color?: string | undefined; + image?: string | undefined; + sample?: string | undefined; + tags?: string[] | undefined; + use_cases?: string[] | undefined; + } + | undefined; + }; diff --git a/src/api/types/GetProjectBalanceV1Response.ts b/src/api/types/GetProjectBalanceV1Response.ts new file mode 100644 index 00000000..41a923a2 --- /dev/null +++ b/src/api/types/GetProjectBalanceV1Response.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface GetProjectBalanceV1Response { + /** The unique identifier of the balance */ + balance_id?: string; + /** The amount of the balance */ + amount?: number; + /** The units of the balance, such as "USD" */ + units?: string; + /** Description or reference of the purchase */ + purchase_order_id?: string; +} diff --git a/src/api/types/GetProjectDistributionCredentialsV1Response.ts b/src/api/types/GetProjectDistributionCredentialsV1Response.ts new file mode 100644 index 00000000..b3a727dc --- /dev/null +++ b/src/api/types/GetProjectDistributionCredentialsV1Response.ts @@ -0,0 +1,28 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface GetProjectDistributionCredentialsV1Response { + member: GetProjectDistributionCredentialsV1Response.Member; + distribution_credentials: GetProjectDistributionCredentialsV1Response.DistributionCredentials; +} + +export namespace GetProjectDistributionCredentialsV1Response { + export interface Member { + /** Unique identifier for the member */ + member_id: string; + /** Email address of the member */ + email: string; + } + + export interface DistributionCredentials { + /** Unique identifier for the distribution credentials */ + distribution_credentials_id: string; + /** The provider of the distribution service */ + provider: string; + /** Optional comment about the credentials */ + comment?: string; + /** List of permission scopes for the credentials */ + scopes: string[]; + /** Timestamp when the credentials were created */ + created: string; + } +} diff --git a/src/api/types/GetProjectKeyV1Response.ts b/src/api/types/GetProjectKeyV1Response.ts new file mode 100644 index 00000000..2043f3f5 --- /dev/null +++ b/src/api/types/GetProjectKeyV1Response.ts @@ -0,0 +1,32 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface GetProjectKeyV1Response { + item?: GetProjectKeyV1Response.Item; +} + +export namespace GetProjectKeyV1Response { + export interface Item { + member?: Item.Member; + } + + export namespace Item { + export interface Member { + member_id?: string; + email?: string; + first_name?: string; + last_name?: string; + api_key?: Member.ApiKey; + } + + export namespace Member { + export interface ApiKey { + api_key_id?: string; + comment?: string; + scopes?: string[]; + tags?: string[]; + expiration_date?: string; + created?: string; + } + } + } +} diff --git a/src/api/types/GetProjectRequestV1Response.ts b/src/api/types/GetProjectRequestV1Response.ts new file mode 100644 index 00000000..440ef178 --- /dev/null +++ b/src/api/types/GetProjectRequestV1Response.ts @@ -0,0 +1,7 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export interface GetProjectRequestV1Response { + request?: Deepgram.ProjectRequestResponse; +} diff --git a/src/api/types/GetProjectV1Response.ts b/src/api/types/GetProjectV1Response.ts new file mode 100644 index 00000000..1d91da68 --- /dev/null +++ b/src/api/types/GetProjectV1Response.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface GetProjectV1Response { + /** The unique identifier of the project */ + project_id?: string; + /** Model Improvement Program opt-out */ + mip_opt_out?: boolean; + /** The name of the project */ + name?: string; +} diff --git a/src/api/types/GrantV1Response.ts b/src/api/types/GrantV1Response.ts new file mode 100644 index 00000000..4e91adaa --- /dev/null +++ b/src/api/types/GrantV1Response.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface GrantV1Response { + /** JSON Web Token (JWT) */ + access_token: string; + /** Time in seconds until the JWT expires */ + expires_in?: number; +} diff --git a/src/api/types/LeaveProjectV1Response.ts b/src/api/types/LeaveProjectV1Response.ts new file mode 100644 index 00000000..9d6f18a5 --- /dev/null +++ b/src/api/types/LeaveProjectV1Response.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeaveProjectV1Response { + /** confirmation message */ + message?: string; +} diff --git a/src/api/types/ListBillingFieldsV1Response.ts b/src/api/types/ListBillingFieldsV1Response.ts new file mode 100644 index 00000000..72e4dca4 --- /dev/null +++ b/src/api/types/ListBillingFieldsV1Response.ts @@ -0,0 +1,26 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListBillingFieldsV1Response { + /** List of accessor UUIDs for the time period */ + accessors?: string[]; + /** List of deployment types for the time period */ + deployments?: ListBillingFieldsV1Response.Deployments.Item[]; + /** List of tags for the time period */ + tags?: string[]; + /** Map of line item names to human-readable descriptions for the time period */ + line_items?: Record; +} + +export namespace ListBillingFieldsV1Response { + export type Deployments = Deployments.Item[]; + + export namespace Deployments { + export const Item = { + Hosted: "hosted", + Beta: "beta", + SelfHosted: "self-hosted", + Dedicated: "dedicated", + } as const; + export type Item = (typeof Item)[keyof typeof Item]; + } +} diff --git a/src/api/types/ListModelsV1Response.ts b/src/api/types/ListModelsV1Response.ts new file mode 100644 index 00000000..115e3dee --- /dev/null +++ b/src/api/types/ListModelsV1Response.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export interface ListModelsV1Response { + stt?: Deepgram.ListModelsV1ResponseSttModels[]; + tts?: Deepgram.ListModelsV1ResponseTtsModels[]; +} diff --git a/src/api/types/ListModelsV1ResponseSttModels.ts b/src/api/types/ListModelsV1ResponseSttModels.ts new file mode 100644 index 00000000..247b34a8 --- /dev/null +++ b/src/api/types/ListModelsV1ResponseSttModels.ts @@ -0,0 +1,13 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListModelsV1ResponseSttModels { + name?: string; + canonical_name?: string; + architecture?: string; + languages?: string[]; + version?: string; + uuid?: string; + batch?: boolean; + streaming?: boolean; + formatted_output?: boolean; +} diff --git a/src/api/types/ListModelsV1ResponseTtsModels.ts b/src/api/types/ListModelsV1ResponseTtsModels.ts new file mode 100644 index 00000000..688c99ce --- /dev/null +++ b/src/api/types/ListModelsV1ResponseTtsModels.ts @@ -0,0 +1,23 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListModelsV1ResponseTtsModels { + name?: string; + canonical_name?: string; + architecture?: string; + languages?: string[]; + version?: string; + uuid?: string; + metadata?: ListModelsV1ResponseTtsModels.Metadata; +} + +export namespace ListModelsV1ResponseTtsModels { + export interface Metadata { + accent?: string; + age?: string; + color?: string; + image?: string; + sample?: string; + tags?: string[]; + use_cases?: string[]; + } +} diff --git a/src/api/types/ListProjectBalancesV1Response.ts b/src/api/types/ListProjectBalancesV1Response.ts new file mode 100644 index 00000000..a16a2cfe --- /dev/null +++ b/src/api/types/ListProjectBalancesV1Response.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListProjectBalancesV1Response { + balances?: ListProjectBalancesV1Response.Balances.Item[]; +} + +export namespace ListProjectBalancesV1Response { + export type Balances = Balances.Item[]; + + export namespace Balances { + export interface Item { + /** The unique identifier of the balance */ + balance_id?: string; + /** The amount of the balance */ + amount?: number; + /** The units of the balance, such as "USD" */ + units?: string; + /** Description or reference of the purchase */ + purchase_order_id?: string; + } + } +} diff --git a/src/api/types/ListProjectDistributionCredentialsV1Response.ts b/src/api/types/ListProjectDistributionCredentialsV1Response.ts new file mode 100644 index 00000000..9244388a --- /dev/null +++ b/src/api/types/ListProjectDistributionCredentialsV1Response.ts @@ -0,0 +1,39 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListProjectDistributionCredentialsV1Response { + /** Array of distribution credentials with associated member information */ + distribution_credentials?: ListProjectDistributionCredentialsV1Response.DistributionCredentials.Item[]; +} + +export namespace ListProjectDistributionCredentialsV1Response { + export type DistributionCredentials = DistributionCredentials.Item[]; + + export namespace DistributionCredentials { + export interface Item { + member: Item.Member; + distribution_credentials: Item.DistributionCredentials; + } + + export namespace Item { + export interface Member { + /** Unique identifier for the member */ + member_id: string; + /** Email address of the member */ + email: string; + } + + export interface DistributionCredentials { + /** Unique identifier for the distribution credentials */ + distribution_credentials_id: string; + /** The provider of the distribution service */ + provider: string; + /** Optional comment about the credentials */ + comment?: string; + /** List of permission scopes for the credentials */ + scopes: string[]; + /** Timestamp when the credentials were created */ + created: string; + } + } + } +} diff --git a/src/api/types/ListProjectInvitesV1Response.ts b/src/api/types/ListProjectInvitesV1Response.ts new file mode 100644 index 00000000..f7b69603 --- /dev/null +++ b/src/api/types/ListProjectInvitesV1Response.ts @@ -0,0 +1,18 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListProjectInvitesV1Response { + invites?: ListProjectInvitesV1Response.Invites.Item[]; +} + +export namespace ListProjectInvitesV1Response { + export type Invites = Invites.Item[]; + + export namespace Invites { + export interface Item { + /** The email address of the invitee */ + email?: string; + /** The scope of the invitee */ + scope?: string; + } + } +} diff --git a/src/api/types/ListProjectKeysV1Response.ts b/src/api/types/ListProjectKeysV1Response.ts new file mode 100644 index 00000000..843b630a --- /dev/null +++ b/src/api/types/ListProjectKeysV1Response.ts @@ -0,0 +1,30 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListProjectKeysV1Response { + api_keys?: ListProjectKeysV1Response.ApiKeys.Item[]; +} + +export namespace ListProjectKeysV1Response { + export type ApiKeys = ApiKeys.Item[]; + + export namespace ApiKeys { + export interface Item { + member?: Item.Member; + api_key?: Item.ApiKey; + } + + export namespace Item { + export interface Member { + member_id?: string; + email?: string; + } + + export interface ApiKey { + api_key_id?: string; + comment?: string; + scopes?: string[]; + created?: string; + } + } + } +} diff --git a/src/api/types/ListProjectMemberScopesV1Response.ts b/src/api/types/ListProjectMemberScopesV1Response.ts new file mode 100644 index 00000000..372766ef --- /dev/null +++ b/src/api/types/ListProjectMemberScopesV1Response.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListProjectMemberScopesV1Response { + /** The API scopes of the member */ + scopes?: string[]; +} diff --git a/src/api/types/ListProjectMembersV1Response.ts b/src/api/types/ListProjectMembersV1Response.ts new file mode 100644 index 00000000..34ca0079 --- /dev/null +++ b/src/api/types/ListProjectMembersV1Response.ts @@ -0,0 +1,17 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListProjectMembersV1Response { + members?: ListProjectMembersV1Response.Members.Item[]; +} + +export namespace ListProjectMembersV1Response { + export type Members = Members.Item[]; + + export namespace Members { + export interface Item { + /** The unique identifier of the member */ + member_id?: string; + email?: string; + } + } +} diff --git a/src/api/types/ListProjectPurchasesV1Response.ts b/src/api/types/ListProjectPurchasesV1Response.ts new file mode 100644 index 00000000..6788fa35 --- /dev/null +++ b/src/api/types/ListProjectPurchasesV1Response.ts @@ -0,0 +1,20 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListProjectPurchasesV1Response { + orders?: ListProjectPurchasesV1Response.Orders.Item[]; +} + +export namespace ListProjectPurchasesV1Response { + export type Orders = Orders.Item[]; + + export namespace Orders { + export interface Item { + order_id?: string; + expiration?: string; + created?: string; + amount?: number; + units?: string; + order_type?: string; + } + } +} diff --git a/src/api/types/ListProjectRequestsV1Response.ts b/src/api/types/ListProjectRequestsV1Response.ts new file mode 100644 index 00000000..37578d36 --- /dev/null +++ b/src/api/types/ListProjectRequestsV1Response.ts @@ -0,0 +1,11 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export interface ListProjectRequestsV1Response { + /** The page number of the paginated response */ + page?: number; + /** The number of results per page */ + limit?: number; + requests?: Deepgram.ProjectRequestResponse[]; +} diff --git a/src/api/types/ListProjectsV1Response.ts b/src/api/types/ListProjectsV1Response.ts new file mode 100644 index 00000000..7374b20c --- /dev/null +++ b/src/api/types/ListProjectsV1Response.ts @@ -0,0 +1,18 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListProjectsV1Response { + projects?: ListProjectsV1Response.Projects.Item[]; +} + +export namespace ListProjectsV1Response { + export type Projects = Projects.Item[]; + + export namespace Projects { + export interface Item { + /** The unique identifier of the project */ + project_id?: string; + /** The name of the project */ + name?: string; + } + } +} diff --git a/src/api/types/ListenV1AcceptedResponse.ts b/src/api/types/ListenV1AcceptedResponse.ts new file mode 100644 index 00000000..eee13ab6 --- /dev/null +++ b/src/api/types/ListenV1AcceptedResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Accepted response for asynchronous transcription requests + */ +export interface ListenV1AcceptedResponse { + /** Unique identifier for tracking the asynchronous request */ + request_id: string; +} diff --git a/src/api/types/ListenV1Callback.ts b/src/api/types/ListenV1Callback.ts new file mode 100644 index 00000000..d9046700 --- /dev/null +++ b/src/api/types/ListenV1Callback.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Callback = unknown; diff --git a/src/api/types/ListenV1CallbackMethod.ts b/src/api/types/ListenV1CallbackMethod.ts new file mode 100644 index 00000000..337f0475 --- /dev/null +++ b/src/api/types/ListenV1CallbackMethod.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +/** HTTP method by which the callback request will be made */ +export const ListenV1CallbackMethod = { + Post: "POST", + Get: "GET", + Put: "PUT", + Delete: "DELETE", +} as const; +export type ListenV1CallbackMethod = (typeof ListenV1CallbackMethod)[keyof typeof ListenV1CallbackMethod]; diff --git a/src/api/types/ListenV1Channels.ts b/src/api/types/ListenV1Channels.ts new file mode 100644 index 00000000..362953e4 --- /dev/null +++ b/src/api/types/ListenV1Channels.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Channels = unknown; diff --git a/src/api/types/ListenV1Diarize.ts b/src/api/types/ListenV1Diarize.ts new file mode 100644 index 00000000..feddf67c --- /dev/null +++ b/src/api/types/ListenV1Diarize.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Defaults to `false`. Recognize speaker changes. Each word in the transcript will be assigned a speaker number starting at 0 */ +export const ListenV1Diarize = { + True: "true", + False: "false", +} as const; +export type ListenV1Diarize = (typeof ListenV1Diarize)[keyof typeof ListenV1Diarize]; diff --git a/src/api/types/ListenV1Dictation.ts b/src/api/types/ListenV1Dictation.ts new file mode 100644 index 00000000..eee20e68 --- /dev/null +++ b/src/api/types/ListenV1Dictation.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Identify and extract key entities from content in submitted audio */ +export const ListenV1Dictation = { + True: "true", + False: "false", +} as const; +export type ListenV1Dictation = (typeof ListenV1Dictation)[keyof typeof ListenV1Dictation]; diff --git a/src/api/types/ListenV1Encoding.ts b/src/api/types/ListenV1Encoding.ts new file mode 100644 index 00000000..689c33ed --- /dev/null +++ b/src/api/types/ListenV1Encoding.ts @@ -0,0 +1,17 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Specify the expected encoding of your submitted audio */ +export const ListenV1Encoding = { + Linear16: "linear16", + Linear32: "linear32", + Flac: "flac", + Alaw: "alaw", + Mulaw: "mulaw", + AmrNb: "amr-nb", + AmrWb: "amr-wb", + Opus: "opus", + OggOpus: "ogg-opus", + Speex: "speex", + G729: "g729", +} as const; +export type ListenV1Encoding = (typeof ListenV1Encoding)[keyof typeof ListenV1Encoding]; diff --git a/src/api/types/ListenV1Endpointing.ts b/src/api/types/ListenV1Endpointing.ts new file mode 100644 index 00000000..2b313a03 --- /dev/null +++ b/src/api/types/ListenV1Endpointing.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Endpointing = unknown; diff --git a/src/api/types/ListenV1Extra.ts b/src/api/types/ListenV1Extra.ts new file mode 100644 index 00000000..8457e361 --- /dev/null +++ b/src/api/types/ListenV1Extra.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Extra = unknown; diff --git a/src/api/types/ListenV1InterimResults.ts b/src/api/types/ListenV1InterimResults.ts new file mode 100644 index 00000000..ae6fd8d3 --- /dev/null +++ b/src/api/types/ListenV1InterimResults.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Specifies whether the streaming endpoint should provide ongoing transcription updates as more audio is received. When set to true, the endpoint sends continuous updates, meaning transcription results may evolve over time */ +export const ListenV1InterimResults = { + True: "true", + False: "false", +} as const; +export type ListenV1InterimResults = (typeof ListenV1InterimResults)[keyof typeof ListenV1InterimResults]; diff --git a/src/api/types/ListenV1Keyterm.ts b/src/api/types/ListenV1Keyterm.ts new file mode 100644 index 00000000..6446ffc3 --- /dev/null +++ b/src/api/types/ListenV1Keyterm.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Keyterm = unknown; diff --git a/src/api/types/ListenV1Keywords.ts b/src/api/types/ListenV1Keywords.ts new file mode 100644 index 00000000..0d88bed7 --- /dev/null +++ b/src/api/types/ListenV1Keywords.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Keywords = unknown; diff --git a/src/api/types/ListenV1Language.ts b/src/api/types/ListenV1Language.ts new file mode 100644 index 00000000..1f614f5a --- /dev/null +++ b/src/api/types/ListenV1Language.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Language = unknown; diff --git a/src/api/types/ListenV1MipOptOut.ts b/src/api/types/ListenV1MipOptOut.ts new file mode 100644 index 00000000..8d86f80a --- /dev/null +++ b/src/api/types/ListenV1MipOptOut.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1MipOptOut = unknown; diff --git a/src/api/types/ListenV1Model.ts b/src/api/types/ListenV1Model.ts new file mode 100644 index 00000000..32b63261 --- /dev/null +++ b/src/api/types/ListenV1Model.ts @@ -0,0 +1,36 @@ +// This file was auto-generated by Fern from our API Definition. + +/** AI model to use for the transcription */ +export const ListenV1Model = { + Nova3: "nova-3", + Nova3General: "nova-3-general", + Nova3Medical: "nova-3-medical", + Nova2: "nova-2", + Nova2General: "nova-2-general", + Nova2Meeting: "nova-2-meeting", + Nova2Finance: "nova-2-finance", + Nova2Conversationalai: "nova-2-conversationalai", + Nova2Voicemail: "nova-2-voicemail", + Nova2Video: "nova-2-video", + Nova2Medical: "nova-2-medical", + Nova2Drivethru: "nova-2-drivethru", + Nova2Automotive: "nova-2-automotive", + Nova: "nova", + NovaGeneral: "nova-general", + NovaPhonecall: "nova-phonecall", + NovaMedical: "nova-medical", + Enhanced: "enhanced", + EnhancedGeneral: "enhanced-general", + EnhancedMeeting: "enhanced-meeting", + EnhancedPhonecall: "enhanced-phonecall", + EnhancedFinance: "enhanced-finance", + Base: "base", + Meeting: "meeting", + Phonecall: "phonecall", + Finance: "finance", + Conversationalai: "conversationalai", + Voicemail: "voicemail", + Video: "video", + Custom: "custom", +} as const; +export type ListenV1Model = (typeof ListenV1Model)[keyof typeof ListenV1Model]; diff --git a/src/api/types/ListenV1Multichannel.ts b/src/api/types/ListenV1Multichannel.ts new file mode 100644 index 00000000..18249907 --- /dev/null +++ b/src/api/types/ListenV1Multichannel.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Transcribe each audio channel independently */ +export const ListenV1Multichannel = { + True: "true", + False: "false", +} as const; +export type ListenV1Multichannel = (typeof ListenV1Multichannel)[keyof typeof ListenV1Multichannel]; diff --git a/src/api/types/ListenV1Numerals.ts b/src/api/types/ListenV1Numerals.ts new file mode 100644 index 00000000..4a87e0df --- /dev/null +++ b/src/api/types/ListenV1Numerals.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Convert numbers from written format to numerical format */ +export const ListenV1Numerals = { + True: "true", + False: "false", +} as const; +export type ListenV1Numerals = (typeof ListenV1Numerals)[keyof typeof ListenV1Numerals]; diff --git a/src/api/types/ListenV1ProfanityFilter.ts b/src/api/types/ListenV1ProfanityFilter.ts new file mode 100644 index 00000000..8cc210cd --- /dev/null +++ b/src/api/types/ListenV1ProfanityFilter.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Profanity Filter looks for recognized profanity and converts it to the nearest recognized non-profane word or removes it from the transcript completely */ +export const ListenV1ProfanityFilter = { + True: "true", + False: "false", +} as const; +export type ListenV1ProfanityFilter = (typeof ListenV1ProfanityFilter)[keyof typeof ListenV1ProfanityFilter]; diff --git a/src/api/types/ListenV1Punctuate.ts b/src/api/types/ListenV1Punctuate.ts new file mode 100644 index 00000000..5433633c --- /dev/null +++ b/src/api/types/ListenV1Punctuate.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Add punctuation and capitalization to the transcript */ +export const ListenV1Punctuate = { + True: "true", + False: "false", +} as const; +export type ListenV1Punctuate = (typeof ListenV1Punctuate)[keyof typeof ListenV1Punctuate]; diff --git a/src/api/types/ListenV1Redact.ts b/src/api/types/ListenV1Redact.ts new file mode 100644 index 00000000..9b2f4ec6 --- /dev/null +++ b/src/api/types/ListenV1Redact.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Redaction removes sensitive information from your transcripts */ +export const ListenV1Redact = { + True: "true", + False: "false", + Pci: "pci", + Numbers: "numbers", + AggressiveNumbers: "aggressive_numbers", + Ssn: "ssn", +} as const; +export type ListenV1Redact = (typeof ListenV1Redact)[keyof typeof ListenV1Redact]; diff --git a/src/api/types/ListenV1Replace.ts b/src/api/types/ListenV1Replace.ts new file mode 100644 index 00000000..9acccf5b --- /dev/null +++ b/src/api/types/ListenV1Replace.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Replace = unknown; diff --git a/src/api/types/ListenV1RequestFile.ts b/src/api/types/ListenV1RequestFile.ts new file mode 100644 index 00000000..aa2ce973 --- /dev/null +++ b/src/api/types/ListenV1RequestFile.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Binary audio file to transcribe + */ +export type ListenV1RequestFile = string; diff --git a/src/api/types/ListenV1Response.ts b/src/api/types/ListenV1Response.ts new file mode 100644 index 00000000..d1c0bfc1 --- /dev/null +++ b/src/api/types/ListenV1Response.ts @@ -0,0 +1,11 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +/** + * The standard transcription response + */ +export interface ListenV1Response { + metadata: Deepgram.ListenV1ResponseMetadata; + results: Deepgram.ListenV1ResponseResults; +} diff --git a/src/api/types/ListenV1ResponseMetadata.ts b/src/api/types/ListenV1ResponseMetadata.ts new file mode 100644 index 00000000..679eff32 --- /dev/null +++ b/src/api/types/ListenV1ResponseMetadata.ts @@ -0,0 +1,43 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1ResponseMetadata { + transaction_key?: string; + request_id: string; + sha256: string; + created: string; + duration: number; + channels: number; + models: string[]; + model_info: Record; + summary_info?: ListenV1ResponseMetadata.SummaryInfo; + sentiment_info?: ListenV1ResponseMetadata.SentimentInfo; + topics_info?: ListenV1ResponseMetadata.TopicsInfo; + intents_info?: ListenV1ResponseMetadata.IntentsInfo; + tags?: string[]; +} + +export namespace ListenV1ResponseMetadata { + export interface SummaryInfo { + model_uuid?: string; + input_tokens?: number; + output_tokens?: number; + } + + export interface SentimentInfo { + model_uuid?: string; + input_tokens?: number; + output_tokens?: number; + } + + export interface TopicsInfo { + model_uuid?: string; + input_tokens?: number; + output_tokens?: number; + } + + export interface IntentsInfo { + model_uuid?: string; + input_tokens?: number; + output_tokens?: number; + } +} diff --git a/src/api/types/ListenV1ResponseResults.ts b/src/api/types/ListenV1ResponseResults.ts new file mode 100644 index 00000000..9b82901e --- /dev/null +++ b/src/api/types/ListenV1ResponseResults.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export interface ListenV1ResponseResults { + channels: Deepgram.ListenV1ResponseResultsChannels; + utterances?: Deepgram.ListenV1ResponseResultsUtterances; + summary?: Deepgram.ListenV1ResponseResultsSummary; + topics?: Deepgram.SharedTopics; + intents?: Deepgram.SharedIntents; + sentiments?: Deepgram.SharedSentiments; +} diff --git a/src/api/types/ListenV1ResponseResultsChannels.ts b/src/api/types/ListenV1ResponseResultsChannels.ts new file mode 100644 index 00000000..3c74d6f3 --- /dev/null +++ b/src/api/types/ListenV1ResponseResultsChannels.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export type ListenV1ResponseResultsChannels = Deepgram.ListenV1ResponseResultsChannelsItem[]; diff --git a/src/api/types/ListenV1ResponseResultsChannelsItem.ts b/src/api/types/ListenV1ResponseResultsChannelsItem.ts new file mode 100644 index 00000000..a2e45e66 --- /dev/null +++ b/src/api/types/ListenV1ResponseResultsChannelsItem.ts @@ -0,0 +1,109 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1ResponseResultsChannelsItem { + search?: ListenV1ResponseResultsChannelsItem.Search.Item[]; + alternatives?: ListenV1ResponseResultsChannelsItem.Alternatives.Item[]; + detected_language?: string; +} + +export namespace ListenV1ResponseResultsChannelsItem { + export type Search = Search.Item[]; + + export namespace Search { + export interface Item { + query?: string; + hits?: Item.Hits.Item[]; + } + + export namespace Item { + export type Hits = Hits.Item[]; + + export namespace Hits { + export interface Item { + confidence?: number; + start?: number; + end?: number; + snippet?: string; + } + } + } + } + + export type Alternatives = Alternatives.Item[]; + + export namespace Alternatives { + export interface Item { + transcript?: string; + confidence?: number; + words?: Item.Words.Item[]; + paragraphs?: Item.Paragraphs; + summaries?: Item.Summaries.Item[]; + topics?: Item.Topics.Item[]; + } + + export namespace Item { + export type Words = Words.Item[]; + + export namespace Words { + export interface Item { + word?: string; + start?: number; + end?: number; + confidence?: number; + } + } + + export interface Paragraphs { + transcript?: string; + paragraphs?: Paragraphs.Paragraphs.Item[]; + } + + export namespace Paragraphs { + export type Paragraphs = Paragraphs.Item[]; + + export namespace Paragraphs { + export interface Item { + sentences?: Item.Sentences.Item[]; + speaker?: number; + num_words?: number; + start?: number; + end?: number; + } + + export namespace Item { + export type Sentences = Sentences.Item[]; + + export namespace Sentences { + export interface Item { + text?: string; + start?: number; + end?: number; + } + } + } + } + } + + export type Summaries = Summaries.Item[]; + + export namespace Summaries { + export interface Item { + summary?: string; + start_word?: number; + end_word?: number; + } + } + + export type Topics = Topics.Item[]; + + export namespace Topics { + export interface Item { + text?: string; + start_word?: number; + end_word?: number; + topics?: string[]; + } + } + } + } +} diff --git a/src/api/types/ListenV1ResponseResultsSummary.ts b/src/api/types/ListenV1ResponseResultsSummary.ts new file mode 100644 index 00000000..33bb678b --- /dev/null +++ b/src/api/types/ListenV1ResponseResultsSummary.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1ResponseResultsSummary { + result?: string; + short?: string; +} diff --git a/src/api/types/ListenV1ResponseResultsUtterances.ts b/src/api/types/ListenV1ResponseResultsUtterances.ts new file mode 100644 index 00000000..2d035379 --- /dev/null +++ b/src/api/types/ListenV1ResponseResultsUtterances.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export type ListenV1ResponseResultsUtterances = Deepgram.ListenV1ResponseResultsUtterancesItem[]; diff --git a/src/api/types/ListenV1ResponseResultsUtterancesItem.ts b/src/api/types/ListenV1ResponseResultsUtterancesItem.ts new file mode 100644 index 00000000..787a32f4 --- /dev/null +++ b/src/api/types/ListenV1ResponseResultsUtterancesItem.ts @@ -0,0 +1,28 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ListenV1ResponseResultsUtterancesItem { + start?: number; + end?: number; + confidence?: number; + channel?: number; + transcript?: string; + words?: ListenV1ResponseResultsUtterancesItem.Words.Item[]; + speaker?: number; + id?: string; +} + +export namespace ListenV1ResponseResultsUtterancesItem { + export type Words = Words.Item[]; + + export namespace Words { + export interface Item { + word?: string; + start?: number; + end?: number; + confidence?: number; + speaker?: number; + speaker_confidence?: number; + punctuated_word?: string; + } + } +} diff --git a/src/api/types/ListenV1SampleRate.ts b/src/api/types/ListenV1SampleRate.ts new file mode 100644 index 00000000..d37e86c8 --- /dev/null +++ b/src/api/types/ListenV1SampleRate.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1SampleRate = unknown; diff --git a/src/api/types/ListenV1Search.ts b/src/api/types/ListenV1Search.ts new file mode 100644 index 00000000..3383114d --- /dev/null +++ b/src/api/types/ListenV1Search.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Search = unknown; diff --git a/src/api/types/ListenV1SmartFormat.ts b/src/api/types/ListenV1SmartFormat.ts new file mode 100644 index 00000000..30c7e3f8 --- /dev/null +++ b/src/api/types/ListenV1SmartFormat.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Apply formatting to transcript output. When set to true, additional formatting will be applied to transcripts to improve readability */ +export const ListenV1SmartFormat = { + True: "true", + False: "false", +} as const; +export type ListenV1SmartFormat = (typeof ListenV1SmartFormat)[keyof typeof ListenV1SmartFormat]; diff --git a/src/api/types/ListenV1Tag.ts b/src/api/types/ListenV1Tag.ts new file mode 100644 index 00000000..b1adf7c5 --- /dev/null +++ b/src/api/types/ListenV1Tag.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Tag = unknown; diff --git a/src/api/types/ListenV1UtteranceEndMs.ts b/src/api/types/ListenV1UtteranceEndMs.ts new file mode 100644 index 00000000..31dcad6f --- /dev/null +++ b/src/api/types/ListenV1UtteranceEndMs.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1UtteranceEndMs = unknown; diff --git a/src/api/types/ListenV1VadEvents.ts b/src/api/types/ListenV1VadEvents.ts new file mode 100644 index 00000000..3819893a --- /dev/null +++ b/src/api/types/ListenV1VadEvents.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Indicates that speech has started. You'll begin receiving Speech Started messages upon speech starting */ +export const ListenV1VadEvents = { + True: "true", + False: "false", +} as const; +export type ListenV1VadEvents = (typeof ListenV1VadEvents)[keyof typeof ListenV1VadEvents]; diff --git a/src/api/types/ListenV1Version.ts b/src/api/types/ListenV1Version.ts new file mode 100644 index 00000000..5a11acdd --- /dev/null +++ b/src/api/types/ListenV1Version.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV1Version = unknown; diff --git a/src/api/types/ListenV2EagerEotThreshold.ts b/src/api/types/ListenV2EagerEotThreshold.ts new file mode 100644 index 00000000..ebb8480a --- /dev/null +++ b/src/api/types/ListenV2EagerEotThreshold.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV2EagerEotThreshold = unknown; diff --git a/src/api/types/ListenV2Encoding.ts b/src/api/types/ListenV2Encoding.ts new file mode 100644 index 00000000..3424ccf3 --- /dev/null +++ b/src/api/types/ListenV2Encoding.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Encoding of the audio stream. Required if sending non-containerized/raw audio. If sending containerized audio, this parameter should be omitted. */ +export const ListenV2Encoding = { + Linear16: "linear16", + Linear32: "linear32", + Mulaw: "mulaw", + Alaw: "alaw", + Opus: "opus", + OggOpus: "ogg-opus", +} as const; +export type ListenV2Encoding = (typeof ListenV2Encoding)[keyof typeof ListenV2Encoding]; diff --git a/src/api/types/ListenV2EotThreshold.ts b/src/api/types/ListenV2EotThreshold.ts new file mode 100644 index 00000000..272c229c --- /dev/null +++ b/src/api/types/ListenV2EotThreshold.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV2EotThreshold = unknown; diff --git a/src/api/types/ListenV2EotTimeoutMs.ts b/src/api/types/ListenV2EotTimeoutMs.ts new file mode 100644 index 00000000..f61e2e56 --- /dev/null +++ b/src/api/types/ListenV2EotTimeoutMs.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV2EotTimeoutMs = unknown; diff --git a/src/api/types/ListenV2Keyterm.ts b/src/api/types/ListenV2Keyterm.ts new file mode 100644 index 00000000..02d00009 --- /dev/null +++ b/src/api/types/ListenV2Keyterm.ts @@ -0,0 +1,7 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Keyterm prompting can improve recognition of specialized terminology. + * Pass multiple keyterm query parameters to boost multiple keyterms. + */ +export type ListenV2Keyterm = string | string[]; diff --git a/src/api/types/ListenV2MipOptOut.ts b/src/api/types/ListenV2MipOptOut.ts new file mode 100644 index 00000000..75085a59 --- /dev/null +++ b/src/api/types/ListenV2MipOptOut.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV2MipOptOut = unknown; diff --git a/src/api/types/ListenV2Model.ts b/src/api/types/ListenV2Model.ts new file mode 100644 index 00000000..1b3431c8 --- /dev/null +++ b/src/api/types/ListenV2Model.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Defines the AI model used to process submitted audio. + */ +export type ListenV2Model = "flux-general-en"; diff --git a/src/api/types/ListenV2SampleRate.ts b/src/api/types/ListenV2SampleRate.ts new file mode 100644 index 00000000..178ecdf6 --- /dev/null +++ b/src/api/types/ListenV2SampleRate.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV2SampleRate = unknown; diff --git a/src/api/types/ListenV2Tag.ts b/src/api/types/ListenV2Tag.ts new file mode 100644 index 00000000..18aee426 --- /dev/null +++ b/src/api/types/ListenV2Tag.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type ListenV2Tag = unknown; diff --git a/src/api/types/ProjectRequestResponse.ts b/src/api/types/ProjectRequestResponse.ts new file mode 100644 index 00000000..93e5ec82 --- /dev/null +++ b/src/api/types/ProjectRequestResponse.ts @@ -0,0 +1,25 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * A single request + */ +export interface ProjectRequestResponse { + /** The unique identifier of the request */ + request_id?: string; + /** The unique identifier of the project */ + project_uuid?: string; + /** The date and time the request was created */ + created?: string; + /** The API path of the request */ + path?: string; + /** The unique identifier of the API key */ + api_key_id?: string; + /** The response of the request */ + response?: Record; + /** The response code of the request */ + code?: number; + /** The deployment type */ + deployment?: string; + /** The callback URL for the request */ + callback?: string; +} diff --git a/src/api/types/ReadV1Request.ts b/src/api/types/ReadV1Request.ts new file mode 100644 index 00000000..10a5ce0f --- /dev/null +++ b/src/api/types/ReadV1Request.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export type ReadV1Request = Deepgram.ReadV1RequestUrl | Deepgram.ReadV1RequestText; diff --git a/src/api/types/ReadV1RequestText.ts b/src/api/types/ReadV1RequestText.ts new file mode 100644 index 00000000..8a9e95ad --- /dev/null +++ b/src/api/types/ReadV1RequestText.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ReadV1RequestText { + /** The plain text to analyze */ + text: string; +} diff --git a/src/api/types/ReadV1RequestUrl.ts b/src/api/types/ReadV1RequestUrl.ts new file mode 100644 index 00000000..a63420ee --- /dev/null +++ b/src/api/types/ReadV1RequestUrl.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ReadV1RequestUrl { + /** A URL pointing to the text source */ + url: string; +} diff --git a/src/api/types/ReadV1Response.ts b/src/api/types/ReadV1Response.ts new file mode 100644 index 00000000..44ea32a0 --- /dev/null +++ b/src/api/types/ReadV1Response.ts @@ -0,0 +1,11 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +/** + * The standard text response + */ +export interface ReadV1Response { + metadata: Deepgram.ReadV1ResponseMetadata; + results: Deepgram.ReadV1ResponseResults; +} diff --git a/src/api/types/ReadV1ResponseMetadata.ts b/src/api/types/ReadV1ResponseMetadata.ts new file mode 100644 index 00000000..58e778f3 --- /dev/null +++ b/src/api/types/ReadV1ResponseMetadata.ts @@ -0,0 +1,43 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ReadV1ResponseMetadata { + metadata?: ReadV1ResponseMetadata.Metadata; +} + +export namespace ReadV1ResponseMetadata { + export interface Metadata { + request_id?: string; + created?: string; + language?: string; + summary_info?: Metadata.SummaryInfo; + sentiment_info?: Metadata.SentimentInfo; + topics_info?: Metadata.TopicsInfo; + intents_info?: Metadata.IntentsInfo; + } + + export namespace Metadata { + export interface SummaryInfo { + model_uuid?: string; + input_tokens?: number; + output_tokens?: number; + } + + export interface SentimentInfo { + model_uuid?: string; + input_tokens?: number; + output_tokens?: number; + } + + export interface TopicsInfo { + model_uuid?: string; + input_tokens?: number; + output_tokens?: number; + } + + export interface IntentsInfo { + model_uuid?: string; + input_tokens?: number; + output_tokens?: number; + } + } +} diff --git a/src/api/types/ReadV1ResponseResults.ts b/src/api/types/ReadV1ResponseResults.ts new file mode 100644 index 00000000..f20b1f0e --- /dev/null +++ b/src/api/types/ReadV1ResponseResults.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Deepgram from "../index.js"; + +export interface ReadV1ResponseResults { + summary?: Deepgram.ReadV1ResponseResultsSummary; + topics?: Deepgram.SharedTopics; + intents?: Deepgram.SharedIntents; + sentiments?: Deepgram.SharedSentiments; +} diff --git a/src/api/types/ReadV1ResponseResultsSummary.ts b/src/api/types/ReadV1ResponseResultsSummary.ts new file mode 100644 index 00000000..5085cfc7 --- /dev/null +++ b/src/api/types/ReadV1ResponseResultsSummary.ts @@ -0,0 +1,20 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Output whenever `summary=true` is used + */ +export interface ReadV1ResponseResultsSummary { + results?: ReadV1ResponseResultsSummary.Results; +} + +export namespace ReadV1ResponseResultsSummary { + export interface Results { + summary?: Results.Summary; + } + + export namespace Results { + export interface Summary { + text?: string; + } + } +} diff --git a/src/api/types/SharedIntents.ts b/src/api/types/SharedIntents.ts new file mode 100644 index 00000000..a8a4d32a --- /dev/null +++ b/src/api/types/SharedIntents.ts @@ -0,0 +1,44 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Output whenever `intents=true` is used + */ +export interface SharedIntents { + results?: SharedIntents.Results; +} + +export namespace SharedIntents { + export interface Results { + intents?: Results.Intents; + } + + export namespace Results { + export interface Intents { + segments?: Intents.Segments.Item[]; + } + + export namespace Intents { + export type Segments = Segments.Item[]; + + export namespace Segments { + export interface Item { + text?: string; + start_word?: number; + end_word?: number; + intents?: Item.Intents.Item[]; + } + + export namespace Item { + export type Intents = Intents.Item[]; + + export namespace Intents { + export interface Item { + intent?: string; + confidence_score?: number; + } + } + } + } + } + } +} diff --git a/src/api/types/SharedSentiments.ts b/src/api/types/SharedSentiments.ts new file mode 100644 index 00000000..4cd332d7 --- /dev/null +++ b/src/api/types/SharedSentiments.ts @@ -0,0 +1,28 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Output whenever `sentiment=true` is used + */ +export interface SharedSentiments { + segments?: SharedSentiments.Segments.Item[]; + average?: SharedSentiments.Average; +} + +export namespace SharedSentiments { + export type Segments = Segments.Item[]; + + export namespace Segments { + export interface Item { + text?: string; + start_word?: number; + end_word?: number; + sentiment?: string; + sentiment_score?: number; + } + } + + export interface Average { + sentiment?: string; + sentiment_score?: number; + } +} diff --git a/src/api/types/SharedTopics.ts b/src/api/types/SharedTopics.ts new file mode 100644 index 00000000..d5631a5b --- /dev/null +++ b/src/api/types/SharedTopics.ts @@ -0,0 +1,44 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * Output whenever `topics=true` is used + */ +export interface SharedTopics { + results?: SharedTopics.Results; +} + +export namespace SharedTopics { + export interface Results { + topics?: Results.Topics; + } + + export namespace Results { + export interface Topics { + segments?: Topics.Segments.Item[]; + } + + export namespace Topics { + export type Segments = Segments.Item[]; + + export namespace Segments { + export interface Item { + text?: string; + start_word?: number; + end_word?: number; + topics?: Item.Topics.Item[]; + } + + export namespace Item { + export type Topics = Topics.Item[]; + + export namespace Topics { + export interface Item { + topic?: string; + confidence_score?: number; + } + } + } + } + } + } +} diff --git a/src/api/types/SpeakV1Encoding.ts b/src/api/types/SpeakV1Encoding.ts new file mode 100644 index 00000000..4c1ff0ab --- /dev/null +++ b/src/api/types/SpeakV1Encoding.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Encoding allows you to specify the expected encoding of your audio output for streaming TTS. Only streaming-compatible encodings are supported. */ +export const SpeakV1Encoding = { + Linear16: "linear16", + Mulaw: "mulaw", + Alaw: "alaw", +} as const; +export type SpeakV1Encoding = (typeof SpeakV1Encoding)[keyof typeof SpeakV1Encoding]; diff --git a/src/api/types/SpeakV1MipOptOut.ts b/src/api/types/SpeakV1MipOptOut.ts new file mode 100644 index 00000000..51bda46f --- /dev/null +++ b/src/api/types/SpeakV1MipOptOut.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type SpeakV1MipOptOut = unknown; diff --git a/src/api/types/SpeakV1Model.ts b/src/api/types/SpeakV1Model.ts new file mode 100644 index 00000000..f1531d95 --- /dev/null +++ b/src/api/types/SpeakV1Model.ts @@ -0,0 +1,69 @@ +// This file was auto-generated by Fern from our API Definition. + +/** AI model used to process submitted text */ +export const SpeakV1Model = { + AuraAsteriaEn: "aura-asteria-en", + AuraLunaEn: "aura-luna-en", + AuraStellaEn: "aura-stella-en", + AuraAthenaEn: "aura-athena-en", + AuraHeraEn: "aura-hera-en", + AuraOrionEn: "aura-orion-en", + AuraArcasEn: "aura-arcas-en", + AuraPerseusEn: "aura-perseus-en", + AuraAngusEn: "aura-angus-en", + AuraOrpheusEn: "aura-orpheus-en", + AuraHeliosEn: "aura-helios-en", + AuraZeusEn: "aura-zeus-en", + Aura2AmaltheaEn: "aura-2-amalthea-en", + Aura2AndromedaEn: "aura-2-andromeda-en", + Aura2ApolloEn: "aura-2-apollo-en", + Aura2ArcasEn: "aura-2-arcas-en", + Aura2AriesEn: "aura-2-aries-en", + Aura2AsteriaEn: "aura-2-asteria-en", + Aura2AthenaEn: "aura-2-athena-en", + Aura2AtlasEn: "aura-2-atlas-en", + Aura2AuroraEn: "aura-2-aurora-en", + Aura2CallistaEn: "aura-2-callista-en", + Aura2CordeliaEn: "aura-2-cordelia-en", + Aura2CoraEn: "aura-2-cora-en", + Aura2DeliaEn: "aura-2-delia-en", + Aura2DracoEn: "aura-2-draco-en", + Aura2ElectraEn: "aura-2-electra-en", + Aura2HarmoniaEn: "aura-2-harmonia-en", + Aura2HelenaEn: "aura-2-helena-en", + Aura2HeraEn: "aura-2-hera-en", + Aura2HermesEn: "aura-2-hermes-en", + Aura2HyperionEn: "aura-2-hyperion-en", + Aura2IrisEn: "aura-2-iris-en", + Aura2JanusEn: "aura-2-janus-en", + Aura2JunoEn: "aura-2-juno-en", + Aura2JupiterEn: "aura-2-jupiter-en", + Aura2LunaEn: "aura-2-luna-en", + Aura2MarsEn: "aura-2-mars-en", + Aura2MinervaEn: "aura-2-minerva-en", + Aura2NeptuneEn: "aura-2-neptune-en", + Aura2OdysseusEn: "aura-2-odysseus-en", + Aura2OpheliaEn: "aura-2-ophelia-en", + Aura2OrionEn: "aura-2-orion-en", + Aura2OrpheusEn: "aura-2-orpheus-en", + Aura2PandoraEn: "aura-2-pandora-en", + Aura2PhoebeEn: "aura-2-phoebe-en", + Aura2PlutoEn: "aura-2-pluto-en", + Aura2SaturnEn: "aura-2-saturn-en", + Aura2SeleneEn: "aura-2-selene-en", + Aura2ThaliaEn: "aura-2-thalia-en", + Aura2TheiaEn: "aura-2-theia-en", + Aura2VestaEn: "aura-2-vesta-en", + Aura2ZeusEn: "aura-2-zeus-en", + Aura2SirioEs: "aura-2-sirio-es", + Aura2NestorEs: "aura-2-nestor-es", + Aura2CarinaEs: "aura-2-carina-es", + Aura2CelesteEs: "aura-2-celeste-es", + Aura2AlvaroEs: "aura-2-alvaro-es", + Aura2DianaEs: "aura-2-diana-es", + Aura2AquilaEs: "aura-2-aquila-es", + Aura2SelenaEs: "aura-2-selena-es", + Aura2EstrellaEs: "aura-2-estrella-es", + Aura2JavierEs: "aura-2-javier-es", +} as const; +export type SpeakV1Model = (typeof SpeakV1Model)[keyof typeof SpeakV1Model]; diff --git a/src/api/types/SpeakV1Response.ts b/src/api/types/SpeakV1Response.ts new file mode 100644 index 00000000..2370db46 --- /dev/null +++ b/src/api/types/SpeakV1Response.ts @@ -0,0 +1,3 @@ +// This file was auto-generated by Fern from our API Definition. + +export type SpeakV1Response = string; diff --git a/src/api/types/SpeakV1SampleRate.ts b/src/api/types/SpeakV1SampleRate.ts new file mode 100644 index 00000000..464d7ff9 --- /dev/null +++ b/src/api/types/SpeakV1SampleRate.ts @@ -0,0 +1,11 @@ +// This file was auto-generated by Fern from our API Definition. + +/** Sample Rate specifies the sample rate for the output audio. Based on encoding 8000 or 24000 are possible defaults. For some encodings sample rate is not configurable. */ +export const SpeakV1SampleRate = { + EightThousand: "8000", + SixteenThousand: "16000", + TwentyFourThousand: "24000", + FortyFourThousandOneHundred: "44100", + FortyEightThousand: "48000", +} as const; +export type SpeakV1SampleRate = (typeof SpeakV1SampleRate)[keyof typeof SpeakV1SampleRate]; diff --git a/src/api/types/UpdateProjectMemberScopesV1Response.ts b/src/api/types/UpdateProjectMemberScopesV1Response.ts new file mode 100644 index 00000000..9a756e86 --- /dev/null +++ b/src/api/types/UpdateProjectMemberScopesV1Response.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface UpdateProjectMemberScopesV1Response { + /** confirmation message */ + message?: string; +} diff --git a/src/api/types/UpdateProjectV1Response.ts b/src/api/types/UpdateProjectV1Response.ts new file mode 100644 index 00000000..3a011162 --- /dev/null +++ b/src/api/types/UpdateProjectV1Response.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface UpdateProjectV1Response { + /** confirmation message */ + message?: string; +} diff --git a/src/api/types/UsageBreakdownV1Response.ts b/src/api/types/UsageBreakdownV1Response.ts new file mode 100644 index 00000000..5f95dc8b --- /dev/null +++ b/src/api/types/UsageBreakdownV1Response.ts @@ -0,0 +1,64 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface UsageBreakdownV1Response { + /** Start date of the usage period */ + start: string; + /** End date of the usage period */ + end: string; + resolution: UsageBreakdownV1Response.Resolution; + results: UsageBreakdownV1Response.Results.Item[]; +} + +export namespace UsageBreakdownV1Response { + export interface Resolution { + /** Time unit for the resolution */ + units: string; + /** Amount of units */ + amount: number; + } + + export type Results = Results.Item[]; + + export namespace Results { + export interface Item { + /** Audio hours processed */ + hours: number; + /** Total hours including all processing */ + total_hours: number; + /** Agent hours used */ + agent_hours: number; + /** Number of input tokens */ + tokens_in: number; + /** Number of output tokens */ + tokens_out: number; + /** Number of text-to-speech characters processed */ + tts_characters: number; + /** Number of requests */ + requests: number; + grouping: Item.Grouping; + } + + export namespace Item { + export interface Grouping { + /** Start date for this group */ + start?: string; + /** End date for this group */ + end?: string; + /** Optional accessor identifier */ + accessor?: string; + /** Optional endpoint identifier */ + endpoint?: string; + /** Optional feature set identifier */ + feature_set?: string; + /** Optional models identifier */ + models?: string; + /** Optional method identifier */ + method?: string; + /** Optional tags */ + tags?: string; + /** Optional deployment identifier */ + deployment?: string; + } + } + } +} diff --git a/src/api/types/UsageFieldsV1Response.ts b/src/api/types/UsageFieldsV1Response.ts new file mode 100644 index 00000000..d5487abb --- /dev/null +++ b/src/api/types/UsageFieldsV1Response.ts @@ -0,0 +1,29 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface UsageFieldsV1Response { + /** List of tags associated with the project */ + tags?: string[]; + /** List of models available for the project. */ + models?: UsageFieldsV1Response.Models.Item[]; + /** Processing methods supported by the API */ + processing_methods?: string[]; + /** API features available to the project */ + features?: string[]; +} + +export namespace UsageFieldsV1Response { + export type Models = Models.Item[]; + + export namespace Models { + export interface Item { + /** Name of the model. */ + name?: string; + /** The language supported by the model (IETF language tag). */ + language?: string; + /** Version identifier of the model, typically with a date and a revision number. */ + version?: string; + /** Unique identifier for the model. */ + model_id?: string; + } + } +} diff --git a/src/api/types/UsageV1Response.ts b/src/api/types/UsageV1Response.ts new file mode 100644 index 00000000..bee029aa --- /dev/null +++ b/src/api/types/UsageV1Response.ts @@ -0,0 +1,14 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface UsageV1Response { + start?: string; + end?: string; + resolution?: UsageV1Response.Resolution; +} + +export namespace UsageV1Response { + export interface Resolution { + units?: string; + amount?: number; + } +} diff --git a/src/api/types/index.ts b/src/api/types/index.ts new file mode 100644 index 00000000..d2aadffd --- /dev/null +++ b/src/api/types/index.ts @@ -0,0 +1,102 @@ +export * from "./AgentThinkModelsV1Response.js"; +export * from "./BillingBreakdownV1Response.js"; +export * from "./CreateKeyV1RequestOne.js"; +export * from "./CreateKeyV1Response.js"; +export * from "./CreateProjectDistributionCredentialsV1Response.js"; +export * from "./CreateProjectInviteV1Response.js"; +export * from "./DeleteProjectInviteV1Response.js"; +export * from "./DeleteProjectKeyV1Response.js"; +export * from "./DeleteProjectMemberV1Response.js"; +export * from "./DeleteProjectV1Response.js"; +export * from "./ErrorResponse.js"; +export * from "./ErrorResponseLegacyError.js"; +export * from "./ErrorResponseModernError.js"; +export * from "./ErrorResponseTextError.js"; +export * from "./GetModelV1Response.js"; +export * from "./GetProjectBalanceV1Response.js"; +export * from "./GetProjectDistributionCredentialsV1Response.js"; +export * from "./GetProjectKeyV1Response.js"; +export * from "./GetProjectRequestV1Response.js"; +export * from "./GetProjectV1Response.js"; +export * from "./GrantV1Response.js"; +export * from "./LeaveProjectV1Response.js"; +export * from "./ListBillingFieldsV1Response.js"; +export * from "./ListenV1AcceptedResponse.js"; +export * from "./ListenV1Callback.js"; +export * from "./ListenV1CallbackMethod.js"; +export * from "./ListenV1Channels.js"; +export * from "./ListenV1Diarize.js"; +export * from "./ListenV1Dictation.js"; +export * from "./ListenV1Encoding.js"; +export * from "./ListenV1Endpointing.js"; +export * from "./ListenV1Extra.js"; +export * from "./ListenV1InterimResults.js"; +export * from "./ListenV1Keyterm.js"; +export * from "./ListenV1Keywords.js"; +export * from "./ListenV1Language.js"; +export * from "./ListenV1MipOptOut.js"; +export * from "./ListenV1Model.js"; +export * from "./ListenV1Multichannel.js"; +export * from "./ListenV1Numerals.js"; +export * from "./ListenV1ProfanityFilter.js"; +export * from "./ListenV1Punctuate.js"; +export * from "./ListenV1Redact.js"; +export * from "./ListenV1Replace.js"; +export * from "./ListenV1RequestFile.js"; +export * from "./ListenV1Response.js"; +export * from "./ListenV1ResponseMetadata.js"; +export * from "./ListenV1ResponseResults.js"; +export * from "./ListenV1ResponseResultsChannels.js"; +export * from "./ListenV1ResponseResultsChannelsItem.js"; +export * from "./ListenV1ResponseResultsSummary.js"; +export * from "./ListenV1ResponseResultsUtterances.js"; +export * from "./ListenV1ResponseResultsUtterancesItem.js"; +export * from "./ListenV1SampleRate.js"; +export * from "./ListenV1Search.js"; +export * from "./ListenV1SmartFormat.js"; +export * from "./ListenV1Tag.js"; +export * from "./ListenV1UtteranceEndMs.js"; +export * from "./ListenV1VadEvents.js"; +export * from "./ListenV1Version.js"; +export * from "./ListenV2EagerEotThreshold.js"; +export * from "./ListenV2Encoding.js"; +export * from "./ListenV2EotThreshold.js"; +export * from "./ListenV2EotTimeoutMs.js"; +export * from "./ListenV2Keyterm.js"; +export * from "./ListenV2MipOptOut.js"; +export * from "./ListenV2Model.js"; +export * from "./ListenV2SampleRate.js"; +export * from "./ListenV2Tag.js"; +export * from "./ListModelsV1Response.js"; +export * from "./ListModelsV1ResponseSttModels.js"; +export * from "./ListModelsV1ResponseTtsModels.js"; +export * from "./ListProjectBalancesV1Response.js"; +export * from "./ListProjectDistributionCredentialsV1Response.js"; +export * from "./ListProjectInvitesV1Response.js"; +export * from "./ListProjectKeysV1Response.js"; +export * from "./ListProjectMemberScopesV1Response.js"; +export * from "./ListProjectMembersV1Response.js"; +export * from "./ListProjectPurchasesV1Response.js"; +export * from "./ListProjectRequestsV1Response.js"; +export * from "./ListProjectsV1Response.js"; +export * from "./ProjectRequestResponse.js"; +export * from "./ReadV1Request.js"; +export * from "./ReadV1RequestText.js"; +export * from "./ReadV1RequestUrl.js"; +export * from "./ReadV1Response.js"; +export * from "./ReadV1ResponseMetadata.js"; +export * from "./ReadV1ResponseResults.js"; +export * from "./ReadV1ResponseResultsSummary.js"; +export * from "./SharedIntents.js"; +export * from "./SharedSentiments.js"; +export * from "./SharedTopics.js"; +export * from "./SpeakV1Encoding.js"; +export * from "./SpeakV1MipOptOut.js"; +export * from "./SpeakV1Model.js"; +export * from "./SpeakV1Response.js"; +export * from "./SpeakV1SampleRate.js"; +export * from "./UpdateProjectMemberScopesV1Response.js"; +export * from "./UpdateProjectV1Response.js"; +export * from "./UsageBreakdownV1Response.js"; +export * from "./UsageFieldsV1Response.js"; +export * from "./UsageV1Response.js"; diff --git a/src/core/exports.ts b/src/core/exports.ts new file mode 100644 index 00000000..43f33fa1 --- /dev/null +++ b/src/core/exports.ts @@ -0,0 +1,3 @@ +export * from "./file/exports.js"; +export * from "./logging/exports.js"; +export * from "./websocket/exports.js"; diff --git a/src/core/fetcher/APIResponse.ts b/src/core/fetcher/APIResponse.ts new file mode 100644 index 00000000..97ab83c2 --- /dev/null +++ b/src/core/fetcher/APIResponse.ts @@ -0,0 +1,23 @@ +import type { RawResponse } from "./RawResponse.js"; + +/** + * The response of an API call. + * It is a successful response or a failed response. + */ +export type APIResponse = SuccessfulResponse | FailedResponse; + +export interface SuccessfulResponse { + ok: true; + body: T; + /** + * @deprecated Use `rawResponse` instead + */ + headers?: Record; + rawResponse: RawResponse; +} + +export interface FailedResponse { + ok: false; + error: T; + rawResponse: RawResponse; +} diff --git a/src/core/fetcher/BinaryResponse.ts b/src/core/fetcher/BinaryResponse.ts new file mode 100644 index 00000000..4b4d0e89 --- /dev/null +++ b/src/core/fetcher/BinaryResponse.ts @@ -0,0 +1,36 @@ +import type { ResponseWithBody } from "./ResponseWithBody.js"; + +export type BinaryResponse = { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/bodyUsed) */ + bodyUsed: boolean; + /** + * Returns a ReadableStream of the response body. + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body) + */ + stream: () => ReadableStream; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/arrayBuffer) */ + arrayBuffer: () => Promise; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/blob) */ + blob: () => Promise; + /** + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/bytes) + * Some versions of the Fetch API may not support this method. + */ + bytes?(): Promise; +}; + +export function getBinaryResponse(response: ResponseWithBody): BinaryResponse { + const binaryResponse: BinaryResponse = { + get bodyUsed() { + return response.bodyUsed; + }, + stream: () => response.body, + arrayBuffer: response.arrayBuffer.bind(response), + blob: response.blob.bind(response), + }; + if ("bytes" in response && typeof response.bytes === "function") { + binaryResponse.bytes = response.bytes.bind(response); + } + + return binaryResponse; +} diff --git a/src/core/fetcher/EndpointMetadata.ts b/src/core/fetcher/EndpointMetadata.ts new file mode 100644 index 00000000..998d68f5 --- /dev/null +++ b/src/core/fetcher/EndpointMetadata.ts @@ -0,0 +1,13 @@ +export type SecuritySchemeKey = string; +/** + * A collection of security schemes, where the key is the name of the security scheme and the value is the list of scopes required for that scheme. + * All schemes in the collection must be satisfied for authentication to be successful. + */ +export type SecuritySchemeCollection = Record; +export type AuthScope = string; +export type EndpointMetadata = { + /** + * An array of security scheme collections. Each collection represents an alternative way to authenticate. + */ + security?: SecuritySchemeCollection[]; +}; diff --git a/src/core/fetcher/EndpointSupplier.ts b/src/core/fetcher/EndpointSupplier.ts new file mode 100644 index 00000000..8079841c --- /dev/null +++ b/src/core/fetcher/EndpointSupplier.ts @@ -0,0 +1,14 @@ +import type { EndpointMetadata } from "./EndpointMetadata.js"; +import type { Supplier } from "./Supplier.js"; + +type EndpointSupplierFn = (arg: { endpointMetadata: EndpointMetadata }) => T | Promise; +export type EndpointSupplier = Supplier | EndpointSupplierFn; +export const EndpointSupplier = { + get: async (supplier: EndpointSupplier, arg: { endpointMetadata: EndpointMetadata }): Promise => { + if (typeof supplier === "function") { + return (supplier as EndpointSupplierFn)(arg); + } else { + return supplier; + } + }, +}; diff --git a/src/core/fetcher/Fetcher.ts b/src/core/fetcher/Fetcher.ts new file mode 100644 index 00000000..fedbcd88 --- /dev/null +++ b/src/core/fetcher/Fetcher.ts @@ -0,0 +1,385 @@ +import { toJson } from "../json.js"; +import { createLogger, type LogConfig, type Logger } from "../logging/logger.js"; +import type { APIResponse } from "./APIResponse.js"; +import { createRequestUrl } from "./createRequestUrl.js"; +import type { EndpointMetadata } from "./EndpointMetadata.js"; +import { EndpointSupplier } from "./EndpointSupplier.js"; +import { getErrorResponseBody } from "./getErrorResponseBody.js"; +import { getFetchFn } from "./getFetchFn.js"; +import { getRequestBody } from "./getRequestBody.js"; +import { getResponseBody } from "./getResponseBody.js"; +import { Headers } from "./Headers.js"; +import { makeRequest } from "./makeRequest.js"; +import { abortRawResponse, toRawResponse, unknownRawResponse } from "./RawResponse.js"; +import { requestWithRetries } from "./requestWithRetries.js"; + +export type FetchFunction = (args: Fetcher.Args) => Promise>; + +export declare namespace Fetcher { + export interface Args { + url: string; + method: string; + contentType?: string; + headers?: Record | null | undefined>; + queryParameters?: Record; + body?: unknown; + timeoutMs?: number; + maxRetries?: number; + withCredentials?: boolean; + abortSignal?: AbortSignal; + requestType?: "json" | "file" | "bytes" | "form" | "other"; + responseType?: "json" | "blob" | "sse" | "streaming" | "text" | "arrayBuffer" | "binary-response"; + duplex?: "half"; + endpointMetadata?: EndpointMetadata; + fetchFn?: typeof fetch; + logging?: LogConfig | Logger; + } + + export type Error = FailedStatusCodeError | NonJsonError | TimeoutError | UnknownError; + + export interface FailedStatusCodeError { + reason: "status-code"; + statusCode: number; + body: unknown; + } + + export interface NonJsonError { + reason: "non-json"; + statusCode: number; + rawBody: string; + } + + export interface TimeoutError { + reason: "timeout"; + } + + export interface UnknownError { + reason: "unknown"; + errorMessage: string; + } +} + +const SENSITIVE_HEADERS = new Set([ + "authorization", + "www-authenticate", + "x-api-key", + "api-key", + "apikey", + "x-api-token", + "x-auth-token", + "auth-token", + "cookie", + "set-cookie", + "proxy-authorization", + "proxy-authenticate", + "x-csrf-token", + "x-xsrf-token", + "x-session-token", + "x-access-token", +]); + +function redactHeaders(headers: Headers | Record): Record { + const filtered: Record = {}; + for (const [key, value] of headers instanceof Headers ? headers.entries() : Object.entries(headers)) { + if (SENSITIVE_HEADERS.has(key.toLowerCase())) { + filtered[key] = "[REDACTED]"; + } else { + filtered[key] = value; + } + } + return filtered; +} + +const SENSITIVE_QUERY_PARAMS = new Set([ + "api_key", + "api-key", + "apikey", + "token", + "access_token", + "access-token", + "auth_token", + "auth-token", + "password", + "passwd", + "secret", + "api_secret", + "api-secret", + "apisecret", + "key", + "session", + "session_id", + "session-id", +]); + +function redactQueryParameters(queryParameters?: Record): Record | undefined { + if (queryParameters == null) { + return queryParameters; + } + const redacted: Record = {}; + for (const [key, value] of Object.entries(queryParameters)) { + if (SENSITIVE_QUERY_PARAMS.has(key.toLowerCase())) { + redacted[key] = "[REDACTED]"; + } else { + redacted[key] = value; + } + } + return redacted; +} + +function redactUrl(url: string): string { + const protocolIndex = url.indexOf("://"); + if (protocolIndex === -1) return url; + + const afterProtocol = protocolIndex + 3; + + // Find the first delimiter that marks the end of the authority section + const pathStart = url.indexOf("/", afterProtocol); + let queryStart = url.indexOf("?", afterProtocol); + let fragmentStart = url.indexOf("#", afterProtocol); + + const firstDelimiter = Math.min( + pathStart === -1 ? url.length : pathStart, + queryStart === -1 ? url.length : queryStart, + fragmentStart === -1 ? url.length : fragmentStart, + ); + + // Find the LAST @ before the delimiter (handles multiple @ in credentials) + let atIndex = -1; + for (let i = afterProtocol; i < firstDelimiter; i++) { + if (url[i] === "@") { + atIndex = i; + } + } + + if (atIndex !== -1) { + url = `${url.slice(0, afterProtocol)}[REDACTED]@${url.slice(atIndex + 1)}`; + } + + // Recalculate queryStart since url might have changed + queryStart = url.indexOf("?"); + if (queryStart === -1) return url; + + fragmentStart = url.indexOf("#", queryStart); + const queryEnd = fragmentStart !== -1 ? fragmentStart : url.length; + const queryString = url.slice(queryStart + 1, queryEnd); + + if (queryString.length === 0) return url; + + // FAST PATH: Quick check if any sensitive keywords present + // Using indexOf is faster than regex for simple substring matching + const lower = queryString.toLowerCase(); + const hasSensitive = + lower.includes("token") || + lower.includes("key") || + lower.includes("password") || + lower.includes("passwd") || + lower.includes("secret") || + lower.includes("session") || + lower.includes("auth"); + + if (!hasSensitive) { + return url; + } + + // SLOW PATH: Parse and redact + const redactedParams: string[] = []; + const params = queryString.split("&"); + + for (const param of params) { + const equalIndex = param.indexOf("="); + if (equalIndex === -1) { + redactedParams.push(param); + continue; + } + + const key = param.slice(0, equalIndex); + let shouldRedact = SENSITIVE_QUERY_PARAMS.has(key.toLowerCase()); + + if (!shouldRedact && key.includes("%")) { + try { + const decodedKey = decodeURIComponent(key); + shouldRedact = SENSITIVE_QUERY_PARAMS.has(decodedKey.toLowerCase()); + } catch {} + } + + redactedParams.push(shouldRedact ? `${key}=[REDACTED]` : param); + } + + return url.slice(0, queryStart + 1) + redactedParams.join("&") + url.slice(queryEnd); +} + +async function getHeaders(args: Fetcher.Args): Promise { + const newHeaders: Headers = new Headers(); + + newHeaders.set( + "Accept", + args.responseType === "json" ? "application/json" : args.responseType === "text" ? "text/plain" : "*/*", + ); + if (args.body !== undefined && args.contentType != null) { + newHeaders.set("Content-Type", args.contentType); + } + + if (args.headers == null) { + return newHeaders; + } + + for (const [key, value] of Object.entries(args.headers)) { + const result = await EndpointSupplier.get(value, { endpointMetadata: args.endpointMetadata ?? {} }); + if (typeof result === "string") { + newHeaders.set(key, result); + continue; + } + if (result == null) { + continue; + } + newHeaders.set(key, `${result}`); + } + return newHeaders; +} + +export async function fetcherImpl(args: Fetcher.Args): Promise> { + const url = createRequestUrl(args.url, args.queryParameters); + const requestBody: BodyInit | undefined = await getRequestBody({ + body: args.body, + type: args.requestType ?? "other", + }); + const fetchFn = args.fetchFn ?? (await getFetchFn()); + const headers = await getHeaders(args); + const logger = createLogger(args.logging); + + if (logger.isDebug()) { + const metadata = { + method: args.method, + url: redactUrl(url), + headers: redactHeaders(headers), + queryParameters: redactQueryParameters(args.queryParameters), + hasBody: requestBody != null, + }; + logger.debug("Making HTTP request", metadata); + } + + try { + const response = await requestWithRetries( + async () => + makeRequest( + fetchFn, + url, + args.method, + headers, + requestBody, + args.timeoutMs, + args.abortSignal, + args.withCredentials, + args.duplex, + ), + args.maxRetries, + ); + + if (response.status >= 200 && response.status < 400) { + if (logger.isDebug()) { + const metadata = { + method: args.method, + url: redactUrl(url), + statusCode: response.status, + responseHeaders: redactHeaders(response.headers), + }; + logger.debug("HTTP request succeeded", metadata); + } + return { + ok: true, + body: (await getResponseBody(response, args.responseType)) as R, + headers: response.headers, + rawResponse: toRawResponse(response), + }; + } else { + if (logger.isError()) { + const metadata = { + method: args.method, + url: redactUrl(url), + statusCode: response.status, + responseHeaders: redactHeaders(Object.fromEntries(response.headers.entries())), + }; + logger.error("HTTP request failed with error status", metadata); + } + return { + ok: false, + error: { + reason: "status-code", + statusCode: response.status, + body: await getErrorResponseBody(response), + }, + rawResponse: toRawResponse(response), + }; + } + } catch (error) { + if (args.abortSignal?.aborted) { + if (logger.isError()) { + const metadata = { + method: args.method, + url: redactUrl(url), + }; + logger.error("HTTP request was aborted", metadata); + } + return { + ok: false, + error: { + reason: "unknown", + errorMessage: "The user aborted a request", + }, + rawResponse: abortRawResponse, + }; + } else if (error instanceof Error && error.name === "AbortError") { + if (logger.isError()) { + const metadata = { + method: args.method, + url: redactUrl(url), + timeoutMs: args.timeoutMs, + }; + logger.error("HTTP request timed out", metadata); + } + return { + ok: false, + error: { + reason: "timeout", + }, + rawResponse: abortRawResponse, + }; + } else if (error instanceof Error) { + if (logger.isError()) { + const metadata = { + method: args.method, + url: redactUrl(url), + errorMessage: error.message, + }; + logger.error("HTTP request failed with error", metadata); + } + return { + ok: false, + error: { + reason: "unknown", + errorMessage: error.message, + }, + rawResponse: unknownRawResponse, + }; + } + + if (logger.isError()) { + const metadata = { + method: args.method, + url: redactUrl(url), + error: toJson(error), + }; + logger.error("HTTP request failed with unknown error", metadata); + } + return { + ok: false, + error: { + reason: "unknown", + errorMessage: toJson(error), + }, + rawResponse: unknownRawResponse, + }; + } +} + +export const fetcher: FetchFunction = fetcherImpl; diff --git a/src/core/fetcher/Headers.ts b/src/core/fetcher/Headers.ts new file mode 100644 index 00000000..af841aa2 --- /dev/null +++ b/src/core/fetcher/Headers.ts @@ -0,0 +1,93 @@ +let Headers: typeof globalThis.Headers; + +if (typeof globalThis.Headers !== "undefined") { + Headers = globalThis.Headers; +} else { + Headers = class Headers implements Headers { + private headers: Map; + + constructor(init?: HeadersInit) { + this.headers = new Map(); + + if (init) { + if (init instanceof Headers) { + init.forEach((value, key) => this.append(key, value)); + } else if (Array.isArray(init)) { + for (const [key, value] of init) { + if (typeof key === "string" && typeof value === "string") { + this.append(key, value); + } else { + throw new TypeError("Each header entry must be a [string, string] tuple"); + } + } + } else { + for (const [key, value] of Object.entries(init)) { + if (typeof value === "string") { + this.append(key, value); + } else { + throw new TypeError("Header values must be strings"); + } + } + } + } + } + + append(name: string, value: string): void { + const key = name.toLowerCase(); + const existing = this.headers.get(key) || []; + this.headers.set(key, [...existing, value]); + } + + delete(name: string): void { + const key = name.toLowerCase(); + this.headers.delete(key); + } + + get(name: string): string | null { + const key = name.toLowerCase(); + const values = this.headers.get(key); + return values ? values.join(", ") : null; + } + + has(name: string): boolean { + const key = name.toLowerCase(); + return this.headers.has(key); + } + + set(name: string, value: string): void { + const key = name.toLowerCase(); + this.headers.set(key, [value]); + } + + forEach(callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: unknown): void { + const boundCallback = thisArg ? callbackfn.bind(thisArg) : callbackfn; + this.headers.forEach((values, key) => boundCallback(values.join(", "), key, this)); + } + + getSetCookie(): string[] { + return this.headers.get("set-cookie") || []; + } + + *entries(): HeadersIterator<[string, string]> { + for (const [key, values] of this.headers.entries()) { + yield [key, values.join(", ")]; + } + } + + *keys(): HeadersIterator { + yield* this.headers.keys(); + } + + *values(): HeadersIterator { + for (const values of this.headers.values()) { + yield values.join(", "); + } + } + + [Symbol.iterator](): HeadersIterator<[string, string]> { + return this.entries(); + } + }; +} + +export { Headers }; diff --git a/src/core/fetcher/HttpResponsePromise.ts b/src/core/fetcher/HttpResponsePromise.ts new file mode 100644 index 00000000..692ca7d7 --- /dev/null +++ b/src/core/fetcher/HttpResponsePromise.ts @@ -0,0 +1,116 @@ +import type { WithRawResponse } from "./RawResponse.js"; + +/** + * A promise that returns the parsed response and lets you retrieve the raw response too. + */ +export class HttpResponsePromise extends Promise { + private innerPromise: Promise>; + private unwrappedPromise: Promise | undefined; + + private constructor(promise: Promise>) { + // Initialize with a no-op to avoid premature parsing + super((resolve) => { + resolve(undefined as unknown as T); + }); + this.innerPromise = promise; + } + + /** + * Creates an `HttpResponsePromise` from a function that returns a promise. + * + * @param fn - A function that returns a promise resolving to a `WithRawResponse` object. + * @param args - Arguments to pass to the function. + * @returns An `HttpResponsePromise` instance. + */ + public static fromFunction Promise>, T>( + fn: F, + ...args: Parameters + ): HttpResponsePromise { + return new HttpResponsePromise(fn(...args)); + } + + /** + * Creates a function that returns an `HttpResponsePromise` from a function that returns a promise. + * + * @param fn - A function that returns a promise resolving to a `WithRawResponse` object. + * @returns A function that returns an `HttpResponsePromise` instance. + */ + public static interceptFunction< + F extends (...args: never[]) => Promise>, + T = Awaited>["data"], + >(fn: F): (...args: Parameters) => HttpResponsePromise { + return (...args: Parameters): HttpResponsePromise => { + return HttpResponsePromise.fromPromise(fn(...args)); + }; + } + + /** + * Creates an `HttpResponsePromise` from an existing promise. + * + * @param promise - A promise resolving to a `WithRawResponse` object. + * @returns An `HttpResponsePromise` instance. + */ + public static fromPromise(promise: Promise>): HttpResponsePromise { + return new HttpResponsePromise(promise); + } + + /** + * Creates an `HttpResponsePromise` from an executor function. + * + * @param executor - A function that takes resolve and reject callbacks to create a promise. + * @returns An `HttpResponsePromise` instance. + */ + public static fromExecutor( + executor: (resolve: (value: WithRawResponse) => void, reject: (reason?: unknown) => void) => void, + ): HttpResponsePromise { + const promise = new Promise>(executor); + return new HttpResponsePromise(promise); + } + + /** + * Creates an `HttpResponsePromise` from a resolved result. + * + * @param result - A `WithRawResponse` object to resolve immediately. + * @returns An `HttpResponsePromise` instance. + */ + public static fromResult(result: WithRawResponse): HttpResponsePromise { + const promise = Promise.resolve(result); + return new HttpResponsePromise(promise); + } + + private unwrap(): Promise { + if (!this.unwrappedPromise) { + this.unwrappedPromise = this.innerPromise.then(({ data }) => data); + } + return this.unwrappedPromise; + } + + /** @inheritdoc */ + public override then( + onfulfilled?: ((value: T) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null, + ): Promise { + return this.unwrap().then(onfulfilled, onrejected); + } + + /** @inheritdoc */ + public override catch( + onrejected?: ((reason: unknown) => TResult | PromiseLike) | null, + ): Promise { + return this.unwrap().catch(onrejected); + } + + /** @inheritdoc */ + public override finally(onfinally?: (() => void) | null): Promise { + return this.unwrap().finally(onfinally); + } + + /** + * Retrieves the data and raw response. + * + * @returns A promise resolving to a `WithRawResponse` object. + */ + public async withRawResponse(): Promise> { + return await this.innerPromise; + } +} diff --git a/src/core/fetcher/RawResponse.ts b/src/core/fetcher/RawResponse.ts new file mode 100644 index 00000000..37fb44e2 --- /dev/null +++ b/src/core/fetcher/RawResponse.ts @@ -0,0 +1,61 @@ +import { Headers } from "./Headers.js"; + +/** + * The raw response from the fetch call excluding the body. + */ +export type RawResponse = Omit< + { + [K in keyof Response as Response[K] extends Function ? never : K]: Response[K]; // strips out functions + }, + "ok" | "body" | "bodyUsed" +>; // strips out body and bodyUsed + +/** + * A raw response indicating that the request was aborted. + */ +export const abortRawResponse: RawResponse = { + headers: new Headers(), + redirected: false, + status: 499, + statusText: "Client Closed Request", + type: "error", + url: "", +} as const; + +/** + * A raw response indicating an unknown error. + */ +export const unknownRawResponse: RawResponse = { + headers: new Headers(), + redirected: false, + status: 0, + statusText: "Unknown Error", + type: "error", + url: "", +} as const; + +/** + * Converts a `RawResponse` object into a `RawResponse` by extracting its properties, + * excluding the `body` and `bodyUsed` fields. + * + * @param response - The `RawResponse` object to convert. + * @returns A `RawResponse` object containing the extracted properties of the input response. + */ +export function toRawResponse(response: Response): RawResponse { + return { + headers: response.headers, + redirected: response.redirected, + status: response.status, + statusText: response.statusText, + type: response.type, + url: response.url, + }; +} + +/** + * Creates a `RawResponse` from a standard `Response` object. + */ +export interface WithRawResponse { + readonly data: T; + readonly rawResponse: RawResponse; +} diff --git a/src/core/fetcher/ResponseWithBody.ts b/src/core/fetcher/ResponseWithBody.ts new file mode 100644 index 00000000..445d40f8 --- /dev/null +++ b/src/core/fetcher/ResponseWithBody.ts @@ -0,0 +1,7 @@ +export type ResponseWithBody = Response & { + body: ReadableStream; +}; + +export function isResponseWithBody(response: Response): response is ResponseWithBody { + return (response as ResponseWithBody).body != null; +} diff --git a/src/core/fetcher/Supplier.ts b/src/core/fetcher/Supplier.ts new file mode 100644 index 00000000..867c931c --- /dev/null +++ b/src/core/fetcher/Supplier.ts @@ -0,0 +1,11 @@ +export type Supplier = T | Promise | (() => T | Promise); + +export const Supplier = { + get: async (supplier: Supplier): Promise => { + if (typeof supplier === "function") { + return (supplier as () => T)(); + } else { + return supplier; + } + }, +}; diff --git a/src/core/fetcher/createRequestUrl.ts b/src/core/fetcher/createRequestUrl.ts new file mode 100644 index 00000000..88e13265 --- /dev/null +++ b/src/core/fetcher/createRequestUrl.ts @@ -0,0 +1,6 @@ +import { toQueryString } from "../url/qs.js"; + +export function createRequestUrl(baseUrl: string, queryParameters?: Record): string { + const queryString = toQueryString(queryParameters, { arrayFormat: "repeat" }); + return queryString ? `${baseUrl}?${queryString}` : baseUrl; +} diff --git a/src/core/fetcher/getErrorResponseBody.ts b/src/core/fetcher/getErrorResponseBody.ts new file mode 100644 index 00000000..7cf4e623 --- /dev/null +++ b/src/core/fetcher/getErrorResponseBody.ts @@ -0,0 +1,33 @@ +import { fromJson } from "../json.js"; +import { getResponseBody } from "./getResponseBody.js"; + +export async function getErrorResponseBody(response: Response): Promise { + let contentType = response.headers.get("Content-Type")?.toLowerCase(); + if (contentType == null || contentType.length === 0) { + return getResponseBody(response); + } + + if (contentType.indexOf(";") !== -1) { + contentType = contentType.split(";")[0]?.trim() ?? ""; + } + switch (contentType) { + case "application/hal+json": + case "application/json": + case "application/ld+json": + case "application/problem+json": + case "application/vnd.api+json": + case "text/json": { + const text = await response.text(); + return text.length > 0 ? fromJson(text) : undefined; + } + default: + if (contentType.startsWith("application/vnd.") && contentType.endsWith("+json")) { + const text = await response.text(); + return text.length > 0 ? fromJson(text) : undefined; + } + + // Fallback to plain text if content type is not recognized + // Even if no body is present, the response will be an empty string + return await response.text(); + } +} diff --git a/src/core/fetcher/getFetchFn.ts b/src/core/fetcher/getFetchFn.ts new file mode 100644 index 00000000..9f845b95 --- /dev/null +++ b/src/core/fetcher/getFetchFn.ts @@ -0,0 +1,3 @@ +export async function getFetchFn(): Promise { + return fetch; +} diff --git a/src/core/fetcher/getHeader.ts b/src/core/fetcher/getHeader.ts new file mode 100644 index 00000000..50f922b0 --- /dev/null +++ b/src/core/fetcher/getHeader.ts @@ -0,0 +1,8 @@ +export function getHeader(headers: Record, header: string): string | undefined { + for (const [headerKey, headerValue] of Object.entries(headers)) { + if (headerKey.toLowerCase() === header.toLowerCase()) { + return headerValue; + } + } + return undefined; +} diff --git a/src/core/fetcher/getRequestBody.ts b/src/core/fetcher/getRequestBody.ts new file mode 100644 index 00000000..91d9d81f --- /dev/null +++ b/src/core/fetcher/getRequestBody.ts @@ -0,0 +1,20 @@ +import { toJson } from "../json.js"; +import { toQueryString } from "../url/qs.js"; + +export declare namespace GetRequestBody { + interface Args { + body: unknown; + type: "json" | "file" | "bytes" | "form" | "other"; + } +} + +export async function getRequestBody({ body, type }: GetRequestBody.Args): Promise { + if (type === "form") { + return toQueryString(body, { arrayFormat: "repeat", encode: true }); + } + if (type.includes("json")) { + return toJson(body); + } else { + return body as BodyInit; + } +} diff --git a/src/core/fetcher/getResponseBody.ts b/src/core/fetcher/getResponseBody.ts new file mode 100644 index 00000000..0f24de17 --- /dev/null +++ b/src/core/fetcher/getResponseBody.ts @@ -0,0 +1,43 @@ +import { fromJson } from "../json.js"; +import { getBinaryResponse } from "./BinaryResponse.js"; +import { isResponseWithBody } from "./ResponseWithBody.js"; + +export async function getResponseBody(response: Response, responseType?: string): Promise { + if (!isResponseWithBody(response)) { + return undefined; + } + switch (responseType) { + case "binary-response": + return getBinaryResponse(response); + case "blob": + return await response.blob(); + case "arrayBuffer": + return await response.arrayBuffer(); + case "sse": + return response.body; + case "streaming": + return response.body; + + case "text": + return await response.text(); + } + + // if responseType is "json" or not specified, try to parse as JSON + const text = await response.text(); + if (text.length > 0) { + try { + const responseBody = fromJson(text); + return responseBody; + } catch (_err) { + return { + ok: false, + error: { + reason: "non-json", + statusCode: response.status, + rawBody: text, + }, + }; + } + } + return undefined; +} diff --git a/src/core/fetcher/index.ts b/src/core/fetcher/index.ts new file mode 100644 index 00000000..c3bc6da2 --- /dev/null +++ b/src/core/fetcher/index.ts @@ -0,0 +1,11 @@ +export type { APIResponse } from "./APIResponse.js"; +export type { BinaryResponse } from "./BinaryResponse.js"; +export type { EndpointMetadata } from "./EndpointMetadata.js"; +export { EndpointSupplier } from "./EndpointSupplier.js"; +export type { Fetcher, FetchFunction } from "./Fetcher.js"; +export { fetcher } from "./Fetcher.js"; +export { getHeader } from "./getHeader.js"; +export { HttpResponsePromise } from "./HttpResponsePromise.js"; +export type { RawResponse, WithRawResponse } from "./RawResponse.js"; +export { abortRawResponse, toRawResponse, unknownRawResponse } from "./RawResponse.js"; +export { Supplier } from "./Supplier.js"; diff --git a/src/core/fetcher/makeRequest.ts b/src/core/fetcher/makeRequest.ts new file mode 100644 index 00000000..c8d3f2ed --- /dev/null +++ b/src/core/fetcher/makeRequest.ts @@ -0,0 +1,42 @@ +import { anySignal, getTimeoutSignal } from "./signals.js"; + +export const makeRequest = async ( + fetchFn: (url: string, init: RequestInit) => Promise, + url: string, + method: string, + headers: Headers | Record, + requestBody: BodyInit | undefined, + timeoutMs?: number, + abortSignal?: AbortSignal, + withCredentials?: boolean, + duplex?: "half", +): Promise => { + const signals: AbortSignal[] = []; + + let timeoutAbortId: NodeJS.Timeout | undefined; + if (timeoutMs != null) { + const { signal, abortId } = getTimeoutSignal(timeoutMs); + timeoutAbortId = abortId; + signals.push(signal); + } + + if (abortSignal != null) { + signals.push(abortSignal); + } + const newSignals = anySignal(signals); + const response = await fetchFn(url, { + method: method, + headers, + body: requestBody, + signal: newSignals, + credentials: withCredentials ? "include" : undefined, + // @ts-ignore + duplex, + }); + + if (timeoutAbortId != null) { + clearTimeout(timeoutAbortId); + } + + return response; +}; diff --git a/src/core/fetcher/requestWithRetries.ts b/src/core/fetcher/requestWithRetries.ts new file mode 100644 index 00000000..1f689688 --- /dev/null +++ b/src/core/fetcher/requestWithRetries.ts @@ -0,0 +1,64 @@ +const INITIAL_RETRY_DELAY = 1000; // in milliseconds +const MAX_RETRY_DELAY = 60000; // in milliseconds +const DEFAULT_MAX_RETRIES = 2; +const JITTER_FACTOR = 0.2; // 20% random jitter + +function addPositiveJitter(delay: number): number { + const jitterMultiplier = 1 + Math.random() * JITTER_FACTOR; + return delay * jitterMultiplier; +} + +function addSymmetricJitter(delay: number): number { + const jitterMultiplier = 1 + (Math.random() - 0.5) * JITTER_FACTOR; + return delay * jitterMultiplier; +} + +function getRetryDelayFromHeaders(response: Response, retryAttempt: number): number { + const retryAfter = response.headers.get("Retry-After"); + if (retryAfter) { + const retryAfterSeconds = parseInt(retryAfter, 10); + if (!Number.isNaN(retryAfterSeconds) && retryAfterSeconds > 0) { + return Math.min(retryAfterSeconds * 1000, MAX_RETRY_DELAY); + } + + const retryAfterDate = new Date(retryAfter); + if (!Number.isNaN(retryAfterDate.getTime())) { + const delay = retryAfterDate.getTime() - Date.now(); + if (delay > 0) { + return Math.min(Math.max(delay, 0), MAX_RETRY_DELAY); + } + } + } + + const rateLimitReset = response.headers.get("X-RateLimit-Reset"); + if (rateLimitReset) { + const resetTime = parseInt(rateLimitReset, 10); + if (!Number.isNaN(resetTime)) { + const delay = resetTime * 1000 - Date.now(); + if (delay > 0) { + return addPositiveJitter(Math.min(delay, MAX_RETRY_DELAY)); + } + } + } + + return addSymmetricJitter(Math.min(INITIAL_RETRY_DELAY * 2 ** retryAttempt, MAX_RETRY_DELAY)); +} + +export async function requestWithRetries( + requestFn: () => Promise, + maxRetries: number = DEFAULT_MAX_RETRIES, +): Promise { + let response: Response = await requestFn(); + + for (let i = 0; i < maxRetries; ++i) { + if ([408, 429].includes(response.status) || response.status >= 500) { + const delay = getRetryDelayFromHeaders(response, i); + + await new Promise((resolve) => setTimeout(resolve, delay)); + response = await requestFn(); + } else { + break; + } + } + return response!; +} diff --git a/src/core/fetcher/signals.ts b/src/core/fetcher/signals.ts new file mode 100644 index 00000000..c9fcaeff --- /dev/null +++ b/src/core/fetcher/signals.ts @@ -0,0 +1,26 @@ +const TIMEOUT = "timeout"; + +export function getTimeoutSignal(timeoutMs: number): { signal: AbortSignal; abortId: NodeJS.Timeout } { + const controller = new AbortController(); + const abortId = setTimeout(() => controller.abort(TIMEOUT), timeoutMs); + return { signal: controller.signal, abortId }; +} + +export function anySignal(...args: AbortSignal[] | [AbortSignal[]]): AbortSignal { + const signals = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args) as AbortSignal[]; + + const controller = new AbortController(); + + for (const signal of signals) { + if (signal.aborted) { + controller.abort((signal as any)?.reason); + break; + } + + signal.addEventListener("abort", () => controller.abort((signal as any)?.reason), { + signal: controller.signal, + }); + } + + return controller.signal; +} diff --git a/src/core/file/exports.ts b/src/core/file/exports.ts new file mode 100644 index 00000000..3b0b3967 --- /dev/null +++ b/src/core/file/exports.ts @@ -0,0 +1 @@ +export type { Uploadable } from "./types.js"; diff --git a/src/core/file/file.ts b/src/core/file/file.ts new file mode 100644 index 00000000..0bacc484 --- /dev/null +++ b/src/core/file/file.ts @@ -0,0 +1,217 @@ +import type { Uploadable } from "./types.js"; + +export async function toBinaryUploadRequest( + file: Uploadable, +): Promise<{ body: Uploadable.FileLike; headers?: Record }> { + const { data, filename, contentLength, contentType } = await getFileWithMetadata(file); + const request = { + body: data, + headers: {} as Record, + }; + if (filename) { + request.headers["Content-Disposition"] = `attachment; filename="${filename}"`; + } + if (contentType) { + request.headers["Content-Type"] = contentType; + } + if (contentLength != null) { + request.headers["Content-Length"] = contentLength.toString(); + } + return request; +} + +export async function toMultipartDataPart( + file: Uploadable, +): Promise<{ data: Uploadable.FileLike; filename?: string; contentType?: string }> { + const { data, filename, contentType } = await getFileWithMetadata(file, { + noSniffFileSize: true, + }); + return { + data, + filename, + contentType, + }; +} + +async function getFileWithMetadata( + file: Uploadable, + { noSniffFileSize }: { noSniffFileSize?: boolean } = {}, +): Promise { + if (isFileLike(file)) { + return getFileWithMetadata( + { + data: file, + }, + { noSniffFileSize }, + ); + } + + if ("path" in file) { + const fs = await import("fs"); + if (!fs || !fs.createReadStream) { + throw new Error("File path uploads are not supported in this environment."); + } + const data = fs.createReadStream(file.path); + const contentLength = + file.contentLength ?? (noSniffFileSize === true ? undefined : await tryGetFileSizeFromPath(file.path)); + const filename = file.filename ?? getNameFromPath(file.path); + return { + data, + filename, + contentType: file.contentType, + contentLength, + }; + } + if ("data" in file) { + const data = file.data; + const contentLength = + file.contentLength ?? + (await tryGetContentLengthFromFileLike(data, { + noSniffFileSize, + })); + const filename = file.filename ?? tryGetNameFromFileLike(data); + return { + data, + filename, + contentType: file.contentType ?? tryGetContentTypeFromFileLike(data), + contentLength, + }; + } + + throw new Error(`Invalid FileUpload of type ${typeof file}: ${JSON.stringify(file)}`); +} + +function isFileLike(value: unknown): value is Uploadable.FileLike { + return ( + isBuffer(value) || + isArrayBufferView(value) || + isArrayBuffer(value) || + isUint8Array(value) || + isBlob(value) || + isFile(value) || + isStreamLike(value) || + isReadableStream(value) + ); +} + +async function tryGetFileSizeFromPath(path: string): Promise { + try { + const fs = await import("fs"); + if (!fs || !fs.promises || !fs.promises.stat) { + return undefined; + } + const fileStat = await fs.promises.stat(path); + return fileStat.size; + } catch (_fallbackError) { + return undefined; + } +} + +function tryGetNameFromFileLike(data: Uploadable.FileLike): string | undefined { + if (isNamedValue(data)) { + return data.name; + } + if (isPathedValue(data)) { + return getNameFromPath(data.path.toString()); + } + return undefined; +} + +async function tryGetContentLengthFromFileLike( + data: Uploadable.FileLike, + { noSniffFileSize }: { noSniffFileSize?: boolean } = {}, +): Promise { + if (isBuffer(data)) { + return data.length; + } + if (isArrayBufferView(data)) { + return data.byteLength; + } + if (isArrayBuffer(data)) { + return data.byteLength; + } + if (isBlob(data)) { + return data.size; + } + if (isFile(data)) { + return data.size; + } + if (noSniffFileSize === true) { + return undefined; + } + if (isPathedValue(data)) { + return await tryGetFileSizeFromPath(data.path.toString()); + } + return undefined; +} + +function tryGetContentTypeFromFileLike(data: Uploadable.FileLike): string | undefined { + if (isBlob(data)) { + return data.type; + } + if (isFile(data)) { + return data.type; + } + + return undefined; +} + +function getNameFromPath(path: string): string | undefined { + const lastForwardSlash = path.lastIndexOf("/"); + const lastBackSlash = path.lastIndexOf("\\"); + const lastSlashIndex = Math.max(lastForwardSlash, lastBackSlash); + return lastSlashIndex >= 0 ? path.substring(lastSlashIndex + 1) : path; +} + +type NamedValue = { + name: string; +} & unknown; + +type PathedValue = { + path: string | { toString(): string }; +} & unknown; + +type StreamLike = { + read?: () => unknown; + pipe?: (dest: unknown) => unknown; +} & unknown; + +function isNamedValue(value: unknown): value is NamedValue { + return typeof value === "object" && value != null && "name" in value; +} + +function isPathedValue(value: unknown): value is PathedValue { + return typeof value === "object" && value != null && "path" in value; +} + +function isStreamLike(value: unknown): value is StreamLike { + return typeof value === "object" && value != null && ("read" in value || "pipe" in value); +} + +function isReadableStream(value: unknown): value is ReadableStream { + return typeof value === "object" && value != null && "getReader" in value; +} + +function isBuffer(value: unknown): value is Buffer { + return typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(value); +} + +function isArrayBufferView(value: unknown): value is ArrayBufferView { + return typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(value); +} + +function isArrayBuffer(value: unknown): value is ArrayBuffer { + return typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer; +} + +function isUint8Array(value: unknown): value is Uint8Array { + return typeof Uint8Array !== "undefined" && value instanceof Uint8Array; +} + +function isBlob(value: unknown): value is Blob { + return typeof Blob !== "undefined" && value instanceof Blob; +} + +function isFile(value: unknown): value is File { + return typeof File !== "undefined" && value instanceof File; +} diff --git a/src/core/file/index.ts b/src/core/file/index.ts new file mode 100644 index 00000000..fc16dd52 --- /dev/null +++ b/src/core/file/index.ts @@ -0,0 +1,2 @@ +export * from "./file.js"; +export * from "./types.js"; diff --git a/src/core/file/types.ts b/src/core/file/types.ts new file mode 100644 index 00000000..531b6927 --- /dev/null +++ b/src/core/file/types.ts @@ -0,0 +1,81 @@ +/** + * A file that can be uploaded. Can be a file-like object (stream, buffer, blob, etc.), + * a path to a file, or an object with a file-like object and metadata. + */ +export type Uploadable = Uploadable.FileLike | Uploadable.FromPath | Uploadable.WithMetadata; + +export namespace Uploadable { + /** + * Various file-like objects that can be used to upload a file. + */ + export type FileLike = + | ArrayBuffer + | ArrayBufferLike + | ArrayBufferView + | Uint8Array + | import("buffer").Buffer + | import("buffer").Blob + | import("buffer").File + | import("stream").Readable + | import("stream/web").ReadableStream + | globalThis.Blob + | globalThis.File + | ReadableStream; + + /** + * A file path with optional metadata, used for uploading a file from the file system. + */ + export type FromPath = { + /** The path to the file to upload */ + path: string; + /** + * Optional override for the file name (defaults to basename of path). + * This is used to set the `Content-Disposition` header in upload requests. + */ + filename?: string; + /** + * Optional MIME type of the file (e.g., 'image/jpeg', 'text/plain'). + * This is used to set the `Content-Type` header in upload requests. + */ + contentType?: string; + /** + * Optional file size in bytes. + * If not provided, the file size will be determined from the file system. + * The content length is used to set the `Content-Length` header in upload requests. + */ + contentLength?: number; + }; + + /** + * A file-like object with metadata, used for uploading files. + */ + export type WithMetadata = { + /** The file data */ + data: FileLike; + /** + * Optional override for the file name (defaults to basename of path). + * This is used to set the `Content-Disposition` header in upload requests. + */ + filename?: string; + /** + * Optional MIME type of the file (e.g., 'image/jpeg', 'text/plain'). + * This is used to set the `Content-Type` header in upload requests. + * + * If not provided, the content type may be determined from the data itself. + * * If the data is a `File`, `Blob`, or similar, the content type will be determined from the file itself, if the type is set. + * * Any other data type will not have a content type set, and the upload request will use `Content-Type: application/octet-stream` instead. + */ + contentType?: string; + /** + * Optional file size in bytes. + * The content length is used to set the `Content-Length` header in upload requests. + * If the content length is not provided and cannot be determined, the upload request will not include the `Content-Length` header, but will use `Transfer-Encoding: chunked` instead. + * + * If not provided, the file size will be determined depending on the data type. + * * If the data is of type `fs.ReadStream` (`createReadStream`), the size will be determined from the file system. + * * If the data is a `Buffer`, `ArrayBuffer`, `Uint8Array`, `Blob`, `File`, or similar, the size will be determined from the data itself. + * * If the data is a `Readable` or `ReadableStream`, the size will not be determined. + */ + contentLength?: number; + }; +} diff --git a/src/core/headers.ts b/src/core/headers.ts new file mode 100644 index 00000000..78ed8b50 --- /dev/null +++ b/src/core/headers.ts @@ -0,0 +1,35 @@ +export function mergeHeaders( + ...headersArray: (Record | null | undefined)[] +): Record { + const result: Record = {}; + + for (const [key, value] of headersArray + .filter((headers) => headers != null) + .flatMap((headers) => Object.entries(headers))) { + const insensitiveKey = key.toLowerCase(); + if (value != null) { + result[insensitiveKey] = value; + } else if (insensitiveKey in result) { + delete result[insensitiveKey]; + } + } + + return result; +} + +export function mergeOnlyDefinedHeaders( + ...headersArray: (Record | null | undefined)[] +): Record { + const result: Record = {}; + + for (const [key, value] of headersArray + .filter((headers) => headers != null) + .flatMap((headers) => Object.entries(headers))) { + const insensitiveKey = key.toLowerCase(); + if (value != null) { + result[insensitiveKey] = value; + } + } + + return result; +} diff --git a/src/core/index.ts b/src/core/index.ts new file mode 100644 index 00000000..fcab13a7 --- /dev/null +++ b/src/core/index.ts @@ -0,0 +1,6 @@ +export * from "./fetcher/index.js"; +export * as file from "./file/index.js"; +export * as logging from "./logging/index.js"; +export * from "./runtime/index.js"; +export * as url from "./url/index.js"; +export * from "./websocket/index.js"; diff --git a/src/core/json.ts b/src/core/json.ts new file mode 100644 index 00000000..c052f324 --- /dev/null +++ b/src/core/json.ts @@ -0,0 +1,27 @@ +/** + * Serialize a value to JSON + * @param value A JavaScript value, usually an object or array, to be converted. + * @param replacer A function that transforms the results. + * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read. + * @returns JSON string + */ +export const toJson = ( + value: unknown, + replacer?: (this: unknown, key: string, value: unknown) => unknown, + space?: string | number, +): string => { + return JSON.stringify(value, replacer, space); +}; + +/** + * Parse JSON string to object, array, or other type + * @param text A valid JSON string. + * @param reviver A function that transforms the results. This function is called for each member of the object. If a member contains nested objects, the nested objects are transformed before the parent object is. + * @returns Parsed object, array, or other type + */ +export function fromJson( + text: string, + reviver?: (this: unknown, key: string, value: unknown) => unknown, +): T { + return JSON.parse(text, reviver); +} diff --git a/src/core/logging/exports.ts b/src/core/logging/exports.ts new file mode 100644 index 00000000..88f6c00d --- /dev/null +++ b/src/core/logging/exports.ts @@ -0,0 +1,19 @@ +import * as logger from "./logger.js"; + +export namespace logging { + /** + * Configuration for logger instances. + */ + export type LogConfig = logger.LogConfig; + export type LogLevel = logger.LogLevel; + export const LogLevel: typeof logger.LogLevel = logger.LogLevel; + export type ILogger = logger.ILogger; + /** + * Console logger implementation that outputs to the console. + */ + export type ConsoleLogger = logger.ConsoleLogger; + /** + * Console logger implementation that outputs to the console. + */ + export const ConsoleLogger: typeof logger.ConsoleLogger = logger.ConsoleLogger; +} diff --git a/src/core/logging/index.ts b/src/core/logging/index.ts new file mode 100644 index 00000000..d81cc32c --- /dev/null +++ b/src/core/logging/index.ts @@ -0,0 +1 @@ +export * from "./logger.js"; diff --git a/src/core/logging/logger.ts b/src/core/logging/logger.ts new file mode 100644 index 00000000..a3f3673c --- /dev/null +++ b/src/core/logging/logger.ts @@ -0,0 +1,203 @@ +export const LogLevel = { + Debug: "debug", + Info: "info", + Warn: "warn", + Error: "error", +} as const; +export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel]; +const logLevelMap: Record = { + [LogLevel.Debug]: 1, + [LogLevel.Info]: 2, + [LogLevel.Warn]: 3, + [LogLevel.Error]: 4, +}; + +export interface ILogger { + /** + * Logs a debug message. + * @param message - The message to log + * @param args - Additional arguments to log + */ + debug(message: string, ...args: unknown[]): void; + /** + * Logs an info message. + * @param message - The message to log + * @param args - Additional arguments to log + */ + info(message: string, ...args: unknown[]): void; + /** + * Logs a warning message. + * @param message - The message to log + * @param args - Additional arguments to log + */ + warn(message: string, ...args: unknown[]): void; + /** + * Logs an error message. + * @param message - The message to log + * @param args - Additional arguments to log + */ + error(message: string, ...args: unknown[]): void; +} + +/** + * Configuration for logger initialization. + */ +export interface LogConfig { + /** + * Minimum log level to output. + * @default LogLevel.Info + */ + level?: LogLevel; + /** + * Logger implementation to use. + * @default new ConsoleLogger() + */ + logger?: ILogger; + /** + * Whether logging should be silenced. + * @default true + */ + silent?: boolean; +} + +/** + * Default console-based logger implementation. + */ +export class ConsoleLogger implements ILogger { + debug(message: string, ...args: unknown[]): void { + console.debug(message, ...args); + } + info(message: string, ...args: unknown[]): void { + console.info(message, ...args); + } + warn(message: string, ...args: unknown[]): void { + console.warn(message, ...args); + } + error(message: string, ...args: unknown[]): void { + console.error(message, ...args); + } +} + +/** + * Logger class that provides level-based logging functionality. + */ +export class Logger { + private readonly level: number; + private readonly logger: ILogger; + private readonly silent: boolean; + + /** + * Creates a new logger instance. + * @param config - Logger configuration + */ + constructor(config: Required) { + this.level = logLevelMap[config.level]; + this.logger = config.logger; + this.silent = config.silent; + } + + /** + * Checks if a log level should be output based on configuration. + * @param level - The log level to check + * @returns True if the level should be logged + */ + public shouldLog(level: LogLevel): boolean { + return !this.silent && this.level <= logLevelMap[level]; + } + + /** + * Checks if debug logging is enabled. + * @returns True if debug logs should be output + */ + public isDebug(): boolean { + return this.shouldLog(LogLevel.Debug); + } + + /** + * Logs a debug message if debug logging is enabled. + * @param message - The message to log + * @param args - Additional arguments to log + */ + public debug(message: string, ...args: unknown[]): void { + if (this.isDebug()) { + this.logger.debug(message, ...args); + } + } + + /** + * Checks if info logging is enabled. + * @returns True if info logs should be output + */ + public isInfo(): boolean { + return this.shouldLog(LogLevel.Info); + } + + /** + * Logs an info message if info logging is enabled. + * @param message - The message to log + * @param args - Additional arguments to log + */ + public info(message: string, ...args: unknown[]): void { + if (this.isInfo()) { + this.logger.info(message, ...args); + } + } + + /** + * Checks if warning logging is enabled. + * @returns True if warning logs should be output + */ + public isWarn(): boolean { + return this.shouldLog(LogLevel.Warn); + } + + /** + * Logs a warning message if warning logging is enabled. + * @param message - The message to log + * @param args - Additional arguments to log + */ + public warn(message: string, ...args: unknown[]): void { + if (this.isWarn()) { + this.logger.warn(message, ...args); + } + } + + /** + * Checks if error logging is enabled. + * @returns True if error logs should be output + */ + public isError(): boolean { + return this.shouldLog(LogLevel.Error); + } + + /** + * Logs an error message if error logging is enabled. + * @param message - The message to log + * @param args - Additional arguments to log + */ + public error(message: string, ...args: unknown[]): void { + if (this.isError()) { + this.logger.error(message, ...args); + } + } +} + +export function createLogger(config?: LogConfig | Logger): Logger { + if (config == null) { + return defaultLogger; + } + if (config instanceof Logger) { + return config; + } + config = config ?? {}; + config.level ??= LogLevel.Info; + config.logger ??= new ConsoleLogger(); + config.silent ??= true; + return new Logger(config as Required); +} + +const defaultLogger: Logger = new Logger({ + level: LogLevel.Info, + logger: new ConsoleLogger(), + silent: true, +}); diff --git a/src/core/runtime/index.ts b/src/core/runtime/index.ts new file mode 100644 index 00000000..cfab23f9 --- /dev/null +++ b/src/core/runtime/index.ts @@ -0,0 +1 @@ +export { RUNTIME } from "./runtime.js"; diff --git a/src/core/runtime/runtime.ts b/src/core/runtime/runtime.ts new file mode 100644 index 00000000..08fd2563 --- /dev/null +++ b/src/core/runtime/runtime.ts @@ -0,0 +1,133 @@ +interface DenoGlobal { + version: { + deno: string; + }; +} + +interface BunGlobal { + version: string; +} + +declare const Deno: DenoGlobal | undefined; +declare const Bun: BunGlobal | undefined; +declare const EdgeRuntime: string | undefined; +declare const self: typeof globalThis.self & { + importScripts?: unknown; +}; + +/** + * A constant that indicates which environment and version the SDK is running in. + */ +export const RUNTIME: Runtime = evaluateRuntime(); + +export interface Runtime { + type: "browser" | "web-worker" | "deno" | "bun" | "node" | "react-native" | "unknown" | "workerd" | "edge-runtime"; + version?: string; + parsedVersion?: number; +} + +function evaluateRuntime(): Runtime { + /** + * A constant that indicates whether the environment the code is running is a Web Browser. + */ + const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined"; + if (isBrowser) { + return { + type: "browser", + version: window.navigator.userAgent, + }; + } + + /** + * A constant that indicates whether the environment the code is running is Cloudflare. + * https://developers.cloudflare.com/workers/runtime-apis/web-standards/#navigatoruseragent + */ + const isCloudflare = typeof globalThis !== "undefined" && globalThis?.navigator?.userAgent === "Cloudflare-Workers"; + if (isCloudflare) { + return { + type: "workerd", + }; + } + + /** + * A constant that indicates whether the environment the code is running is Edge Runtime. + * https://vercel.com/docs/functions/runtimes/edge-runtime#check-if-you're-running-on-the-edge-runtime + */ + const isEdgeRuntime = typeof EdgeRuntime === "string"; + if (isEdgeRuntime) { + return { + type: "edge-runtime", + }; + } + + /** + * A constant that indicates whether the environment the code is running is a Web Worker. + */ + const isWebWorker = + typeof self === "object" && + typeof self?.importScripts === "function" && + (self.constructor?.name === "DedicatedWorkerGlobalScope" || + self.constructor?.name === "ServiceWorkerGlobalScope" || + self.constructor?.name === "SharedWorkerGlobalScope"); + if (isWebWorker) { + return { + type: "web-worker", + }; + } + + /** + * A constant that indicates whether the environment the code is running is Deno. + * FYI Deno spoofs process.versions.node, see https://deno.land/std@0.177.0/node/process.ts?s=versions + */ + const isDeno = + typeof Deno !== "undefined" && typeof Deno.version !== "undefined" && typeof Deno.version.deno !== "undefined"; + if (isDeno) { + return { + type: "deno", + version: Deno.version.deno, + }; + } + + /** + * A constant that indicates whether the environment the code is running is Bun.sh. + */ + const isBun = typeof Bun !== "undefined" && typeof Bun.version !== "undefined"; + if (isBun) { + return { + type: "bun", + version: Bun.version, + }; + } + + /** + * A constant that indicates whether the environment the code is running is Node.JS. + */ + const isNode = + typeof process !== "undefined" && + "version" in process && + !!process.version && + "versions" in process && + !!process.versions?.node; + if (isNode) { + return { + type: "node", + version: process.versions.node, + parsedVersion: Number(process.versions.node.split(".")[0]), + }; + } + + /** + * A constant that indicates whether the environment the code is running is in React-Native. + * https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/setUpNavigator.js + */ + const isReactNative = typeof navigator !== "undefined" && navigator?.product === "ReactNative"; + if (isReactNative) { + return { + type: "react-native", + }; + } + + return { + type: "unknown", + }; +} diff --git a/src/core/url/encodePathParam.ts b/src/core/url/encodePathParam.ts new file mode 100644 index 00000000..19b90124 --- /dev/null +++ b/src/core/url/encodePathParam.ts @@ -0,0 +1,18 @@ +export function encodePathParam(param: unknown): string { + if (param === null) { + return "null"; + } + const typeofParam = typeof param; + switch (typeofParam) { + case "undefined": + return "undefined"; + case "string": + case "number": + case "boolean": + break; + default: + param = String(param); + break; + } + return encodeURIComponent(param as string | number | boolean); +} diff --git a/src/core/url/index.ts b/src/core/url/index.ts new file mode 100644 index 00000000..f2e0fa2d --- /dev/null +++ b/src/core/url/index.ts @@ -0,0 +1,3 @@ +export { encodePathParam } from "./encodePathParam.js"; +export { join } from "./join.js"; +export { toQueryString } from "./qs.js"; diff --git a/src/core/url/join.ts b/src/core/url/join.ts new file mode 100644 index 00000000..7ca7daef --- /dev/null +++ b/src/core/url/join.ts @@ -0,0 +1,79 @@ +export function join(base: string, ...segments: string[]): string { + if (!base) { + return ""; + } + + if (segments.length === 0) { + return base; + } + + if (base.includes("://")) { + let url: URL; + try { + url = new URL(base); + } catch { + return joinPath(base, ...segments); + } + + const lastSegment = segments[segments.length - 1]; + const shouldPreserveTrailingSlash = lastSegment?.endsWith("/"); + + for (const segment of segments) { + const cleanSegment = trimSlashes(segment); + if (cleanSegment) { + url.pathname = joinPathSegments(url.pathname, cleanSegment); + } + } + + if (shouldPreserveTrailingSlash && !url.pathname.endsWith("/")) { + url.pathname += "/"; + } + + return url.toString(); + } + + return joinPath(base, ...segments); +} + +function joinPath(base: string, ...segments: string[]): string { + if (segments.length === 0) { + return base; + } + + let result = base; + + const lastSegment = segments[segments.length - 1]; + const shouldPreserveTrailingSlash = lastSegment?.endsWith("/"); + + for (const segment of segments) { + const cleanSegment = trimSlashes(segment); + if (cleanSegment) { + result = joinPathSegments(result, cleanSegment); + } + } + + if (shouldPreserveTrailingSlash && !result.endsWith("/")) { + result += "/"; + } + + return result; +} + +function joinPathSegments(left: string, right: string): string { + if (left.endsWith("/")) { + return left + right; + } + return `${left}/${right}`; +} + +function trimSlashes(str: string): string { + if (!str) return str; + + let start = 0; + let end = str.length; + + if (str.startsWith("/")) start = 1; + if (str.endsWith("/")) end = str.length - 1; + + return start === 0 && end === str.length ? str : str.slice(start, end); +} diff --git a/src/core/url/qs.ts b/src/core/url/qs.ts new file mode 100644 index 00000000..13e89be9 --- /dev/null +++ b/src/core/url/qs.ts @@ -0,0 +1,74 @@ +interface QueryStringOptions { + arrayFormat?: "indices" | "repeat"; + encode?: boolean; +} + +const defaultQsOptions: Required = { + arrayFormat: "indices", + encode: true, +} as const; + +function encodeValue(value: unknown, shouldEncode: boolean): string { + if (value === undefined) { + return ""; + } + if (value === null) { + return ""; + } + const stringValue = String(value); + return shouldEncode ? encodeURIComponent(stringValue) : stringValue; +} + +function stringifyObject(obj: Record, prefix = "", options: Required): string[] { + const parts: string[] = []; + + for (const [key, value] of Object.entries(obj)) { + const fullKey = prefix ? `${prefix}[${key}]` : key; + + if (value === undefined) { + continue; + } + + if (Array.isArray(value)) { + if (value.length === 0) { + continue; + } + for (let i = 0; i < value.length; i++) { + const item = value[i]; + if (item === undefined) { + continue; + } + if (typeof item === "object" && !Array.isArray(item) && item !== null) { + const arrayKey = options.arrayFormat === "indices" ? `${fullKey}[${i}]` : fullKey; + parts.push(...stringifyObject(item as Record, arrayKey, options)); + } else { + const arrayKey = options.arrayFormat === "indices" ? `${fullKey}[${i}]` : fullKey; + const encodedKey = options.encode ? encodeURIComponent(arrayKey) : arrayKey; + parts.push(`${encodedKey}=${encodeValue(item, options.encode)}`); + } + } + } else if (typeof value === "object" && value !== null) { + if (Object.keys(value as Record).length === 0) { + continue; + } + parts.push(...stringifyObject(value as Record, fullKey, options)); + } else { + const encodedKey = options.encode ? encodeURIComponent(fullKey) : fullKey; + parts.push(`${encodedKey}=${encodeValue(value, options.encode)}`); + } + } + + return parts; +} + +export function toQueryString(obj: unknown, options?: QueryStringOptions): string { + if (obj == null || typeof obj !== "object") { + return ""; + } + + const parts = stringifyObject(obj as Record, "", { + ...defaultQsOptions, + ...options, + }); + return parts.join("&"); +} diff --git a/src/core/websocket/events.ts b/src/core/websocket/events.ts new file mode 100644 index 00000000..87de6277 --- /dev/null +++ b/src/core/websocket/events.ts @@ -0,0 +1,42 @@ +export class Event { + public target: any; + public type: string; + constructor(type: string, target: any) { + this.target = target; + this.type = type; + } +} + +export class ErrorEvent extends Event { + public message: string; + public error: Error; + constructor(error: Error, target: any) { + super("error", target); + this.message = error.message; + this.error = error; + } +} + +export class CloseEvent extends Event { + public code: number; + public reason: string; + public wasClean = true; + constructor(code = 1000, reason = "", target: any) { + super("close", target); + this.code = code; + this.reason = reason; + } +} +export interface WebSocketEventMap { + close: CloseEvent; + error: ErrorEvent; + message: MessageEvent; + open: Event; +} + +export interface WebSocketEventListenerMap { + close: (event: CloseEvent) => void | { handleEvent: (event: CloseEvent) => void }; + error: (event: ErrorEvent) => void | { handleEvent: (event: ErrorEvent) => void }; + message: (event: MessageEvent) => void | { handleEvent: (event: MessageEvent) => void }; + open: (event: Event) => void | { handleEvent: (event: Event) => void }; +} diff --git a/src/core/websocket/exports.ts b/src/core/websocket/exports.ts new file mode 100644 index 00000000..91271654 --- /dev/null +++ b/src/core/websocket/exports.ts @@ -0,0 +1,9 @@ +import type * as events from "./events.js"; +import type * as ws from "./ws.js"; + +export type ReconnectingWebSocket = typeof ws.ReconnectingWebSocket; +export declare namespace ReconnectingWebSocket { + export type Event = events.Event; + export type CloseEvent = events.CloseEvent; + export type ErrorEvent = events.ErrorEvent; +} diff --git a/src/core/websocket/index.ts b/src/core/websocket/index.ts new file mode 100644 index 00000000..16867d6b --- /dev/null +++ b/src/core/websocket/index.ts @@ -0,0 +1 @@ +export * from "./ws.js"; diff --git a/src/core/websocket/ws.ts b/src/core/websocket/ws.ts new file mode 100644 index 00000000..cba4f692 --- /dev/null +++ b/src/core/websocket/ws.ts @@ -0,0 +1,522 @@ +import { WebSocket as NodeWebSocket } from "ws"; + +import { RUNTIME } from "../runtime/index.js"; +import { toQueryString } from "../url/qs.js"; +import * as Events from "./events.js"; + +const getGlobalWebSocket = (): WebSocket | undefined => { + if (typeof WebSocket !== "undefined") { + // @ts-ignore + return WebSocket; + } else if (RUNTIME.type === "node") { + return NodeWebSocket as unknown as WebSocket; + } + return undefined; +}; + +/** + * Returns true if given argument looks like a WebSocket class + */ +const isWebSocket = (w: any) => typeof w !== "undefined" && !!w && w.CLOSING === 2; + +export type Event = Events.Event; +export type ErrorEvent = Events.ErrorEvent; +export type CloseEvent = Events.CloseEvent; + +export declare namespace ReconnectingWebSocket { + export interface Args { + url: string; + protocols?: string | string[]; + options?: ReconnectingWebSocket.Options; + headers?: Record; + queryParameters?: Record; + } + + export type Options = { + WebSocket?: any; + maxReconnectionDelay?: number; + minReconnectionDelay?: number; + reconnectionDelayGrowFactor?: number; + minUptime?: number; + connectionTimeout?: number; + maxRetries?: number; + maxEnqueuedMessages?: number; + startClosed?: boolean; + debug?: boolean; + }; + + export type UrlProvider = string | (() => string) | (() => Promise); + + export type Message = string | ArrayBuffer | Blob | ArrayBufferView; + + export type ListenersMap = { + error: Array; + message: Array; + open: Array; + close: Array; + }; +} + +const DEFAULT_OPTIONS = { + maxReconnectionDelay: 10000, + minReconnectionDelay: 1000 + Math.random() * 4000, + minUptime: 5000, + reconnectionDelayGrowFactor: 1.3, + connectionTimeout: 4000, + maxRetries: Infinity, + maxEnqueuedMessages: Infinity, + startClosed: false, + debug: false, +}; + +export class ReconnectingWebSocket { + private _ws?: WebSocket; + private _listeners: ReconnectingWebSocket.ListenersMap = { + error: [], + message: [], + open: [], + close: [], + }; + private _retryCount = -1; + private _uptimeTimeout: any; + private _connectTimeout: any; + private _shouldReconnect = true; + private _connectLock = false; + private _binaryType: BinaryType = "blob"; + private _closeCalled = false; + private _messageQueue: ReconnectingWebSocket.Message[] = []; + + private readonly _url: ReconnectingWebSocket.UrlProvider; + private readonly _protocols?: string | string[]; + private readonly _options: ReconnectingWebSocket.Options; + private readonly _headers?: Record; + private readonly _queryParameters?: Record; + + constructor({ url, protocols, options, headers, queryParameters }: ReconnectingWebSocket.Args) { + this._url = url; + this._protocols = protocols; + this._options = options ?? DEFAULT_OPTIONS; + this._headers = headers; + this._queryParameters = queryParameters; + if (this._options.startClosed) { + this._shouldReconnect = false; + } + this._connect(); + } + + public static readonly CONNECTING = 0; + public static readonly OPEN = 1; + public static readonly CLOSING = 2; + public static readonly CLOSED = 3; + + public readonly CONNECTING: typeof ReconnectingWebSocket.CONNECTING = ReconnectingWebSocket.CONNECTING; + public readonly OPEN: typeof ReconnectingWebSocket.OPEN = ReconnectingWebSocket.OPEN; + public readonly CLOSING: typeof ReconnectingWebSocket.CLOSING = ReconnectingWebSocket.CLOSING; + public readonly CLOSED: typeof ReconnectingWebSocket.CLOSED = ReconnectingWebSocket.CLOSED; + + get binaryType() { + return this._ws ? this._ws.binaryType : this._binaryType; + } + + set binaryType(value: BinaryType) { + this._binaryType = value; + if (this._ws) { + this._ws.binaryType = value; + } + } + + /** + * Returns the number or connection retries + */ + get retryCount(): number { + return Math.max(this._retryCount, 0); + } + + /** + * The number of bytes of data that have been queued using calls to send() but not yet + * transmitted to the network. This value resets to zero once all queued data has been sent. + * This value does not reset to zero when the connection is closed; if you keep calling send(), + * this will continue to climb. Read only + */ + get bufferedAmount(): number { + const bytes = this._messageQueue.reduce((acc, message) => { + if (typeof message === "string") { + acc += message.length; // not byte size + } else if (message instanceof Blob) { + acc += message.size; + } else { + acc += message.byteLength; + } + return acc; + }, 0); + return bytes + (this._ws ? this._ws.bufferedAmount : 0); + } + + /** + * The extensions selected by the server. This is currently only the empty string or a list of + * extensions as negotiated by the connection + */ + get extensions(): string { + return this._ws ? this._ws.extensions : ""; + } + + /** + * A string indicating the name of the sub-protocol the server selected; + * this will be one of the strings specified in the protocols parameter when creating the + * WebSocket object + */ + get protocol(): string { + return this._ws ? this._ws.protocol : ""; + } + + /** + * The current state of the connection; this is one of the Ready state constants + */ + get readyState(): number { + if (this._ws) { + return this._ws.readyState; + } + return this._options.startClosed ? ReconnectingWebSocket.CLOSED : ReconnectingWebSocket.CONNECTING; + } + + /** + * The URL as resolved by the constructor + */ + get url(): string { + return this._ws ? this._ws.url : ""; + } + + /** + * An event listener to be called when the WebSocket connection's readyState changes to CLOSED + */ + public onclose: ((event: Events.CloseEvent) => void) | null = null; + + /** + * An event listener to be called when an error occurs + */ + public onerror: ((event: Events.ErrorEvent) => void) | null = null; + + /** + * An event listener to be called when a message is received from the server + */ + public onmessage: ((event: MessageEvent) => void) | null = null; + + /** + * An event listener to be called when the WebSocket connection's readyState changes to OPEN; + * this indicates that the connection is ready to send and receive data + */ + public onopen: ((event: Event) => void) | null = null; + + /** + * Closes the WebSocket connection or connection attempt, if any. If the connection is already + * CLOSED, this method does nothing + */ + public close(code = 1000, reason?: string): void { + this._closeCalled = true; + this._shouldReconnect = false; + this._clearTimeouts(); + if (!this._ws) { + this._debug("close enqueued: no ws instance"); + return; + } + if (this._ws.readyState === this.CLOSED) { + this._debug("close: already closed"); + return; + } + this._ws.close(code, reason); + } + + /** + * Closes the WebSocket connection or connection attempt and connects again. + * Resets retry counter; + */ + public reconnect(code?: number, reason?: string): void { + this._shouldReconnect = true; + this._closeCalled = false; + this._retryCount = -1; + if (!this._ws || this._ws.readyState === this.CLOSED) { + this._connect(); + } else { + this._disconnect(code, reason); + this._connect(); + } + } + + /** + * Enqueue specified data to be transmitted to the server over the WebSocket connection + */ + public send(data: ReconnectingWebSocket.Message): void { + if (this._ws && this._ws.readyState === this.OPEN) { + this._debug("send", data); + this._ws.send(data); + } else { + const { maxEnqueuedMessages = DEFAULT_OPTIONS.maxEnqueuedMessages } = this._options; + if (this._messageQueue.length < maxEnqueuedMessages) { + this._debug("enqueue", data); + this._messageQueue.push(data); + } + } + } + + /** + * Register an event handler of a specific event type + */ + public addEventListener( + type: T, + listener: Events.WebSocketEventListenerMap[T], + ): void { + if (this._listeners[type]) { + // @ts-ignore + this._listeners[type].push(listener); + } + } + + public dispatchEvent(event: Event) { + const listeners = this._listeners[event.type as keyof Events.WebSocketEventListenerMap]; + if (listeners) { + for (const listener of listeners) { + this._callEventListener(event, listener); + } + } + return true; + } + + /** + * Removes an event listener + */ + public removeEventListener( + type: T, + listener: Events.WebSocketEventListenerMap[T], + ): void { + if (this._listeners[type]) { + // @ts-ignore + this._listeners[type] = this._listeners[type].filter( + // @ts-ignore + (l) => l !== listener, + ); + } + } + + private _debug(...args: any[]) { + if (this._options.debug) { + // not using spread because compiled version uses Symbols + // tslint:disable-next-line + // biome-ignore lint/suspicious/noConsole: allow console + console.log.apply(console, ["RWS>", ...args]); + } + } + + private _getNextDelay() { + const { + reconnectionDelayGrowFactor = DEFAULT_OPTIONS.reconnectionDelayGrowFactor, + minReconnectionDelay = DEFAULT_OPTIONS.minReconnectionDelay, + maxReconnectionDelay = DEFAULT_OPTIONS.maxReconnectionDelay, + } = this._options; + let delay = 0; + if (this._retryCount > 0) { + delay = minReconnectionDelay * reconnectionDelayGrowFactor ** (this._retryCount - 1); + if (delay > maxReconnectionDelay) { + delay = maxReconnectionDelay; + } + } + this._debug("next delay", delay); + return delay; + } + + private _wait(): Promise { + return new Promise((resolve) => { + setTimeout(resolve, this._getNextDelay()); + }); + } + + private _getNextUrl(urlProvider: ReconnectingWebSocket.UrlProvider): Promise { + if (typeof urlProvider === "string") { + return Promise.resolve(urlProvider); + } + if (typeof urlProvider === "function") { + const url = urlProvider(); + if (typeof url === "string") { + return Promise.resolve(url); + } + // @ts-ignore redundant check + if (url.then) { + return url; + } + } + throw Error("Invalid URL"); + } + + private _connect() { + if (this._connectLock || !this._shouldReconnect) { + return; + } + this._connectLock = true; + + const { + maxRetries = DEFAULT_OPTIONS.maxRetries, + connectionTimeout = DEFAULT_OPTIONS.connectionTimeout, + WebSocket = getGlobalWebSocket(), + } = this._options; + + if (this._retryCount >= maxRetries) { + this._debug("max retries reached", this._retryCount, ">=", maxRetries); + return; + } + + this._retryCount++; + + this._debug("connect", this._retryCount); + this._removeListeners(); + if (!isWebSocket(WebSocket)) { + throw Error("No valid WebSocket class provided"); + } + this._wait() + .then(() => this._getNextUrl(this._url)) + .then((url) => { + if (this._closeCalled) { + return; + } + const options: Record = {}; + if (this._headers) { + options.headers = this._headers; + } + if (this._queryParameters && Object.keys(this._queryParameters).length > 0) { + const queryString = toQueryString(this._queryParameters, { arrayFormat: "repeat" }); + if (queryString) { + url = `${url}?${queryString}`; + } + } + this._ws = new WebSocket(url, this._protocols, options); + this._ws!.binaryType = this._binaryType; + this._connectLock = false; + this._addListeners(); + + this._connectTimeout = setTimeout(() => this._handleTimeout(), connectionTimeout); + }); + } + + private _handleTimeout() { + this._debug("timeout event"); + this._handleError(new Events.ErrorEvent(Error("TIMEOUT"), this)); + } + + private _disconnect(code = 1000, reason?: string) { + this._clearTimeouts(); + if (!this._ws) { + return; + } + this._removeListeners(); + try { + this._ws.close(code, reason); + this._handleClose(new Events.CloseEvent(code, reason, this)); + } catch (_error) { + // ignore + } + } + + private _acceptOpen() { + this._debug("accept open"); + this._retryCount = 0; + } + + private _callEventListener( + event: Events.WebSocketEventMap[T], + listener: Events.WebSocketEventListenerMap[T], + ) { + if ("handleEvent" in listener) { + // @ts-ignore + listener.handleEvent(event); + } else { + // @ts-ignore + listener(event); + } + } + + private _handleOpen = (event: Event) => { + this._debug("open event"); + const { minUptime = DEFAULT_OPTIONS.minUptime } = this._options; + + clearTimeout(this._connectTimeout); + this._uptimeTimeout = setTimeout(() => this._acceptOpen(), minUptime); + + this._ws!.binaryType = this._binaryType; + + // send enqueued messages (messages sent before websocket open event) + this._messageQueue.forEach((message) => this._ws?.send(message)); + this._messageQueue = []; + + if (this.onopen) { + this.onopen(event); + } + this._listeners.open.forEach((listener) => this._callEventListener(event, listener)); + }; + + private _handleMessage = (event: MessageEvent) => { + this._debug("message event"); + + if (this.onmessage) { + this.onmessage(event); + } + this._listeners.message.forEach((listener) => this._callEventListener(event, listener)); + }; + + private _handleError = (event: Events.ErrorEvent) => { + this._debug("error event", event.message); + this._disconnect(undefined, event.message === "TIMEOUT" ? "timeout" : undefined); + + if (this.onerror) { + this.onerror(event); + } + this._debug("exec error listeners"); + this._listeners.error.forEach((listener) => this._callEventListener(event, listener)); + + this._connect(); + }; + + private _handleClose = (event: Events.CloseEvent) => { + this._debug("close event"); + this._clearTimeouts(); + + if (event.code === 1000) { + this._shouldReconnect = false; + } + + if (this._shouldReconnect) { + this._connect(); + } + + if (this.onclose) { + this.onclose(event); + } + this._listeners.close.forEach((listener) => this._callEventListener(event, listener)); + }; + + private _removeListeners() { + if (!this._ws) { + return; + } + this._debug("removeListeners"); + this._ws.removeEventListener("open", this._handleOpen); + this._ws.removeEventListener("close", this._handleClose); + this._ws.removeEventListener("message", this._handleMessage); + // @ts-ignore + this._ws.removeEventListener("error", this._handleError); + } + + private _addListeners() { + if (!this._ws) { + return; + } + this._debug("addListeners"); + this._ws.addEventListener("open", this._handleOpen); + this._ws.addEventListener("close", this._handleClose); + this._ws.addEventListener("message", this._handleMessage); + // @ts-ignore + this._ws.addEventListener("error", this._handleError); + } + + private _clearTimeouts() { + clearTimeout(this._connectTimeout); + clearTimeout(this._uptimeTimeout); + } +} diff --git a/src/environments.ts b/src/environments.ts new file mode 100644 index 00000000..b6dc037f --- /dev/null +++ b/src/environments.ts @@ -0,0 +1,23 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface DeepgramEnvironmentUrls { + base: string; + agent: string; + production: string; + agent: string; +} + +export const DeepgramEnvironment = { + Production: { + base: "https://api.deepgram.com", + production: "wss://api.deepgram.com", + agent: "wss://agent.deepgram.com", + }, + Agent: { + base: "https://agent.deepgram.com", + production: "wss://api.deepgram.com", + agent: "wss://agent.deepgram.com", + }, +} as const; + +export type DeepgramEnvironment = typeof DeepgramEnvironment.Production | typeof DeepgramEnvironment.Agent; diff --git a/src/errors/DeepgramError.ts b/src/errors/DeepgramError.ts new file mode 100644 index 00000000..eaf639b1 --- /dev/null +++ b/src/errors/DeepgramError.ts @@ -0,0 +1,53 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as core from "../core/index.js"; +import { toJson } from "../core/json.js"; + +export class DeepgramError extends Error { + public readonly statusCode?: number; + public readonly body?: unknown; + public readonly rawResponse?: core.RawResponse; + + constructor({ + message, + statusCode, + body, + rawResponse, + }: { + message?: string; + statusCode?: number; + body?: unknown; + rawResponse?: core.RawResponse; + }) { + super(buildMessage({ message, statusCode, body })); + Object.setPrototypeOf(this, DeepgramError.prototype); + this.statusCode = statusCode; + this.body = body; + this.rawResponse = rawResponse; + } +} + +function buildMessage({ + message, + statusCode, + body, +}: { + message: string | undefined; + statusCode: number | undefined; + body: unknown | undefined; +}): string { + const lines: string[] = []; + if (message != null) { + lines.push(message); + } + + if (statusCode != null) { + lines.push(`Status code: ${statusCode.toString()}`); + } + + if (body != null) { + lines.push(`Body: ${toJson(body, undefined, 2)}`); + } + + return lines.join("\n"); +} diff --git a/src/errors/DeepgramTimeoutError.ts b/src/errors/DeepgramTimeoutError.ts new file mode 100644 index 00000000..fc50b1f5 --- /dev/null +++ b/src/errors/DeepgramTimeoutError.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export class DeepgramTimeoutError extends Error { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, DeepgramTimeoutError.prototype); + } +} diff --git a/src/errors/index.ts b/src/errors/index.ts new file mode 100644 index 00000000..35d3b545 --- /dev/null +++ b/src/errors/index.ts @@ -0,0 +1,2 @@ +export { DeepgramError } from "./DeepgramError.js"; +export { DeepgramTimeoutError } from "./DeepgramTimeoutError.js"; diff --git a/src/exports.ts b/src/exports.ts new file mode 100644 index 00000000..7b70ee14 --- /dev/null +++ b/src/exports.ts @@ -0,0 +1 @@ +export * from "./core/exports.js"; diff --git a/src/index.ts b/src/index.ts index 7e4e873c..51747912 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,68 +1,6 @@ -import { DeepgramClientOptions, IKeyFactory } from "./lib/types/DeepgramClientOptions"; -import { DeepgramVersionError } from "./lib/errors"; -import DeepgramClient from "./DeepgramClient"; - -/** - * This class is deprecated and should not be used. It throws a `DeepgramVersionError` when instantiated. - * - * @deprecated - * @see https://dpgr.am/js-v3 - */ -class Deepgram { - constructor(protected apiKey: string, protected apiUrl?: string, protected requireSSL?: boolean) { - throw new DeepgramVersionError(); - } -} - -/** - * Creates a new Deepgram client instance. - * - * @param {DeepgramClientArgs} args - Arguments to pass to the Deepgram client constructor. - * @returns A new Deepgram client instance. - */ -function createClient(): DeepgramClient; -function createClient(key?: string | IKeyFactory): DeepgramClient; -function createClient(options?: DeepgramClientOptions): DeepgramClient; -function createClient(key?: string | IKeyFactory, options?: DeepgramClientOptions): DeepgramClient; -function createClient( - keyOrOptions?: string | IKeyFactory | DeepgramClientOptions, - options?: DeepgramClientOptions -): DeepgramClient { - let resolvedOptions: DeepgramClientOptions = {}; - - if (typeof keyOrOptions === "string" || typeof keyOrOptions === "function") { - if (typeof options === "object") { - resolvedOptions = options; - } - - resolvedOptions.key = keyOrOptions; - } else if (typeof keyOrOptions === "object") { - resolvedOptions = keyOrOptions; - } - - return new DeepgramClient(resolvedOptions); -} - -export { createClient, DeepgramClient, Deepgram }; - -/** - * Helpful exports. - */ -export * from "./packages"; -export * from "./lib/types"; -export * from "./lib/enums"; -export * from "./lib/constants"; -export * from "./lib/errors"; -export * from "./lib/helpers"; - -/** - * Captions. These will be tree-shaken if unused. - * - * @see https://github.com/deepgram/deepgram-node-captions - * - * import/export declarations don't do anything but set up an alias to the - * exported variable, they do not count as a "use". Given their semantics, - * they are tracked specially by any bundler and will not adversely affect - * tree-shaking. - */ -export { webvtt, srt } from "@deepgram/captions"; +export * as Deepgram from "./api/index.js"; +export type { BaseClientOptions, BaseRequestOptions } from "./BaseClient.js"; +export { DeepgramClient } from "./Client.js"; +export { DeepgramEnvironment, type DeepgramEnvironmentUrls } from "./environments.js"; +export { DeepgramError, DeepgramTimeoutError } from "./errors/index.js"; +export * from "./exports.js"; diff --git a/src/lib/constants.ts b/src/lib/constants.ts deleted file mode 100644 index 759221f8..00000000 --- a/src/lib/constants.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { convertProtocolToWs } from "./helpers"; -import { isBrowser, isBun, isNode, NODE_VERSION, BUN_VERSION, BROWSER_AGENT } from "./runtime"; -import { version } from "./version"; -import type { DefaultNamespaceOptions, DefaultClientOptions } from "./types"; - -const getAgent = () => { - if (isNode()) { - return `node/${NODE_VERSION}`; - } else if (isBun()) { - return `bun/${BUN_VERSION}`; - } else if (isBrowser()) { - return `javascript ${BROWSER_AGENT}`; - } else { - return `unknown`; - } -}; - -export const DEFAULT_HEADERS = { - "Content-Type": `application/json`, - "X-Client-Info": `@deepgram/sdk; ${isBrowser() ? "browser" : "server"}; v${version}`, - "User-Agent": `@deepgram/sdk/${version} ${getAgent()}`, -}; - -export const DEFAULT_URL = "https://api.deepgram.com"; -export const DEFAULT_AGENT_URL = "wss://agent.deepgram.com"; - -export const DEFAULT_GLOBAL_OPTIONS: Partial = { - fetch: { options: { url: DEFAULT_URL, headers: DEFAULT_HEADERS } }, - websocket: { - options: { url: convertProtocolToWs(DEFAULT_URL), _nodeOnlyHeaders: DEFAULT_HEADERS }, - }, -}; - -export const DEFAULT_AGENT_OPTIONS: Partial = { - fetch: { options: { url: DEFAULT_URL, headers: DEFAULT_HEADERS } }, - websocket: { - options: { url: DEFAULT_AGENT_URL, _nodeOnlyHeaders: DEFAULT_HEADERS }, - }, -}; - -export const DEFAULT_OPTIONS: DefaultClientOptions = { - global: DEFAULT_GLOBAL_OPTIONS, - agent: DEFAULT_AGENT_OPTIONS, -}; - -export enum SOCKET_STATES { - connecting = 0, - open = 1, - closing = 2, - closed = 3, -} - -export enum CONNECTION_STATE { - Connecting = "connecting", - Open = "open", - Closing = "closing", - Closed = "closed", -} diff --git a/src/lib/enums/AgentEvents.ts b/src/lib/enums/AgentEvents.ts deleted file mode 100644 index c8915ea9..00000000 --- a/src/lib/enums/AgentEvents.ts +++ /dev/null @@ -1,74 +0,0 @@ -export enum AgentEvents { - /** - * Built in socket events. - */ - Open = "Open", - Close = "Close", - Error = "Error", - /** - * Audio event? - */ - Audio = "Audio", - /** - * Confirms the successful connection to the websocket. - * { type: "Welcome", request_id: "String"} - */ - Welcome = "Welcome", - /** - * Confirms that your `configure` request was successful. - * { type: "SettingsApplied" } - */ - SettingsApplied = "SettingsApplied", - /** - * Triggered when the agent "hears" the user say something. - * { type: "ConversationText", role: string, content: string } - */ - ConversationText = "ConversationText", - /** - * Triggered when the agent begins receiving user audio. - * { type: "UserStartedSpeaking" } - */ - UserStartedSpeaking = "UserStartedSpeaking", - /** - * Triggered when the user has stopped speaking and the agent is processing the audio. - * { type: "AgentThinking", content: string } - */ - AgentThinking = "AgentThinking", - /** - * A request to call client-side functions. - * { type: "FunctionCallRequest", functions: { id: string; name: string; arguments: string; client_side: boolean}[] } - */ - FunctionCallRequest = "FunctionCallRequest", - /** - * Triggered when the agent begins streaming an audio response. - * YOU WILL ONLY RECEIVE THIS EVENT IF YOU HAVE ENABLED `experimental` IN YOUR CONFIG. - * { type: "AgentStartedSpeaking", total_latency: number, tts_latency: number, ttt_latency: number } - */ - AgentStartedSpeaking = "AgentStartedSpeaking", - /** - * Triggered when the agent has finished streaming an audio response. - * { type: "AgentAudioDone" } - */ - AgentAudioDone = "AgentAudioDone", - /** - * This event is only emitted when you send an `InjectAgentMessage` request while - * the user is currently speaking or the server is processing user audio. - * { type: "InjectionRefused", message: string } - */ - InjectionRefused = "InjectionRefused", - /** - * A successful response to the `UpdateInstructions` request. - * { type: "PromptUpdated" } - */ - PromptUpdated = "PromptUpdated", - /** - * A successful response to the `UpdateSpeak` request. - * { type: "SpeakUpdated" } - */ - SpeakUpdated = "SpeakUpdated", - - /** - * Catch all for any other message event - */ - Unhandled = "Unhandled", -} diff --git a/src/lib/enums/LiveConnectionState.ts b/src/lib/enums/LiveConnectionState.ts deleted file mode 100644 index 4fef1bc8..00000000 --- a/src/lib/enums/LiveConnectionState.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SOCKET_STATES } from "../constants"; - -/** - * Enum representing the different states of a live connection. - * - * @deprecated Since 3.4. Use `SOCKET_STATES` for generic socket connection states instead. - */ -export enum LiveConnectionState { - CONNECTING = SOCKET_STATES.connecting, - OPEN = SOCKET_STATES.open, - CLOSING = SOCKET_STATES.closing, - CLOSED = SOCKET_STATES.closed, -} diff --git a/src/lib/enums/LiveTTSEvents.ts b/src/lib/enums/LiveTTSEvents.ts deleted file mode 100644 index 6c39a47e..00000000 --- a/src/lib/enums/LiveTTSEvents.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Enumeration of events related to live text-to-speech synthesis. - * - * - `Open`: Built-in socket event for when the connection is opened. - * - `Close`: Built-in socket event for when the connection is closed. - * - `Error`: Built-in socket event for when an error occurs. - * - `Metadata`: Event for when metadata is received. - * - `Flushed`: Event for when the server has flushed the buffer. - * - `Warning`: Event for when a warning is received. - * - `Unhandled`: Catch-all event for any other message event. - */ -export enum LiveTTSEvents { - /** - * Built in socket events. - */ - Open = "Open", - Close = "Close", - Error = "Error", - - /** - * Message { type: string } - */ - Metadata = "Metadata", - Flushed = "Flushed", - Warning = "Warning", - - /** - * Audio data event. - */ - Audio = "Audio", - - /** - * Catch all for any other message event - */ - Unhandled = "Unhandled", -} diff --git a/src/lib/enums/LiveTranscriptionEvents.ts b/src/lib/enums/LiveTranscriptionEvents.ts deleted file mode 100644 index 022eb94f..00000000 --- a/src/lib/enums/LiveTranscriptionEvents.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Enumeration of events related to live transcription. - * - * - `Open`: Built-in socket event for when the connection is opened. - * - `Close`: Built-in socket event for when the connection is closed. - * - `Error`: Built-in socket event for when an error occurs. - * - `Transcript`: Event for when a transcript message is received. - * - `Metadata`: Event for when metadata is received. - * - `UtteranceEnd`: Event for when an utterance ends. - * - `SpeechStarted`: Event for when speech is detected. - * - `Unhandled`: Catch-all event for any other message event. - */ -export enum LiveTranscriptionEvents { - /** - * Built in socket events. - */ - Open = "open", - Close = "close", - Error = "error", - - /** - * Message { type: string } - */ - Transcript = "Results", - Metadata = "Metadata", - UtteranceEnd = "UtteranceEnd", - SpeechStarted = "SpeechStarted", - - /** - * Catch all for any other message event - */ - Unhandled = "Unhandled", -} diff --git a/src/lib/enums/index.ts b/src/lib/enums/index.ts deleted file mode 100644 index a4a31923..00000000 --- a/src/lib/enums/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./AgentEvents"; -export * from "./LiveConnectionState"; -export * from "./LiveTranscriptionEvents"; -export * from "./LiveTTSEvents"; diff --git a/src/lib/errors.ts b/src/lib/errors.ts deleted file mode 100644 index ea1a22b1..00000000 --- a/src/lib/errors.ts +++ /dev/null @@ -1,102 +0,0 @@ -export class DeepgramError extends Error { - protected __dgError = true; - - constructor(message: string) { - super(message); - this.name = "DeepgramError"; - } -} - -export function isDeepgramError(error: unknown): error is DeepgramError { - return typeof error === "object" && error !== null && "__dgError" in error; -} - -export class DeepgramApiError extends DeepgramError { - status: number; - - constructor(message: string, status: number) { - super(message); - this.name = "DeepgramApiError"; - this.status = status; - } - - toJSON() { - return { - name: this.name, - message: this.message, - status: this.status, - }; - } -} - -export class DeepgramUnknownError extends DeepgramError { - originalError: unknown; - - constructor(message: string, originalError: unknown) { - super(message); - this.name = "DeepgramUnknownError"; - this.originalError = originalError; - } -} - -export class DeepgramVersionError extends DeepgramError { - constructor() { - super( - `You are attempting to use an old format for a newer SDK version. Read more here: https://dpgr.am/js-v3` - ); - - this.name = "DeepgramVersionError"; - } -} - -/** - * Enhanced WebSocket error that captures additional debugging information - * including status codes, request IDs, and response headers when available. - */ -export class DeepgramWebSocketError extends DeepgramError { - originalEvent?: ErrorEvent | Event; - statusCode?: number; - requestId?: string; - responseHeaders?: Record; - url?: string; - readyState?: number; - - constructor( - message: string, - options: { - originalEvent?: ErrorEvent | Event; - statusCode?: number; - requestId?: string; - responseHeaders?: Record; - url?: string; - readyState?: number; - } = {} - ) { - super(message); - this.name = "DeepgramWebSocketError"; - this.originalEvent = options.originalEvent; - this.statusCode = options.statusCode; - this.requestId = options.requestId; - this.responseHeaders = options.responseHeaders; - this.url = options.url; - this.readyState = options.readyState; - } - - toJSON() { - return { - name: this.name, - message: this.message, - statusCode: this.statusCode, - requestId: this.requestId, - responseHeaders: this.responseHeaders, - url: this.url, - readyState: this.readyState, - originalEvent: this.originalEvent - ? { - type: this.originalEvent.type, - timeStamp: this.originalEvent.timeStamp, - } - : undefined, - }; - } -} diff --git a/src/lib/fetch.ts b/src/lib/fetch.ts deleted file mode 100644 index 214fe12d..00000000 --- a/src/lib/fetch.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { resolveHeadersConstructor } from "./helpers"; -import crossFetch from "cross-fetch"; -import type { Fetch } from "./types"; - -/** - * Resolves the appropriate fetch function to use, either a custom fetch function provided as an argument, or the global fetch function if available, or the cross-fetch library if the global fetch function is not available. - * - * @param customFetch - An optional custom fetch function to use instead of the global fetch function. - * @returns A fetch function that can be used to make HTTP requests. - */ -export const resolveFetch = (customFetch?: Fetch): Fetch => { - let _fetch: Fetch; - - if (customFetch) { - _fetch = customFetch; - } else if (typeof fetch === "undefined") { - _fetch = crossFetch as unknown as Fetch; - } else { - _fetch = fetch; - } - - return (...args) => _fetch(...args); -}; - -interface FetchWithAuthOptions { - apiKey?: string; - customFetch?: Fetch; - accessToken?: string; -} - -/** - * Resolves a fetch function that includes an "Authorization" header with the provided API key. - * - * @param apiKey - The API key to include in the "Authorization" header. - * @param customFetch - An optional custom fetch function to use instead of the global fetch function. - * @returns A fetch function that can be used to make HTTP requests with the provided API key in the "Authorization" header. - */ -export const fetchWithAuth = ({ - apiKey, - customFetch, - accessToken, -}: Readonly): Fetch => { - const fetch = resolveFetch(customFetch); - const HeadersConstructor = resolveHeadersConstructor(); - - return async (input, init) => { - const headers = new HeadersConstructor(init?.headers); - - if (!headers.has("Authorization")) { - headers.set("Authorization", accessToken ? `Bearer ${accessToken}` : `Token ${apiKey}`); - } - - return fetch(input, { ...init, headers }); - }; -}; - -/** - * Resolves the appropriate Response object to use, either the global Response object if available, or the Response object from the cross-fetch library if the global Response object is not available. - * - * @returns The appropriate Response object to use for making HTTP requests. - */ -export const resolveResponse = async () => { - if (typeof Response === "undefined") { - return (await import("cross-fetch")).Response; - } - - return Response; -}; diff --git a/src/lib/helpers.ts b/src/lib/helpers.ts deleted file mode 100644 index 9d0b16bb..00000000 --- a/src/lib/helpers.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { - DeepgramClientOptions, - FileSource, - PrerecordedSource, - UrlSource, - TextSource, - AnalyzeSource, - LiveSchema, - TranscriptionSchema, -} from "./types"; -import { Headers as CrossFetchHeaders } from "cross-fetch"; -import type { Readable } from "node:stream"; -import merge from "deepmerge"; -import { isBrowser } from "./runtime"; - -export function stripTrailingSlash(url: string): string { - return url.replace(/\/$/, ""); -} - -export function applyDefaults(options: Partial = {}, subordinate: Partial = {}): S { - return merge(subordinate, options); -} - -export function appendSearchParams( - searchParams: URLSearchParams, - options: Record -): void { - Object.keys(options).forEach((i) => { - if (Array.isArray(options[i])) { - const arrayParams = options[i] as Array; - arrayParams.forEach((param) => { - searchParams.append(i, String(param)); - }); - } else { - searchParams.append(i, String(options[i])); - } - }); -} - -export const resolveHeadersConstructor = () => { - if (typeof Headers === "undefined") { - return CrossFetchHeaders; - } - - return Headers; -}; - -export const isUrlSource = ( - providedSource: PrerecordedSource | AnalyzeSource -): providedSource is UrlSource => { - if (providedSource && (providedSource as UrlSource).url) return true; - - return false; -}; - -export const isTextSource = ( - providedSource: PrerecordedSource | AnalyzeSource -): providedSource is TextSource => { - if (providedSource && (providedSource as TextSource).text) return true; - - return false; -}; - -export const isFileSource = (providedSource: PrerecordedSource): providedSource is FileSource => { - if (isReadStreamSource(providedSource) || isBufferSource(providedSource)) return true; - - return false; -}; - -const isBufferSource = (providedSource: PrerecordedSource): providedSource is Buffer => { - return providedSource != null && Buffer.isBuffer(providedSource); -}; - -const isReadStreamSource = (providedSource: PrerecordedSource): providedSource is Readable => { - if (providedSource == null) return false; - - // In browser environments, there's no Readable stream from Node.js - if (isBrowser()) return false; - - // Check for stream-like properties without importing Readable - return ( - typeof providedSource === "object" && - typeof (providedSource as any).pipe === "function" && - typeof (providedSource as any).read === "function" && - typeof (providedSource as any)._readableState === "object" - ); -}; - -export class CallbackUrl extends URL { - public callbackUrl = true; -} - -export const convertProtocolToWs = (url: string) => { - const convert = (string: string) => string.toLowerCase().replace(/^http/, "ws"); - - return convert(url); -}; - -export const buildRequestUrl = ( - endpoint: string, - baseUrl: string | URL, - transcriptionOptions: LiveSchema | TranscriptionSchema -): URL => { - const url = new URL(endpoint, baseUrl); - appendSearchParams(url.searchParams, transcriptionOptions); - - return url; -}; - -export function isLiveSchema(arg: any): arg is LiveSchema { - return arg != null && typeof arg.interim_results !== "undefined"; -} - -export function isDeepgramClientOptions(arg: any): arg is DeepgramClientOptions { - return arg != null && typeof arg.global !== "undefined"; -} - -export const convertLegacyOptions = (optionsArg: DeepgramClientOptions): DeepgramClientOptions => { - const newOptions: DeepgramClientOptions = {}; - - if (optionsArg._experimentalCustomFetch) { - newOptions.global = { - fetch: { - client: optionsArg._experimentalCustomFetch, - }, - }; - } - - optionsArg = merge(optionsArg, newOptions); - - if (optionsArg.restProxy?.url) { - newOptions.global = { - fetch: { - options: { - proxy: { - url: optionsArg.restProxy?.url, - }, - }, - }, - }; - } - - optionsArg = merge(optionsArg, newOptions); - - if (optionsArg.global?.url) { - newOptions.global = { - fetch: { - options: { - url: optionsArg.global.url, - }, - }, - websocket: { - options: { - url: optionsArg.global.url, - }, - }, - }; - } - - optionsArg = merge(optionsArg, newOptions); - - if (optionsArg.global?.headers) { - newOptions.global = { - fetch: { - options: { - headers: optionsArg.global?.headers, - }, - }, - websocket: { - options: { - _nodeOnlyHeaders: optionsArg.global?.headers, - }, - }, - }; - } - - optionsArg = merge(optionsArg, newOptions); - - return optionsArg; -}; diff --git a/src/lib/runtime.ts b/src/lib/runtime.ts deleted file mode 100644 index b7f25d2b..00000000 --- a/src/lib/runtime.ts +++ /dev/null @@ -1,20 +0,0 @@ -export const NODE_VERSION = - typeof process !== "undefined" && process.versions && process.versions.node - ? process.versions.node - : "unknown"; - -export const BUN_VERSION = - typeof process !== "undefined" && process.versions && process.versions.bun - ? process.versions.bun - : "unknown"; - -export const BROWSER_AGENT = - typeof window !== "undefined" && window.navigator && window.navigator.userAgent - ? window.navigator.userAgent - : "unknown"; - -export const isBrowser = () => BROWSER_AGENT !== "unknown"; - -export const isNode = () => NODE_VERSION !== "unknown"; - -export const isBun = () => BUN_VERSION !== "unknown"; diff --git a/src/lib/types/AgentLiveSchema.ts b/src/lib/types/AgentLiveSchema.ts deleted file mode 100644 index a2f81a74..00000000 --- a/src/lib/types/AgentLiveSchema.ts +++ /dev/null @@ -1,92 +0,0 @@ -type Provider = { type: string } & Record; - -type SpeakProvider = { - provider: Provider; - endpoint?: { - url: string; - headers?: Record; - }; -}; - -/** - * @see https://developers.deepgram.com/docs/configure-voice-agent - */ -interface AgentLiveSchema extends Record { - /** - * Set to true to enable experimental features. - * @default false - */ - experimental?: boolean; - /** - * @see https://developers.deepgram.com/docs/the-deepgram-model-improvement-partnership-program - * To opt out of Deepgram Model Improvement Program. - * @default false - */ - mips_opt_out?: boolean; - audio: { - input?: { - /** - * @default "linear16" - */ - encoding: string; - /** - * @default 16000 - */ - sample_rate: number; - }; - /** - * @see https://developers.deepgram.com/docs/tts-media-output-settings#audio-format-combinations - */ - output?: { - encoding?: string; - sample_rate?: number; - bitrate?: number; - /** - * @default "none" - */ - container?: string; - }; - }; - agent: { - /** - * ISO 639-1 language code for agent language. - * @default "en" - */ - language?: string; - listen?: { - provider: Provider; - }; - speak?: SpeakProvider | SpeakProvider[]; - /** - * @see https://developers.deepgram.com/docs/voice-agent-tts-models - */ - think?: { - provider: Provider; - /** - * Optional ONLY if LLM provider is OpenAI or Anthropic. - */ - endpoint?: { - url: string; - headers?: Record; - }; - functions?: { - name?: string; - description?: string; - parameters?: Record; - endpoint?: { - url?: string; - method?: string; - headers?: Record; - }; - }[]; - prompt?: string; - context_length?: number | "max"; - }; - /** - * Optional message the agent will say at the start of the connection. - */ - greeting?: string; - }; -} - -export type { AgentLiveSchema, SpeakProvider }; diff --git a/src/lib/types/AnalyzeSchema.ts b/src/lib/types/AnalyzeSchema.ts deleted file mode 100644 index a15f9604..00000000 --- a/src/lib/types/AnalyzeSchema.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Options for read analysis - */ -interface AnalyzeSchema extends Record { - /** - * @see https://developers.deepgram.com/docs/callback - */ - callback?: string; - - /** - * @see https://developers.deepgram.com/docs/callback#results - */ - callback_method?: "put" | "post"; - - custom_intent?: string | string[]; - - custom_intent_mode?: "strict" | "extended"; - - custom_topic?: string | string[]; - - custom_topic_mode?: "strict" | "extended"; - - intents?: boolean; - - language?: string; - - summarize?: boolean; - - sentiment?: boolean; - - topics?: boolean; - - /** - * @see https://developers.deepgram.com/docs/extra-metadata - */ - extra?: string[] | string; -} - -export type { AnalyzeSchema }; diff --git a/src/lib/types/AsyncAnalyzeResponse.ts b/src/lib/types/AsyncAnalyzeResponse.ts deleted file mode 100644 index ba7dd76f..00000000 --- a/src/lib/types/AsyncAnalyzeResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface AsyncAnalyzeResponse { - request_id: string; -} diff --git a/src/lib/types/AsyncPrerecordedResponse.ts b/src/lib/types/AsyncPrerecordedResponse.ts deleted file mode 100644 index e5a76bb6..00000000 --- a/src/lib/types/AsyncPrerecordedResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface AsyncPrerecordedResponse { - request_id: string; -} diff --git a/src/lib/types/CreateOnPremCredentialsSchema.ts b/src/lib/types/CreateOnPremCredentialsSchema.ts deleted file mode 100644 index 655984bb..00000000 --- a/src/lib/types/CreateOnPremCredentialsSchema.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface CreateOnPremCredentialsSchema extends Record { - comment?: string; - scopes?: string[]; - provider?: string; -} diff --git a/src/lib/types/CreateProjectKeyResponse.ts b/src/lib/types/CreateProjectKeyResponse.ts deleted file mode 100644 index 73b83814..00000000 --- a/src/lib/types/CreateProjectKeyResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface CreateProjectKeyResponse { - api_key_id: string; - key: string; - comment?: string; - scopes: string[]; - tags?: string[]; - created: string; - expiration_date?: string; -} diff --git a/src/lib/types/CreateProjectKeySchema.ts b/src/lib/types/CreateProjectKeySchema.ts deleted file mode 100644 index 9f43b0b5..00000000 --- a/src/lib/types/CreateProjectKeySchema.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type CreateProjectKeySchema = ExpirationOptions | TtlOptions; - -interface ExpirationOptions extends CommonOptions { - expiration_date?: string; -} - -export interface TtlOptions extends CommonOptions { - time_to_live_in_seconds?: number; -} - -interface CommonOptions extends Record { - comment: string; - scopes: string[]; - tags?: string[]; -} diff --git a/src/lib/types/DeepgramClientOptions.ts b/src/lib/types/DeepgramClientOptions.ts deleted file mode 100644 index 4f074fdb..00000000 --- a/src/lib/types/DeepgramClientOptions.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Fetch, FetchOptions } from "./Fetch"; - -export type IKeyFactory = () => string; -export type IFetch = typeof fetch; -export type IWebSocket = typeof WebSocket; - -interface TransportFetchOptions extends TransportOptions, FetchOptions {} -interface TransportWebSocketOptions extends TransportOptions { - _nodeOnlyHeaders?: { [index: string]: any }; -} - -type TransportUrl = string; - -interface TransportOptions { - url?: TransportUrl; - proxy?: { - url: TransportUrl; - }; -} - -interface ITransport { - client?: C; - options?: O; -} - -export type DefaultNamespaceOptions = { - key?: string | IKeyFactory; - accessToken?: string | IKeyFactory; - fetch: { - options: { url: TransportUrl }; - }; - websocket: { - options: { url: TransportUrl }; - }; -} & NamespaceOptions; - -export interface NamespaceOptions { - key?: string | IKeyFactory; - accessToken?: string | IKeyFactory; - fetch?: ITransport; - websocket?: ITransport; -} - -export type DefaultClientOptions = { - global: Partial; -} & DeepgramClientOptions; - -/** - * Configures the options for a Deepgram client. - * - * The `DeepgramClientOptions` interface defines the configuration options for a Deepgram client. It includes options for various namespaces, such as `global`, `listen`, `manage`, `onprem`, `read`, and `speak`. Each namespace has its own options for configuring the transport, including the URL, proxy, and options for the fetch and WebSocket clients. - * - * The `global` namespace is used to configure options that apply globally to the Deepgram client. The other namespaces are used to configure options specific to different Deepgram API endpoints. - * Support introductory formats: - * - fetch: FetchOptions; - * - _experimentalCustomFetch?: Fetch; - * - restProxy?: { - * url: null | string; - * }; - */ -export interface DeepgramClientOptions { - key?: string | IKeyFactory; - accessToken?: string | IKeyFactory; - global?: NamespaceOptions & { url?: string; headers?: { [index: string]: any } }; - listen?: NamespaceOptions; - manage?: NamespaceOptions; - onprem?: NamespaceOptions; - read?: NamespaceOptions; - speak?: NamespaceOptions; - agent?: NamespaceOptions; - - /** - * @deprecated as of 3.4, use a namespace like `global` instead - */ - fetch?: FetchOptions; - - /** - * @deprecated as of 3.4, use a namespace like `global` instead - */ - _experimentalCustomFetch?: Fetch; - - /** - * @deprecated as of 3.4, use a namespace like `global` instead - */ - restProxy?: { - url: null | string; - }; -} diff --git a/src/lib/types/DeepgramResponse.ts b/src/lib/types/DeepgramResponse.ts deleted file mode 100644 index 5a6c3893..00000000 --- a/src/lib/types/DeepgramResponse.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { DeepgramError } from "../errors"; - -export type DeepgramResponse = SuccessResponse | ErrorResponse; - -interface SuccessResponse { - result: T; - error: null; -} - -interface ErrorResponse { - result: null; - error: DeepgramError; -} diff --git a/src/lib/types/DeepgramSource.ts b/src/lib/types/DeepgramSource.ts deleted file mode 100644 index b9169a72..00000000 --- a/src/lib/types/DeepgramSource.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Readable } from "node:stream"; - -export type PrerecordedSource = UrlSource | Buffer | Readable; - -export type FileSource = Buffer | Readable; - -export interface UrlSource { - url: string; -} - -export interface TextSource { - text: string; -} - -export type AnalyzeSource = UrlSource | TextSource; diff --git a/src/lib/types/Fetch.ts b/src/lib/types/Fetch.ts deleted file mode 100644 index 0496c325..00000000 --- a/src/lib/types/Fetch.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type Fetch = typeof fetch; - -export type FetchOptions = RequestInit & { method?: RequestMethodType; duplex?: string }; - -export type RequestMethodType = "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; diff --git a/src/lib/types/FunctionCallResponse.ts b/src/lib/types/FunctionCallResponse.ts deleted file mode 100644 index ab74bffa..00000000 --- a/src/lib/types/FunctionCallResponse.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Respond with this when you receive a `FunctionCallRequest` payload. - */ -export interface FunctionCallResponse { - /** - * This must be the ID that was received in the request. - */ - id: string; - /** - * The name of the function being called. - */ - name: string; - /** - * The result of the function call. - */ - content: string; -} diff --git a/src/lib/types/GetModelsResponse.ts b/src/lib/types/GetModelsResponse.ts deleted file mode 100644 index eefe613d..00000000 --- a/src/lib/types/GetModelsResponse.ts +++ /dev/null @@ -1,24 +0,0 @@ -type Model = { - name: string; - canonical_name: string; - architecture: string; - languages?: string[]; - version: string; - uuid: string; - batch?: boolean; - streaming?: boolean; - formatted_output?: boolean; - metadata?: { - accent: string; - color: string; - image: string; - sample: string; - }; -}; - -export type GetModelResponse = Model; - -export type GetModelsResponse = { - stt: Model[]; - tts: Model[]; -}; diff --git a/src/lib/types/GetModelsSchema.ts b/src/lib/types/GetModelsSchema.ts deleted file mode 100644 index b0f34982..00000000 --- a/src/lib/types/GetModelsSchema.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface GetModelsSchema extends Record { - include_outdated?: boolean; -} diff --git a/src/lib/types/GetProjectBalancesResponse.ts b/src/lib/types/GetProjectBalancesResponse.ts deleted file mode 100644 index f3527ea1..00000000 --- a/src/lib/types/GetProjectBalancesResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface GetProjectBalancesResponse { - balances: GetProjectBalanceResponse[]; -} - -export interface GetProjectBalanceResponse { - balance_id: string; - amount: number; - units: string; - purchase: string; -} diff --git a/src/lib/types/GetProjectInvitesResponse.ts b/src/lib/types/GetProjectInvitesResponse.ts deleted file mode 100644 index cb5fce0d..00000000 --- a/src/lib/types/GetProjectInvitesResponse.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface GetProjectInvitesResponse { - invites: Invite[]; -} - -interface Invite { - email: string; - scope: string; -} diff --git a/src/lib/types/GetProjectKeysResponse.ts b/src/lib/types/GetProjectKeysResponse.ts deleted file mode 100644 index ff85c688..00000000 --- a/src/lib/types/GetProjectKeysResponse.ts +++ /dev/null @@ -1,23 +0,0 @@ -export interface GetProjectKeysResponse { - api_keys: GetProjectKeyResponse[]; -} - -export interface GetProjectKeyResponse { - member: Member; - api_key: Key; -} - -interface Member { - member_id: string; - email: string; - first_name: string; - last_name: string; -} - -interface Key { - api_key_id: string; - comment?: string; - scopes: string[]; - tags?: string[]; - created: string; -} diff --git a/src/lib/types/GetProjectMemberScopesResponse.ts b/src/lib/types/GetProjectMemberScopesResponse.ts deleted file mode 100644 index 0103f6bf..00000000 --- a/src/lib/types/GetProjectMemberScopesResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface GetProjectMemberScopesResponse { - scopes: string[]; -} diff --git a/src/lib/types/GetProjectMembersResponse.ts b/src/lib/types/GetProjectMembersResponse.ts deleted file mode 100644 index 8f1e28a4..00000000 --- a/src/lib/types/GetProjectMembersResponse.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface GetProjectMembersResponse { - members: Member[]; -} - -interface Member { - member_id: string; - first_name: string; - last_name: string; - scopes: string[]; - email: string; -} diff --git a/src/lib/types/GetProjectResponse.ts b/src/lib/types/GetProjectResponse.ts deleted file mode 100644 index ce338334..00000000 --- a/src/lib/types/GetProjectResponse.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface GetProjectResponse { - project_id: string; - name: string; - company: string; -} diff --git a/src/lib/types/GetProjectUsageFieldsResponse.ts b/src/lib/types/GetProjectUsageFieldsResponse.ts deleted file mode 100644 index 42ff55a4..00000000 --- a/src/lib/types/GetProjectUsageFieldsResponse.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface GetProjectUsageFieldsResponse { - tags: string[]; - models: UsageModel[]; - processing_methods: string[]; - languages: string[]; - features: string[]; -} - -interface UsageModel { - name: string; - language: string; - version: string; - model_id: string; -} diff --git a/src/lib/types/GetProjectUsageFieldsSchema.ts b/src/lib/types/GetProjectUsageFieldsSchema.ts deleted file mode 100644 index 4b7004bf..00000000 --- a/src/lib/types/GetProjectUsageFieldsSchema.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface GetProjectUsageFieldsSchema extends Record { - start?: string; - end: string; -} diff --git a/src/lib/types/GetProjectUsageRequestsResponse.ts b/src/lib/types/GetProjectUsageRequestsResponse.ts deleted file mode 100644 index 6b67901f..00000000 --- a/src/lib/types/GetProjectUsageRequestsResponse.ts +++ /dev/null @@ -1,49 +0,0 @@ -export interface GetProjectUsageRequestsResponse { - page: number; - limit: number; - requests: GetProjectUsageRequestResponse[]; -} - -export interface GetProjectUsageRequestResponse { - request_id: string; - created: string; - path: string; - api_key_id: string; - response: { - details: { - usd?: number; - duration?: number; - total_audio?: number; - channels?: number; - streams?: number; - models?: string[]; - method?: string; - tags?: string[]; - features?: string[]; - config?: { - alternatives?: number; - callback?: string; - diarize?: boolean; - keywords?: string[]; - language?: string; - model?: string; - multichannel?: boolean; - ner?: boolean; - numerals?: boolean; - profanity_filter?: boolean; - punctuate?: boolean; - redact?: string[]; - search?: string[]; - utterances?: boolean; - [key: string]: unknown; - }; - }; - code?: number; - completed?: string; - }; - callback?: { - attempts?: number; - code?: number; - completed?: string; - }; -} diff --git a/src/lib/types/GetProjectUsageRequestsSchema.ts b/src/lib/types/GetProjectUsageRequestsSchema.ts deleted file mode 100644 index 1b4b4e3e..00000000 --- a/src/lib/types/GetProjectUsageRequestsSchema.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface GetProjectUsageRequestsSchema extends Record { - start?: string; - end?: string; - limit?: number; - status?: string; -} diff --git a/src/lib/types/GetProjectUsageSummaryResponse.ts b/src/lib/types/GetProjectUsageSummaryResponse.ts deleted file mode 100644 index c19687a9..00000000 --- a/src/lib/types/GetProjectUsageSummaryResponse.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface GetProjectUsageSummaryResponse { - start: string; - end: string; - resolution: { - units: string; - amount: number; - }; - results: UsageSummary[]; -} - -interface UsageSummary { - start: string; - end: string; - hours: number; - total_hours: number; - requests: number; -} diff --git a/src/lib/types/GetProjectUsageSummarySchema.ts b/src/lib/types/GetProjectUsageSummarySchema.ts deleted file mode 100644 index e91421f3..00000000 --- a/src/lib/types/GetProjectUsageSummarySchema.ts +++ /dev/null @@ -1,23 +0,0 @@ -export interface GetProjectUsageSummarySchema extends Record { - start?: string; - end: string; - accessor?: string; - tag?: string; - method?: string; - model?: string; - multichannel?: boolean; - interim_results?: boolean; - punctuate?: boolean; - ner?: boolean; - utterances?: boolean; - replace?: boolean; - profanity_filter?: boolean; - keywords?: boolean; - detect_topics?: boolean; - diarize?: boolean; - search?: boolean; - redact?: boolean; - alternatives?: boolean; - numerals?: boolean; - smart_format?: boolean; -} diff --git a/src/lib/types/GetProjectsResponse.ts b/src/lib/types/GetProjectsResponse.ts deleted file mode 100644 index 316ed39b..00000000 --- a/src/lib/types/GetProjectsResponse.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface GetProjectsResponse { - projects: Project[]; -} - -interface Project { - project_id: string; - name: string; -} diff --git a/src/lib/types/GetTokenDetailsResponse.ts b/src/lib/types/GetTokenDetailsResponse.ts deleted file mode 100644 index 23367434..00000000 --- a/src/lib/types/GetTokenDetailsResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface GetTokenDetailsResponse { - [key: string]: unknown; -} diff --git a/src/lib/types/GrantTokenResponse.ts b/src/lib/types/GrantTokenResponse.ts deleted file mode 100644 index 8560b8ee..00000000 --- a/src/lib/types/GrantTokenResponse.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface GrantTokenResponse { - access_token: string; - expires_in: number; -} diff --git a/src/lib/types/GrantTokenSchema.ts b/src/lib/types/GrantTokenSchema.ts deleted file mode 100644 index 692b6e45..00000000 --- a/src/lib/types/GrantTokenSchema.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface GrantTokenSchema extends Record { - /** - * Time to live in seconds for the token. Defaults to 30 seconds. - * @minimum 1 - * @maximum 3600 - * @example 30 - */ - ttl_seconds?: number; -} diff --git a/src/lib/types/ListOnPremCredentialsResponse.ts b/src/lib/types/ListOnPremCredentialsResponse.ts deleted file mode 100644 index bc979dc1..00000000 --- a/src/lib/types/ListOnPremCredentialsResponse.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface ListOnPremCredentialsResponse { - distribution_credentials: OnPremCredentialResponse[]; -} - -export interface OnPremCredentialResponse { - member: { - member_id: string; - email: string; - }; - distribution_credentials: { - distribution_credentials_id: string; - provider: string; - comment: string; - scopes: string[]; - created: string; - }; -} diff --git a/src/lib/types/LiveConfigOptions.ts b/src/lib/types/LiveConfigOptions.ts deleted file mode 100644 index 47b60c87..00000000 --- a/src/lib/types/LiveConfigOptions.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { LiveSchema } from "./TranscriptionSchema"; - -/** - * Partial configuration options for the LiveSchema, including: - * - `numerals`: Configures how numerals are handled in the live transcription. - */ -export type LiveConfigOptions = Partial>; diff --git a/src/lib/types/LiveMetadataEvent.ts b/src/lib/types/LiveMetadataEvent.ts deleted file mode 100644 index b623615a..00000000 --- a/src/lib/types/LiveMetadataEvent.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface LiveMetadataEvent { - type: "Metadata"; - transaction_key: string; - request_id: string; - sha256: string; - created: string; - duration: number; - channels: number; -} diff --git a/src/lib/types/LiveTranscriptionEvent.ts b/src/lib/types/LiveTranscriptionEvent.ts deleted file mode 100644 index 9938f9ab..00000000 --- a/src/lib/types/LiveTranscriptionEvent.ts +++ /dev/null @@ -1,34 +0,0 @@ -export interface LiveTranscriptionEvent { - type: "Results"; - channel_index: number[]; - duration: number; - start: number; - is_final?: boolean; - speech_final?: boolean; - channel: { - alternatives: { - transcript: string; - confidence: number; - languages: string[]; - words: { - word: string; - start: number; - end: number; - confidence: number; - language: string; - punctuated_word: string; - speaker?: number; - }[]; - }[]; - }; - metadata: { - request_id: string; - model_info: { - name: string; - version: string; - arch: string; - }; - model_uuid: string; - }; - from_finalize?: boolean; -} diff --git a/src/lib/types/MessageResponse.ts b/src/lib/types/MessageResponse.ts deleted file mode 100644 index a2c23cc1..00000000 --- a/src/lib/types/MessageResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface MessageResponse { - message: string; -} diff --git a/src/lib/types/SendProjectInviteSchema.ts b/src/lib/types/SendProjectInviteSchema.ts deleted file mode 100644 index 45dc78b4..00000000 --- a/src/lib/types/SendProjectInviteSchema.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface SendProjectInviteSchema extends Record { - email: string; - scope: string; -} diff --git a/src/lib/types/SpeakSchema.ts b/src/lib/types/SpeakSchema.ts deleted file mode 100644 index 3f37aa81..00000000 --- a/src/lib/types/SpeakSchema.ts +++ /dev/null @@ -1,29 +0,0 @@ -export interface SpeakSchema extends Record { - /** - * The model, voice, language, and version of the voice. - * Follows the format of[modelname]-[voicename]-[language]-[version]. - */ - model?: string; - - /** - * Encoding options for the output audio. Default is 'mp3'. - */ - encoding?: "linear16" | "mulaw" | "alaw" | "mp3" | "opus" | "flac" | "aac"; - - /** - * File format wrapper for the audio. - */ - container?: string; - - /** - * Sample rate of the audio output. - */ - sample_rate?: number; - - /** - * Bit rate of the audio output. - */ - bit_rate?: number; - - [key: string]: unknown; -} diff --git a/src/lib/types/SpeechStartedEvent.ts b/src/lib/types/SpeechStartedEvent.ts deleted file mode 100644 index 2a8bdaba..00000000 --- a/src/lib/types/SpeechStartedEvent.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface SpeechStartedEvent { - type: "SpeechStarted"; - channel: number[]; - timestamp: number; -} diff --git a/src/lib/types/SyncAnalyzeResponse.ts b/src/lib/types/SyncAnalyzeResponse.ts deleted file mode 100644 index d56fc85d..00000000 --- a/src/lib/types/SyncAnalyzeResponse.ts +++ /dev/null @@ -1,91 +0,0 @@ -export interface SyncAnalyzeResponse { - model_uuid: string; - metadata: Metadata; - results: Results; -} - -interface IntentsInfo { - model_uuid: string; - input_tokens: number; - output_tokens: number; -} - -interface SentimentInfo { - model_uuid: string; - input_tokens: number; - output_tokens: number; -} - -interface SummaryInfo { - model_uuid: string; - input_tokens: number; - output_tokens: number; -} - -interface TopicsInfo { - model_uuid: string; - input_tokens: number; - output_tokens: number; -} - -interface Metadata { - request_id: string; - created: string; - language: string; - intents_info: IntentsInfo; - sentiment_info: SentimentInfo; - summary_info: SummaryInfo; - topics_info: TopicsInfo; - extra?: { - [key: string]: unknown; - }; -} - -interface Average { - sentiment: string; - sentiment_score: number; -} - -interface Summary { - text: string; -} - -interface Topic { - topic: string; - confidence_score: number; -} - -interface Intent { - intent: string; - confidence_score: number; -} - -interface Segment { - text: string; - start_word: number; - end_word: number; - sentiment: "positive" | "neutral" | "negative"; - sentiment_score?: number; - topics?: Topic[]; - intents?: Intent[]; -} - -interface Sentiments { - segments: Segment[]; - average: Average; -} - -interface Topics { - segments: Segment[]; -} - -interface Intents { - segments: Segment[]; -} - -interface Results { - sentiments?: Sentiments; - summary?: Summary; - topics?: Topics; - intents?: Intents; -} diff --git a/src/lib/types/SyncPrerecordedResponse.ts b/src/lib/types/SyncPrerecordedResponse.ts deleted file mode 100644 index a0b51229..00000000 --- a/src/lib/types/SyncPrerecordedResponse.ts +++ /dev/null @@ -1,213 +0,0 @@ -export interface SyncPrerecordedResponse { - metadata: Metadata; - results: Result; -} - -interface Alternative { - transcript: string; - confidence: number; - words: WordBase[]; - summaries?: Summary[]; - paragraphs?: ParagraphGroup; - entities?: Entity[]; - translations?: Translation[]; - topics?: TopicGroup[]; - languages?: string[]; -} - -interface Channel { - search?: Search[]; - alternatives: Alternative[]; - detected_language?: string; - language_confidence?: number; -} - -interface Entity { - label: string; - value: string; - confidence: number; - start_word: number; - end_word: number; -} - -interface Hit { - confidence: number; - start: number; - end: number; - snippet: string; -} - -interface Metadata { - transaction_key: string; - request_id: string; - sha256: string; - created: string; - duration: number; - channels: number; - models: string[]; - warnings?: Warning[]; - model_info: Record; - summary_info?: SummaryInfo; - intents_info?: IntentsInfo; - sentiment_info?: SentimentInfo; - topics_info?: TopicsInfo; - extra?: { - [key: string]: unknown; - }; -} - -interface ModelInfo { - name: string; - version: string; - arch: string; -} - -interface SummaryInfo { - input_tokens: number; - output_tokens: number; - model_uuid: string; -} - -interface IntentsInfo { - model_uuid: string; - input_tokens: number; - output_tokens: number; -} - -interface SentimentInfo { - model_uuid: string; - input_tokens: number; - output_tokens: number; -} - -interface TopicsInfo { - model_uuid: string; - input_tokens: number; - output_tokens: number; -} - -interface Paragraph { - sentences: Sentence[]; - start: number; - end: number; - num_words: number; - speaker?: number; -} - -interface ParagraphGroup { - transcript: string; - paragraphs: Paragraph[]; -} - -interface Result { - channels: Channel[]; - utterances?: Utterance[]; - summary?: TranscriptionSummary; - sentiments?: Sentiments; - topics?: Topics; - intents?: Intents; -} - -interface Sentiments { - segments: Segment[]; - average: Average; -} - -interface Topics { - segments: Segment[]; -} - -interface Intents { - segments: Segment[]; -} - -interface Intent { - intent: string; - confidence_score: number; -} - -interface Average { - sentiment: string; - sentiment_score: number; -} - -interface Topic { - topic: string; - confidence_score: number; -} - -interface Segment { - text: string; - start_word: number; - end_word: number; - sentiment?: string; - sentiment_score?: number; - topics?: Topic[]; - intents?: Intent[]; -} - -interface Search { - query: string; - hits: Hit[]; -} - -interface Sentence { - text: string; - start: number; - end: number; -} - -interface Summary { - summary?: string; - start_word?: number; - end_word?: number; -} -interface TranscriptionSummary { - result: string; - short: string; -} - -interface Topic { - topic: string; - confidence: number; -} - -interface TopicGroup { - topics: Topic[]; - text: string; - start_word: number; - end_word: number; -} - -interface Translation { - language: string; - translation: string; -} - -interface Utterance { - start: number; - end: number; - confidence: number; - channel: number; - transcript: string; - words: WordBase[]; - speaker?: number; - id: string; -} - -interface Warning { - parameter: string; - type: string; - message: string; -} - -interface WordBase { - word: string; - start: number; - end: number; - confidence: number; - punctuated_word?: string; - speaker?: number; - speaker_confidence?: number; - language?: string; -} diff --git a/src/lib/types/TranscriptionSchema.ts b/src/lib/types/TranscriptionSchema.ts deleted file mode 100644 index cb55ab7f..00000000 --- a/src/lib/types/TranscriptionSchema.ts +++ /dev/null @@ -1,246 +0,0 @@ -/** - * Options for transcription - */ -interface TranscriptionSchema extends Record { - /** - * @see https://developers.deepgram.com/docs/model - */ - model?: string; - - /** - * @deprecated - * @see https://developers.deepgram.com/docs/tier - */ - tier?: string; - - /** - * @see https://developers.deepgram.com/docs/version - */ - version?: string; - - /** - * @see https://developers.deepgram.com/docs/language - */ - language?: string; - - /** - * @see https://developers.deepgram.com/docs/punctuation - */ - punctuate?: boolean; - - /** - * @see https://developers.deepgram.com/docs/profanity-filter - */ - profanity_filter?: boolean; - - /** - * @see https://developers.deepgram.com/docs/redaction - */ - redact?: string[] | string | boolean; - - /** - * @see https://developers.deepgram.com/docs/diarization - */ - diarize?: boolean; - - /** - * @see https://developers.deepgram.com/docs/diarization - */ - diarize_version?: string; - - /** - * @see https://developers.deepgram.com/docs/smart-format - */ - smart_format?: boolean; - - /** - * @see https://developers.deepgram.com/docs/filler-words - */ - filler_words?: boolean; - - /** - * @see https://developers.deepgram.com/docs/multichannel - */ - multichannel?: boolean; - - /** - * @see https://developers.deepgram.com/docs/numerals - * @deprecated - */ - numerals?: boolean; - - /** - * @see https://developers.deepgram.com/docs/search - */ - search?: string[] | string; - - /** - * @see https://developers.deepgram.com/docs/find-and-replace - */ - replace?: string[] | string; - - /** - * @see https://developers.deepgram.com/docs/callback - */ - callback?: string; - - /** - * @see https://developers.deepgram.com/docs/callback#results - */ - callback_method?: "put" | "post"; - - /** - * @see https://developers.deepgram.com/docs/keywords - */ - keywords?: string[] | string; - - /** - * @see https://developers.deepgram.com/docs/keyterm - */ - keyterm?: string[] | string; - - /** - * @see https://developers.deepgram.com/docs/tagging - */ - tag?: string[]; - - /** - * As yet unreleased. - */ - sentiment?: boolean; - - /** - * As yet unreleased. - */ - intents?: boolean; - - /** - * As yet unreleased. - */ - custom_intent?: string[] | string; - - /** - * As yet unreleased. - */ - custom_intent_mode?: "strict" | "extended"; - - /** - * As yet unreleased. - */ - topics?: boolean; - - /** - * As yet unreleased. - */ - custom_topic?: string[] | string; - - /** - * As yet unreleased. - */ - custom_topic_mode?: "strict" | "extended"; - - /** - * @see https://developers.deepgram.com/docs/extra-metadata - */ - extra?: string[] | string; -} - -interface PrerecordedSchema extends TranscriptionSchema { - /** - * @see https://developers.deepgram.com/docs/detect-entities - */ - detect_entities?: boolean; - - /** - * @see https://developers.deepgram.com/docs/language-detection - */ - detect_language?: boolean | string[]; - - /** - * @see https://developers.deepgram.com/docs/topic-detection - */ - detect_topics?: boolean; - - /** - * Alternatives will run your transcription X number of times and return - * that many variations of the transcription, allowing for the selection - * of the most accurate. Cost increases by number of alternatives. - * - * @deprecated - */ - alternatives?: number; - - /** - * @see https://developers.deepgram.com/docs/paragraphs - */ - paragraphs?: boolean; - - /** - * @see https://developers.deepgram.com/docs/summarization - */ - summarize?: boolean | string; - - /** - * @see https://developers.deepgram.com/docs/utterances - */ - utterances?: boolean; - - /** - * @see https://developers.deepgram.com/docs/utterance-split - */ - utt_split?: number; - - /** - * @see https://developers.deepgram.com/docs/smart-format#dictation - */ - dictation?: boolean; - - /** - * @see https://developers.deepgram.com/docs/smart-format#measurements - */ - measurements?: boolean; -} - -interface LiveSchema extends TranscriptionSchema { - /** - * @see https://developers.deepgram.com/docs/channels - */ - channels?: number; - - /** - * @see https://developers.deepgram.com/docs/encoding - */ - encoding?: string; - - /** - * @see https://developers.deepgram.com/docs/sample-rate - */ - sample_rate?: number; - - /** - * @see https://developers.deepgram.com/docs/endpointing - */ - endpointing?: false | number; - - /** - * @see https://developers.deepgram.com/docs/interim-results - */ - interim_results?: boolean; - - /** - * @see https://developers.deepgram.com/docs/smart-format#using-no-delay - */ - no_delay?: boolean; - - /** - * @see https://developers.deepgram.com/docs/understanding-end-of-speech-detection - */ - utterance_end_ms?: number; - - /** - * @see https://developers.deepgram.com/docs/start-of-speech-detection - */ - vad_events?: boolean; -} - -export type { TranscriptionSchema, PrerecordedSchema, LiveSchema }; diff --git a/src/lib/types/UpdateProjectMemberScopeSchema.ts b/src/lib/types/UpdateProjectMemberScopeSchema.ts deleted file mode 100644 index f4a7e64a..00000000 --- a/src/lib/types/UpdateProjectMemberScopeSchema.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface UpdateProjectMemberScopeSchema extends Record { - scope: string; -} diff --git a/src/lib/types/UpdateProjectSchema.ts b/src/lib/types/UpdateProjectSchema.ts deleted file mode 100644 index f5b090e5..00000000 --- a/src/lib/types/UpdateProjectSchema.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface UpdateProjectSchema extends Record { - name?: string; - company?: string; -} diff --git a/src/lib/types/UtteranceEndEvent.ts b/src/lib/types/UtteranceEndEvent.ts deleted file mode 100644 index 83e241cc..00000000 --- a/src/lib/types/UtteranceEndEvent.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface UtteranceEndEvent { - type: "UtteranceEnd"; - channel: number[]; - last_word_end: number; -} diff --git a/src/lib/types/VoidResponse.ts b/src/lib/types/VoidResponse.ts deleted file mode 100644 index cfb8d74b..00000000 --- a/src/lib/types/VoidResponse.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { DeepgramError } from "../errors"; - -export type VoidResponse = SuccessResponse | ErrorResponse; - -interface SuccessResponse { - error: null; -} - -interface ErrorResponse { - error: DeepgramError; -} diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts deleted file mode 100644 index d0451ad0..00000000 --- a/src/lib/types/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -export * from "./AgentLiveSchema"; -export * from "./AnalyzeSchema"; -export * from "./AsyncAnalyzeResponse"; -export * from "./AsyncPrerecordedResponse"; -export * from "./CreateOnPremCredentialsSchema"; -export * from "./CreateProjectKeyResponse"; -export * from "./CreateProjectKeySchema"; -export * from "./DeepgramClientOptions"; -export * from "./DeepgramResponse"; -export * from "./DeepgramSource"; -export * from "./Fetch"; -export * from "./FunctionCallResponse"; -export * from "./GetModelsResponse"; -export * from "./GetModelsSchema"; -export * from "./GetProjectBalancesResponse"; -export * from "./GetProjectInvitesResponse"; -export * from "./GetProjectKeysResponse"; -export * from "./GetProjectMemberScopesResponse"; -export * from "./GetProjectMembersResponse"; -export * from "./GetProjectResponse"; -export * from "./GetProjectsResponse"; -export * from "./GetProjectUsageFieldsResponse"; -export * from "./GetProjectUsageFieldsSchema"; -export * from "./GetProjectUsageRequestsResponse"; -export * from "./GetProjectUsageRequestsSchema"; -export * from "./GetProjectUsageSummaryResponse"; -export * from "./GetProjectUsageSummarySchema"; -export * from "./GetTokenDetailsResponse"; -export * from "./GrantTokenResponse"; -export * from "./GrantTokenSchema"; -export * from "./ListOnPremCredentialsResponse"; -export * from "./LiveConfigOptions"; -export * from "./LiveMetadataEvent"; -export * from "./LiveTranscriptionEvent"; -export * from "./MessageResponse"; -export * from "./SendProjectInviteSchema"; -export * from "./SpeakSchema"; -export * from "./SpeechStartedEvent"; -export * from "./SyncAnalyzeResponse"; -export * from "./SyncPrerecordedResponse"; -export * from "./TranscriptionSchema"; -export * from "./UpdateProjectMemberScopeSchema"; -export * from "./UpdateProjectSchema"; -export * from "./UtteranceEndEvent"; -export * from "./VoidResponse"; diff --git a/src/lib/version.ts b/src/lib/version.ts deleted file mode 100644 index c4963561..00000000 --- a/src/lib/version.ts +++ /dev/null @@ -1 +0,0 @@ -export const version = "0.0.0-automated"; diff --git a/src/packages/AbstractClient.ts b/src/packages/AbstractClient.ts deleted file mode 100644 index 1668c185..00000000 --- a/src/packages/AbstractClient.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { EventEmitter } from "events"; -import { DEFAULT_OPTIONS, DEFAULT_URL } from "../lib/constants"; -import { DeepgramError } from "../lib/errors"; -import { appendSearchParams, applyDefaults, convertLegacyOptions } from "../lib/helpers"; -import type { - DeepgramClientOptions, - DefaultClientOptions, - DefaultNamespaceOptions, - NamespaceOptions, -} from "../lib/types"; - -export const noop = () => {}; - -/** - * Represents an abstract Deepgram client that provides a base implementation for interacting with the Deepgram API. - * - * The `AbstractClient` class is responsible for: - * - Initializing the Deepgram API key - * - Applying default options for the client and namespace - * - Providing a namespace for organizing API requests - * - * Subclasses of `AbstractClient` should implement the specific functionality for interacting with the Deepgram API. - */ -export abstract class AbstractClient extends EventEmitter { - protected factory: Function | undefined = undefined; - protected key: string | undefined = undefined; - protected accessToken: string | undefined = undefined; - protected options: DefaultClientOptions; - public namespace: string = "global"; - public version: string = "v1"; - public baseUrl: string = DEFAULT_URL; - public logger: Function = noop; - - /** - * Constructs a new instance of the DeepgramClient class with the provided options. - * - * @param options - The options to configure the DeepgramClient instance. - * @param options.key - The Deepgram API key to use for authentication. If not provided, the `DEEPGRAM_API_KEY` environment variable will be used. - * @param options.accessToken - The Deepgram access token to use for authentication. If not provided, the `DEEPGRAM_ACCESS_TOKEN` environment variable will be used. - * @param options.global - Global options that apply to all requests made by the DeepgramClient instance. - * @param options.global.fetch - Options to configure the fetch requests made by the DeepgramClient instance. - * @param options.global.fetch.options - Additional options to pass to the fetch function, such as `url` and `headers`. - * @param options.namespace - Options specific to a particular namespace within the DeepgramClient instance. - */ - constructor(options: DeepgramClientOptions) { - super(); - - // run the factory for the access token if it's a function - if (typeof options.accessToken === "function") { - this.factory = options.accessToken; - this.accessToken = this.factory(); - } else { - this.accessToken = options.accessToken; - } - - // run the factory for the key if it's a function - if (typeof options.key === "function") { - this.factory = options.key; - this.key = this.factory(); - } else { - this.key = options.key; - } - - // implement priority-based credential resolution for environment variables - if (!this.key && !this.accessToken) { - // check for DEEPGRAM_ACCESS_TOKEN first (higher priority) - this.accessToken = process.env.DEEPGRAM_ACCESS_TOKEN as string; - - // if still no access token, fall back to DEEPGRAM_API_KEY (lower priority) - if (!this.accessToken) { - this.key = process.env.DEEPGRAM_API_KEY as string; - } - } - - // if we STILL have neither, throw an error - if (!this.key && !this.accessToken) { - throw new DeepgramError("A deepgram API key or access token is required."); - } - - options = convertLegacyOptions(options); - - /** - * Apply default options. - */ - this.options = applyDefaults( - options, - DEFAULT_OPTIONS - ); - } - - /** - * Sets the version for the current instance of the Deepgram API and returns the instance. - * - * @param version - The version to set for the Deepgram API instance. Defaults to "v1" if not provided. - * @returns The current instance of the AbstractClient with the updated version. - */ - public v(version: string = "v1"): this { - this.version = version; - - return this; - } - - /** - * Gets the namespace options for the current instance of the AbstractClient. - * The namespace options include the default options merged with the global options, - * and the API key for the current instance. - * - * @returns The namespace options for the current instance. - */ - get namespaceOptions(): DefaultNamespaceOptions { - const defaults = applyDefaults( - (this.options as any)[this.namespace], - this.options.global - ); - - return { - ...defaults, - key: this.key, - }; - } - - /** - * Generates a URL for an API endpoint with optional query parameters and transcription options. - * - * @param endpoint - The API endpoint URL, which may contain placeholders for fields. - * @param fields - An optional object containing key-value pairs to replace placeholders in the endpoint URL. - * @param transcriptionOptions - Optional transcription options to include as query parameters in the URL. - * @returns A URL object representing the constructed API request URL. - */ - public getRequestUrl( - endpoint: string, - fields: { [key: string]: string } = { version: this.version }, - transcriptionOptions?: { - [key: string]: unknown; - } - ): URL { - /** - * If we pass in fields without a version, set a version. - */ - fields.version = this.version; - - /** - * Version and template the endpoint for input argument.. - */ - endpoint = endpoint.replace(/:(\w+)/g, function (_, key) { - return fields![key]; - }); - - /** - * Create a URL object. - */ - const url = new URL(endpoint as string, this.baseUrl); - - /** - * If there are transcription options, append them to the request as URL querystring parameters - */ - if (transcriptionOptions) { - appendSearchParams(url.searchParams, transcriptionOptions); - } - - return url; - } - - /** - * Logs the message. - * - * For customized logging, `this.logger` can be overridden. - */ - public log(kind: string, msg: string, data?: any) { - this.logger(kind, msg, data); - } -} diff --git a/src/packages/AbstractLiveClient.ts b/src/packages/AbstractLiveClient.ts deleted file mode 100644 index b25675b4..00000000 --- a/src/packages/AbstractLiveClient.ts +++ /dev/null @@ -1,542 +0,0 @@ -import { AbstractClient, noop } from "./AbstractClient"; -import { CONNECTION_STATE, SOCKET_STATES } from "../lib/constants"; -import type { DeepgramClientOptions, LiveSchema } from "../lib/types"; -import type { WebSocket as WSWebSocket } from "ws"; -import { isBun } from "../lib/runtime"; -import { DeepgramWebSocketError } from "../lib/errors"; - -/** - * Represents a constructor for a WebSocket-like object that can be used in the application. - * The constructor takes the following parameters: - * @param address - The URL or address of the WebSocket server. - * @param _ignored - An optional parameter that is ignored. - * @param options - An optional object containing headers to be included in the WebSocket connection. - * @returns A WebSocket-like object that implements the WebSocketLike interface. - */ -interface WebSocketLikeConstructor { - new( - address: string | URL, - _ignored?: any, - options?: { headers: object | undefined } - ): WebSocketLike; -} - -/** - * Represents the types of WebSocket-like connections that can be used in the application. - * This type is used to provide a common interface for different WebSocket implementations, - * such as the native WebSocket API, a WebSocket wrapper library, or a dummy implementation - * for testing purposes. - */ -type WebSocketLike = WebSocket | WSWebSocket | WSWebSocketDummy; - -/** - * Represents the types of data that can be sent or received over a WebSocket-like connection. - */ -type SocketDataLike = string | ArrayBufferLike | Blob; - -/** - * Represents an error that occurred in a WebSocket-like connection. - * @property {any} error - The underlying error object. - * @property {string} message - A human-readable error message. - * @property {string} type - The type of the error. - */ -// interface WebSocketLikeError { -// error: any; -// message: string; -// type: string; -// } - -/** - * Indicates whether a native WebSocket implementation is available in the current environment. - */ -const NATIVE_WEBSOCKET_AVAILABLE = typeof WebSocket !== "undefined"; - -/** - * Represents an abstract live client that extends the AbstractClient class. - * The AbstractLiveClient class provides functionality for connecting, reconnecting, and disconnecting a WebSocket connection, as well as sending data over the connection. - * Subclasses of this class are responsible for setting up the connection event handlers. - * - * @abstract - */ -export abstract class AbstractLiveClient extends AbstractClient { - public headers: { [key: string]: string }; - public transport: WebSocketLikeConstructor | null; - public conn: WebSocketLike | null = null; - public sendBuffer: Function[] = []; - - constructor(options: DeepgramClientOptions) { - super(options); - - const { - key, - websocket: { options: websocketOptions, client }, - } = this.namespaceOptions; - - if (this.proxy) { - this.baseUrl = websocketOptions.proxy!.url; - } else { - this.baseUrl = websocketOptions.url; - } - - if (client) { - this.transport = client; - } else { - this.transport = null; - } - - if (websocketOptions._nodeOnlyHeaders) { - this.headers = websocketOptions._nodeOnlyHeaders; - } else { - this.headers = {}; - } - - if (!("Authorization" in this.headers)) { - if (this.accessToken) { - this.headers["Authorization"] = `Bearer ${this.accessToken}`; // Use token if available - } else { - this.headers["Authorization"] = `Token ${key}`; // Add default token - } - } - } - - /** - * Connects the socket, unless already connected. - * - * @protected Can only be called from within the class. - */ - protected connect(transcriptionOptions: LiveSchema, endpoint: string): void { - if (this.conn) { - return; - } - - this.reconnect = (options = transcriptionOptions) => { - this.connect(options, endpoint); - }; - - const requestUrl = this.getRequestUrl(endpoint, {}, transcriptionOptions); - const accessToken = this.accessToken; - const apiKey = this.key; - - if (!accessToken && !apiKey) { - throw new Error("No key or access token provided for WebSocket connection."); - } - - /** - * Custom websocket transport - */ - if (this.transport) { - this.conn = new this.transport(requestUrl, undefined, { - headers: this.headers, - }); - this.setupConnection(); - return; - } - - /** - * @summary Bun websocket transport has a bug where it's native WebSocket implementation messes up the headers - * @summary This is a workaround to use the WS package for the websocket connection instead of the native Bun WebSocket - * @summary you can track the issue here - * @link https://github.com/oven-sh/bun/issues/4529 - */ - if (isBun()) { - import("ws").then(({ default: WS }) => { - this.conn = new WS(requestUrl, { - headers: this.headers, - }); - console.log(`Using WS package`); - this.setupConnection(); - }); - return; - } - - /** - * Native websocket transport (browser) - */ - if (NATIVE_WEBSOCKET_AVAILABLE) { - this.conn = new WebSocket( - requestUrl, - accessToken ? ["bearer", accessToken] : ["token", apiKey!] - ); - this.setupConnection(); - return; - } - - /** - * Dummy websocket - */ - this.conn = new WSWebSocketDummy(requestUrl, undefined, { - close: () => { - this.conn = null; - }, - }); - - /** - * WS package for node environment - */ - import("ws").then(({ default: WS }) => { - this.conn = new WS(requestUrl, undefined, { - headers: this.headers, - }); - this.setupConnection(); - }); - } - - /** - * Reconnects the socket using new or existing transcription options. - * - * @param options - The transcription options to use when reconnecting the socket. - */ - public reconnect: (options: LiveSchema) => void = noop; - - /** - * Disconnects the socket from the client. - * - * @param code A numeric status code to send on disconnect. - * @param reason A custom reason for the disconnect. - */ - public disconnect(code?: number, reason?: string): void { - if (this.conn) { - this.conn.onclose = function () { }; // noop - if (code) { - this.conn.close(code, reason ?? ""); - } else { - this.conn.close(); - } - this.conn = null; - } - } - - /** - * Returns the current connection state of the WebSocket connection. - * - * @returns The current connection state of the WebSocket connection. - */ - public connectionState(): CONNECTION_STATE { - switch (this.conn && this.conn.readyState) { - case SOCKET_STATES.connecting: - return CONNECTION_STATE.Connecting; - case SOCKET_STATES.open: - return CONNECTION_STATE.Open; - case SOCKET_STATES.closing: - return CONNECTION_STATE.Closing; - default: - return CONNECTION_STATE.Closed; - } - } - - /** - * Returns the current ready state of the WebSocket connection. - * - * @returns The current ready state of the WebSocket connection. - */ - public getReadyState(): SOCKET_STATES { - return this.conn?.readyState ?? SOCKET_STATES.closed; - } - - /** - * Returns `true` is the connection is open. - */ - public isConnected(): boolean { - return this.connectionState() === CONNECTION_STATE.Open; - } - - /** - * Sends data to the Deepgram API via websocket connection - * @param data Audio data to send to Deepgram - * - * Conforms to RFC #146 for Node.js - does not send an empty byte. - * @see https://github.com/deepgram/deepgram-python-sdk/issues/146 - */ - send(data: SocketDataLike): void { - const callback = async () => { - if (data instanceof Blob) { - if (data.size === 0) { - this.log("warn", "skipping `send` for zero-byte blob", data); - - return; - } - - data = await data.arrayBuffer(); - } - - if (typeof data !== "string") { - if (!data?.byteLength) { - this.log("warn", "skipping `send` for zero-byte payload", data); - - return; - } - } - - this.conn?.send(data); - }; - - if (this.isConnected()) { - callback(); - } else { - this.sendBuffer.push(callback); - } - } - - /** - * Determines whether the current instance should proxy requests. - * @returns {boolean} true if the current instance should proxy requests; otherwise, false - */ - get proxy(): boolean { - return this.key === "proxy" && !!this.namespaceOptions.websocket.options.proxy?.url; - } - - /** - * Extracts enhanced error information from a WebSocket error event. - * This method attempts to capture additional debugging information such as - * status codes, request IDs, and response headers when available. - * - * @example - * ```typescript - * // Enhanced error information is now available in error events: - * connection.on(LiveTranscriptionEvents.Error, (err) => { - * console.error("WebSocket Error:", err.message); - * - * // Access HTTP status code (e.g., 502, 403, etc.) - * if (err.statusCode) { - * console.error(`HTTP Status Code: ${err.statusCode}`); - * } - * - * // Access Deepgram request ID for support tickets - * if (err.requestId) { - * console.error(`Deepgram Request ID: ${err.requestId}`); - * } - * - * // Access WebSocket URL and connection state - * if (err.url) { - * console.error(`WebSocket URL: ${err.url}`); - * } - * - * if (err.readyState !== undefined) { - * const stateNames = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; - * console.error(`Connection State: ${stateNames[err.readyState]}`); - * } - * - * // Access response headers for additional debugging - * if (err.responseHeaders) { - * console.error("Response Headers:", err.responseHeaders); - * } - * - * // Access the enhanced error object for detailed debugging - * if (err.error?.name === 'DeepgramWebSocketError') { - * console.error("Enhanced Error Details:", err.error.toJSON()); - * } - * }); - * ``` - * - * @param event - The error event from the WebSocket - * @param conn - The WebSocket connection object - * @returns Enhanced error information object - */ - protected extractErrorInformation( - event: ErrorEvent | Event, - conn?: WebSocketLike - ): { - statusCode?: number; - requestId?: string; - responseHeaders?: Record; - url?: string; - readyState?: number; - } { - const errorInfo: { - statusCode?: number; - requestId?: string; - responseHeaders?: Record; - url?: string; - readyState?: number; - } = {}; - - // Extract basic connection information - if (conn) { - errorInfo.readyState = conn.readyState; - errorInfo.url = typeof conn.url === "string" ? conn.url : conn.url?.toString(); - } - - // Try to extract additional information from the WebSocket connection - // This works with the 'ws' package which exposes more detailed error information - if (conn && typeof conn === "object") { - const wsConn = conn as any; - - // Extract status code if available (from 'ws' package) - if (wsConn._req && wsConn._req.res) { - errorInfo.statusCode = wsConn._req.res.statusCode; - - // Extract response headers if available - if (wsConn._req.res.headers) { - errorInfo.responseHeaders = { ...wsConn._req.res.headers }; - - // Extract request ID from Deepgram response headers - const requestId = - wsConn._req.res.headers["dg-request-id"] || wsConn._req.res.headers["x-dg-request-id"]; - if (requestId) { - errorInfo.requestId = requestId; - } - } - } - - // For native WebSocket, try to extract information from the event - if (event && "target" in event && event.target) { - const target = event.target as any; - if (target.url) { - errorInfo.url = target.url; - } - if (target.readyState !== undefined) { - errorInfo.readyState = target.readyState; - } - } - } - - return errorInfo; - } - - /** - * Creates an enhanced error object with additional debugging information. - * This method provides backward compatibility by including both the original - * error event and enhanced error information. - * - * @param event - The original error event - * @param enhancedInfo - Additional error information extracted from the connection - * @returns An object containing both original and enhanced error information - */ - protected createEnhancedError( - event: ErrorEvent | Event, - enhancedInfo: { - statusCode?: number; - requestId?: string; - responseHeaders?: Record; - url?: string; - readyState?: number; - } - ) { - // Create the enhanced error for detailed debugging - const enhancedError = new DeepgramWebSocketError( - (event as ErrorEvent).message || "WebSocket connection error", - { - originalEvent: event, - ...enhancedInfo, - } - ); - - // Return an object that maintains backward compatibility - // while providing enhanced information - return { - // Original event for backward compatibility - ...event, - // Enhanced error information - error: enhancedError, - // Additional fields for easier access - statusCode: enhancedInfo.statusCode, - requestId: enhancedInfo.requestId, - responseHeaders: enhancedInfo.responseHeaders, - url: enhancedInfo.url, - readyState: enhancedInfo.readyState, - // Enhanced message with more context - message: this.buildEnhancedErrorMessage(event, enhancedInfo), - }; - } - - /** - * Builds an enhanced error message with additional context information. - * - * @param event - The original error event - * @param enhancedInfo - Additional error information - * @returns A more descriptive error message - */ - protected buildEnhancedErrorMessage( - event: ErrorEvent | Event, - enhancedInfo: { - statusCode?: number; - requestId?: string; - responseHeaders?: Record; - url?: string; - readyState?: number; - } - ): string { - let message = (event as ErrorEvent).message || "WebSocket connection error"; - - const details: string[] = []; - - if (enhancedInfo.statusCode) { - details.push(`Status: ${enhancedInfo.statusCode}`); - } - - if (enhancedInfo.requestId) { - details.push(`Request ID: ${enhancedInfo.requestId}`); - } - - if (enhancedInfo.readyState !== undefined) { - const stateNames = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; - const stateName = - stateNames[enhancedInfo.readyState] || `Unknown(${enhancedInfo.readyState})`; - details.push(`Ready State: ${stateName}`); - } - - if (enhancedInfo.url) { - details.push(`URL: ${enhancedInfo.url}`); - } - - if (details.length > 0) { - message += ` (${details.join(", ")})`; - } - - return message; - } - - /** - * Sets up the standard connection event handlers (open, close, error) for WebSocket connections. - * This method abstracts the common connection event registration pattern used across all live clients. - * - * @param events - Object containing the event constants for the specific client type - * @param events.Open - Event constant for connection open - * @param events.Close - Event constant for connection close - * @param events.Error - Event constant for connection error - * @protected - */ - protected setupConnectionEvents(events: { Open: string; Close: string; Error: string }): void { - if (this.conn) { - this.conn.onopen = () => { - this.emit(events.Open, this); - }; - - this.conn.onclose = (event: any) => { - this.emit(events.Close, event); - }; - - this.conn.onerror = (event: ErrorEvent) => { - const enhancedInfo = this.extractErrorInformation(event, this.conn || undefined); - const enhancedError = this.createEnhancedError(event, enhancedInfo); - this.emit(events.Error, enhancedError); - }; - } - } - - /** - * Sets up the connection event handlers. - * - * @abstract Requires subclasses to set up context aware event handlers. - */ - abstract setupConnection(): void; -} - -class WSWebSocketDummy { - binaryType: string = "arraybuffer"; - close: Function; - onclose: Function = () => { }; - onerror: Function = () => { }; - onmessage: Function = () => { }; - onopen: Function = () => { }; - readyState: number = SOCKET_STATES.connecting; - send: Function = () => { }; - url: string | URL | null = null; - - constructor(address: URL, _protocols: undefined, options: { close: Function }) { - this.url = address.toString(); - this.close = options.close; - } -} - -export { AbstractLiveClient as AbstractWsClient }; diff --git a/src/packages/AbstractRestClient.ts b/src/packages/AbstractRestClient.ts deleted file mode 100644 index d36e92aa..00000000 --- a/src/packages/AbstractRestClient.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { DeepgramApiError, DeepgramError, DeepgramUnknownError } from "../lib/errors"; -import type { Readable } from "node:stream"; -import { fetchWithAuth, resolveResponse } from "../lib/fetch"; -import type { Fetch, FetchOptions, RequestMethodType } from "../lib/types/Fetch"; -import { AbstractClient } from "./AbstractClient"; -import { DeepgramClientOptions } from "../lib/types"; -import { isBrowser } from "../lib/runtime"; -import merge from "deepmerge"; - -/** - * An abstract class that extends `AbstractClient` and provides a base implementation for a REST-based API client. - * This class handles authentication, error handling, and other common functionality for REST API clients. - */ -export abstract class AbstractRestClient extends AbstractClient { - protected fetch: Fetch; - - /** - * Constructs a new instance of the `AbstractRestClient` class with the provided options. - * - * @param options - The client options to use for this instance. - * @throws {DeepgramError} If the client is being used in a browser and no proxy is provided. - */ - constructor(options: DeepgramClientOptions) { - super(options); - - if (isBrowser() && !this.proxy) { - throw new DeepgramError( - "Due to CORS we are unable to support REST-based API calls to our API from the browser. Please consider using a proxy: https://dpgr.am/js-proxy for more information." - ); - } - - const { accessToken, key: apiKey, fetch: customFetch } = this; - - this.fetch = fetchWithAuth({ accessToken, apiKey, customFetch }); - - if (this.proxy) { - this.baseUrl = this.namespaceOptions.fetch.options.proxy!.url; - } else { - this.baseUrl = this.namespaceOptions.fetch.options.url; - } - } - - /** - * Constructs an error message from the provided error object. - * - * @param err - The error object to extract the error message from. - * @returns The constructed error message. - */ - protected _getErrorMessage(err: any): string { - return err.msg || err.message || err.error_description || err.error || JSON.stringify(err); - } - - /** - * Handles an error that occurred during a request. - * - * @param error - The error that occurred during the request. - * @param reject - The rejection function to call with the error. - * @returns A Promise that resolves when the error has been handled. - */ - protected async _handleError(error: unknown, reject: (reason?: any) => void) { - const Res = await resolveResponse(); - - if (error instanceof Res) { - error - .json() - .then((err) => { - reject(new DeepgramApiError(this._getErrorMessage(err), error.status || 500)); - }) - .catch((err) => { - reject(new DeepgramUnknownError(this._getErrorMessage(err), err)); - }); - } else { - reject(new DeepgramUnknownError(this._getErrorMessage(error), error)); - } - } - - /** - * Constructs the options object to be used for a fetch request. - * - * @param method - The HTTP method to use for the request, such as "GET", "POST", "PUT", "PATCH", or "DELETE". - * @param bodyOrOptions - For "POST", "PUT", and "PATCH" requests, the request body as a string, Buffer, or Readable stream. For "GET" and "DELETE" requests, the fetch options to use. - * @param options - Additional fetch options to use for the request. - * @returns The constructed fetch options object. - */ - protected _getRequestOptions( - method: RequestMethodType, - bodyOrOptions?: string | Buffer | Readable | FetchOptions, - options?: FetchOptions - ): FetchOptions { - let reqOptions: FetchOptions = { method }; - - if (method === "GET" || method === "DELETE") { - reqOptions = { ...reqOptions, ...(bodyOrOptions as FetchOptions) }; - } else { - reqOptions = { - duplex: "half", - body: bodyOrOptions as BodyInit, - ...reqOptions, - ...options, - }; - } - - return merge(this.namespaceOptions.fetch.options, reqOptions, { clone: false }); - } - - /** - * Handles an HTTP request using the provided method, URL, and optional request body and options. - * - * @param method - The HTTP method to use for the request, such as "GET", "POST", "PUT", "PATCH", or "DELETE". - * @param url - The URL to send the request to. - * @param bodyOrOptions - For "POST", "PUT", and "PATCH" requests, the request body as a string, Buffer, or Readable stream. For "GET" and "DELETE" requests, the fetch options to use. - * @param options - Additional fetch options to use for the request. - * @returns A Promise that resolves to the Response object for the request. - */ - protected async _handleRequest( - method: "GET" | "DELETE", - url: URL, - options?: FetchOptions - ): Promise; - protected async _handleRequest( - method: "POST" | "PUT" | "PATCH", - url: URL, - body: string | Buffer | Readable, - options?: FetchOptions - ): Promise; - protected async _handleRequest( - method: RequestMethodType, - url: URL, - bodyOrOptions?: string | Buffer | Readable | FetchOptions, - options?: FetchOptions - ): Promise { - return new Promise((resolve, reject) => { - const fetcher = this.fetch; - - fetcher(url, this._getRequestOptions(method, bodyOrOptions, options)) - .then((result) => { - if (!result.ok) throw result; - resolve(result); - }) - .catch((error) => this._handleError(error, reject)); - }); - } - - /** - * Handles an HTTP GET request using the provided URL and optional request options. - * - * @param url - The URL to send the GET request to. - * @param options - Additional fetch options to use for the GET request. - * @returns A Promise that resolves to the Response object for the GET request. - */ - protected async get(url: URL, options?: FetchOptions): Promise { - return this._handleRequest("GET", url, options); - } - - /** - * Handles an HTTP POST request using the provided URL, request body, and optional request options. - * - * @param url - The URL to send the POST request to. - * @param body - The request body as a string, Buffer, or Readable stream. - * @param options - Additional fetch options to use for the POST request. - * @returns A Promise that resolves to the Response object for the POST request. - */ - protected async post( - url: URL, - body: string | Buffer | Readable, - options?: FetchOptions - ): Promise { - return this._handleRequest("POST", url, body, options); - } - - /** - * Handles an HTTP PUT request using the provided URL, request body, and optional request options. - * - * @param url - The URL to send the PUT request to. - * @param body - The request body as a string, Buffer, or Readable stream. - * @param options - Additional fetch options to use for the PUT request. - * @returns A Promise that resolves to the Response object for the PUT request. - */ - protected async put( - url: URL, - body: string | Buffer | Readable, - options?: FetchOptions - ): Promise { - return this._handleRequest("PUT", url, body, options); - } - - /** - * Handles an HTTP PATCH request using the provided URL, request body, and optional request options. - * - * @param url - The URL to send the PATCH request to. - * @param body - The request body as a string, Buffer, or Readable stream. - * @param options - Additional fetch options to use for the PATCH request. - * @returns A Promise that resolves to the Response object for the PATCH request. - */ - protected async patch( - url: URL, - body: string | Buffer | Readable, - options?: FetchOptions - ): Promise { - return this._handleRequest("PATCH", url, body, options); - } - - /** - * Handles an HTTP DELETE request using the provided URL and optional request options. - * - * @param url - The URL to send the DELETE request to. - * @param options - Additional fetch options to use for the DELETE request. - * @returns A Promise that resolves to the Response object for the DELETE request. - */ - protected async delete(url: URL, options?: FetchOptions): Promise { - return this._handleRequest("DELETE", url, options); - } - - /** - * Determines whether the current instance should proxy requests. - * @returns {boolean} true if the current instance should proxy requests; otherwise, false - */ - get proxy(): boolean { - return this.key === "proxy" && !!this.namespaceOptions.fetch.options.proxy?.url; - } -} - -export { AbstractRestClient as AbstractRestfulClient }; diff --git a/src/packages/AgentLiveClient.ts b/src/packages/AgentLiveClient.ts deleted file mode 100644 index 59d9b1f8..00000000 --- a/src/packages/AgentLiveClient.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { DEFAULT_AGENT_URL } from "../lib/constants"; -import { AgentEvents } from "../lib/enums/AgentEvents"; -import type { AgentLiveSchema, DeepgramClientOptions, FunctionCallResponse } from "../lib/types"; -import { AbstractLiveClient } from "./AbstractLiveClient"; - -export class AgentLiveClient extends AbstractLiveClient { - public namespace: string = "agent"; - - constructor(options: DeepgramClientOptions, endpoint: string = "/:version/agent/converse") { - super(options); - this.baseUrl = options.agent?.websocket?.options?.url ?? DEFAULT_AGENT_URL; - - this.connect({}, endpoint); - } - - /** - * Sets up the connection event handlers. - * This method is responsible for handling the various events that can occur on the WebSocket connection, such as opening, closing, and receiving messages. - * - When the connection is opened, it emits the `AgentEvents.Open` event. - * - When the connection is closed, it emits the `AgentEvents.Close` event. - * - When an error occurs on the connection, it emits the `AgentEvents.Error` event. - * - When a message is received, it parses the message and emits the appropriate event based on the message type. - */ - public setupConnection(): void { - // Set up standard connection events (open, close, error) using abstracted method - this.setupConnectionEvents({ - Open: AgentEvents.Open, - Close: AgentEvents.Close, - Error: AgentEvents.Error, - }); - - // Set up message handling specific to agent conversations - if (this.conn) { - this.conn.onmessage = (event: MessageEvent) => { - this.handleMessage(event); - }; - } - } - - /** - * Handles incoming messages from the WebSocket connection. - * @param event - The MessageEvent object representing the received message. - */ - protected handleMessage(event: MessageEvent): void { - if (typeof event.data === "string") { - try { - const data = JSON.parse(event.data); - this.handleTextMessage(data); - } catch (error) { - this.emit(AgentEvents.Error, { - event, - data: - event.data?.toString().substring(0, 200) + - (event.data?.toString().length > 200 ? "..." : ""), - message: "Unable to parse `data` as JSON.", - error, - url: this.conn?.url, - readyState: this.conn?.readyState, - }); - } - } else if (event.data instanceof Blob) { - event.data.arrayBuffer().then((buffer) => { - this.handleBinaryMessage(Buffer.from(buffer)); - }); - } else if (event.data instanceof ArrayBuffer) { - this.handleBinaryMessage(Buffer.from(event.data)); - } else if (Buffer.isBuffer(event.data)) { - this.handleBinaryMessage(event.data); - } else { - console.log("Received unknown data type", event.data); - this.emit(AgentEvents.Error, { - event, - message: "Received unknown data type.", - url: this.conn?.url, - readyState: this.conn?.readyState, - dataType: typeof event.data, - }); - } - } - - /** - * Handles binary messages received from the WebSocket connection. - * @param data - The binary data. - */ - protected handleBinaryMessage(data: Buffer): void { - this.emit(AgentEvents.Audio, data); - } - - /** - * Handles text messages received from the WebSocket connection. - * @param data - The parsed JSON data. - */ - protected handleTextMessage(data: any): void { - if (data.type in AgentEvents) { - this.emit(data.type, data); - } else { - this.emit(AgentEvents.Unhandled, data); - } - } - - /** - * To be called with your model configuration BEFORE sending - * any audio data. - * @param options - The SettingsConfiguration object. - */ - public configure(options: AgentLiveSchema): void { - const string = JSON.stringify({ - type: "Settings", - ...options, - }); - this.send(string); - } - - /** - * Provide new system prompt to the LLM. - * @param prompt - The system prompt to provide. - */ - public updatePrompt(prompt: string): void { - this.send(JSON.stringify({ type: "UpdatePrompt", prompt })); - } - - /** - * Change the speak model. - * @param model - The new model to use. - */ - public updateSpeak(speakConfig: Exclude): void { - this.send(JSON.stringify({ type: "UpdateSpeak", speak: speakConfig })); - } - - /** - * Immediately trigger an agent message. If this message - * is sent while the user is speaking, or while the server is in the - * middle of sending audio, then the request will be ignored and an InjectionRefused - * event will be emitted. - * @example "Hold on while I look that up for you." - * @example "Are you still on the line?" - * @param content - The message to speak. - */ - public injectAgentMessage(content: string): void { - this.send(JSON.stringify({ type: "InjectAgentMessage", content })); - } - - /** - * Send a text-based message to the agent as if it came from the user. - * This allows you to inject user messages into the conversation for the agent to respond to. - * @example "Hello! Can you hear me?" - * @example "What's the weather like today?" - * @param content - The specific phrase or statement the agent should respond to. - */ - public injectUserMessage(content: string): void { - this.send(JSON.stringify({ type: "InjectUserMessage", content })); - } - - /** - * Respond to a function call request. - * @param response - The response to the function call request. - */ - public functionCallResponse(response: FunctionCallResponse): void { - this.send(JSON.stringify({ type: "FunctionCallResponse", ...response })); - } - - /** - * Send a keepalive to avoid closing the websocket while you - * are not transmitting audio. This should be sent at least - * every 8 seconds. - */ - public keepAlive(): void { - this.send(JSON.stringify({ type: "KeepAlive" })); - } -} diff --git a/src/packages/AuthRestClient.ts b/src/packages/AuthRestClient.ts deleted file mode 100644 index 1f74c1fd..00000000 --- a/src/packages/AuthRestClient.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { isDeepgramError } from "../lib/errors"; -import type { DeepgramResponse } from "../lib/types/DeepgramResponse"; -import type { GrantTokenResponse } from "../lib/types/GrantTokenResponse"; -import type { GrantTokenSchema } from "../lib/types/GrantTokenSchema"; -import { AbstractRestClient } from "./AbstractRestClient"; - -export class AuthRestClient extends AbstractRestClient { - public namespace: string = "auth"; - - /** - * Generates a new temporary token for the Deepgram API. - * @param options Optional configuration options for the token generation. Includes ttl_seconds to set token expiration. - * @param endpoint Optional custom endpoint to use for the request. Defaults to ":version/auth/grant". - * @returns Object containing the result of the request or an error if one occurred. Result will contain access_token and expires_in properties. - */ - public async grantToken( - options: GrantTokenSchema = {}, - endpoint = ":version/auth/grant" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint); - const body = JSON.stringify(options); - const result: GrantTokenResponse = await this.post(requestUrl, body, { - headers: { "Content-Type": "application/json" }, - }).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } -} diff --git a/src/packages/ListenClient.ts b/src/packages/ListenClient.ts deleted file mode 100644 index 9473cdff..00000000 --- a/src/packages/ListenClient.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AbstractClient } from "./AbstractClient"; -import { ListenLiveClient } from "./ListenLiveClient"; -import { ListenRestClient } from "./ListenRestClient"; -import { LiveSchema } from "../lib/types"; - -/** - * The `ListenClient` class extends the `AbstractClient` class and provides access to the "listen" namespace. - * It exposes two methods: - * - * 1. `prerecorded()`: Returns a `ListenRestClient` instance for interacting with the prerecorded listen API. - * 2. `live(transcriptionOptions: LiveSchema = {}, endpoint = ":version/listen")`: Returns a `ListenLiveClient` instance for interacting with the live listen API, with the provided transcription options and endpoint. - */ -export class ListenClient extends AbstractClient { - public namespace: string = "listen"; - - /** - * Returns a `ListenRestClient` instance for interacting with the prerecorded listen API. - */ - get prerecorded() { - return new ListenRestClient(this.options); - } - - /** - * Returns a `ListenLiveClient` instance for interacting with the live listen API, with the provided transcription options and endpoint. - * @param {LiveSchema} [transcriptionOptions={}] - The transcription options to use for the live listen API. - * @param {string} [endpoint=":version/listen"] - The endpoint to use for the live listen API. - * @returns {ListenLiveClient} - A `ListenLiveClient` instance for interacting with the live listen API. - */ - public live( - transcriptionOptions: LiveSchema = {}, - endpoint: string = ":version/listen" - ): ListenLiveClient { - return new ListenLiveClient(this.options, transcriptionOptions, endpoint); - } -} diff --git a/src/packages/ListenLiveClient.ts b/src/packages/ListenLiveClient.ts deleted file mode 100644 index a5f39670..00000000 --- a/src/packages/ListenLiveClient.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { AbstractLiveClient } from "./AbstractLiveClient"; -import { LiveTranscriptionEvents } from "../lib/enums"; -import type { LiveSchema, LiveConfigOptions, DeepgramClientOptions } from "../lib/types"; -import { DeepgramError } from "../lib/errors"; - -/** - * The `ListenLiveClient` class extends the `AbstractLiveClient` class and provides functionality for setting up and managing a WebSocket connection for live transcription. - * - * The constructor takes in `DeepgramClientOptions` and an optional `LiveSchema` object, as well as an optional `endpoint` string. It then calls the `connect` method of the parent `AbstractLiveClient` class to establish the WebSocket connection. - * - * The `setupConnection` method is responsible for handling the various events that can occur on the WebSocket connection, such as opening, closing, and receiving messages. It sets up event handlers for these events and emits the appropriate events based on the message type. - * - * The `configure` method allows you to send additional configuration options to the connected session, such as enabling numerals. - * - * The `keepAlive` method sends a "KeepAlive" message to the server to maintain the connection. - * - * The `requestClose` method requests the server to close the connection. - * - * The `finish` method is deprecated as of version 3.4 and will be removed in version 4.0. Use `requestClose` instead. - */ -export class ListenLiveClient extends AbstractLiveClient { - public namespace: string = "listen"; - - /** - * Constructs a new `ListenLiveClient` instance with the provided options. - * - * @param options - The `DeepgramClientOptions` to use for the client connection. - * @param transcriptionOptions - An optional `LiveSchema` object containing additional configuration options for the live transcription. - * @param endpoint - An optional string representing the WebSocket endpoint to connect to. Defaults to `:version/listen`. - */ - constructor( - options: DeepgramClientOptions, - transcriptionOptions: LiveSchema = {}, - endpoint: string = ":version/listen" - ) { - super(options); - - if (transcriptionOptions.keyterm?.length && !transcriptionOptions.model?.startsWith("nova-3")) { - throw new DeepgramError("Keyterms are only supported with the Nova 3 models."); - } - - this.connect(transcriptionOptions, endpoint); - } - - /** - * Sets up the connection event handlers. - * This method is responsible for handling the various events that can occur on the WebSocket connection, such as opening, closing, and receiving messages. - * - When the connection is opened, it emits the `LiveTranscriptionEvents.Open` event. - * - When the connection is closed, it emits the `LiveTranscriptionEvents.Close` event. - * - When an error occurs on the connection, it emits the `LiveTranscriptionEvents.Error` event. - * - When a message is received, it parses the message and emits the appropriate event based on the message type, such as `LiveTranscriptionEvents.Metadata`, `LiveTranscriptionEvents.Transcript`, `LiveTranscriptionEvents.UtteranceEnd`, and `LiveTranscriptionEvents.SpeechStarted`. - */ - public setupConnection(): void { - // Set up standard connection events (open, close, error) using abstracted method - this.setupConnectionEvents({ - Open: LiveTranscriptionEvents.Open, - Close: LiveTranscriptionEvents.Close, - Error: LiveTranscriptionEvents.Error, - }); - - // Set up message handling specific to transcription - if (this.conn) { - this.conn.onmessage = (event: MessageEvent) => { - try { - const data: any = JSON.parse(event.data.toString()); - - if (data.type === LiveTranscriptionEvents.Metadata) { - this.emit(LiveTranscriptionEvents.Metadata, data); - } else if (data.type === LiveTranscriptionEvents.Transcript) { - this.emit(LiveTranscriptionEvents.Transcript, data); - } else if (data.type === LiveTranscriptionEvents.UtteranceEnd) { - this.emit(LiveTranscriptionEvents.UtteranceEnd, data); - } else if (data.type === LiveTranscriptionEvents.SpeechStarted) { - this.emit(LiveTranscriptionEvents.SpeechStarted, data); - } else { - this.emit(LiveTranscriptionEvents.Unhandled, data); - } - } catch (error) { - this.emit(LiveTranscriptionEvents.Error, { - event, - message: "Unable to parse `data` as JSON.", - error, - url: this.conn?.url, - readyState: this.conn?.readyState, - data: - event.data?.toString().substring(0, 200) + - (event.data?.toString().length > 200 ? "..." : ""), - }); - } - }; - } - } - - /** - * Sends additional config to the connected session. - * - * @param config - The configuration options to apply to the LiveClient. - * @param config.numerals - We currently only support numerals. - */ - public configure(config: LiveConfigOptions): void { - this.send( - JSON.stringify({ - type: "Configure", - processors: config, - }) - ); - } - - /** - * Sends a "KeepAlive" message to the server to maintain the connection. - */ - public keepAlive(): void { - this.send( - JSON.stringify({ - type: "KeepAlive", - }) - ); - } - - /** - * Sends a "Finalize" message to flush any transcription sitting in the server's buffer. - */ - public finalize(): void { - this.send( - JSON.stringify({ - type: "Finalize", - }) - ); - } - - /** - * @deprecated Since version 3.4. Will be removed in version 4.0. Use `requestClose` instead. - */ - public finish(): void { - this.requestClose(); - } - - /** - * Requests the server close the connection. - */ - public requestClose(): void { - this.send( - JSON.stringify({ - type: "CloseStream", - }) - ); - } -} - -export { ListenLiveClient as LiveClient }; diff --git a/src/packages/ListenRestClient.ts b/src/packages/ListenRestClient.ts deleted file mode 100644 index 754d7aad..00000000 --- a/src/packages/ListenRestClient.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { CallbackUrl, isFileSource, isUrlSource } from "../lib/helpers"; -import { DeepgramError, isDeepgramError } from "../lib/errors"; -import type { - AsyncPrerecordedResponse, - DeepgramResponse, - FileSource, - PrerecordedSchema, - SyncPrerecordedResponse, - UrlSource, -} from "../lib/types"; -import { AbstractRestClient } from "./AbstractRestClient"; - -/** - * The `ListenRestClient` class extends the `AbstractRestClient` class and provides methods for transcribing audio from URLs or files using the Deepgram API. - * - * The `transcribeUrl` method is used to transcribe audio from a URL synchronously. It takes a `UrlSource` object as the source, an optional `PrerecordedSchema` object as options, and an optional endpoint string. It returns a `DeepgramResponse` object containing the transcription result or an error. - * - * The `transcribeFile` method is used to transcribe audio from a file synchronously. It takes a `FileSource` object as the source, an optional `PrerecordedSchema` object as options, and an optional endpoint string. It returns a `DeepgramResponse` object containing the transcription result or an error. - * - * The `transcribeUrlCallback` method is used to transcribe audio from a URL asynchronously. It takes a `UrlSource` object as the source, a `CallbackUrl` object as the callback, an optional `PrerecordedSchema` object as options, and an optional endpoint string. It returns a `DeepgramResponse` object containing the transcription result or an error. - * - * The `transcribeFileCallback` method is used to transcribe audio from a file asynchronously. It takes a `FileSource` object as the source, a `CallbackUrl` object as the callback, an optional `PrerecordedSchema` object as options, and an optional endpoint string. It returns a `DeepgramResponse` object containing the transcription result or an error. - */ -export class ListenRestClient extends AbstractRestClient { - public namespace: string = "listen"; - - /** - * Transcribes audio from a URL synchronously. - * - * @param source - The URL source object containing the audio URL to transcribe. - * @param options - An optional `PrerecordedSchema` object containing additional options for the transcription. - * @param endpoint - An optional endpoint string to use for the transcription request. - * @returns A `DeepgramResponse` object containing the transcription result or an error. - */ - async transcribeUrl( - source: UrlSource, - options?: PrerecordedSchema, - endpoint = ":version/listen" - ): Promise> { - try { - let body; - - if (isUrlSource(source)) { - body = JSON.stringify(source); - } else { - throw new DeepgramError("Unknown transcription source type"); - } - - if (options !== undefined && "callback" in options) { - throw new DeepgramError( - "Callback cannot be provided as an option to a synchronous transcription. Use `transcribeUrlCallback` or `transcribeFileCallback` instead." - ); - } - - if (options?.keyterm?.length && !options.model?.startsWith("nova-3")) { - throw new DeepgramError("Keyterms are only supported with the Nova 3 models."); - } - - const requestUrl = this.getRequestUrl(endpoint, {}, { ...{}, ...options }); - const result: SyncPrerecordedResponse = await this.post(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Transcribes audio from a file asynchronously. - * - * @param source - The file source object containing the audio file to transcribe. - * @param options - An optional `PrerecordedSchema` object containing additional options for the transcription. - * @param endpoint - An optional endpoint string to use for the transcription request. - * @returns A `DeepgramResponse` object containing the transcription result or an error. - */ - async transcribeFile( - source: FileSource, - options?: PrerecordedSchema, - endpoint = ":version/listen" - ): Promise> { - try { - let body; - - if (isFileSource(source)) { - body = source; - } else { - throw new DeepgramError("Unknown transcription source type"); - } - - if (options !== undefined && "callback" in options) { - throw new DeepgramError( - "Callback cannot be provided as an option to a synchronous transcription. Use `transcribeUrlCallback` or `transcribeFileCallback` instead." - ); - } - - const requestUrl = this.getRequestUrl(endpoint, {}, { ...{}, ...options }); - const result: SyncPrerecordedResponse = await this.post(requestUrl, body, { - headers: { "Content-Type": "deepgram/audio+video" }, - }).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Transcribes audio from a URL asynchronously. - * - * @param source - The URL source object containing the audio file to transcribe. - * @param callback - The callback URL to receive the transcription result. - * @param options - An optional `PrerecordedSchema` object containing additional options for the transcription. - * @param endpoint - An optional endpoint string to use for the transcription request. - * @returns A `DeepgramResponse` object containing the transcription result or an error. - */ - async transcribeUrlCallback( - source: UrlSource, - callback: CallbackUrl, - options?: PrerecordedSchema, - endpoint = ":version/listen" - ): Promise> { - try { - let body; - - if (isUrlSource(source)) { - body = JSON.stringify(source); - } else { - throw new DeepgramError("Unknown transcription source type"); - } - - const requestUrl = this.getRequestUrl( - endpoint, - {}, - { ...options, callback: callback.toString() } - ); - const result: AsyncPrerecordedResponse = await this.post(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Transcribes audio from a file asynchronously. - * - * @param source - The file source object containing the audio file to transcribe. - * @param callback - The callback URL to receive the transcription result. - * @param options - An optional `PrerecordedSchema` object containing additional options for the transcription. - * @param endpoint - An optional endpoint string to use for the transcription request. - * @returns A `DeepgramResponse` object containing the transcription result or an error. - */ - async transcribeFileCallback( - source: FileSource, - callback: CallbackUrl, - options?: PrerecordedSchema, - endpoint = ":version/listen" - ): Promise> { - try { - let body; - - if (isFileSource(source)) { - body = source; - } else { - throw new DeepgramError("Unknown transcription source type"); - } - - const requestUrl = this.getRequestUrl( - endpoint, - {}, - { ...options, callback: callback.toString() } - ); - const result: AsyncPrerecordedResponse = await this.post(requestUrl, body, { - headers: { "Content-Type": "deepgram/audio+video" }, - }).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } -} - -export { ListenRestClient as PrerecordedClient }; diff --git a/src/packages/ManageRestClient.ts b/src/packages/ManageRestClient.ts deleted file mode 100644 index 812c24c8..00000000 --- a/src/packages/ManageRestClient.ts +++ /dev/null @@ -1,814 +0,0 @@ -import { isDeepgramError } from "../lib/errors"; -import type { - CreateProjectKeySchema, - CreateProjectKeyResponse, - DeepgramResponse, - GetProjectBalanceResponse, - GetProjectBalancesResponse, - GetProjectInvitesResponse, - GetProjectKeyResponse, - GetProjectKeysResponse, - GetProjectMemberScopesResponse, - GetProjectMembersResponse, - GetProjectResponse, - GetProjectsResponse, - GetProjectUsageFieldsSchema, - GetProjectUsageFieldsResponse, - GetProjectUsageRequestResponse, - GetProjectUsageRequestsSchema, - GetProjectUsageRequestsResponse, - GetProjectUsageSummarySchema, - GetProjectUsageSummaryResponse, - MessageResponse, - SendProjectInviteSchema, - UpdateProjectMemberScopeSchema, - UpdateProjectSchema, - VoidResponse, - GetTokenDetailsResponse, - GetModelsResponse, - GetModelResponse, - GetModelsSchema, -} from "../lib/types"; -import { AbstractRestClient } from "./AbstractRestClient"; - -/** - * The `ManageRestClient` class provides a set of methods for interacting with the Deepgram Manage API. It extends the `AbstractRestClient` class and provides functionality for managing projects, keys, members, invites, usage, balances, and models. - * - * The class has a `namespace` property that is set to `"manage"`, which is used in the construction of the request URLs. - * - * The methods in this class include: - * - `getTokenDetails`: Retrieves the details of the current authentication token. - * - `getProjects`: Retrieves a list of all projects associated with the authenticated account. - * - `getProject`: Retrieves the details of a specific project. - * - `updateProject`: Updates the details of a specific project. - * - `deleteProject`: Deletes a specific project. - * - `getProjectKeys`: Retrieves a list of all API keys associated with a specific project. - * - `getProjectKey`: Retrieves the details of a specific API key. - * - `createProjectKey`: Creates a new API key for a specific project. - * - `deleteProjectKey`: Deletes a specific API key. - * - `getProjectMembers`: Retrieves a list of all members associated with a specific project. - * - `removeProjectMember`: Removes a specific member from a project. - * - `getProjectMemberScopes`: Retrieves the scopes associated with a specific project member. - * - `updateProjectMemberScope`: Updates the scopes associated with a specific project member. - * - `getProjectInvites`: Retrieves a list of all pending invitations for a specific project. - * - `sendProjectInvite`: Sends a new invitation to a specific email address for a project. - * - `deleteProjectInvite`: Deletes a specific invitation for a project. - * - `leaveProject`: Removes the authenticated user from a specific project. - * - `getProjectUsageRequests`: Retrieves a list of all usage requests for a specific project. - * - `getProjectUsageRequest`: Retrieves the details of a specific usage request. - * - `getProjectUsageSummary`: Retrieves a summary of the usage for a specific project. - * - `getProjectUsageFields`: Retrieves a list of the available usage fields for a specific project. - * - `getProjectBalances`: Retrieves a list of all balances associated with a specific project. - * - `getProjectBalance`: Retrieves the details of a specific balance for a project. - * - `getAllModels`: Retrieves all models for a project. - * - `getModel`: Retrieves a specific model. - */ -export class ManageRestClient extends AbstractRestClient { - public namespace: string = "manage"; - - /** - * Retrieves the details of the current authentication token. - * - * @returns A promise that resolves to an object containing the token details, or an error object if an error occurs. - * @see https://developers.deepgram.com/docs/authenticating#test-request - */ - async getTokenDetails( - endpoint = ":version/auth/token" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint); - const result: GetTokenDetailsResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves a list of all projects associated with the authenticated user. - * - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects". - * @returns A promise that resolves to an object containing the list of projects, or an error object if an error occurs. - * @see https://developers.deepgram.com/reference/get-projects - */ - async getProjects( - endpoint = ":version/projects" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint); - const result: GetProjectsResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves the details of a specific project associated with the authenticated user. - * - * @param projectId - The ID of the project to retrieve. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId". - * @returns A promise that resolves to an object containing the project details, or an error object if an error occurs. - * @see https://developers.deepgram.com/reference/get-project - */ - async getProject( - projectId: string, - endpoint = ":version/projects/:projectId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - const result: GetProjectResponse = await this.get(requestUrl).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Updates an existing project associated with the authenticated user. - * - * @param projectId - The ID of the project to update. - * @param options - An object containing the updated project details. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId". - * @returns A promise that resolves to an object containing the response message, or an error object if an error occurs. - * @see https://developers.deepgram.com/reference/update-project - */ - async updateProject( - projectId: string, - options: UpdateProjectSchema, - endpoint = ":version/projects/:projectId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }, options); - const body = JSON.stringify(options); - - const result: MessageResponse = await this.patch(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Deletes an existing project associated with the authenticated user. - * - * @param projectId - The ID of the project to delete. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId". - * @returns A promise that resolves to an object containing the response message, or an error object if an error occurs. - * @see https://developers.deepgram.com/reference/delete-project - */ - async deleteProject( - projectId: string, - endpoint = ":version/projects/:projectId" - ): Promise { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - await this.delete(requestUrl); - - return { error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { error }; - } - - throw error; - } - } - - /** - * Retrieves a list of project keys associated with the specified project. - * - * @param projectId - The ID of the project to retrieve the keys for. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/keys". - * @returns A promise that resolves to an object containing the list of project keys, or an error object if an error occurs. - * @see https://developers.deepgram.com/reference/list-keys - */ - async getProjectKeys( - projectId: string, - endpoint = ":version/projects/:projectId/keys" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - const result: GetProjectKeysResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves a specific project key associated with the specified project. - * - * @param projectId - The ID of the project to retrieve the key for. - * @param keyId - The ID of the project key to retrieve. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/keys/:keyId". - * @returns A promise that resolves to an object containing the project key, or an error object if an error occurs. - * @see https://developers.deepgram.com/reference/get-key - */ - async getProjectKey( - projectId: string, - keyId: string, - endpoint = ":version/projects/:projectId/keys/:keyId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, keyId }); - const result: GetProjectKeyResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Creates a new project key for the specified project. - * - * @param projectId - The ID of the project to create the key for. - * @param options - An object containing the options for creating the project key. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/keys". - * @returns A promise that resolves to an object containing the created project key, or an error object if an error occurs. - * @see https://developers.deepgram.com/reference/create-key - */ - async createProjectKey( - projectId: string, - options: CreateProjectKeySchema, - endpoint = ":version/projects/:projectId/keys" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }, options); - const body = JSON.stringify(options); - - const result: CreateProjectKeyResponse = await this.post(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Deletes the specified project key. - * - * @param projectId - The ID of the project the key belongs to. - * @param keyId - The ID of the key to delete. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/keys/:keyId". - * @returns A promise that resolves to an object containing a null result and an error object if an error occurs. - * @see https://developers.deepgram.com/reference/delete-key - */ - async deleteProjectKey( - projectId: string, - keyId: string, - endpoint = ":version/projects/:projectId/keys/:keyId" - ): Promise { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, keyId }); - await this.delete(requestUrl); - - return { error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { error }; - } - - throw error; - } - } - - /** - * Retrieves the members of the specified project. - * - * @param projectId - The ID of the project to retrieve members for. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/members". - * @returns A promise that resolves to an object containing the project members and an error object if an error occurs. - * @see https://developers.deepgram.com/reference/get-members - */ - async getProjectMembers( - projectId: string, - endpoint = ":version/projects/:projectId/members" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - const result: GetProjectMembersResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Removes a member from the specified project. - * - * @param projectId - The ID of the project to remove the member from. - * @param memberId - The ID of the member to remove. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/members/:memberId". - * @returns A promise that resolves to an object containing a null error if the operation was successful, or an error object if an error occurred. - * @see https://developers.deepgram.com/reference/remove-member - */ - async removeProjectMember( - projectId: string, - memberId: string, - endpoint = ":version/projects/:projectId/members/:memberId" - ): Promise { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, memberId }); - await this.delete(requestUrl); - - return { error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { error }; - } - - throw error; - } - } - - /** - * Retrieves the scopes for the specified project member. - * - * @param projectId - The ID of the project to retrieve the member scopes for. - * @param memberId - The ID of the member to retrieve the scopes for. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/members/:memberId/scopes". - * @returns A promise that resolves to an object containing the retrieved scopes or an error object if an error occurred. - * @see https://developers.deepgram.com/reference/get-member-scopes - */ - async getProjectMemberScopes( - projectId: string, - memberId: string, - endpoint = ":version/projects/:projectId/members/:memberId/scopes" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, memberId }); - const result: GetProjectMemberScopesResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Updates the scopes for the specified project member. - * - * @param projectId - The ID of the project to update the member scopes for. - * @param memberId - The ID of the member to update the scopes for. - * @param options - An object containing the new scopes to apply to the member. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/members/:memberId/scopes". - * @returns A promise that resolves to an object containing the result of the update operation or an error object if an error occurred. - * @see https://developers.deepgram.com/reference/update-scope - */ - async updateProjectMemberScope( - projectId: string, - memberId: string, - options: UpdateProjectMemberScopeSchema, - endpoint = ":version/projects/:projectId/members/:memberId/scopes" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, memberId }, options); - const body = JSON.stringify(options); - - const result: MessageResponse = await this.put(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves the project invites for the specified project. - * - * @param projectId - The ID of the project to retrieve the invites for. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/invites". - * @returns A promise that resolves to an object containing the result of the get operation or an error object if an error occurred. - * @see https://developers.deepgram.com/reference/list-invites - */ - async getProjectInvites( - projectId: string, - endpoint = ":version/projects/:projectId/invites" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - const result: GetProjectInvitesResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Sends a project invite to the specified email addresses. - * - * @param projectId - The ID of the project to send the invite for. - * @param options - An object containing the email addresses to invite and any additional options. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/invites". - * @returns A promise that resolves to an object containing the result of the post operation or an error object if an error occurred. - * @see https://developers.deepgram.com/reference/send-invites - */ - async sendProjectInvite( - projectId: string, - options: SendProjectInviteSchema, - endpoint = ":version/projects/:projectId/invites" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }, options); - const body = JSON.stringify(options); - - const result: MessageResponse = await this.post(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Deletes a project invite for the specified email address. - * - * @param projectId - The ID of the project to delete the invite for. - * @param email - The email address of the invite to delete. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/invites/:email". - * @returns A promise that resolves to an object containing a null result and an error object if an error occurred. - * @see https://developers.deepgram.com/reference/delete-invite - */ - async deleteProjectInvite( - projectId: string, - email: string, - endpoint = ":version/projects/:projectId/invites/:email" - ): Promise { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, email }); - await this.delete(requestUrl); - - return { error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { error }; - } - - throw error; - } - } - - /** - * Leaves the specified project. - * - * @param projectId - The ID of the project to leave. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/leave". - * @returns A promise that resolves to an object containing a null result and an error object if an error occurred. - * @see https://developers.deepgram.com/reference/leave-project - */ - async leaveProject( - projectId: string, - endpoint = ":version/projects/:projectId/leave" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - const result: MessageResponse = await this.delete(requestUrl).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves a list of usage requests for the specified project. - * - * @param projectId - The ID of the project to retrieve usage requests for. - * @param options - An object containing options to filter the usage requests, such as pagination parameters. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/requests". - * @returns A promise that resolves to an object containing the list of usage requests and an error object if an error occurred. - * @see https://developers.deepgram.com/reference/get-all-requests - */ - async getProjectUsageRequests( - projectId: string, - options: GetProjectUsageRequestsSchema, - endpoint = ":version/projects/:projectId/requests" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }, options); - const result: GetProjectUsageRequestsResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves the details of a specific usage request for the specified project. - * - * @param projectId - The ID of the project to retrieve the usage request for. - * @param requestId - The ID of the usage request to retrieve. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/requests/:requestId". - * @returns A promise that resolves to an object containing the usage request details and an error object if an error occurred. - * @see https://developers.deepgram.com/reference/get-request - */ - async getProjectUsageRequest( - projectId: string, - requestId: string, - endpoint = ":version/projects/:projectId/requests/:requestId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, requestId }); - const result: GetProjectUsageRequestResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves the usage summary for the specified project. - * - * @param projectId - The ID of the project to retrieve the usage summary for. - * @param options - An object containing optional parameters for the request, such as filters and pagination options. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/usage". - * @returns A promise that resolves to an object containing the usage summary and an error object if an error occurred. - * @see https://developers.deepgram.com/reference/get-usage - */ - async getProjectUsageSummary( - projectId: string, - options: GetProjectUsageSummarySchema, - endpoint = ":version/projects/:projectId/usage" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }, options); - const result: GetProjectUsageSummaryResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves the usage fields for the specified project. - * - * @param projectId - The ID of the project to retrieve the usage fields for. - * @param options - An object containing optional parameters for the request, such as filters and pagination options. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/usage/fields". - * @returns A promise that resolves to an object containing the usage fields and an error object if an error occurred. - * @see https://developers.deepgram.com/reference/get-fields - */ - async getProjectUsageFields( - projectId: string, - options: GetProjectUsageFieldsSchema, - endpoint = ":version/projects/:projectId/usage/fields" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }, options); - const result: GetProjectUsageFieldsResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves the balances for the specified project. - * - * @param projectId - The ID of the project to retrieve the balances for. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/balances". - * @returns A promise that resolves to an object containing the project balances and an error object if an error occurred. - * @see https://developers.deepgram.com/reference/get-all-balances - */ - async getProjectBalances( - projectId: string, - endpoint = ":version/projects/:projectId/balances" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - const result: GetProjectBalancesResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves the balance for the specified project and balance ID. - * - * @param projectId - The ID of the project to retrieve the balance for. - * @param balanceId - The ID of the balance to retrieve. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/projects/:projectId/balances/:balanceId". - * @returns A promise that resolves to an object containing the project balance and an error object if an error occurred. - * @see https://developers.deepgram.com/reference/get-balance - */ - async getProjectBalance( - projectId: string, - balanceId: string, - endpoint = ":version/projects/:projectId/balances/:balanceId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, balanceId }); - const result: GetProjectBalanceResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves all models for a given project. - * - * @param projectId - The ID of the project. - * @param endpoint - (optional) The endpoint URL for retrieving models. Defaults to ":version/projects/:projectId/models". - * @returns A promise that resolves to a DeepgramResponse containing the GetModelsResponse. - * @example - * ```typescript - * import { createClient } from "@deepgram/sdk"; - * - * const deepgram = createClient(DEEPGRAM_API_KEY); - * const { result: models, error } = deepgram.manage.getAllModels("projectId"); - * - * if (error) { - * console.error(error); - * } else { - * console.log(models); - * } - * ``` - */ - async getAllModels( - projectId: string, - options: GetModelsSchema = {}, - endpoint = ":version/projects/:projectId/models" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }, options); - const result: GetModelsResponse = await this.get(requestUrl).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves a model from the specified project. - * - * @param projectId - The ID of the project. - * @param modelId - The ID of the model. - * @param endpoint - (optional) The endpoint URL for the request. Default value is ":version/projects/:projectId/models/:modelId". - * @returns A promise that resolves to a DeepgramResponse containing the GetModelResponse. - * @example - * ```typescript - * import { createClient } from "@deepgram/sdk"; - * - * const deepgram = createClient(DEEPGRAM_API_KEY); - * const { result: model, error } = deepgram.models.getModel("projectId", "modelId"); - * - * if (error) { - * console.error(error); - * } else { - * console.log(model); - * } - * ``` - */ - async getModel( - projectId: string, - modelId: string, - endpoint = ":version/projects/:projectId/models/:modelId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, modelId }); - const result: GetModelResponse = await this.get(requestUrl).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } -} - -export { ManageRestClient as ManageClient }; diff --git a/src/packages/ModelsRestClient.ts b/src/packages/ModelsRestClient.ts deleted file mode 100644 index 0038a9a7..00000000 --- a/src/packages/ModelsRestClient.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { isDeepgramError } from "../lib/errors"; -import { - DeepgramResponse, - GetModelResponse, - GetModelsResponse, - GetModelsSchema, -} from "../lib/types"; -import { AbstractRestClient } from "./AbstractRestClient"; - -/** - * Represents a REST client for interacting with the Deepgram API. - * - * The `ModelsRestClient` class provides methods for interacting with the Deepgram API to retrieve information about available models. - * @extends AbstractRestClient - */ -export class ModelsRestClient extends AbstractRestClient { - public namespace: string = "models"; - - /** - * Retrieves a list of all available models. - * - * @param endpoint - (optional) The endpoint to request. - * @returns A promise that resolves with the response from the Deepgram API. - * @example - * ```typescript - * import { createClient } from "@deepgram/sdk"; - * - * const deepgram = createClient(DEEPGRAM_API_KEY); - * const { result: models, error } = deepgram.models.getAll(); - * - * if (error) { - * console.error(error); - * } else { - * console.log(models); - * } - * ``` - */ - async getAll( - endpoint = ":version/models", - options: GetModelsSchema = {} - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, {}, options); - const result: GetModelsResponse = await this.get(requestUrl).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves information about a specific model. - * - * @param modelId - The UUID of the model to retrieve. - * @param endpoint - (optional) The endpoint to request. - * @returns A promise that resolves with the response from the Deepgram API. - * @example - * ```typescript - * import { createClient } from "@deepgram/sdk"; - * - * const deepgram = createClient(DEEPGRAM_API_KEY); - * const { result: model, error } = deepgram.models.getModel("modelId"); - * - * if (error) { - * console.error(error); - * } else { - * console.log(model); - * } - * ``` - */ - async getModel( - modelId: string, - endpoint = ":version/models/:modelId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { modelId }); - const result: GetModelResponse = await this.get(requestUrl).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } -} diff --git a/src/packages/ReadRestClient.ts b/src/packages/ReadRestClient.ts deleted file mode 100644 index d5782576..00000000 --- a/src/packages/ReadRestClient.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { CallbackUrl, isTextSource, isUrlSource } from "../lib/helpers"; -import { DeepgramError, isDeepgramError } from "../lib/errors"; -import type { - AnalyzeSchema, - AsyncAnalyzeResponse, - DeepgramResponse, - SyncAnalyzeResponse, - TextSource, - UrlSource, -} from "../lib/types"; -import { AbstractRestClient } from "./AbstractRestClient"; - -/** - * The `ReadRestClient` class extends the `AbstractRestClient` class and provides methods for analyzing audio sources synchronously and asynchronously. - * - * The `analyzeUrl` method analyzes a URL-based audio source synchronously, returning a promise that resolves to the analysis response or an error. - * - * The `analyzeText` method analyzes a text-based audio source synchronously, returning a promise that resolves to the analysis response or an error. - * - * The `analyzeUrlCallback` method analyzes a URL-based audio source asynchronously, returning a promise that resolves to the analysis response or an error. - * - * The `analyzeTextCallback` method analyzes a text-based audio source asynchronously, returning a promise that resolves to the analysis response or an error. - */ -export class ReadRestClient extends AbstractRestClient { - public namespace: string = "read"; - - /** - * Analyzes a URL-based audio source synchronously. - * - * @param source - The URL-based audio source to analyze. - * @param options - Optional analysis options. - * @param endpoint - The API endpoint to use for the analysis. Defaults to ":version/read". - * @returns A promise that resolves to the analysis response, or an error if the analysis fails. - */ - async analyzeUrl( - source: UrlSource, - options?: AnalyzeSchema, - endpoint = ":version/read" - ): Promise> { - try { - let body; - - if (isUrlSource(source)) { - body = JSON.stringify(source); - } else { - throw new DeepgramError("Unknown source type"); - } - - if (options !== undefined && "callback" in options) { - throw new DeepgramError( - "Callback cannot be provided as an option to a synchronous transcription. Use `analyzeUrlCallback` or `analyzeTextCallback` instead." - ); - } - - const requestUrl = this.getRequestUrl(endpoint, {}, { ...{}, ...options }); - const result: SyncAnalyzeResponse = await this.post(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Analyzes a text-based audio source synchronously. - * - * @param source - The text-based audio source to analyze. - * @param options - Optional analysis options. - * @param endpoint - The API endpoint to use for the analysis. Defaults to ":version/read". - * @returns A promise that resolves to the analysis response, or an error if the analysis fails. - */ - async analyzeText( - source: TextSource, - options?: AnalyzeSchema, - endpoint = ":version/read" - ): Promise> { - try { - let body; - - if (isTextSource(source)) { - body = JSON.stringify(source); - } else { - throw new DeepgramError("Unknown source type"); - } - - if (options !== undefined && "callback" in options) { - throw new DeepgramError( - "Callback cannot be provided as an option to a synchronous requests. Use `analyzeUrlCallback` or `analyzeTextCallback` instead." - ); - } - - const requestUrl = this.getRequestUrl(endpoint, {}, { ...{}, ...options }); - const result: SyncAnalyzeResponse = await this.post(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Analyzes a URL-based audio source asynchronously. - * - * @param source - The URL-based audio source to analyze. - * @param callback - The URL to call back with the analysis results. - * @param options - Optional analysis options. - * @param endpoint - The API endpoint to use for the analysis. Defaults to ":version/read". - * @returns A promise that resolves to the analysis response, or an error if the analysis fails. - */ - async analyzeUrlCallback( - source: UrlSource, - callback: CallbackUrl, - options?: AnalyzeSchema, - endpoint = ":version/read" - ): Promise> { - try { - let body; - - if (isUrlSource(source)) { - body = JSON.stringify(source); - } else { - throw new DeepgramError("Unknown source type"); - } - - const requestUrl = this.getRequestUrl( - endpoint, - {}, - { ...options, callback: callback.toString() } - ); - const result: AsyncAnalyzeResponse = await this.post(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Analyzes a text-based audio source asynchronously. - * - * @param source - The text-based audio source to analyze. - * @param callback - The URL to call back with the analysis results. - * @param options - Optional analysis options. - * @param endpoint - The API endpoint to use for the analysis. Defaults to ":version/read". - * @returns A promise that resolves to the analysis response, or an error if the analysis fails. - */ - async analyzeTextCallback( - source: TextSource, - callback: CallbackUrl, - options?: AnalyzeSchema, - endpoint = ":version/read" - ): Promise> { - try { - let body; - - if (isTextSource(source)) { - body = JSON.stringify(source); - } else { - throw new DeepgramError("Unknown source type"); - } - - const requestUrl = this.getRequestUrl( - endpoint, - {}, - { ...options, callback: callback.toString() } - ); - const result: AsyncAnalyzeResponse = await this.post(requestUrl, body, { - headers: { "Content-Type": "deepgram/audio+video" }, - }).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } -} - -export { ReadRestClient as ReadClient }; diff --git a/src/packages/SelfHostedRestClient.ts b/src/packages/SelfHostedRestClient.ts deleted file mode 100644 index f897334e..00000000 --- a/src/packages/SelfHostedRestClient.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { isDeepgramError } from "../lib/errors"; -import type { - CreateOnPremCredentialsSchema, - DeepgramResponse, - ListOnPremCredentialsResponse, - MessageResponse, - OnPremCredentialResponse, -} from "../lib/types"; -import { AbstractRestClient } from "./AbstractRestClient"; - -/** - * The `SelfHostedRestClient` class extends the `AbstractRestClient` class and provides methods for interacting with the Deepgram self-hosted API. - * - * This class is used to list, retrieve, create, and delete self-hosted credentials for a Deepgram project. - */ -export class SelfHostedRestClient extends AbstractRestClient { - public namespace: string = "selfhosted"; - - /** - * Lists the self-hosted credentials for a Deepgram project. - * - * @param projectId - The ID of the Deepgram project. - * @returns A promise that resolves to an object containing the list of self-hosted credentials and any error that occurred. - * @see https://developers.deepgram.com/reference/list-credentials - */ - async listCredentials( - projectId: string, - endpoint = ":version/projects/:projectId/onprem/distribution/credentials" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - const result: ListOnPremCredentialsResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Retrieves the self-hosted credentials for a specific Deepgram project and credentials ID. - * - * @param projectId - The ID of the Deepgram project. - * @param credentialsId - The ID of the self-hosted credentials to retrieve. - * @returns A promise that resolves to an object containing the self-hosted credentials and any error that occurred. - * @see https://developers.deepgram.com/reference/get-credentials - */ - async getCredentials( - projectId: string, - credentialsId: string, - endpoint = ":version/projects/:projectId/onprem/distribution/credentials/:credentialsId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, credentialsId }); - const result: OnPremCredentialResponse = await this.get(requestUrl).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Creates self-hosted credentials for a specific Deepgram project. - * - * @param projectId - The ID of the Deepgram project. - * @param options - The options for creating the self-hosted credentials. - * @returns A promise that resolves to an object containing the created self-hosted credentials and any error that occurred. - * @see https://developers.deepgram.com/reference/create-credentials - */ - async createCredentials( - projectId: string, - options: CreateOnPremCredentialsSchema, - endpoint = ":version/projects/:projectId/onprem/distribution/credentials" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId }); - const body = JSON.stringify(options); - - const result: OnPremCredentialResponse = await this.post(requestUrl, body).then((result) => - result.json() - ); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } - - /** - * Deletes self-hosted credentials for a specific Deepgram project. - * - * @param projectId - The ID of the Deepgram project. - * @param credentialsId - The ID of the self-hosted credentials to delete. - * @returns A promise that resolves to an object containing a message response and any error that occurred. - * @see https://developers.deepgram.com/reference/delete-credentials - */ - async deleteCredentials( - projectId: string, - credentialsId: string, - endpoint = ":version/projects/:projectId/onprem/distribution/credentials/:credentialsId" - ): Promise> { - try { - const requestUrl = this.getRequestUrl(endpoint, { projectId, credentialsId }); - const result: MessageResponse = await this.delete(requestUrl).then((result) => result.json()); - - return { result, error: null }; - } catch (error) { - if (isDeepgramError(error)) { - return { result: null, error }; - } - - throw error; - } - } -} - -export { SelfHostedRestClient as OnPremClient }; diff --git a/src/packages/SpeakClient.ts b/src/packages/SpeakClient.ts deleted file mode 100644 index 097e0705..00000000 --- a/src/packages/SpeakClient.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AbstractClient } from "./AbstractClient"; -import { SpeakLiveClient } from "./SpeakLiveClient"; -import { SpeakRestClient } from "./SpeakRestClient"; -import { SpeakSchema } from "../lib/types"; -import { TextSource } from "../lib/types"; - -/** - * The `SpeakClient` class extends the `AbstractClient` class and provides access to the "speak" namespace. - * It exposes two methods: - * - * 1. `request()`: Returns a `SpeakRestClient` instance for interacting with the rest speak API. - * 2. `live(ttsOptions: SpeakSchema = {}, endpoint = ":version/speak")`: Returns a `SpeakLiveClient` instance for interacting with the live speak API, with the provided TTS options and endpoint. - */ -export class SpeakClient extends AbstractClient { - public namespace: string = "speak"; - - /** - * Returns a `SpeakRestClient` instance for interacting with the rest speak API. - */ - public request(source: TextSource, options?: SpeakSchema, endpoint = ":version/speak") { - const client = new SpeakRestClient(this.options); - - return client.request(source, options, endpoint); - } - - /** - * Returns a `SpeakLiveClient` instance for interacting with the live speak API, with the provided TTS options and endpoint. - * @param {SpeakSchema} [ttsOptions={}] - The TTS options to use for the live speak API. - * @param {string} [endpoint=":version/speak"] - The endpoint to use for the live speak API. - * @returns {SpeakLiveClient} - A `SpeakLiveClient` instance for interacting with the live speak API. - */ - public live(ttsOptions: SpeakSchema = {}, endpoint: string = ":version/speak"): SpeakLiveClient { - return new SpeakLiveClient(this.options, ttsOptions, endpoint); - } -} diff --git a/src/packages/SpeakLiveClient.ts b/src/packages/SpeakLiveClient.ts deleted file mode 100644 index ef731ac6..00000000 --- a/src/packages/SpeakLiveClient.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { AbstractLiveClient } from "./AbstractLiveClient"; -import { LiveTTSEvents } from "../lib/enums"; -import type { SpeakSchema, DeepgramClientOptions } from "../lib/types"; - -/** - * The `SpeakLiveClient` class extends the `AbstractLiveClient` class and provides functionality for setting up and managing a WebSocket connection for live text-to-speech synthesis. - * - * The constructor takes in `DeepgramClientOptions` and an optional `SpeakSchema` object, as well as an optional `endpoint` string. It then calls the `connect` method of the parent `AbstractLiveClient` class to establish the WebSocket connection. - * - * The `setupConnection` method is responsible for handling the various events that can occur on the WebSocket connection, such as opening, closing, and receiving messages. It sets up event handlers for these events and emits the appropriate events based on the message type. - * - * The `configure` method allows you to send additional configuration options to the connected session. - * - * The `requestClose` method requests the server to close the connection. - */ -export class SpeakLiveClient extends AbstractLiveClient { - public namespace: string = "speak"; - - /** - * Constructs a new `SpeakLiveClient` instance with the provided options. - * - * @param options - The `DeepgramClientOptions` to use for the client connection. - * @param speakOptions - An optional `SpeakSchema` object containing additional configuration options for the text-to-speech. - * @param endpoint - An optional string representing the WebSocket endpoint to connect to. Defaults to `:version/speak`. - */ - constructor( - options: DeepgramClientOptions, - speakOptions: Omit = {}, - endpoint: string = ":version/speak" - ) { - super(options); - - this.connect(speakOptions, endpoint); - } - - /** - * Sets up the connection event handlers. - * This method is responsible for handling the various events that can occur on the WebSocket connection, such as opening, closing, and receiving data. - * - When the connection is opened, it emits the `LiveTTSEvents.Open` event. - * - When the connection is closed, it emits the `LiveTTSEvents.Close` event. - * - When an error occurs on the connection, it emits the `LiveTTSEvents.Error` event. - * - When a message is received, it parses the message and emits the appropriate event based on the message type, such as `LiveTTSEvents.Metadata`, `LiveTTSEvents.Flushed`, and `LiveTTSEvents.Warning`. - */ - public setupConnection(): void { - // Set up standard connection events (open, close, error) using abstracted method - this.setupConnectionEvents({ - Open: LiveTTSEvents.Open, - Close: LiveTTSEvents.Close, - Error: LiveTTSEvents.Error, - }); - - // Set up message handling specific to text-to-speech - if (this.conn) { - this.conn.onmessage = (event: MessageEvent) => { - this.handleMessage(event); - }; - } - } - - /** - * Handles text messages received from the WebSocket connection. - * @param data - The parsed JSON data. - */ - protected handleTextMessage(data: any): void { - if (data.type === LiveTTSEvents.Metadata) { - this.emit(LiveTTSEvents.Metadata, data); - } else if (data.type === LiveTTSEvents.Flushed) { - this.emit(LiveTTSEvents.Flushed, data); - } else if (data.type === LiveTTSEvents.Warning) { - this.emit(LiveTTSEvents.Warning, data); - } else { - this.emit(LiveTTSEvents.Unhandled, data); - } - } - - /** - * Handles binary messages received from the WebSocket connection. - * @param data - The binary data. - */ - protected handleBinaryMessage(data: Buffer): void { - this.emit(LiveTTSEvents.Audio, data); - } - - /** - * Sends a text input message to the server. - * - * @param {string} text - The text to convert to speech. - */ - public sendText(text: string): void { - this.send( - JSON.stringify({ - type: "Speak", - text, - }) - ); - } - - /** - * Requests the server flush the current buffer and return generated audio. - */ - public flush(): void { - this.send( - JSON.stringify({ - type: "Flush", - }) - ); - } - - /** - * Requests the server clear the current buffer. - */ - public clear(): void { - this.send( - JSON.stringify({ - type: "Clear", - }) - ); - } - - /** - * Requests the server close the connection. - */ - public requestClose(): void { - this.send( - JSON.stringify({ - type: "Close", - }) - ); - } - - /** - * Handles incoming messages from the WebSocket connection. - * @param event - The MessageEvent object representing the received message. - */ - protected handleMessage(event: MessageEvent): void { - if (typeof event.data === "string") { - try { - const data = JSON.parse(event.data); - this.handleTextMessage(data); - } catch (error) { - this.emit(LiveTTSEvents.Error, { - event, - message: "Unable to parse `data` as JSON.", - error, - url: this.conn?.url, - readyState: this.conn?.readyState, - data: - event.data?.toString().substring(0, 200) + - (event.data?.toString().length > 200 ? "..." : ""), - }); - } - } else if (event.data instanceof Blob) { - event.data.arrayBuffer().then((buffer) => { - this.handleBinaryMessage(Buffer.from(buffer)); - }); - } else if (event.data instanceof ArrayBuffer) { - this.handleBinaryMessage(Buffer.from(event.data)); - } else if (Buffer.isBuffer(event.data)) { - this.handleBinaryMessage(event.data); - } else { - console.log("Received unknown data type", event.data); - this.emit(LiveTTSEvents.Error, { - event, - message: "Received unknown data type.", - url: this.conn?.url, - readyState: this.conn?.readyState, - dataType: typeof event.data, - }); - } - } -} diff --git a/src/packages/SpeakRestClient.ts b/src/packages/SpeakRestClient.ts deleted file mode 100644 index ae272641..00000000 --- a/src/packages/SpeakRestClient.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { DeepgramError, DeepgramUnknownError } from "../lib/errors"; -import { isTextSource } from "../lib/helpers"; -import { SpeakSchema, TextSource } from "../lib/types"; -import { AbstractRestClient } from "./AbstractRestClient"; - -/** - * Provides a client for interacting with the Deepgram Text-to-Speech API. - */ -export class SpeakRestClient extends AbstractRestClient { - public namespace: string = "speak"; - public result: undefined | Response; - - /** - * Sends a request to the Deepgram Text-to-Speech API to generate audio from the provided text source. - * - * @param source - The text source to be converted to audio. - * @param options - Optional configuration options for the text-to-speech request. - * @param endpoint - The API endpoint to use for the request. Defaults to ":version/speak". - * @returns A promise that resolves to the SpeakRestClient instance, which can be used to retrieve the response headers and body. - * @throws {DeepgramError} If the text source type is unknown. - * @throws {DeepgramUnknownError} If the request was made before a previous request completed. - * @see https://developers.deepgram.com/reference/text-to-speech-api - */ - async request( - source: TextSource, - options?: SpeakSchema, - endpoint = ":version/speak" - ): Promise { - let body; - - if (isTextSource(source)) { - body = JSON.stringify(source); - } else { - throw new DeepgramError("Unknown transcription source type"); - } - - const requestUrl = this.getRequestUrl( - endpoint, - {}, - { ...{ model: "aura-2-thalia-en" }, ...options } - ); - this.result = await this.post(requestUrl, body, { - headers: { Accept: "audio/*", "Content-Type": "application/json" }, - }); - - return this; - } - - /** - * Retrieves the response body as a readable stream. - * - * @returns A promise that resolves to the response body as a readable stream, or `null` if no request has been made yet. - * @throws {DeepgramUnknownError} If a request has not been made yet. - */ - async getStream(): Promise | null> { - if (!this.result) - throw new DeepgramUnknownError("Tried to get stream before making request", ""); - - return this.result.body; - } - - /** - * Retrieves the response headers from the previous request. - * - * @returns A promise that resolves to the response headers, or throws a `DeepgramUnknownError` if no request has been made yet. - */ - async getHeaders(): Promise { - if (!this.result) - throw new DeepgramUnknownError("Tried to get headers before making request", ""); - - return this.result.headers; - } -} diff --git a/src/packages/index.ts b/src/packages/index.ts deleted file mode 100644 index f210a660..00000000 --- a/src/packages/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -export * from "./AbstractClient"; -export * from "./AbstractLiveClient"; -export * from "./AbstractRestClient"; -export * from "./AgentLiveClient"; -export * from "./AuthRestClient"; -export * from "./ListenClient"; -export * from "./ListenLiveClient"; -export * from "./ListenRestClient"; -export * from "./ManageRestClient"; -export * from "./ModelsRestClient"; -export * from "./ReadRestClient"; -export * from "./SelfHostedRestClient"; -export * from "./SpeakClient"; -export * from "./SpeakLiveClient"; -export * from "./SpeakRestClient"; diff --git a/src/version.ts b/src/version.ts new file mode 100644 index 00000000..1d1a4f3e --- /dev/null +++ b/src/version.ts @@ -0,0 +1 @@ +export const SDK_VERSION = "4.11.3"; diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index 948575d0..00000000 --- a/tests/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Test Suites - -This directory contains the E2E and unit tests for the Deepgram JS SDK. - -## Running Tests - -### All Tests - -To run the entire test suite: - -```bash -pnpm test -``` - -### E2E Tests - -To run only the end-to-end tests: - -```bash -pnpm test tests/e2e/ -``` - -### Unit Tests - -To run only the unit tests: - -```bash -pnpm test tests/unit/ -``` - -### Snapshot Updates - -To update snapshots with real API calls: - -```bash -# Using Jest's update flag -pnpm test tests/e2e/ -- -u - -# or - -# By using an environment variable -DEEPGRAM_FORCE_REAL_API=true pnpm test tests/e2e/ -``` - -For more details on the testing strategy, please see the main [project README.md](../README.md). diff --git a/tests/__fixtures__/listen.ts b/tests/__fixtures__/listen.ts deleted file mode 100644 index 5c5f57db..00000000 --- a/tests/__fixtures__/listen.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Test fixtures for Listen (Speech-to-Text) API - */ - -/** - * Common transcription options used across multiple tests - */ -export const commonTranscriptionOptions = { - model: "nova-3", - smart_format: true, - punctuate: true, -} as const; - -/** - * Test audio URLs for different scenarios - */ -export const testAudioUrls = { - spacewalk: "https://dpgr.am/spacewalk.wav", -} as const; - -/** - * URL source objects for transcribeUrl tests - */ -export const urlSources = { - spacewalk: { - url: testAudioUrls.spacewalk, - }, -} as const; - -/** - * File paths for test audio files - */ -export const testAudioFiles = { - spacewalk: "spacewalk.wav", -} as const; - -/** - * Alternative transcription options for different test scenarios - */ -export const transcriptionOptions = { - basic: { - model: "nova-3", - }, - enhanced: { - model: "nova-3", - smart_format: true, - punctuate: true, - diarize: true, - }, - withKeyterms: { - model: "nova-3", - smart_format: true, - punctuate: true, - keyterm: ["spacewalk"], - }, -} as const; - -/** - * Callback URLs for async operations - */ -export const callbackUrls = { - webhook: "https://your-webhook-url.com/callback", - testEndpoint: "https://test-callback.example.com/webhook", -} as const; diff --git a/tests/__fixtures__/manage.ts b/tests/__fixtures__/manage.ts deleted file mode 100644 index f22e480b..00000000 --- a/tests/__fixtures__/manage.ts +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Test fixtures for Manage API (Project Management) - */ - -/** - * Test project IDs for management operations - */ -export const testProjectIds = { - primary: "test-project-123", - secondary: "test-project-456", - toDelete: "test-project-789", -} as const; - -/** - * Test member IDs for member management operations - */ -export const testMemberIds = { - member1: "test-member-123", - member2: "test-member-456", - toRemove: "test-member-789", -} as const; - -/** - * Test API key IDs for key management operations - */ -export const testKeyIds = { - key1: "test-key-123", - key2: "test-key-456", - toDelete: "test-key-789", -} as const; - -/** - * Test balance IDs for balance operations - */ -export const testBalanceIds = { - balance1: "test-balance-123", - balance2: "test-balance-456", -} as const; - -/** - * Test request IDs for usage operations - */ -export const testRequestIds = { - request1: "test-request-123", - request2: "test-request-456", -} as const; - -/** - * Project creation/update options - */ -export const projectOptions = { - create: { - name: "Test Project", - company: "Test Company", - }, - update: { - name: "Updated Test Project", - company: "Updated Test Company", - }, -} as const; - -/** - * API key creation options - */ -export const keyOptions = { - create: { - comment: "Test API key for e2e testing", - scopes: ["usage:write", "usage:read"], - }, - createMinimal: { - comment: "Minimal test key", - scopes: [], - }, -}; - -/** - * Member scope update options - */ -export const memberScopeOptions = { - update: { - scope: "member" as const, - }, - updateAdmin: { - scope: "admin" as const, - }, -} as const; - -/** - * Project invitation options - */ -export const inviteOptions = { - single: { - email: "test@example.com", - scope: "member", - }, - multiple: { - email: "test-bulk@example.com", // API may support bulk but type shows single - scope: "member", - }, -}; - -/** - * Usage request query options - */ -export const usageRequestOptions = { - basic: { - start: "2024-01-01", - end: "2024-01-31", - }, - withLimit: { - start: "2024-01-01", - end: "2024-01-31", - limit: 10, - }, - withPagination: { - start: "2024-01-01", - end: "2024-01-31", - limit: 5, - page: 1, - }, -} as const; - -/** - * Usage summary query options - */ -export const usageSummaryOptions = { - basic: { - start: "2024-01-01", - end: "2024-01-31", - }, - withFilters: { - start: "2024-01-01", - end: "2024-01-31", - accessor: "streaming", - tag: "test", - method: "POST", - model: "nova-2", - }, -} as const; - -/** - * Usage fields query options - */ -export const usageFieldsOptions = { - basic: { - start: "2024-01-01", - end: "2024-01-31", - }, - withFilters: { - start: "2024-01-01", - end: "2024-01-31", - include_tags: true, - }, -} as const; - -/** - * Test model IDs for project-scoped model operations - */ -export const testModelIds = { - sttModel: "nova-2", - ttsModel: "aura-thalia-en", - customModel: "custom-model-123", -} as const; - -/** - * Test email addresses for invite operations - */ -export const testEmails = { - toInvite: "test@example.com", - toDelete: "invited@example.com", - bulk: "test-bulk@example.com", -} as const; - -/** - * Project-scoped model query options - */ -export const modelOptions = { - basic: {}, - withFilters: { - includeOutdated: false, - }, -} as const; diff --git a/tests/__fixtures__/models.ts b/tests/__fixtures__/models.ts deleted file mode 100644 index 82f730fa..00000000 --- a/tests/__fixtures__/models.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Test fixtures for Models API - */ - -/** - * Test model IDs for model operations (mock IDs for testing) - */ -export const testModelIds = { - nova: "nova-2-general", - whisper: "whisper-medium", - custom: "custom-model-123", -} as const; diff --git a/tests/__fixtures__/read.ts b/tests/__fixtures__/read.ts deleted file mode 100644 index eec09723..00000000 --- a/tests/__fixtures__/read.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Test fixtures for Read (Text Analysis) API - */ - -/** - * Test text sources for Read API (text analysis) scenarios - */ -export const testReadSources = { - simpleText: { text: "Hello world, this is a test." }, - complexText: { - text: "The quick brown fox jumps over the lazy dog. This sentence contains every letter of the alphabet.", - }, - sentimentText: { text: "I absolutely love this product! It's amazing and works perfectly." }, - urlSource: { url: "https://example.com/article.txt" }, -} as const; - -/** - * Common analysis options for Read API tests - */ -export const commonAnalysisOptions = { - sentiment: true, - summarize: true, - intents: true, - language: "en", -} as const; - -/** - * Callback URLs for async operations - */ -export const callbackUrls = { - webhook: "https://your-webhook-url.com/callback", - testEndpoint: "https://test-callback.example.com/webhook", -} as const; diff --git a/tests/__fixtures__/selfhosted.ts b/tests/__fixtures__/selfhosted.ts deleted file mode 100644 index 0a0f49e3..00000000 --- a/tests/__fixtures__/selfhosted.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Test fixtures for Selfhosted API - */ - -/** - * Test project IDs for management operations (mock IDs for testing) - */ -export const testProjectIds = { - primary: "test-project-123", - secondary: "test-project-456", -} as const; - -/** - * Test credentials for self-hosted operations - */ -export const testCredentials = { - createOptions: { - comment: "Test credentials for e2e testing", - scopes: ["usage:write"] as string[], - }, - credentialId: "test-credential-123", -} as const; diff --git a/tests/__fixtures__/spacewalk.wav b/tests/__fixtures__/spacewalk.wav deleted file mode 100644 index 498be744..00000000 Binary files a/tests/__fixtures__/spacewalk.wav and /dev/null differ diff --git a/tests/__fixtures__/speak.ts b/tests/__fixtures__/speak.ts deleted file mode 100644 index 2656e216..00000000 --- a/tests/__fixtures__/speak.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Test fixtures for Speak (Text-to-Speech) API - */ - -/** - * Common TTS options used across multiple tests - */ -export const commonTTSOptions = { - model: "aura-2-thalia-en", - encoding: "mp3", -} as const; - -/** - * Test text sources for TTS scenarios - */ -export const testTextSources = { - greeting: { text: "Hello, how can I help you today?" }, - longText: { - text: "This is a longer text sample for testing text-to-speech functionality with multiple sentences. It should demonstrate how the API handles longer content.", - }, - multiline: { text: "Line one.\nLine two.\nLine three with more content." }, -} as const; - -/** - * Alternative TTS options for different test scenarios - */ -export const ttsOptions = { - basic: { - model: "aura-2-thalia-en", - }, - highQuality: { - model: "aura-2-thalia-en", - encoding: "linear16", - sample_rate: 48000, - }, - compressed: { - model: "aura-2-thalia-en", - encoding: "mp3", - bit_rate: 128000, - }, -} as const; diff --git a/tests/__utils__/index.ts b/tests/__utils__/index.ts deleted file mode 100644 index 7480c547..00000000 --- a/tests/__utils__/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./serializers"; -export * from "./mocks"; diff --git a/tests/__utils__/mocks.ts b/tests/__utils__/mocks.ts deleted file mode 100644 index b5638747..00000000 --- a/tests/__utils__/mocks.ts +++ /dev/null @@ -1,486 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-require-imports, no-console */ -import { - mockTranscribeUrlResponse, - mockTranscribeFileResponse, - mockAsyncListenUrlResponse, - mockAsyncListenFileResponse, -} from "../e2e/__mocks__/listen"; -import { mockAudioBuffer, mockTTSHeaders } from "../e2e/__mocks__/speak"; -import { mockGetAllModelsResponse, mockGetModelResponse } from "../e2e/__mocks__/models"; -import { mockGrantTokenResponse } from "../e2e/__mocks__/auth"; -import { - mockAnalyzeTextResponse, - mockAnalyzeUrlResponse, - mockAsyncAnalyzeResponse, - mockAsyncReadUrlResponse, - mockAsyncReadTextResponse, -} from "../e2e/__mocks__/read"; -import { - mockListCredentialsResponse, - mockGetCredentialsResponse, - mockCreateCredentialsResponse, - mockDeleteCredentialsResponse, -} from "../e2e/__mocks__/selfhosted"; -import { - mockGetProjectsResponse, - mockGetProjectResponse, - mockGetProjectKeysResponse, - mockGetProjectKeyResponse, - mockGetProjectMembersResponse, - mockGetProjectBalancesResponse, - mockGetProjectUsageRequestsResponse, - mockGetProjectUsageSummaryResponse, - mockCreateProjectKeyResponse, - mockGetTokenDetailsResponse, - mockDeleteProjectResponse, - mockDeleteProjectKeyResponse, - mockRemoveProjectMemberResponse, - mockDeleteProjectInviteResponse, - mockGetProjectMemberScopesResponse, - mockUpdateProjectMemberScopeResponse, - mockGetProjectInvitesResponse, - mockSendProjectInviteResponse, - mockLeaveProjectResponse, - mockGetProjectUsageRequestResponse, - mockGetProjectUsageFieldsResponse, - mockGetProjectBalanceResponse, - mockGetAllProjectModelsResponse, - mockGetProjectModelResponse, - mockUpdateProjectResponse, -} from "../e2e/__mocks__/manage"; - -// Store original fetch to restore later -let originalFetch: typeof global.fetch | undefined; -let originalCrossFetch: any; - -/** - * Determines if we're in snapshot update mode - */ -function isUpdatingSnapshots(): boolean { - const isUpdateMode = - process.argv.includes("--updateSnapshot") || - process.argv.includes("-u") || - process.env.DEEPGRAM_FORCE_REAL_API === "true"; - - return isUpdateMode; -} - -/** - * Creates a mock fetch function that handles Deepgram API requests - */ -function createMockFetch(): typeof fetch { - return async (input: RequestInfo | URL, init?: RequestInit): Promise => { - const url = - typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url; - const method = init?.method || "GET"; - - // Mock Deepgram API endpoints - if (url.includes("api.deepgram.com")) { - if (url.includes("/v1/listen") && method === "POST") { - // Check if it's a callback request (async) - const isCallbackRequest = url.includes("callback="); - - // Check if it's a URL-based or file-based request - const body = init?.body; - let isUrlRequest = false; - - if (typeof body === "string") { - try { - const parsed = JSON.parse(body); - isUrlRequest = parsed && parsed.url; - } catch { - // Not JSON - } - } - - let responseData; - if (isCallbackRequest) { - responseData = isUrlRequest ? mockAsyncListenUrlResponse : mockAsyncListenFileResponse; - } else { - responseData = isUrlRequest ? mockTranscribeUrlResponse : mockTranscribeFileResponse; - } - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - if (url.includes("/v1/speak") && method === "POST") { - return new Response(mockAudioBuffer, { - status: 200, - headers: new Headers(mockTTSHeaders), - }); - } - - if (url.includes("/v1/models") && method === "GET") { - // Check if it's a specific model request (has model ID in path) - const modelIdMatch = url.match(/\/v1\/models\/([^?]+)/); - const responseData = modelIdMatch ? mockGetModelResponse : mockGetAllModelsResponse; - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - if (url.includes("/v1/auth/grant") && method === "POST") { - // Handle the ttl_seconds parameter from the request body - const responseData = { ...mockGrantTokenResponse }; - - if (init?.body) { - try { - const requestBody = JSON.parse(init.body as string); - if (requestBody.ttl_seconds) { - // Update the expires_in value based on ttl_seconds - responseData.expires_in = requestBody.ttl_seconds; - } - } catch (e) { - // If parsing fails, use default response - } - } - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - if (url.includes("/v1/read") && method === "POST") { - // Check if it's a callback request (async) - const isCallbackRequest = url.includes("callback="); - - if (isCallbackRequest) { - // Check if it's a URL-based or text-based request for callback - const body = init?.body; - let isUrlRequest = false; - - if (typeof body === "string") { - try { - const parsed = JSON.parse(body); - isUrlRequest = parsed && parsed.url; - } catch { - // Not JSON - } - } - - const responseData = isUrlRequest ? mockAsyncReadUrlResponse : mockAsyncReadTextResponse; - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check if it's a URL-based or text-based request - const body = init?.body; - let isUrlRequest = false; - - if (typeof body === "string") { - try { - const parsed = JSON.parse(body); - isUrlRequest = parsed && parsed.url; - } catch { - // Not JSON - } - } - - const responseData = isUrlRequest ? mockAnalyzeUrlResponse : mockAnalyzeTextResponse; - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - if (url.includes("/onprem/distribution/credentials")) { - if (method === "GET") { - // Check if it's a specific credential request (has credential ID in path) - const credentialIdMatch = url.match(/\/credentials\/([^?]+)$/); - const responseData = credentialIdMatch - ? mockGetCredentialsResponse - : mockListCredentialsResponse; - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - if (method === "POST") { - return new Response(JSON.stringify(mockCreateCredentialsResponse), { - status: 201, - headers: { "content-type": "application/json" }, - }); - } - - if (method === "DELETE") { - return new Response(JSON.stringify(mockDeleteCredentialsResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - } - - if (url.includes("/v1/auth/token") && method === "GET") { - return new Response(JSON.stringify(mockGetTokenDetailsResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - if (url.includes("/v1/projects") && method === "GET") { - // Check for project keys endpoint - if (url.includes("/keys")) { - // Check if it's a specific key request (has key ID in path after /keys/) - const keyIdMatch = url.match(/\/keys\/([^?/]+)$/); - const responseData = keyIdMatch ? mockGetProjectKeyResponse : mockGetProjectKeysResponse; - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project members endpoint - if (url.includes("/members")) { - // Check for member scopes endpoint - if (url.includes("/scopes")) { - return new Response(JSON.stringify(mockGetProjectMemberScopesResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - return new Response(JSON.stringify(mockGetProjectMembersResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project balances endpoint - if (url.includes("/balances")) { - // Check if it's a specific balance request - const balanceIdMatch = url.match(/\/balances\/([^?/]+)$/); - const responseData = balanceIdMatch - ? mockGetProjectBalanceResponse - : mockGetProjectBalancesResponse; - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project invites endpoint - if (url.includes("/invites")) { - return new Response(JSON.stringify(mockGetProjectInvitesResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project usage requests endpoint - if (url.includes("/requests")) { - // Check if it's a specific request - const requestIdMatch = url.match(/\/requests\/([^?/]+)$/); - const responseData = requestIdMatch - ? mockGetProjectUsageRequestResponse - : mockGetProjectUsageRequestsResponse; - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project usage summary endpoint - if (url.includes("/usage/fields")) { - return new Response(JSON.stringify(mockGetProjectUsageFieldsResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project usage summary endpoint - if (url.includes("/usage")) { - return new Response(JSON.stringify(mockGetProjectUsageSummaryResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project models endpoint - if (url.includes("/models")) { - // Check if it's a specific model request - const modelIdMatch = url.match(/\/models\/([^?/]+)$/); - const responseData = modelIdMatch - ? mockGetProjectModelResponse - : mockGetAllProjectModelsResponse; - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check if it's a specific project request (has project ID in path) - const projectIdMatch = url.match(/\/v1\/projects\/([^?/]+)$/); - const responseData = projectIdMatch ? mockGetProjectResponse : mockGetProjectsResponse; - - return new Response(JSON.stringify(responseData), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - if (url.includes("/v1/projects") && method === "POST") { - // Check for project key creation - if (url.includes("/keys")) { - return new Response(JSON.stringify(mockCreateProjectKeyResponse), { - status: 201, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project invites - if (url.includes("/invites")) { - return new Response(JSON.stringify(mockSendProjectInviteResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - } - - if (url.includes("/v1/projects") && method === "PATCH") { - // Check for project updates - if (url.match(/\/v1\/projects\/[^/]+$/)) { - return new Response(JSON.stringify(mockUpdateProjectResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - } - - if (url.includes("/v1/projects") && method === "PUT") { - // Check for member scope updates - if (url.includes("/scopes")) { - return new Response(JSON.stringify(mockUpdateProjectMemberScopeResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - } - - if (url.includes("/v1/projects") && method === "DELETE") { - // Check for leave project (special case - returns JSON response) - if (url.includes("/leave")) { - return new Response(JSON.stringify(mockLeaveProjectResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for project deletion - if (url.match(/\/v1\/projects\/[^/]+$/)) { - return new Response(JSON.stringify(mockDeleteProjectResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for key deletion - if (url.includes("/keys/")) { - return new Response(JSON.stringify(mockDeleteProjectKeyResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for member removal - if (url.includes("/members/")) { - return new Response(JSON.stringify(mockRemoveProjectMemberResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - - // Check for invite deletion - if (url.includes("/invites/")) { - return new Response(JSON.stringify(mockDeleteProjectInviteResponse), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } - } - } - - // If we get here, it's not a Deepgram API request we're mocking - throw new Error(`Network request blocked in offline test mode: ${method} ${url}`); - }; -} - -/** - * Sets up API mocks for e2e tests - * This allows tests to run without internet/API key requirements - * E2E tests use mocks by default, but can be toggled to real APIs - */ -export function setupApiMocks(): void { - // Check if we should use real APIs instead of mocks - if (process.env.DEEPGRAM_FORCE_REAL_API === "true") { - return; // Skip mock setup - use real APIs - } - - // Store original implementations - originalFetch = global.fetch; - - // Try to mock cross-fetch as well - try { - const crossFetch = require("cross-fetch"); - originalCrossFetch = crossFetch.default || crossFetch; - } catch (_e) { - // cross-fetch might not be available or loaded yet - } - - // Create our mock fetch - const mockFetch = createMockFetch(); - - // Override global fetch - global.fetch = mockFetch as any; - - // Also try to override cross-fetch - try { - const crossFetch = require("cross-fetch"); - if (crossFetch.default) { - crossFetch.default = mockFetch; - } else { - Object.assign(crossFetch, mockFetch); - } - } catch (_e) { - // Might not be available - } -} - -/** - * Cleans up all mocks after tests - */ -export function cleanupApiMocks(): void { - // Restore original fetch - if (originalFetch) { - global.fetch = originalFetch; - originalFetch = undefined; - } - - // Restore cross-fetch if we mocked it - if (originalCrossFetch) { - try { - const crossFetch = require("cross-fetch"); - if (crossFetch.default) { - crossFetch.default = originalCrossFetch; - } else { - Object.assign(crossFetch, originalCrossFetch); - } - originalCrossFetch = undefined; - } catch (_e) { - // Might not be available - } - } -} diff --git a/tests/__utils__/serializers.ts b/tests/__utils__/serializers.ts deleted file mode 100644 index cd47f06c..00000000 --- a/tests/__utils__/serializers.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Simple serializer that replaces values with type placeholders for non-deterministic testing - * Perfect for AI APIs where response content varies but structure should remain consistent - */ -export const structureOnlySerializer = { - test: (val: any) => val != null && typeof val === "object", - serialize: (val: any) => { - const replaceValues = (obj: any): any => { - if (obj === null) return null; - if (obj === undefined) return undefined; - if (typeof obj === "string") return ""; - if (typeof obj === "number") return ""; - if (typeof obj === "boolean") return ""; - - if (Array.isArray(obj)) { - return obj.length > 0 ? [replaceValues(obj[0])] : []; - } - - if (typeof obj === "object") { - const result: any = {}; - for (const key of Object.keys(obj).sort()) { - result[key] = replaceValues(obj[key]); - } - return result; - } - - return obj; - }; - - return JSON.stringify(replaceValues(val), null, 2); - }, -}; diff --git a/tests/__utils__/websocket-mocks.ts b/tests/__utils__/websocket-mocks.ts deleted file mode 100644 index 0072bd4b..00000000 --- a/tests/__utils__/websocket-mocks.ts +++ /dev/null @@ -1,365 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { SOCKET_STATES } from "../../src/lib/constants"; - -/** - * Mock WebSocket data for different live client scenarios - */ -export const mockWebSocketData = { - listen: { - metadata: { - type: "Metadata", - transaction_key: "deprecated", - request_id: "550e8400-e29b-41d4-a716-446655440000", - sha256: "abc123def456", - created: "2024-01-15T10:30:00Z", - duration: 120.5, - channels: 1, - }, - transcript: { - type: "Results", - channel_index: [0, 1], - duration: 2.5, - start: 0.0, - is_final: true, - channel: { - alternatives: [ - { - transcript: "Hello world from WebSocket test", - confidence: 0.95, - words: [ - { word: "Hello", start: 0.0, end: 0.5, confidence: 0.95 }, - { word: "world", start: 0.6, end: 1.0, confidence: 0.94 }, - { word: "from", start: 1.1, end: 1.3, confidence: 0.96 }, - { word: "WebSocket", start: 1.4, end: 1.8, confidence: 0.93 }, - { word: "test", start: 1.9, end: 2.2, confidence: 0.97 }, - ], - }, - ], - }, - }, - utteranceEnd: { - type: "UtteranceEnd", - channel: [0], - last_word_end: 2.5, - }, - speechStarted: { - type: "SpeechStarted", - channel: [0], - timestamp: 1.2, - }, - }, - speak: { - metadata: { - type: "Metadata", - request_id: "550e8400-e29b-41d4-a716-446655440001", - model_name: "aura-asteria-en", - model_uuid: "c0e51fb0-7b76-42f0-b8c0-8ad7a14fb5b5", - char_count: 25, - transfer_encoding: "chunked", - date: "Thu, 15 Aug 2024 17:22:02 GMT", - }, - warning: { - type: "Warning", - warn_code: "W001", - warn_msg: "Sample warning message from TTS", - }, - flushed: { - type: "Flushed", - }, - }, - agent: { - welcome: { - type: "Welcome", - request_id: "550e8400-e29b-41d4-a716-446655440002", - }, - conversationText: { - type: "ConversationText", - role: "user", - content: "Hello, how can you help me today?", - }, - agentThinking: { - type: "AgentThinking", - content: "Let me think about that...", - }, - functionCallRequest: { - type: "FunctionCallRequest", - functions: [ - { - id: "function-123", - name: "get_weather", - arguments: '{"location": "San Francisco", "units": "celsius"}', - client_side: true, - }, - ], - }, - agentStartedSpeaking: { - type: "AgentStartedSpeaking", - total_latency: 250, - tts_latency: 100, - ttt_latency: 150, - }, - agentAudioDone: { - type: "AgentAudioDone", - }, - }, -}; - -/** - * Mock audio data for testing binary WebSocket messages - */ -export const mockAudioData = new ArrayBuffer(1024); - -/** - * Event handler type for WebSocket events - */ -type EventHandler = (event?: any) => void; - -/** - * Mock WebSocket class that simulates WebSocket behavior for testing - */ -export class MockWebSocket { - public url: string; - public readyState: number = SOCKET_STATES.connecting; - public onopen: EventHandler | null = null; - public onclose: EventHandler | null = null; - public onerror: EventHandler | null = null; - public onmessage: EventHandler | null = null; - public binaryType: string = "arraybuffer"; - - private sendBuffer: any[] = []; - private messageQueue: any[] = []; - private isConnected = false; - - constructor(url: string, protocols?: string | string[], options?: any) { - this.url = url.toString(); - - // Simulate async connection - setTimeout(() => { - this.readyState = SOCKET_STATES.open; - this.isConnected = true; - if (this.onopen) { - this.onopen(); - } - }, 0); - } - - /** - * Mock send method that stores sent data for testing - */ - public send(data: string | ArrayBuffer | Blob): void { - if (this.readyState !== SOCKET_STATES.open) { - throw new Error("WebSocket is not open"); - } - this.sendBuffer.push(data); - } - - /** - * Mock close method - */ - public close(code?: number, reason?: string): void { - this.readyState = SOCKET_STATES.closing; - setTimeout(() => { - this.readyState = SOCKET_STATES.closed; - if (this.onclose) { - this.onclose({ code: code || 1000, reason: reason || "Normal closure" }); - } - }, 0); - } - - /** - * Simulate receiving a message (for testing) - */ - public simulateMessage(data: any): void { - if (this.onmessage && this.isConnected) { - const messageEvent = { - data: typeof data === "string" ? data : JSON.stringify(data), - type: "message", - }; - this.onmessage(messageEvent); - } - } - - /** - * Simulate receiving binary data (for testing) - */ - public simulateBinaryMessage(data: ArrayBuffer | Buffer): void { - if (this.onmessage && this.isConnected) { - const messageEvent = { - data: data instanceof Buffer ? data.buffer : data, - type: "message", - }; - this.onmessage(messageEvent); - } - } - - /** - * Simulate a connection error (for testing) - */ - public simulateError(message: string = "Connection error"): void { - if (this.onerror) { - this.onerror({ type: "error", message }); - } - } - - /** - * Get all messages that were sent (for testing assertions) - */ - public getSentMessages(): any[] { - return [...this.sendBuffer]; - } - - /** - * Clear the send buffer (for testing cleanup) - */ - public clearSentMessages(): void { - this.sendBuffer = []; - } - - /** - * Check if WebSocket is in a connected state - */ - public isOpen(): boolean { - return this.readyState === SOCKET_STATES.open; - } -} - -/** - * Creates a MockWebSocket constructor that can be used in tests - */ -export function createMockWebSocketConstructor(): typeof MockWebSocket { - return MockWebSocket; -} - -/** - * Helper function to create a mock WebSocket instance - */ -export function createMockWebSocket(url: string = "wss://api.deepgram.com"): MockWebSocket { - return new MockWebSocket(url); -} - -/** - * WebSocket scenario simulator for different test cases - */ -export class WebSocketScenario { - private mockWebSocket: MockWebSocket; - - constructor(mockWebSocket: MockWebSocket) { - this.mockWebSocket = mockWebSocket; - } - - /** - * Simulate a successful listen transcription scenario - */ - public async simulateListenTranscription(): Promise { - // Wait for connection - await this.waitForConnection(); - - // Send metadata first - this.mockWebSocket.simulateMessage(mockWebSocketData.listen.metadata); - - // Send speech started - this.mockWebSocket.simulateMessage(mockWebSocketData.listen.speechStarted); - - // Send transcript - this.mockWebSocket.simulateMessage(mockWebSocketData.listen.transcript); - - // Send utterance end - this.mockWebSocket.simulateMessage(mockWebSocketData.listen.utteranceEnd); - } - - /** - * Simulate a speak TTS scenario - */ - public async simulateSpeakTTS(): Promise { - // Wait for connection - await this.waitForConnection(); - - // Send metadata - this.mockWebSocket.simulateMessage(mockWebSocketData.speak.metadata); - - // Send audio data - this.mockWebSocket.simulateBinaryMessage(mockAudioData); - - // Send flushed - this.mockWebSocket.simulateMessage(mockWebSocketData.speak.flushed); - } - - /** - * Simulate an agent conversation scenario - */ - public async simulateAgentConversation(): Promise { - // Wait for connection - await this.waitForConnection(); - - // Send welcome - this.mockWebSocket.simulateMessage(mockWebSocketData.agent.welcome); - - // User speaks - this.mockWebSocket.simulateMessage(mockWebSocketData.agent.conversationText); - - // Agent thinks - this.mockWebSocket.simulateMessage(mockWebSocketData.agent.agentThinking); - - // Agent starts speaking - this.mockWebSocket.simulateMessage(mockWebSocketData.agent.agentStartedSpeaking); - - // Send audio - this.mockWebSocket.simulateBinaryMessage(mockAudioData); - - // Agent done - this.mockWebSocket.simulateMessage(mockWebSocketData.agent.agentAudioDone); - } - - /** - * Simulate a function call scenario - */ - public async simulateFunctionCall(): Promise { - // Wait for connection - await this.waitForConnection(); - - // Send welcome - this.mockWebSocket.simulateMessage(mockWebSocketData.agent.welcome); - - // Send function call request - this.mockWebSocket.simulateMessage(mockWebSocketData.agent.functionCallRequest); - } - - /** - * Wait for WebSocket connection to be established - */ - private async waitForConnection(): Promise { - return new Promise((resolve, reject) => { - if (this.mockWebSocket.isOpen()) { - resolve(); - return; - } - - let timeoutId: NodeJS.Timeout | null = null; - let intervalId: NodeJS.Timeout | null = null; - - // Set up timeout to reject if connection doesn't open within 5 seconds - timeoutId = setTimeout(() => { - if (intervalId) { - clearInterval(intervalId); - } - reject(new Error("WebSocket connection timeout: Connection did not open within 5 seconds")); - }, 5000); - - // Poll for connection with cleanup on success - const checkConnection = () => { - if (this.mockWebSocket.isOpen()) { - if (timeoutId) { - clearTimeout(timeoutId); - } - if (intervalId) { - clearInterval(intervalId); - } - resolve(); - } - }; - - // Start polling every 10ms - intervalId = setInterval(checkConnection, 10); - }); - } -} diff --git a/tests/custom.test.ts b/tests/custom.test.ts new file mode 100644 index 00000000..7f5e031c --- /dev/null +++ b/tests/custom.test.ts @@ -0,0 +1,13 @@ +/** + * This is a custom test file, if you wish to add more tests + * to your SDK. + * Be sure to mark this file in `.fernignore`. + * + * If you include example requests/responses in your fern definition, + * you will have tests automatically generated for you. + */ +describe("test", () => { + it("default", () => { + expect(true).toBe(true); + }); +}); diff --git a/tests/e2e/__mocks__/auth.ts b/tests/e2e/__mocks__/auth.ts deleted file mode 100644 index a7c032d6..00000000 --- a/tests/e2e/__mocks__/auth.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Mock response data for Auth API endpoints - */ - -export const mockGrantTokenResponse = { - access_token: - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", - expires_in: 28800, -}; diff --git a/tests/e2e/__mocks__/listen.ts b/tests/e2e/__mocks__/listen.ts deleted file mode 100644 index d761d74f..00000000 --- a/tests/e2e/__mocks__/listen.ts +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Mock response data for Listen API endpoints - * Based on actual Deepgram API response structure - */ - -import type { AsyncPrerecordedResponse } from "../../../src/lib/types"; - -export const mockTranscribeFileResponse = { - metadata: { - transaction_key: "mock-transaction-key", - request_id: "mock-request-id-5678", - sha256: "mock-file-sha256-hash", - created: "2024-01-15T10:35:00.000Z", - duration: 25.933313, - channels: 1, - models: ["mock-model-uuid"], - model_info: { - "mock-model-uuid": { - name: "general-nova-3", - version: "2024-01-01.0", - arch: "nova-3", - }, - }, - }, - results: { - channels: [ - { - alternatives: [ - { - transcript: - "Yeah. As much as it's worth celebrating the first spacewalk with an all female team, I think many of us are looking forward to it just being normal. And I think if it signifies anything, it is to honor the women who came before us who were skilled and qualified and didn't get the same opportunities that we have today.", - confidence: 0.9983989, - words: [ - { - word: "yeah", - start: 0.0, - end: 0.48, - confidence: 0.99592936, - punctuated_word: "Yeah.", - }, - { - word: "as", - start: 0.48, - end: 0.64, - confidence: 0.994148, - punctuated_word: "As", - }, - { - word: "much", - start: 1.12, - end: 1.36, - confidence: 0.99942505, - punctuated_word: "much", - }, - // Truncated for brevity - this would contain all words - ], - paragraphs: { - transcript: - "Yeah. As much as it's worth celebrating the first spacewalk with an all female team, I think many of us are looking forward to it just being normal. And I think if it signifies anything, it is to honor the women who came before us who were skilled and qualified and didn't get the same opportunities that we have today.", - paragraphs: [ - { - sentences: [ - { - text: "Yeah.", - start: 0.0, - end: 0.48, - }, - { - text: "As much as it's worth celebrating the first spacewalk with an all female team, I think many of us are looking forward to it just being normal.", - start: 0.48, - end: 12.4, - }, - { - text: "And I think if it signifies anything, it is to honor the women who came before us who were skilled and qualified and didn't get the same opportunities that we have today.", - start: 12.795, - end: 25.355, - }, - ], - start: 0.0, - end: 25.355, - num_words: 62, - }, - ], - }, - }, - ], - }, - ], - }, -}; - -export const mockTranscribeUrlResponse = { - metadata: { - transaction_key: "mock-transaction-key", - request_id: "mock-request-id-1234", - sha256: "mock-sha256-hash", - created: "2024-01-15T10:30:00.000Z", - duration: 25.933313, - channels: 1, - models: ["mock-model-uuid"], - model_info: { - "mock-model-uuid": { - name: "general-nova-3", - version: "2024-01-01.0", - arch: "nova-3", - }, - }, - }, - results: { - channels: [ - { - alternatives: [ - { - transcript: - "Yeah. As much as it's worth celebrating the first spacewalk with an all female team, I think many of us are looking forward to it just being normal. And I think if it signifies anything, it is to honor the women who came before us who were skilled and qualified and didn't get the same opportunities that we have today.", - confidence: 0.9983989, - words: [ - { - word: "yeah", - start: 0.0, - end: 0.48, - confidence: 0.99592936, - punctuated_word: "Yeah.", - }, - { - word: "as", - start: 0.48, - end: 0.64, - confidence: 0.994148, - punctuated_word: "As", - }, - { - word: "much", - start: 1.12, - end: 1.36, - confidence: 0.99942505, - punctuated_word: "much", - }, - // Truncated for brevity - this would contain all words - ], - paragraphs: { - transcript: - "Yeah. As much as it's worth celebrating the first spacewalk with an all female team, I think many of us are looking forward to it just being normal. And I think if it signifies anything, it is to honor the women who came before us who were skilled and qualified and didn't get the same opportunities that we have today.", - paragraphs: [ - { - sentences: [ - { - text: "Yeah.", - start: 0.0, - end: 0.48, - }, - { - text: "As much as it's worth celebrating the first spacewalk with an all female team, I think many of us are looking forward to it just being normal.", - start: 0.48, - end: 12.4, - }, - { - text: "And I think if it signifies anything, it is to honor the women who came before us who were skilled and qualified and didn't get the same opportunities that we have today.", - start: 12.795, - end: 25.355, - }, - ], - start: 0.0, - end: 25.355, - num_words: 62, - }, - ], - }, - }, - ], - }, - ], - }, -}; - -export const mockAsyncListenUrlResponse: AsyncPrerecordedResponse = { - request_id: "async-550e8400-e29b-41d4-a716-446655440002", -}; - -export const mockAsyncListenFileResponse: AsyncPrerecordedResponse = { - request_id: "async-550e8400-e29b-41d4-a716-446655440003", -}; diff --git a/tests/e2e/__mocks__/manage.ts b/tests/e2e/__mocks__/manage.ts deleted file mode 100644 index 0ee7bad5..00000000 --- a/tests/e2e/__mocks__/manage.ts +++ /dev/null @@ -1,322 +0,0 @@ -/** - * Mock responses for Manage API endpoints - */ - -import type { - GetProjectsResponse, - GetProjectResponse, - MessageResponse, - GetProjectKeysResponse, - GetProjectKeyResponse, - CreateProjectKeyResponse, - GetProjectMembersResponse, - GetProjectMemberScopesResponse, - GetProjectInvitesResponse, - GetProjectUsageRequestsResponse, - GetProjectUsageRequestResponse, - GetProjectUsageSummaryResponse, - GetProjectUsageFieldsResponse, - GetProjectBalancesResponse, - GetProjectBalanceResponse, - GetModelsResponse, - GetModelResponse, - GetTokenDetailsResponse, - VoidResponse, -} from "../../../src/lib/types"; - -// Projects -export const mockGetProjectsResponse: GetProjectsResponse = { - projects: [ - { - project_id: "test-project-123", - name: "Test Project", - }, - { - project_id: "test-project-456", - name: "Another Project", - }, - ], -}; - -export const mockGetProjectResponse: GetProjectResponse = { - project_id: "test-project-123", - name: "Test Project", - company: "Test Company", -}; - -export const mockUpdateProjectResponse: MessageResponse = { - message: "Project updated successfully", -}; - -export const mockLeaveProjectResponse: MessageResponse = { - message: "Successfully left project", -}; - -// Keys -export const mockGetProjectKeysResponse: GetProjectKeysResponse = { - api_keys: [ - { - member: { - member_id: "test-member-123", - email: "test@example.com", - first_name: "Test", - last_name: "User", - }, - api_key: { - api_key_id: "test-key-123", - comment: "Test API key", - scopes: ["usage:write", "usage:read"], - created: "2024-01-01T00:00:00.000Z", - }, - }, - { - member: { - member_id: "test-member-456", - email: "another@example.com", - first_name: "Another", - last_name: "User", - }, - api_key: { - api_key_id: "test-key-456", - comment: "Another API key", - scopes: ["usage:read"], - created: "2024-01-02T00:00:00.000Z", - }, - }, - ], -}; - -export const mockGetProjectKeyResponse: GetProjectKeyResponse = { - member: { - member_id: "test-member-123", - email: "test@example.com", - first_name: "Test", - last_name: "User", - }, - api_key: { - api_key_id: "test-key-123", - comment: "Test API key", - scopes: ["usage:write", "usage:read"], - created: "2024-01-01T00:00:00.000Z", - }, -}; - -export const mockCreateProjectKeyResponse: CreateProjectKeyResponse = { - api_key_id: "test-key-new-789", - key: "ak_test_key_1234567890abcdef", - comment: "Test API key for e2e testing", - scopes: ["usage:write", "usage:read"], - created: "2024-01-01T00:00:00.000Z", -}; - -// Members -export const mockGetProjectMembersResponse: GetProjectMembersResponse = { - members: [ - { - member_id: "test-member-123", - email: "test@example.com", - first_name: "Test", - last_name: "User", - scopes: ["admin"], - }, - { - member_id: "test-member-456", - email: "another@example.com", - first_name: "Another", - last_name: "User", - scopes: ["member"], - }, - ], -}; - -export const mockGetProjectMemberScopesResponse: GetProjectMemberScopesResponse = { - scopes: ["member"], -}; - -export const mockUpdateProjectMemberScopeResponse: MessageResponse = { - message: "Member scope updated successfully", -}; - -// Invites -export const mockGetProjectInvitesResponse: GetProjectInvitesResponse = { - invites: [ - { - email: "invited@example.com", - scope: "member", - }, - ], -}; - -export const mockSendProjectInviteResponse: MessageResponse = { - message: "Invite sent successfully", -}; - -// Usage Requests -export const mockGetProjectUsageRequestsResponse: GetProjectUsageRequestsResponse = { - page: 0, - limit: 10, - requests: [ - { - request_id: "test-request-123", - created: "2024-01-01T00:00:00.000Z", - path: "/v1/listen", - api_key_id: "test-key-123", - response: { - code: 200, - completed: "2024-01-01T00:00:05.000Z", - details: { - usd: 0.0045, - duration: 30.5, - total_audio: 30.5, - channels: 1, - models: ["nova-2"], - method: "POST", - }, - }, - }, - { - request_id: "test-request-456", - created: "2024-01-01T01:00:00.000Z", - path: "/v1/speak", - api_key_id: "test-key-123", - response: { - code: 200, - completed: "2024-01-01T01:00:02.000Z", - details: { - usd: 0.002, - models: ["aura-thalia-en"], - method: "POST", - }, - }, - }, - ], -}; - -export const mockGetProjectUsageRequestResponse: GetProjectUsageRequestResponse = { - request_id: "test-request-123", - created: "2024-01-01T00:00:00.000Z", - path: "/v1/listen", - api_key_id: "test-key-123", - response: { - code: 200, - completed: "2024-01-01T00:00:05.000Z", - details: { - usd: 0.0045, - duration: 30.5, - total_audio: 30.5, - channels: 1, - models: ["nova-2"], - method: "POST", - }, - }, -}; - -export const mockGetProjectUsageSummaryResponse: GetProjectUsageSummaryResponse = { - start: "2024-01-01", - end: "2024-01-31", - resolution: { - units: "day", - amount: 1, - }, - results: [ - { - start: "2024-01-01", - end: "2024-01-31", - hours: 10.5, - total_hours: 10.5, - requests: 50, - }, - ], -}; - -export const mockGetProjectUsageFieldsResponse: GetProjectUsageFieldsResponse = { - tags: ["test", "production"], - models: [], - processing_methods: ["sync", "async"], - languages: ["en", "es", "fr"], - features: ["smart_format", "punctuate", "diarize"], -}; - -// Balances -export const mockGetProjectBalancesResponse: GetProjectBalancesResponse = { - balances: [ - { - balance_id: "test-balance-123", - amount: 100.5, - units: "usd", - purchase: "test-purchase-123", - }, - { - balance_id: "test-balance-456", - amount: 50.25, - units: "usd", - purchase: "test-purchase-456", - }, - ], -}; - -export const mockGetProjectBalanceResponse: GetProjectBalanceResponse = { - balance_id: "test-balance-123", - amount: 100.5, - units: "usd", - purchase: "test-purchase-123", -}; - -// Project-scoped Models (simplified) -export const mockGetAllProjectModelsResponse: GetModelsResponse = { - stt: [ - { - name: "nova-2", - canonical_name: "nova-2-general", - architecture: "nova-2", - languages: ["en"], - version: "2024-01-01", - uuid: "model-uuid-123", - }, - ], - tts: [ - { - name: "aura-thalia-en", - canonical_name: "aura-thalia-en", - architecture: "aura", - languages: ["en"], - version: "2024-01-01", - uuid: "model-uuid-456", - }, - ], -}; - -export const mockGetProjectModelResponse: GetModelResponse = { - name: "nova-2", - canonical_name: "nova-2-general", - architecture: "nova-2", - languages: ["en"], - version: "2024-01-01", - uuid: "model-uuid-123", -}; - -// Token Details -export const mockGetTokenDetailsResponse: GetTokenDetailsResponse = { - api_key_id: "test-key-123", - scopes: ["usage:write", "usage:read"], - created: "2024-01-01T00:00:00.000Z", -}; - -// Generic void/delete responses -export const mockDeleteProjectResponse: VoidResponse = { - error: null, -}; - -export const mockDeleteProjectKeyResponse: VoidResponse = { - error: null, -}; - -export const mockRemoveProjectMemberResponse: VoidResponse = { - error: null, -}; - -export const mockDeleteProjectInviteResponse: VoidResponse = { - error: null, -}; - -// Note: Other message responses already exist below in the file diff --git a/tests/e2e/__mocks__/models.ts b/tests/e2e/__mocks__/models.ts deleted file mode 100644 index 892f2f50..00000000 --- a/tests/e2e/__mocks__/models.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Mock response data for Models API endpoints - */ - -export const mockGetAllModelsResponse = { - stt: [ - { - name: "nova-2-general", - canonical_name: "nova-2-general", - architecture: "nova-2", - languages: ["en"], - version: "2024-01-09", - uuid: "f58fb2c5-4057-4aa2-a9a7-884ab2b25b48", - batch: true, - streaming: true, - metadata: { - tier: "nova", - }, - }, - { - name: "nova-2-phonecall", - canonical_name: "nova-2-phonecall", - architecture: "nova-2", - languages: ["en"], - version: "2024-01-09", - uuid: "a4c682e4-d5d8-4a2b-9e6c-f7e8d3a1b2c5", - batch: true, - streaming: true, - metadata: { - tier: "nova", - }, - }, - ], - tts: [ - { - name: "aura-2-thalia-en", - canonical_name: "aura-2-thalia-en", - architecture: "aura-2", - languages: ["en"], - version: "2024-01-09", - uuid: "b7d9a3f2-1c4e-5b8a-9d6f-2e3c1a7b4d9e", - metadata: { - tier: "aura", - }, - }, - ], -}; - -export const mockGetModelResponse = { - name: "nova-2-general", - canonical_name: "nova-2-general", - architecture: "nova-2", - languages: ["en"], - version: "2024-01-09", - uuid: "f58fb2c5-4057-4aa2-a9a7-884ab2b25b48", - batch: true, - streaming: true, - metadata: { - tier: "nova", - description: - "Nova-2 General is a powerful, fast, and accurate speech-to-text model for general use cases.", - }, -}; diff --git a/tests/e2e/__mocks__/read.ts b/tests/e2e/__mocks__/read.ts deleted file mode 100644 index f42dda1a..00000000 --- a/tests/e2e/__mocks__/read.ts +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Mock response data for Read API endpoints - */ - -import type { AsyncAnalyzeResponse } from "../../../src/lib/types"; - -export const mockAnalyzeTextResponse = { - metadata: { - request_id: "mock-request-id-123", - created: "2024-01-09T10:00:00.000Z", - language: "en", - intents: { - model_uuid: "mock-intents-model-uuid", - model_name: "intent-classifier-v1", - model_metadata: {}, - }, - sentiment: { - model_uuid: "mock-sentiment-model-uuid", - model_name: "sentiment-analyzer-v1", - model_metadata: {}, - }, - summary: { - model_uuid: "mock-summary-model-uuid", - model_name: "text-summarizer-v1", - model_metadata: {}, - }, - }, - results: { - intents: { - segments: [ - { - text: "Hello world, this is a test.", - start_word: 0, - end_word: 6, - intents: [ - { - intent: "greeting", - confidence: 0.95, - }, - ], - }, - ], - }, - sentiments: { - segments: [ - { - text: "Hello world, this is a test.", - start_word: 0, - end_word: 6, - sentiment: "neutral", - sentiment_score: 0.0, - }, - ], - average: { - sentiment: "neutral", - sentiment_score: 0.0, - }, - }, - summary: { - short: "A simple test greeting message.", - }, - }, -}; - -export const mockAnalyzeUrlResponse = { - metadata: { - request_id: "mock-request-id-456", - created: "2024-01-09T10:00:00.000Z", - language: "en", - intents: { - model_uuid: "mock-intents-model-uuid", - model_name: "intent-classifier-v1", - model_metadata: {}, - }, - sentiment: { - model_uuid: "mock-sentiment-model-uuid", - model_name: "sentiment-analyzer-v1", - model_metadata: {}, - }, - summary: { - model_uuid: "mock-summary-model-uuid", - model_name: "text-summarizer-v1", - model_metadata: {}, - }, - }, - results: { - intents: { - segments: [ - { - text: "Content from URL source for analysis.", - start_word: 0, - end_word: 6, - intents: [ - { - intent: "informational", - confidence: 0.87, - }, - ], - }, - ], - }, - sentiments: { - segments: [ - { - text: "Content from URL source for analysis.", - start_word: 0, - end_word: 6, - sentiment: "neutral", - sentiment_score: 0.1, - }, - ], - average: { - sentiment: "neutral", - sentiment_score: 0.1, - }, - }, - summary: { - short: "Analysis of content from a URL source.", - }, - }, -}; - -export const mockAsyncAnalyzeResponse = { - request_id: "mock-async-request-id-789", -}; - -export const mockAsyncReadUrlResponse: AsyncAnalyzeResponse = { - request_id: "async-read-550e8400-e29b-41d4-a716-446655440004", -}; - -export const mockAsyncReadTextResponse: AsyncAnalyzeResponse = { - request_id: "async-read-550e8400-e29b-41d4-a716-446655440005", -}; diff --git a/tests/e2e/__mocks__/selfhosted.ts b/tests/e2e/__mocks__/selfhosted.ts deleted file mode 100644 index e378ee15..00000000 --- a/tests/e2e/__mocks__/selfhosted.ts +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Mock response data for Self-hosted API endpoints - */ - -export const mockListCredentialsResponse = { - distribution_credentials: [ - { - member: { - member_id: "test-member-123", - email: "test@example.com", - }, - distribution_credentials: { - distribution_credentials_id: "test-credential-123", - comment: "Test credentials for development", - scopes: ["usage:write", "keys:read"], - provider: "test-provider", - created: "2024-01-09T10:00:00.000Z", - }, - }, - { - member: { - member_id: "test-member-456", - email: "prod@example.com", - }, - distribution_credentials: { - distribution_credentials_id: "test-credential-456", - comment: "Production credentials", - scopes: ["usage:write"], - provider: "prod-provider", - created: "2024-01-08T10:00:00.000Z", - }, - }, - ], -}; - -export const mockGetCredentialsResponse = { - member: { - member_id: "test-member-123", - email: "test@example.com", - }, - distribution_credentials: { - distribution_credentials_id: "test-credential-123", - comment: "Test credentials for development", - scopes: ["usage:write", "keys:read"], - provider: "test-provider", - created: "2024-01-09T10:00:00.000Z", - }, -}; - -export const mockCreateCredentialsResponse = { - member: { - member_id: "test-member-new", - email: "new@example.com", - }, - distribution_credentials: { - distribution_credentials_id: "test-credential-new-789", - comment: "Test credentials for e2e testing", - scopes: ["usage:write"], - provider: "test-provider", - created: "2024-01-09T11:00:00.000Z", - }, -}; - -export const mockDeleteCredentialsResponse = { - message: "Credentials successfully deleted", -}; diff --git a/tests/e2e/__mocks__/speak.ts b/tests/e2e/__mocks__/speak.ts deleted file mode 100644 index bcc9006b..00000000 --- a/tests/e2e/__mocks__/speak.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Mock response for Speak API endpoint - * Based on actual Deepgram TTS API response structure - * Since TTS returns binary audio data, we'll simulate this with a mock buffer - */ - -// Create a mock audio buffer that simulates MP3 data -// This is just a minimal mock - real MP3 data would be much larger -export const mockAudioBuffer = Buffer.from([ - // MP3 header bytes (simplified mock) - 0xff, 0xfb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // Some mock audio data - 0x4c, 0x41, 0x4d, 0x45, 0x33, 0x2e, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // Add some more bytes to make it more realistic - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, -]); - -/** - * Mock headers that would be returned by the TTS API - */ -export const mockTTSHeaders = { - "content-type": "audio/mpeg", - "content-length": mockAudioBuffer.length.toString(), - "x-dg-model": "aura-2-thalia-en", - "x-dg-request-id": "mock-tts-request-id-1234", -} as const; diff --git a/tests/e2e/__snapshots__/auth-grant-token.test.ts.snap b/tests/e2e/__snapshots__/auth-grant-token.test.ts.snap deleted file mode 100644 index 1485e542..00000000 --- a/tests/e2e/__snapshots__/auth-grant-token.test.ts.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`auth grantToken E2E should generate a temporary access token: auth-grantToken-response-structure 1`] = ` -{ - "access_token": "", - "expires_in": "" -} -`; diff --git a/tests/e2e/__snapshots__/listen-transcribe-file-callback.test.ts.snap b/tests/e2e/__snapshots__/listen-transcribe-file-callback.test.ts.snap deleted file mode 100644 index 37906ff1..00000000 --- a/tests/e2e/__snapshots__/listen-transcribe-file-callback.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`listen transcribeFileCallback E2E should transcribe file with callback and return async response: listen-transcribe-file-callback-response-structure 1`] = ` -{ - "error": null, - "result": { - "request_id": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/listen-transcribe-file.test.ts.snap b/tests/e2e/__snapshots__/listen-transcribe-file.test.ts.snap deleted file mode 100644 index 2a80afa1..00000000 --- a/tests/e2e/__snapshots__/listen-transcribe-file.test.ts.snap +++ /dev/null @@ -1,62 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`listen transcribeFile E2E should transcribe audio from file and match expected response structure: listen-transcribeFile-response-structure 1`] = ` -{ - "metadata": { - "channels": "", - "created": "", - "duration": "", - "model_info": { - "mock-model-uuid": { - "arch": "", - "name": "", - "version": "" - } - }, - "models": [ - "" - ], - "request_id": "", - "sha256": "", - "transaction_key": "" - }, - "results": { - "channels": [ - { - "alternatives": [ - { - "confidence": "", - "paragraphs": { - "paragraphs": [ - { - "end": "", - "num_words": "", - "sentences": [ - { - "end": "", - "start": "", - "text": "" - } - ], - "start": "" - } - ], - "transcript": "" - }, - "transcript": "", - "words": [ - { - "confidence": "", - "end": "", - "punctuated_word": "", - "start": "", - "word": "" - } - ] - } - ] - } - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/listen-transcribe-url-callback.test.ts.snap b/tests/e2e/__snapshots__/listen-transcribe-url-callback.test.ts.snap deleted file mode 100644 index 1c406824..00000000 --- a/tests/e2e/__snapshots__/listen-transcribe-url-callback.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`listen transcribeUrlCallback E2E should transcribe URL with callback and return async response: listen-transcribe-url-callback-response-structure 1`] = ` -{ - "error": null, - "result": { - "request_id": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/listen-transcribe-url.test.ts.snap b/tests/e2e/__snapshots__/listen-transcribe-url.test.ts.snap deleted file mode 100644 index 77f31f4e..00000000 --- a/tests/e2e/__snapshots__/listen-transcribe-url.test.ts.snap +++ /dev/null @@ -1,62 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`listen transcribeUrl E2E should transcribe audio from URL and match expected response structure: listen-transcribeUrl-response-structure 1`] = ` -{ - "metadata": { - "channels": "", - "created": "", - "duration": "", - "model_info": { - "mock-model-uuid": { - "arch": "", - "name": "", - "version": "" - } - }, - "models": [ - "" - ], - "request_id": "", - "sha256": "", - "transaction_key": "" - }, - "results": { - "channels": [ - { - "alternatives": [ - { - "confidence": "", - "paragraphs": { - "paragraphs": [ - { - "end": "", - "num_words": "", - "sentences": [ - { - "end": "", - "start": "", - "text": "" - } - ], - "start": "" - } - ], - "transcript": "" - }, - "transcript": "", - "words": [ - { - "confidence": "", - "end": "", - "punctuated_word": "", - "start": "", - "word": "" - } - ] - } - ] - } - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-create-project-key.test.ts.snap b/tests/e2e/__snapshots__/manage-create-project-key.test.ts.snap deleted file mode 100644 index 347fc1d7..00000000 --- a/tests/e2e/__snapshots__/manage-create-project-key.test.ts.snap +++ /dev/null @@ -1,16 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage createProjectKey E2E should create a new API key for a specific project: manage-createProjectKey-response-structure 1`] = ` -{ - "error": null, - "result": { - "api_key_id": "", - "comment": "", - "created": "", - "key": "", - "scopes": [ - "" - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-all-models.test.ts.snap b/tests/e2e/__snapshots__/manage-get-all-models.test.ts.snap deleted file mode 100644 index f9d22c17..00000000 --- a/tests/e2e/__snapshots__/manage-get-all-models.test.ts.snap +++ /dev/null @@ -1,59 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getAllModels E2E should get all project models with basic options: manage-getAllModels-basic-response-structure 1`] = ` -{ - "stt": [ - { - "architecture": "", - "canonical_name": "", - "languages": [ - "" - ], - "name": "", - "uuid": "", - "version": "" - } - ], - "tts": [ - { - "architecture": "", - "canonical_name": "", - "languages": [ - "" - ], - "name": "", - "uuid": "", - "version": "" - } - ] -} -`; - -exports[`manage getAllModels E2E should get all project models with filtered options: manage-getAllModels-filtered-response-structure 1`] = ` -{ - "stt": [ - { - "architecture": "", - "canonical_name": "", - "languages": [ - "" - ], - "name": "", - "uuid": "", - "version": "" - } - ], - "tts": [ - { - "architecture": "", - "canonical_name": "", - "languages": [ - "" - ], - "name": "", - "uuid": "", - "version": "" - } - ] -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-model.test.ts.snap b/tests/e2e/__snapshots__/manage-get-model.test.ts.snap deleted file mode 100644 index b352c151..00000000 --- a/tests/e2e/__snapshots__/manage-get-model.test.ts.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getModel E2E should get a different project model: manage-getModel-tts-response-structure 1`] = ` -{ - "architecture": "", - "canonical_name": "", - "languages": [ - "" - ], - "name": "", - "uuid": "", - "version": "" -} -`; - -exports[`manage getModel E2E should get a specific project model: manage-getModel-stt-response-structure 1`] = ` -{ - "architecture": "", - "canonical_name": "", - "languages": [ - "" - ], - "name": "", - "uuid": "", - "version": "" -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-balance.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-balance.test.ts.snap deleted file mode 100644 index 24cfb38c..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-balance.test.ts.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectBalance E2E should retrieve a specific project balance by ID: manage-getProjectBalance-response-structure 1`] = ` -{ - "error": null, - "result": { - "amount": "", - "balance_id": "", - "purchase": "", - "units": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-balances.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-balances.test.ts.snap deleted file mode 100644 index 6ac4b536..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-balances.test.ts.snap +++ /dev/null @@ -1,17 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectBalances E2E should retrieve all project balances for a specific project: manage-getProjectBalances-response-structure 1`] = ` -{ - "error": null, - "result": { - "balances": [ - { - "amount": "", - "balance_id": "", - "purchase": "", - "units": "" - } - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-invites.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-invites.test.ts.snap deleted file mode 100644 index 2bd60d89..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-invites.test.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectInvites E2E should retrieve all project invitations for a specific project: manage-getProjectInvites-response-structure 1`] = ` -{ - "error": null, - "result": { - "invites": [ - { - "email": "", - "scope": "" - } - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-key.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-key.test.ts.snap deleted file mode 100644 index 4011ae06..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-key.test.ts.snap +++ /dev/null @@ -1,23 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectKey E2E should retrieve a specific project key by ID: manage-getProjectKey-response-structure 1`] = ` -{ - "error": null, - "result": { - "api_key": { - "api_key_id": "", - "comment": "", - "created": "", - "scopes": [ - "" - ] - }, - "member": { - "email": "", - "first_name": "", - "last_name": "", - "member_id": "" - } - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-keys.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-keys.test.ts.snap deleted file mode 100644 index 64e1dfbf..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-keys.test.ts.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectKeys E2E should retrieve all project keys for a specific project: manage-getProjectKeys-response-structure 1`] = ` -{ - "error": null, - "result": { - "api_keys": [ - { - "api_key": { - "api_key_id": "", - "comment": "", - "created": "", - "scopes": [ - "" - ] - }, - "member": { - "email": "", - "first_name": "", - "last_name": "", - "member_id": "" - } - } - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-member-scopes.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-member-scopes.test.ts.snap deleted file mode 100644 index b303ff7a..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-member-scopes.test.ts.snap +++ /dev/null @@ -1,12 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectMemberScopes E2E should retrieve member scopes for a specific project member: manage-getProjectMemberScopes-response-structure 1`] = ` -{ - "error": null, - "result": { - "scopes": [ - "" - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-members.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-members.test.ts.snap deleted file mode 100644 index 69c25d66..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-members.test.ts.snap +++ /dev/null @@ -1,20 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectMembers E2E should retrieve all project members for a specific project: manage-getProjectMembers-response-structure 1`] = ` -{ - "error": null, - "result": { - "members": [ - { - "email": "", - "first_name": "", - "last_name": "", - "member_id": "", - "scopes": [ - "" - ] - } - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-usage-fields.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-usage-fields.test.ts.snap deleted file mode 100644 index 8b232681..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-usage-fields.test.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectUsageFields E2E should retrieve usage fields for a specific project with basic options: manage-getProjectUsageFields-response-structure 1`] = ` -{ - "error": null, - "result": { - "features": [ - "" - ], - "languages": [ - "" - ], - "models": [], - "processing_methods": [ - "" - ], - "tags": [ - "" - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-usage-request.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-usage-request.test.ts.snap deleted file mode 100644 index 8f2294d9..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-usage-request.test.ts.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectUsageRequest E2E should retrieve a specific usage request by ID: manage-getProjectUsageRequest-response-structure 1`] = ` -{ - "error": null, - "result": { - "api_key_id": "", - "created": "", - "path": "", - "request_id": "", - "response": { - "code": "", - "completed": "", - "details": { - "channels": "", - "duration": "", - "method": "", - "models": [ - "" - ], - "total_audio": "", - "usd": "" - } - } - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-usage-requests.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-usage-requests.test.ts.snap deleted file mode 100644 index 7859d535..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-usage-requests.test.ts.snap +++ /dev/null @@ -1,33 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectUsageRequests E2E should retrieve usage requests for a specific project with basic options: manage-getProjectUsageRequests-response-structure 1`] = ` -{ - "error": null, - "result": { - "limit": "", - "page": "", - "requests": [ - { - "api_key_id": "", - "created": "", - "path": "", - "request_id": "", - "response": { - "code": "", - "completed": "", - "details": { - "channels": "", - "duration": "", - "method": "", - "models": [ - "" - ], - "total_audio": "", - "usd": "" - } - } - } - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project-usage-summary.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project-usage-summary.test.ts.snap deleted file mode 100644 index 577381a2..00000000 --- a/tests/e2e/__snapshots__/manage-get-project-usage-summary.test.ts.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjectUsageSummary E2E should retrieve usage summary for a specific project with basic options: manage-getProjectUsageSummary-response-structure 1`] = ` -{ - "error": null, - "result": { - "end": "", - "resolution": { - "amount": "", - "units": "" - }, - "results": [ - { - "end": "", - "hours": "", - "requests": "", - "start": "", - "total_hours": "" - } - ], - "start": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-project.test.ts.snap b/tests/e2e/__snapshots__/manage-get-project.test.ts.snap deleted file mode 100644 index f3354099..00000000 --- a/tests/e2e/__snapshots__/manage-get-project.test.ts.snap +++ /dev/null @@ -1,12 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProject E2E should retrieve a specific project by ID: manage-getProject-response-structure 1`] = ` -{ - "error": null, - "result": { - "company": "", - "name": "", - "project_id": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-projects.test.ts.snap b/tests/e2e/__snapshots__/manage-get-projects.test.ts.snap deleted file mode 100644 index 506dc02d..00000000 --- a/tests/e2e/__snapshots__/manage-get-projects.test.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getProjects E2E should retrieve all projects for the authenticated user: manage-getProjects-response-structure 1`] = ` -{ - "error": null, - "result": { - "projects": [ - { - "name": "", - "project_id": "" - } - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-get-token-details.test.ts.snap b/tests/e2e/__snapshots__/manage-get-token-details.test.ts.snap deleted file mode 100644 index 9fddca15..00000000 --- a/tests/e2e/__snapshots__/manage-get-token-details.test.ts.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage getTokenDetails E2E should retrieve token details for the authenticated user: manage-getTokenDetails-response-structure 1`] = ` -{ - "error": null, - "result": { - "api_key_id": "", - "created": "", - "scopes": [ - "" - ] - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-leave-project.test.ts.snap b/tests/e2e/__snapshots__/manage-leave-project.test.ts.snap deleted file mode 100644 index d2d2009c..00000000 --- a/tests/e2e/__snapshots__/manage-leave-project.test.ts.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage leaveProject E2E should leave a project: manage-leaveProject-response-structure 1`] = ` -{ - "message": "" -} -`; diff --git a/tests/e2e/__snapshots__/manage-send-project-invite.test.ts.snap b/tests/e2e/__snapshots__/manage-send-project-invite.test.ts.snap deleted file mode 100644 index d57806d0..00000000 --- a/tests/e2e/__snapshots__/manage-send-project-invite.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage sendProjectInvite E2E should send a project invitation to a single email: manage-sendProjectInvite-response-structure 1`] = ` -{ - "error": null, - "result": { - "message": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-update-project-member-scope.test.ts.snap b/tests/e2e/__snapshots__/manage-update-project-member-scope.test.ts.snap deleted file mode 100644 index 4105150c..00000000 --- a/tests/e2e/__snapshots__/manage-update-project-member-scope.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage updateProjectMemberScope E2E should update a project member's scope: manage-updateProjectMemberScope-response-structure 1`] = ` -{ - "error": null, - "result": { - "message": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/manage-update-project.test.ts.snap b/tests/e2e/__snapshots__/manage-update-project.test.ts.snap deleted file mode 100644 index 479b0fa6..00000000 --- a/tests/e2e/__snapshots__/manage-update-project.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`manage updateProject E2E should update a project with new details: manage-updateProject-response-structure 1`] = ` -{ - "error": null, - "result": { - "message": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/models-get-all.test.ts.snap b/tests/e2e/__snapshots__/models-get-all.test.ts.snap deleted file mode 100644 index 850c322b..00000000 --- a/tests/e2e/__snapshots__/models-get-all.test.ts.snap +++ /dev/null @@ -1,38 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`models getAll E2E should retrieve all available models: models-getAll-response-structure 1`] = ` -{ - "stt": [ - { - "architecture": "", - "batch": "", - "canonical_name": "", - "languages": [ - "" - ], - "metadata": { - "tier": "" - }, - "name": "", - "streaming": "", - "uuid": "", - "version": "" - } - ], - "tts": [ - { - "architecture": "", - "canonical_name": "", - "languages": [ - "" - ], - "metadata": { - "tier": "" - }, - "name": "", - "uuid": "", - "version": "" - } - ] -} -`; diff --git a/tests/e2e/__snapshots__/models-get-model.test.ts.snap b/tests/e2e/__snapshots__/models-get-model.test.ts.snap deleted file mode 100644 index 99a0984c..00000000 --- a/tests/e2e/__snapshots__/models-get-model.test.ts.snap +++ /dev/null @@ -1,20 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`models getModel E2E should retrieve specific model information: models-getModel-response-structure 1`] = ` -{ - "architecture": "", - "batch": "", - "canonical_name": "", - "languages": [ - "" - ], - "metadata": { - "description": "", - "tier": "" - }, - "name": "", - "streaming": "", - "uuid": "", - "version": "" -} -`; diff --git a/tests/e2e/__snapshots__/read-analyze-text-callback.test.ts.snap b/tests/e2e/__snapshots__/read-analyze-text-callback.test.ts.snap deleted file mode 100644 index 009dcf83..00000000 --- a/tests/e2e/__snapshots__/read-analyze-text-callback.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`read analyzeTextCallback E2E should analyze text with callback and return async response: read-analyze-text-callback-response-structure 1`] = ` -{ - "error": null, - "result": { - "request_id": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/read-analyze-text.test.ts.snap b/tests/e2e/__snapshots__/read-analyze-text.test.ts.snap deleted file mode 100644 index dc7b90b0..00000000 --- a/tests/e2e/__snapshots__/read-analyze-text.test.ts.snap +++ /dev/null @@ -1,61 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`read analyzeText E2E should analyze text synchronously: read-analyzeText-response-structure 1`] = ` -{ - "metadata": { - "created": "", - "intents": { - "model_metadata": {}, - "model_name": "", - "model_uuid": "" - }, - "language": "", - "request_id": "", - "sentiment": { - "model_metadata": {}, - "model_name": "", - "model_uuid": "" - }, - "summary": { - "model_metadata": {}, - "model_name": "", - "model_uuid": "" - } - }, - "results": { - "intents": { - "segments": [ - { - "end_word": "", - "intents": [ - { - "confidence": "", - "intent": "" - } - ], - "start_word": "", - "text": "" - } - ] - }, - "sentiments": { - "average": { - "sentiment": "", - "sentiment_score": "" - }, - "segments": [ - { - "end_word": "", - "sentiment": "", - "sentiment_score": "", - "start_word": "", - "text": "" - } - ] - }, - "summary": { - "short": "" - } - } -} -`; diff --git a/tests/e2e/__snapshots__/read-analyze-url-callback.test.ts.snap b/tests/e2e/__snapshots__/read-analyze-url-callback.test.ts.snap deleted file mode 100644 index 3d6f1426..00000000 --- a/tests/e2e/__snapshots__/read-analyze-url-callback.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`read analyzeUrlCallback E2E should analyze URL with callback and return async response: read-analyze-url-callback-response-structure 1`] = ` -{ - "error": null, - "result": { - "request_id": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/read-analyze-url.test.ts.snap b/tests/e2e/__snapshots__/read-analyze-url.test.ts.snap deleted file mode 100644 index abb6fc5f..00000000 --- a/tests/e2e/__snapshots__/read-analyze-url.test.ts.snap +++ /dev/null @@ -1,61 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`read analyzeUrl E2E should analyze URL source synchronously: read-analyzeUrl-response-structure 1`] = ` -{ - "metadata": { - "created": "", - "intents": { - "model_metadata": {}, - "model_name": "", - "model_uuid": "" - }, - "language": "", - "request_id": "", - "sentiment": { - "model_metadata": {}, - "model_name": "", - "model_uuid": "" - }, - "summary": { - "model_metadata": {}, - "model_name": "", - "model_uuid": "" - } - }, - "results": { - "intents": { - "segments": [ - { - "end_word": "", - "intents": [ - { - "confidence": "", - "intent": "" - } - ], - "start_word": "", - "text": "" - } - ] - }, - "sentiments": { - "average": { - "sentiment": "", - "sentiment_score": "" - }, - "segments": [ - { - "end_word": "", - "sentiment": "", - "sentiment_score": "", - "start_word": "", - "text": "" - } - ] - }, - "summary": { - "short": "" - } - } -} -`; diff --git a/tests/e2e/__snapshots__/selfhosted-create-credentials.test.ts.snap b/tests/e2e/__snapshots__/selfhosted-create-credentials.test.ts.snap deleted file mode 100644 index 85c7e330..00000000 --- a/tests/e2e/__snapshots__/selfhosted-create-credentials.test.ts.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`selfhosted createCredentials E2E should create new self-hosted credentials: selfhosted-createCredentials-response-structure 1`] = ` -{ - "distribution_credentials": { - "comment": "", - "created": "", - "distribution_credentials_id": "", - "provider": "", - "scopes": [ - "" - ] - }, - "member": { - "email": "", - "member_id": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/selfhosted-delete-credentials.test.ts.snap b/tests/e2e/__snapshots__/selfhosted-delete-credentials.test.ts.snap deleted file mode 100644 index 2dd4566b..00000000 --- a/tests/e2e/__snapshots__/selfhosted-delete-credentials.test.ts.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`selfhosted deleteCredentials E2E should delete self-hosted credentials: selfhosted-deleteCredentials-response-structure 1`] = ` -{ - "message": "" -} -`; diff --git a/tests/e2e/__snapshots__/selfhosted-get-credentials.test.ts.snap b/tests/e2e/__snapshots__/selfhosted-get-credentials.test.ts.snap deleted file mode 100644 index 2bb675fa..00000000 --- a/tests/e2e/__snapshots__/selfhosted-get-credentials.test.ts.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`selfhosted getCredentials E2E should retrieve specific self-hosted credentials: selfhosted-getCredentials-response-structure 1`] = ` -{ - "distribution_credentials": { - "comment": "", - "created": "", - "distribution_credentials_id": "", - "provider": "", - "scopes": [ - "" - ] - }, - "member": { - "email": "", - "member_id": "" - } -} -`; diff --git a/tests/e2e/__snapshots__/selfhosted-list-credentials.test.ts.snap b/tests/e2e/__snapshots__/selfhosted-list-credentials.test.ts.snap deleted file mode 100644 index bc7b3ef8..00000000 --- a/tests/e2e/__snapshots__/selfhosted-list-credentials.test.ts.snap +++ /dev/null @@ -1,23 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`selfhosted listCredentials E2E should list self-hosted credentials: selfhosted-listCredentials-response-structure 1`] = ` -{ - "distribution_credentials": [ - { - "distribution_credentials": { - "comment": "", - "created": "", - "distribution_credentials_id": "", - "provider": "", - "scopes": [ - "" - ] - }, - "member": { - "email": "", - "member_id": "" - } - } - ] -} -`; diff --git a/tests/e2e/__snapshots__/speak-request.test.ts.snap b/tests/e2e/__snapshots__/speak-request.test.ts.snap deleted file mode 100644 index 57513a96..00000000 --- a/tests/e2e/__snapshots__/speak-request.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`speak request E2E should generate speech from text and return audio data: speak-request-response-headers 1`] = ` -{ - "content-length": "", - "content-type": "", - "x-dg-model": "", - "x-dg-request-id": "" -} -`; diff --git a/tests/e2e/agent-live-connection.test.ts b/tests/e2e/agent-live-connection.test.ts deleted file mode 100644 index cc515762..00000000 --- a/tests/e2e/agent-live-connection.test.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { AgentLiveClient } from "../../src/packages/AgentLiveClient"; -import { AgentEvents } from "../../src/lib/enums/AgentEvents"; -import { CONNECTION_STATE } from "../../src/lib/constants"; -import { MockWebSocket, WebSocketScenario, mockWebSocketData } from "../__utils__/websocket-mocks"; - -// Helper to wait for events -function waitForEvent(emitter: any, eventName: string, timeout = 2000): Promise { - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - reject(new Error(`Event '${eventName}' did not fire within ${timeout}ms`)); - }, timeout); - - emitter.once(eventName, (data: any) => { - clearTimeout(timer); - resolve(data); - }); - }); -} - -// Helper to collect multiple events -function collectEvents(emitter: any, eventNames: string[], timeout = 3000): Promise { - return new Promise((resolve, reject) => { - const results: any[] = []; - const received = new Set(); - - const timer = setTimeout(() => { - reject( - new Error( - `Not all events received within ${timeout}ms. Missing: ${eventNames.filter( - (name) => !received.has(name) - )}` - ) - ); - }, timeout); - - eventNames.forEach((eventName) => { - emitter.on(eventName, (data: any) => { - if (!received.has(eventName)) { - received.add(eventName); - results.push({ event: eventName, data }); - - if (received.size === eventNames.length) { - clearTimeout(timer); - resolve(results); - } - } - }); - }); - }); -} - -describe("agent live connection E2E", () => { - let mockWebSocketInstance: MockWebSocket; - let client: AgentLiveClient; - - // Custom WebSocket constructor that captures the instance - const createMockWebSocketConstructor = () => { - return class MockWebSocketConstructor extends MockWebSocket { - constructor(url: string, protocols?: string | string[], options?: any) { - super(url, protocols, options); - // Store instance for test access - mockWebSocketInstance = this as MockWebSocket; - } - }; - }; - - beforeEach(() => { - const MockWebSocketConstructor = createMockWebSocketConstructor(); - - client = new AgentLiveClient({ - key: "test-api-key", - global: { - websocket: { - // @ts-expect-error - Using mock for testing - client: MockWebSocketConstructor, - }, - }, - }); - }); - - afterEach(() => { - if (client) { - client.disconnect(); - } - }); - - it("should handle complete agent conversation workflow", async () => { - await waitForEvent(client, AgentEvents.Open); - - expect(client.connectionState()).toBe(CONNECTION_STATE.Open); - expect(mockWebSocketInstance.url).toContain("agent"); - - // Set up event collectors for conversation workflow - const eventsPromise = collectEvents(client, [ - AgentEvents.Welcome, - AgentEvents.ConversationText, - AgentEvents.AgentThinking, - AgentEvents.AgentStartedSpeaking, - AgentEvents.Audio, - AgentEvents.AgentAudioDone, - ]); - - // Simulate complete conversation - const scenario = new WebSocketScenario(mockWebSocketInstance); - await scenario.simulateAgentConversation(); - - const events = await eventsPromise; - expect(events).toHaveLength(6); - - const eventMap = events.reduce((acc, { event, data }) => { - acc[event] = data; - return acc; - }, {}); - - expect(eventMap[AgentEvents.Welcome]).toEqual(mockWebSocketData.agent.welcome); - expect(eventMap[AgentEvents.ConversationText]).toEqual( - mockWebSocketData.agent.conversationText - ); - expect(eventMap[AgentEvents.AgentThinking]).toEqual(mockWebSocketData.agent.agentThinking); - expect(eventMap[AgentEvents.AgentStartedSpeaking]).toEqual( - mockWebSocketData.agent.agentStartedSpeaking - ); - expect(eventMap[AgentEvents.Audio]).toBeInstanceOf(Buffer); - expect(eventMap[AgentEvents.AgentAudioDone]).toEqual(mockWebSocketData.agent.agentAudioDone); - }); - - it("should handle function call interaction workflow", async () => { - await waitForEvent(client, AgentEvents.Open); - - // Set up event collectors for function call scenario - const eventsPromise = collectEvents(client, [ - AgentEvents.Welcome, - AgentEvents.FunctionCallRequest, - ]); - - // Simulate function call scenario - const scenario = new WebSocketScenario(mockWebSocketInstance); - await scenario.simulateFunctionCall(); - - const events = await eventsPromise; - expect(events).toHaveLength(2); - - const functionCallEvent = events.find((e) => e.event === AgentEvents.FunctionCallRequest); - expect(functionCallEvent.data).toEqual(mockWebSocketData.agent.functionCallRequest); - expect(functionCallEvent.data.functions).toHaveLength(1); - expect(functionCallEvent.data.functions[0].name).toBe("get_weather"); - }); - - it("should handle bidirectional audio communication", async () => { - await waitForEvent(client, AgentEvents.Open); - - // Simulate sending user audio to agent - const userAudio1 = new ArrayBuffer(1024); - const userAudio2 = new ArrayBuffer(2048); - - client.send(userAudio1); - client.send(userAudio2); - - // Send keepAlive during conversation - client.keepAlive(); - - const sentMessages = mockWebSocketInstance.getSentMessages(); - expect(sentMessages).toContain(userAudio1); - expect(sentMessages).toContain(userAudio2); - expect(sentMessages).toContain(JSON.stringify({ type: "KeepAlive" })); - }); -}); diff --git a/tests/e2e/auth-grant-token.test.ts b/tests/e2e/auth-grant-token.test.ts deleted file mode 100644 index 0d51a9c4..00000000 --- a/tests/e2e/auth-grant-token.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { createClient } from "../../src/index"; -import { AuthRestClient } from "../../src/packages/AuthRestClient"; -import { DeepgramError } from "../../src/lib/errors"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; - -describe("auth grantToken E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should generate a temporary access token", async () => { - const { result, error } = await deepgram.auth.grantToken(); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - // Type guard to ensure result is not null for subsequent operations - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("auth-grantToken-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("access_token"); - expect(result).toHaveProperty("expires_in"); - - // Verify data types and format - expect(typeof result.access_token).toBe("string"); - expect(typeof result.expires_in).toBe("number"); - - // Verify access token is a non-empty string (should be JWT format in real API) - expect(result.access_token.length).toBeGreaterThan(0); - - // Verify expires_in is a positive number (typically in seconds) - expect(result.expires_in).toBeGreaterThan(0); - }, 30000); - - it("should handle custom endpoint for token generation", async () => { - const customEndpoint = ":version/auth/grant"; - const { result, error } = await deepgram.auth.grantToken({}, customEndpoint); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Verify the response structure is consistent - expect(result).toHaveProperty("access_token"); - expect(result).toHaveProperty("expires_in"); - expect(typeof result.access_token).toBe("string"); - expect(typeof result.expires_in).toBe("number"); - }, 30000); - - it("should generate token with custom ttl_seconds", async () => { - const { result, error } = await deepgram.auth.grantToken({ ttl_seconds: 60 }); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Verify the response structure is consistent - expect(result).toHaveProperty("access_token"); - expect(result).toHaveProperty("expires_in"); - expect(typeof result.access_token).toBe("string"); - expect(typeof result.expires_in).toBe("number"); - - // Verify access token is a non-empty string - expect(result.access_token.length).toBeGreaterThan(0); - expect(result.expires_in).toBeGreaterThan(0); - }, 30000); - - it("should handle ttl_seconds with custom endpoint", async () => { - const customEndpoint = ":version/auth/grant"; - const { result, error } = await deepgram.auth.grantToken({ ttl_seconds: 120 }, customEndpoint); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Verify the response structure is consistent - expect(result).toHaveProperty("access_token"); - expect(result).toHaveProperty("expires_in"); - expect(typeof result.access_token).toBe("string"); - expect(typeof result.expires_in).toBe("number"); - }, 30000); - - it("should handle empty options object (backward compatibility)", async () => { - const { result, error } = await deepgram.auth.grantToken({}); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Verify the response structure is consistent - expect(result).toHaveProperty("access_token"); - expect(result).toHaveProperty("expires_in"); - expect(typeof result.access_token).toBe("string"); - expect(typeof result.expires_in).toBe("number"); - }, 30000); - - it("should handle DeepgramError and return it in response", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const authClient = new AuthRestClient({ key: apiKey }); - - // Mock the post method to throw a DeepgramError - const mockError = new DeepgramError("Test DeepgramError"); - jest.spyOn(authClient as any, "post").mockRejectedValue(mockError); - - const { result, error } = await authClient.grantToken(); - - expect(result).toBeNull(); - expect(error).toBe(mockError); - expect(error).toBeInstanceOf(DeepgramError); - - // Clean up spy - jest.restoreAllMocks(); - }); - - it("should re-throw non-DeepgramError", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const authClient = new AuthRestClient({ key: apiKey }); - - // Mock the post method to throw a regular Error - const mockError = new Error("Network error"); - jest.spyOn(authClient as any, "post").mockRejectedValue(mockError); - - await expect(authClient.grantToken()).rejects.toThrow("Network error"); - await expect(authClient.grantToken()).rejects.toThrow(Error); - - // Clean up spy - jest.restoreAllMocks(); - }); -}); diff --git a/tests/e2e/listen-live-connection.test.ts b/tests/e2e/listen-live-connection.test.ts deleted file mode 100644 index b20f6563..00000000 --- a/tests/e2e/listen-live-connection.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { ListenLiveClient } from "../../src/packages/ListenLiveClient"; -import { LiveTranscriptionEvents } from "../../src/lib/enums/LiveTranscriptionEvents"; -import { CONNECTION_STATE } from "../../src/lib/constants"; -import { MockWebSocket, WebSocketScenario, mockWebSocketData } from "../__utils__/websocket-mocks"; - -// Helper to wait for events -function waitForEvent(emitter: any, eventName: string, timeout = 2000): Promise { - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - reject(new Error(`Event '${eventName}' did not fire within ${timeout}ms`)); - }, timeout); - - emitter.once(eventName, (data: any) => { - clearTimeout(timer); - resolve(data); - }); - }); -} - -// Helper to collect multiple events -function collectEvents(emitter: any, eventNames: string[], timeout = 3000): Promise { - return new Promise((resolve, reject) => { - const results: any[] = []; - const received = new Set(); - - const timer = setTimeout(() => { - reject( - new Error( - `Not all events received within ${timeout}ms. Missing: ${eventNames.filter( - (name) => !received.has(name) - )}` - ) - ); - }, timeout); - - eventNames.forEach((eventName) => { - emitter.on(eventName, (data: any) => { - if (!received.has(eventName)) { - received.add(eventName); - results.push({ event: eventName, data }); - - if (received.size === eventNames.length) { - clearTimeout(timer); - resolve(results); - } - } - }); - }); - }); -} - -describe("listen live connection E2E", () => { - let mockWebSocketInstance: MockWebSocket; - let client: ListenLiveClient; - - // Custom WebSocket constructor that captures the instance - const createMockWebSocketConstructor = () => { - return class MockWebSocketConstructor extends MockWebSocket { - constructor(url: string, protocols?: string | string[], options?: any) { - super(url, protocols, options); - // Store instance for test access - mockWebSocketInstance = this as MockWebSocket; - } - }; - }; - - beforeEach(() => { - const MockWebSocketConstructor = createMockWebSocketConstructor(); - - client = new ListenLiveClient({ - key: "test-api-key", - global: { - websocket: { - // @ts-expect-error - Using mock for testing - client: MockWebSocketConstructor, - }, - }, - }); - }); - - afterEach(() => { - if (client) { - client.disconnect(); - } - }); - - it("should establish WebSocket connection and handle full transcription workflow", async () => { - // Wait for connection to establish - const connectionPromise = waitForEvent(client, LiveTranscriptionEvents.Open); - await connectionPromise; - - expect(client.connectionState()).toBe(CONNECTION_STATE.Open); - expect(mockWebSocketInstance.url).toContain("listen"); - expect(mockWebSocketInstance.isOpen()).toBe(true); - - // Set up event collectors for the full workflow - const eventsPromise = collectEvents(client, [ - LiveTranscriptionEvents.Metadata, - LiveTranscriptionEvents.SpeechStarted, - LiveTranscriptionEvents.Transcript, - LiveTranscriptionEvents.UtteranceEnd, - ]); - - // Simulate a complete transcription session - const scenario = new WebSocketScenario(mockWebSocketInstance); - await scenario.simulateListenTranscription(); - - // Verify all events were received in order - const events = await eventsPromise; - expect(events).toHaveLength(4); - - const eventMap = events.reduce((acc, { event, data }) => { - acc[event] = data; - return acc; - }, {}); - - expect(eventMap[LiveTranscriptionEvents.Metadata]).toEqual(mockWebSocketData.listen.metadata); - expect(eventMap[LiveTranscriptionEvents.SpeechStarted]).toEqual( - mockWebSocketData.listen.speechStarted - ); - expect(eventMap[LiveTranscriptionEvents.Transcript]).toEqual( - mockWebSocketData.listen.transcript - ); - expect(eventMap[LiveTranscriptionEvents.UtteranceEnd]).toEqual( - mockWebSocketData.listen.utteranceEnd - ); - }); - - it("should handle real-time audio streaming simulation", async () => { - await waitForEvent(client, LiveTranscriptionEvents.Open); - - // Simulate sending audio chunks - const audioChunk1 = new ArrayBuffer(1024); - const audioChunk2 = new ArrayBuffer(2048); - const audioChunk3 = new ArrayBuffer(512); - - client.send(audioChunk1); - client.send(audioChunk2); - client.send(audioChunk3); - - const sentMessages = mockWebSocketInstance.getSentMessages(); - expect(sentMessages).toContain(audioChunk1); - expect(sentMessages).toContain(audioChunk2); - expect(sentMessages).toContain(audioChunk3); - expect(sentMessages).toHaveLength(3); - }); - - it("should handle connection interruption and recovery", async () => { - await waitForEvent(client, LiveTranscriptionEvents.Open); - - // Simulate connection loss - const closePromise = waitForEvent(client, LiveTranscriptionEvents.Close); - mockWebSocketInstance.close(1006, "Connection lost"); - - const closeEvent = await closePromise; - expect(closeEvent.code).toBe(1006); - expect(client.connectionState()).toBe(CONNECTION_STATE.Closed); - - // Verify reconnect capability exists - expect(typeof client.reconnect).toBe("function"); - }); - - it("should handle keepAlive mechanism for long sessions", async () => { - await waitForEvent(client, LiveTranscriptionEvents.Open); - - // Simulate periodic keepAlive calls - client.keepAlive(); - client.keepAlive(); - client.keepAlive(); - - const sentMessages = mockWebSocketInstance.getSentMessages(); - const keepAliveMessages = sentMessages.filter( - (msg) => msg === JSON.stringify({ type: "KeepAlive" }) - ); - expect(keepAliveMessages).toHaveLength(3); - }); - - it("should handle graceful session termination", async () => { - await waitForEvent(client, LiveTranscriptionEvents.Open); - - // Send close stream request - client.requestClose(); - - const sentMessages = mockWebSocketInstance.getSentMessages(); - expect(sentMessages).toContain(JSON.stringify({ type: "CloseStream" })); - - // Disconnect the client - client.disconnect(); - - // Check final connection state - expect(client.connectionState()).toBe(CONNECTION_STATE.Closed); - }); -}); diff --git a/tests/e2e/listen-transcribe-file-callback.test.ts b/tests/e2e/listen-transcribe-file-callback.test.ts deleted file mode 100644 index 8d9886bc..00000000 --- a/tests/e2e/listen-transcribe-file-callback.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { callbackUrls, testAudioFiles, transcriptionOptions } from "../__fixtures__/listen"; -import type { DeepgramResponse, AsyncPrerecordedResponse } from "../../src/lib/types"; -import { CallbackUrl } from "../../src/lib/helpers"; -import { readFileSync } from "fs"; -import { resolve } from "path"; - -describe("listen transcribeFileCallback E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should transcribe file with callback and return async response", async () => { - const audioFile = readFileSync( - resolve(__dirname, "..", "__fixtures__", testAudioFiles.spacewalk) - ); - - const response: DeepgramResponse = - await deepgram.listen.prerecorded.transcribeFileCallback( - audioFile, - new CallbackUrl(callbackUrls.webhook), - transcriptionOptions.basic - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("request_id"); - expect(typeof response.result.request_id).toBe("string"); - expect(response.result.request_id.length).toBeGreaterThan(0); - } - - expect(response).toMatchSnapshot("listen-transcribe-file-callback-response-structure"); - }); - - it("should handle enhanced options with callback", async () => { - const audioFile = readFileSync( - resolve(__dirname, "..", "__fixtures__", testAudioFiles.spacewalk) - ); - - const response: DeepgramResponse = - await deepgram.listen.prerecorded.transcribeFileCallback( - audioFile, - new CallbackUrl(callbackUrls.testEndpoint), - transcriptionOptions.enhanced - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.request_id).toBeDefined(); - expect(typeof response.result.request_id).toBe("string"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/listen-transcribe-file.test.ts b/tests/e2e/listen-transcribe-file.test.ts deleted file mode 100644 index d55ff5c3..00000000 --- a/tests/e2e/listen-transcribe-file.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testAudioFiles, commonTranscriptionOptions } from "../__fixtures__/listen"; -import * as fs from "fs"; -import * as path from "path"; - -describe("listen transcribeFile E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should transcribe audio from file and match expected response structure", async () => { - const audioFilePath = path.join(__dirname, "../__fixtures__", testAudioFiles.spacewalk); - - // Verify the test file exists - expect(fs.existsSync(audioFilePath)).toBe(true); - - // Read the audio file - const audioBuffer = fs.readFileSync(audioFilePath); - - const { result, error } = await deepgram.listen.prerecorded.transcribeFile( - audioBuffer, - commonTranscriptionOptions - ); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - // Type guard to ensure result is not null for subsequent operations - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot (using custom serializer for non-deterministic content) - expect(result).toMatchSnapshot("listen-transcribeFile-response-structure"); - - // Essential structural validation - verify we have the required properties - expect(result.metadata).toBeDefined(); - expect(result.results).toBeDefined(); - expect(Array.isArray(result.results.channels)).toBe(true); - expect(result.results.channels.length).toBeGreaterThan(0); - - // Verify we got actual transcription content - const transcript = result.results.channels[0]?.alternatives?.[0]?.transcript; - expect(transcript).toBeTruthy(); - expect(typeof transcript).toBe("string"); - expect(transcript.length).toBeGreaterThan(0); - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/listen-transcribe-url-callback.test.ts b/tests/e2e/listen-transcribe-url-callback.test.ts deleted file mode 100644 index 73044bce..00000000 --- a/tests/e2e/listen-transcribe-url-callback.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { callbackUrls, urlSources, transcriptionOptions } from "../__fixtures__/listen"; -import type { DeepgramResponse, AsyncPrerecordedResponse } from "../../src/lib/types"; -import { CallbackUrl } from "../../src/lib/helpers"; - -describe("listen transcribeUrlCallback E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should transcribe URL with callback and return async response", async () => { - const response: DeepgramResponse = - await deepgram.listen.prerecorded.transcribeUrlCallback( - urlSources.spacewalk, - new CallbackUrl(callbackUrls.webhook), - transcriptionOptions.basic - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("request_id"); - expect(typeof response.result.request_id).toBe("string"); - expect(response.result.request_id.length).toBeGreaterThan(0); - } - - expect(response).toMatchSnapshot("listen-transcribe-url-callback-response-structure"); - }); - - it("should handle enhanced options with callback", async () => { - const response: DeepgramResponse = - await deepgram.listen.prerecorded.transcribeUrlCallback( - urlSources.spacewalk, - new CallbackUrl(callbackUrls.testEndpoint), - transcriptionOptions.enhanced - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.request_id).toBeDefined(); - expect(typeof response.result.request_id).toBe("string"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/listen-transcribe-url.test.ts b/tests/e2e/listen-transcribe-url.test.ts deleted file mode 100644 index 54ad0c8b..00000000 --- a/tests/e2e/listen-transcribe-url.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { urlSources, commonTranscriptionOptions } from "../__fixtures__/listen"; - -describe("listen transcribeUrl E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should transcribe audio from URL and match expected response structure", async () => { - const { result, error } = await deepgram.listen.prerecorded.transcribeUrl( - urlSources.spacewalk, - commonTranscriptionOptions - ); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - // Type guard to ensure result is not null for subsequent operations - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot (using custom serializer for non-deterministic content) - expect(result).toMatchSnapshot("listen-transcribeUrl-response-structure"); - - // Essential structural validation - verify we have the required properties - expect(result.metadata).toBeDefined(); - expect(result.results).toBeDefined(); - expect(Array.isArray(result.results.channels)).toBe(true); - expect(result.results.channels.length).toBeGreaterThan(0); - - // Verify we got actual transcription content - const transcript = result.results.channels[0]?.alternatives?.[0]?.transcript; - expect(transcript).toBeTruthy(); - expect(typeof transcript).toBe("string"); - expect(transcript.length).toBeGreaterThan(0); - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-create-project-key.test.ts b/tests/e2e/manage-create-project-key.test.ts deleted file mode 100644 index 95c59268..00000000 --- a/tests/e2e/manage-create-project-key.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, keyOptions } from "../__fixtures__/manage"; -import type { DeepgramResponse, CreateProjectKeyResponse } from "../../src/lib/types"; - -describe("manage createProjectKey E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should create a new API key for a specific project", async () => { - const response: DeepgramResponse = - await deepgram.manage.createProjectKey(testProjectIds.primary, keyOptions.create); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("api_key_id"); - expect(response.result).toHaveProperty("key"); - expect(response.result).toHaveProperty("comment"); - expect(response.result).toHaveProperty("scopes"); - expect(response.result).toHaveProperty("created"); - - expect(typeof response.result.api_key_id).toBe("string"); - expect(typeof response.result.key).toBe("string"); - expect(typeof response.result.comment).toBe("string"); - expect(typeof response.result.created).toBe("string"); - expect(Array.isArray(response.result.scopes)).toBe(true); - - // Verify the key has the correct format (starts with "ak_") - expect(response.result.key).toMatch(/^ak_/); - } - - expect(response).toMatchSnapshot("manage-createProjectKey-response-structure"); - }); - - it("should create a minimal API key with just comment", async () => { - const response: DeepgramResponse = - await deepgram.manage.createProjectKey(testProjectIds.primary, keyOptions.createMinimal); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("api_key_id"); - expect(response.result).toHaveProperty("key"); - expect(response.result).toHaveProperty("comment"); - expect(typeof response.result.comment).toBe("string"); - } - }); - - it("should handle custom endpoint for createProjectKey", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/keys`; - const response: DeepgramResponse = - await deepgram.manage.createProjectKey( - testProjectIds.primary, - keyOptions.create, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("api_key_id"); - expect(response.result).toHaveProperty("key"); - expect(response.result.key).toMatch(/^ak_/); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-delete-project-invite.test.ts b/tests/e2e/manage-delete-project-invite.test.ts deleted file mode 100644 index dbf90dd8..00000000 --- a/tests/e2e/manage-delete-project-invite.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { createClient } from "../../src/index"; -import { setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testEmails } from "../__fixtures__/manage"; - -describe("manage deleteProjectInvite E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - setupApiMocks(); - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - }); - - afterAll(() => { - cleanupApiMocks(); - }); - - it("should delete a project invite", async () => { - const { error } = await deepgram.manage.deleteProjectInvite( - testProjectIds.primary, - testEmails.toDelete - ); - - expect(error).toBeNull(); - }); -}); diff --git a/tests/e2e/manage-delete-project-key.test.ts b/tests/e2e/manage-delete-project-key.test.ts deleted file mode 100644 index ac7183bb..00000000 --- a/tests/e2e/manage-delete-project-key.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { createClient } from "../../src/index"; -import { setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testKeyIds } from "../__fixtures__/manage"; - -describe("manage deleteProjectKey E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - setupApiMocks(); - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - }); - - afterAll(() => { - cleanupApiMocks(); - }); - - it("should delete a project key", async () => { - const { error } = await deepgram.manage.deleteProjectKey( - testProjectIds.primary, - testKeyIds.toDelete - ); - - expect(error).toBeNull(); - }); -}); diff --git a/tests/e2e/manage-delete-project.test.ts b/tests/e2e/manage-delete-project.test.ts deleted file mode 100644 index 441d75b2..00000000 --- a/tests/e2e/manage-delete-project.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createClient } from "../../src/index"; -import { setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds } from "../__fixtures__/manage"; - -describe("manage deleteProject E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - setupApiMocks(); - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - }); - - afterAll(() => { - cleanupApiMocks(); - }); - - it("should delete a project", async () => { - const { error } = await deepgram.manage.deleteProject(testProjectIds.toDelete); - - expect(error).toBeNull(); - }); -}); diff --git a/tests/e2e/manage-get-all-models.test.ts b/tests/e2e/manage-get-all-models.test.ts deleted file mode 100644 index 56828b39..00000000 --- a/tests/e2e/manage-get-all-models.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, modelOptions } from "../__fixtures__/manage"; - -describe("manage getAllModels E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - setupApiMocks(); - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - cleanupApiMocks(); - }); - - it("should get all project models with basic options", async () => { - const { result, error } = await deepgram.manage.getAllModels( - testProjectIds.primary, - modelOptions.basic - ); - - expect(error).toBeNull(); - expect(result).toMatchSnapshot("manage-getAllModels-basic-response-structure"); - }); - - it("should get all project models with filtered options", async () => { - const { result, error } = await deepgram.manage.getAllModels( - testProjectIds.primary, - modelOptions.withFilters - ); - - expect(error).toBeNull(); - expect(result).toMatchSnapshot("manage-getAllModels-filtered-response-structure"); - }); -}); diff --git a/tests/e2e/manage-get-model.test.ts b/tests/e2e/manage-get-model.test.ts deleted file mode 100644 index 41151602..00000000 --- a/tests/e2e/manage-get-model.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testModelIds } from "../__fixtures__/manage"; - -describe("manage getModel E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - setupApiMocks(); - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - cleanupApiMocks(); - }); - - it("should get a specific project model", async () => { - const { result, error } = await deepgram.manage.getModel( - testProjectIds.primary, - testModelIds.sttModel - ); - - expect(error).toBeNull(); - expect(result).toMatchSnapshot("manage-getModel-stt-response-structure"); - }); - - it("should get a different project model", async () => { - const { result, error } = await deepgram.manage.getModel( - testProjectIds.primary, - testModelIds.ttsModel - ); - - expect(error).toBeNull(); - expect(result).toMatchSnapshot("manage-getModel-tts-response-structure"); - }); -}); diff --git a/tests/e2e/manage-get-project-balance.test.ts b/tests/e2e/manage-get-project-balance.test.ts deleted file mode 100644 index 8ff02684..00000000 --- a/tests/e2e/manage-get-project-balance.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testBalanceIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectBalanceResponse } from "../../src/lib/types"; - -describe("manage getProjectBalance E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve a specific project balance by ID", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectBalance(testProjectIds.primary, testBalanceIds.balance1); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("balance_id"); - expect(response.result).toHaveProperty("amount"); - expect(response.result).toHaveProperty("units"); - expect(response.result).toHaveProperty("purchase"); - - expect(typeof response.result.balance_id).toBe("string"); - expect(typeof response.result.amount).toBe("number"); - expect(typeof response.result.units).toBe("string"); - expect(typeof response.result.purchase).toBe("string"); - } - - expect(response).toMatchSnapshot("manage-getProjectBalance-response-structure"); - }); - - it("should handle custom endpoint for getProjectBalance", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/balances/${testBalanceIds.balance1}`; - const response: DeepgramResponse = - await deepgram.manage.getProjectBalance( - testProjectIds.primary, - testBalanceIds.balance1, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("balance_id"); - expect(response.result).toHaveProperty("amount"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-balances.test.ts b/tests/e2e/manage-get-project-balances.test.ts deleted file mode 100644 index d1a4e301..00000000 --- a/tests/e2e/manage-get-project-balances.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectBalancesResponse } from "../../src/lib/types"; - -describe("manage getProjectBalances E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve all project balances for a specific project", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectBalances(testProjectIds.primary); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("balances"); - expect(Array.isArray(response.result.balances)).toBe(true); - - // Verify balance structure if any balances exist - if (response.result.balances.length > 0) { - const balance = response.result.balances[0]; - expect(balance).toHaveProperty("balance_id"); - expect(balance).toHaveProperty("amount"); - expect(balance).toHaveProperty("units"); - expect(balance).toHaveProperty("purchase"); - - expect(typeof balance.balance_id).toBe("string"); - expect(typeof balance.amount).toBe("number"); - expect(typeof balance.units).toBe("string"); - expect(typeof balance.purchase).toBe("string"); - } - } - - expect(response).toMatchSnapshot("manage-getProjectBalances-response-structure"); - }); - - it("should handle custom endpoint for getProjectBalances", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/balances`; - const response: DeepgramResponse = - await deepgram.manage.getProjectBalances(testProjectIds.primary, customEndpoint); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.balances).toBeDefined(); - expect(Array.isArray(response.result.balances)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-invites.test.ts b/tests/e2e/manage-get-project-invites.test.ts deleted file mode 100644 index d60a4794..00000000 --- a/tests/e2e/manage-get-project-invites.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectInvitesResponse } from "../../src/lib/types"; - -describe("manage getProjectInvites E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve all project invitations for a specific project", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectInvites(testProjectIds.primary); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("invites"); - expect(Array.isArray(response.result.invites)).toBe(true); - - // Verify invite structure if any invites exist - if (response.result.invites.length > 0) { - const invite = response.result.invites[0]; - expect(invite).toHaveProperty("email"); - expect(invite).toHaveProperty("scope"); - - expect(typeof invite.email).toBe("string"); - expect(typeof invite.scope).toBe("string"); - } - } - - expect(response).toMatchSnapshot("manage-getProjectInvites-response-structure"); - }); - - it("should handle custom endpoint for getProjectInvites", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/invites`; - const response: DeepgramResponse = - await deepgram.manage.getProjectInvites(testProjectIds.primary, customEndpoint); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.invites).toBeDefined(); - expect(Array.isArray(response.result.invites)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-key.test.ts b/tests/e2e/manage-get-project-key.test.ts deleted file mode 100644 index 9abcffb1..00000000 --- a/tests/e2e/manage-get-project-key.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testKeyIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectKeyResponse } from "../../src/lib/types"; - -describe("manage getProjectKey E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve a specific project key by ID", async () => { - const response: DeepgramResponse = await deepgram.manage.getProjectKey( - testProjectIds.primary, - testKeyIds.key1 - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("member"); - expect(response.result).toHaveProperty("api_key"); - - expect(response.result.member).toHaveProperty("member_id"); - expect(response.result.member).toHaveProperty("email"); - - expect(response.result.api_key).toHaveProperty("api_key_id"); - expect(response.result.api_key).toHaveProperty("comment"); - expect(response.result.api_key).toHaveProperty("scopes"); - expect(response.result.api_key).toHaveProperty("created"); - - expect(Array.isArray(response.result.api_key.scopes)).toBe(true); - } - - expect(response).toMatchSnapshot("manage-getProjectKey-response-structure"); - }); - - it("should handle custom endpoint for getProjectKey", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/keys/${testKeyIds.key1}`; - const response: DeepgramResponse = await deepgram.manage.getProjectKey( - testProjectIds.primary, - testKeyIds.key1, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("member"); - expect(response.result).toHaveProperty("api_key"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-keys.test.ts b/tests/e2e/manage-get-project-keys.test.ts deleted file mode 100644 index 63eeb05b..00000000 --- a/tests/e2e/manage-get-project-keys.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectKeysResponse } from "../../src/lib/types"; - -describe("manage getProjectKeys E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve all project keys for a specific project", async () => { - const response: DeepgramResponse = await deepgram.manage.getProjectKeys( - testProjectIds.primary - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("api_keys"); - expect(Array.isArray(response.result.api_keys)).toBe(true); - - // Verify key structure if any keys exist - if (response.result.api_keys.length > 0) { - const key = response.result.api_keys[0]; - expect(key).toHaveProperty("member"); - expect(key).toHaveProperty("api_key"); - - expect(key.member).toHaveProperty("member_id"); - expect(key.member).toHaveProperty("email"); - - expect(key.api_key).toHaveProperty("api_key_id"); - expect(key.api_key).toHaveProperty("comment"); - expect(key.api_key).toHaveProperty("scopes"); - expect(key.api_key).toHaveProperty("created"); - - expect(Array.isArray(key.api_key.scopes)).toBe(true); - } - } - - expect(response).toMatchSnapshot("manage-getProjectKeys-response-structure"); - }); - - it("should handle custom endpoint for getProjectKeys", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/keys`; - const response: DeepgramResponse = await deepgram.manage.getProjectKeys( - testProjectIds.primary, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.api_keys).toBeDefined(); - expect(Array.isArray(response.result.api_keys)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-member-scopes.test.ts b/tests/e2e/manage-get-project-member-scopes.test.ts deleted file mode 100644 index 57c0365f..00000000 --- a/tests/e2e/manage-get-project-member-scopes.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testMemberIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectMemberScopesResponse } from "../../src/lib/types"; - -describe("manage getProjectMemberScopes E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve member scopes for a specific project member", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectMemberScopes(testProjectIds.primary, testMemberIds.member1); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("scopes"); - expect(Array.isArray(response.result.scopes)).toBe(true); - - // Verify scope values if any scopes exist - if (response.result.scopes.length > 0) { - response.result.scopes.forEach((scope) => { - expect(typeof scope).toBe("string"); - }); - } - } - - expect(response).toMatchSnapshot("manage-getProjectMemberScopes-response-structure"); - }); - - it("should handle custom endpoint for getProjectMemberScopes", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/members/${testMemberIds.member1}/scopes`; - const response: DeepgramResponse = - await deepgram.manage.getProjectMemberScopes( - testProjectIds.primary, - testMemberIds.member1, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.scopes).toBeDefined(); - expect(Array.isArray(response.result.scopes)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-members.test.ts b/tests/e2e/manage-get-project-members.test.ts deleted file mode 100644 index 8b2dcd6d..00000000 --- a/tests/e2e/manage-get-project-members.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectMembersResponse } from "../../src/lib/types"; - -describe("manage getProjectMembers E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve all project members for a specific project", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectMembers(testProjectIds.primary); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("members"); - expect(Array.isArray(response.result.members)).toBe(true); - - // Verify member structure if any members exist - if (response.result.members.length > 0) { - const member = response.result.members[0]; - expect(member).toHaveProperty("member_id"); - expect(member).toHaveProperty("email"); - expect(member).toHaveProperty("first_name"); - expect(member).toHaveProperty("last_name"); - expect(member).toHaveProperty("scopes"); - - expect(typeof member.member_id).toBe("string"); - expect(typeof member.email).toBe("string"); - expect(Array.isArray(member.scopes)).toBe(true); - } - } - - expect(response).toMatchSnapshot("manage-getProjectMembers-response-structure"); - }); - - it("should handle custom endpoint for getProjectMembers", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/members`; - const response: DeepgramResponse = - await deepgram.manage.getProjectMembers(testProjectIds.primary, customEndpoint); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.members).toBeDefined(); - expect(Array.isArray(response.result.members)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-usage-fields.test.ts b/tests/e2e/manage-get-project-usage-fields.test.ts deleted file mode 100644 index 81b5e50d..00000000 --- a/tests/e2e/manage-get-project-usage-fields.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, usageFieldsOptions } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectUsageFieldsResponse } from "../../src/lib/types"; - -describe("manage getProjectUsageFields E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve usage fields for a specific project with basic options", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageFields(testProjectIds.primary, usageFieldsOptions.basic); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("tags"); - expect(response.result).toHaveProperty("models"); - expect(response.result).toHaveProperty("processing_methods"); - expect(response.result).toHaveProperty("languages"); - expect(response.result).toHaveProperty("features"); - - expect(Array.isArray(response.result.tags)).toBe(true); - expect(Array.isArray(response.result.models)).toBe(true); - expect(Array.isArray(response.result.processing_methods)).toBe(true); - expect(Array.isArray(response.result.languages)).toBe(true); - expect(Array.isArray(response.result.features)).toBe(true); - } - - expect(response).toMatchSnapshot("manage-getProjectUsageFields-response-structure"); - }); - - it("should handle usage fields with filters", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageFields( - testProjectIds.primary, - usageFieldsOptions.withFilters - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.tags).toBeDefined(); - expect(Array.isArray(response.result.tags)).toBe(true); - } - }); - - it("should handle custom endpoint for getProjectUsageFields", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/usage/fields`; - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageFields( - testProjectIds.primary, - usageFieldsOptions.basic, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.tags).toBeDefined(); - expect(Array.isArray(response.result.tags)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-usage-request.test.ts b/tests/e2e/manage-get-project-usage-request.test.ts deleted file mode 100644 index c2120e52..00000000 --- a/tests/e2e/manage-get-project-usage-request.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testRequestIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectUsageRequestResponse } from "../../src/lib/types"; - -describe("manage getProjectUsageRequest E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve a specific usage request by ID", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageRequest(testProjectIds.primary, testRequestIds.request1); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("request_id"); - expect(response.result).toHaveProperty("created"); - expect(response.result).toHaveProperty("path"); - expect(response.result).toHaveProperty("api_key_id"); - expect(response.result).toHaveProperty("response"); - - expect(typeof response.result.request_id).toBe("string"); - expect(typeof response.result.created).toBe("string"); - expect(typeof response.result.path).toBe("string"); - expect(typeof response.result.api_key_id).toBe("string"); - expect(typeof response.result.response).toBe("object"); - - // Verify response details - if (response.result.response) { - expect(response.result.response).toHaveProperty("code"); - expect(response.result.response).toHaveProperty("completed"); - expect(response.result.response).toHaveProperty("details"); - } - } - - expect(response).toMatchSnapshot("manage-getProjectUsageRequest-response-structure"); - }); - - it("should handle custom endpoint for getProjectUsageRequest", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/requests/${testRequestIds.request1}`; - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageRequest( - testProjectIds.primary, - testRequestIds.request1, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("request_id"); - expect(response.result).toHaveProperty("path"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-usage-requests.test.ts b/tests/e2e/manage-get-project-usage-requests.test.ts deleted file mode 100644 index f1947190..00000000 --- a/tests/e2e/manage-get-project-usage-requests.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, usageRequestOptions } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectUsageRequestsResponse } from "../../src/lib/types"; - -describe("manage getProjectUsageRequests E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve usage requests for a specific project with basic options", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageRequests( - testProjectIds.primary, - usageRequestOptions.basic - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("page"); - expect(response.result).toHaveProperty("limit"); - expect(response.result).toHaveProperty("requests"); - expect(Array.isArray(response.result.requests)).toBe(true); - - // Verify request structure if any requests exist - if (response.result.requests.length > 0) { - const request = response.result.requests[0]; - expect(request).toHaveProperty("request_id"); - expect(request).toHaveProperty("created"); - expect(request).toHaveProperty("path"); - expect(request).toHaveProperty("api_key_id"); - expect(request).toHaveProperty("response"); - - expect(typeof request.request_id).toBe("string"); - expect(typeof request.created).toBe("string"); - expect(typeof request.path).toBe("string"); - expect(typeof request.api_key_id).toBe("string"); - expect(typeof request.response).toBe("object"); - } - } - - expect(response).toMatchSnapshot("manage-getProjectUsageRequests-response-structure"); - }); - - it("should handle usage requests with limit and pagination", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageRequests( - testProjectIds.primary, - usageRequestOptions.withPagination - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.requests).toBeDefined(); - expect(Array.isArray(response.result.requests)).toBe(true); - expect(typeof response.result.page).toBe("number"); - expect(typeof response.result.limit).toBe("number"); - } - }); - - it("should handle custom endpoint for getProjectUsageRequests", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/requests`; - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageRequests( - testProjectIds.primary, - usageRequestOptions.basic, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.requests).toBeDefined(); - expect(Array.isArray(response.result.requests)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project-usage-summary.test.ts b/tests/e2e/manage-get-project-usage-summary.test.ts deleted file mode 100644 index 853ceb47..00000000 --- a/tests/e2e/manage-get-project-usage-summary.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, usageSummaryOptions } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectUsageSummaryResponse } from "../../src/lib/types"; - -describe("manage getProjectUsageSummary E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve usage summary for a specific project with basic options", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageSummary( - testProjectIds.primary, - usageSummaryOptions.basic - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("start"); - expect(response.result).toHaveProperty("end"); - expect(response.result).toHaveProperty("resolution"); - expect(response.result).toHaveProperty("results"); - - expect(typeof response.result.start).toBe("string"); - expect(typeof response.result.end).toBe("string"); - expect(Array.isArray(response.result.results)).toBe(true); - - // Verify result structure if any results exist - if (response.result.results.length > 0) { - const result = response.result.results[0]; - expect(result).toHaveProperty("start"); - expect(result).toHaveProperty("end"); - expect(result).toHaveProperty("hours"); - expect(result).toHaveProperty("requests"); - } - } - - expect(response).toMatchSnapshot("manage-getProjectUsageSummary-response-structure"); - }); - - it("should handle usage summary with filters", async () => { - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageSummary( - testProjectIds.primary, - usageSummaryOptions.withFilters - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.results).toBeDefined(); - expect(Array.isArray(response.result.results)).toBe(true); - } - }); - - it("should handle custom endpoint for getProjectUsageSummary", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/usage`; - const response: DeepgramResponse = - await deepgram.manage.getProjectUsageSummary( - testProjectIds.primary, - usageSummaryOptions.basic, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.results).toBeDefined(); - expect(Array.isArray(response.result.results)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-project.test.ts b/tests/e2e/manage-get-project.test.ts deleted file mode 100644 index 362e7899..00000000 --- a/tests/e2e/manage-get-project.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds } from "../__fixtures__/manage"; -import type { DeepgramResponse, GetProjectResponse } from "../../src/lib/types"; - -describe("manage getProject E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve a specific project by ID", async () => { - const response: DeepgramResponse = await deepgram.manage.getProject( - testProjectIds.primary - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("project_id"); - expect(response.result).toHaveProperty("name"); - expect(response.result).toHaveProperty("company"); - expect(typeof response.result.project_id).toBe("string"); - expect(typeof response.result.name).toBe("string"); - expect(typeof response.result.company).toBe("string"); - } - - expect(response).toMatchSnapshot("manage-getProject-response-structure"); - }); - - it("should handle custom endpoint for getProject", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}`; - const response: DeepgramResponse = await deepgram.manage.getProject( - testProjectIds.primary, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("project_id"); - expect(response.result).toHaveProperty("name"); - expect(response.result).toHaveProperty("company"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-projects.test.ts b/tests/e2e/manage-get-projects.test.ts deleted file mode 100644 index 38e2e1c9..00000000 --- a/tests/e2e/manage-get-projects.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import type { DeepgramResponse, GetProjectsResponse } from "../../src/lib/types"; - -describe("manage getProjects E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve all projects for the authenticated user", async () => { - const response: DeepgramResponse = await deepgram.manage.getProjects(); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("projects"); - expect(Array.isArray(response.result.projects)).toBe(true); - - // Verify project structure if any projects exist - if (response.result.projects.length > 0) { - const project = response.result.projects[0]; - expect(project).toHaveProperty("project_id"); - expect(project).toHaveProperty("name"); - expect(typeof project.project_id).toBe("string"); - expect(typeof project.name).toBe("string"); - } - } - - expect(response).toMatchSnapshot("manage-getProjects-response-structure"); - }); - - it("should handle custom endpoint for getProjects", async () => { - const customEndpoint = ":version/projects"; - const response: DeepgramResponse = await deepgram.manage.getProjects( - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.projects).toBeDefined(); - expect(Array.isArray(response.result.projects)).toBe(true); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-get-token-details.test.ts b/tests/e2e/manage-get-token-details.test.ts deleted file mode 100644 index e6e0487b..00000000 --- a/tests/e2e/manage-get-token-details.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import type { DeepgramResponse, GetTokenDetailsResponse } from "../../src/lib/types"; - -describe("manage getTokenDetails E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve token details for the authenticated user", async () => { - const response: DeepgramResponse = - await deepgram.manage.getTokenDetails(); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("api_key_id"); - expect(response.result).toHaveProperty("scopes"); - expect(response.result).toHaveProperty("created"); - - expect(typeof response.result.api_key_id).toBe("string"); - expect(Array.isArray(response.result.scopes)).toBe(true); - expect(typeof response.result.created).toBe("string"); - } - - expect(response).toMatchSnapshot("manage-getTokenDetails-response-structure"); - }); - - it("should handle custom endpoint for getTokenDetails", async () => { - const customEndpoint = ":version/auth/token"; - const response: DeepgramResponse = - await deepgram.manage.getTokenDetails(customEndpoint); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("api_key_id"); - expect(response.result).toHaveProperty("scopes"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-leave-project.test.ts b/tests/e2e/manage-leave-project.test.ts deleted file mode 100644 index ca80e99b..00000000 --- a/tests/e2e/manage-leave-project.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds } from "../__fixtures__/manage"; - -describe("manage leaveProject E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - setupApiMocks(); - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - cleanupApiMocks(); - }); - - it("should leave a project", async () => { - const { result, error } = await deepgram.manage.leaveProject(testProjectIds.primary); - - expect(error).toBeNull(); - expect(result).toMatchSnapshot("manage-leaveProject-response-structure"); - }); -}); diff --git a/tests/e2e/manage-remove-project-member.test.ts b/tests/e2e/manage-remove-project-member.test.ts deleted file mode 100644 index 4535fa95..00000000 --- a/tests/e2e/manage-remove-project-member.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { createClient } from "../../src/index"; -import { setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testMemberIds } from "../__fixtures__/manage"; - -describe("manage removeProjectMember E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - setupApiMocks(); - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - }); - - afterAll(() => { - cleanupApiMocks(); - }); - - it("should remove a project member", async () => { - const { error } = await deepgram.manage.removeProjectMember( - testProjectIds.primary, - testMemberIds.toRemove - ); - - expect(error).toBeNull(); - }); -}); diff --git a/tests/e2e/manage-send-project-invite.test.ts b/tests/e2e/manage-send-project-invite.test.ts deleted file mode 100644 index 2fb8d988..00000000 --- a/tests/e2e/manage-send-project-invite.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, inviteOptions } from "../__fixtures__/manage"; -import type { DeepgramResponse, MessageResponse } from "../../src/lib/types"; - -describe("manage sendProjectInvite E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should send a project invitation to a single email", async () => { - const response: DeepgramResponse = await deepgram.manage.sendProjectInvite( - testProjectIds.primary, - inviteOptions.single - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("message"); - expect(typeof response.result.message).toBe("string"); - } - - expect(response).toMatchSnapshot("manage-sendProjectInvite-response-structure"); - }); - - it("should send project invitations to multiple emails", async () => { - const response: DeepgramResponse = await deepgram.manage.sendProjectInvite( - testProjectIds.primary, - inviteOptions.multiple - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("message"); - } - }); - - it("should handle custom endpoint for sendProjectInvite", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/invites`; - const response: DeepgramResponse = await deepgram.manage.sendProjectInvite( - testProjectIds.primary, - inviteOptions.single, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-update-project-member-scope.test.ts b/tests/e2e/manage-update-project-member-scope.test.ts deleted file mode 100644 index ecbc0467..00000000 --- a/tests/e2e/manage-update-project-member-scope.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testMemberIds, memberScopeOptions } from "../__fixtures__/manage"; -import type { DeepgramResponse, MessageResponse } from "../../src/lib/types"; - -describe("manage updateProjectMemberScope E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should update a project member's scope", async () => { - const response: DeepgramResponse = - await deepgram.manage.updateProjectMemberScope( - testProjectIds.primary, - testMemberIds.member1, - memberScopeOptions.update - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("message"); - expect(typeof response.result.message).toBe("string"); - } - - expect(response).toMatchSnapshot("manage-updateProjectMemberScope-response-structure"); - }); - - it("should update a member scope to admin", async () => { - const response: DeepgramResponse = - await deepgram.manage.updateProjectMemberScope( - testProjectIds.primary, - testMemberIds.member2, - memberScopeOptions.updateAdmin - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("message"); - } - }); - - it("should handle custom endpoint for updateProjectMemberScope", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}/members/${testMemberIds.member1}/scopes`; - const response: DeepgramResponse = - await deepgram.manage.updateProjectMemberScope( - testProjectIds.primary, - testMemberIds.member1, - memberScopeOptions.update, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("message"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/manage-update-project.test.ts b/tests/e2e/manage-update-project.test.ts deleted file mode 100644 index 874fdd7a..00000000 --- a/tests/e2e/manage-update-project.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, projectOptions } from "../__fixtures__/manage"; -import type { DeepgramResponse, MessageResponse } from "../../src/lib/types"; - -describe("manage updateProject E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should update a project with new details", async () => { - const response: DeepgramResponse = await deepgram.manage.updateProject( - testProjectIds.primary, - projectOptions.update - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("message"); - expect(typeof response.result.message).toBe("string"); - } - - expect(response).toMatchSnapshot("manage-updateProject-response-structure"); - }); - - it("should handle custom endpoint for updateProject", async () => { - const customEndpoint = `:version/projects/${testProjectIds.primary}`; - const response: DeepgramResponse = await deepgram.manage.updateProject( - testProjectIds.primary, - projectOptions.update, - customEndpoint - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("message"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/models-get-all.test.ts b/tests/e2e/models-get-all.test.ts deleted file mode 100644 index 3983582e..00000000 --- a/tests/e2e/models-get-all.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { createClient } from "../../src/index"; -import { ModelsRestClient } from "../../src/packages/ModelsRestClient"; -import { DeepgramError } from "../../src/lib/errors"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; - -describe("models getAll E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve all available models", async () => { - const { result, error } = await deepgram.models.getAll(); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - // Type guard to ensure result is not null for subsequent operations - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("models-getAll-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("stt"); - expect(result).toHaveProperty("tts"); - expect(Array.isArray(result.stt)).toBe(true); - expect(Array.isArray(result.tts)).toBe(true); - - // Verify STT models have required properties - if (result.stt.length > 0) { - const sttModel = result.stt[0]; - expect(sttModel).toHaveProperty("name"); - expect(sttModel).toHaveProperty("canonical_name"); - expect(sttModel).toHaveProperty("architecture"); - expect(sttModel).toHaveProperty("languages"); - expect(sttModel).toHaveProperty("uuid"); - expect(Array.isArray(sttModel.languages)).toBe(true); - } - - // Verify TTS models have required properties - if (result.tts.length > 0) { - const ttsModel = result.tts[0]; - expect(ttsModel).toHaveProperty("name"); - expect(ttsModel).toHaveProperty("canonical_name"); - expect(ttsModel).toHaveProperty("architecture"); - expect(ttsModel).toHaveProperty("languages"); - expect(ttsModel).toHaveProperty("uuid"); - expect(Array.isArray(ttsModel.languages)).toBe(true); - } - }, 30000); - - it("should handle model options and filters", async () => { - const options = { - include_outdated: false, - }; - - const { result, error } = await deepgram.models.getAll(":version/models", options); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Verify the request was successful - expect(result).toHaveProperty("stt"); - expect(result).toHaveProperty("tts"); - }, 30000); - - it("should handle DeepgramError and return it in response", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const modelsClient = new ModelsRestClient({ key: apiKey }); - - // Mock the get method to throw a DeepgramError - const mockError = new DeepgramError("Test DeepgramError"); - jest.spyOn(modelsClient as any, "get").mockRejectedValue(mockError); - - const { result, error } = await modelsClient.getAll(); - - expect(result).toBeNull(); - expect(error).toBe(mockError); - expect(error).toBeInstanceOf(DeepgramError); - - // Clean up spy - jest.restoreAllMocks(); - }); - - it("should re-throw non-DeepgramError", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const modelsClient = new ModelsRestClient({ key: apiKey }); - - // Mock the get method to throw a regular Error - const mockError = new Error("Network error"); - jest.spyOn(modelsClient as any, "get").mockRejectedValue(mockError); - - await expect(modelsClient.getAll()).rejects.toThrow("Network error"); - await expect(modelsClient.getAll()).rejects.toThrow(Error); - - // Clean up spy - jest.restoreAllMocks(); - }); -}); diff --git a/tests/e2e/models-get-model.test.ts b/tests/e2e/models-get-model.test.ts deleted file mode 100644 index 7c4a1b0f..00000000 --- a/tests/e2e/models-get-model.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { createClient } from "../../src/index"; -import { ModelsRestClient } from "../../src/packages/ModelsRestClient"; -import { DeepgramError } from "../../src/lib/errors"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testModelIds } from "../__fixtures__/models"; - -describe("models getModel E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve specific model information", async () => { - const { result, error } = await deepgram.models.getModel(testModelIds.nova); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - // Type guard to ensure result is not null for subsequent operations - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("models-getModel-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("name"); - expect(result).toHaveProperty("canonical_name"); - expect(result).toHaveProperty("architecture"); - expect(result).toHaveProperty("languages"); - expect(result).toHaveProperty("uuid"); - expect(result).toHaveProperty("version"); - - // Verify data types - expect(typeof result.name).toBe("string"); - expect(typeof result.canonical_name).toBe("string"); - expect(typeof result.architecture).toBe("string"); - expect(Array.isArray(result.languages)).toBe(true); - expect(typeof result.uuid).toBe("string"); - expect(typeof result.version).toBe("string"); - - // Verify languages array contains strings - if (result.languages) { - result.languages.forEach((lang) => { - expect(typeof lang).toBe("string"); - }); - } - }, 30000); - - it("should handle DeepgramError and return it in response", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const modelsClient = new ModelsRestClient({ key: apiKey }); - - // Mock the get method to throw a DeepgramError - const mockError = new DeepgramError("Test DeepgramError"); - jest.spyOn(modelsClient as any, "get").mockRejectedValue(mockError); - - const { result, error } = await modelsClient.getModel(testModelIds.nova); - - expect(result).toBeNull(); - expect(error).toBe(mockError); - expect(error).toBeInstanceOf(DeepgramError); - - // Clean up spy - jest.restoreAllMocks(); - }); - - it("should re-throw non-DeepgramError", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const modelsClient = new ModelsRestClient({ key: apiKey }); - - // Mock the get method to throw a regular Error - const mockError = new Error("Network error"); - jest.spyOn(modelsClient as any, "get").mockRejectedValue(mockError); - - await expect(modelsClient.getModel(testModelIds.nova)).rejects.toThrow("Network error"); - await expect(modelsClient.getModel(testModelIds.nova)).rejects.toThrow(Error); - - // Clean up spy - jest.restoreAllMocks(); - }); -}); diff --git a/tests/e2e/read-analyze-text-callback.test.ts b/tests/e2e/read-analyze-text-callback.test.ts deleted file mode 100644 index f053f12d..00000000 --- a/tests/e2e/read-analyze-text-callback.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { callbackUrls, testReadSources, commonAnalysisOptions } from "../__fixtures__/read"; -import type { DeepgramResponse, AsyncAnalyzeResponse } from "../../src/lib/types"; -import { CallbackUrl } from "../../src/lib/helpers"; - -describe("read analyzeTextCallback E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should analyze text with callback and return async response", async () => { - const response: DeepgramResponse = - await deepgram.read.analyzeTextCallback( - testReadSources.sentimentText, - new CallbackUrl(callbackUrls.webhook), - commonAnalysisOptions - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("request_id"); - expect(typeof response.result.request_id).toBe("string"); - expect(response.result.request_id.length).toBeGreaterThan(0); - } - - expect(response).toMatchSnapshot("read-analyze-text-callback-response-structure"); - }); - - it("should handle simple text analysis with callback", async () => { - const response: DeepgramResponse = - await deepgram.read.analyzeTextCallback( - testReadSources.simpleText, - new CallbackUrl(callbackUrls.testEndpoint), - { sentiment: true, summarize: true } - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.request_id).toBeDefined(); - expect(typeof response.result.request_id).toBe("string"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/read-analyze-text.test.ts b/tests/e2e/read-analyze-text.test.ts deleted file mode 100644 index a6cdf159..00000000 --- a/tests/e2e/read-analyze-text.test.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { createClient } from "../../src/index"; -import { ReadRestClient } from "../../src/packages/ReadRestClient"; -import { DeepgramError } from "../../src/lib/errors"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testReadSources, commonAnalysisOptions } from "../__fixtures__/read"; - -describe("read analyzeText E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should analyze text synchronously", async () => { - const { result, error } = await deepgram.read.analyzeText( - testReadSources.simpleText, - commonAnalysisOptions - ); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - // Type guard to ensure result is not null for subsequent operations - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("read-analyzeText-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("metadata"); - expect(result).toHaveProperty("results"); - - // Verify metadata structure - expect(result.metadata).toHaveProperty("request_id"); - expect(result.metadata).toHaveProperty("created"); - expect(typeof result.metadata.request_id).toBe("string"); - expect(typeof result.metadata.created).toBe("string"); - - // Verify results structure based on requested analysis options - if (commonAnalysisOptions.sentiment) { - expect(result.results).toHaveProperty("sentiments"); - if (result.results.sentiments) { - expect(result.results.sentiments).toHaveProperty("segments"); - expect(Array.isArray(result.results.sentiments.segments)).toBe(true); - } - } - - if (commonAnalysisOptions.intents) { - expect(result.results).toHaveProperty("intents"); - if (result.results.intents) { - expect(result.results.intents).toHaveProperty("segments"); - expect(Array.isArray(result.results.intents.segments)).toBe(true); - } - } - - if (commonAnalysisOptions.summarize) { - expect(result.results).toHaveProperty("summary"); - } - }, 30000); - - it("should analyze text with different analysis options", async () => { - const sentimentOnlyOptions = { - sentiment: true, - language: "en", - }; - - const { result, error } = await deepgram.read.analyzeText( - testReadSources.sentimentText, - sentimentOnlyOptions - ); - - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - expect(result).toHaveProperty("results"); - - // Should have sentiment analysis since it was requested - expect(result.results).toHaveProperty("sentiments"); - - // Verify sentiment structure - const sentiments = result.results.sentiments; - if (sentiments) { - expect(sentiments).toHaveProperty("segments"); - expect(Array.isArray(sentiments.segments)).toBe(true); - - if (sentiments.segments.length > 0) { - const segment = sentiments.segments[0]; - expect(segment).toHaveProperty("sentiment"); - expect(segment).toHaveProperty("sentiment_score"); - expect(typeof segment.sentiment).toBe("string"); - expect(typeof segment.sentiment_score).toBe("number"); - } - } - }, 30000); - - it("should reject synchronous analysis with callback option", async () => { - const optionsWithCallback = { - ...commonAnalysisOptions, - callback: "https://example.com/callback", - }; - - const { result, error } = await deepgram.read.analyzeText( - testReadSources.simpleText, - optionsWithCallback - ); - - // Should return an error, not throw - expect(result).toBeNull(); - expect(error).toBeTruthy(); - expect(error?.message).toContain("Callback cannot be provided as an option to a synchronous"); - }, 30000); - - it("should handle DeepgramError and return it in response", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const readClient = new ReadRestClient({ key: apiKey }); - - // Mock the post method to throw a DeepgramError - const mockError = new DeepgramError("Test DeepgramError"); - jest.spyOn(readClient as any, "post").mockRejectedValue(mockError); - - const { result, error } = await readClient.analyzeText( - testReadSources.simpleText, - commonAnalysisOptions - ); - - expect(result).toBeNull(); - expect(error).toBe(mockError); - expect(error).toBeInstanceOf(DeepgramError); - - // Clean up spy - jest.restoreAllMocks(); - }); - - it("should re-throw non-DeepgramError", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const readClient = new ReadRestClient({ key: apiKey }); - - // Mock the post method to throw a regular Error - const mockError = new Error("Network error"); - jest.spyOn(readClient as any, "post").mockRejectedValue(mockError); - - await expect( - readClient.analyzeText(testReadSources.simpleText, commonAnalysisOptions) - ).rejects.toThrow("Network error"); - await expect( - readClient.analyzeText(testReadSources.simpleText, commonAnalysisOptions) - ).rejects.toThrow(Error); - - // Clean up spy - jest.restoreAllMocks(); - }); -}); diff --git a/tests/e2e/read-analyze-url-callback.test.ts b/tests/e2e/read-analyze-url-callback.test.ts deleted file mode 100644 index 3c05b9c6..00000000 --- a/tests/e2e/read-analyze-url-callback.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { callbackUrls, testReadSources, commonAnalysisOptions } from "../__fixtures__/read"; -import type { DeepgramResponse, AsyncAnalyzeResponse } from "../../src/lib/types"; -import { CallbackUrl } from "../../src/lib/helpers"; - -describe("read analyzeUrlCallback E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should analyze URL with callback and return async response", async () => { - const response: DeepgramResponse = await deepgram.read.analyzeUrlCallback( - testReadSources.urlSource, - new CallbackUrl(callbackUrls.webhook), - commonAnalysisOptions - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result).toHaveProperty("request_id"); - expect(typeof response.result.request_id).toBe("string"); - expect(response.result.request_id.length).toBeGreaterThan(0); - } - - expect(response).toMatchSnapshot("read-analyze-url-callback-response-structure"); - }); - - it("should handle basic analysis options with callback", async () => { - const response: DeepgramResponse = await deepgram.read.analyzeUrlCallback( - testReadSources.urlSource, - new CallbackUrl(callbackUrls.testEndpoint), - { sentiment: true } - ); - - expect(response.error).toBeNull(); - expect(response.result).toBeDefined(); - - if (response.result) { - expect(response.result.request_id).toBeDefined(); - expect(typeof response.result.request_id).toBe("string"); - } - }, 30000); // 30 second timeout for API call -}); diff --git a/tests/e2e/read-analyze-url.test.ts b/tests/e2e/read-analyze-url.test.ts deleted file mode 100644 index 3be73a73..00000000 --- a/tests/e2e/read-analyze-url.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { createClient } from "../../src/index"; -import { ReadRestClient } from "../../src/packages/ReadRestClient"; -import { DeepgramError } from "../../src/lib/errors"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testReadSources, commonAnalysisOptions } from "../__fixtures__/read"; - -describe("read analyzeUrl E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should analyze URL source synchronously", async () => { - const { result, error } = await deepgram.read.analyzeUrl( - testReadSources.urlSource, - commonAnalysisOptions - ); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("read-analyzeUrl-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("metadata"); - expect(result).toHaveProperty("results"); - - expect(result.metadata).toHaveProperty("request_id"); - expect(typeof result.metadata.request_id).toBe("string"); - - // Verify analysis results are present - expect(result.results).toBeTruthy(); - }, 30000); - - it("should handle DeepgramError and return it in response", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const readClient = new ReadRestClient({ key: apiKey }); - - // Mock the post method to throw a DeepgramError - const mockError = new DeepgramError("Test DeepgramError"); - jest.spyOn(readClient as any, "post").mockRejectedValue(mockError); - - const { result, error } = await readClient.analyzeUrl( - testReadSources.urlSource, - commonAnalysisOptions - ); - - expect(result).toBeNull(); - expect(error).toBe(mockError); - expect(error).toBeInstanceOf(DeepgramError); - - // Clean up spy - jest.restoreAllMocks(); - }); - - it("should re-throw non-DeepgramError", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const readClient = new ReadRestClient({ key: apiKey }); - - // Mock the post method to throw a regular Error - const mockError = new Error("Network error"); - jest.spyOn(readClient as any, "post").mockRejectedValue(mockError); - - await expect( - readClient.analyzeUrl(testReadSources.urlSource, commonAnalysisOptions) - ).rejects.toThrow("Network error"); - await expect( - readClient.analyzeUrl(testReadSources.urlSource, commonAnalysisOptions) - ).rejects.toThrow(Error); - - // Clean up spy - jest.restoreAllMocks(); - }); -}); diff --git a/tests/e2e/selfhosted-create-credentials.test.ts b/tests/e2e/selfhosted-create-credentials.test.ts deleted file mode 100644 index 6dd7c40b..00000000 --- a/tests/e2e/selfhosted-create-credentials.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testCredentials } from "../__fixtures__/selfhosted"; - -describe("selfhosted createCredentials E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should create new self-hosted credentials", async () => { - const { result, error } = await deepgram.selfhosted.createCredentials( - testProjectIds.primary, - testCredentials.createOptions - ); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("selfhosted-createCredentials-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("member"); - expect(result).toHaveProperty("distribution_credentials"); - - const credData = result.distribution_credentials; - expect(credData).toHaveProperty("distribution_credentials_id"); - expect(credData).toHaveProperty("comment"); - expect(credData).toHaveProperty("scopes"); - expect(credData).toHaveProperty("provider"); - expect(credData).toHaveProperty("created"); - - // Verify the created credentials match our input - expect(credData.comment).toBe(testCredentials.createOptions.comment); - expect(credData.scopes).toEqual(testCredentials.createOptions.scopes); - }, 30000); -}); diff --git a/tests/e2e/selfhosted-delete-credentials.test.ts b/tests/e2e/selfhosted-delete-credentials.test.ts deleted file mode 100644 index 15a0e7a7..00000000 --- a/tests/e2e/selfhosted-delete-credentials.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testCredentials } from "../__fixtures__/selfhosted"; - -describe("selfhosted deleteCredentials E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should delete self-hosted credentials", async () => { - const { result, error } = await deepgram.selfhosted.deleteCredentials( - testProjectIds.primary, - testCredentials.credentialId - ); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("selfhosted-deleteCredentials-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("message"); - expect(typeof result.message).toBe("string"); - expect(result.message.length).toBeGreaterThan(0); - }, 30000); -}); diff --git a/tests/e2e/selfhosted-get-credentials.test.ts b/tests/e2e/selfhosted-get-credentials.test.ts deleted file mode 100644 index aa04835a..00000000 --- a/tests/e2e/selfhosted-get-credentials.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { createClient } from "../../src/index"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds, testCredentials } from "../__fixtures__/selfhosted"; - -describe("selfhosted getCredentials E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should retrieve specific self-hosted credentials", async () => { - const { result, error } = await deepgram.selfhosted.getCredentials( - testProjectIds.primary, - testCredentials.credentialId - ); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("selfhosted-getCredentials-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("member"); - expect(result).toHaveProperty("distribution_credentials"); - - expect(result.member).toHaveProperty("member_id"); - expect(result.member).toHaveProperty("email"); - - const credData = result.distribution_credentials; - expect(credData).toHaveProperty("distribution_credentials_id"); - expect(credData).toHaveProperty("comment"); - expect(credData).toHaveProperty("scopes"); - expect(credData).toHaveProperty("provider"); - expect(credData).toHaveProperty("created"); - - // Verify data types - expect(typeof credData.distribution_credentials_id).toBe("string"); - expect(typeof credData.comment).toBe("string"); - expect(Array.isArray(credData.scopes)).toBe(true); - expect(typeof credData.provider).toBe("string"); - expect(typeof credData.created).toBe("string"); - - // Verify scopes array contains strings - credData.scopes.forEach((scope) => { - expect(typeof scope).toBe("string"); - }); - }, 30000); -}); diff --git a/tests/e2e/selfhosted-list-credentials.test.ts b/tests/e2e/selfhosted-list-credentials.test.ts deleted file mode 100644 index 3a880af9..00000000 --- a/tests/e2e/selfhosted-list-credentials.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { createClient } from "../../src/index"; -import { SelfHostedRestClient } from "../../src/packages/SelfHostedRestClient"; -import { DeepgramError } from "../../src/lib/errors"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testProjectIds } from "../__fixtures__/selfhosted"; - -describe("selfhosted listCredentials E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should list self-hosted credentials", async () => { - const { result, error } = await deepgram.selfhosted.listCredentials(testProjectIds.primary); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - // Type guard to ensure result is not null for subsequent operations - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Test the structure with snapshot - expect(result).toMatchSnapshot("selfhosted-listCredentials-response-structure"); - - // Essential structural validation - expect(result).toHaveProperty("distribution_credentials"); - expect(Array.isArray(result.distribution_credentials)).toBe(true); - - // Verify credentials structure if any exist - if (result.distribution_credentials.length > 0) { - const credential = result.distribution_credentials[0]; - expect(credential).toHaveProperty("member"); - expect(credential).toHaveProperty("distribution_credentials"); - - expect(credential.member).toHaveProperty("member_id"); - expect(credential.member).toHaveProperty("email"); - - const credData = credential.distribution_credentials; - expect(credData).toHaveProperty("distribution_credentials_id"); - expect(credData).toHaveProperty("comment"); - expect(credData).toHaveProperty("scopes"); - expect(credData).toHaveProperty("provider"); - expect(credData).toHaveProperty("created"); - - expect(Array.isArray(credData.scopes)).toBe(true); - } - }, 30000); - - it("should handle different endpoint configurations", async () => { - const customEndpoint = ":version/projects/:projectId/onprem/distribution/credentials"; - - const { result, error } = await deepgram.selfhosted.listCredentials( - testProjectIds.secondary, - customEndpoint - ); - - // Verify no error occurred - expect(error).toBeNull(); - expect(result).toBeTruthy(); - - if (!result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Verify the request was successful - expect(result).toHaveProperty("distribution_credentials"); - expect(Array.isArray(result.distribution_credentials)).toBe(true); - }, 30000); - - it("should handle DeepgramError and return it in response", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const selfhostedClient = new SelfHostedRestClient({ key: apiKey }); - - // Mock the get method to throw a DeepgramError - const mockError = new DeepgramError("Test DeepgramError"); - jest.spyOn(selfhostedClient as any, "get").mockRejectedValue(mockError); - - const { result, error } = await selfhostedClient.listCredentials(testProjectIds.primary); - - expect(result).toBeNull(); - expect(error).toBe(mockError); - expect(error).toBeInstanceOf(DeepgramError); - - // Clean up spy - jest.restoreAllMocks(); - }); - - it("should re-throw non-DeepgramError", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const selfhostedClient = new SelfHostedRestClient({ key: apiKey }); - - // Mock the get method to throw a regular Error - const mockError = new Error("Network error"); - jest.spyOn(selfhostedClient as any, "get").mockRejectedValue(mockError); - - await expect(selfhostedClient.listCredentials(testProjectIds.primary)).rejects.toThrow( - "Network error" - ); - await expect(selfhostedClient.listCredentials(testProjectIds.primary)).rejects.toThrow(Error); - - // Clean up spy - jest.restoreAllMocks(); - }); -}); diff --git a/tests/e2e/speak-live-connection.test.ts b/tests/e2e/speak-live-connection.test.ts deleted file mode 100644 index 4c843f51..00000000 --- a/tests/e2e/speak-live-connection.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { SpeakLiveClient } from "../../src/packages/SpeakLiveClient"; -import { LiveTTSEvents } from "../../src/lib/enums/LiveTTSEvents"; -import { CONNECTION_STATE } from "../../src/lib/constants"; -import { MockWebSocket, WebSocketScenario, mockWebSocketData } from "../__utils__/websocket-mocks"; - -// Helper to wait for events -function waitForEvent(emitter: any, eventName: string, timeout = 2000): Promise { - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - reject(new Error(`Event '${eventName}' did not fire within ${timeout}ms`)); - }, timeout); - - emitter.once(eventName, (data: any) => { - clearTimeout(timer); - resolve(data); - }); - }); -} - -// Helper to collect multiple events -function collectEvents(emitter: any, eventNames: string[], timeout = 3000): Promise { - return new Promise((resolve, reject) => { - const results: any[] = []; - const received = new Set(); - - const timer = setTimeout(() => { - reject( - new Error( - `Not all events received within ${timeout}ms. Missing: ${eventNames.filter( - (name) => !received.has(name) - )}` - ) - ); - }, timeout); - - eventNames.forEach((eventName) => { - emitter.on(eventName, (data: any) => { - if (!received.has(eventName)) { - received.add(eventName); - results.push({ event: eventName, data }); - - if (received.size === eventNames.length) { - clearTimeout(timer); - resolve(results); - } - } - }); - }); - }); -} - -describe("speak live connection E2E", () => { - let mockWebSocketInstance: MockWebSocket; - let client: SpeakLiveClient; - - // Custom WebSocket constructor that captures the instance - const createMockWebSocketConstructor = () => { - return class MockWebSocketConstructor extends MockWebSocket { - constructor(url: string, protocols?: string | string[], options?: any) { - super(url, protocols, options); - // Store instance for test access - mockWebSocketInstance = this as MockWebSocket; - } - }; - }; - - beforeEach(() => { - const MockWebSocketConstructor = createMockWebSocketConstructor(); - - client = new SpeakLiveClient({ - key: "test-api-key", - global: { - websocket: { - // @ts-expect-error - Using mock for testing - client: MockWebSocketConstructor, - }, - }, - }); - }); - - afterEach(() => { - if (client) { - client.disconnect(); - } - }); - - it("should handle complete TTS synthesis workflow", async () => { - await waitForEvent(client, LiveTTSEvents.Open); - - expect(client.connectionState()).toBe(CONNECTION_STATE.Open); - expect(mockWebSocketInstance.url).toContain("speak"); - - // Set up event collectors for TTS workflow - const eventsPromise = collectEvents(client, [ - LiveTTSEvents.Metadata, - LiveTTSEvents.Audio, - LiveTTSEvents.Flushed, - ]); - - // Simulate TTS synthesis - const scenario = new WebSocketScenario(mockWebSocketInstance); - await scenario.simulateSpeakTTS(); - - const events = await eventsPromise; - expect(events).toHaveLength(3); - - const eventMap = events.reduce((acc, { event, data }) => { - acc[event] = data; - return acc; - }, {}); - - expect(eventMap[LiveTTSEvents.Metadata]).toEqual(mockWebSocketData.speak.metadata); - expect(eventMap[LiveTTSEvents.Audio]).toBeInstanceOf(Buffer); - expect(eventMap[LiveTTSEvents.Flushed]).toEqual(mockWebSocketData.speak.flushed); - }); - - it("should handle streaming text-to-speech session", async () => { - await waitForEvent(client, LiveTTSEvents.Open); - - // Simulate streaming text input - const texts = [ - "Hello, this is the first sentence.", - "This is the second sentence to synthesize.", - "And here's the final sentence.", - ]; - - texts.forEach((text) => { - client.sendText(text); - }); - - // Flush to get all audio - client.flush(); - - const sentMessages = mockWebSocketInstance.getSentMessages(); - - // Verify all text messages were sent - texts.forEach((text) => { - expect(sentMessages).toContain(JSON.stringify({ type: "Speak", text })); - }); - - // Verify flush was sent - expect(sentMessages).toContain(JSON.stringify({ type: "Flush" })); - }); - - it("should handle TTS session with multiple operations", async () => { - await waitForEvent(client, LiveTTSEvents.Open); - - // Simulate complex TTS session - client.sendText("Start of message"); - client.sendText("Middle part"); - client.flush(); // Get audio for first part - client.clear(); // Clear buffer - client.sendText("New message after clear"); - client.requestClose(); // End session - - const sentMessages = mockWebSocketInstance.getSentMessages(); - expect(sentMessages).toContain(JSON.stringify({ type: "Speak", text: "Start of message" })); - expect(sentMessages).toContain(JSON.stringify({ type: "Speak", text: "Middle part" })); - expect(sentMessages).toContain(JSON.stringify({ type: "Flush" })); - expect(sentMessages).toContain(JSON.stringify({ type: "Clear" })); - expect(sentMessages).toContain( - JSON.stringify({ type: "Speak", text: "New message after clear" }) - ); - expect(sentMessages).toContain(JSON.stringify({ type: "Close" })); - }); -}); diff --git a/tests/e2e/speak-request.test.ts b/tests/e2e/speak-request.test.ts deleted file mode 100644 index e8dab8e5..00000000 --- a/tests/e2e/speak-request.test.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { createClient } from "../../src/index"; -import { SpeakRestClient } from "../../src/packages/SpeakRestClient"; -import { structureOnlySerializer, setupApiMocks, cleanupApiMocks } from "../__utils__"; -import { testTextSources, commonTTSOptions } from "../__fixtures__/speak"; - -describe("speak request E2E", () => { - let deepgram: ReturnType; - - beforeAll(() => { - // Set up API mocks (only active when not updating snapshots) - setupApiMocks(); - - // Use mock API key when mocking, real one when updating snapshots - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - deepgram = createClient(apiKey); - - // Add our custom serializer - expect.addSnapshotSerializer(structureOnlySerializer); - }); - - afterAll(() => { - // Clean up mocks - cleanupApiMocks(); - }); - - it("should generate speech from text and return audio data", async () => { - const speakClient = await deepgram.speak.request(testTextSources.greeting, commonTTSOptions); - - // Verify we got a response - expect(speakClient).toBeTruthy(); - expect(speakClient.result).toBeTruthy(); - - // Type guard to ensure result is not null for subsequent operations - if (!speakClient.result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - // Verify the response structure - expect(speakClient.result.ok).toBe(true); - expect(speakClient.result.status).toBe(200); - - // Verify we can get the audio stream - const audioStream = await speakClient.getStream(); - expect(audioStream).toBeTruthy(); - - // Verify headers contain expected TTS metadata - const headers = await speakClient.getHeaders(); - expect(headers).toBeTruthy(); - expect(headers.get("content-type")).toContain("audio/"); - - // Check for Deepgram-specific headers (if present) - const contentLength = headers.get("content-length"); - if (contentLength) { - expect(parseInt(contentLength)).toBeGreaterThan(0); - } - - // Test the structure with snapshot - const headerObj = Object.fromEntries(headers.entries()); - expect(headerObj).toMatchSnapshot("speak-request-response-headers"); - - // Verify audio stream is readable - expect(audioStream).toBeInstanceOf(ReadableStream); - }, 30000); // 30 second timeout for API call - - it("should handle different TTS options", async () => { - const speakClient = await deepgram.speak.request(testTextSources.longText, { - model: "aura-2-thalia-en", - encoding: "linear16", - sample_rate: 48000, - }); - - // Verify we got a response with the configured options - expect(speakClient).toBeTruthy(); - expect(speakClient.result).toBeTruthy(); - - if (!speakClient.result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - expect(speakClient.result.ok).toBe(true); - expect(speakClient.result.status).toBe(200); - - // Verify audio stream is available - const audioStream = await speakClient.getStream(); - expect(audioStream).toBeTruthy(); - expect(audioStream).toBeInstanceOf(ReadableStream); - - // Verify headers - const headers = await speakClient.getHeaders(); - expect(headers).toBeTruthy(); - expect(headers.get("content-type")).toBeTruthy(); - }, 30000); - - it("should handle multiline text input", async () => { - const speakClient = await deepgram.speak.request(testTextSources.multiline, commonTTSOptions); - - // Verify we got a response - expect(speakClient).toBeTruthy(); - expect(speakClient.result).toBeTruthy(); - - if (!speakClient.result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - expect(speakClient.result.ok).toBe(true); - - // Verify we can access the audio data - const audioStream = await speakClient.getStream(); - expect(audioStream).toBeTruthy(); - - const headers = await speakClient.getHeaders(); - expect(headers).toBeTruthy(); - expect(headers.get("content-type")).toContain("audio/"); - }, 30000); - - it("should reject empty text source", async () => { - // Empty text should be rejected by the client validation - await expect(deepgram.speak.request({ text: "" }, commonTTSOptions)).rejects.toThrow( - "Unknown transcription source type" - ); - }, 30000); - - it("should handle various audio encodings", async () => { - const encodingTests = [ - { encoding: "mp3" as const }, - { encoding: "linear16" as const, sample_rate: 48000 }, - { encoding: "opus" as const }, - ]; - - for (const options of encodingTests) { - const speakClient = await deepgram.speak.request( - { text: "Testing encoding: " + options.encoding }, - { - model: "aura-2-thalia-en", - ...options, - } - ); - - expect(speakClient).toBeTruthy(); - expect(speakClient.result).toBeTruthy(); - - if (!speakClient.result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - expect(speakClient.result.ok).toBe(true); - - const audioStream = await speakClient.getStream(); - expect(audioStream).toBeTruthy(); - } - }, 30000); - - it("should preserve special characters and punctuation", async () => { - const specialTextSource = { - text: "Hello! How are you? I'm fine. Testing 123, $50.00, and émojis 🎵", - }; - - const speakClient = await deepgram.speak.request(specialTextSource, commonTTSOptions); - - expect(speakClient).toBeTruthy(); - expect(speakClient.result).toBeTruthy(); - - if (!speakClient.result) { - throw new Error("Result should not be null after toBeTruthy check"); - } - - expect(speakClient.result.ok).toBe(true); - - const audioStream = await speakClient.getStream(); - expect(audioStream).toBeTruthy(); - - const headers = await speakClient.getHeaders(); - expect(headers).toBeTruthy(); - expect(headers.get("content-type")).toContain("audio/"); - }, 30000); - - it("should throw error when trying to getStream before making a request", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const speakClient = new SpeakRestClient({ key: apiKey }); - - await expect(speakClient.getStream()).rejects.toThrow( - "Tried to get stream before making request" - ); - }); - - it("should throw error when trying to getHeaders before making a request", async () => { - const apiKey = process.env.DEEPGRAM_API_KEY || "mock-api-key"; - const speakClient = new SpeakRestClient({ key: apiKey }); - - await expect(speakClient.getHeaders()).rejects.toThrow( - "Tried to get headers before making request" - ); - }); -}); diff --git a/tests/manual/README.md b/tests/manual/README.md new file mode 100644 index 00000000..842c018b --- /dev/null +++ b/tests/manual/README.md @@ -0,0 +1,139 @@ +# Manual Tests for Deepgram JS SDK + +This directory contains manual tests for the Deepgram JavaScript SDK. These tests are simple, standalone Node.js scripts that demonstrate various SDK features and can be used for manual testing and verification. + +**Note:** These tests require the locally built SDK from the `dist/cjs/` directory. They test the actual build output, not the npm package. + +## Prerequisites + +- Node.js 18.0.0 or higher +- A valid Deepgram API key set in the `DEEPGRAM_API_KEY` environment variable + +## Setup + +1. **Build the SDK first** (required before running any tests): + + ```bash + yarn build + ``` + +2. Set your Deepgram API key: + ```bash + export DEEPGRAM_API_KEY=your_api_key_here + ``` + +## Running Tests + +All tests are simple Node.js scripts that can be run directly: + +```bash +node tests/manual/listen/v1/media/transcribe_file/main.js +``` + +## Test Categories + +### Listen API Tests + +#### V1 Media - Transcribe File + +- `listen/v1/media/transcribe_file/main.js` - Basic file transcription +- `listen/v1/media/transcribe_file/with_auth_token.js` - File transcription with access token +- `listen/v1/media/transcribe_file/with_raw_response.js` - File transcription with raw response + +#### V1 Media - Transcribe URL + +- `listen/v1/media/transcribe_url/main.js` - Basic URL transcription +- `listen/v1/media/transcribe_url/with_auth_token.js` - URL transcription with access token +- `listen/v1/media/transcribe_url/with_raw_response.js` - URL transcription with raw response + +#### V1 WebSocket Connect + +- `listen/v1/connect/main.js` - Basic WebSocket connection +- `listen/v1/connect/with_auth_token.js` - WebSocket connection with access token +- `listen/v1/connect/with_raw_response.js` - WebSocket connection (same as main) + +#### V2 WebSocket Connect + +- `listen/v2/connect/main.js` - Basic V2 WebSocket connection +- `listen/v2/connect/with_auth_token.js` - V2 WebSocket connection with access token +- `listen/v2/connect/with_raw_response.js` - V2 WebSocket connection (same as main) + +### Speak API Tests + +#### V1 Audio Generate + +- `speak/v1/audio/generate/main.js` - Basic text-to-speech +- `speak/v1/audio/generate/with_auth_token.js` - Text-to-speech with access token +- `speak/v1/audio/generate/with_raw_response.js` - Text-to-speech with raw response + +#### V1 WebSocket Connect + +- `speak/v1/connect/main.js` - Basic Speak WebSocket connection +- `speak/v1/connect/with_auth_token.js` - Speak WebSocket connection with access token +- `speak/v1/connect/with_raw_response.js` - Speak WebSocket connection (same as main) + +### Read API Tests + +#### V1 Text Analyze + +- `read/v1/text/analyze/main.js` - Basic text analysis +- `read/v1/text/analyze/with_auth_token.js` - Text analysis with access token +- `read/v1/text/analyze/with_raw_response.js` - Text analysis with raw response + +### Agent API Tests + +#### V1 Connect + +- `agent/v1/connect/main.js` - Basic Voice Agent connection +- `agent/v1/connect/with_auth_token.js` - Voice Agent connection with access token +- `agent/v1/connect/with_raw_response.js` - Voice Agent connection (same as main) + +## Test Patterns + +### Basic Tests (`main.js`) + +These tests demonstrate the simplest usage of each feature. All tests use async/await since the JavaScript SDK is Promise-based. + +### Access Token Tests (`with_auth_token.js`) + +These tests demonstrate how to use temporary access tokens instead of API keys. They: + +1. Request an access token using an API key +2. Create a new client with the access token +3. Make the API call using the access token + +### Raw Response Tests (`with_raw_response.js`) + +These tests use the `withRawResponse` API to get the full HTTP response including headers and status codes. + +## WebSocket Tests + +WebSocket tests include timeout-based cleanup for demonstration purposes: + +```javascript +setTimeout(() => { + connection.close(); +}, 3000); // EXAMPLE ONLY: Wait 3 seconds before closing +``` + +**Note**: In production applications, you should NOT use timeouts like this. Instead: + +- Keep the connection alive for as long as needed +- Integrate with your application's event loop +- Close the connection when your application logic determines it's appropriate + +## Expected Behavior + +All tests should either: + +- Complete successfully and print "Request sent" / "Response received" messages +- Fail gracefully and print a caught error message in the format `Caught: ` + +No test requires user interaction to complete. + +## Fixtures + +Audio fixture files are located in `fixtures/`: + +- `audio.wav` - WAV audio file for testing +- `audio.mp3` - MP3 audio file for testing diff --git a/tests/manual/agent/v1/connect/main.js b/tests/manual/agent/v1/connect/main.js new file mode 100644 index 00000000..79f4ce66 --- /dev/null +++ b/tests/manual/agent/v1/connect/main.js @@ -0,0 +1,79 @@ +// @ts-check +/** @typedef {import("../../../../../dist/cjs/index.js").DeepgramClient} */ +const { DeepgramClient } = require("../../../../../dist/cjs/index.js"); + +/** @type {DeepgramClient} */ +const client = new DeepgramClient(); + +(async () => { + try { + const agent = await client.agent.v1.connect(); + + // Send minimal settings to configure the agent per the latest spec + const settings = { + audio: { + input: { + encoding: "linear16", + sample_rate: 44100, + }, + }, + agent: { + listen: { + provider: { + type: "deepgram", + model: "nova-3", + smart_format: true, + }, + }, + think: { + provider: { + type: "open_ai", + model: "gpt-4o-mini", + temperature: 0.7, + }, + prompt: 'Reply only and explicitly with "OK".', + }, + speak: { + provider: { + type: "deepgram", + model: "aura-2-asteria-en", + }, + }, + }, + }; + + console.log("Send SettingsConfiguration message"); + agent.sendSettings(settings); + + agent.on("open", () => { + console.log("Connection opened"); + }); + + agent.on("message", (message) => { + if (message instanceof Buffer || message instanceof ArrayBuffer) { + console.log("Received audio event"); + } else { + const msgType = message?.type || "Unknown"; + console.log(`Received ${msgType} event`); + } + }); + + agent.on("close", () => { + console.log("Connection closed"); + }); + + agent.on("error", (error) => { + console.log(`Caught: ${error.message || error}`); + }); + + // EXAMPLE ONLY: Wait briefly to see some events before exiting + // In production, you would typically keep the connection alive and send audio data + // or integrate into your application's event loop + setTimeout(() => { + agent.close(); + }, 3000); // EXAMPLE ONLY: Wait 3 seconds before closing + } catch (e) { + console.error(`Error: ${e.message || e}`); + throw e; + } +})(); diff --git a/tests/manual/agent/v1/settings/think/models/list/main.js b/tests/manual/agent/v1/settings/think/models/list/main.js new file mode 100644 index 00000000..6a397413 --- /dev/null +++ b/tests/manual/agent/v1/settings/think/models/list/main.js @@ -0,0 +1,17 @@ +// @ts-check +/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */ +const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js"); + +/** @type {DeepgramClient} */ +const client = new DeepgramClient(); + +(async () => { + try { + console.log("Request sent"); + const response = await client.agent.v1.settings.think.models.list(); + console.log("Response received"); + } catch (e) { + console.error(`Error: ${e.message || e}`); + throw e; + } +})(); diff --git a/tests/manual/auth/v1/tokens/grant/main.js b/tests/manual/auth/v1/tokens/grant/main.js new file mode 100644 index 00000000..925f1596 --- /dev/null +++ b/tests/manual/auth/v1/tokens/grant/main.js @@ -0,0 +1,18 @@ +// @ts-check +/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */ +const { DeepgramClient } = require("../../../../../../dist/cjs/index.js"); + +/** @type {DeepgramClient} */ +const client = new DeepgramClient(); + +(async () => { + try { + console.log('Request sent'); + const response = await client.auth.v1.tokens.grant(); + console.log('Response received'); + } catch (e) { + console.error(`Error: ${e.message || e}`); + throw e; + } +})(); + diff --git a/tests/manual/browser-test-utils.js b/tests/manual/browser-test-utils.js new file mode 100644 index 00000000..0080d566 --- /dev/null +++ b/tests/manual/browser-test-utils.js @@ -0,0 +1,375 @@ +const { chromium } = require("playwright"); +const webpack = require("webpack"); +const path = require("path"); +const fs = require("fs"); +const http = require("http"); + +/** + * Shared utilities for browser-based SDK testing with Playwright + */ + +/** + * Build a browser-compatible webpack bundle of the SDK + * @param {string} outputDir - Directory to output the bundle + * @returns {Promise} + */ +async function buildBrowserBundle(outputDir) { + console.log("Building browser bundle with webpack..."); + + const webpackConfig = { + mode: "development", + entry: path.resolve(__dirname, "../../src/index.ts"), + output: { + path: outputDir, + filename: "deepgram-browser-bundle.js", + library: { + name: "DeepgramSDK", + type: "umd", + }, + globalObject: "this", + }, + resolve: { + extensions: [".ts", ".js"], + extensionAlias: { + ".js": [".ts", ".js"], + }, + fallback: { + // Exclude Node.js modules for browser + ws: false, + fs: false, + path: false, + stream: false, + os: false, + http: false, + https: false, + util: false, + buffer: false, + events: false, + }, + }, + module: { + rules: [ + { + test: /\.ts$/, + use: { + loader: "ts-loader", + options: { + configFile: path.resolve(__dirname, "../../tsconfig.json"), + }, + }, + exclude: /node_modules/, + }, + ], + }, + target: "web", + }; + + return new Promise((resolve, reject) => { + webpack(webpackConfig, (err, stats) => { + if (err) { + reject(err); + return; + } + + if (stats.hasErrors()) { + reject(new Error(stats.toString({ colors: true }))); + return; + } + + console.log("✓ Browser bundle created successfully"); + resolve(); + }); + }); +} + +/** + * Create an HTTP server to serve test files + * @param {Object} options - Server configuration + * @param {string} options.testDir - Base directory for serving files + * @param {number} options.port - Port number + * @param {Function} [options.customFileHandler] - Optional custom handler for special routes + * @returns {Promise} + */ +function createServer({ testDir, port, customFileHandler }) { + const server = http.createServer((req, res) => { + // Allow custom handler to intercept requests + if (customFileHandler) { + const handled = customFileHandler(req, res, testDir); + if (handled) return; + } + + // Default file serving + let filePath = path.join(testDir, req.url === "/" ? "test-browser.html" : req.url); + + // Security: prevent directory traversal + if (!filePath.startsWith(testDir)) { + res.writeHead(403); + res.end("Forbidden"); + return; + } + + fs.readFile(filePath, (err, data) => { + if (err) { + res.writeHead(404); + res.end("Not found"); + return; + } + + const ext = path.extname(filePath); + const contentTypes = { + ".html": "text/html", + ".js": "application/javascript", + ".json": "application/json", + ".wav": "audio/wav", + ".mp3": "audio/mpeg", + }; + + res.writeHead(200, { + "Content-Type": contentTypes[ext] || "application/octet-stream", + "Access-Control-Allow-Origin": "*", + }); + res.end(data); + }); + }); + + return new Promise((resolve, reject) => { + server.listen(port, (err) => { + if (err) reject(err); + else resolve(server); + }); + }); +} + +/** + * Prepare HTML template by replacing placeholders + * @param {Object} options - Template options + * @param {string} options.templatePath - Path to HTML template + * @param {string} options.outputPath - Where to write processed HTML + * @param {Object} options.replacements - Key-value pairs for replacements + */ +function prepareHtmlTemplate({ templatePath, outputPath, replacements }) { + let html = fs.readFileSync(templatePath, "utf8"); + + // Replace all placeholders + for (const [key, value] of Object.entries(replacements)) { + html = html.replace(new RegExp(`{{${key}}}`, "g"), value); + } + + fs.writeFileSync(outputPath, html); +} + +/** + * Launch browser and navigate to test page + * @param {Object} options - Browser options + * @param {number} options.port - Server port + * @param {string} [options.path] - Path to navigate to (default: /) + * @returns {Promise<{browser, page}>} + */ +async function launchBrowserTest({ port, path: urlPath = "/" }) { + console.log("Launching headless Chromium..."); + const browser = await chromium.launch({ + headless: true, + args: ["--no-sandbox"], + }); + + const context = await browser.newContext(); + const page = await context.newPage(); + + // Capture browser logs + page.on("console", (msg) => { + console.log(`[Browser ${msg.type().toUpperCase()}]:`, msg.text()); + }); + + page.on("pageerror", (error) => { + console.error("[Browser Error]:", error.message); + }); + + // Navigate to test page + console.log("Loading test page...\n"); + await page.goto(`http://localhost:${port}${urlPath}`); + + return { browser, page }; +} + +/** + * Wait for test result and evaluate success/failure + * @param {Object} page - Playwright page object + * @param {number} [timeout=30000] - Timeout in milliseconds + * @returns {Promise} Test result object + */ +async function waitForTestResult(page, timeout = 30000) { + console.log("Running test..."); + await page.waitForFunction(() => window.testResult !== undefined, { timeout }); + return await page.evaluate(() => window.testResult); +} + +/** + * Evaluate and log test results + * @param {Object} result - Test result object + * @returns {boolean} True if test passed, false otherwise + */ +function evaluateTestResult(result) { + console.log("\n" + "=".repeat(50)); + console.log("TEST RESULT"); + console.log("=".repeat(50)); + console.log(JSON.stringify(result, null, 2)); + console.log("=".repeat(50) + "\n"); + + if (result.success) { + console.log("✓ Test PASSED\n"); + + // Log additional details + if (result.audioSize) { + console.log("Audio file size:", result.audioSize, "bytes"); + } + if (result.firstTranscript) { + const preview = result.firstTranscript.length > 100 + ? result.firstTranscript.substring(0, 100) + "..." + : result.firstTranscript; + console.log("Transcript:", preview, "\n"); + } + + return true; + } else { + // Check if it's a CORS/network error (expected in browsers) + const isCorsError = result.error && ( + result.error.includes("CORS") || + result.error.includes("Access-Control") || + result.error.includes("Failed to fetch") || + result.stack?.includes("Failed to fetch") + ); + + if (isCorsError) { + console.log("⚠️ Test encountered CORS/network error (expected in browsers)"); + console.log(" Browser console showed CORS policy blocking the request."); + console.log(" This is normal - browsers can't make direct API calls with custom headers."); + console.log(" The SDK loaded, initialized, and executed correctly!"); + console.log(" In production, proxy API calls through your backend.\n"); + console.log("✓ SDK browser compatibility test: PASSED\n"); + return true; + } else { + console.error("✗ Test FAILED:", result.error, "\n"); + return false; + } + } +} + +/** + * Cleanup test files and resources + * @param {Object} options - Cleanup options + * @param {Array} options.files - Files to delete + * @param {http.Server} [options.server] - Server to close + * @param {Object} [options.browser] - Browser to close + */ +async function cleanup({ files = [], server, browser }) { + console.log("Cleaning up..."); + + for (const file of files) { + try { + if (fs.existsSync(file)) { + fs.unlinkSync(file); + } + } catch (err) { + console.error(`Failed to delete ${file}:`, err.message); + } + } + + if (browser) { + await browser.close(); + } + + if (server) { + server.close(); + } + + console.log("✓ Cleaned up temporary files"); +} + +/** + * Run a complete browser test + * @param {Object} config - Test configuration + * @returns {Promise} + */ +async function runBrowserTest(config) { + let browser; + let server; + const bundlePath = path.join(config.testDir, "deepgram-browser-bundle.js"); + const testHtmlPath = path.join(config.testDir, "test-browser.html"); + + try { + console.log("Setting up browser test environment...\n"); + + // Get API key + const apiKey = process.env.DEEPGRAM_API_KEY; + if (!apiKey) { + throw new Error("DEEPGRAM_API_KEY environment variable is not set"); + } + + // Build bundle + await buildBrowserBundle(config.testDir); + + // Prepare HTML + prepareHtmlTemplate({ + templatePath: path.join(config.testDir, "browser-standalone.html"), + outputPath: testHtmlPath, + replacements: { DEEPGRAM_API_KEY: apiKey }, + }); + console.log("✓ Test HTML prepared\n"); + + // Start server + console.log(`Starting HTTP server on port ${config.port}...`); + server = await createServer({ + testDir: config.testDir, + port: config.port, + customFileHandler: config.customFileHandler, + }); + console.log(`✓ Server running at http://localhost:${config.port}\n`); + + // Launch browser and run test + const browserTest = await launchBrowserTest({ port: config.port }); + browser = browserTest.browser; + const page = browserTest.page; + + // Wait for result + const result = await waitForTestResult(page, config.timeout || 30000); + + // Evaluate result + const passed = evaluateTestResult(result); + if (!passed) { + process.exitCode = 1; + } + + // Cleanup + await cleanup({ + files: [testHtmlPath, bundlePath], + server, + browser, + }); + } catch (error) { + console.error("\n✗ Error:", error.message); + if (error.stack) { + console.error(error.stack); + } + process.exitCode = 1; + + // Attempt cleanup + await cleanup({ + files: [testHtmlPath, bundlePath], + server, + browser, + }); + } +} + +module.exports = { + buildBrowserBundle, + createServer, + prepareHtmlTemplate, + launchBrowserTest, + waitForTestResult, + evaluateTestResult, + cleanup, + runBrowserTest, +}; + + diff --git a/tests/manual/fixtures/audio.mp3 b/tests/manual/fixtures/audio.mp3 new file mode 100644 index 00000000..ca632f71 Binary files /dev/null and b/tests/manual/fixtures/audio.mp3 differ diff --git a/examples/spacewalk.wav b/tests/manual/fixtures/audio.wav similarity index 100% rename from examples/spacewalk.wav rename to tests/manual/fixtures/audio.wav diff --git a/tests/manual/listen/v1/connect/main.js b/tests/manual/listen/v1/connect/main.js new file mode 100644 index 00000000..f05c8149 --- /dev/null +++ b/tests/manual/listen/v1/connect/main.js @@ -0,0 +1,42 @@ +// @ts-check +/** @typedef {import("../../../../../dist/cjs/index.js").DeepgramClient} */ +const { DeepgramClient } = require("../../../../../dist/cjs/index.js"); + +/** @type {DeepgramClient} */ +const client = new DeepgramClient(); + +(async () => { + try { + const connection = await client.listen.v1.connect({ + model: 'nova-3' + }); + + connection.on('open', () => { + console.log('Connection opened'); + }); + + connection.on('message', (message) => { + const msgType = message?.type || 'Unknown'; + console.log(`Received ${msgType} event`); + }); + + connection.on('close', () => { + console.log('Connection closed'); + }); + + connection.on('error', (error) => { + console.log(`Caught: ${error.message || error}`); + }); + + // EXAMPLE ONLY: Wait briefly to see some events before exiting + // In production, you would typically keep the connection alive and send audio data + // or integrate into your application's event loop + setTimeout(() => { + connection.close(); + }, 3000); // EXAMPLE ONLY: Wait 3 seconds before closing + } catch (e) { + console.error(`Error: ${e.message || e}`); + throw e; + } +})(); + diff --git a/tests/manual/listen/v1/media/transcribe_file/browser-standalone.html b/tests/manual/listen/v1/media/transcribe_file/browser-standalone.html new file mode 100644 index 00000000..491ee2ec --- /dev/null +++ b/tests/manual/listen/v1/media/transcribe_file/browser-standalone.html @@ -0,0 +1,87 @@ + + + + + Deepgram SDK Browser Test - transcribeFile + + +

Deepgram SDK Browser Test - transcribeFile

+
Loading...
+

+    
+    
+    
+
+
+
diff --git a/tests/manual/listen/v1/media/transcribe_file/browser-standalone.js b/tests/manual/listen/v1/media/transcribe_file/browser-standalone.js
new file mode 100644
index 00000000..c712ed9e
--- /dev/null
+++ b/tests/manual/listen/v1/media/transcribe_file/browser-standalone.js
@@ -0,0 +1,48 @@
+const path = require("path");
+const fs = require("fs");
+const { runBrowserTest } = require("../../../../browser-test-utils.js");
+
+/**
+ * Browser test for transcribeFile method
+ * 
+ * Tests the SDK's ability to upload and transcribe audio files in a browser environment.
+ * Serves a local audio file via HTTP and tests binary data handling.
+ */
+
+(async () => {
+    await runBrowserTest({
+        testDir: __dirname,
+        port: 8766,
+        timeout: 30000,
+        customFileHandler: (req, res, testDir) => {
+            // Handle audio file request
+            if (req.url === "/audio.wav") {
+                const audioPath = path.resolve(__dirname, "../../../../../../tests/manual/fixtures/audio.wav");
+                const fixturesPath = path.resolve(__dirname, "../../../../../../tests/manual/fixtures");
+                
+                // Security check
+                if (!audioPath.startsWith(fixturesPath)) {
+                    res.writeHead(403);
+                    res.end("Forbidden");
+                    return true;
+                }
+
+                fs.readFile(audioPath, (err, data) => {
+                    if (err) {
+                        res.writeHead(404);
+                        res.end("Audio file not found");
+                        return;
+                    }
+
+                    res.writeHead(200, {
+                        "Content-Type": "audio/wav",
+                        "Access-Control-Allow-Origin": "*",
+                    });
+                    res.end(data);
+                });
+                return true; // Handled
+            }
+            return false; // Not handled, use default
+        },
+    });
+})();
diff --git a/tests/manual/listen/v1/media/transcribe_file/main.js b/tests/manual/listen/v1/media/transcribe_file/main.js
new file mode 100644
index 00000000..219621d5
--- /dev/null
+++ b/tests/manual/listen/v1/media/transcribe_file/main.js
@@ -0,0 +1,26 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+const fs = require('fs');
+const path = require('path');
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        // Path to audio file from fixtures
+        const audioPath = path.join(__dirname, '..', '..', '..', '..', 'fixtures', 'audio.wav');
+        const audioData = fs.readFileSync(audioPath);
+
+        console.log('Request sent');
+        const response = await client.listen.v1.media.transcribeFile(audioData, {
+            model: 'nova-3'
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/listen/v1/media/transcribe_url/browser-standalone.html b/tests/manual/listen/v1/media/transcribe_url/browser-standalone.html
new file mode 100644
index 00000000..a5122705
--- /dev/null
+++ b/tests/manual/listen/v1/media/transcribe_url/browser-standalone.html
@@ -0,0 +1,73 @@
+
+
+
+
+    
+    Deepgram SDK Browser Test - transcribeUrl
+
+
+
+    

Deepgram SDK Browser Test - transcribeUrl

+
Loading...
+

+
+    
+    
+
+
+
\ No newline at end of file
diff --git a/tests/manual/listen/v1/media/transcribe_url/browser-standalone.js b/tests/manual/listen/v1/media/transcribe_url/browser-standalone.js
new file mode 100644
index 00000000..0a0961f4
--- /dev/null
+++ b/tests/manual/listen/v1/media/transcribe_url/browser-standalone.js
@@ -0,0 +1,17 @@
+const path = require("path");
+const { runBrowserTest } = require("../../../../browser-test-utils.js");
+
+/**
+ * Browser test for transcribeUrl method
+ * 
+ * Tests the SDK's ability to transcribe audio from a URL in a browser environment.
+ * Uses webpack to create a browser-compatible bundle and Playwright for testing.
+ */
+
+(async () => {
+    await runBrowserTest({
+        testDir: __dirname,
+        port: 8765,
+        timeout: 30000,
+    });
+})();
diff --git a/tests/manual/listen/v1/media/transcribe_url/main.js b/tests/manual/listen/v1/media/transcribe_url/main.js
new file mode 100644
index 00000000..fc52e997
--- /dev/null
+++ b/tests/manual/listen/v1/media/transcribe_url/main.js
@@ -0,0 +1,22 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.listen.v1.media.transcribeUrl({
+            url: 'https://dpgr.am/spacewalk.wav'
+        }, {
+            model: 'nova-3'
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/listen/v2/connect/main.js b/tests/manual/listen/v2/connect/main.js
new file mode 100644
index 00000000..cb0fd175
--- /dev/null
+++ b/tests/manual/listen/v2/connect/main.js
@@ -0,0 +1,44 @@
+// @ts-check
+/** @typedef {import("../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        const connection = await client.listen.v2.connect({
+            model: 'flux-general-en',
+            encoding: 'linear16',
+            sample_rate: '16000'
+        });
+
+        connection.on('open', () => {
+            console.log('Connection opened');
+        });
+
+        connection.on('message', (message) => {
+            const msgType = message?.type || 'Unknown';
+            console.log(`Received ${msgType} event`);
+        });
+
+        connection.on('close', () => {
+            console.log('Connection closed');
+        });
+
+        connection.on('error', (error) => {
+            console.log(`Caught: ${error.message || error}`);
+        });
+
+        // EXAMPLE ONLY: Wait briefly to see some events before exiting
+        // In production, you would typically keep the connection alive and send audio data
+        // or integrate into your application's event loop
+        setTimeout(() => {
+            connection.close();
+        }, 3000); // EXAMPLE ONLY: Wait 3 seconds before closing
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/models/get/main.js b/tests/manual/manage/v1/models/get/main.js
new file mode 100644
index 00000000..b0528dc4
--- /dev/null
+++ b/tests/manual/manage/v1/models/get/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.models.get("af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/models/list/main.js b/tests/manual/manage/v1/models/list/main.js
new file mode 100644
index 00000000..b51533bc
--- /dev/null
+++ b/tests/manual/manage/v1/models/list/main.js
@@ -0,0 +1,20 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.models.list({
+            include_outdated: true,
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/billing/balances/get/main.js b/tests/manual/manage/v1/projects/billing/balances/get/main.js
new file mode 100644
index 00000000..ab099d5a
--- /dev/null
+++ b/tests/manual/manage/v1/projects/billing/balances/get/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.billing.balances.get("123456-7890-1234-5678-901234", "123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/billing/balances/list/main.js b/tests/manual/manage/v1/projects/billing/balances/list/main.js
new file mode 100644
index 00000000..98455cc7
--- /dev/null
+++ b/tests/manual/manage/v1/projects/billing/balances/list/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.billing.balances.list("123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/billing/breakdown/list/main.js b/tests/manual/manage/v1/projects/billing/breakdown/list/main.js
new file mode 100644
index 00000000..f961d896
--- /dev/null
+++ b/tests/manual/manage/v1/projects/billing/breakdown/list/main.js
@@ -0,0 +1,25 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.billing.breakdown.list("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+            accessor: "12345678-1234-1234-1234-123456789012",
+            deployment: "hosted",
+            tag: "tag1",
+            line_item: "streaming::nova-3",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/billing/fields/list/main.js b/tests/manual/manage/v1/projects/billing/fields/list/main.js
new file mode 100644
index 00000000..46bb5e0d
--- /dev/null
+++ b/tests/manual/manage/v1/projects/billing/fields/list/main.js
@@ -0,0 +1,21 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.billing.fields.list("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/billing/purchases/list/main.js b/tests/manual/manage/v1/projects/billing/purchases/list/main.js
new file mode 100644
index 00000000..ed7059b5
--- /dev/null
+++ b/tests/manual/manage/v1/projects/billing/purchases/list/main.js
@@ -0,0 +1,20 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.billing.purchases.list("123456-7890-1234-5678-901234", {
+            limit: 1.1,
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/delete/main.js b/tests/manual/manage/v1/projects/delete/main.js
new file mode 100644
index 00000000..33b6560e
--- /dev/null
+++ b/tests/manual/manage/v1/projects/delete/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.delete("123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/get/main.js b/tests/manual/manage/v1/projects/get/main.js
new file mode 100644
index 00000000..ed29ffd8
--- /dev/null
+++ b/tests/manual/manage/v1/projects/get/main.js
@@ -0,0 +1,21 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.get("123456-7890-1234-5678-901234", {
+            limit: 1.1,
+            page: 1.1,
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/keys/create/main.js b/tests/manual/manage/v1/projects/keys/create/main.js
new file mode 100644
index 00000000..f5d70569
--- /dev/null
+++ b/tests/manual/manage/v1/projects/keys/create/main.js
@@ -0,0 +1,20 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.keys.create("project_id", {
+            key: "value",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/keys/delete/main.js b/tests/manual/manage/v1/projects/keys/delete/main.js
new file mode 100644
index 00000000..6502e590
--- /dev/null
+++ b/tests/manual/manage/v1/projects/keys/delete/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.keys.delete("123456-7890-1234-5678-901234", "123456789012345678901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/keys/get/main.js b/tests/manual/manage/v1/projects/keys/get/main.js
new file mode 100644
index 00000000..50a767f5
--- /dev/null
+++ b/tests/manual/manage/v1/projects/keys/get/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.keys.get("123456-7890-1234-5678-901234", "123456789012345678901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/keys/list/main.js b/tests/manual/manage/v1/projects/keys/list/main.js
new file mode 100644
index 00000000..578d1d6f
--- /dev/null
+++ b/tests/manual/manage/v1/projects/keys/list/main.js
@@ -0,0 +1,20 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.keys.list("123456-7890-1234-5678-901234", {
+            status: "active",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/leave/main.js b/tests/manual/manage/v1/projects/leave/main.js
new file mode 100644
index 00000000..11b7e7c0
--- /dev/null
+++ b/tests/manual/manage/v1/projects/leave/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.leave("123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/list/main.js b/tests/manual/manage/v1/projects/list/main.js
new file mode 100644
index 00000000..401d0218
--- /dev/null
+++ b/tests/manual/manage/v1/projects/list/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.list();
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/members/delete/main.js b/tests/manual/manage/v1/projects/members/delete/main.js
new file mode 100644
index 00000000..01766b5b
--- /dev/null
+++ b/tests/manual/manage/v1/projects/members/delete/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.members.delete("123456-7890-1234-5678-901234", "123456789012345678901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/members/invites/create/main.js b/tests/manual/manage/v1/projects/members/invites/create/main.js
new file mode 100644
index 00000000..305ba01d
--- /dev/null
+++ b/tests/manual/manage/v1/projects/members/invites/create/main.js
@@ -0,0 +1,21 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.members.invites.create("123456-7890-1234-5678-901234", {
+            email: "email",
+            scope: "scope",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/members/invites/delete/main.js b/tests/manual/manage/v1/projects/members/invites/delete/main.js
new file mode 100644
index 00000000..47374402
--- /dev/null
+++ b/tests/manual/manage/v1/projects/members/invites/delete/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.members.invites.delete("123456-7890-1234-5678-901234", "john.doe@example.com");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/members/invites/list/main.js b/tests/manual/manage/v1/projects/members/invites/list/main.js
new file mode 100644
index 00000000..fa2aaf28
--- /dev/null
+++ b/tests/manual/manage/v1/projects/members/invites/list/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.members.invites.list("123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/members/list/main.js b/tests/manual/manage/v1/projects/members/list/main.js
new file mode 100644
index 00000000..f31188e7
--- /dev/null
+++ b/tests/manual/manage/v1/projects/members/list/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.members.list("123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/members/scopes/list/main.js b/tests/manual/manage/v1/projects/members/scopes/list/main.js
new file mode 100644
index 00000000..3a598fa0
--- /dev/null
+++ b/tests/manual/manage/v1/projects/members/scopes/list/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.members.scopes.list("123456-7890-1234-5678-901234", "123456789012345678901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/members/scopes/update/main.js b/tests/manual/manage/v1/projects/members/scopes/update/main.js
new file mode 100644
index 00000000..cf1f87ee
--- /dev/null
+++ b/tests/manual/manage/v1/projects/members/scopes/update/main.js
@@ -0,0 +1,20 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.members.scopes.update("123456-7890-1234-5678-901234", "123456789012345678901234", {
+            scope: "admin",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/models/get/main.js b/tests/manual/manage/v1/projects/models/get/main.js
new file mode 100644
index 00000000..4d7f335c
--- /dev/null
+++ b/tests/manual/manage/v1/projects/models/get/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.models.get("123456-7890-1234-5678-901234", "af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/models/list/main.js b/tests/manual/manage/v1/projects/models/list/main.js
new file mode 100644
index 00000000..cebc54db
--- /dev/null
+++ b/tests/manual/manage/v1/projects/models/list/main.js
@@ -0,0 +1,20 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.models.list("123456-7890-1234-5678-901234", {
+            include_outdated: true,
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/requests/get/main.js b/tests/manual/manage/v1/projects/requests/get/main.js
new file mode 100644
index 00000000..158c38ca
--- /dev/null
+++ b/tests/manual/manage/v1/projects/requests/get/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.requests.get("123456-7890-1234-5678-901234", "123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/requests/list/main.js b/tests/manual/manage/v1/projects/requests/list/main.js
new file mode 100644
index 00000000..99886f71
--- /dev/null
+++ b/tests/manual/manage/v1/projects/requests/list/main.js
@@ -0,0 +1,29 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.requests.list("123456-7890-1234-5678-901234", {
+            start: "2024-01-15T09:30:00Z",
+            end: "2024-01-15T09:30:00Z",
+            limit: 1.1,
+            page: 1.1,
+            accessor: "12345678-1234-1234-1234-123456789012",
+            request_id: "12345678-1234-1234-1234-123456789012",
+            deployment: "hosted",
+            endpoint: "listen",
+            method: "sync",
+            status: "succeeded",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/update/main.js b/tests/manual/manage/v1/projects/update/main.js
new file mode 100644
index 00000000..dbd4b4f2
--- /dev/null
+++ b/tests/manual/manage/v1/projects/update/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.update("123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/usage/breakdown/get/main.js b/tests/manual/manage/v1/projects/usage/breakdown/get/main.js
new file mode 100644
index 00000000..1b87b441
--- /dev/null
+++ b/tests/manual/manage/v1/projects/usage/breakdown/get/main.js
@@ -0,0 +1,64 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.usage.breakdown.get("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+            grouping: "accessor",
+            accessor: "12345678-1234-1234-1234-123456789012",
+            alternatives: true,
+            callback_method: true,
+            callback: true,
+            channels: true,
+            custom_intent_mode: true,
+            custom_intent: true,
+            custom_topic_mode: true,
+            custom_topic: true,
+            deployment: "hosted",
+            detect_entities: true,
+            detect_language: true,
+            diarize: true,
+            dictation: true,
+            encoding: true,
+            endpoint: "listen",
+            extra: true,
+            filler_words: true,
+            intents: true,
+            keyterm: true,
+            keywords: true,
+            language: true,
+            measurements: true,
+            method: "sync",
+            model: "6f548761-c9c0-429a-9315-11a1d28499c8",
+            multichannel: true,
+            numerals: true,
+            paragraphs: true,
+            profanity_filter: true,
+            punctuate: true,
+            redact: true,
+            replace: true,
+            sample_rate: true,
+            search: true,
+            sentiment: true,
+            smart_format: true,
+            summarize: true,
+            tag: "tag1",
+            topics: true,
+            utt_split: true,
+            utterances: true,
+            version: true,
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/usage/fields/list/main.js b/tests/manual/manage/v1/projects/usage/fields/list/main.js
new file mode 100644
index 00000000..43e2e615
--- /dev/null
+++ b/tests/manual/manage/v1/projects/usage/fields/list/main.js
@@ -0,0 +1,21 @@
+// @ts-check
+/** @typedef {import("../../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.usage.fields.list("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/manage/v1/projects/usage/get/main.js b/tests/manual/manage/v1/projects/usage/get/main.js
new file mode 100644
index 00000000..28ba944b
--- /dev/null
+++ b/tests/manual/manage/v1/projects/usage/get/main.js
@@ -0,0 +1,63 @@
+// @ts-check
+/** @typedef {import("../../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.manage.v1.projects.usage.get("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+            accessor: "12345678-1234-1234-1234-123456789012",
+            alternatives: true,
+            callback_method: true,
+            callback: true,
+            channels: true,
+            custom_intent_mode: true,
+            custom_intent: true,
+            custom_topic_mode: true,
+            custom_topic: true,
+            deployment: "hosted",
+            detect_entities: true,
+            detect_language: true,
+            diarize: true,
+            dictation: true,
+            encoding: true,
+            endpoint: "listen",
+            extra: true,
+            filler_words: true,
+            intents: true,
+            keyterm: true,
+            keywords: true,
+            language: true,
+            measurements: true,
+            method: "sync",
+            model: "6f548761-c9c0-429a-9315-11a1d28499c8",
+            multichannel: true,
+            numerals: true,
+            paragraphs: true,
+            profanity_filter: true,
+            punctuate: true,
+            redact: true,
+            replace: true,
+            sample_rate: true,
+            search: true,
+            sentiment: true,
+            smart_format: true,
+            summarize: true,
+            tag: "tag1",
+            topics: true,
+            utt_split: true,
+            utterances: true,
+            version: true,
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/read/v1/text/analyze/main.js b/tests/manual/read/v1/text/analyze/main.js
new file mode 100644
index 00000000..11363a0b
--- /dev/null
+++ b/tests/manual/read/v1/text/analyze/main.js
@@ -0,0 +1,26 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log("Request sent");
+        const response = await client.read.v1.text.analyze({
+            language: "en",
+            sentiment: true,
+            summarize: "v2",
+            topics: true,
+            intents: true,
+            body: {
+                text: "Hello, world!",
+            },
+        });
+        console.log("Response received");
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
diff --git a/tests/manual/selfHosted/v1/distributionCredentials/create/main.js b/tests/manual/selfHosted/v1/distributionCredentials/create/main.js
new file mode 100644
index 00000000..01dff2f2
--- /dev/null
+++ b/tests/manual/selfHosted/v1/distributionCredentials/create/main.js
@@ -0,0 +1,20 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.selfHosted.v1.distributionCredentials.create("123456-7890-1234-5678-901234", {
+            provider: "quay",
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/selfHosted/v1/distributionCredentials/delete/main.js b/tests/manual/selfHosted/v1/distributionCredentials/delete/main.js
new file mode 100644
index 00000000..fd40bfaf
--- /dev/null
+++ b/tests/manual/selfHosted/v1/distributionCredentials/delete/main.js
@@ -0,0 +1,21 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.selfHosted.v1.distributionCredentials.delete(
+            "123456-7890-1234-5678-901234",
+            "8b36cfd0-472f-4a21-833f-2d6343c3a2f3",
+        );
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/selfHosted/v1/distributionCredentials/get/main.js b/tests/manual/selfHosted/v1/distributionCredentials/get/main.js
new file mode 100644
index 00000000..ba4e6eac
--- /dev/null
+++ b/tests/manual/selfHosted/v1/distributionCredentials/get/main.js
@@ -0,0 +1,21 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.selfHosted.v1.distributionCredentials.get(
+            "123456-7890-1234-5678-901234",
+            "8b36cfd0-472f-4a21-833f-2d6343c3a2f3",
+        );
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/selfHosted/v1/distributionCredentials/list/main.js b/tests/manual/selfHosted/v1/distributionCredentials/list/main.js
new file mode 100644
index 00000000..1c4422fe
--- /dev/null
+++ b/tests/manual/selfHosted/v1/distributionCredentials/list/main.js
@@ -0,0 +1,18 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.selfHosted.v1.distributionCredentials.list("123456-7890-1234-5678-901234");
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/speak/v1/audio/generate/main.js b/tests/manual/speak/v1/audio/generate/main.js
new file mode 100644
index 00000000..8eae8c0e
--- /dev/null
+++ b/tests/manual/speak/v1/audio/generate/main.js
@@ -0,0 +1,20 @@
+// @ts-check
+/** @typedef {import("../../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        console.log('Request sent');
+        const response = await client.speak.v1.audio.generate({
+            text: 'Hello, this is a sample text to speech conversion.'
+        });
+        console.log('Response received');
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/manual/speak/v1/connect/main.js b/tests/manual/speak/v1/connect/main.js
new file mode 100644
index 00000000..ace4b178
--- /dev/null
+++ b/tests/manual/speak/v1/connect/main.js
@@ -0,0 +1,54 @@
+// @ts-check
+/** @typedef {import("../../../../../dist/cjs/index.js").DeepgramClient} */
+const { DeepgramClient } = require("../../../../../dist/cjs/index.js");
+
+/** @type {DeepgramClient} */
+const client = new DeepgramClient();
+
+(async () => {
+    try {
+        const connection = await client.speak.v1.connect({
+            model: 'aura-2-asteria-en',
+            encoding: 'linear16',
+            sample_rate: 24000
+        });
+
+        connection.on('open', () => {
+            console.log('Connection opened');
+        });
+
+        connection.on('message', (message) => {
+            if (message instanceof Buffer || message instanceof ArrayBuffer) {
+                console.log('Received audio event');
+            } else {
+                const msgType = message?.type || 'Unknown';
+                console.log(`Received ${msgType} event`);
+            }
+        });
+
+        connection.on('close', () => {
+            console.log('Connection closed');
+        });
+
+        connection.on('error', (error) => {
+            console.log(`Caught: ${error.message || error}`);
+        });
+
+        // Send control messages
+        console.log('Send Flush message');
+        connection.sendControl({ type: 'Flush' });
+        console.log('Send Close message');
+        connection.sendControl({ type: 'Close' });
+
+        // EXAMPLE ONLY: Wait briefly to see some events before exiting
+        // In production, you would typically keep the connection alive and send text data
+        // or integrate into your application's event loop
+        setTimeout(() => {
+            connection.close();
+        }, 3000); // EXAMPLE ONLY: Wait 3 seconds before closing
+    } catch (e) {
+        console.error(`Error: ${e.message || e}`);
+        throw e;
+    }
+})();
+
diff --git a/tests/mock-server/MockServer.ts b/tests/mock-server/MockServer.ts
new file mode 100644
index 00000000..95487215
--- /dev/null
+++ b/tests/mock-server/MockServer.ts
@@ -0,0 +1,29 @@
+import type { RequestHandlerOptions } from "msw";
+import type { SetupServer } from "msw/node";
+
+import { mockEndpointBuilder } from "./mockEndpointBuilder";
+
+export interface MockServerOptions {
+    baseUrl: string;
+    server: SetupServer;
+}
+
+export class MockServer {
+    private readonly server: SetupServer;
+    public readonly baseUrl: string;
+
+    constructor({ baseUrl, server }: MockServerOptions) {
+        this.baseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
+        this.server = server;
+    }
+
+    public mockEndpoint(options?: RequestHandlerOptions): ReturnType {
+        const builder = mockEndpointBuilder({
+            once: options?.once ?? true,
+            onBuild: (handler) => {
+                this.server.use(handler);
+            },
+        }).baseUrl(this.baseUrl);
+        return builder;
+    }
+}
diff --git a/tests/mock-server/MockServerPool.ts b/tests/mock-server/MockServerPool.ts
new file mode 100644
index 00000000..e1a90f7f
--- /dev/null
+++ b/tests/mock-server/MockServerPool.ts
@@ -0,0 +1,106 @@
+import { setupServer } from "msw/node";
+
+import { fromJson, toJson } from "../../src/core/json";
+import { MockServer } from "./MockServer";
+import { randomBaseUrl } from "./randomBaseUrl";
+
+const mswServer = setupServer();
+interface MockServerOptions {
+    baseUrl?: string;
+}
+
+async function formatHttpRequest(request: Request, id?: string): Promise {
+    try {
+        const clone = request.clone();
+        const headers = [...clone.headers.entries()].map(([k, v]) => `${k}: ${v}`).join("\n");
+
+        let body = "";
+        try {
+            const contentType = clone.headers.get("content-type");
+            if (contentType?.includes("application/json")) {
+                body = toJson(fromJson(await clone.text()), undefined, 2);
+            } else if (clone.body) {
+                body = await clone.text();
+            }
+        } catch (_e) {
+            body = "(unable to parse body)";
+        }
+
+        const title = id ? `### Request ${id} ###\n` : "";
+        const firstLine = `${title}${request.method} ${request.url.toString()} HTTP/1.1`;
+
+        return `\n${firstLine}\n${headers}\n\n${body || "(no body)"}\n`;
+    } catch (e) {
+        return `Error formatting request: ${e}`;
+    }
+}
+
+async function formatHttpResponse(response: Response, id?: string): Promise {
+    try {
+        const clone = response.clone();
+        const headers = [...clone.headers.entries()].map(([k, v]) => `${k}: ${v}`).join("\n");
+
+        let body = "";
+        try {
+            const contentType = clone.headers.get("content-type");
+            if (contentType?.includes("application/json")) {
+                body = toJson(fromJson(await clone.text()), undefined, 2);
+            } else if (clone.body) {
+                body = await clone.text();
+            }
+        } catch (_e) {
+            body = "(unable to parse body)";
+        }
+
+        const title = id ? `### Response for ${id} ###\n` : "";
+        const firstLine = `${title}HTTP/1.1 ${response.status} ${response.statusText}`;
+
+        return `\n${firstLine}\n${headers}\n\n${body || "(no body)"}\n`;
+    } catch (e) {
+        return `Error formatting response: ${e}`;
+    }
+}
+
+class MockServerPool {
+    private servers: MockServer[] = [];
+
+    public createServer(options?: Partial): MockServer {
+        const baseUrl = options?.baseUrl || randomBaseUrl();
+        const server = new MockServer({ baseUrl, server: mswServer });
+        this.servers.push(server);
+        return server;
+    }
+
+    public getServers(): MockServer[] {
+        return [...this.servers];
+    }
+
+    public listen(): void {
+        const onUnhandledRequest = process.env.LOG_LEVEL === "debug" ? "warn" : "bypass";
+        mswServer.listen({ onUnhandledRequest });
+
+        if (process.env.LOG_LEVEL === "debug") {
+            mswServer.events.on("request:start", async ({ request, requestId }) => {
+                const formattedRequest = await formatHttpRequest(request, requestId);
+                console.debug(`request:start\n${formattedRequest}`);
+            });
+
+            mswServer.events.on("request:unhandled", async ({ request, requestId }) => {
+                const formattedRequest = await formatHttpRequest(request, requestId);
+                console.debug(`request:unhandled\n${formattedRequest}`);
+            });
+
+            mswServer.events.on("response:mocked", async ({ request, response, requestId }) => {
+                const formattedResponse = await formatHttpResponse(response, requestId);
+                console.debug(`response:mocked\n${formattedResponse}`);
+            });
+        }
+    }
+
+    public close(): void {
+        this.servers = [];
+        mswServer.close();
+    }
+}
+
+export const mockServerPool = new MockServerPool();
diff --git a/tests/mock-server/mockEndpointBuilder.ts b/tests/mock-server/mockEndpointBuilder.ts
new file mode 100644
index 00000000..1b0e5107
--- /dev/null
+++ b/tests/mock-server/mockEndpointBuilder.ts
@@ -0,0 +1,227 @@
+import { type DefaultBodyType, type HttpHandler, HttpResponse, type HttpResponseResolver, http } from "msw";
+
+import { url } from "../../src/core";
+import { toJson } from "../../src/core/json";
+import { withFormUrlEncoded } from "./withFormUrlEncoded";
+import { withHeaders } from "./withHeaders";
+import { withJson } from "./withJson";
+
+type HttpMethod = "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head";
+
+interface MethodStage {
+    baseUrl(baseUrl: string): MethodStage;
+    all(path: string): RequestHeadersStage;
+    get(path: string): RequestHeadersStage;
+    post(path: string): RequestHeadersStage;
+    put(path: string): RequestHeadersStage;
+    delete(path: string): RequestHeadersStage;
+    patch(path: string): RequestHeadersStage;
+    options(path: string): RequestHeadersStage;
+    head(path: string): RequestHeadersStage;
+}
+
+interface RequestHeadersStage extends RequestBodyStage, ResponseStage {
+    header(name: string, value: string): RequestHeadersStage;
+    headers(headers: Record): RequestBodyStage;
+}
+
+interface RequestBodyStage extends ResponseStage {
+    jsonBody(body: unknown): ResponseStage;
+    formUrlEncodedBody(body: unknown): ResponseStage;
+}
+
+interface ResponseStage {
+    respondWith(): ResponseStatusStage;
+}
+interface ResponseStatusStage {
+    statusCode(statusCode: number): ResponseHeaderStage;
+}
+
+interface ResponseHeaderStage extends ResponseBodyStage, BuildStage {
+    header(name: string, value: string): ResponseHeaderStage;
+    headers(headers: Record): ResponseHeaderStage;
+}
+
+interface ResponseBodyStage {
+    jsonBody(body: unknown): BuildStage;
+}
+
+interface BuildStage {
+    build(): HttpHandler;
+}
+
+export interface HttpHandlerBuilderOptions {
+    onBuild?: (handler: HttpHandler) => void;
+    once?: boolean;
+}
+
+class RequestBuilder implements MethodStage, RequestHeadersStage, RequestBodyStage, ResponseStage {
+    private method: HttpMethod = "get";
+    private _baseUrl: string = "";
+    private path: string = "/";
+    private readonly predicates: ((resolver: HttpResponseResolver) => HttpResponseResolver)[] = [];
+    private readonly handlerOptions?: HttpHandlerBuilderOptions;
+
+    constructor(options?: HttpHandlerBuilderOptions) {
+        this.handlerOptions = options;
+    }
+
+    baseUrl(baseUrl: string): MethodStage {
+        this._baseUrl = baseUrl;
+        return this;
+    }
+
+    all(path: string): RequestHeadersStage {
+        this.method = "all";
+        this.path = path;
+        return this;
+    }
+
+    get(path: string): RequestHeadersStage {
+        this.method = "get";
+        this.path = path;
+        return this;
+    }
+
+    post(path: string): RequestHeadersStage {
+        this.method = "post";
+        this.path = path;
+        return this;
+    }
+
+    put(path: string): RequestHeadersStage {
+        this.method = "put";
+        this.path = path;
+        return this;
+    }
+
+    delete(path: string): RequestHeadersStage {
+        this.method = "delete";
+        this.path = path;
+        return this;
+    }
+
+    patch(path: string): RequestHeadersStage {
+        this.method = "patch";
+        this.path = path;
+        return this;
+    }
+
+    options(path: string): RequestHeadersStage {
+        this.method = "options";
+        this.path = path;
+        return this;
+    }
+
+    head(path: string): RequestHeadersStage {
+        this.method = "head";
+        this.path = path;
+        return this;
+    }
+
+    header(name: string, value: string): RequestHeadersStage {
+        this.predicates.push((resolver) => withHeaders({ [name]: value }, resolver));
+        return this;
+    }
+
+    headers(headers: Record): RequestBodyStage {
+        this.predicates.push((resolver) => withHeaders(headers, resolver));
+        return this;
+    }
+
+    jsonBody(body: unknown): ResponseStage {
+        if (body === undefined) {
+            throw new Error("Undefined is not valid JSON. Do not call jsonBody if you want an empty body.");
+        }
+        this.predicates.push((resolver) => withJson(body, resolver));
+        return this;
+    }
+
+    formUrlEncodedBody(body: unknown): ResponseStage {
+        if (body === undefined) {
+            throw new Error(
+                "Undefined is not valid for form-urlencoded. Do not call formUrlEncodedBody if you want an empty body.",
+            );
+        }
+        this.predicates.push((resolver) => withFormUrlEncoded(body, resolver));
+        return this;
+    }
+
+    respondWith(): ResponseStatusStage {
+        return new ResponseBuilder(this.method, this.buildUrl(), this.predicates, this.handlerOptions);
+    }
+
+    private buildUrl(): string {
+        return url.join(this._baseUrl, this.path);
+    }
+}
+
+class ResponseBuilder implements ResponseStatusStage, ResponseHeaderStage, ResponseBodyStage, BuildStage {
+    private readonly method: HttpMethod;
+    private readonly url: string;
+    private readonly requestPredicates: ((resolver: HttpResponseResolver) => HttpResponseResolver)[];
+    private readonly handlerOptions?: HttpHandlerBuilderOptions;
+
+    private responseStatusCode: number = 200;
+    private responseHeaders: Record = {};
+    private responseBody: DefaultBodyType = undefined;
+
+    constructor(
+        method: HttpMethod,
+        url: string,
+        requestPredicates: ((resolver: HttpResponseResolver) => HttpResponseResolver)[],
+        options?: HttpHandlerBuilderOptions,
+    ) {
+        this.method = method;
+        this.url = url;
+        this.requestPredicates = requestPredicates;
+        this.handlerOptions = options;
+    }
+
+    public statusCode(code: number): ResponseHeaderStage {
+        this.responseStatusCode = code;
+        return this;
+    }
+
+    public header(name: string, value: string): ResponseHeaderStage {
+        this.responseHeaders[name] = value;
+        return this;
+    }
+
+    public headers(headers: Record): ResponseHeaderStage {
+        this.responseHeaders = { ...this.responseHeaders, ...headers };
+        return this;
+    }
+
+    public jsonBody(body: unknown): BuildStage {
+        if (body === undefined) {
+            throw new Error("Undefined is not valid JSON. Do not call jsonBody if you expect an empty body.");
+        }
+        this.responseBody = toJson(body);
+        return this;
+    }
+
+    public build(): HttpHandler {
+        const responseResolver: HttpResponseResolver = () => {
+            const response = new HttpResponse(this.responseBody, {
+                status: this.responseStatusCode,
+                headers: this.responseHeaders,
+            });
+            // if no Content-Type header is set, delete the default text content type that is set
+            if (Object.keys(this.responseHeaders).some((key) => key.toLowerCase() === "content-type") === false) {
+                response.headers.delete("Content-Type");
+            }
+            return response;
+        };
+
+        const finalResolver = this.requestPredicates.reduceRight((acc, predicate) => predicate(acc), responseResolver);
+
+        const handler = http[this.method](this.url, finalResolver, this.handlerOptions);
+        this.handlerOptions?.onBuild?.(handler);
+        return handler;
+    }
+}
+
+export function mockEndpointBuilder(options?: HttpHandlerBuilderOptions): MethodStage {
+    return new RequestBuilder(options);
+}
diff --git a/tests/mock-server/randomBaseUrl.ts b/tests/mock-server/randomBaseUrl.ts
new file mode 100644
index 00000000..031aa640
--- /dev/null
+++ b/tests/mock-server/randomBaseUrl.ts
@@ -0,0 +1,4 @@
+export function randomBaseUrl(): string {
+    const randomString = Math.random().toString(36).substring(2, 15);
+    return `http://${randomString}.localhost`;
+}
diff --git a/tests/mock-server/setup.ts b/tests/mock-server/setup.ts
new file mode 100644
index 00000000..aeb3a95a
--- /dev/null
+++ b/tests/mock-server/setup.ts
@@ -0,0 +1,10 @@
+import { afterAll, beforeAll } from "vitest";
+
+import { mockServerPool } from "./MockServerPool";
+
+beforeAll(() => {
+    mockServerPool.listen();
+});
+afterAll(() => {
+    mockServerPool.close();
+});
diff --git a/tests/mock-server/withFormUrlEncoded.ts b/tests/mock-server/withFormUrlEncoded.ts
new file mode 100644
index 00000000..e9e6ff2d
--- /dev/null
+++ b/tests/mock-server/withFormUrlEncoded.ts
@@ -0,0 +1,80 @@
+import { type HttpResponseResolver, passthrough } from "msw";
+
+import { toJson } from "../../src/core/json";
+
+/**
+ * Creates a request matcher that validates if the request form-urlencoded body exactly matches the expected object
+ * @param expectedBody - The exact body object to match against
+ * @param resolver - Response resolver to execute if body matches
+ */
+export function withFormUrlEncoded(expectedBody: unknown, resolver: HttpResponseResolver): HttpResponseResolver {
+    return async (args) => {
+        const { request } = args;
+
+        let clonedRequest: Request;
+        let bodyText: string | undefined;
+        let actualBody: Record;
+        try {
+            clonedRequest = request.clone();
+            bodyText = await clonedRequest.text();
+            if (bodyText === "") {
+                console.error("Request body is empty, expected a form-urlencoded body.");
+                return passthrough();
+            }
+            const params = new URLSearchParams(bodyText);
+            actualBody = {};
+            for (const [key, value] of params.entries()) {
+                actualBody[key] = value;
+            }
+        } catch (error) {
+            console.error(`Error processing form-urlencoded request body:\n\tError: ${error}\n\tBody: ${bodyText}`);
+            return passthrough();
+        }
+
+        const mismatches = findMismatches(actualBody, expectedBody);
+        if (Object.keys(mismatches).length > 0) {
+            console.error("Form-urlencoded body mismatch:", toJson(mismatches, undefined, 2));
+            return passthrough();
+        }
+
+        return resolver(args);
+    };
+}
+
+function findMismatches(actual: any, expected: any): Record {
+    const mismatches: Record = {};
+
+    if (typeof actual !== typeof expected) {
+        return { value: { actual, expected } };
+    }
+
+    if (typeof actual !== "object" || actual === null || expected === null) {
+        if (actual !== expected) {
+            return { value: { actual, expected } };
+        }
+        return {};
+    }
+
+    const actualKeys = Object.keys(actual);
+    const expectedKeys = Object.keys(expected);
+
+    const allKeys = new Set([...actualKeys, ...expectedKeys]);
+
+    for (const key of allKeys) {
+        if (!expectedKeys.includes(key)) {
+            if (actual[key] === undefined) {
+                continue;
+            }
+            mismatches[key] = { actual: actual[key], expected: undefined };
+        } else if (!actualKeys.includes(key)) {
+            if (expected[key] === undefined) {
+                continue;
+            }
+            mismatches[key] = { actual: undefined, expected: expected[key] };
+        } else if (actual[key] !== expected[key]) {
+            mismatches[key] = { actual: actual[key], expected: expected[key] };
+        }
+    }
+
+    return mismatches;
+}
diff --git a/tests/mock-server/withHeaders.ts b/tests/mock-server/withHeaders.ts
new file mode 100644
index 00000000..6599d2b4
--- /dev/null
+++ b/tests/mock-server/withHeaders.ts
@@ -0,0 +1,70 @@
+import { type HttpResponseResolver, passthrough } from "msw";
+
+/**
+ * Creates a request matcher that validates if request headers match specified criteria
+ * @param expectedHeaders - Headers to match against
+ * @param resolver - Response resolver to execute if headers match
+ */
+export function withHeaders(
+    expectedHeaders: Record boolean)>,
+    resolver: HttpResponseResolver,
+): HttpResponseResolver {
+    return (args) => {
+        const { request } = args;
+        const { headers } = request;
+
+        const mismatches: Record<
+            string,
+            { actual: string | null; expected: string | RegExp | ((value: string) => boolean) }
+        > = {};
+
+        for (const [key, expectedValue] of Object.entries(expectedHeaders)) {
+            const actualValue = headers.get(key);
+
+            if (actualValue === null) {
+                mismatches[key] = { actual: null, expected: expectedValue };
+                continue;
+            }
+
+            if (typeof expectedValue === "function") {
+                if (!expectedValue(actualValue)) {
+                    mismatches[key] = { actual: actualValue, expected: expectedValue };
+                }
+            } else if (expectedValue instanceof RegExp) {
+                if (!expectedValue.test(actualValue)) {
+                    mismatches[key] = { actual: actualValue, expected: expectedValue };
+                }
+            } else if (expectedValue !== actualValue) {
+                mismatches[key] = { actual: actualValue, expected: expectedValue };
+            }
+        }
+
+        if (Object.keys(mismatches).length > 0) {
+            const formattedMismatches = formatHeaderMismatches(mismatches);
+            console.error("Header mismatch:", formattedMismatches);
+            return passthrough();
+        }
+
+        return resolver(args);
+    };
+}
+
+function formatHeaderMismatches(
+    mismatches: Record boolean) }>,
+): Record {
+    const formatted: Record = {};
+
+    for (const [key, { actual, expected }] of Object.entries(mismatches)) {
+        formatted[key] = {
+            actual,
+            expected:
+                expected instanceof RegExp
+                    ? expected.toString()
+                    : typeof expected === "function"
+                      ? "[Function]"
+                      : expected,
+        };
+    }
+
+    return formatted;
+}
diff --git a/tests/mock-server/withJson.ts b/tests/mock-server/withJson.ts
new file mode 100644
index 00000000..b627638b
--- /dev/null
+++ b/tests/mock-server/withJson.ts
@@ -0,0 +1,158 @@
+import { type HttpResponseResolver, passthrough } from "msw";
+
+import { fromJson, toJson } from "../../src/core/json";
+
+/**
+ * Creates a request matcher that validates if the request JSON body exactly matches the expected object
+ * @param expectedBody - The exact body object to match against
+ * @param resolver - Response resolver to execute if body matches
+ */
+export function withJson(expectedBody: unknown, resolver: HttpResponseResolver): HttpResponseResolver {
+    return async (args) => {
+        const { request } = args;
+
+        let clonedRequest: Request;
+        let bodyText: string | undefined;
+        let actualBody: unknown;
+        try {
+            clonedRequest = request.clone();
+            bodyText = await clonedRequest.text();
+            if (bodyText === "") {
+                console.error("Request body is empty, expected a JSON object.");
+                return passthrough();
+            }
+            actualBody = fromJson(bodyText);
+        } catch (error) {
+            console.error(`Error processing request body:\n\tError: ${error}\n\tBody: ${bodyText}`);
+            return passthrough();
+        }
+
+        const mismatches = findMismatches(actualBody, expectedBody);
+        if (Object.keys(mismatches).filter((key) => !key.startsWith("pagination.")).length > 0) {
+            console.error("JSON body mismatch:", toJson(mismatches, undefined, 2));
+            return passthrough();
+        }
+
+        return resolver(args);
+    };
+}
+
+function findMismatches(actual: any, expected: any): Record {
+    const mismatches: Record = {};
+
+    if (typeof actual !== typeof expected) {
+        if (areEquivalent(actual, expected)) {
+            return {};
+        }
+        return { value: { actual, expected } };
+    }
+
+    if (typeof actual !== "object" || actual === null || expected === null) {
+        if (actual !== expected) {
+            if (areEquivalent(actual, expected)) {
+                return {};
+            }
+            return { value: { actual, expected } };
+        }
+        return {};
+    }
+
+    if (Array.isArray(actual) && Array.isArray(expected)) {
+        if (actual.length !== expected.length) {
+            return { length: { actual: actual.length, expected: expected.length } };
+        }
+
+        const arrayMismatches: Record = {};
+        for (let i = 0; i < actual.length; i++) {
+            const itemMismatches = findMismatches(actual[i], expected[i]);
+            if (Object.keys(itemMismatches).length > 0) {
+                for (const [mismatchKey, mismatchValue] of Object.entries(itemMismatches)) {
+                    arrayMismatches[`[${i}]${mismatchKey === "value" ? "" : `.${mismatchKey}`}`] = mismatchValue;
+                }
+            }
+        }
+        return arrayMismatches;
+    }
+
+    const actualKeys = Object.keys(actual);
+    const expectedKeys = Object.keys(expected);
+
+    const allKeys = new Set([...actualKeys, ...expectedKeys]);
+
+    for (const key of allKeys) {
+        if (!expectedKeys.includes(key)) {
+            if (actual[key] === undefined) {
+                continue; // Skip undefined values in actual
+            }
+            mismatches[key] = { actual: actual[key], expected: undefined };
+        } else if (!actualKeys.includes(key)) {
+            if (expected[key] === undefined) {
+                continue; // Skip undefined values in expected
+            }
+            mismatches[key] = { actual: undefined, expected: expected[key] };
+        } else if (
+            typeof actual[key] === "object" &&
+            actual[key] !== null &&
+            typeof expected[key] === "object" &&
+            expected[key] !== null
+        ) {
+            const nestedMismatches = findMismatches(actual[key], expected[key]);
+            if (Object.keys(nestedMismatches).length > 0) {
+                for (const [nestedKey, nestedValue] of Object.entries(nestedMismatches)) {
+                    mismatches[`${key}${nestedKey === "value" ? "" : `.${nestedKey}`}`] = nestedValue;
+                }
+            }
+        } else if (actual[key] !== expected[key]) {
+            if (areEquivalent(actual[key], expected[key])) {
+                continue;
+            }
+            mismatches[key] = { actual: actual[key], expected: expected[key] };
+        }
+    }
+
+    return mismatches;
+}
+
+function areEquivalent(actual: unknown, expected: unknown): boolean {
+    if (actual === expected) {
+        return true;
+    }
+    if (isEquivalentBigInt(actual, expected)) {
+        return true;
+    }
+    if (isEquivalentDatetime(actual, expected)) {
+        return true;
+    }
+    return false;
+}
+
+function isEquivalentBigInt(actual: unknown, expected: unknown) {
+    if (typeof actual === "number") {
+        actual = BigInt(actual);
+    }
+    if (typeof expected === "number") {
+        expected = BigInt(expected);
+    }
+    if (typeof actual === "bigint" && typeof expected === "bigint") {
+        return actual === expected;
+    }
+    return false;
+}
+
+function isEquivalentDatetime(str1: unknown, str2: unknown): boolean {
+    if (typeof str1 !== "string" || typeof str2 !== "string") {
+        return false;
+    }
+    const isoDatePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
+    if (!isoDatePattern.test(str1) || !isoDatePattern.test(str2)) {
+        return false;
+    }
+
+    try {
+        const date1 = new Date(str1).getTime();
+        const date2 = new Date(str2).getTime();
+        return date1 === date2;
+    } catch {
+        return false;
+    }
+}
diff --git a/tests/setup.ts b/tests/setup.ts
index 7b0c83a2..a5651f81 100644
--- a/tests/setup.ts
+++ b/tests/setup.ts
@@ -1,46 +1,80 @@
-import "jest";
-import dotenv from "dotenv";
-
-/**
- * Test Setup for Deepgram JS SDK
- *
- * IMPORTANT: AI transcription services are non-deterministic!
- * The same audio file may produce different (but valid) transcriptions on different calls.
- * Our tests focus on structural validation and quality metrics rather than exact content matching.
- */
-
-// Load environment variables from .env file
-dotenv.config();
-
-// Global test setup
-beforeAll(() => {
-  // Set test environment variables
-  process.env.NODE_ENV = "test";
-
-  // Configure environment for better offline testing
-  // This helps ensure tests don't accidentally make real network calls
-  if (!process.env.DEEPGRAM_API_KEY) {
-    process.env.DEEPGRAM_API_KEY = "mock-api-key-for-testing";
-  }
-
-  // Mock console methods for cleaner test output (optional)
-  if (process.env.JEST_SILENT !== "false") {
-    jest.spyOn(console, "log").mockImplementation(() => {});
-    jest.spyOn(console, "warn").mockImplementation(() => {});
-    jest.spyOn(console, "error").mockImplementation(() => {});
-  }
-});
+import { expect } from "vitest";
+
+interface CustomMatchers {
+    toContainHeaders(expectedHeaders: Record): R;
+}
+
+declare module "vitest" {
+    interface Assertion extends CustomMatchers {}
+    interface AsymmetricMatchersContaining extends CustomMatchers {}
+}
+
+expect.extend({
+    toContainHeaders(actual: unknown, expectedHeaders: Record) {
+        const isHeaders = actual instanceof Headers;
+        const isPlainObject = typeof actual === "object" && actual !== null && !Array.isArray(actual);
+
+        if (!isHeaders && !isPlainObject) {
+            throw new TypeError("Received value must be an instance of Headers or a plain object!");
+        }
+
+        if (typeof expectedHeaders !== "object" || expectedHeaders === null || Array.isArray(expectedHeaders)) {
+            throw new TypeError("Expected headers must be a plain object!");
+        }
+
+        const missingHeaders: string[] = [];
+        const mismatchedHeaders: Array<{ key: string; expected: string; actual: string | null }> = [];
+
+        for (const [key, value] of Object.entries(expectedHeaders)) {
+            let actualValue: string | null = null;
+
+            if (isHeaders) {
+                // Headers.get() is already case-insensitive
+                actualValue = (actual as Headers).get(key);
+            } else {
+                // For plain objects, do case-insensitive lookup
+                const actualObj = actual as Record;
+                const lowerKey = key.toLowerCase();
+                const foundKey = Object.keys(actualObj).find((k) => k.toLowerCase() === lowerKey);
+                actualValue = foundKey ? actualObj[foundKey] : null;
+            }
+
+            if (actualValue === null || actualValue === undefined) {
+                missingHeaders.push(key);
+            } else if (actualValue !== value) {
+                mismatchedHeaders.push({ key, expected: value, actual: actualValue });
+            }
+        }
+
+        const pass = missingHeaders.length === 0 && mismatchedHeaders.length === 0;
+
+        const actualType = isHeaders ? "Headers" : "object";
+
+        if (pass) {
+            return {
+                message: () => `expected ${actualType} not to contain ${this.utils.printExpected(expectedHeaders)}`,
+                pass: true,
+            };
+        } else {
+            const messages: string[] = [];
 
-afterAll(async () => {
-  // Restore console methods
-  jest.restoreAllMocks();
+            if (missingHeaders.length > 0) {
+                messages.push(`Missing headers: ${this.utils.printExpected(missingHeaders.join(", "))}`);
+            }
 
-  // Force close HTTP connections to prevent Jest hanging
-  // This addresses the TLSWRAP handles that keep Jest from exiting
-  if (typeof global.gc === "function") {
-    global.gc();
-  }
+            if (mismatchedHeaders.length > 0) {
+                const mismatches = mismatchedHeaders.map(
+                    ({ key, expected, actual }) =>
+                        `${key}: expected ${this.utils.printExpected(expected)} but got ${this.utils.printReceived(actual)}`,
+                );
+                messages.push(mismatches.join("\n"));
+            }
 
-  // Give a small delay to allow cleanup
-  await new Promise((resolve) => setTimeout(resolve, 100));
+            return {
+                message: () =>
+                    `expected ${actualType} to contain ${this.utils.printExpected(expectedHeaders)}\n\n${messages.join("\n")}`,
+                pass: false,
+            };
+        }
+    },
 });
diff --git a/tests/tsconfig.json b/tests/tsconfig.json
new file mode 100644
index 00000000..a477df47
--- /dev/null
+++ b/tests/tsconfig.json
@@ -0,0 +1,11 @@
+{
+    "extends": "../tsconfig.base.json",
+    "compilerOptions": {
+        "outDir": null,
+        "rootDir": "..",
+        "baseUrl": "..",
+        "types": ["vitest/globals"]
+    },
+    "include": ["../src", "../tests"],
+    "exclude": []
+}
diff --git a/tests/unit/constants.test.ts b/tests/unit/constants.test.ts
deleted file mode 100644
index ae492947..00000000
--- a/tests/unit/constants.test.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-import {
-  DEFAULT_HEADERS,
-  DEFAULT_URL,
-  DEFAULT_OPTIONS,
-  SOCKET_STATES,
-  CONNECTION_STATE,
-} from "../../src/lib/constants";
-
-describe("Unit Tests - Constants and Configuration", () => {
-  describe("DEFAULT_HEADERS", () => {
-    it("should have required headers with correct structure", () => {
-      expect(DEFAULT_HEADERS["Content-Type"]).toBe("application/json");
-      expect(DEFAULT_HEADERS["X-Client-Info"]).toMatch(
-        /@deepgram\/sdk; (browser|server); v[\d.-]+/
-      );
-      expect(DEFAULT_HEADERS["User-Agent"]).toMatch(
-        /@deepgram\/sdk\/[\d.-]+(automated)? (node\/[\d.]+|bun\/[\d.]+|javascript)/
-      );
-    });
-
-    it("should have all required header fields", () => {
-      expect(DEFAULT_HEADERS).toHaveProperty("Content-Type");
-      expect(DEFAULT_HEADERS["Content-Type"]).toBeTruthy();
-
-      expect(DEFAULT_HEADERS).toHaveProperty("X-Client-Info");
-      expect(DEFAULT_HEADERS["X-Client-Info"]).toBeTruthy();
-
-      expect(DEFAULT_HEADERS).toHaveProperty("User-Agent");
-      expect(DEFAULT_HEADERS["User-Agent"]).toBeTruthy();
-    });
-  });
-
-  describe("DEFAULT_URL and DEFAULT_OPTIONS", () => {
-    it("should have correct default URL", () => {
-      expect(DEFAULT_URL).toBe("https://api.deepgram.com");
-    });
-
-    it("should have properly structured DEFAULT_OPTIONS", () => {
-      expect(DEFAULT_OPTIONS).toHaveProperty("global");
-      expect(DEFAULT_OPTIONS).toHaveProperty("agent");
-
-      // Global options structure
-      expect(DEFAULT_OPTIONS.global).toHaveProperty("fetch");
-      expect(DEFAULT_OPTIONS.global).toHaveProperty("websocket");
-      expect(DEFAULT_OPTIONS.global?.fetch).toHaveProperty("options");
-      expect(DEFAULT_OPTIONS.global?.websocket).toHaveProperty("options");
-
-      // Agent options structure
-      expect(DEFAULT_OPTIONS.agent).toHaveProperty("fetch");
-      expect(DEFAULT_OPTIONS.agent).toHaveProperty("websocket");
-      expect(DEFAULT_OPTIONS.agent?.fetch).toHaveProperty("options");
-      expect(DEFAULT_OPTIONS.agent?.websocket).toHaveProperty("options");
-    });
-
-    it("should have correct URLs in options", () => {
-      expect(DEFAULT_OPTIONS.global?.fetch?.options?.url).toBe("https://api.deepgram.com");
-      expect(DEFAULT_OPTIONS.global?.websocket?.options?.url).toBe("wss://api.deepgram.com");
-      expect(DEFAULT_OPTIONS.agent?.fetch?.options?.url).toBe("https://api.deepgram.com");
-      expect(DEFAULT_OPTIONS.agent?.websocket?.options?.url).toBe("wss://agent.deepgram.com");
-    });
-
-    it("should include headers in options", () => {
-      expect(DEFAULT_OPTIONS.global?.fetch?.options?.headers).toEqual(DEFAULT_HEADERS);
-      expect(DEFAULT_OPTIONS.global?.websocket?.options?._nodeOnlyHeaders).toEqual(DEFAULT_HEADERS);
-      expect(DEFAULT_OPTIONS.agent?.fetch?.options?.headers).toEqual(DEFAULT_HEADERS);
-      expect(DEFAULT_OPTIONS.agent?.websocket?.options?._nodeOnlyHeaders).toEqual(DEFAULT_HEADERS);
-    });
-  });
-
-  describe("Enums", () => {
-    it("should have correct SOCKET_STATES values", () => {
-      expect(SOCKET_STATES.connecting).toBe(0);
-      expect(SOCKET_STATES.open).toBe(1);
-      expect(SOCKET_STATES.closing).toBe(2);
-      expect(SOCKET_STATES.closed).toBe(3);
-    });
-
-    it("should have correct CONNECTION_STATE values", () => {
-      expect(CONNECTION_STATE.Connecting).toBe("connecting");
-      expect(CONNECTION_STATE.Open).toBe("open");
-      expect(CONNECTION_STATE.Closing).toBe("closing");
-      expect(CONNECTION_STATE.Closed).toBe("closed");
-    });
-
-    it("should have all expected enum members", () => {
-      const expectedSocketStates = ["connecting", "open", "closing", "closed"];
-      const expectedConnectionStates = ["Connecting", "Open", "Closing", "Closed"];
-
-      expectedSocketStates.forEach((state) => {
-        expect(SOCKET_STATES).toHaveProperty(state);
-      });
-
-      expectedConnectionStates.forEach((state) => {
-        expect(CONNECTION_STATE).toHaveProperty(state);
-      });
-    });
-  });
-});
diff --git a/tests/unit/fetch-utilities.test.ts b/tests/unit/fetch-utilities.test.ts
deleted file mode 100644
index cfc1f25a..00000000
--- a/tests/unit/fetch-utilities.test.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-import { resolveHeadersConstructor } from "../../src/lib/helpers";
-import { resolveFetch, fetchWithAuth, resolveResponse } from "../../src/lib/fetch";
-
-describe("Unit Tests - Fetch Utilities", () => {
-  describe("resolveHeadersConstructor", () => {
-    it("should return a valid Headers constructor", () => {
-      const HeadersConstructor = resolveHeadersConstructor();
-
-      expect(typeof HeadersConstructor).toBe("function");
-
-      // Should be able to create a Headers instance
-      const headers = new HeadersConstructor();
-      expect(headers).toBeDefined();
-
-      // Should be able to set and get headers
-      headers.set("Content-Type", "application/json");
-      expect(headers.get("Content-Type")).toBe("application/json");
-    });
-  });
-
-  describe("resolveFetch", () => {
-    it("should return the custom fetch when provided", () => {
-      const customFetch = jest.fn();
-      const resolved = resolveFetch(customFetch);
-
-      expect(typeof resolved).toBe("function");
-
-      // Should use the custom fetch when called
-      resolved("test-url", {});
-      expect(customFetch).toHaveBeenCalledWith("test-url", {});
-    });
-
-    it("should return a working fetch function when no custom fetch provided", () => {
-      const resolved = resolveFetch();
-
-      expect(typeof resolved).toBe("function");
-      // Function should be callable (we can't easily test actual network calls in unit tests)
-    });
-
-    it("should handle fetch arguments correctly", () => {
-      const customFetch = jest.fn().mockResolvedValue({ ok: true });
-      const resolved = resolveFetch(customFetch);
-
-      const url = "https://api.example.com/test";
-      const options = { method: "POST", body: "test data" };
-
-      resolved(url, options);
-
-      expect(customFetch).toHaveBeenCalledWith(url, options);
-    });
-  });
-
-  describe("fetchWithAuth", () => {
-    it("should add Authorization header when not present", async () => {
-      const mockFetch = jest.fn().mockResolvedValue({ ok: true });
-      const apiKey = "test-api-key";
-      const authenticatedFetch = fetchWithAuth({ apiKey, customFetch: mockFetch });
-
-      await authenticatedFetch("https://api.example.com/test", {});
-
-      expect(mockFetch).toHaveBeenCalledWith(
-        "https://api.example.com/test",
-        expect.objectContaining({
-          headers: expect.any(Object),
-        })
-      );
-
-      const callArgs = mockFetch.mock.calls[0][1];
-      const headers = callArgs.headers;
-      expect(headers.get("Authorization")).toBe("Token test-api-key");
-    });
-
-    it("should not override existing Authorization header", async () => {
-      const mockFetch = jest.fn().mockResolvedValue({ ok: true });
-      const apiKey = "test-api-key";
-      const authenticatedFetch = fetchWithAuth({ apiKey, customFetch: mockFetch });
-
-      const existingHeaders = new Headers();
-      existingHeaders.set("Authorization", "Bearer existing-token");
-
-      await authenticatedFetch("https://api.example.com/test", {
-        headers: existingHeaders,
-      });
-
-      const callArgs = mockFetch.mock.calls[0][1];
-      const headers = callArgs.headers;
-      expect(headers.get("Authorization")).toBe("Bearer existing-token");
-    });
-
-    it("should preserve other headers", async () => {
-      const mockFetch = jest.fn().mockResolvedValue({ ok: true });
-      const apiKey = "test-api-key";
-      const authenticatedFetch = fetchWithAuth({ apiKey, customFetch: mockFetch });
-
-      const headers = { "Content-Type": "application/json", "X-Custom": "value" };
-
-      await authenticatedFetch("https://api.example.com/test", { headers });
-
-      const callArgs = mockFetch.mock.calls[0][1];
-      const resultHeaders = callArgs.headers;
-      expect(resultHeaders.get("Content-Type")).toBe("application/json");
-      expect(resultHeaders.get("X-Custom")).toBe("value");
-      expect(resultHeaders.get("Authorization")).toBe("Token test-api-key");
-    });
-  });
-
-  describe("resolveResponse", () => {
-    it("should return a valid Response constructor", async () => {
-      const ResponseConstructor = await resolveResponse();
-
-      expect(typeof ResponseConstructor).toBe("function");
-      expect(ResponseConstructor.name).toBe("Response");
-
-      // Should be able to create a Response instance
-      const response = new ResponseConstructor("test body", { status: 200 });
-      expect(response).toBeDefined();
-      expect(response.status).toBe(200);
-    });
-  });
-});
diff --git a/tests/unit/fetcher/Fetcher.test.ts b/tests/unit/fetcher/Fetcher.test.ts
new file mode 100644
index 00000000..60df2b5e
--- /dev/null
+++ b/tests/unit/fetcher/Fetcher.test.ts
@@ -0,0 +1,261 @@
+import fs from "fs";
+import { join } from "path";
+import stream from "stream";
+import type { BinaryResponse } from "../../../src/core";
+import { type Fetcher, fetcherImpl } from "../../../src/core/fetcher/Fetcher";
+
+describe("Test fetcherImpl", () => {
+    it("should handle successful request", async () => {
+        const mockArgs: Fetcher.Args = {
+            url: "https://httpbin.org/post",
+            method: "POST",
+            headers: { "X-Test": "x-test-header" },
+            body: { data: "test" },
+            contentType: "application/json",
+            requestType: "json",
+            maxRetries: 0,
+            responseType: "json",
+        };
+
+        global.fetch = vi.fn().mockResolvedValue(
+            new Response(JSON.stringify({ data: "test" }), {
+                status: 200,
+                statusText: "OK",
+            }),
+        );
+
+        const result = await fetcherImpl(mockArgs);
+        expect(result.ok).toBe(true);
+        if (result.ok) {
+            expect(result.body).toEqual({ data: "test" });
+        }
+
+        expect(global.fetch).toHaveBeenCalledWith(
+            "https://httpbin.org/post",
+            expect.objectContaining({
+                method: "POST",
+                headers: expect.toContainHeaders({ "X-Test": "x-test-header" }),
+                body: JSON.stringify({ data: "test" }),
+            }),
+        );
+    });
+
+    it("should send octet stream", async () => {
+        const url = "https://httpbin.org/post/file";
+        const mockArgs: Fetcher.Args = {
+            url,
+            method: "POST",
+            headers: { "X-Test": "x-test-header" },
+            contentType: "application/octet-stream",
+            requestType: "bytes",
+            maxRetries: 0,
+            responseType: "json",
+            body: fs.createReadStream(join(__dirname, "test-file.txt")),
+        };
+
+        global.fetch = vi.fn().mockResolvedValue(
+            new Response(JSON.stringify({ data: "test" }), {
+                status: 200,
+                statusText: "OK",
+            }),
+        );
+
+        const result = await fetcherImpl(mockArgs);
+
+        expect(global.fetch).toHaveBeenCalledWith(
+            url,
+            expect.objectContaining({
+                method: "POST",
+                headers: expect.toContainHeaders({ "X-Test": "x-test-header" }),
+                body: expect.any(fs.ReadStream),
+            }),
+        );
+        expect(result.ok).toBe(true);
+        if (result.ok) {
+            expect(result.body).toEqual({ data: "test" });
+        }
+    });
+
+    it("should receive file as stream", async () => {
+        const url = "https://httpbin.org/post/file";
+        const mockArgs: Fetcher.Args = {
+            url,
+            method: "GET",
+            headers: { "X-Test": "x-test-header" },
+            maxRetries: 0,
+            responseType: "binary-response",
+        };
+
+        global.fetch = vi.fn().mockResolvedValue(
+            new Response(
+                stream.Readable.toWeb(fs.createReadStream(join(__dirname, "test-file.txt"))) as ReadableStream,
+                {
+                    status: 200,
+                    statusText: "OK",
+                },
+            ),
+        );
+
+        const result = await fetcherImpl(mockArgs);
+
+        expect(global.fetch).toHaveBeenCalledWith(
+            url,
+            expect.objectContaining({
+                method: "GET",
+                headers: expect.toContainHeaders({ "X-Test": "x-test-header" }),
+            }),
+        );
+        expect(result.ok).toBe(true);
+        if (result.ok) {
+            const body = result.body as BinaryResponse;
+            expect(body).toBeDefined();
+            expect(body.bodyUsed).toBe(false);
+            expect(typeof body.stream).toBe("function");
+            const stream = body.stream();
+            expect(stream).toBeInstanceOf(ReadableStream);
+            const reader = stream.getReader();
+            const { value } = await reader.read();
+            const decoder = new TextDecoder();
+            const streamContent = decoder.decode(value);
+            expect(streamContent).toBe("This is a test file!\n");
+            expect(body.bodyUsed).toBe(true);
+        }
+    });
+
+    it("should receive file as blob", async () => {
+        const url = "https://httpbin.org/post/file";
+        const mockArgs: Fetcher.Args = {
+            url,
+            method: "GET",
+            headers: { "X-Test": "x-test-header" },
+            maxRetries: 0,
+            responseType: "binary-response",
+        };
+
+        global.fetch = vi.fn().mockResolvedValue(
+            new Response(
+                stream.Readable.toWeb(fs.createReadStream(join(__dirname, "test-file.txt"))) as ReadableStream,
+                {
+                    status: 200,
+                    statusText: "OK",
+                },
+            ),
+        );
+
+        const result = await fetcherImpl(mockArgs);
+
+        expect(global.fetch).toHaveBeenCalledWith(
+            url,
+            expect.objectContaining({
+                method: "GET",
+                headers: expect.toContainHeaders({ "X-Test": "x-test-header" }),
+            }),
+        );
+        expect(result.ok).toBe(true);
+        if (result.ok) {
+            const body = result.body as BinaryResponse;
+            expect(body).toBeDefined();
+            expect(body.bodyUsed).toBe(false);
+            expect(typeof body.blob).toBe("function");
+            const blob = await body.blob();
+            expect(blob).toBeInstanceOf(Blob);
+            const reader = blob.stream().getReader();
+            const { value } = await reader.read();
+            const decoder = new TextDecoder();
+            const streamContent = decoder.decode(value);
+            expect(streamContent).toBe("This is a test file!\n");
+            expect(body.bodyUsed).toBe(true);
+        }
+    });
+
+    it("should receive file as arraybuffer", async () => {
+        const url = "https://httpbin.org/post/file";
+        const mockArgs: Fetcher.Args = {
+            url,
+            method: "GET",
+            headers: { "X-Test": "x-test-header" },
+            maxRetries: 0,
+            responseType: "binary-response",
+        };
+
+        global.fetch = vi.fn().mockResolvedValue(
+            new Response(
+                stream.Readable.toWeb(fs.createReadStream(join(__dirname, "test-file.txt"))) as ReadableStream,
+                {
+                    status: 200,
+                    statusText: "OK",
+                },
+            ),
+        );
+
+        const result = await fetcherImpl(mockArgs);
+
+        expect(global.fetch).toHaveBeenCalledWith(
+            url,
+            expect.objectContaining({
+                method: "GET",
+                headers: expect.toContainHeaders({ "X-Test": "x-test-header" }),
+            }),
+        );
+        expect(result.ok).toBe(true);
+        if (result.ok) {
+            const body = result.body as BinaryResponse;
+            expect(body).toBeDefined();
+            expect(body.bodyUsed).toBe(false);
+            expect(typeof body.arrayBuffer).toBe("function");
+            const arrayBuffer = await body.arrayBuffer();
+            expect(arrayBuffer).toBeInstanceOf(ArrayBuffer);
+            const decoder = new TextDecoder();
+            const streamContent = decoder.decode(new Uint8Array(arrayBuffer));
+            expect(streamContent).toBe("This is a test file!\n");
+            expect(body.bodyUsed).toBe(true);
+        }
+    });
+
+    it("should receive file as bytes", async () => {
+        const url = "https://httpbin.org/post/file";
+        const mockArgs: Fetcher.Args = {
+            url,
+            method: "GET",
+            headers: { "X-Test": "x-test-header" },
+            maxRetries: 0,
+            responseType: "binary-response",
+        };
+
+        global.fetch = vi.fn().mockResolvedValue(
+            new Response(
+                stream.Readable.toWeb(fs.createReadStream(join(__dirname, "test-file.txt"))) as ReadableStream,
+                {
+                    status: 200,
+                    statusText: "OK",
+                },
+            ),
+        );
+
+        const result = await fetcherImpl(mockArgs);
+
+        expect(global.fetch).toHaveBeenCalledWith(
+            url,
+            expect.objectContaining({
+                method: "GET",
+                headers: expect.toContainHeaders({ "X-Test": "x-test-header" }),
+            }),
+        );
+        expect(result.ok).toBe(true);
+        if (result.ok) {
+            const body = result.body as BinaryResponse;
+            expect(body).toBeDefined();
+            expect(body.bodyUsed).toBe(false);
+            expect(typeof body.bytes).toBe("function");
+            if (!body.bytes) {
+                return;
+            }
+            const bytes = await body.bytes();
+            expect(bytes).toBeInstanceOf(Uint8Array);
+            const decoder = new TextDecoder();
+            const streamContent = decoder.decode(bytes);
+            expect(streamContent).toBe("This is a test file!\n");
+            expect(body.bodyUsed).toBe(true);
+        }
+    });
+});
diff --git a/tests/unit/fetcher/HttpResponsePromise.test.ts b/tests/unit/fetcher/HttpResponsePromise.test.ts
new file mode 100644
index 00000000..2ec008e5
--- /dev/null
+++ b/tests/unit/fetcher/HttpResponsePromise.test.ts
@@ -0,0 +1,143 @@
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+import { HttpResponsePromise } from "../../../src/core/fetcher/HttpResponsePromise";
+import type { RawResponse, WithRawResponse } from "../../../src/core/fetcher/RawResponse";
+
+describe("HttpResponsePromise", () => {
+    const mockRawResponse: RawResponse = {
+        headers: new Headers(),
+        redirected: false,
+        status: 200,
+        statusText: "OK",
+        type: "basic" as ResponseType,
+        url: "https://example.com",
+    };
+    const mockData = { id: "123", name: "test" };
+    const mockWithRawResponse: WithRawResponse = {
+        data: mockData,
+        rawResponse: mockRawResponse,
+    };
+
+    describe("fromFunction", () => {
+        it("should create an HttpResponsePromise from a function", async () => {
+            const mockFn = vi
+                .fn<(arg1: string, arg2: string) => Promise>>()
+                .mockResolvedValue(mockWithRawResponse);
+
+            const responsePromise = HttpResponsePromise.fromFunction(mockFn, "arg1", "arg2");
+
+            const result = await responsePromise;
+            expect(result).toEqual(mockData);
+            expect(mockFn).toHaveBeenCalledWith("arg1", "arg2");
+
+            const resultWithRawResponse = await responsePromise.withRawResponse();
+            expect(resultWithRawResponse).toEqual({
+                data: mockData,
+                rawResponse: mockRawResponse,
+            });
+        });
+    });
+
+    describe("fromPromise", () => {
+        it("should create an HttpResponsePromise from a promise", async () => {
+            const promise = Promise.resolve(mockWithRawResponse);
+
+            const responsePromise = HttpResponsePromise.fromPromise(promise);
+
+            const result = await responsePromise;
+            expect(result).toEqual(mockData);
+
+            const resultWithRawResponse = await responsePromise.withRawResponse();
+            expect(resultWithRawResponse).toEqual({
+                data: mockData,
+                rawResponse: mockRawResponse,
+            });
+        });
+    });
+
+    describe("fromExecutor", () => {
+        it("should create an HttpResponsePromise from an executor function", async () => {
+            const responsePromise = HttpResponsePromise.fromExecutor((resolve) => {
+                resolve(mockWithRawResponse);
+            });
+
+            const result = await responsePromise;
+            expect(result).toEqual(mockData);
+
+            const resultWithRawResponse = await responsePromise.withRawResponse();
+            expect(resultWithRawResponse).toEqual({
+                data: mockData,
+                rawResponse: mockRawResponse,
+            });
+        });
+    });
+
+    describe("fromResult", () => {
+        it("should create an HttpResponsePromise from a result", async () => {
+            const responsePromise = HttpResponsePromise.fromResult(mockWithRawResponse);
+
+            const result = await responsePromise;
+            expect(result).toEqual(mockData);
+
+            const resultWithRawResponse = await responsePromise.withRawResponse();
+            expect(resultWithRawResponse).toEqual({
+                data: mockData,
+                rawResponse: mockRawResponse,
+            });
+        });
+    });
+
+    describe("Promise methods", () => {
+        let responsePromise: HttpResponsePromise;
+
+        beforeEach(() => {
+            responsePromise = HttpResponsePromise.fromResult(mockWithRawResponse);
+        });
+
+        it("should support then() method", async () => {
+            const result = await responsePromise.then((data) => ({
+                ...data,
+                modified: true,
+            }));
+
+            expect(result).toEqual({
+                ...mockData,
+                modified: true,
+            });
+        });
+
+        it("should support catch() method", async () => {
+            const errorResponsePromise = HttpResponsePromise.fromExecutor((_, reject) => {
+                reject(new Error("Test error"));
+            });
+
+            const catchSpy = vi.fn();
+            await errorResponsePromise.catch(catchSpy);
+
+            expect(catchSpy).toHaveBeenCalled();
+            const error = catchSpy.mock.calls[0]?.[0];
+            expect(error).toBeInstanceOf(Error);
+            expect((error as Error).message).toBe("Test error");
+        });
+
+        it("should support finally() method", async () => {
+            const finallySpy = vi.fn();
+            await responsePromise.finally(finallySpy);
+
+            expect(finallySpy).toHaveBeenCalled();
+        });
+    });
+
+    describe("withRawResponse", () => {
+        it("should return both data and raw response", async () => {
+            const responsePromise = HttpResponsePromise.fromResult(mockWithRawResponse);
+
+            const result = await responsePromise.withRawResponse();
+
+            expect(result).toEqual({
+                data: mockData,
+                rawResponse: mockRawResponse,
+            });
+        });
+    });
+});
diff --git a/tests/unit/fetcher/RawResponse.test.ts b/tests/unit/fetcher/RawResponse.test.ts
new file mode 100644
index 00000000..375ee3f3
--- /dev/null
+++ b/tests/unit/fetcher/RawResponse.test.ts
@@ -0,0 +1,34 @@
+import { describe, expect, it } from "vitest";
+
+import { toRawResponse } from "../../../src/core/fetcher/RawResponse";
+
+describe("RawResponse", () => {
+    describe("toRawResponse", () => {
+        it("should convert Response to RawResponse by removing body, bodyUsed, and ok properties", () => {
+            const mockHeaders = new Headers({ "content-type": "application/json" });
+            const mockResponse = {
+                body: "test body",
+                bodyUsed: false,
+                ok: true,
+                headers: mockHeaders,
+                redirected: false,
+                status: 200,
+                statusText: "OK",
+                type: "basic" as ResponseType,
+                url: "https://example.com",
+            };
+
+            const result = toRawResponse(mockResponse as unknown as Response);
+
+            expect("body" in result).toBe(false);
+            expect("bodyUsed" in result).toBe(false);
+            expect("ok" in result).toBe(false);
+            expect(result.headers).toBe(mockHeaders);
+            expect(result.redirected).toBe(false);
+            expect(result.status).toBe(200);
+            expect(result.statusText).toBe("OK");
+            expect(result.type).toBe("basic");
+            expect(result.url).toBe("https://example.com");
+        });
+    });
+});
diff --git a/tests/unit/fetcher/createRequestUrl.test.ts b/tests/unit/fetcher/createRequestUrl.test.ts
new file mode 100644
index 00000000..a92f1b5e
--- /dev/null
+++ b/tests/unit/fetcher/createRequestUrl.test.ts
@@ -0,0 +1,163 @@
+import { createRequestUrl } from "../../../src/core/fetcher/createRequestUrl";
+
+describe("Test createRequestUrl", () => {
+    const BASE_URL = "https://api.example.com";
+
+    interface TestCase {
+        description: string;
+        baseUrl: string;
+        queryParams?: Record;
+        expected: string;
+    }
+
+    const testCases: TestCase[] = [
+        {
+            description: "should return the base URL when no query parameters are provided",
+            baseUrl: BASE_URL,
+            expected: BASE_URL,
+        },
+        {
+            description: "should append simple query parameters",
+            baseUrl: BASE_URL,
+            queryParams: { key: "value", another: "param" },
+            expected: "https://api.example.com?key=value&another=param",
+        },
+        {
+            description: "should handle array query parameters",
+            baseUrl: BASE_URL,
+            queryParams: { items: ["a", "b", "c"] },
+            expected: "https://api.example.com?items=a&items=b&items=c",
+        },
+        {
+            description: "should handle object query parameters",
+            baseUrl: BASE_URL,
+            queryParams: { filter: { name: "John", age: 30 } },
+            expected: "https://api.example.com?filter%5Bname%5D=John&filter%5Bage%5D=30",
+        },
+        {
+            description: "should handle mixed types of query parameters",
+            baseUrl: BASE_URL,
+            queryParams: {
+                simple: "value",
+                array: ["x", "y"],
+                object: { key: "value" },
+            },
+            expected: "https://api.example.com?simple=value&array=x&array=y&object%5Bkey%5D=value",
+        },
+        {
+            description: "should handle empty query parameters object",
+            baseUrl: BASE_URL,
+            queryParams: {},
+            expected: BASE_URL,
+        },
+        {
+            description: "should encode special characters in query parameters",
+            baseUrl: BASE_URL,
+            queryParams: { special: "a&b=c d" },
+            expected: "https://api.example.com?special=a%26b%3Dc%20d",
+        },
+        {
+            description: "should handle numeric values",
+            baseUrl: BASE_URL,
+            queryParams: { count: 42, price: 19.99, active: 1, inactive: 0 },
+            expected: "https://api.example.com?count=42&price=19.99&active=1&inactive=0",
+        },
+        {
+            description: "should handle boolean values",
+            baseUrl: BASE_URL,
+            queryParams: { enabled: true, disabled: false },
+            expected: "https://api.example.com?enabled=true&disabled=false",
+        },
+        {
+            description: "should handle null and undefined values",
+            baseUrl: BASE_URL,
+            queryParams: {
+                valid: "value",
+                nullValue: null,
+                undefinedValue: undefined,
+                emptyString: "",
+            },
+            expected: "https://api.example.com?valid=value&nullValue=&emptyString=",
+        },
+        {
+            description: "should handle deeply nested objects",
+            baseUrl: BASE_URL,
+            queryParams: {
+                user: {
+                    profile: {
+                        name: "John",
+                        settings: { theme: "dark" },
+                    },
+                },
+            },
+            expected:
+                "https://api.example.com?user%5Bprofile%5D%5Bname%5D=John&user%5Bprofile%5D%5Bsettings%5D%5Btheme%5D=dark",
+        },
+        {
+            description: "should handle arrays of objects",
+            baseUrl: BASE_URL,
+            queryParams: {
+                users: [
+                    { name: "John", age: 30 },
+                    { name: "Jane", age: 25 },
+                ],
+            },
+            expected:
+                "https://api.example.com?users%5Bname%5D=John&users%5Bage%5D=30&users%5Bname%5D=Jane&users%5Bage%5D=25",
+        },
+        {
+            description: "should handle mixed arrays",
+            baseUrl: BASE_URL,
+            queryParams: {
+                mixed: ["string", 42, true, { key: "value" }],
+            },
+            expected: "https://api.example.com?mixed=string&mixed=42&mixed=true&mixed%5Bkey%5D=value",
+        },
+        {
+            description: "should handle empty arrays",
+            baseUrl: BASE_URL,
+            queryParams: { emptyArray: [] },
+            expected: BASE_URL,
+        },
+        {
+            description: "should handle empty objects",
+            baseUrl: BASE_URL,
+            queryParams: { emptyObject: {} },
+            expected: BASE_URL,
+        },
+        {
+            description: "should handle special characters in keys",
+            baseUrl: BASE_URL,
+            queryParams: { "key with spaces": "value", "key[with]brackets": "value" },
+            expected: "https://api.example.com?key%20with%20spaces=value&key%5Bwith%5Dbrackets=value",
+        },
+        {
+            description: "should handle URL with existing query parameters",
+            baseUrl: "https://api.example.com?existing=param",
+            queryParams: { new: "value" },
+            expected: "https://api.example.com?existing=param?new=value",
+        },
+        {
+            description: "should handle complex nested structures",
+            baseUrl: BASE_URL,
+            queryParams: {
+                filters: {
+                    status: ["active", "pending"],
+                    category: {
+                        type: "electronics",
+                        subcategories: ["phones", "laptops"],
+                    },
+                },
+                sort: { field: "name", direction: "asc" },
+            },
+            expected:
+                "https://api.example.com?filters%5Bstatus%5D=active&filters%5Bstatus%5D=pending&filters%5Bcategory%5D%5Btype%5D=electronics&filters%5Bcategory%5D%5Bsubcategories%5D=phones&filters%5Bcategory%5D%5Bsubcategories%5D=laptops&sort%5Bfield%5D=name&sort%5Bdirection%5D=asc",
+        },
+    ];
+
+    testCases.forEach(({ description, baseUrl, queryParams, expected }) => {
+        it(description, () => {
+            expect(createRequestUrl(baseUrl, queryParams)).toBe(expected);
+        });
+    });
+});
diff --git a/tests/unit/fetcher/getRequestBody.test.ts b/tests/unit/fetcher/getRequestBody.test.ts
new file mode 100644
index 00000000..8a6c3a57
--- /dev/null
+++ b/tests/unit/fetcher/getRequestBody.test.ts
@@ -0,0 +1,129 @@
+import { getRequestBody } from "../../../src/core/fetcher/getRequestBody";
+import { RUNTIME } from "../../../src/core/runtime";
+
+describe("Test getRequestBody", () => {
+    interface TestCase {
+        description: string;
+        input: any;
+        type: "json" | "form" | "file" | "bytes" | "other";
+        expected: any;
+        skipCondition?: () => boolean;
+    }
+
+    const testCases: TestCase[] = [
+        {
+            description: "should stringify body if not FormData in Node environment",
+            input: { key: "value" },
+            type: "json",
+            expected: '{"key":"value"}',
+            skipCondition: () => RUNTIME.type !== "node",
+        },
+        {
+            description: "should stringify body if not FormData in browser environment",
+            input: { key: "value" },
+            type: "json",
+            expected: '{"key":"value"}',
+            skipCondition: () => RUNTIME.type !== "browser",
+        },
+        {
+            description: "should return the Uint8Array",
+            input: new Uint8Array([1, 2, 3]),
+            type: "bytes",
+            expected: new Uint8Array([1, 2, 3]),
+        },
+        {
+            description: "should serialize objects for form-urlencoded content type",
+            input: { username: "johndoe", email: "john@example.com" },
+            type: "form",
+            expected: "username=johndoe&email=john%40example.com",
+        },
+        {
+            description: "should serialize complex nested objects and arrays for form-urlencoded content type",
+            input: {
+                user: {
+                    profile: {
+                        name: "John Doe",
+                        settings: {
+                            theme: "dark",
+                            notifications: true,
+                        },
+                    },
+                    tags: ["admin", "user"],
+                    contacts: [
+                        { type: "email", value: "john@example.com" },
+                        { type: "phone", value: "+1234567890" },
+                    ],
+                },
+                filters: {
+                    status: ["active", "pending"],
+                    metadata: {
+                        created: "2024-01-01",
+                        categories: ["electronics", "books"],
+                    },
+                },
+                preferences: ["notifications", "updates"],
+            },
+            type: "form",
+            expected:
+                "user%5Bprofile%5D%5Bname%5D=John%20Doe&" +
+                "user%5Bprofile%5D%5Bsettings%5D%5Btheme%5D=dark&" +
+                "user%5Bprofile%5D%5Bsettings%5D%5Bnotifications%5D=true&" +
+                "user%5Btags%5D=admin&" +
+                "user%5Btags%5D=user&" +
+                "user%5Bcontacts%5D%5Btype%5D=email&" +
+                "user%5Bcontacts%5D%5Bvalue%5D=john%40example.com&" +
+                "user%5Bcontacts%5D%5Btype%5D=phone&" +
+                "user%5Bcontacts%5D%5Bvalue%5D=%2B1234567890&" +
+                "filters%5Bstatus%5D=active&" +
+                "filters%5Bstatus%5D=pending&" +
+                "filters%5Bmetadata%5D%5Bcreated%5D=2024-01-01&" +
+                "filters%5Bmetadata%5D%5Bcategories%5D=electronics&" +
+                "filters%5Bmetadata%5D%5Bcategories%5D=books&" +
+                "preferences=notifications&" +
+                "preferences=updates",
+        },
+        {
+            description: "should return the input for pre-serialized form-urlencoded strings",
+            input: "key=value&another=param",
+            type: "other",
+            expected: "key=value&another=param",
+        },
+        {
+            description: "should JSON stringify objects",
+            input: { key: "value" },
+            type: "json",
+            expected: '{"key":"value"}',
+        },
+    ];
+
+    testCases.forEach(({ description, input, type, expected, skipCondition }) => {
+        it(description, async () => {
+            if (skipCondition?.()) {
+                return;
+            }
+
+            const result = await getRequestBody({
+                body: input,
+                type,
+            });
+
+            if (input instanceof Uint8Array) {
+                expect(result).toBe(input);
+            } else {
+                expect(result).toBe(expected);
+            }
+        });
+    });
+
+    it("should return FormData in browser environment", async () => {
+        if (RUNTIME.type === "browser") {
+            const formData = new FormData();
+            formData.append("key", "value");
+            const result = await getRequestBody({
+                body: formData,
+                type: "file",
+            });
+            expect(result).toBe(formData);
+        }
+    });
+});
diff --git a/tests/unit/fetcher/getResponseBody.test.ts b/tests/unit/fetcher/getResponseBody.test.ts
new file mode 100644
index 00000000..ad6be7fc
--- /dev/null
+++ b/tests/unit/fetcher/getResponseBody.test.ts
@@ -0,0 +1,97 @@
+import { getResponseBody } from "../../../src/core/fetcher/getResponseBody";
+
+import { RUNTIME } from "../../../src/core/runtime";
+
+describe("Test getResponseBody", () => {
+    interface SimpleTestCase {
+        description: string;
+        responseData: string | Record;
+        responseType?: "blob" | "sse" | "streaming" | "text";
+        expected: any;
+        skipCondition?: () => boolean;
+    }
+
+    const simpleTestCases: SimpleTestCase[] = [
+        {
+            description: "should handle text response type",
+            responseData: "test text",
+            responseType: "text",
+            expected: "test text",
+        },
+        {
+            description: "should handle JSON response",
+            responseData: { key: "value" },
+            expected: { key: "value" },
+        },
+        {
+            description: "should handle empty response",
+            responseData: "",
+            expected: undefined,
+        },
+        {
+            description: "should handle non-JSON response",
+            responseData: "invalid json",
+            expected: {
+                ok: false,
+                error: {
+                    reason: "non-json",
+                    statusCode: 200,
+                    rawBody: "invalid json",
+                },
+            },
+        },
+    ];
+
+    simpleTestCases.forEach(({ description, responseData, responseType, expected, skipCondition }) => {
+        it(description, async () => {
+            if (skipCondition?.()) {
+                return;
+            }
+
+            const mockResponse = new Response(
+                typeof responseData === "string" ? responseData : JSON.stringify(responseData),
+            );
+            const result = await getResponseBody(mockResponse, responseType);
+            expect(result).toEqual(expected);
+        });
+    });
+
+    it("should handle blob response type", async () => {
+        const mockBlob = new Blob(["test"], { type: "text/plain" });
+        const mockResponse = new Response(mockBlob);
+        const result = await getResponseBody(mockResponse, "blob");
+        // @ts-expect-error
+        expect(result.constructor.name).toBe("Blob");
+    });
+
+    it("should handle sse response type", async () => {
+        if (RUNTIME.type === "node") {
+            const mockStream = new ReadableStream();
+            const mockResponse = new Response(mockStream);
+            const result = await getResponseBody(mockResponse, "sse");
+            expect(result).toBe(mockStream);
+        }
+    });
+
+    it("should handle streaming response type", async () => {
+        const encoder = new TextEncoder();
+        const testData = "test stream data";
+        const mockStream = new ReadableStream({
+            start(controller) {
+                controller.enqueue(encoder.encode(testData));
+                controller.close();
+            },
+        });
+
+        const mockResponse = new Response(mockStream);
+        const result = (await getResponseBody(mockResponse, "streaming")) as ReadableStream;
+
+        expect(result).toBeInstanceOf(ReadableStream);
+
+        const reader = result.getReader();
+        const decoder = new TextDecoder();
+        const { value } = await reader.read();
+        const streamContent = decoder.decode(value);
+        expect(streamContent).toBe(testData);
+    });
+});
diff --git a/tests/unit/fetcher/logging.test.ts b/tests/unit/fetcher/logging.test.ts
new file mode 100644
index 00000000..366c9b6c
--- /dev/null
+++ b/tests/unit/fetcher/logging.test.ts
@@ -0,0 +1,517 @@
+import { fetcherImpl } from "../../../src/core/fetcher/Fetcher";
+
+function createMockLogger() {
+    return {
+        debug: vi.fn(),
+        info: vi.fn(),
+        warn: vi.fn(),
+        error: vi.fn(),
+    };
+}
+
+function mockSuccessResponse(data: unknown = { data: "test" }, status = 200, statusText = "OK") {
+    global.fetch = vi.fn().mockResolvedValue(
+        new Response(JSON.stringify(data), {
+            status,
+            statusText,
+        }),
+    );
+}
+
+function mockErrorResponse(data: unknown = { error: "Error" }, status = 404, statusText = "Not Found") {
+    global.fetch = vi.fn().mockResolvedValue(
+        new Response(JSON.stringify(data), {
+            status,
+            statusText,
+        }),
+    );
+}
+
+describe("Fetcher Logging Integration", () => {
+    describe("Request Logging", () => {
+        it("should log successful request at debug level", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "POST",
+                headers: { "Content-Type": "application/json" },
+                body: { test: "data" },
+                contentType: "application/json",
+                requestType: "json",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    method: "POST",
+                    url: "https://example.com/api",
+                    headers: expect.toContainHeaders({
+                        "Content-Type": "application/json",
+                    }),
+                    hasBody: true,
+                }),
+            );
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "HTTP request succeeded",
+                expect.objectContaining({
+                    method: "POST",
+                    url: "https://example.com/api",
+                    statusCode: 200,
+                }),
+            );
+        });
+
+        it("should not log debug messages at info level for successful requests", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "info",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).not.toHaveBeenCalled();
+            expect(mockLogger.info).not.toHaveBeenCalled();
+        });
+
+        it("should log request with body flag", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "POST",
+                body: { data: "test" },
+                contentType: "application/json",
+                requestType: "json",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    hasBody: true,
+                }),
+            );
+        });
+
+        it("should log request without body flag", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    hasBody: false,
+                }),
+            );
+        });
+
+        it("should not log when silent mode is enabled", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: true,
+                },
+            });
+
+            expect(mockLogger.debug).not.toHaveBeenCalled();
+            expect(mockLogger.info).not.toHaveBeenCalled();
+            expect(mockLogger.warn).not.toHaveBeenCalled();
+            expect(mockLogger.error).not.toHaveBeenCalled();
+        });
+
+        it("should not log when no logging config is provided", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+            });
+
+            expect(mockLogger.debug).not.toHaveBeenCalled();
+        });
+    });
+
+    describe("Error Logging", () => {
+        it("should log 4xx errors at error level", async () => {
+            const mockLogger = createMockLogger();
+            mockErrorResponse({ error: "Not found" }, 404, "Not Found");
+
+            const result = await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "error",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(result.ok).toBe(false);
+            expect(mockLogger.error).toHaveBeenCalledWith(
+                "HTTP request failed with error status",
+                expect.objectContaining({
+                    method: "GET",
+                    url: "https://example.com/api",
+                    statusCode: 404,
+                }),
+            );
+        });
+
+        it("should log 5xx errors at error level", async () => {
+            const mockLogger = createMockLogger();
+            mockErrorResponse({ error: "Internal error" }, 500, "Internal Server Error");
+
+            const result = await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "error",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(result.ok).toBe(false);
+            expect(mockLogger.error).toHaveBeenCalledWith(
+                "HTTP request failed with error status",
+                expect.objectContaining({
+                    method: "GET",
+                    url: "https://example.com/api",
+                    statusCode: 500,
+                }),
+            );
+        });
+
+        it("should log aborted request errors", async () => {
+            const mockLogger = createMockLogger();
+
+            const abortController = new AbortController();
+            abortController.abort();
+
+            global.fetch = vi.fn().mockRejectedValue(new Error("Aborted"));
+
+            const result = await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                abortSignal: abortController.signal,
+                maxRetries: 0,
+                logging: {
+                    level: "error",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(result.ok).toBe(false);
+            expect(mockLogger.error).toHaveBeenCalledWith(
+                "HTTP request was aborted",
+                expect.objectContaining({
+                    method: "GET",
+                    url: "https://example.com/api",
+                }),
+            );
+        });
+
+        it("should log timeout errors", async () => {
+            const mockLogger = createMockLogger();
+
+            const timeoutError = new Error("Request timeout");
+            timeoutError.name = "AbortError";
+
+            global.fetch = vi.fn().mockRejectedValue(timeoutError);
+
+            const result = await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "error",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(result.ok).toBe(false);
+            expect(mockLogger.error).toHaveBeenCalledWith(
+                "HTTP request timed out",
+                expect.objectContaining({
+                    method: "GET",
+                    url: "https://example.com/api",
+                    timeoutMs: undefined,
+                }),
+            );
+        });
+
+        it("should log unknown errors", async () => {
+            const mockLogger = createMockLogger();
+
+            const unknownError = new Error("Unknown error");
+
+            global.fetch = vi.fn().mockRejectedValue(unknownError);
+
+            const result = await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "error",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(result.ok).toBe(false);
+            expect(mockLogger.error).toHaveBeenCalledWith(
+                "HTTP request failed with error",
+                expect.objectContaining({
+                    method: "GET",
+                    url: "https://example.com/api",
+                    errorMessage: "Unknown error",
+                }),
+            );
+        });
+    });
+
+    describe("Logging with Redaction", () => {
+        it("should redact sensitive data in error logs", async () => {
+            const mockLogger = createMockLogger();
+            mockErrorResponse({ error: "Unauthorized" }, 401, "Unauthorized");
+
+            await fetcherImpl({
+                url: "https://example.com/api?api_key=secret",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "error",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.error).toHaveBeenCalledWith(
+                "HTTP request failed with error status",
+                expect.objectContaining({
+                    url: "https://example.com/api?api_key=[REDACTED]",
+                }),
+            );
+        });
+    });
+
+    describe("Different HTTP Methods", () => {
+        it("should log GET requests", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    method: "GET",
+                }),
+            );
+        });
+
+        it("should log POST requests", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse({ data: "test" }, 201, "Created");
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "POST",
+                body: { data: "test" },
+                contentType: "application/json",
+                requestType: "json",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    method: "POST",
+                }),
+            );
+        });
+
+        it("should log PUT requests", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "PUT",
+                body: { data: "test" },
+                contentType: "application/json",
+                requestType: "json",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    method: "PUT",
+                }),
+            );
+        });
+
+        it("should log DELETE requests", async () => {
+            const mockLogger = createMockLogger();
+            global.fetch = vi.fn().mockResolvedValue(
+                new Response(null, {
+                    status: 200,
+                    statusText: "OK",
+                }),
+            );
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "DELETE",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    method: "DELETE",
+                }),
+            );
+        });
+    });
+
+    describe("Status Code Logging", () => {
+        it("should log 2xx success status codes", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse({ data: "test" }, 201, "Created");
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "POST",
+                body: { data: "test" },
+                contentType: "application/json",
+                requestType: "json",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "HTTP request succeeded",
+                expect.objectContaining({
+                    statusCode: 201,
+                }),
+            );
+        });
+
+        it("should log 3xx redirect status codes as success", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse({ data: "test" }, 301, "Moved Permanently");
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "HTTP request succeeded",
+                expect.objectContaining({
+                    statusCode: 301,
+                }),
+            );
+        });
+    });
+});
diff --git a/tests/unit/fetcher/makeRequest.test.ts b/tests/unit/fetcher/makeRequest.test.ts
new file mode 100644
index 00000000..ea49466a
--- /dev/null
+++ b/tests/unit/fetcher/makeRequest.test.ts
@@ -0,0 +1,54 @@
+import type { Mock } from "vitest";
+import { makeRequest } from "../../../src/core/fetcher/makeRequest";
+
+describe("Test makeRequest", () => {
+    const mockPostUrl = "https://httpbin.org/post";
+    const mockGetUrl = "https://httpbin.org/get";
+    const mockHeaders = { "Content-Type": "application/json" };
+    const mockBody = JSON.stringify({ key: "value" });
+
+    let mockFetch: Mock;
+
+    beforeEach(() => {
+        mockFetch = vi.fn();
+        mockFetch.mockResolvedValue(new Response(JSON.stringify({ test: "successful" }), { status: 200 }));
+    });
+
+    it("should handle POST request correctly", async () => {
+        const response = await makeRequest(mockFetch, mockPostUrl, "POST", mockHeaders, mockBody);
+        const responseBody = await response.json();
+        expect(responseBody).toEqual({ test: "successful" });
+        expect(mockFetch).toHaveBeenCalledTimes(1);
+        const [calledUrl, calledOptions] = mockFetch.mock.calls[0];
+        expect(calledUrl).toBe(mockPostUrl);
+        expect(calledOptions).toEqual(
+            expect.objectContaining({
+                method: "POST",
+                headers: mockHeaders,
+                body: mockBody,
+                credentials: undefined,
+            }),
+        );
+        expect(calledOptions.signal).toBeDefined();
+        expect(calledOptions.signal).toBeInstanceOf(AbortSignal);
+    });
+
+    it("should handle GET request correctly", async () => {
+        const response = await makeRequest(mockFetch, mockGetUrl, "GET", mockHeaders, undefined);
+        const responseBody = await response.json();
+        expect(responseBody).toEqual({ test: "successful" });
+        expect(mockFetch).toHaveBeenCalledTimes(1);
+        const [calledUrl, calledOptions] = mockFetch.mock.calls[0];
+        expect(calledUrl).toBe(mockGetUrl);
+        expect(calledOptions).toEqual(
+            expect.objectContaining({
+                method: "GET",
+                headers: mockHeaders,
+                body: undefined,
+                credentials: undefined,
+            }),
+        );
+        expect(calledOptions.signal).toBeDefined();
+        expect(calledOptions.signal).toBeInstanceOf(AbortSignal);
+    });
+});
diff --git a/tests/unit/fetcher/redacting.test.ts b/tests/unit/fetcher/redacting.test.ts
new file mode 100644
index 00000000..d599376b
--- /dev/null
+++ b/tests/unit/fetcher/redacting.test.ts
@@ -0,0 +1,1115 @@
+import { fetcherImpl } from "../../../src/core/fetcher/Fetcher";
+
+function createMockLogger() {
+    return {
+        debug: vi.fn(),
+        info: vi.fn(),
+        warn: vi.fn(),
+        error: vi.fn(),
+    };
+}
+
+function mockSuccessResponse(data: unknown = { data: "test" }, status = 200, statusText = "OK") {
+    global.fetch = vi.fn().mockResolvedValue(
+        new Response(JSON.stringify(data), {
+            status,
+            statusText,
+        }),
+    );
+}
+
+describe("Redacting Logic", () => {
+    describe("Header Redaction", () => {
+        it("should redact authorization header", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: { Authorization: "Bearer secret-token-12345" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        Authorization: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact api-key header (case-insensitive)", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: { "X-API-KEY": "secret-api-key" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        "X-API-KEY": "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact cookie header", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: { Cookie: "session=abc123; token=xyz789" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        Cookie: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact x-auth-token header", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: { "x-auth-token": "auth-token-12345" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        "x-auth-token": "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact proxy-authorization header", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: { "Proxy-Authorization": "Basic credentials" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        "Proxy-Authorization": "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact x-csrf-token header", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: { "X-CSRF-Token": "csrf-token-abc" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        "X-CSRF-Token": "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact www-authenticate header", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: { "WWW-Authenticate": "Bearer realm=example" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        "WWW-Authenticate": "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact x-session-token header", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: { "X-Session-Token": "session-token-xyz" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        "X-Session-Token": "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should not redact non-sensitive headers", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: {
+                    "Content-Type": "application/json",
+                    "User-Agent": "Test/1.0",
+                    Accept: "application/json",
+                },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        "Content-Type": "application/json",
+                        "User-Agent": "Test/1.0",
+                        Accept: "application/json",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact multiple sensitive headers at once", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                headers: {
+                    Authorization: "Bearer token",
+                    "X-API-Key": "api-key",
+                    Cookie: "session=123",
+                    "Content-Type": "application/json",
+                },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    headers: expect.toContainHeaders({
+                        Authorization: "[REDACTED]",
+                        "X-API-Key": "[REDACTED]",
+                        Cookie: "[REDACTED]",
+                        "Content-Type": "application/json",
+                    }),
+                }),
+            );
+        });
+    });
+
+    describe("Response Header Redaction", () => {
+        it("should redact Set-Cookie in response headers", async () => {
+            const mockLogger = createMockLogger();
+
+            const mockHeaders = new Headers();
+            mockHeaders.set("Set-Cookie", "session=abc123; HttpOnly; Secure");
+            mockHeaders.set("Content-Type", "application/json");
+
+            global.fetch = vi.fn().mockResolvedValue(
+                new Response(JSON.stringify({ data: "test" }), {
+                    status: 200,
+                    statusText: "OK",
+                    headers: mockHeaders,
+                }),
+            );
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "HTTP request succeeded",
+                expect.objectContaining({
+                    responseHeaders: expect.toContainHeaders({
+                        "set-cookie": "[REDACTED]",
+                        "content-type": "application/json",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact authorization in response headers", async () => {
+            const mockLogger = createMockLogger();
+
+            const mockHeaders = new Headers();
+            mockHeaders.set("Authorization", "Bearer token-123");
+            mockHeaders.set("Content-Type", "application/json");
+
+            global.fetch = vi.fn().mockResolvedValue(
+                new Response(JSON.stringify({ data: "test" }), {
+                    status: 200,
+                    statusText: "OK",
+                    headers: mockHeaders,
+                }),
+            );
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "HTTP request succeeded",
+                expect.objectContaining({
+                    responseHeaders: expect.toContainHeaders({
+                        authorization: "[REDACTED]",
+                        "content-type": "application/json",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact response headers in error responses", async () => {
+            const mockLogger = createMockLogger();
+
+            const mockHeaders = new Headers();
+            mockHeaders.set("WWW-Authenticate", "Bearer realm=example");
+            mockHeaders.set("Content-Type", "application/json");
+
+            global.fetch = vi.fn().mockResolvedValue(
+                new Response(JSON.stringify({ error: "Unauthorized" }), {
+                    status: 401,
+                    statusText: "Unauthorized",
+                    headers: mockHeaders,
+                }),
+            );
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "error",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.error).toHaveBeenCalledWith(
+                "HTTP request failed with error status",
+                expect.objectContaining({
+                    responseHeaders: expect.toContainHeaders({
+                        "www-authenticate": "[REDACTED]",
+                        "content-type": "application/json",
+                    }),
+                }),
+            );
+        });
+    });
+
+    describe("Query Parameter Redaction", () => {
+        it("should redact api_key query parameter", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: { api_key: "secret-key" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        api_key: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact token query parameter", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: { token: "secret-token" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        token: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact access_token query parameter", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: { access_token: "secret-access-token" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        access_token: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact password query parameter", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: { password: "secret-password" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        password: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact secret query parameter", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: { secret: "secret-value" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        secret: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should redact session_id query parameter", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: { session_id: "session-123" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        session_id: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+
+        it("should not redact non-sensitive query parameters", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: {
+                    page: "1",
+                    limit: "10",
+                    sort: "name",
+                },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        page: "1",
+                        limit: "10",
+                        sort: "name",
+                    }),
+                }),
+            );
+        });
+
+        it("should not redact parameters containing 'auth' substring like 'author'", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: {
+                    author: "john",
+                    authenticate: "false",
+                    authorization_level: "user",
+                },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        author: "john",
+                        authenticate: "false",
+                        authorization_level: "user",
+                    }),
+                }),
+            );
+        });
+
+        it("should handle undefined query parameters", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: undefined,
+                }),
+            );
+        });
+
+        it("should redact case-insensitive query parameters", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                queryParameters: { API_KEY: "secret-key", Token: "secret-token" },
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    queryParameters: expect.objectContaining({
+                        API_KEY: "[REDACTED]",
+                        Token: "[REDACTED]",
+                    }),
+                }),
+            );
+        });
+    });
+
+    describe("URL Redaction", () => {
+        it("should redact credentials in URL", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://user:password@example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://[REDACTED]@example.com/api",
+                }),
+            );
+        });
+
+        it("should redact api_key in query string", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?api_key=secret-key&page=1",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?api_key=[REDACTED]&page=1",
+                }),
+            );
+        });
+
+        it("should redact token in query string", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?token=secret-token",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?token=[REDACTED]",
+                }),
+            );
+        });
+
+        it("should redact password in query string", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?username=user&password=secret",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?username=user&password=[REDACTED]",
+                }),
+            );
+        });
+
+        it("should not redact non-sensitive query strings", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?page=1&limit=10&sort=name",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?page=1&limit=10&sort=name",
+                }),
+            );
+        });
+
+        it("should not redact URL parameters containing 'auth' substring like 'author'", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?author=john&authenticate=false&page=1",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?author=john&authenticate=false&page=1",
+                }),
+            );
+        });
+
+        it("should handle URL with fragment", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?token=secret#section",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?token=[REDACTED]#section",
+                }),
+            );
+        });
+
+        it("should redact URL-encoded query parameters", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?api%5Fkey=secret",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?api%5Fkey=[REDACTED]",
+                }),
+            );
+        });
+
+        it("should handle URL without query string", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api",
+                }),
+            );
+        });
+
+        it("should handle empty query string", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?",
+                }),
+            );
+        });
+
+        it("should redact multiple sensitive parameters in URL", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?api_key=secret1&token=secret2&page=1",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?api_key=[REDACTED]&token=[REDACTED]&page=1",
+                }),
+            );
+        });
+
+        it("should redact both credentials and query parameters", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://user:pass@example.com/api?token=secret",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://[REDACTED]@example.com/api?token=[REDACTED]",
+                }),
+            );
+        });
+
+        it("should use fast path for URLs without sensitive keywords", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?page=1&limit=10&sort=name&filter=value",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?page=1&limit=10&sort=name&filter=value",
+                }),
+            );
+        });
+
+        it("should handle query parameter without value", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?flag&token=secret",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?flag&token=[REDACTED]",
+                }),
+            );
+        });
+
+        it("should handle URL with multiple @ symbols in credentials", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://user@example.com:pass@host.com/api",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://[REDACTED]@host.com/api",
+                }),
+            );
+        });
+
+        it("should handle URL with @ in query parameter but not in credentials", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://example.com/api?email=user@example.com",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://example.com/api?email=user@example.com",
+                }),
+            );
+        });
+
+        it("should handle URL with both credentials and @ in path", async () => {
+            const mockLogger = createMockLogger();
+            mockSuccessResponse();
+
+            await fetcherImpl({
+                url: "https://user:pass@example.com/users/@username",
+                method: "GET",
+                responseType: "json",
+                maxRetries: 0,
+                logging: {
+                    level: "debug",
+                    logger: mockLogger,
+                    silent: false,
+                },
+            });
+
+            expect(mockLogger.debug).toHaveBeenCalledWith(
+                "Making HTTP request",
+                expect.objectContaining({
+                    url: "https://[REDACTED]@example.com/users/@username",
+                }),
+            );
+        });
+    });
+});
diff --git a/tests/unit/fetcher/requestWithRetries.test.ts b/tests/unit/fetcher/requestWithRetries.test.ts
new file mode 100644
index 00000000..d2266136
--- /dev/null
+++ b/tests/unit/fetcher/requestWithRetries.test.ts
@@ -0,0 +1,230 @@
+import type { Mock, MockInstance } from "vitest";
+import { requestWithRetries } from "../../../src/core/fetcher/requestWithRetries";
+
+describe("requestWithRetries", () => {
+    let mockFetch: Mock;
+    let originalMathRandom: typeof Math.random;
+    let setTimeoutSpy: MockInstance;
+
+    beforeEach(() => {
+        mockFetch = vi.fn();
+        originalMathRandom = Math.random;
+
+        Math.random = vi.fn(() => 0.5);
+
+        vi.useFakeTimers({
+            toFake: [
+                "setTimeout",
+                "clearTimeout",
+                "setInterval",
+                "clearInterval",
+                "setImmediate",
+                "clearImmediate",
+                "Date",
+                "performance",
+                "requestAnimationFrame",
+                "cancelAnimationFrame",
+                "requestIdleCallback",
+                "cancelIdleCallback",
+            ],
+        });
+    });
+
+    afterEach(() => {
+        Math.random = originalMathRandom;
+        vi.clearAllMocks();
+        vi.clearAllTimers();
+    });
+
+    it("should retry on retryable status codes", async () => {
+        setTimeoutSpy = vi.spyOn(global, "setTimeout").mockImplementation((callback: (args: void) => void) => {
+            process.nextTick(callback);
+            return null as any;
+        });
+
+        const retryableStatuses = [408, 429, 500, 502];
+        let callCount = 0;
+
+        mockFetch.mockImplementation(async () => {
+            if (callCount < retryableStatuses.length) {
+                return new Response("", { status: retryableStatuses[callCount++] });
+            }
+            return new Response("", { status: 200 });
+        });
+
+        const responsePromise = requestWithRetries(() => mockFetch(), retryableStatuses.length);
+        await vi.runAllTimersAsync();
+        const response = await responsePromise;
+
+        expect(mockFetch).toHaveBeenCalledTimes(retryableStatuses.length + 1);
+        expect(response.status).toBe(200);
+    });
+
+    it("should respect maxRetries limit", async () => {
+        setTimeoutSpy = vi.spyOn(global, "setTimeout").mockImplementation((callback: (args: void) => void) => {
+            process.nextTick(callback);
+            return null as any;
+        });
+
+        const maxRetries = 2;
+        mockFetch.mockResolvedValue(new Response("", { status: 500 }));
+
+        const responsePromise = requestWithRetries(() => mockFetch(), maxRetries);
+        await vi.runAllTimersAsync();
+        const response = await responsePromise;
+
+        expect(mockFetch).toHaveBeenCalledTimes(maxRetries + 1);
+        expect(response.status).toBe(500);
+    });
+
+    it("should not retry on success status codes", async () => {
+        setTimeoutSpy = vi.spyOn(global, "setTimeout").mockImplementation((callback: (args: void) => void) => {
+            process.nextTick(callback);
+            return null as any;
+        });
+
+        const successStatuses = [200, 201, 202];
+
+        for (const status of successStatuses) {
+            mockFetch.mockReset();
+            setTimeoutSpy.mockClear();
+            mockFetch.mockResolvedValueOnce(new Response("", { status }));
+
+            const responsePromise = requestWithRetries(() => mockFetch(), 3);
+            await vi.runAllTimersAsync();
+            await responsePromise;
+
+            expect(mockFetch).toHaveBeenCalledTimes(1);
+            expect(setTimeoutSpy).not.toHaveBeenCalled();
+        }
+    });
+
+    interface RetryHeaderTestCase {
+        description: string;
+        headerName: string;
+        headerValue: string | (() => string);
+        expectedDelayMin: number;
+        expectedDelayMax: number;
+    }
+
+    const retryHeaderTests: RetryHeaderTestCase[] = [
+        {
+            description: "should respect retry-after header with seconds value",
+            headerName: "retry-after",
+            headerValue: "5",
+            expectedDelayMin: 4000,
+            expectedDelayMax: 6000,
+        },
+        {
+            description: "should respect retry-after header with HTTP date value",
+            headerName: "retry-after",
+            headerValue: () => new Date(Date.now() + 3000).toUTCString(),
+            expectedDelayMin: 2000,
+            expectedDelayMax: 4000,
+        },
+        {
+            description: "should respect x-ratelimit-reset header",
+            headerName: "x-ratelimit-reset",
+            headerValue: () => Math.floor((Date.now() + 4000) / 1000).toString(),
+            expectedDelayMin: 3000,
+            expectedDelayMax: 6000,
+        },
+    ];
+
+    retryHeaderTests.forEach(({ description, headerName, headerValue, expectedDelayMin, expectedDelayMax }) => {
+        it(description, async () => {
+            setTimeoutSpy = vi.spyOn(global, "setTimeout").mockImplementation((callback: (args: void) => void) => {
+                process.nextTick(callback);
+                return null as any;
+            });
+
+            const value = typeof headerValue === "function" ? headerValue() : headerValue;
+            mockFetch
+                .mockResolvedValueOnce(
+                    new Response("", {
+                        status: 429,
+                        headers: new Headers({ [headerName]: value }),
+                    }),
+                )
+                .mockResolvedValueOnce(new Response("", { status: 200 }));
+
+            const responsePromise = requestWithRetries(() => mockFetch(), 1);
+            await vi.runAllTimersAsync();
+            const response = await responsePromise;
+
+            expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), expect.any(Number));
+            const actualDelay = setTimeoutSpy.mock.calls[0][1];
+            expect(actualDelay).toBeGreaterThan(expectedDelayMin);
+            expect(actualDelay).toBeLessThan(expectedDelayMax);
+            expect(response.status).toBe(200);
+        });
+    });
+
+    it("should apply correct exponential backoff with jitter", async () => {
+        setTimeoutSpy = vi.spyOn(global, "setTimeout").mockImplementation((callback: (args: void) => void) => {
+            process.nextTick(callback);
+            return null as any;
+        });
+
+        mockFetch.mockResolvedValue(new Response("", { status: 500 }));
+        const maxRetries = 3;
+        const expectedDelays = [1000, 2000, 4000];
+
+        const responsePromise = requestWithRetries(() => mockFetch(), maxRetries);
+        await vi.runAllTimersAsync();
+        await responsePromise;
+
+        expect(setTimeoutSpy).toHaveBeenCalledTimes(expectedDelays.length);
+
+        expectedDelays.forEach((delay, index) => {
+            expect(setTimeoutSpy).toHaveBeenNthCalledWith(index + 1, expect.any(Function), delay);
+        });
+
+        expect(mockFetch).toHaveBeenCalledTimes(maxRetries + 1);
+    });
+
+    it("should handle concurrent retries independently", async () => {
+        setTimeoutSpy = vi.spyOn(global, "setTimeout").mockImplementation((callback: (args: void) => void) => {
+            process.nextTick(callback);
+            return null as any;
+        });
+
+        mockFetch
+            .mockResolvedValueOnce(new Response("", { status: 500 }))
+            .mockResolvedValueOnce(new Response("", { status: 500 }))
+            .mockResolvedValueOnce(new Response("", { status: 200 }))
+            .mockResolvedValueOnce(new Response("", { status: 200 }));
+
+        const promise1 = requestWithRetries(() => mockFetch(), 1);
+        const promise2 = requestWithRetries(() => mockFetch(), 1);
+
+        await vi.runAllTimersAsync();
+        const [response1, response2] = await Promise.all([promise1, promise2]);
+
+        expect(response1.status).toBe(200);
+        expect(response2.status).toBe(200);
+    });
+
+    it("should cap delay at MAX_RETRY_DELAY for large header values", async () => {
+        setTimeoutSpy = vi.spyOn(global, "setTimeout").mockImplementation((callback: (args: void) => void) => {
+            process.nextTick(callback);
+            return null as any;
+        });
+
+        mockFetch
+            .mockResolvedValueOnce(
+                new Response("", {
+                    status: 429,
+                    headers: new Headers({ "retry-after": "120" }), // 120 seconds = 120000ms > MAX_RETRY_DELAY (60000ms)
+                }),
+            )
+            .mockResolvedValueOnce(new Response("", { status: 200 }));
+
+        const responsePromise = requestWithRetries(() => mockFetch(), 1);
+        await vi.runAllTimersAsync();
+        const response = await responsePromise;
+
+        expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), 60000);
+        expect(response.status).toBe(200);
+    });
+});
diff --git a/tests/unit/fetcher/signals.test.ts b/tests/unit/fetcher/signals.test.ts
new file mode 100644
index 00000000..d7b6d1e6
--- /dev/null
+++ b/tests/unit/fetcher/signals.test.ts
@@ -0,0 +1,69 @@
+import { anySignal, getTimeoutSignal } from "../../../src/core/fetcher/signals";
+
+describe("Test getTimeoutSignal", () => {
+    beforeEach(() => {
+        vi.useFakeTimers();
+    });
+
+    afterEach(() => {
+        vi.useRealTimers();
+    });
+
+    it("should return an object with signal and abortId", () => {
+        const { signal, abortId } = getTimeoutSignal(1000);
+
+        expect(signal).toBeDefined();
+        expect(abortId).toBeDefined();
+        expect(signal).toBeInstanceOf(AbortSignal);
+        expect(signal.aborted).toBe(false);
+    });
+
+    it("should create a signal that aborts after the specified timeout", () => {
+        const timeoutMs = 5000;
+        const { signal } = getTimeoutSignal(timeoutMs);
+
+        expect(signal.aborted).toBe(false);
+
+        vi.advanceTimersByTime(timeoutMs - 1);
+        expect(signal.aborted).toBe(false);
+
+        vi.advanceTimersByTime(1);
+        expect(signal.aborted).toBe(true);
+    });
+});
+
+describe("Test anySignal", () => {
+    it("should return an AbortSignal", () => {
+        const signal = anySignal(new AbortController().signal);
+        expect(signal).toBeInstanceOf(AbortSignal);
+    });
+
+    it("should abort when any of the input signals is aborted", () => {
+        const controller1 = new AbortController();
+        const controller2 = new AbortController();
+        const signal = anySignal(controller1.signal, controller2.signal);
+
+        expect(signal.aborted).toBe(false);
+        controller1.abort();
+        expect(signal.aborted).toBe(true);
+    });
+
+    it("should handle an array of signals", () => {
+        const controller1 = new AbortController();
+        const controller2 = new AbortController();
+        const signal = anySignal([controller1.signal, controller2.signal]);
+
+        expect(signal.aborted).toBe(false);
+        controller2.abort();
+        expect(signal.aborted).toBe(true);
+    });
+
+    it("should abort immediately if one of the input signals is already aborted", () => {
+        const controller1 = new AbortController();
+        const controller2 = new AbortController();
+        controller1.abort();
+
+        const signal = anySignal(controller1.signal, controller2.signal);
+        expect(signal.aborted).toBe(true);
+    });
+});
diff --git a/tests/unit/fetcher/test-file.txt b/tests/unit/fetcher/test-file.txt
new file mode 100644
index 00000000..c66d471e
--- /dev/null
+++ b/tests/unit/fetcher/test-file.txt
@@ -0,0 +1 @@
+This is a test file!
diff --git a/tests/unit/file/file.test.ts b/tests/unit/file/file.test.ts
new file mode 100644
index 00000000..d7c4570b
--- /dev/null
+++ b/tests/unit/file/file.test.ts
@@ -0,0 +1,498 @@
+import fs from "fs";
+import { join } from "path";
+import { Readable } from "stream";
+import { toBinaryUploadRequest, type Uploadable } from "../../../src/core/file/index";
+
+describe("toBinaryUploadRequest", () => {
+    const TEST_FILE_PATH = join(__dirname, "..", "test-file.txt");
+
+    beforeEach(() => {
+        vi.clearAllMocks();
+    });
+
+    describe("Buffer input", () => {
+        it("should handle Buffer with all metadata", async () => {
+            const buffer = Buffer.from("test data");
+            const input: Uploadable.WithMetadata = {
+                data: buffer,
+                filename: "test.txt",
+                contentType: "text/plain",
+                contentLength: 42,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(buffer);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="test.txt"',
+                "Content-Type": "text/plain",
+                "Content-Length": "42",
+            });
+        });
+
+        it("should handle Buffer without metadata", async () => {
+            const buffer = Buffer.from("test data");
+            const input: Uploadable.WithMetadata = {
+                data: buffer,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(buffer);
+            expect(result.headers).toEqual({
+                "Content-Length": "9", // buffer.length
+            });
+        });
+
+        it("should handle Buffer passed directly", async () => {
+            const buffer = Buffer.from("test data");
+
+            const result = await toBinaryUploadRequest(buffer);
+
+            expect(result.body).toBe(buffer);
+            expect(result.headers).toEqual({
+                "Content-Length": "9", // buffer.length
+            });
+        });
+    });
+
+    describe("ArrayBuffer input", () => {
+        it("should handle ArrayBuffer with metadata", async () => {
+            const arrayBuffer = new ArrayBuffer(10);
+            const input: Uploadable.WithMetadata = {
+                data: arrayBuffer,
+                filename: "data.bin",
+                contentType: "application/octet-stream",
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(arrayBuffer);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="data.bin"',
+                "Content-Type": "application/octet-stream",
+                "Content-Length": "10", // arrayBuffer.byteLength
+            });
+        });
+
+        it("should handle ArrayBuffer passed directly", async () => {
+            const arrayBuffer = new ArrayBuffer(10);
+
+            const result = await toBinaryUploadRequest(arrayBuffer);
+
+            expect(result.body).toBe(arrayBuffer);
+            expect(result.headers).toEqual({
+                "Content-Length": "10", // arrayBuffer.byteLength
+            });
+        });
+    });
+
+    describe("Uint8Array input", () => {
+        it("should handle Uint8Array with metadata", async () => {
+            const uint8Array = new Uint8Array([1, 2, 3, 4, 5]);
+            const input: Uploadable.WithMetadata = {
+                data: uint8Array,
+                filename: "bytes.bin",
+                contentType: "application/octet-stream",
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(uint8Array);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="bytes.bin"',
+                "Content-Type": "application/octet-stream",
+                "Content-Length": "5", // uint8Array.byteLength
+            });
+        });
+
+        it("should handle Uint8Array passed directly", async () => {
+            const uint8Array = new Uint8Array([1, 2, 3, 4, 5]);
+
+            const result = await toBinaryUploadRequest(uint8Array);
+
+            expect(result.body).toBe(uint8Array);
+            expect(result.headers).toEqual({
+                "Content-Length": "5", // uint8Array.byteLength
+            });
+        });
+    });
+
+    describe("Blob input", () => {
+        it("should handle Blob with metadata", async () => {
+            const blob = new Blob(["test content"], { type: "text/plain" });
+            const input: Uploadable.WithMetadata = {
+                data: blob,
+                filename: "override.txt",
+                contentType: "text/html", // Override blob's type
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(blob);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="override.txt"',
+                "Content-Type": "text/html", // Should use provided contentType
+                "Content-Length": "12", // blob.size
+            });
+        });
+
+        it("should handle Blob with intrinsic type", async () => {
+            const blob = new Blob(["test content"], { type: "application/json" });
+            const input: Uploadable.WithMetadata = {
+                data: blob,
+                filename: "data.json",
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(blob);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="data.json"',
+                "Content-Type": "application/json", // Should use blob's type
+                "Content-Length": "12", // blob.size
+            });
+        });
+
+        it("should handle Blob passed directly", async () => {
+            const blob = new Blob(["test content"], { type: "text/plain" });
+
+            const result = await toBinaryUploadRequest(blob);
+
+            expect(result.body).toBe(blob);
+            expect(result.headers).toEqual({
+                "Content-Type": "text/plain", // Should use blob's type
+                "Content-Length": "12", // blob.size
+            });
+        });
+    });
+
+    describe("File input", () => {
+        it("should handle File with metadata", async () => {
+            const file = new File(["file content"], "original.txt", { type: "text/plain" });
+            const input: Uploadable.WithMetadata = {
+                data: file,
+                filename: "renamed.txt",
+                contentType: "text/html", // Override file's type
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(file);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="renamed.txt"',
+                "Content-Type": "text/html", // Should use provided contentType
+                "Content-Length": "12", // file.size
+            });
+        });
+
+        it("should handle File with intrinsic properties", async () => {
+            const file = new File(["file content"], "test.json", { type: "application/json" });
+            const input: Uploadable.WithMetadata = {
+                data: file,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(file);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="test.json"', // Should use file's name
+                "Content-Type": "application/json", // Should use file's type
+                "Content-Length": "12", // file.size
+            });
+        });
+
+        it("should handle File passed directly", async () => {
+            const file = new File(["file content"], "direct.txt", { type: "text/plain" });
+
+            const result = await toBinaryUploadRequest(file);
+
+            expect(result.body).toBe(file);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="direct.txt"',
+                "Content-Type": "text/plain",
+                "Content-Length": "12", // file.size
+            });
+        });
+    });
+
+    describe("ReadableStream input", () => {
+        it("should handle ReadableStream with metadata", async () => {
+            const stream = new ReadableStream({
+                start(controller) {
+                    controller.enqueue(new TextEncoder().encode("stream data"));
+                    controller.close();
+                },
+            });
+            const input: Uploadable.WithMetadata = {
+                data: stream,
+                filename: "stream.txt",
+                contentType: "text/plain",
+                contentLength: 100,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(stream);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="stream.txt"',
+                "Content-Type": "text/plain",
+                "Content-Length": "100", // Should use provided contentLength
+            });
+        });
+
+        it("should handle ReadableStream without size", async () => {
+            const stream = new ReadableStream({
+                start(controller) {
+                    controller.enqueue(new TextEncoder().encode("stream data"));
+                    controller.close();
+                },
+            });
+            const input: Uploadable.WithMetadata = {
+                data: stream,
+                filename: "stream.txt",
+                contentType: "text/plain",
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(stream);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="stream.txt"',
+                "Content-Type": "text/plain",
+                // No Content-Length header since it cannot be determined from ReadableStream
+            });
+        });
+
+        it("should handle ReadableStream passed directly", async () => {
+            const stream = new ReadableStream({
+                start(controller) {
+                    controller.enqueue(new TextEncoder().encode("stream data"));
+                    controller.close();
+                },
+            });
+
+            const result = await toBinaryUploadRequest(stream);
+
+            expect(result.body).toBe(stream);
+            expect(result.headers).toEqual({
+                // No headers since no metadata provided and cannot be determined
+            });
+        });
+    });
+
+    describe("Node.js Readable stream input", () => {
+        it("should handle Readable stream with metadata", async () => {
+            const readable = new Readable({
+                read() {
+                    this.push("readable data");
+                    this.push(null);
+                },
+            });
+            const input: Uploadable.WithMetadata = {
+                data: readable,
+                filename: "readable.txt",
+                contentType: "text/plain",
+                contentLength: 50,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(readable);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="readable.txt"',
+                "Content-Type": "text/plain",
+                "Content-Length": "50", // Should use provided contentLength
+            });
+        });
+
+        it("should handle Readable stream without size", async () => {
+            const readable = new Readable({
+                read() {
+                    this.push("readable data");
+                    this.push(null);
+                },
+            });
+            const input: Uploadable.WithMetadata = {
+                data: readable,
+                filename: "readable.txt",
+                contentType: "text/plain",
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(readable);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="readable.txt"',
+                "Content-Type": "text/plain",
+                // No Content-Length header since it cannot be determined from Readable
+            });
+        });
+
+        it("should handle Readable stream passed directly", async () => {
+            const readable = new Readable({
+                read() {
+                    this.push("readable data");
+                    this.push(null);
+                },
+            });
+
+            const result = await toBinaryUploadRequest(readable);
+
+            expect(result.body).toBe(readable);
+            expect(result.headers).toEqual({
+                // No headers since no metadata provided and cannot be determined
+            });
+        });
+    });
+
+    describe("File path input (FromPath type)", () => {
+        it("should handle file path with all metadata", async () => {
+            const input: Uploadable.FromPath = {
+                path: TEST_FILE_PATH,
+                filename: "custom.txt",
+                contentType: "text/html",
+                contentLength: 42,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBeInstanceOf(fs.ReadStream);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="custom.txt"',
+                "Content-Type": "text/html",
+                "Content-Length": "42", // Should use provided contentLength
+            });
+        });
+
+        it("should handle file path with minimal metadata", async () => {
+            const input: Uploadable.FromPath = {
+                path: TEST_FILE_PATH,
+                contentType: "text/plain",
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBeInstanceOf(fs.ReadStream);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="test-file.txt"', // Should extract from path
+                "Content-Type": "text/plain",
+                "Content-Length": "21", // Should determine from file system (test file is 21 bytes)
+            });
+        });
+
+        it("should handle file path with no metadata", async () => {
+            const input: Uploadable.FromPath = {
+                path: TEST_FILE_PATH,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBeInstanceOf(fs.ReadStream);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="test-file.txt"', // Should extract from path
+                "Content-Length": "21", // Should determine from file system (test file is 21 bytes)
+            });
+        });
+    });
+
+    describe("ArrayBufferView input", () => {
+        it("should handle ArrayBufferView with metadata", async () => {
+            const arrayBuffer = new ArrayBuffer(10);
+            const arrayBufferView = new Int8Array(arrayBuffer);
+            const input: Uploadable.WithMetadata = {
+                data: arrayBufferView,
+                filename: "view.bin",
+                contentType: "application/octet-stream",
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(arrayBufferView);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="view.bin"',
+                "Content-Type": "application/octet-stream",
+                "Content-Length": "10", // arrayBufferView.byteLength
+            });
+        });
+
+        it("should handle ArrayBufferView passed directly", async () => {
+            const arrayBuffer = new ArrayBuffer(10);
+            const arrayBufferView = new Int8Array(arrayBuffer);
+
+            const result = await toBinaryUploadRequest(arrayBufferView);
+
+            expect(result.body).toBe(arrayBufferView);
+            expect(result.headers).toEqual({
+                "Content-Length": "10", // arrayBufferView.byteLength
+            });
+        });
+    });
+
+    describe("Edge cases", () => {
+        it("should handle empty headers when no metadata is available", async () => {
+            const buffer = Buffer.from("");
+            const input: Uploadable.WithMetadata = {
+                data: buffer,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(buffer);
+            expect(result.headers).toEqual({
+                "Content-Length": "0",
+            });
+        });
+
+        it("should handle zero contentLength", async () => {
+            const buffer = Buffer.from("test");
+            const input: Uploadable.WithMetadata = {
+                data: buffer,
+                contentLength: 0,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(buffer);
+            expect(result.headers).toEqual({
+                "Content-Length": "0", // Should use provided 0
+            });
+        });
+
+        it("should handle null filename", async () => {
+            const buffer = Buffer.from("test");
+            const input: Uploadable.WithMetadata = {
+                data: buffer,
+                filename: undefined,
+                contentType: "text/plain",
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(buffer);
+            expect(result.headers).toEqual({
+                "Content-Type": "text/plain",
+                "Content-Length": "4",
+                // No Content-Disposition since filename is undefined
+            });
+        });
+
+        it("should handle null contentType", async () => {
+            const buffer = Buffer.from("test");
+            const input: Uploadable.WithMetadata = {
+                data: buffer,
+                filename: "test.txt",
+                contentType: undefined,
+            };
+
+            const result = await toBinaryUploadRequest(input);
+
+            expect(result.body).toBe(buffer);
+            expect(result.headers).toEqual({
+                "Content-Disposition": 'attachment; filename="test.txt"',
+                "Content-Length": "4",
+                // No Content-Type since contentType is undefined
+            });
+        });
+    });
+});
diff --git a/tests/unit/live-client-connection-state.test.ts b/tests/unit/live-client-connection-state.test.ts
deleted file mode 100644
index 78bf9a5d..00000000
--- a/tests/unit/live-client-connection-state.test.ts
+++ /dev/null
@@ -1,369 +0,0 @@
-import { ListenLiveClient } from "../../src/packages/ListenLiveClient";
-import { SpeakLiveClient } from "../../src/packages/SpeakLiveClient";
-import { AgentLiveClient } from "../../src/packages/AgentLiveClient";
-import { CONNECTION_STATE, SOCKET_STATES } from "../../src/lib/constants";
-import { LiveTranscriptionEvents } from "../../src/lib/enums/LiveTranscriptionEvents";
-
-describe("Unit Tests - Live Client Connection State", () => {
-  describe("Connection State Management", () => {
-    let client: ListenLiveClient;
-    let mockConnection: any;
-
-    beforeEach(() => {
-      // Mock the connection object
-      mockConnection = {
-        readyState: SOCKET_STATES.connecting,
-        send: jest.fn(),
-        close: jest.fn(),
-        onopen: null,
-        onclose: null,
-        onerror: null,
-        onmessage: null,
-      };
-
-      // Create a mock WebSocket constructor
-      const MockWebSocket = jest.fn().mockImplementation(() => mockConnection);
-
-      // Create client with mocked transport
-      client = new ListenLiveClient({
-        key: "test-key",
-        global: {
-          websocket: {
-            // @ts-expect-error - bypassing TypeScript for testing
-            client: MockWebSocket,
-          },
-        },
-      });
-    });
-
-    afterEach(() => {
-      if (client) {
-        client.disconnect();
-      }
-    });
-
-    it("should report correct connection state during lifecycle", () => {
-      // Initially connecting
-      expect(client.connectionState()).toBe(CONNECTION_STATE.Connecting);
-
-      // Simulate connection open
-      mockConnection.readyState = SOCKET_STATES.open;
-      expect(client.connectionState()).toBe(CONNECTION_STATE.Open);
-
-      // Simulate connection closing
-      mockConnection.readyState = SOCKET_STATES.closing;
-      expect(client.connectionState()).toBe(CONNECTION_STATE.Closing);
-
-      // Simulate connection closed
-      mockConnection.readyState = SOCKET_STATES.closed;
-      expect(client.connectionState()).toBe(CONNECTION_STATE.Closed);
-    });
-
-    it("should correctly report if connected", () => {
-      // Not connected initially
-      expect(client.isConnected()).toBe(false);
-
-      // Connected when open
-      mockConnection.readyState = SOCKET_STATES.open;
-      expect(client.isConnected()).toBe(true);
-
-      // Not connected when closing
-      mockConnection.readyState = SOCKET_STATES.closing;
-      expect(client.isConnected()).toBe(false);
-    });
-
-    it("should provide ready state access", () => {
-      mockConnection.readyState = SOCKET_STATES.open;
-      expect(client.getReadyState()).toBe(SOCKET_STATES.open);
-
-      mockConnection.readyState = SOCKET_STATES.closed;
-      expect(client.getReadyState()).toBe(SOCKET_STATES.closed);
-    });
-
-    it("should handle disconnection properly", () => {
-      mockConnection.readyState = SOCKET_STATES.open;
-
-      client.disconnect();
-
-      expect(mockConnection.close).toHaveBeenCalled();
-    });
-
-    it("should handle disconnection with code and reason", () => {
-      mockConnection.readyState = SOCKET_STATES.open;
-
-      client.disconnect(1000, "Test closure");
-
-      expect(mockConnection.close).toHaveBeenCalledWith(1000, "Test closure");
-    });
-
-    it("should have reconnect function available", () => {
-      expect(typeof client.reconnect).toBe("function");
-    });
-  });
-
-  describe("ListenLiveClient Specific Functionality", () => {
-    let client: ListenLiveClient;
-    let mockConnection: any;
-
-    beforeEach(() => {
-      mockConnection = {
-        readyState: SOCKET_STATES.open,
-        send: jest.fn(),
-        close: jest.fn(),
-        onopen: null,
-        onclose: null,
-        onerror: null,
-        onmessage: null,
-      };
-
-      const MockWebSocket = jest.fn().mockImplementation(() => mockConnection);
-
-      client = new ListenLiveClient({
-        key: "test-key",
-        global: {
-          websocket: {
-            // @ts-expect-error - bypassing TypeScript for testing
-            client: MockWebSocket,
-          },
-        },
-      });
-    });
-
-    afterEach(() => {
-      client.disconnect();
-    });
-
-    it("should send audio data correctly", () => {
-      const audioData = new ArrayBuffer(1024);
-      client.send(audioData);
-
-      expect(mockConnection.send).toHaveBeenCalledWith(audioData);
-    });
-
-    it("should send string data correctly", () => {
-      const textData = "test message";
-      client.send(textData);
-
-      expect(mockConnection.send).toHaveBeenCalledWith(textData);
-    });
-
-    it("should buffer messages when not connected", () => {
-      mockConnection.readyState = SOCKET_STATES.connecting;
-
-      const audioData = new ArrayBuffer(512);
-      client.send(audioData);
-
-      // Should not send immediately when not connected
-      expect(mockConnection.send).not.toHaveBeenCalled();
-    });
-
-    it("should send keepAlive messages", () => {
-      client.keepAlive();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "KeepAlive" }));
-    });
-
-    it("should send close stream requests", () => {
-      client.requestClose();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "CloseStream" }));
-    });
-
-    it("should use finish method (deprecated)", () => {
-      client.finish();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "CloseStream" }));
-    });
-  });
-
-  describe("SpeakLiveClient Specific Functionality", () => {
-    let client: SpeakLiveClient;
-    let mockConnection: any;
-
-    beforeEach(() => {
-      mockConnection = {
-        readyState: SOCKET_STATES.open,
-        send: jest.fn(),
-        close: jest.fn(),
-        onopen: null,
-        onclose: null,
-        onerror: null,
-        onmessage: null,
-      };
-
-      const MockWebSocket = jest.fn().mockImplementation(() => mockConnection);
-
-      client = new SpeakLiveClient({
-        key: "test-key",
-        global: {
-          websocket: {
-            // @ts-expect-error - bypassing TypeScript for testing
-            client: MockWebSocket,
-          },
-        },
-      });
-    });
-
-    afterEach(() => {
-      client.disconnect();
-    });
-
-    it("should send text for TTS synthesis", () => {
-      const text = "Hello, this is a test.";
-      client.sendText(text);
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "Speak", text }));
-    });
-
-    it("should send flush commands", () => {
-      client.flush();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "Flush" }));
-    });
-
-    it("should send clear commands", () => {
-      client.clear();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "Clear" }));
-    });
-
-    it("should send close requests", () => {
-      client.requestClose();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "Close" }));
-    });
-  });
-
-  describe("AgentLiveClient Specific Functionality", () => {
-    let client: AgentLiveClient;
-    let mockConnection: any;
-
-    beforeEach(() => {
-      mockConnection = {
-        readyState: SOCKET_STATES.open,
-        send: jest.fn(),
-        close: jest.fn(),
-        onopen: null,
-        onclose: null,
-        onerror: null,
-        onmessage: null,
-      };
-
-      const MockWebSocket = jest.fn().mockImplementation(() => mockConnection);
-
-      client = new AgentLiveClient({
-        key: "test-key",
-        global: {
-          websocket: {
-            // @ts-expect-error - bypassing TypeScript for testing
-            client: MockWebSocket,
-          },
-        },
-      });
-    });
-
-    afterEach(() => {
-      client.disconnect();
-    });
-
-    it("should send keepAlive messages", () => {
-      client.keepAlive();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "KeepAlive" }));
-    });
-
-    it("should send audio data", () => {
-      const audioData = new ArrayBuffer(1024);
-      client.send(audioData);
-
-      expect(mockConnection.send).toHaveBeenCalledWith(audioData);
-    });
-
-    it("should handle namespace correctly", () => {
-      expect(client.namespace).toBe("agent");
-    });
-  });
-
-  describe("Error Handling", () => {
-    let client: ListenLiveClient;
-    let mockConnection: any;
-
-    beforeEach(() => {
-      mockConnection = {
-        readyState: SOCKET_STATES.open,
-        send: jest.fn(),
-        close: jest.fn(),
-        onopen: null,
-        onclose: null,
-        onerror: null,
-        onmessage: null,
-      };
-
-      const MockWebSocket = jest.fn().mockImplementation(() => mockConnection);
-
-      client = new ListenLiveClient({
-        key: "test-key",
-        global: {
-          websocket: {
-            // @ts-expect-error - bypassing TypeScript for testing
-            client: MockWebSocket,
-          },
-        },
-      });
-
-      client.setupConnection();
-    });
-
-    afterEach(() => {
-      client.disconnect();
-    });
-
-    it("should handle empty blob data gracefully", async () => {
-      const logSpy = jest.spyOn(client as any, "log").mockImplementation();
-
-      const emptyBlob = new Blob([]);
-      client.send(emptyBlob);
-
-      // Wait for async blob processing
-      await new Promise((resolve) => setTimeout(resolve, 0));
-
-      expect(logSpy).toHaveBeenCalledWith("warn", "skipping `send` for zero-byte blob", emptyBlob);
-      expect(mockConnection.send).not.toHaveBeenCalled();
-
-      logSpy.mockRestore();
-    });
-
-    it("should handle zero-byte ArrayBuffer gracefully", () => {
-      const logSpy = jest.spyOn(client as any, "log").mockImplementation();
-
-      const emptyBuffer = new ArrayBuffer(0);
-      client.send(emptyBuffer);
-
-      expect(logSpy).toHaveBeenCalledWith(
-        "warn",
-        "skipping `send` for zero-byte payload",
-        emptyBuffer
-      );
-      expect(mockConnection.send).not.toHaveBeenCalled();
-
-      logSpy.mockRestore();
-    });
-
-    it("should handle connection errors gracefully", () => {
-      const errorSpy = jest.fn();
-      client.on(LiveTranscriptionEvents.Error, errorSpy);
-
-      const errorEvent = { type: "error", message: "Connection failed" };
-      mockConnection.onerror(errorEvent);
-
-      expect(errorSpy).toHaveBeenCalledWith(
-        expect.objectContaining({
-          type: "error",
-          message: expect.stringContaining("Connection failed"),
-          error: expect.any(Object),
-          readyState: expect.any(Number),
-        })
-      );
-    });
-  });
-});
diff --git a/tests/unit/live-client-message-handling.test.ts b/tests/unit/live-client-message-handling.test.ts
deleted file mode 100644
index a6af8b95..00000000
--- a/tests/unit/live-client-message-handling.test.ts
+++ /dev/null
@@ -1,686 +0,0 @@
-import { ListenLiveClient } from "../../src/packages/ListenLiveClient";
-import { SpeakLiveClient } from "../../src/packages/SpeakLiveClient";
-import { AgentLiveClient } from "../../src/packages/AgentLiveClient";
-import { LiveTranscriptionEvents } from "../../src/lib/enums/LiveTranscriptionEvents";
-import { LiveTTSEvents } from "../../src/lib/enums/LiveTTSEvents";
-import { AgentEvents } from "../../src/lib/enums/AgentEvents";
-import { SOCKET_STATES } from "../../src/lib/constants";
-
-describe("Unit Tests - Live Client Message Handling", () => {
-  describe("ListenLiveClient Message Handling", () => {
-    let client: ListenLiveClient;
-    let mockConnection: any;
-
-    beforeEach(() => {
-      // Mock the connection object
-      mockConnection = {
-        readyState: SOCKET_STATES.open,
-        send: jest.fn(),
-        close: jest.fn(),
-        onopen: null,
-        onclose: null,
-        onerror: null,
-        onmessage: null,
-      };
-
-      // Create a mock WebSocket constructor
-      const MockWebSocket = jest.fn().mockImplementation(() => mockConnection);
-
-      // Create client with minimal options
-      client = new ListenLiveClient({
-        key: "test-key",
-        global: {
-          websocket: {
-            client: MockWebSocket as any, // Use custom transport to avoid real connections
-          },
-        },
-      });
-
-      // The constructor already calls connect, so just setup the connection
-      client.setupConnection();
-    });
-
-    it("should emit Open event when connection opens", () => {
-      const openSpy = jest.fn();
-      client.on(LiveTranscriptionEvents.Open, openSpy);
-
-      // Simulate connection open
-      mockConnection.onopen();
-
-      expect(openSpy).toHaveBeenCalledWith(client);
-    });
-
-    it("should emit Close event when connection closes", () => {
-      const closeSpy = jest.fn();
-      const closeEvent = { code: 1000, reason: "Normal closure" };
-      client.on(LiveTranscriptionEvents.Close, closeSpy);
-
-      // Simulate connection close
-      mockConnection.onclose(closeEvent);
-
-      expect(closeSpy).toHaveBeenCalledWith(closeEvent);
-    });
-
-    it("should emit Error event when connection errors", () => {
-      const errorSpy = jest.fn();
-      const errorEvent = { type: "error", message: "Connection failed" };
-      client.on(LiveTranscriptionEvents.Error, errorSpy);
-
-      // Simulate connection error
-      mockConnection.onerror(errorEvent);
-
-      expect(errorSpy).toHaveBeenCalledWith(
-        expect.objectContaining({
-          type: "error",
-          message: expect.stringContaining("Connection failed"),
-          error: expect.any(Object),
-          readyState: expect.any(Number),
-        })
-      );
-    });
-
-    it("should handle Transcript messages correctly", () => {
-      const transcriptSpy = jest.fn();
-      client.on(LiveTranscriptionEvents.Transcript, transcriptSpy);
-
-      const transcriptData = {
-        type: "Results",
-        channel_index: [0, 1],
-        duration: 2.5,
-        start: 0.0,
-        is_final: true,
-        channel: {
-          alternatives: [
-            {
-              transcript: "Hello world",
-              confidence: 0.95,
-              words: [
-                { word: "Hello", start: 0.0, end: 0.5, confidence: 0.95 },
-                { word: "world", start: 0.6, end: 1.0, confidence: 0.94 },
-              ],
-            },
-          ],
-        },
-      };
-
-      // Simulate receiving transcript message
-      const messageEvent = { data: JSON.stringify(transcriptData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(transcriptSpy).toHaveBeenCalledWith(transcriptData);
-    });
-
-    it("should handle Metadata messages correctly", () => {
-      const metadataSpy = jest.fn();
-      client.on(LiveTranscriptionEvents.Metadata, metadataSpy);
-
-      const metadataData = {
-        type: "Metadata",
-        transaction_key: "deprecated",
-        request_id: "550e8400-e29b-41d4-a716-446655440002",
-        sha256: "abc123",
-        created: "2024-01-15T10:30:00Z",
-        duration: 120.5,
-        channels: 1,
-      };
-
-      // Simulate receiving metadata message
-      const messageEvent = { data: JSON.stringify(metadataData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(metadataSpy).toHaveBeenCalledWith(metadataData);
-    });
-
-    it("should handle UtteranceEnd messages correctly", () => {
-      const utteranceEndSpy = jest.fn();
-      client.on(LiveTranscriptionEvents.UtteranceEnd, utteranceEndSpy);
-
-      const utteranceEndData = {
-        type: "UtteranceEnd",
-        channel: [0],
-        last_word_end: 2.5,
-      };
-
-      // Simulate receiving utterance end message
-      const messageEvent = { data: JSON.stringify(utteranceEndData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(utteranceEndSpy).toHaveBeenCalledWith(utteranceEndData);
-    });
-
-    it("should handle SpeechStarted messages correctly", () => {
-      const speechStartedSpy = jest.fn();
-      client.on(LiveTranscriptionEvents.SpeechStarted, speechStartedSpy);
-
-      const speechStartedData = {
-        type: "SpeechStarted",
-        channel: [0],
-        timestamp: 1.2,
-      };
-
-      // Simulate receiving speech started message
-      const messageEvent = { data: JSON.stringify(speechStartedData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(speechStartedSpy).toHaveBeenCalledWith(speechStartedData);
-    });
-
-    it("should emit Unhandled event for unknown message types", () => {
-      const unhandledSpy = jest.fn();
-      client.on(LiveTranscriptionEvents.Unhandled, unhandledSpy);
-
-      const unknownData = {
-        type: "UnknownMessageType",
-        data: "some data",
-      };
-
-      // Simulate receiving unknown message
-      const messageEvent = { data: JSON.stringify(unknownData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(unhandledSpy).toHaveBeenCalledWith(unknownData);
-    });
-
-    it("should emit Error event for malformed JSON messages", () => {
-      const errorSpy = jest.fn();
-      client.on(LiveTranscriptionEvents.Error, errorSpy);
-
-      // Simulate receiving malformed JSON
-      const messageEvent = { data: "invalid json {" };
-      mockConnection.onmessage(messageEvent);
-
-      expect(errorSpy).toHaveBeenCalledWith(
-        expect.objectContaining({
-          event: messageEvent,
-          message: "Unable to parse `data` as JSON.",
-          error: expect.any(Error),
-        })
-      );
-    });
-
-    it("should send keepAlive message correctly", () => {
-      client.keepAlive();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "KeepAlive" }));
-    });
-
-    it("should send requestClose message correctly", () => {
-      client.requestClose();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "CloseStream" }));
-    });
-  });
-
-  describe("SpeakLiveClient Message Handling", () => {
-    let client: SpeakLiveClient;
-    let mockConnection: any;
-
-    beforeEach(() => {
-      // Mock the connection object
-      mockConnection = {
-        readyState: SOCKET_STATES.open,
-        send: jest.fn(),
-        close: jest.fn(),
-        onopen: null,
-        onclose: null,
-        onerror: null,
-        onmessage: null,
-      };
-
-      // Create a mock WebSocket constructor
-      const MockWebSocket = jest.fn().mockImplementation(() => mockConnection);
-
-      // Create client with minimal options
-      client = new SpeakLiveClient({
-        key: "test-key",
-        global: {
-          websocket: {
-            client: MockWebSocket as any, // Use custom transport to avoid real connections
-          },
-        },
-      });
-
-      // The constructor already calls connect, so just setup the connection
-      client.setupConnection();
-    });
-
-    it("should emit Open event when connection opens", () => {
-      const openSpy = jest.fn();
-      client.on(LiveTTSEvents.Open, openSpy);
-
-      // Simulate connection open
-      mockConnection.onopen();
-
-      expect(openSpy).toHaveBeenCalledWith(client);
-    });
-
-    it("should handle Metadata messages correctly", () => {
-      const metadataSpy = jest.fn();
-      client.on(LiveTTSEvents.Metadata, metadataSpy);
-
-      const metadataData = {
-        type: "Metadata",
-        request_id: "550e8400-e29b-41d4-a716-446655440003",
-        model_name: "aura-asteria-en",
-        model_uuid: "c0e51fb0-7b76-42f0-b8c0-8ad7a14fb5b5",
-        char_count: 25,
-        transfer_encoding: "chunked",
-        date: "Thu, 15 Aug 2024 17:22:02 GMT",
-      };
-
-      // Simulate receiving metadata message
-      const messageEvent = { data: JSON.stringify(metadataData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(metadataSpy).toHaveBeenCalledWith(metadataData);
-    });
-
-    it("should handle Flushed messages correctly", () => {
-      const flushedSpy = jest.fn();
-      client.on(LiveTTSEvents.Flushed, flushedSpy);
-
-      const flushedData = {
-        type: "Flushed",
-      };
-
-      // Simulate receiving flushed message
-      const messageEvent = { data: JSON.stringify(flushedData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(flushedSpy).toHaveBeenCalledWith(flushedData);
-    });
-
-    it("should handle Warning messages correctly", () => {
-      const warningSpy = jest.fn();
-      client.on(LiveTTSEvents.Warning, warningSpy);
-
-      const warningData = {
-        type: "Warning",
-        warn_code: "W001",
-        warn_msg: "Sample warning message",
-      };
-
-      // Simulate receiving warning message
-      const messageEvent = { data: JSON.stringify(warningData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(warningSpy).toHaveBeenCalledWith(warningData);
-    });
-
-    it("should handle binary audio data correctly", () => {
-      const audioSpy = jest.fn();
-      client.on(LiveTTSEvents.Audio, audioSpy);
-
-      const audioBuffer = new ArrayBuffer(1024);
-      const messageEvent = { data: audioBuffer };
-      mockConnection.onmessage(messageEvent);
-
-      expect(audioSpy).toHaveBeenCalledWith(Buffer.from(audioBuffer));
-    });
-
-    it("should handle Blob audio data correctly", () => {
-      const audioSpy = jest.fn();
-      client.on(LiveTTSEvents.Audio, audioSpy);
-
-      const audioData = new Uint8Array([1, 2, 3, 4]);
-      const blob = new Blob([audioData]);
-
-      // Mock blob.arrayBuffer()
-      blob.arrayBuffer = jest.fn().mockResolvedValue(audioData.buffer);
-
-      const messageEvent = { data: blob };
-      mockConnection.onmessage(messageEvent);
-
-      // Wait for async arrayBuffer processing
-      return new Promise((resolve) => {
-        setTimeout(() => {
-          expect(audioSpy).toHaveBeenCalledWith(Buffer.from(audioData.buffer));
-          resolve(undefined);
-        }, 0);
-      });
-    });
-
-    it("should emit Unhandled event for unknown message types", () => {
-      const unhandledSpy = jest.fn();
-      client.on(LiveTTSEvents.Unhandled, unhandledSpy);
-
-      const unknownData = {
-        type: "UnknownMessageType",
-        data: "some data",
-      };
-
-      // Simulate receiving unknown message
-      const messageEvent = { data: JSON.stringify(unknownData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(unhandledSpy).toHaveBeenCalledWith(unknownData);
-    });
-
-    it("should send text correctly", () => {
-      const text = "Hello, this is a test message.";
-      client.sendText(text);
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "Speak", text }));
-    });
-
-    it("should send flush correctly", () => {
-      client.flush();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "Flush" }));
-    });
-  });
-
-  describe("AgentLiveClient Message Handling", () => {
-    let client: AgentLiveClient;
-    let mockConnection: any;
-
-    beforeEach(() => {
-      // Mock the connection object
-      mockConnection = {
-        readyState: SOCKET_STATES.open,
-        send: jest.fn(),
-        close: jest.fn(),
-        onopen: null,
-        onclose: null,
-        onerror: null,
-        onmessage: null,
-      };
-
-      // Create a mock WebSocket constructor
-      const MockWebSocket = jest.fn().mockImplementation(() => mockConnection);
-
-      // Create client with minimal options
-      client = new AgentLiveClient({
-        key: "test-key",
-        global: {
-          websocket: {
-            client: MockWebSocket as any, // Use custom transport to avoid real connections
-          },
-        },
-      });
-
-      // The constructor already calls connect, so just setup the connection
-      client.setupConnection();
-    });
-
-    it("should emit Open event when connection opens", () => {
-      const openSpy = jest.fn();
-      client.on(AgentEvents.Open, openSpy);
-
-      // Simulate connection open
-      mockConnection.onopen();
-
-      expect(openSpy).toHaveBeenCalledWith(client);
-    });
-
-    it("should handle Welcome messages correctly", () => {
-      const welcomeSpy = jest.fn();
-      client.on(AgentEvents.Welcome, welcomeSpy);
-
-      const welcomeData = {
-        type: "Welcome",
-        request_id: "550e8400-e29b-41d4-a716-446655440004",
-      };
-
-      // Simulate receiving welcome message
-      const messageEvent = { data: JSON.stringify(welcomeData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(welcomeSpy).toHaveBeenCalledWith(welcomeData);
-    });
-
-    it("should handle ConversationText messages correctly", () => {
-      const conversationTextSpy = jest.fn();
-      client.on(AgentEvents.ConversationText, conversationTextSpy);
-
-      const conversationTextData = {
-        type: "ConversationText",
-        role: "user",
-        content: "Hello, how are you?",
-      };
-
-      // Simulate receiving conversation text message
-      const messageEvent = { data: JSON.stringify(conversationTextData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(conversationTextSpy).toHaveBeenCalledWith(conversationTextData);
-    });
-
-    it("should handle FunctionCallRequest messages correctly", () => {
-      const functionCallSpy = jest.fn();
-      client.on(AgentEvents.FunctionCallRequest, functionCallSpy);
-
-      const functionCallData = {
-        type: "FunctionCallRequest",
-        functions: [
-          {
-            id: "function-1",
-            name: "get_weather",
-            arguments: '{"location": "New York"}',
-            client_side: true,
-          },
-        ],
-      };
-
-      // Simulate receiving function call request
-      const messageEvent = { data: JSON.stringify(functionCallData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(functionCallSpy).toHaveBeenCalledWith(functionCallData);
-    });
-
-    it("should handle AgentStartedSpeaking messages correctly", () => {
-      const agentStartedSpy = jest.fn();
-      client.on(AgentEvents.AgentStartedSpeaking, agentStartedSpy);
-
-      const agentStartedData = {
-        type: "AgentStartedSpeaking",
-        total_latency: 250,
-        tts_latency: 100,
-        ttt_latency: 150,
-      };
-
-      // Simulate receiving agent started speaking message
-      const messageEvent = { data: JSON.stringify(agentStartedData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(agentStartedSpy).toHaveBeenCalledWith(agentStartedData);
-    });
-
-    it("should handle binary audio data correctly", () => {
-      const audioSpy = jest.fn();
-      client.on(AgentEvents.Audio, audioSpy);
-
-      const audioBuffer = new ArrayBuffer(2048);
-      const messageEvent = { data: audioBuffer };
-      mockConnection.onmessage(messageEvent);
-
-      expect(audioSpy).toHaveBeenCalledWith(Buffer.from(audioBuffer));
-    });
-
-    it("should emit Unhandled event for unknown message types", () => {
-      const unhandledSpy = jest.fn();
-      client.on(AgentEvents.Unhandled, unhandledSpy);
-
-      const unknownData = {
-        type: "UnknownMessageType",
-        data: "some data",
-      };
-
-      // Simulate receiving unknown message
-      const messageEvent = { data: JSON.stringify(unknownData) };
-      mockConnection.onmessage(messageEvent);
-
-      expect(unhandledSpy).toHaveBeenCalledWith(unknownData);
-    });
-
-    it("should handle messages with unknown data types correctly", () => {
-      const errorSpy = jest.fn();
-      client.on(AgentEvents.Error, errorSpy);
-
-      // Simulate receiving message with unknown data type
-      const unknownDataType = { some: "weird data type" };
-      const messageEvent = { data: unknownDataType };
-      mockConnection.onmessage(messageEvent);
-
-      expect(errorSpy).toHaveBeenCalledWith(
-        expect.objectContaining({
-          event: messageEvent,
-          message: "Received unknown data type.",
-        })
-      );
-    });
-
-    it("should send keepAlive message correctly", () => {
-      client.keepAlive();
-
-      expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "KeepAlive" }));
-    });
-
-    describe("speak provider configuration", () => {
-      it("should accept single provider", () => {
-        const config = {
-          audio: { input: { encoding: "linear16", sample_rate: 16000 } },
-          agent: {
-            speak: {
-              provider: { type: "deepgram", model: "aura-2-zeus-en" },
-            },
-          },
-        };
-
-        client.configure(config);
-        expect(mockConnection.send).toHaveBeenCalledWith(
-          JSON.stringify({ type: "Settings", ...config })
-        );
-      });
-
-      it("should accept array of providers", () => {
-        const config = {
-          audio: { input: { encoding: "linear16", sample_rate: 16000 } },
-          agent: {
-            speak: [
-              { provider: { type: "deepgram", model: "aura-2-zeus-en" } },
-              {
-                provider: { type: "openai", model: "tts-1", voice: "shimmer" },
-                endpoint: { url: "https://api.openai.com/v1/audio/speech", headers: { auth: "key" } }
-              },
-            ],
-          },
-        };
-
-        client.configure(config);
-        expect(mockConnection.send).toHaveBeenCalledWith(
-          JSON.stringify({ type: "Settings", ...config })
-        );
-      });
-    });
-
-    describe("mips_opt_out configuration", () => {
-      it("should accept mips_opt_out as true", () => {
-        const config = {
-          audio: { input: { encoding: "linear16", sample_rate: 16000 } },
-          mips_opt_out: true,
-          agent: {
-            language: "en",
-            speak: {
-              provider: { type: "deepgram", model: "aura-2-zeus-en" },
-            },
-          },
-        };
-
-        client.configure(config);
-        expect(mockConnection.send).toHaveBeenCalledWith(
-          JSON.stringify({ type: "Settings", ...config })
-        );
-      });
-
-      it("should accept mips_opt_out as false", () => {
-        const config = {
-          audio: { input: { encoding: "linear16", sample_rate: 16000 } },
-          mips_opt_out: false,
-          agent: {
-            language: "en",
-            speak: {
-              provider: { type: "deepgram", model: "aura-2-zeus-en" },
-            },
-          },
-        };
-
-        client.configure(config);
-        expect(mockConnection.send).toHaveBeenCalledWith(
-          JSON.stringify({ type: "Settings", ...config })
-        );
-      });
-
-      it("should work without mips_opt_out (default behavior)", () => {
-        const config = {
-          audio: { input: { encoding: "linear16", sample_rate: 16000 } },
-          agent: {
-            language: "en",
-            speak: {
-              provider: { type: "deepgram", model: "aura-2-zeus-en" },
-            },
-          },
-        };
-
-        client.configure(config);
-        expect(mockConnection.send).toHaveBeenCalledWith(
-          JSON.stringify({ type: "Settings", ...config })
-        );
-      });
-    });
-
-    describe("updateSpeak method", () => {
-      it("should update with single provider", () => {
-        const provider = { provider: { type: "deepgram", model: "aura-2-zeus-en" } };
-
-        client.updateSpeak(provider);
-        expect(mockConnection.send).toHaveBeenCalledWith(
-          JSON.stringify({ type: "UpdateSpeak", speak: provider })
-        );
-      });
-
-      it("should update with array of providers", () => {
-        const providers = [
-          { provider: { type: "deepgram", model: "aura-2-zeus-en" } },
-          { provider: { type: "openai", model: "tts-1", voice: "shimmer" } },
-        ];
-
-        client.updateSpeak(providers);
-        expect(mockConnection.send).toHaveBeenCalledWith(
-          JSON.stringify({ type: "UpdateSpeak", speak: providers })
-        );
-      });
-    });
-
-    describe("injectUserMessage method", () => {
-      it("should send injectUserMessage correctly", () => {
-        const content = "Hello! Can you hear me?";
-        client.injectUserMessage(content);
-
-        expect(mockConnection.send).toHaveBeenCalledWith(
-          JSON.stringify({ type: "InjectUserMessage", content })
-        );
-      });
-
-      it("should send injectUserMessage with different content types", () => {
-        const testCases = [
-          "What's the weather like today?",
-          "Simple greeting",
-          "Multi-line\nmessage content",
-          "", // Edge case: empty string
-        ];
-
-        testCases.forEach((content) => {
-          jest.clearAllMocks(); // Reset mock between test cases
-
-          client.injectUserMessage(content);
-
-          expect(mockConnection.send).toHaveBeenCalledWith(
-            JSON.stringify({ type: "InjectUserMessage", content })
-          );
-        });
-      });
-    });
-  });
-});
diff --git a/tests/unit/logging/logger.test.ts b/tests/unit/logging/logger.test.ts
new file mode 100644
index 00000000..2e0b5fe5
--- /dev/null
+++ b/tests/unit/logging/logger.test.ts
@@ -0,0 +1,454 @@
+import { ConsoleLogger, createLogger, Logger, LogLevel } from "../../../src/core/logging/logger";
+
+function createMockLogger() {
+    return {
+        debug: vi.fn(),
+        info: vi.fn(),
+        warn: vi.fn(),
+        error: vi.fn(),
+    };
+}
+
+describe("Logger", () => {
+    describe("LogLevel", () => {
+        it("should have correct log levels", () => {
+            expect(LogLevel.Debug).toBe("debug");
+            expect(LogLevel.Info).toBe("info");
+            expect(LogLevel.Warn).toBe("warn");
+            expect(LogLevel.Error).toBe("error");
+        });
+    });
+
+    describe("ConsoleLogger", () => {
+        let consoleLogger: ConsoleLogger;
+        let consoleSpy: {
+            debug: ReturnType;
+            info: ReturnType;
+            warn: ReturnType;
+            error: ReturnType;
+        };
+
+        beforeEach(() => {
+            consoleLogger = new ConsoleLogger();
+            consoleSpy = {
+                debug: vi.spyOn(console, "debug").mockImplementation(() => {}),
+                info: vi.spyOn(console, "info").mockImplementation(() => {}),
+                warn: vi.spyOn(console, "warn").mockImplementation(() => {}),
+                error: vi.spyOn(console, "error").mockImplementation(() => {}),
+            };
+        });
+
+        afterEach(() => {
+            consoleSpy.debug.mockRestore();
+            consoleSpy.info.mockRestore();
+            consoleSpy.warn.mockRestore();
+            consoleSpy.error.mockRestore();
+        });
+
+        it("should log debug messages", () => {
+            consoleLogger.debug("debug message", { data: "test" });
+            expect(consoleSpy.debug).toHaveBeenCalledWith("debug message", { data: "test" });
+        });
+
+        it("should log info messages", () => {
+            consoleLogger.info("info message", { data: "test" });
+            expect(consoleSpy.info).toHaveBeenCalledWith("info message", { data: "test" });
+        });
+
+        it("should log warn messages", () => {
+            consoleLogger.warn("warn message", { data: "test" });
+            expect(consoleSpy.warn).toHaveBeenCalledWith("warn message", { data: "test" });
+        });
+
+        it("should log error messages", () => {
+            consoleLogger.error("error message", { data: "test" });
+            expect(consoleSpy.error).toHaveBeenCalledWith("error message", { data: "test" });
+        });
+
+        it("should handle multiple arguments", () => {
+            consoleLogger.debug("message", "arg1", "arg2", { key: "value" });
+            expect(consoleSpy.debug).toHaveBeenCalledWith("message", "arg1", "arg2", { key: "value" });
+        });
+    });
+
+    describe("Logger with level filtering", () => {
+        let mockLogger: {
+            debug: ReturnType;
+            info: ReturnType;
+            warn: ReturnType;
+            error: ReturnType;
+        };
+
+        beforeEach(() => {
+            mockLogger = createMockLogger();
+        });
+
+        describe("Debug level", () => {
+            it("should log all levels when set to debug", () => {
+                const logger = new Logger({
+                    level: LogLevel.Debug,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                logger.debug("debug");
+                logger.info("info");
+                logger.warn("warn");
+                logger.error("error");
+
+                expect(mockLogger.debug).toHaveBeenCalledWith("debug");
+                expect(mockLogger.info).toHaveBeenCalledWith("info");
+                expect(mockLogger.warn).toHaveBeenCalledWith("warn");
+                expect(mockLogger.error).toHaveBeenCalledWith("error");
+            });
+
+            it("should report correct level checks", () => {
+                const logger = new Logger({
+                    level: LogLevel.Debug,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                expect(logger.isDebug()).toBe(true);
+                expect(logger.isInfo()).toBe(true);
+                expect(logger.isWarn()).toBe(true);
+                expect(logger.isError()).toBe(true);
+            });
+        });
+
+        describe("Info level", () => {
+            it("should log info, warn, and error when set to info", () => {
+                const logger = new Logger({
+                    level: LogLevel.Info,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                logger.debug("debug");
+                logger.info("info");
+                logger.warn("warn");
+                logger.error("error");
+
+                expect(mockLogger.debug).not.toHaveBeenCalled();
+                expect(mockLogger.info).toHaveBeenCalledWith("info");
+                expect(mockLogger.warn).toHaveBeenCalledWith("warn");
+                expect(mockLogger.error).toHaveBeenCalledWith("error");
+            });
+
+            it("should report correct level checks", () => {
+                const logger = new Logger({
+                    level: LogLevel.Info,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                expect(logger.isDebug()).toBe(false);
+                expect(logger.isInfo()).toBe(true);
+                expect(logger.isWarn()).toBe(true);
+                expect(logger.isError()).toBe(true);
+            });
+        });
+
+        describe("Warn level", () => {
+            it("should log warn and error when set to warn", () => {
+                const logger = new Logger({
+                    level: LogLevel.Warn,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                logger.debug("debug");
+                logger.info("info");
+                logger.warn("warn");
+                logger.error("error");
+
+                expect(mockLogger.debug).not.toHaveBeenCalled();
+                expect(mockLogger.info).not.toHaveBeenCalled();
+                expect(mockLogger.warn).toHaveBeenCalledWith("warn");
+                expect(mockLogger.error).toHaveBeenCalledWith("error");
+            });
+
+            it("should report correct level checks", () => {
+                const logger = new Logger({
+                    level: LogLevel.Warn,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                expect(logger.isDebug()).toBe(false);
+                expect(logger.isInfo()).toBe(false);
+                expect(logger.isWarn()).toBe(true);
+                expect(logger.isError()).toBe(true);
+            });
+        });
+
+        describe("Error level", () => {
+            it("should only log error when set to error", () => {
+                const logger = new Logger({
+                    level: LogLevel.Error,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                logger.debug("debug");
+                logger.info("info");
+                logger.warn("warn");
+                logger.error("error");
+
+                expect(mockLogger.debug).not.toHaveBeenCalled();
+                expect(mockLogger.info).not.toHaveBeenCalled();
+                expect(mockLogger.warn).not.toHaveBeenCalled();
+                expect(mockLogger.error).toHaveBeenCalledWith("error");
+            });
+
+            it("should report correct level checks", () => {
+                const logger = new Logger({
+                    level: LogLevel.Error,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                expect(logger.isDebug()).toBe(false);
+                expect(logger.isInfo()).toBe(false);
+                expect(logger.isWarn()).toBe(false);
+                expect(logger.isError()).toBe(true);
+            });
+        });
+
+        describe("Silent mode", () => {
+            it("should not log anything when silent is true", () => {
+                const logger = new Logger({
+                    level: LogLevel.Debug,
+                    logger: mockLogger,
+                    silent: true,
+                });
+
+                logger.debug("debug");
+                logger.info("info");
+                logger.warn("warn");
+                logger.error("error");
+
+                expect(mockLogger.debug).not.toHaveBeenCalled();
+                expect(mockLogger.info).not.toHaveBeenCalled();
+                expect(mockLogger.warn).not.toHaveBeenCalled();
+                expect(mockLogger.error).not.toHaveBeenCalled();
+            });
+
+            it("should report all level checks as false when silent", () => {
+                const logger = new Logger({
+                    level: LogLevel.Debug,
+                    logger: mockLogger,
+                    silent: true,
+                });
+
+                expect(logger.isDebug()).toBe(false);
+                expect(logger.isInfo()).toBe(false);
+                expect(logger.isWarn()).toBe(false);
+                expect(logger.isError()).toBe(false);
+            });
+        });
+
+        describe("shouldLog", () => {
+            it("should correctly determine if level should be logged", () => {
+                const logger = new Logger({
+                    level: LogLevel.Info,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                expect(logger.shouldLog(LogLevel.Debug)).toBe(false);
+                expect(logger.shouldLog(LogLevel.Info)).toBe(true);
+                expect(logger.shouldLog(LogLevel.Warn)).toBe(true);
+                expect(logger.shouldLog(LogLevel.Error)).toBe(true);
+            });
+
+            it("should return false for all levels when silent", () => {
+                const logger = new Logger({
+                    level: LogLevel.Debug,
+                    logger: mockLogger,
+                    silent: true,
+                });
+
+                expect(logger.shouldLog(LogLevel.Debug)).toBe(false);
+                expect(logger.shouldLog(LogLevel.Info)).toBe(false);
+                expect(logger.shouldLog(LogLevel.Warn)).toBe(false);
+                expect(logger.shouldLog(LogLevel.Error)).toBe(false);
+            });
+        });
+
+        describe("Multiple arguments", () => {
+            it("should pass multiple arguments to logger", () => {
+                const logger = new Logger({
+                    level: LogLevel.Debug,
+                    logger: mockLogger,
+                    silent: false,
+                });
+
+                logger.debug("message", "arg1", { key: "value" }, 123);
+                expect(mockLogger.debug).toHaveBeenCalledWith("message", "arg1", { key: "value" }, 123);
+            });
+        });
+    });
+
+    describe("createLogger", () => {
+        it("should return default logger when no config provided", () => {
+            const logger = createLogger();
+            expect(logger).toBeInstanceOf(Logger);
+        });
+
+        it("should return same logger instance when Logger is passed", () => {
+            const customLogger = new Logger({
+                level: LogLevel.Debug,
+                logger: new ConsoleLogger(),
+                silent: false,
+            });
+
+            const result = createLogger(customLogger);
+            expect(result).toBe(customLogger);
+        });
+
+        it("should create logger with custom config", () => {
+            const mockLogger = createMockLogger();
+
+            const logger = createLogger({
+                level: LogLevel.Warn,
+                logger: mockLogger,
+                silent: false,
+            });
+
+            expect(logger).toBeInstanceOf(Logger);
+            logger.warn("test");
+            expect(mockLogger.warn).toHaveBeenCalledWith("test");
+        });
+
+        it("should use default values for missing config", () => {
+            const logger = createLogger({});
+            expect(logger).toBeInstanceOf(Logger);
+        });
+
+        it("should override default level", () => {
+            const mockLogger = createMockLogger();
+
+            const logger = createLogger({
+                level: LogLevel.Debug,
+                logger: mockLogger,
+                silent: false,
+            });
+
+            logger.debug("test");
+            expect(mockLogger.debug).toHaveBeenCalledWith("test");
+        });
+
+        it("should override default silent mode", () => {
+            const mockLogger = createMockLogger();
+
+            const logger = createLogger({
+                logger: mockLogger,
+                silent: false,
+            });
+
+            logger.info("test");
+            expect(mockLogger.info).toHaveBeenCalledWith("test");
+        });
+
+        it("should use provided logger implementation", () => {
+            const customLogger = createMockLogger();
+
+            const logger = createLogger({
+                logger: customLogger,
+                level: LogLevel.Debug,
+                silent: false,
+            });
+
+            logger.debug("test");
+            expect(customLogger.debug).toHaveBeenCalledWith("test");
+        });
+
+        it("should default to silent: true", () => {
+            const mockLogger = createMockLogger();
+
+            const logger = createLogger({
+                logger: mockLogger,
+                level: LogLevel.Debug,
+            });
+
+            logger.debug("test");
+            expect(mockLogger.debug).not.toHaveBeenCalled();
+        });
+    });
+
+    describe("Default logger", () => {
+        it("should have silent: true by default", () => {
+            const logger = createLogger();
+            expect(logger.shouldLog(LogLevel.Info)).toBe(false);
+        });
+
+        it("should not log when using default logger", () => {
+            const logger = createLogger();
+
+            logger.info("test");
+            expect(logger.isInfo()).toBe(false);
+        });
+    });
+
+    describe("Edge cases", () => {
+        it("should handle empty message", () => {
+            const mockLogger = createMockLogger();
+
+            const logger = new Logger({
+                level: LogLevel.Debug,
+                logger: mockLogger,
+                silent: false,
+            });
+
+            logger.debug("");
+            expect(mockLogger.debug).toHaveBeenCalledWith("");
+        });
+
+        it("should handle no arguments", () => {
+            const mockLogger = createMockLogger();
+
+            const logger = new Logger({
+                level: LogLevel.Debug,
+                logger: mockLogger,
+                silent: false,
+            });
+
+            logger.debug("message");
+            expect(mockLogger.debug).toHaveBeenCalledWith("message");
+        });
+
+        it("should handle complex objects", () => {
+            const mockLogger = createMockLogger();
+
+            const logger = new Logger({
+                level: LogLevel.Debug,
+                logger: mockLogger,
+                silent: false,
+            });
+
+            const complexObject = {
+                nested: { key: "value" },
+                array: [1, 2, 3],
+                fn: () => "test",
+            };
+
+            logger.debug("message", complexObject);
+            expect(mockLogger.debug).toHaveBeenCalledWith("message", complexObject);
+        });
+
+        it("should handle errors as arguments", () => {
+            const mockLogger = createMockLogger();
+
+            const logger = new Logger({
+                level: LogLevel.Error,
+                logger: mockLogger,
+                silent: false,
+            });
+
+            const error = new Error("Test error");
+            logger.error("Error occurred", error);
+            expect(mockLogger.error).toHaveBeenCalledWith("Error occurred", error);
+        });
+    });
+});
diff --git a/tests/unit/object-utilities.test.ts b/tests/unit/object-utilities.test.ts
deleted file mode 100644
index 8e8f3ebf..00000000
--- a/tests/unit/object-utilities.test.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-import { applyDefaults, appendSearchParams } from "../../src/lib/helpers";
-
-describe("Unit Tests - Object Manipulation Utilities", () => {
-  describe("applyDefaults", () => {
-    it("should merge options with defaults correctly", () => {
-      const defaults = { punctuate: true, smart_format: false, language: "en-US" };
-      const options = { language: "es-ES", model: "nova-2" };
-
-      const result = applyDefaults(options, defaults) as any;
-
-      // Options should override defaults
-      expect(result.language).toBe("es-ES");
-      expect(result.model).toBe("nova-2");
-
-      // Defaults should be preserved when not overridden
-      expect(result.punctuate).toBe(true);
-      expect(result.smart_format).toBe(false);
-    });
-
-    it("should handle empty options", () => {
-      const defaults = { punctuate: true, smart_format: false };
-      const result = applyDefaults({}, defaults);
-
-      expect(result).toEqual(defaults);
-    });
-
-    it("should handle empty defaults", () => {
-      const options = { language: "en-US", model: "nova-2" };
-      const result = applyDefaults(options, {});
-
-      expect(result).toEqual(options);
-    });
-
-    it("should handle nested objects", () => {
-      const defaults = {
-        nested: { deep: "default", other: "property" },
-        simple: "value",
-      };
-      const options = {
-        nested: { deep: "override" },
-        new: "property",
-      };
-
-      const result = applyDefaults(options, defaults) as any;
-
-      expect(result.nested.deep).toBe("override");
-      expect(result.nested.other).toBe("property");
-      expect(result.simple).toBe("value");
-      expect(result.new).toBe("property");
-    });
-
-    it("should handle undefined inputs", () => {
-      const defaults = { punctuate: true };
-
-      const result1 = applyDefaults(undefined, defaults);
-      expect(result1).toEqual(defaults);
-
-      const result2 = applyDefaults({ language: "en" }, undefined);
-      expect(result2).toEqual({ language: "en" });
-    });
-  });
-
-  describe("appendSearchParams", () => {
-    it("should handle string parameters", () => {
-      const searchParams = new URLSearchParams();
-      appendSearchParams(searchParams, { language: "en-US", model: "nova-2" });
-
-      expect(searchParams.get("language")).toBe("en-US");
-      expect(searchParams.get("model")).toBe("nova-2");
-    });
-
-    it("should handle boolean parameters", () => {
-      const searchParams = new URLSearchParams();
-      appendSearchParams(searchParams, { punctuate: true, smart_format: false });
-
-      expect(searchParams.get("punctuate")).toBe("true");
-      expect(searchParams.get("smart_format")).toBe("false");
-    });
-
-    it("should handle number parameters", () => {
-      const searchParams = new URLSearchParams();
-      appendSearchParams(searchParams, { confidence: 0.8, alternatives: 3 });
-
-      expect(searchParams.get("confidence")).toBe("0.8");
-      expect(searchParams.get("alternatives")).toBe("3");
-    });
-
-    it("should handle array parameters", () => {
-      const searchParams = new URLSearchParams();
-      appendSearchParams(searchParams, { keywords: ["hello", "world", "test"] });
-
-      const keywords = searchParams.getAll("keywords");
-      expect(keywords).toEqual(["hello", "world", "test"]);
-    });
-
-    it("should handle mixed parameter types", () => {
-      const searchParams = new URLSearchParams();
-      const options = {
-        keywords: ["hello", "world"],
-        language: "en-US",
-        punctuate: true,
-        confidence: 0.9,
-      };
-
-      appendSearchParams(searchParams, options);
-
-      expect(searchParams.getAll("keywords")).toEqual(["hello", "world"]);
-      expect(searchParams.get("language")).toBe("en-US");
-      expect(searchParams.get("punctuate")).toBe("true");
-      expect(searchParams.get("confidence")).toBe("0.9");
-    });
-
-    it("should handle empty options", () => {
-      const searchParams = new URLSearchParams();
-      appendSearchParams(searchParams, {});
-
-      expect(searchParams.toString()).toBe("");
-    });
-  });
-});
diff --git a/tests/unit/options-transformation.test.ts b/tests/unit/options-transformation.test.ts
deleted file mode 100644
index c97306a2..00000000
--- a/tests/unit/options-transformation.test.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { convertLegacyOptions } from "../../src/lib/helpers";
-
-describe("Unit Tests - Options Transformation Utilities", () => {
-  describe("convertLegacyOptions", () => {
-    it("should convert _experimentalCustomFetch to global.fetch.client", () => {
-      const customFetch = jest.fn();
-      const options = { _experimentalCustomFetch: customFetch };
-
-      const result = convertLegacyOptions(options as any);
-
-      expect(result.global?.fetch?.client).toBe(customFetch);
-    });
-
-    it("should convert restProxy.url to global.fetch.options.proxy.url", () => {
-      const options = { restProxy: { url: "https://proxy.example.com" } };
-
-      const result = convertLegacyOptions(options as any);
-
-      expect(result.global?.fetch?.options?.proxy?.url).toBe("https://proxy.example.com");
-    });
-
-    it("should convert global.url to both fetch and websocket options", () => {
-      const options = { global: { url: "https://custom-api.deepgram.com" } };
-
-      const result = convertLegacyOptions(options);
-
-      expect(result.global?.fetch?.options?.url).toBe("https://custom-api.deepgram.com");
-      expect(result.global?.websocket?.options?.url).toBe("https://custom-api.deepgram.com");
-    });
-
-    it("should convert global.headers to both fetch and websocket options", () => {
-      const customHeaders = { "Custom-Header": "value", Another: "header" };
-      const options = { global: { headers: customHeaders } };
-
-      const result = convertLegacyOptions(options);
-
-      expect(result.global?.fetch?.options?.headers).toEqual(customHeaders);
-      expect(result.global?.websocket?.options?._nodeOnlyHeaders).toEqual(customHeaders);
-    });
-
-    it("should handle combined legacy options", () => {
-      const customFetch = jest.fn();
-      const customHeaders = { "X-Custom": "header" };
-      const options = {
-        _experimentalCustomFetch: customFetch,
-        restProxy: { url: "https://proxy.example.com" },
-        global: {
-          url: "https://custom-api.deepgram.com",
-          headers: customHeaders,
-        },
-      };
-
-      const result = convertLegacyOptions(options as any);
-
-      // Should have all conversions
-      expect(result.global?.fetch?.client).toBe(customFetch);
-      expect(result.global?.fetch?.options?.proxy?.url).toBe("https://proxy.example.com");
-      expect(result.global?.fetch?.options?.url).toBe("https://custom-api.deepgram.com");
-      expect(result.global?.fetch?.options?.headers).toEqual(customHeaders);
-      expect(result.global?.websocket?.options?.url).toBe("https://custom-api.deepgram.com");
-      expect(result.global?.websocket?.options?._nodeOnlyHeaders).toEqual(customHeaders);
-    });
-
-    it("should return empty object when no legacy options provided", () => {
-      const result = convertLegacyOptions({});
-
-      // Should have some structure from the merge operations
-      expect(typeof result).toBe("object");
-    });
-
-    it("should preserve existing options", () => {
-      const existingOptions = {
-        global: {
-          fetch: {
-            options: {
-              url: "https://existing.com",
-            },
-          },
-        },
-      };
-      const options = {
-        ...existingOptions,
-        _experimentalCustomFetch: jest.fn(),
-      };
-
-      const result = convertLegacyOptions(options as any);
-
-      // Should preserve existing URL while adding new fetch client
-      expect(result.global?.fetch?.options?.url).toBe("https://existing.com");
-      expect(result.global?.fetch?.client).toBeDefined();
-    });
-  });
-});
diff --git a/tests/unit/string-utilities.test.ts b/tests/unit/string-utilities.test.ts
deleted file mode 100644
index 65cf9614..00000000
--- a/tests/unit/string-utilities.test.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { stripTrailingSlash, convertProtocolToWs } from "../../src/lib/helpers";
-
-describe("Unit Tests - String and URL Utilities", () => {
-  describe("stripTrailingSlash", () => {
-    it("should remove trailing slash from URLs", () => {
-      expect(stripTrailingSlash("https://api.deepgram.com/")).toBe("https://api.deepgram.com");
-      expect(stripTrailingSlash("https://api.deepgram.com/v1/")).toBe(
-        "https://api.deepgram.com/v1"
-      );
-      expect(stripTrailingSlash("path/")).toBe("path");
-      expect(stripTrailingSlash("/")).toBe("");
-    });
-
-    it("should not modify URLs without trailing slash", () => {
-      expect(stripTrailingSlash("https://api.deepgram.com")).toBe("https://api.deepgram.com");
-      expect(stripTrailingSlash("https://api.deepgram.com/v1")).toBe("https://api.deepgram.com/v1");
-      expect(stripTrailingSlash("path")).toBe("path");
-    });
-
-    it("should handle empty string", () => {
-      expect(stripTrailingSlash("")).toBe("");
-    });
-
-    it("should only remove one trailing slash", () => {
-      expect(stripTrailingSlash("https://api.deepgram.com//")).toBe("https://api.deepgram.com/");
-    });
-  });
-
-  describe("convertProtocolToWs", () => {
-    it("should convert HTTP to WebSocket protocols", () => {
-      expect(convertProtocolToWs("https://api.deepgram.com")).toBe("wss://api.deepgram.com");
-      expect(convertProtocolToWs("http://api.deepgram.com")).toBe("ws://api.deepgram.com");
-    });
-
-    it("should handle uppercase protocols", () => {
-      expect(convertProtocolToWs("HTTPS://API.DEEPGRAM.COM")).toBe("wss://api.deepgram.com");
-      expect(convertProtocolToWs("HTTP://API.DEEPGRAM.COM")).toBe("ws://api.deepgram.com");
-    });
-
-    it("should not modify WebSocket protocols", () => {
-      expect(convertProtocolToWs("wss://already-websocket.com")).toBe(
-        "wss://already-websocket.com"
-      );
-      expect(convertProtocolToWs("ws://already-websocket.com")).toBe("ws://already-websocket.com");
-    });
-
-    it("should handle mixed case protocols", () => {
-      expect(convertProtocolToWs("Http://example.com")).toBe("ws://example.com");
-      expect(convertProtocolToWs("Https://example.com")).toBe("wss://example.com");
-    });
-
-    it("should handle protocols without authority", () => {
-      expect(convertProtocolToWs("http:example")).toBe("ws:example");
-      expect(convertProtocolToWs("https:example")).toBe("wss:example");
-    });
-  });
-});
diff --git a/tests/unit/test-file.txt b/tests/unit/test-file.txt
new file mode 100644
index 00000000..c66d471e
--- /dev/null
+++ b/tests/unit/test-file.txt
@@ -0,0 +1 @@
+This is a test file!
diff --git a/tests/unit/type-guards.test.ts b/tests/unit/type-guards.test.ts
deleted file mode 100644
index 91622ac8..00000000
--- a/tests/unit/type-guards.test.ts
+++ /dev/null
@@ -1,194 +0,0 @@
-import {
-  isUrlSource,
-  isTextSource,
-  isFileSource,
-  isLiveSchema,
-  isDeepgramClientOptions,
-} from "../../src/lib/helpers";
-import { Readable } from "node:stream";
-
-describe("Unit Tests - Type Guards and Validators", () => {
-  describe("isUrlSource", () => {
-    it("should identify URL sources correctly", () => {
-      // Valid URL sources
-      expect(isUrlSource({ url: "https://dpgr.am/spacewalk.wav" })).toBe(true);
-      expect(isUrlSource({ url: "file://local.wav" })).toBe(true);
-      expect(isUrlSource({ url: "" })).toBe(false); // Empty string should be false
-
-      // Invalid sources
-      expect(isUrlSource({ text: "This is not a URL source" } as any)).toBe(false);
-      expect(isUrlSource({ buffer: Buffer.from("fake audio") } as any)).toBe(false);
-      expect(isUrlSource({ invalidProperty: "value" } as any)).toBe(false);
-      expect(isUrlSource({} as any)).toBe(false);
-      expect(isUrlSource(null as any)).toBe(false);
-      expect(isUrlSource(undefined as any)).toBe(false);
-    });
-  });
-
-  describe("isTextSource", () => {
-    it("should identify text sources correctly", () => {
-      // Valid text sources
-      expect(isTextSource({ text: "This is a text source" })).toBe(true);
-      expect(isTextSource({ text: "Multi-line\ntext content" })).toBe(true);
-
-      // Empty string should be falsy
-      expect(isTextSource({ text: "" })).toBe(false);
-
-      // Invalid sources
-      expect(isTextSource({ url: "https://dpgr.am/spacewalk.wav" } as any)).toBe(false);
-      expect(isTextSource({ invalidProperty: "value" } as any)).toBe(false);
-      expect(isTextSource({} as any)).toBe(false);
-      expect(isTextSource(null as any)).toBe(false);
-      expect(isTextSource(undefined as any)).toBe(false);
-    });
-  });
-
-  describe("isFileSource", () => {
-    it("should identify file sources correctly", () => {
-      const buffer = Buffer.from("fake audio data");
-      const readable = new Readable({
-        read() {
-          this.push("audio data");
-          this.push(null);
-        },
-      });
-
-      // Valid file sources
-      expect(isFileSource(buffer)).toBe(true);
-      expect(isFileSource(readable)).toBe(true);
-
-      // Invalid sources
-      expect(isFileSource({ url: "https://dpgr.am/spacewalk.wav" } as any)).toBe(false);
-      expect(isFileSource({ text: "This is text" } as any)).toBe(false);
-      expect(isFileSource("string data" as any)).toBe(false);
-      expect(isFileSource({} as any)).toBe(false);
-      expect(isFileSource(null as any)).toBe(false);
-      expect(isFileSource(undefined as any)).toBe(false);
-      expect(isFileSource(123 as any)).toBe(false);
-      expect(isFileSource([] as any)).toBe(false);
-    });
-  });
-
-  describe("isLiveSchema", () => {
-    it("should identify live schema correctly", () => {
-      // Valid live schemas
-      expect(isLiveSchema({ interim_results: true })).toBe(true);
-      expect(isLiveSchema({ interim_results: false })).toBe(true);
-      expect(isLiveSchema({ interim_results: true, language: "en-US" })).toBe(true);
-
-      // Invalid schemas - interim_results must be defined
-      expect(isLiveSchema({ language: "en-US", model: "nova-2" })).toBe(false);
-      expect(isLiveSchema({})).toBe(false);
-      expect(isLiveSchema(null)).toBe(false);
-      expect(isLiveSchema(undefined)).toBe(false);
-      expect(isLiveSchema("not an object")).toBe(false);
-      expect(isLiveSchema(123)).toBe(false);
-    });
-  });
-
-  describe("isDeepgramClientOptions", () => {
-    it("should identify Deepgram client options correctly", () => {
-      // Valid client options
-      expect(isDeepgramClientOptions({ global: { url: "https://api.deepgram.com" } })).toBe(true);
-      expect(isDeepgramClientOptions({ global: {} })).toBe(true);
-      expect(isDeepgramClientOptions({ global: { headers: { Custom: "Header" } } })).toBe(true);
-
-      // Invalid options - global property must be defined
-      expect(isDeepgramClientOptions({ apiKey: "test-key" })).toBe(false);
-      expect(isDeepgramClientOptions({})).toBe(false);
-      expect(isDeepgramClientOptions(null)).toBe(false);
-      expect(isDeepgramClientOptions(undefined)).toBe(false);
-      expect(isDeepgramClientOptions("not an object")).toBe(false);
-      expect(isDeepgramClientOptions(123)).toBe(false);
-    });
-  });
-});
-
-describe("isFileSource with duck-typed stream detection", () => {
-  let isBrowserMock: jest.SpyInstance;
-
-  beforeEach(() => {
-    // Import and mock the isBrowser function
-    const runtime = require("../../src/lib/runtime"); // eslint-disable-line @typescript-eslint/no-require-imports
-    isBrowserMock = jest.spyOn(runtime, "isBrowser");
-  });
-
-  afterEach(() => {
-    isBrowserMock.mockRestore();
-  });
-
-  describe("in Node.js environment", () => {
-    beforeEach(() => {
-      isBrowserMock.mockReturnValue(false);
-    });
-
-    it("should detect objects with all required stream properties", () => {
-      const streamLikeObject = {
-        pipe: jest.fn(),
-        read: jest.fn(),
-        _readableState: { flowing: null, ended: false },
-      };
-
-      expect(isFileSource(streamLikeObject as any)).toBe(true);
-    });
-
-    it("should reject objects missing pipe method", () => {
-      const invalidStream = {
-        read: jest.fn(),
-        _readableState: {},
-      };
-
-      expect(isFileSource(invalidStream as any)).toBe(false);
-    });
-
-    it("should reject objects missing read method", () => {
-      const invalidStream = {
-        pipe: jest.fn(),
-        _readableState: {},
-      };
-
-      expect(isFileSource(invalidStream as any)).toBe(false);
-    });
-
-    it("should reject objects missing _readableState", () => {
-      const invalidStream = {
-        pipe: jest.fn(),
-        read: jest.fn(),
-      };
-
-      expect(isFileSource(invalidStream as any)).toBe(false);
-    });
-
-    it("should reject objects where methods are not functions", () => {
-      const invalidStream = {
-        pipe: "not a function",
-        read: jest.fn(),
-        _readableState: {},
-      };
-
-      expect(isFileSource(invalidStream as any)).toBe(false);
-    });
-  });
-
-  describe("in browser environment", () => {
-    beforeEach(() => {
-      isBrowserMock.mockReturnValue(true);
-    });
-
-    it("should always return false for stream-like objects", () => {
-      const streamLikeObject = {
-        pipe: jest.fn(),
-        read: jest.fn(),
-        _readableState: {},
-      };
-
-      // Even with all properties, should return false in browser
-      expect(isFileSource(streamLikeObject as any)).toBe(false);
-    });
-
-    it("should still detect Buffer objects", () => {
-      const buffer = Buffer.from("test data");
-      expect(isFileSource(buffer)).toBe(true);
-    });
-  });
-});
diff --git a/tests/unit/url-builders.test.ts b/tests/unit/url-builders.test.ts
deleted file mode 100644
index 8e9f0401..00000000
--- a/tests/unit/url-builders.test.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { buildRequestUrl } from "../../src/lib/helpers";
-
-describe("Unit Tests - URL Building Utilities", () => {
-  describe("buildRequestUrl", () => {
-    it("should build URLs with string base URL", () => {
-      const url = buildRequestUrl("v1/listen", "https://api.deepgram.com", {
-        language: "en-US",
-        model: "nova-2",
-      });
-
-      expect(url.href).toBe("https://api.deepgram.com/v1/listen?language=en-US&model=nova-2");
-      expect(url.searchParams.get("language")).toBe("en-US");
-      expect(url.searchParams.get("model")).toBe("nova-2");
-    });
-
-    it("should build URLs with URL object base", () => {
-      const baseUrl = new URL("https://api.deepgram.com");
-      const url = buildRequestUrl("v1/listen", baseUrl, { punctuate: true, smart_format: false });
-
-      expect(url.href).toBe("https://api.deepgram.com/v1/listen?punctuate=true&smart_format=false");
-      expect(url.searchParams.get("punctuate")).toBe("true");
-      expect(url.searchParams.get("smart_format")).toBe("false");
-    });
-
-    it("should handle array parameters", () => {
-      const url = buildRequestUrl("v1/speak", "https://api.deepgram.com", {
-        keywords: ["hello", "world"],
-      });
-
-      expect(url.searchParams.getAll("keywords")).toEqual(["hello", "world"]);
-      expect(url.href).toBe("https://api.deepgram.com/v1/speak?keywords=hello&keywords=world");
-    });
-
-    it("should handle empty options", () => {
-      const url = buildRequestUrl("v1/listen", "https://api.deepgram.com", {});
-
-      expect(url.href).toBe("https://api.deepgram.com/v1/listen");
-      expect(url.search).toBe("");
-    });
-
-    it("should handle numeric parameters", () => {
-      const url = buildRequestUrl("v1/listen", "https://api.deepgram.com", {
-        confidence: 0.8,
-        alternatives: 3,
-      });
-
-      expect(url.searchParams.get("confidence")).toBe("0.8");
-      expect(url.searchParams.get("alternatives")).toBe("3");
-    });
-
-    it("should handle boolean parameters", () => {
-      const url = buildRequestUrl("v1/listen", "https://api.deepgram.com", {
-        interim_results: true,
-        endpointing: false,
-      });
-
-      expect(url.searchParams.get("interim_results")).toBe("true");
-      expect(url.searchParams.get("endpointing")).toBe("false");
-    });
-
-    it("should preserve base URL path", () => {
-      const url = buildRequestUrl("listen", "https://api.deepgram.com/v1/", { language: "en-US" });
-
-      expect(url.pathname).toBe("/v1/listen");
-      expect(url.href).toBe("https://api.deepgram.com/v1/listen?language=en-US");
-    });
-  });
-});
diff --git a/tests/unit/url/join.test.ts b/tests/unit/url/join.test.ts
new file mode 100644
index 00000000..123488f0
--- /dev/null
+++ b/tests/unit/url/join.test.ts
@@ -0,0 +1,284 @@
+import { join } from "../../../src/core/url/index";
+
+describe("join", () => {
+    interface TestCase {
+        description: string;
+        base: string;
+        segments: string[];
+        expected: string;
+    }
+
+    describe("basic functionality", () => {
+        const basicTests: TestCase[] = [
+            { description: "should return empty string for empty base", base: "", segments: [], expected: "" },
+            {
+                description: "should return empty string for empty base with path",
+                base: "",
+                segments: ["path"],
+                expected: "",
+            },
+            {
+                description: "should handle single segment",
+                base: "base",
+                segments: ["segment"],
+                expected: "base/segment",
+            },
+            {
+                description: "should handle single segment with trailing slash on base",
+                base: "base/",
+                segments: ["segment"],
+                expected: "base/segment",
+            },
+            {
+                description: "should handle single segment with leading slash",
+                base: "base",
+                segments: ["/segment"],
+                expected: "base/segment",
+            },
+            {
+                description: "should handle single segment with both slashes",
+                base: "base/",
+                segments: ["/segment"],
+                expected: "base/segment",
+            },
+            {
+                description: "should handle multiple segments",
+                base: "base",
+                segments: ["path1", "path2", "path3"],
+                expected: "base/path1/path2/path3",
+            },
+            {
+                description: "should handle multiple segments with slashes",
+                base: "base/",
+                segments: ["/path1/", "/path2/", "/path3/"],
+                expected: "base/path1/path2/path3/",
+            },
+        ];
+
+        basicTests.forEach(({ description, base, segments, expected }) => {
+            it(description, () => {
+                expect(join(base, ...segments)).toBe(expected);
+            });
+        });
+    });
+
+    describe("URL handling", () => {
+        const urlTests: TestCase[] = [
+            {
+                description: "should handle absolute URLs",
+                base: "https://example.com",
+                segments: ["api", "v1"],
+                expected: "https://example.com/api/v1",
+            },
+            {
+                description: "should handle absolute URLs with slashes",
+                base: "https://example.com/",
+                segments: ["/api/", "/v1/"],
+                expected: "https://example.com/api/v1/",
+            },
+            {
+                description: "should handle absolute URLs with base path",
+                base: "https://example.com/base",
+                segments: ["api", "v1"],
+                expected: "https://example.com/base/api/v1",
+            },
+            {
+                description: "should preserve URL query parameters",
+                base: "https://example.com?query=1",
+                segments: ["api"],
+                expected: "https://example.com/api?query=1",
+            },
+            {
+                description: "should preserve URL fragments",
+                base: "https://example.com#fragment",
+                segments: ["api"],
+                expected: "https://example.com/api#fragment",
+            },
+            {
+                description: "should preserve URL query and fragments",
+                base: "https://example.com?query=1#fragment",
+                segments: ["api"],
+                expected: "https://example.com/api?query=1#fragment",
+            },
+            {
+                description: "should handle http protocol",
+                base: "http://example.com",
+                segments: ["api"],
+                expected: "http://example.com/api",
+            },
+            {
+                description: "should handle ftp protocol",
+                base: "ftp://example.com",
+                segments: ["files"],
+                expected: "ftp://example.com/files",
+            },
+            {
+                description: "should handle ws protocol",
+                base: "ws://example.com",
+                segments: ["socket"],
+                expected: "ws://example.com/socket",
+            },
+            {
+                description: "should fallback to path joining for malformed URLs",
+                base: "not-a-url://",
+                segments: ["path"],
+                expected: "not-a-url:///path",
+            },
+        ];
+
+        urlTests.forEach(({ description, base, segments, expected }) => {
+            it(description, () => {
+                expect(join(base, ...segments)).toBe(expected);
+            });
+        });
+    });
+
+    describe("edge cases", () => {
+        const edgeCaseTests: TestCase[] = [
+            {
+                description: "should handle empty segments",
+                base: "base",
+                segments: ["", "path"],
+                expected: "base/path",
+            },
+            {
+                description: "should handle null segments",
+                base: "base",
+                segments: [null as any, "path"],
+                expected: "base/path",
+            },
+            {
+                description: "should handle undefined segments",
+                base: "base",
+                segments: [undefined as any, "path"],
+                expected: "base/path",
+            },
+            {
+                description: "should handle segments with only single slash",
+                base: "base",
+                segments: ["/", "path"],
+                expected: "base/path",
+            },
+            {
+                description: "should handle segments with only double slash",
+                base: "base",
+                segments: ["//", "path"],
+                expected: "base/path",
+            },
+            {
+                description: "should handle base paths with trailing slashes",
+                base: "base/",
+                segments: ["path"],
+                expected: "base/path",
+            },
+            {
+                description: "should handle complex nested paths",
+                base: "api/v1/",
+                segments: ["/users/", "/123/", "/profile"],
+                expected: "api/v1/users/123/profile",
+            },
+        ];
+
+        edgeCaseTests.forEach(({ description, base, segments, expected }) => {
+            it(description, () => {
+                expect(join(base, ...segments)).toBe(expected);
+            });
+        });
+    });
+
+    describe("real-world scenarios", () => {
+        const realWorldTests: TestCase[] = [
+            {
+                description: "should handle API endpoint construction",
+                base: "https://api.example.com/v1",
+                segments: ["users", "123", "posts"],
+                expected: "https://api.example.com/v1/users/123/posts",
+            },
+            {
+                description: "should handle file path construction",
+                base: "/var/www",
+                segments: ["html", "assets", "images"],
+                expected: "/var/www/html/assets/images",
+            },
+            {
+                description: "should handle relative path construction",
+                base: "../parent",
+                segments: ["child", "grandchild"],
+                expected: "../parent/child/grandchild",
+            },
+            {
+                description: "should handle Windows-style paths",
+                base: "C:\\Users",
+                segments: ["Documents", "file.txt"],
+                expected: "C:\\Users/Documents/file.txt",
+            },
+        ];
+
+        realWorldTests.forEach(({ description, base, segments, expected }) => {
+            it(description, () => {
+                expect(join(base, ...segments)).toBe(expected);
+            });
+        });
+    });
+
+    describe("performance scenarios", () => {
+        it("should handle many segments efficiently", () => {
+            const segments = Array(100).fill("segment");
+            const result = join("base", ...segments);
+            expect(result).toBe(`base/${segments.join("/")}`);
+        });
+
+        it("should handle long URLs", () => {
+            const longPath = "a".repeat(1000);
+            expect(join("https://example.com", longPath)).toBe(`https://example.com/${longPath}`);
+        });
+    });
+
+    describe("trailing slash preservation", () => {
+        const trailingSlashTests: TestCase[] = [
+            {
+                description:
+                    "should preserve trailing slash on final result when base has trailing slash and no segments",
+                base: "https://api.example.com/",
+                segments: [],
+                expected: "https://api.example.com/",
+            },
+            {
+                description: "should preserve trailing slash on v1 path",
+                base: "https://api.example.com/v1/",
+                segments: [],
+                expected: "https://api.example.com/v1/",
+            },
+            {
+                description: "should preserve trailing slash when last segment has trailing slash",
+                base: "https://api.example.com",
+                segments: ["users/"],
+                expected: "https://api.example.com/users/",
+            },
+            {
+                description: "should preserve trailing slash with relative path",
+                base: "api/v1",
+                segments: ["users/"],
+                expected: "api/v1/users/",
+            },
+            {
+                description: "should preserve trailing slash with multiple segments",
+                base: "https://api.example.com",
+                segments: ["v1", "collections/"],
+                expected: "https://api.example.com/v1/collections/",
+            },
+            {
+                description: "should preserve trailing slash with base path",
+                base: "base",
+                segments: ["path1", "path2/"],
+                expected: "base/path1/path2/",
+            },
+        ];
+
+        trailingSlashTests.forEach(({ description, base, segments, expected }) => {
+            it(description, () => {
+                expect(join(base, ...segments)).toBe(expected);
+            });
+        });
+    });
+});
diff --git a/tests/unit/url/qs.test.ts b/tests/unit/url/qs.test.ts
new file mode 100644
index 00000000..42cdffb9
--- /dev/null
+++ b/tests/unit/url/qs.test.ts
@@ -0,0 +1,278 @@
+import { toQueryString } from "../../../src/core/url/index";
+
+describe("Test qs toQueryString", () => {
+    interface BasicTestCase {
+        description: string;
+        input: any;
+        expected: string;
+    }
+
+    describe("Basic functionality", () => {
+        const basicTests: BasicTestCase[] = [
+            { description: "should return empty string for null", input: null, expected: "" },
+            { description: "should return empty string for undefined", input: undefined, expected: "" },
+            { description: "should return empty string for string primitive", input: "hello", expected: "" },
+            { description: "should return empty string for number primitive", input: 42, expected: "" },
+            { description: "should return empty string for true boolean", input: true, expected: "" },
+            { description: "should return empty string for false boolean", input: false, expected: "" },
+            { description: "should handle empty objects", input: {}, expected: "" },
+            {
+                description: "should handle simple key-value pairs",
+                input: { name: "John", age: 30 },
+                expected: "name=John&age=30",
+            },
+        ];
+
+        basicTests.forEach(({ description, input, expected }) => {
+            it(description, () => {
+                expect(toQueryString(input)).toBe(expected);
+            });
+        });
+    });
+
+    describe("Array handling", () => {
+        interface ArrayTestCase {
+            description: string;
+            input: any;
+            options?: { arrayFormat?: "repeat" | "indices" };
+            expected: string;
+        }
+
+        const arrayTests: ArrayTestCase[] = [
+            {
+                description: "should handle arrays with indices format (default)",
+                input: { items: ["a", "b", "c"] },
+                expected: "items%5B0%5D=a&items%5B1%5D=b&items%5B2%5D=c",
+            },
+            {
+                description: "should handle arrays with repeat format",
+                input: { items: ["a", "b", "c"] },
+                options: { arrayFormat: "repeat" },
+                expected: "items=a&items=b&items=c",
+            },
+            {
+                description: "should handle empty arrays",
+                input: { items: [] },
+                expected: "",
+            },
+            {
+                description: "should handle arrays with mixed types",
+                input: { mixed: ["string", 42, true, false] },
+                expected: "mixed%5B0%5D=string&mixed%5B1%5D=42&mixed%5B2%5D=true&mixed%5B3%5D=false",
+            },
+            {
+                description: "should handle arrays with objects",
+                input: { users: [{ name: "John" }, { name: "Jane" }] },
+                expected: "users%5B0%5D%5Bname%5D=John&users%5B1%5D%5Bname%5D=Jane",
+            },
+            {
+                description: "should handle arrays with objects in repeat format",
+                input: { users: [{ name: "John" }, { name: "Jane" }] },
+                options: { arrayFormat: "repeat" },
+                expected: "users%5Bname%5D=John&users%5Bname%5D=Jane",
+            },
+        ];
+
+        arrayTests.forEach(({ description, input, options, expected }) => {
+            it(description, () => {
+                expect(toQueryString(input, options)).toBe(expected);
+            });
+        });
+    });
+
+    describe("Nested objects", () => {
+        const nestedTests: BasicTestCase[] = [
+            {
+                description: "should handle nested objects",
+                input: { user: { name: "John", age: 30 } },
+                expected: "user%5Bname%5D=John&user%5Bage%5D=30",
+            },
+            {
+                description: "should handle deeply nested objects",
+                input: { user: { profile: { name: "John", settings: { theme: "dark" } } } },
+                expected: "user%5Bprofile%5D%5Bname%5D=John&user%5Bprofile%5D%5Bsettings%5D%5Btheme%5D=dark",
+            },
+            {
+                description: "should handle empty nested objects",
+                input: { user: {} },
+                expected: "",
+            },
+        ];
+
+        nestedTests.forEach(({ description, input, expected }) => {
+            it(description, () => {
+                expect(toQueryString(input)).toBe(expected);
+            });
+        });
+    });
+
+    describe("Encoding", () => {
+        interface EncodingTestCase {
+            description: string;
+            input: any;
+            options?: { encode?: boolean };
+            expected: string;
+        }
+
+        const encodingTests: EncodingTestCase[] = [
+            {
+                description: "should encode by default",
+                input: { name: "John Doe", email: "john@example.com" },
+                expected: "name=John%20Doe&email=john%40example.com",
+            },
+            {
+                description: "should not encode when encode is false",
+                input: { name: "John Doe", email: "john@example.com" },
+                options: { encode: false },
+                expected: "name=John Doe&email=john@example.com",
+            },
+            {
+                description: "should encode special characters in keys",
+                input: { "user name": "John", "email[primary]": "john@example.com" },
+                expected: "user%20name=John&email%5Bprimary%5D=john%40example.com",
+            },
+            {
+                description: "should not encode special characters in keys when encode is false",
+                input: { "user name": "John", "email[primary]": "john@example.com" },
+                options: { encode: false },
+                expected: "user name=John&email[primary]=john@example.com",
+            },
+        ];
+
+        encodingTests.forEach(({ description, input, options, expected }) => {
+            it(description, () => {
+                expect(toQueryString(input, options)).toBe(expected);
+            });
+        });
+    });
+
+    describe("Mixed scenarios", () => {
+        interface MixedTestCase {
+            description: string;
+            input: any;
+            options?: { arrayFormat?: "repeat" | "indices" };
+            expected: string;
+        }
+
+        const mixedTests: MixedTestCase[] = [
+            {
+                description: "should handle complex nested structures",
+                input: {
+                    filters: {
+                        status: ["active", "pending"],
+                        category: {
+                            type: "electronics",
+                            subcategories: ["phones", "laptops"],
+                        },
+                    },
+                    sort: { field: "name", direction: "asc" },
+                },
+                expected:
+                    "filters%5Bstatus%5D%5B0%5D=active&filters%5Bstatus%5D%5B1%5D=pending&filters%5Bcategory%5D%5Btype%5D=electronics&filters%5Bcategory%5D%5Bsubcategories%5D%5B0%5D=phones&filters%5Bcategory%5D%5Bsubcategories%5D%5B1%5D=laptops&sort%5Bfield%5D=name&sort%5Bdirection%5D=asc",
+            },
+            {
+                description: "should handle complex nested structures with repeat format",
+                input: {
+                    filters: {
+                        status: ["active", "pending"],
+                        category: {
+                            type: "electronics",
+                            subcategories: ["phones", "laptops"],
+                        },
+                    },
+                    sort: { field: "name", direction: "asc" },
+                },
+                options: { arrayFormat: "repeat" },
+                expected:
+                    "filters%5Bstatus%5D=active&filters%5Bstatus%5D=pending&filters%5Bcategory%5D%5Btype%5D=electronics&filters%5Bcategory%5D%5Bsubcategories%5D=phones&filters%5Bcategory%5D%5Bsubcategories%5D=laptops&sort%5Bfield%5D=name&sort%5Bdirection%5D=asc",
+            },
+            {
+                description: "should handle arrays with null/undefined values",
+                input: { items: ["a", null, "c", undefined, "e"] },
+                expected: "items%5B0%5D=a&items%5B1%5D=&items%5B2%5D=c&items%5B4%5D=e",
+            },
+            {
+                description: "should handle objects with null/undefined values",
+                input: { name: "John", age: null, email: undefined, active: true },
+                expected: "name=John&age=&active=true",
+            },
+        ];
+
+        mixedTests.forEach(({ description, input, options, expected }) => {
+            it(description, () => {
+                expect(toQueryString(input, options)).toBe(expected);
+            });
+        });
+    });
+
+    describe("Edge cases", () => {
+        const edgeCaseTests: BasicTestCase[] = [
+            {
+                description: "should handle numeric keys",
+                input: { "0": "zero", "1": "one" },
+                expected: "0=zero&1=one",
+            },
+            {
+                description: "should handle boolean values in objects",
+                input: { enabled: true, disabled: false },
+                expected: "enabled=true&disabled=false",
+            },
+            {
+                description: "should handle empty strings",
+                input: { name: "", description: "test" },
+                expected: "name=&description=test",
+            },
+            {
+                description: "should handle zero values",
+                input: { count: 0, price: 0.0 },
+                expected: "count=0&price=0",
+            },
+            {
+                description: "should handle arrays with empty strings",
+                input: { items: ["a", "", "c"] },
+                expected: "items%5B0%5D=a&items%5B1%5D=&items%5B2%5D=c",
+            },
+        ];
+
+        edgeCaseTests.forEach(({ description, input, expected }) => {
+            it(description, () => {
+                expect(toQueryString(input)).toBe(expected);
+            });
+        });
+    });
+
+    describe("Options combinations", () => {
+        interface OptionsTestCase {
+            description: string;
+            input: any;
+            options?: { arrayFormat?: "repeat" | "indices"; encode?: boolean };
+            expected: string;
+        }
+
+        const optionsTests: OptionsTestCase[] = [
+            {
+                description: "should respect both arrayFormat and encode options",
+                input: { items: ["a & b", "c & d"] },
+                options: { arrayFormat: "repeat", encode: false },
+                expected: "items=a & b&items=c & d",
+            },
+            {
+                description: "should use default options when none provided",
+                input: { items: ["a", "b"] },
+                expected: "items%5B0%5D=a&items%5B1%5D=b",
+            },
+            {
+                description: "should merge provided options with defaults",
+                input: { items: ["a", "b"], name: "John Doe" },
+                options: { encode: false },
+                expected: "items[0]=a&items[1]=b&name=John Doe",
+            },
+        ];
+
+        optionsTests.forEach(({ description, input, options, expected }) => {
+            it(description, () => {
+                expect(toQueryString(input, options)).toBe(expected);
+            });
+        });
+    });
+});
diff --git a/tests/wire/.gitkeep b/tests/wire/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/wire/agent/v1/settings/think/models.test.ts b/tests/wire/agent/v1/settings/think/models.test.ts
new file mode 100644
index 00000000..8bdd403f
--- /dev/null
+++ b/tests/wire/agent/v1/settings/think/models.test.ts
@@ -0,0 +1,58 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("ModelsClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { models: [{ id: "gpt-5", name: "name", provider: "open_ai" }] };
+        server
+            .mockEndpoint()
+            .get("/v1/agent/settings/think/models")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.agent.v1.settings.think.models.list();
+        expect(response).toEqual({
+            models: [
+                {
+                    id: "gpt-5",
+                    name: "name",
+                    provider: "open_ai",
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/agent/settings/think/models")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.agent.v1.settings.think.models.list();
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/auth/v1/tokens.test.ts b/tests/wire/auth/v1/tokens.test.ts
new file mode 100644
index 00000000..74f205d9
--- /dev/null
+++ b/tests/wire/auth/v1/tokens.test.ts
@@ -0,0 +1,60 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../src/api/index";
+import { DeepgramClient } from "../../../../src/Client";
+import { mockServerPool } from "../../../mock-server/MockServerPool";
+
+describe("TokensClient", () => {
+    test("grant (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = {};
+        const rawResponseBody = {
+            access_token:
+                "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U",
+            expires_in: 30,
+        };
+        server
+            .mockEndpoint()
+            .post("/v1/auth/grant")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.auth.v1.tokens.grant();
+        expect(response).toEqual({
+            access_token:
+                "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U",
+            expires_in: 30,
+        });
+    });
+
+    test("grant (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = {};
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .post("/v1/auth/grant")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.auth.v1.tokens.grant();
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/listen/v1/media.test.ts b/tests/wire/listen/v1/media.test.ts
new file mode 100644
index 00000000..78431476
--- /dev/null
+++ b/tests/wire/listen/v1/media.test.ts
@@ -0,0 +1,208 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../src/api/index";
+import { DeepgramClient } from "../../../../src/Client";
+import { mockServerPool } from "../../../mock-server/MockServerPool";
+
+describe("MediaClient", () => {
+    test("transcribeUrl (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { url: "https://dpgr.am/spacewalk.wav" };
+        const rawResponseBody = {
+            metadata: {
+                request_id: "a847f427-4ad5-4d67-9b95-db801e58251c",
+                sha256: "154e291ecfa8be6ab8343560bcc109008fa7853eb5372533e8efdefc9b504c33",
+                created: "2024-05-12T18:57:13Z",
+                duration: 25.933313,
+                channels: 1,
+                models: ["30089e05-99d1-4376-b32e-c263170674af"],
+                model_info: {
+                    "30089e05-99d1-4376-b32e-c263170674af": {
+                        name: "2-general-nova",
+                        version: "2024-01-09.29447",
+                        arch: "nova-2",
+                    },
+                },
+                summary_info: {
+                    model_uuid: "67875a7f-c9c4-48a0-aa55-5bdb8a91c34a",
+                    input_tokens: 95,
+                    output_tokens: 63,
+                },
+                sentiment_info: {
+                    model_uuid: "80ab3179-d113-4254-bd6b-4a2f96498695",
+                    input_tokens: 105,
+                    output_tokens: 105,
+                },
+                topics_info: {
+                    model_uuid: "80ab3179-d113-4254-bd6b-4a2f96498695",
+                    input_tokens: 105,
+                    output_tokens: 7,
+                },
+                intents_info: {
+                    model_uuid: "80ab3179-d113-4254-bd6b-4a2f96498695",
+                    input_tokens: 105,
+                    output_tokens: 4,
+                },
+                tags: ["test"],
+            },
+            results: {
+                channels: [{}],
+                utterances: [{}],
+                summary: {
+                    result: "success",
+                    short: "Speaker 0 discusses the significance of the first all-female spacewalk with an all-female team, stating that it is a tribute to the skilled and qualified women who were denied opportunities in the past.",
+                },
+                sentiments: {
+                    segments: [
+                        {
+                            text: "Yeah. As as much as, um, it's worth celebrating, uh, the first, uh, spacewalk, um, with an all-female team, I think many of us are looking forward to it just being normal. And, um, I think if it signifies anything, it is, uh, to honor the the women who came before us who, um, were skilled and qualified, um, and didn't get the the same opportunities that we have today.",
+                            start_word: 0,
+                            end_word: 69,
+                            sentiment: "positive",
+                            sentiment_score: 0.5810546875,
+                        },
+                    ],
+                    average: { sentiment: "positive", sentiment_score: 0.5810185185185185 },
+                },
+            },
+        };
+        server
+            .mockEndpoint()
+            .post("/v1/listen")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.listen.v1.media.transcribeUrl({
+            callback: "callback",
+            callback_method: "POST",
+            extra: "extra",
+            sentiment: true,
+            summarize: "v2",
+            tag: "tag",
+            topics: true,
+            custom_topic: "custom_topic",
+            custom_topic_mode: "extended",
+            intents: true,
+            custom_intent: "custom_intent",
+            custom_intent_mode: "extended",
+            detect_entities: true,
+            detect_language: true,
+            diarize: true,
+            dictation: true,
+            encoding: "linear16",
+            filler_words: true,
+            keywords: "keywords",
+            language: "language",
+            measurements: true,
+            model: "nova-3",
+            multichannel: true,
+            numerals: true,
+            paragraphs: true,
+            profanity_filter: true,
+            punctuate: true,
+            redact: "redact",
+            replace: "replace",
+            search: "search",
+            smart_format: true,
+            utterances: true,
+            utt_split: 1.1,
+            version: "latest",
+            mip_opt_out: true,
+            url: "https://dpgr.am/spacewalk.wav",
+        });
+        expect(response).toEqual({
+            metadata: {
+                request_id: "a847f427-4ad5-4d67-9b95-db801e58251c",
+                sha256: "154e291ecfa8be6ab8343560bcc109008fa7853eb5372533e8efdefc9b504c33",
+                created: "2024-05-12T18:57:13Z",
+                duration: 25.933313,
+                channels: 1,
+                models: ["30089e05-99d1-4376-b32e-c263170674af"],
+                model_info: {
+                    "30089e05-99d1-4376-b32e-c263170674af": {
+                        name: "2-general-nova",
+                        version: "2024-01-09.29447",
+                        arch: "nova-2",
+                    },
+                },
+                summary_info: {
+                    model_uuid: "67875a7f-c9c4-48a0-aa55-5bdb8a91c34a",
+                    input_tokens: 95,
+                    output_tokens: 63,
+                },
+                sentiment_info: {
+                    model_uuid: "80ab3179-d113-4254-bd6b-4a2f96498695",
+                    input_tokens: 105,
+                    output_tokens: 105,
+                },
+                topics_info: {
+                    model_uuid: "80ab3179-d113-4254-bd6b-4a2f96498695",
+                    input_tokens: 105,
+                    output_tokens: 7,
+                },
+                intents_info: {
+                    model_uuid: "80ab3179-d113-4254-bd6b-4a2f96498695",
+                    input_tokens: 105,
+                    output_tokens: 4,
+                },
+                tags: ["test"],
+            },
+            results: {
+                channels: [{}],
+                utterances: [{}],
+                summary: {
+                    result: "success",
+                    short: "Speaker 0 discusses the significance of the first all-female spacewalk with an all-female team, stating that it is a tribute to the skilled and qualified women who were denied opportunities in the past.",
+                },
+                sentiments: {
+                    segments: [
+                        {
+                            text: "Yeah. As as much as, um, it's worth celebrating, uh, the first, uh, spacewalk, um, with an all-female team, I think many of us are looking forward to it just being normal. And, um, I think if it signifies anything, it is, uh, to honor the the women who came before us who, um, were skilled and qualified, um, and didn't get the the same opportunities that we have today.",
+                            start_word: 0,
+                            end_word: 69,
+                            sentiment: "positive",
+                            sentiment_score: 0.5810546875,
+                        },
+                    ],
+                    average: {
+                        sentiment: "positive",
+                        sentiment_score: 0.5810185185185185,
+                    },
+                },
+            },
+        });
+    });
+
+    test("transcribeUrl (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { url: "url" };
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .post("/v1/listen")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.listen.v1.media.transcribeUrl({
+                url: "url",
+            });
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/models.test.ts b/tests/wire/manage/v1/models.test.ts
new file mode 100644
index 00000000..f878b4f7
--- /dev/null
+++ b/tests/wire/manage/v1/models.test.ts
@@ -0,0 +1,169 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../src/api/index";
+import { DeepgramClient } from "../../../../src/Client";
+import { mockServerPool } from "../../../mock-server/MockServerPool";
+
+describe("ModelsClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            stt: [
+                {
+                    name: "nova-3",
+                    canonical_name: "nova-3",
+                    architecture: "base",
+                    languages: ["en", "en-us"],
+                    version: "2021-11-10.1",
+                    uuid: "6b28e919-8427-4f32-9847-492e2efd7daf",
+                    batch: true,
+                    streaming: true,
+                    formatted_output: true,
+                },
+            ],
+            tts: [
+                {
+                    name: "zeus",
+                    canonical_name: "aura-2-zeus-en",
+                    architecture: "aura-2",
+                    languages: ["en", "en-US"],
+                    version: "2025-04-07.0",
+                    uuid: "2baf189d-91ac-481d-b6d1-750888667b31",
+                    metadata: {
+                        accent: "American",
+                        age: "Adult",
+                        color: "#C58DFF",
+                        image: "https://static.deepgram.com/examples/avatars/zeus.jpg",
+                        sample: "https://static.deepgram.com/examples/Aura-2-zeus.wav",
+                        tags: ["masculine", "deep", "trustworthy", "smooth"],
+                        use_cases: ["IVR"],
+                    },
+                },
+            ],
+        };
+        server.mockEndpoint().get("/v1/models").respondWith().statusCode(200).jsonBody(rawResponseBody).build();
+
+        const response = await client.manage.v1.models.list({
+            include_outdated: true,
+        });
+        expect(response).toEqual({
+            stt: [
+                {
+                    name: "nova-3",
+                    canonical_name: "nova-3",
+                    architecture: "base",
+                    languages: ["en", "en-us"],
+                    version: "2021-11-10.1",
+                    uuid: "6b28e919-8427-4f32-9847-492e2efd7daf",
+                    batch: true,
+                    streaming: true,
+                    formatted_output: true,
+                },
+            ],
+            tts: [
+                {
+                    name: "zeus",
+                    canonical_name: "aura-2-zeus-en",
+                    architecture: "aura-2",
+                    languages: ["en", "en-US"],
+                    version: "2025-04-07.0",
+                    uuid: "2baf189d-91ac-481d-b6d1-750888667b31",
+                    metadata: {
+                        accent: "American",
+                        age: "Adult",
+                        color: "#C58DFF",
+                        image: "https://static.deepgram.com/examples/avatars/zeus.jpg",
+                        sample: "https://static.deepgram.com/examples/Aura-2-zeus.wav",
+                        tags: ["masculine", "deep", "trustworthy", "smooth"],
+                        use_cases: ["IVR"],
+                    },
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server.mockEndpoint().get("/v1/models").respondWith().statusCode(400).jsonBody(rawResponseBody).build();
+
+        await expect(async () => {
+            return await client.manage.v1.models.list();
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            name: "general",
+            canonical_name: "enhanced-general",
+            architecture: "polaris",
+            languages: ["en", "en-us"],
+            version: "2022-05-18.1",
+            uuid: "c7226e9e-ae1c-4057-ae2a-a71a6b0dc588",
+            batch: true,
+            streaming: true,
+            formatted_output: false,
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/models/af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.models.get("af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291");
+        expect(response).toEqual({
+            name: "general",
+            canonical_name: "enhanced-general",
+            architecture: "polaris",
+            languages: ["en", "en-us"],
+            version: "2022-05-18.1",
+            uuid: "c7226e9e-ae1c-4057-ae2a-a71a6b0dc588",
+            batch: true,
+            streaming: true,
+            formatted_output: false,
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/models/model_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.models.get("model_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects.test.ts b/tests/wire/manage/v1/projects.test.ts
new file mode 100644
index 00000000..61db1678
--- /dev/null
+++ b/tests/wire/manage/v1/projects.test.ts
@@ -0,0 +1,232 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../src/api/index";
+import { DeepgramClient } from "../../../../src/Client";
+import { mockServerPool } from "../../../mock-server/MockServerPool";
+
+describe("ProjectsClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { projects: [{ project_id: "project_id", name: "name" }] };
+        server.mockEndpoint().get("/v1/projects").respondWith().statusCode(200).jsonBody(rawResponseBody).build();
+
+        const response = await client.manage.v1.projects.list();
+        expect(response).toEqual({
+            projects: [
+                {
+                    project_id: "project_id",
+                    name: "name",
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server.mockEndpoint().get("/v1/projects").respondWith().statusCode(400).jsonBody(rawResponseBody).build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.list();
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { project_id: "project_id", mip_opt_out: true, name: "name" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.get("123456-7890-1234-5678-901234", {
+            limit: 1.1,
+            page: 1.1,
+        });
+        expect(response).toEqual({
+            project_id: "project_id",
+            mip_opt_out: true,
+            name: "name",
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.get("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("delete (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { message: "message" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/123456-7890-1234-5678-901234")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.delete("123456-7890-1234-5678-901234");
+        expect(response).toEqual({
+            message: "message",
+        });
+    });
+
+    test("delete (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/project_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.delete("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("update (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = {};
+        const rawResponseBody = { message: "Successfully updated project info." };
+        server
+            .mockEndpoint()
+            .patch("/v1/projects/123456-7890-1234-5678-901234")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.update("123456-7890-1234-5678-901234");
+        expect(response).toEqual({
+            message: "Successfully updated project info.",
+        });
+    });
+
+    test("update (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = {};
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .patch("/v1/projects/project_id")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.update("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("leave (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { message: "message" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/123456-7890-1234-5678-901234/leave")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.leave("123456-7890-1234-5678-901234");
+        expect(response).toEqual({
+            message: "message",
+        });
+    });
+
+    test("leave (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/project_id/leave")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.leave("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/billing/balances.test.ts b/tests/wire/manage/v1/projects/billing/balances.test.ts
new file mode 100644
index 00000000..4b3d25fe
--- /dev/null
+++ b/tests/wire/manage/v1/projects/billing/balances.test.ts
@@ -0,0 +1,119 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("BalancesClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            balances: [
+                { balance_id: "balance_id", amount: 1.1, units: "units", purchase_order_id: "purchase_order_id" },
+            ],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/balances")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.billing.balances.list("123456-7890-1234-5678-901234");
+        expect(response).toEqual({
+            balances: [
+                {
+                    balance_id: "balance_id",
+                    amount: 1.1,
+                    units: "units",
+                    purchase_order_id: "purchase_order_id",
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/balances")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.billing.balances.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            balance_id: "balance_id",
+            amount: 1.1,
+            units: "units",
+            purchase_order_id: "purchase_order_id",
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/balances/123456-7890-1234-5678-901234")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.billing.balances.get(
+            "123456-7890-1234-5678-901234",
+            "123456-7890-1234-5678-901234",
+        );
+        expect(response).toEqual({
+            balance_id: "balance_id",
+            amount: 1.1,
+            units: "units",
+            purchase_order_id: "purchase_order_id",
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/balances/balance_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.billing.balances.get("project_id", "balance_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/billing/breakdown.test.ts b/tests/wire/manage/v1/projects/billing/breakdown.test.ts
new file mode 100644
index 00000000..519a7e77
--- /dev/null
+++ b/tests/wire/manage/v1/projects/billing/breakdown.test.ts
@@ -0,0 +1,94 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("BreakdownClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            start: "2025-01-16",
+            end: "2025-01-23",
+            resolution: { units: "day", amount: 1 },
+            results: [
+                {
+                    dollars: 0.25,
+                    grouping: {
+                        start: "2025-01-16",
+                        end: "2025-01-16",
+                        accessor: "123456789012345678901234",
+                        deployment: "hosted",
+                        line_item: "streaming::nova-3",
+                        tags: ["tag1", "tag2"],
+                    },
+                },
+            ],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/billing/breakdown")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.billing.breakdown.list("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+            accessor: "12345678-1234-1234-1234-123456789012",
+            deployment: "hosted",
+            tag: "tag1",
+            line_item: "streaming::nova-3",
+        });
+        expect(response).toEqual({
+            start: "2025-01-16",
+            end: "2025-01-23",
+            resolution: {
+                units: "day",
+                amount: 1,
+            },
+            results: [
+                {
+                    dollars: 0.25,
+                    grouping: {
+                        start: "2025-01-16",
+                        end: "2025-01-16",
+                        accessor: "123456789012345678901234",
+                        deployment: "hosted",
+                        line_item: "streaming::nova-3",
+                        tags: ["tag1", "tag2"],
+                    },
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/billing/breakdown")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.billing.breakdown.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/billing/fields.test.ts b/tests/wire/manage/v1/projects/billing/fields.test.ts
new file mode 100644
index 00000000..b0cb25a1
--- /dev/null
+++ b/tests/wire/manage/v1/projects/billing/fields.test.ts
@@ -0,0 +1,66 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("FieldsClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            accessors: ["12345678-1234-1234-1234-123456789012", "87654321-4321-4321-4321-210987654321"],
+            deployments: ["hosted", "self-hosted"],
+            tags: ["dev", "production"],
+            line_items: { "streaming::nova-3": "Nova - 3 (Stream)", "sync::aura-2": "Aura -2 (Sync)" },
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/billing/fields")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.billing.fields.list("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+        });
+        expect(response).toEqual({
+            accessors: ["12345678-1234-1234-1234-123456789012", "87654321-4321-4321-4321-210987654321"],
+            deployments: ["hosted", "self-hosted"],
+            tags: ["dev", "production"],
+            line_items: {
+                "streaming::nova-3": "Nova - 3 (Stream)",
+                "sync::aura-2": "Aura -2 (Sync)",
+            },
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/billing/fields")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.billing.fields.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/billing/purchases.test.ts b/tests/wire/manage/v1/projects/billing/purchases.test.ts
new file mode 100644
index 00000000..16d1880c
--- /dev/null
+++ b/tests/wire/manage/v1/projects/billing/purchases.test.ts
@@ -0,0 +1,74 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("PurchasesClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            orders: [
+                {
+                    order_id: "025e19ba-b6d9-4a04-9f99-4fe715aca5f1",
+                    expiration: "2026-03-04T00:00:00Z",
+                    created: "2023-02-21T21:13:40Z",
+                    amount: 150,
+                    units: "usd",
+                    order_type: "promotional",
+                },
+            ],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/purchases")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.billing.purchases.list("123456-7890-1234-5678-901234", {
+            limit: 1.1,
+        });
+        expect(response).toEqual({
+            orders: [
+                {
+                    order_id: "025e19ba-b6d9-4a04-9f99-4fe715aca5f1",
+                    expiration: "2026-03-04T00:00:00Z",
+                    created: "2023-02-21T21:13:40Z",
+                    amount: 150,
+                    units: "usd",
+                    order_type: "promotional",
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/purchases")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.billing.purchases.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/keys.test.ts b/tests/wire/manage/v1/projects/keys.test.ts
new file mode 100644
index 00000000..2acedc5e
--- /dev/null
+++ b/tests/wire/manage/v1/projects/keys.test.ts
@@ -0,0 +1,270 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../src/Client";
+import { mockServerPool } from "../../../../mock-server/MockServerPool";
+
+describe("KeysClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            api_keys: [
+                {
+                    member: { member_id: "1000-2000-3000-4000", email: "john@test.com" },
+                    api_key: {
+                        api_key_id: "1234567890abcdef1234567890abcdef",
+                        comment: "A comment",
+                        scopes: ["admin"],
+                        created: "2021-01-01T00:00:00Z",
+                    },
+                },
+            ],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/keys")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.keys.list("123456-7890-1234-5678-901234", {
+            status: "active",
+        });
+        expect(response).toEqual({
+            api_keys: [
+                {
+                    member: {
+                        member_id: "1000-2000-3000-4000",
+                        email: "john@test.com",
+                    },
+                    api_key: {
+                        api_key_id: "1234567890abcdef1234567890abcdef",
+                        comment: "A comment",
+                        scopes: ["admin"],
+                        created: "2021-01-01T00:00:00Z",
+                    },
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/keys")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.keys.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("create (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { key: "value" };
+        const rawResponseBody = {
+            api_key_id: "api_key_id",
+            key: "key",
+            comment: "comment",
+            scopes: ["scopes", "scopes"],
+            tags: ["tags", "tags"],
+            expiration_date: "2024-01-15T09:30:00Z",
+        };
+        server
+            .mockEndpoint()
+            .post("/v1/projects/project_id/keys")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.keys.create("project_id", {
+            key: "value",
+        });
+        expect(response).toEqual({
+            api_key_id: "api_key_id",
+            key: "key",
+            comment: "comment",
+            scopes: ["scopes", "scopes"],
+            tags: ["tags", "tags"],
+            expiration_date: "2024-01-15T09:30:00Z",
+        });
+    });
+
+    test("create (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { key: "value" };
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .post("/v1/projects/project_id/keys")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.keys.create("project_id", {
+                key: "value",
+            });
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            item: {
+                member: {
+                    member_id: "1000-2000-3000-4000",
+                    email: "john@test.com",
+                    first_name: "John",
+                    last_name: "Doe",
+                    api_key: {
+                        api_key_id: "1000-2000-3000-4000",
+                        comment: "A comment",
+                        scopes: ["admin"],
+                        tags: ["prod", "west-region"],
+                        expiration_date: "2021-01-01T00:00:00Z",
+                        created: "2021-01-01T00:00:00Z",
+                    },
+                },
+            },
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/keys/123456789012345678901234")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.keys.get(
+            "123456-7890-1234-5678-901234",
+            "123456789012345678901234",
+        );
+        expect(response).toEqual({
+            item: {
+                member: {
+                    member_id: "1000-2000-3000-4000",
+                    email: "john@test.com",
+                    first_name: "John",
+                    last_name: "Doe",
+                    api_key: {
+                        api_key_id: "1000-2000-3000-4000",
+                        comment: "A comment",
+                        scopes: ["admin"],
+                        tags: ["prod", "west-region"],
+                        expiration_date: "2021-01-01T00:00:00Z",
+                        created: "2021-01-01T00:00:00Z",
+                    },
+                },
+            },
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/keys/key_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.keys.get("project_id", "key_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("delete (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { message: "message" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/123456-7890-1234-5678-901234/keys/123456789012345678901234")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.keys.delete(
+            "123456-7890-1234-5678-901234",
+            "123456789012345678901234",
+        );
+        expect(response).toEqual({
+            message: "message",
+        });
+    });
+
+    test("delete (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/project_id/keys/key_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.keys.delete("project_id", "key_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/members.test.ts b/tests/wire/manage/v1/projects/members.test.ts
new file mode 100644
index 00000000..b880ad92
--- /dev/null
+++ b/tests/wire/manage/v1/projects/members.test.ts
@@ -0,0 +1,105 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../src/Client";
+import { mockServerPool } from "../../../../mock-server/MockServerPool";
+
+describe("MembersClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { members: [{ member_id: "member_id", email: "email" }] };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/members")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.members.list("123456-7890-1234-5678-901234");
+        expect(response).toEqual({
+            members: [
+                {
+                    member_id: "member_id",
+                    email: "email",
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/members")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.members.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("delete (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { message: "message" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/123456-7890-1234-5678-901234/members/123456789012345678901234")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.members.delete(
+            "123456-7890-1234-5678-901234",
+            "123456789012345678901234",
+        );
+        expect(response).toEqual({
+            message: "message",
+        });
+    });
+
+    test("delete (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/project_id/members/member_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.members.delete("project_id", "member_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/members/invites.test.ts b/tests/wire/manage/v1/projects/members/invites.test.ts
new file mode 100644
index 00000000..84babbf1
--- /dev/null
+++ b/tests/wire/manage/v1/projects/members/invites.test.ts
@@ -0,0 +1,158 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("InvitesClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { invites: [{ email: "email", scope: "scope" }] };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/invites")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.members.invites.list("123456-7890-1234-5678-901234");
+        expect(response).toEqual({
+            invites: [
+                {
+                    email: "email",
+                    scope: "scope",
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/invites")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.members.invites.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("create (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { email: "email", scope: "scope" };
+        const rawResponseBody = { message: "message" };
+        server
+            .mockEndpoint()
+            .post("/v1/projects/123456-7890-1234-5678-901234/invites")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.members.invites.create("123456-7890-1234-5678-901234", {
+            email: "email",
+            scope: "scope",
+        });
+        expect(response).toEqual({
+            message: "message",
+        });
+    });
+
+    test("create (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { email: "email", scope: "scope" };
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .post("/v1/projects/project_id/invites")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.members.invites.create("project_id", {
+                email: "email",
+                scope: "scope",
+            });
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("delete (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { message: "message" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/123456-7890-1234-5678-901234/invites/john.doe%40example.com")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.members.invites.delete(
+            "123456-7890-1234-5678-901234",
+            "john.doe@example.com",
+        );
+        expect(response).toEqual({
+            message: "message",
+        });
+    });
+
+    test("delete (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/project_id/invites/email")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.members.invites.delete("project_id", "email");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/members/scopes.test.ts b/tests/wire/manage/v1/projects/members/scopes.test.ts
new file mode 100644
index 00000000..2fe5891f
--- /dev/null
+++ b/tests/wire/manage/v1/projects/members/scopes.test.ts
@@ -0,0 +1,110 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("ScopesClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { scopes: ["scopes"] };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/members/123456789012345678901234/scopes")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.members.scopes.list(
+            "123456-7890-1234-5678-901234",
+            "123456789012345678901234",
+        );
+        expect(response).toEqual({
+            scopes: ["scopes"],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/members/member_id/scopes")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.members.scopes.list("project_id", "member_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("update (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { scope: "admin" };
+        const rawResponseBody = { message: "message" };
+        server
+            .mockEndpoint()
+            .put("/v1/projects/123456-7890-1234-5678-901234/members/123456789012345678901234/scopes")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.members.scopes.update(
+            "123456-7890-1234-5678-901234",
+            "123456789012345678901234",
+            {
+                scope: "admin",
+            },
+        );
+        expect(response).toEqual({
+            message: "message",
+        });
+    });
+
+    test("update (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { scope: "scope" };
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .put("/v1/projects/project_id/members/member_id/scopes")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.members.scopes.update("project_id", "member_id", {
+                scope: "scope",
+            });
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/models.test.ts b/tests/wire/manage/v1/projects/models.test.ts
new file mode 100644
index 00000000..ea7006db
--- /dev/null
+++ b/tests/wire/manage/v1/projects/models.test.ts
@@ -0,0 +1,184 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../src/Client";
+import { mockServerPool } from "../../../../mock-server/MockServerPool";
+
+describe("ModelsClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            stt: [
+                {
+                    name: "nova-3",
+                    canonical_name: "nova-3",
+                    architecture: "base",
+                    languages: ["en", "en-us"],
+                    version: "2021-11-10.1",
+                    uuid: "6b28e919-8427-4f32-9847-492e2efd7daf",
+                    batch: true,
+                    streaming: true,
+                    formatted_output: true,
+                },
+            ],
+            tts: [
+                {
+                    name: "zeus",
+                    canonical_name: "aura-2-zeus-en",
+                    architecture: "aura-2",
+                    languages: ["en", "en-US"],
+                    version: "2025-04-07.0",
+                    uuid: "2baf189d-91ac-481d-b6d1-750888667b31",
+                    metadata: {
+                        accent: "American",
+                        age: "Adult",
+                        color: "#C58DFF",
+                        image: "https://static.deepgram.com/examples/avatars/zeus.jpg",
+                        sample: "https://static.deepgram.com/examples/Aura-2-zeus.wav",
+                        tags: ["masculine", "deep", "trustworthy", "smooth"],
+                        use_cases: ["IVR"],
+                    },
+                },
+            ],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/models")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.models.list("123456-7890-1234-5678-901234", {
+            include_outdated: true,
+        });
+        expect(response).toEqual({
+            stt: [
+                {
+                    name: "nova-3",
+                    canonical_name: "nova-3",
+                    architecture: "base",
+                    languages: ["en", "en-us"],
+                    version: "2021-11-10.1",
+                    uuid: "6b28e919-8427-4f32-9847-492e2efd7daf",
+                    batch: true,
+                    streaming: true,
+                    formatted_output: true,
+                },
+            ],
+            tts: [
+                {
+                    name: "zeus",
+                    canonical_name: "aura-2-zeus-en",
+                    architecture: "aura-2",
+                    languages: ["en", "en-US"],
+                    version: "2025-04-07.0",
+                    uuid: "2baf189d-91ac-481d-b6d1-750888667b31",
+                    metadata: {
+                        accent: "American",
+                        age: "Adult",
+                        color: "#C58DFF",
+                        image: "https://static.deepgram.com/examples/avatars/zeus.jpg",
+                        sample: "https://static.deepgram.com/examples/Aura-2-zeus.wav",
+                        tags: ["masculine", "deep", "trustworthy", "smooth"],
+                        use_cases: ["IVR"],
+                    },
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/models")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.models.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            name: "general",
+            canonical_name: "enhanced-general",
+            architecture: "polaris",
+            languages: ["en", "en-us"],
+            version: "2022-05-18.1",
+            uuid: "c7226e9e-ae1c-4057-ae2a-a71a6b0dc588",
+            batch: true,
+            streaming: true,
+            formatted_output: false,
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/models/af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.models.get(
+            "123456-7890-1234-5678-901234",
+            "af6e9977-99f6-4d8f-b6f5-dfdf6fb6e291",
+        );
+        expect(response).toEqual({
+            name: "general",
+            canonical_name: "enhanced-general",
+            architecture: "polaris",
+            languages: ["en", "en-us"],
+            version: "2022-05-18.1",
+            uuid: "c7226e9e-ae1c-4057-ae2a-a71a6b0dc588",
+            batch: true,
+            streaming: true,
+            formatted_output: false,
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/models/model_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.models.get("project_id", "model_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/requests.test.ts b/tests/wire/manage/v1/projects/requests.test.ts
new file mode 100644
index 00000000..d2c8e8bc
--- /dev/null
+++ b/tests/wire/manage/v1/projects/requests.test.ts
@@ -0,0 +1,167 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../src/Client";
+import { mockServerPool } from "../../../../mock-server/MockServerPool";
+
+describe("RequestsClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            page: 1.1,
+            limit: 1.1,
+            requests: [
+                {
+                    request_id: "request_id",
+                    project_uuid: "project_uuid",
+                    created: "2024-01-15T09:30:00Z",
+                    path: "path",
+                    api_key_id: "api_key_id",
+                    response: { key: "value" },
+                    code: 1.1,
+                    deployment: "deployment",
+                    callback: "callback",
+                },
+            ],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/requests")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.requests.list("123456-7890-1234-5678-901234", {
+            start: "2024-01-15T09:30:00Z",
+            end: "2024-01-15T09:30:00Z",
+            limit: 1.1,
+            page: 1.1,
+            accessor: "12345678-1234-1234-1234-123456789012",
+            request_id: "12345678-1234-1234-1234-123456789012",
+            deployment: "hosted",
+            endpoint: "listen",
+            method: "sync",
+            status: "succeeded",
+        });
+        expect(response).toEqual({
+            page: 1.1,
+            limit: 1.1,
+            requests: [
+                {
+                    request_id: "request_id",
+                    project_uuid: "project_uuid",
+                    created: "2024-01-15T09:30:00Z",
+                    path: "path",
+                    api_key_id: "api_key_id",
+                    response: {
+                        key: "value",
+                    },
+                    code: 1.1,
+                    deployment: "deployment",
+                    callback: "callback",
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/requests")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.requests.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            request: {
+                request_id: "request_id",
+                project_uuid: "project_uuid",
+                created: "2024-01-15T09:30:00Z",
+                path: "path",
+                api_key_id: "api_key_id",
+                response: { key: "value" },
+                code: 1.1,
+                deployment: "deployment",
+                callback: "callback",
+            },
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/requests/123456-7890-1234-5678-901234")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.requests.get(
+            "123456-7890-1234-5678-901234",
+            "123456-7890-1234-5678-901234",
+        );
+        expect(response).toEqual({
+            request: {
+                request_id: "request_id",
+                project_uuid: "project_uuid",
+                created: "2024-01-15T09:30:00Z",
+                path: "path",
+                api_key_id: "api_key_id",
+                response: {
+                    key: "value",
+                },
+                code: 1.1,
+                deployment: "deployment",
+                callback: "callback",
+            },
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/requests/request_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.requests.get("project_id", "request_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/usage.test.ts b/tests/wire/manage/v1/projects/usage.test.ts
new file mode 100644
index 00000000..5e3fd5b2
--- /dev/null
+++ b/tests/wire/manage/v1/projects/usage.test.ts
@@ -0,0 +1,102 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../src/Client";
+import { mockServerPool } from "../../../../mock-server/MockServerPool";
+
+describe("UsageClient", () => {
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { start: "2024-10-16", end: "2024-10-23", resolution: { units: "day", amount: 1 } };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/usage")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.usage.get("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+            accessor: "12345678-1234-1234-1234-123456789012",
+            alternatives: true,
+            callback_method: true,
+            callback: true,
+            channels: true,
+            custom_intent_mode: true,
+            custom_intent: true,
+            custom_topic_mode: true,
+            custom_topic: true,
+            deployment: "hosted",
+            detect_entities: true,
+            detect_language: true,
+            diarize: true,
+            dictation: true,
+            encoding: true,
+            endpoint: "listen",
+            extra: true,
+            filler_words: true,
+            intents: true,
+            keyterm: true,
+            keywords: true,
+            language: true,
+            measurements: true,
+            method: "sync",
+            model: "6f548761-c9c0-429a-9315-11a1d28499c8",
+            multichannel: true,
+            numerals: true,
+            paragraphs: true,
+            profanity_filter: true,
+            punctuate: true,
+            redact: true,
+            replace: true,
+            sample_rate: true,
+            search: true,
+            sentiment: true,
+            smart_format: true,
+            summarize: true,
+            tag: "tag1",
+            topics: true,
+            utt_split: true,
+            utterances: true,
+            version: true,
+        });
+        expect(response).toEqual({
+            start: "2024-10-16",
+            end: "2024-10-23",
+            resolution: {
+                units: "day",
+                amount: 1,
+            },
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/usage")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.usage.get("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/usage/breakdown.test.ts b/tests/wire/manage/v1/projects/usage/breakdown.test.ts
new file mode 100644
index 00000000..40c51fe3
--- /dev/null
+++ b/tests/wire/manage/v1/projects/usage/breakdown.test.ts
@@ -0,0 +1,151 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("BreakdownClient", () => {
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            start: "2025-01-16",
+            end: "2025-01-23",
+            resolution: { units: "day", amount: 1 },
+            results: [
+                {
+                    hours: 1619.7242069444444,
+                    total_hours: 1621.7395791666668,
+                    agent_hours: 41.33564388888889,
+                    tokens_in: 0,
+                    tokens_out: 0,
+                    tts_characters: 9158866,
+                    requests: 373381,
+                    grouping: {
+                        start: "2025-01-16",
+                        end: "2025-01-16",
+                        accessor: "123456789012345678901234",
+                        endpoint: "listen",
+                        feature_set: "punctuate",
+                        models: "Nova-2",
+                        method: "async",
+                        tags: "tag1",
+                        deployment: "self-hosted",
+                    },
+                },
+            ],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/usage/breakdown")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.usage.breakdown.get("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+            grouping: "accessor",
+            accessor: "12345678-1234-1234-1234-123456789012",
+            alternatives: true,
+            callback_method: true,
+            callback: true,
+            channels: true,
+            custom_intent_mode: true,
+            custom_intent: true,
+            custom_topic_mode: true,
+            custom_topic: true,
+            deployment: "hosted",
+            detect_entities: true,
+            detect_language: true,
+            diarize: true,
+            dictation: true,
+            encoding: true,
+            endpoint: "listen",
+            extra: true,
+            filler_words: true,
+            intents: true,
+            keyterm: true,
+            keywords: true,
+            language: true,
+            measurements: true,
+            method: "sync",
+            model: "6f548761-c9c0-429a-9315-11a1d28499c8",
+            multichannel: true,
+            numerals: true,
+            paragraphs: true,
+            profanity_filter: true,
+            punctuate: true,
+            redact: true,
+            replace: true,
+            sample_rate: true,
+            search: true,
+            sentiment: true,
+            smart_format: true,
+            summarize: true,
+            tag: "tag1",
+            topics: true,
+            utt_split: true,
+            utterances: true,
+            version: true,
+        });
+        expect(response).toEqual({
+            start: "2025-01-16",
+            end: "2025-01-23",
+            resolution: {
+                units: "day",
+                amount: 1,
+            },
+            results: [
+                {
+                    hours: 1619.7242069444444,
+                    total_hours: 1621.7395791666668,
+                    agent_hours: 41.33564388888889,
+                    tokens_in: 0,
+                    tokens_out: 0,
+                    tts_characters: 9158866,
+                    requests: 373381,
+                    grouping: {
+                        start: "2025-01-16",
+                        end: "2025-01-16",
+                        accessor: "123456789012345678901234",
+                        endpoint: "listen",
+                        feature_set: "punctuate",
+                        models: "Nova-2",
+                        method: "async",
+                        tags: "tag1",
+                        deployment: "self-hosted",
+                    },
+                },
+            ],
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/usage/breakdown")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.usage.breakdown.get("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/manage/v1/projects/usage/fields.test.ts b/tests/wire/manage/v1/projects/usage/fields.test.ts
new file mode 100644
index 00000000..612f5168
--- /dev/null
+++ b/tests/wire/manage/v1/projects/usage/fields.test.ts
@@ -0,0 +1,77 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../../../src/api/index";
+import { DeepgramClient } from "../../../../../../src/Client";
+import { mockServerPool } from "../../../../../mock-server/MockServerPool";
+
+describe("FieldsClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            tags: ["tag=dev", "tag=production"],
+            models: [
+                {
+                    name: "2-medical-nova",
+                    language: "en-MY",
+                    version: "2024-05-31.13574",
+                    model_id: "1234567890-12345-67890",
+                },
+            ],
+            processing_methods: ["sync", "streaming"],
+            features: ["alternatives", "detect_entities", "detect_language"],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/usage/fields")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.manage.v1.projects.usage.fields.list("123456-7890-1234-5678-901234", {
+            start: "start",
+            end: "end",
+        });
+        expect(response).toEqual({
+            tags: ["tag=dev", "tag=production"],
+            models: [
+                {
+                    name: "2-medical-nova",
+                    language: "en-MY",
+                    version: "2024-05-31.13574",
+                    model_id: "1234567890-12345-67890",
+                },
+            ],
+            processing_methods: ["sync", "streaming"],
+            features: ["alternatives", "detect_entities", "detect_language"],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/usage/fields")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.manage.v1.projects.usage.fields.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/read/v1/text.test.ts b/tests/wire/read/v1/text.test.ts
new file mode 100644
index 00000000..7726a511
--- /dev/null
+++ b/tests/wire/read/v1/text.test.ts
@@ -0,0 +1,119 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../src/api/index";
+import { DeepgramClient } from "../../../../src/Client";
+import { mockServerPool } from "../../../mock-server/MockServerPool";
+
+describe("TextClient", () => {
+    test("analyze (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { url: "url" };
+        const rawResponseBody = {
+            metadata: {
+                metadata: {
+                    request_id: "d04af392-db11-4c1d-83e1-20e34f0b8999",
+                    created: "2024-11-18T23:47:44Z",
+                    language: "en",
+                },
+            },
+            results: {
+                sentiments: {
+                    segments: [
+                        {
+                            text: "Yeah. As as much as, um, it's worth celebrating, uh, the first, uh, spacewalk, um, with an all-female team, I think many of us are looking forward to it just being normal. And, um, I think if it signifies anything, it is, uh, to honor the the women who came before us who, um, were skilled and qualified, um, and didn't get the the same opportunities that we have today.",
+                            start_word: 0,
+                            end_word: 69,
+                            sentiment: "positive",
+                            sentiment_score: 0.5810546875,
+                        },
+                    ],
+                    average: { sentiment: "positive", sentiment_score: 0.5810185185185185 },
+                },
+            },
+        };
+        server
+            .mockEndpoint()
+            .post("/v1/read")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.read.v1.text.analyze({
+            callback: "callback",
+            callback_method: "POST",
+            sentiment: true,
+            summarize: "v2",
+            tag: "tag",
+            topics: true,
+            custom_topic: "custom_topic",
+            custom_topic_mode: "extended",
+            intents: true,
+            custom_intent: "custom_intent",
+            custom_intent_mode: "extended",
+            language: "language",
+            body: {
+                url: "url",
+            },
+        });
+        expect(response).toEqual({
+            metadata: {
+                metadata: {
+                    request_id: "d04af392-db11-4c1d-83e1-20e34f0b8999",
+                    created: "2024-11-18T23:47:44Z",
+                    language: "en",
+                },
+            },
+            results: {
+                sentiments: {
+                    segments: [
+                        {
+                            text: "Yeah. As as much as, um, it's worth celebrating, uh, the first, uh, spacewalk, um, with an all-female team, I think many of us are looking forward to it just being normal. And, um, I think if it signifies anything, it is, uh, to honor the the women who came before us who, um, were skilled and qualified, um, and didn't get the the same opportunities that we have today.",
+                            start_word: 0,
+                            end_word: 69,
+                            sentiment: "positive",
+                            sentiment_score: 0.5810546875,
+                        },
+                    ],
+                    average: {
+                        sentiment: "positive",
+                        sentiment_score: 0.5810185185185185,
+                    },
+                },
+            },
+        });
+    });
+
+    test("analyze (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = { url: "url" };
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .post("/v1/read")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.read.v1.text.analyze({
+                body: {
+                    url: "url",
+                },
+            });
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tests/wire/selfHosted/v1/distributionCredentials.test.ts b/tests/wire/selfHosted/v1/distributionCredentials.test.ts
new file mode 100644
index 00000000..143a7861
--- /dev/null
+++ b/tests/wire/selfHosted/v1/distributionCredentials.test.ts
@@ -0,0 +1,288 @@
+// This file was auto-generated by Fern from our API Definition.
+
+import * as Deepgram from "../../../../src/api/index";
+import { DeepgramClient } from "../../../../src/Client";
+import { mockServerPool } from "../../../mock-server/MockServerPool";
+
+describe("DistributionCredentialsClient", () => {
+    test("list (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            distribution_credentials: [
+                {
+                    member: { member_id: "3376abcd-8e5e-49d3-92d4-876d3a4f0363", email: "email@example.com" },
+                    distribution_credentials: {
+                        distribution_credentials_id: "8b36cfd0-472f-4a21-833f-2d6343c3a2f3",
+                        provider: "quay",
+                        comment: "My Self-Hosted Distribution Credentials",
+                        scopes: ["self-hosted:product:api", "self-hosted:product:engine"],
+                        created: "2023-06-28T15:36:59Z",
+                    },
+                },
+            ],
+        };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/123456-7890-1234-5678-901234/self-hosted/distribution/credentials")
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.selfHosted.v1.distributionCredentials.list("123456-7890-1234-5678-901234");
+        expect(response).toEqual({
+            distribution_credentials: [
+                {
+                    member: {
+                        member_id: "3376abcd-8e5e-49d3-92d4-876d3a4f0363",
+                        email: "email@example.com",
+                    },
+                    distribution_credentials: {
+                        distribution_credentials_id: "8b36cfd0-472f-4a21-833f-2d6343c3a2f3",
+                        provider: "quay",
+                        comment: "My Self-Hosted Distribution Credentials",
+                        scopes: ["self-hosted:product:api", "self-hosted:product:engine"],
+                        created: "2023-06-28T15:36:59Z",
+                    },
+                },
+            ],
+        });
+    });
+
+    test("list (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/self-hosted/distribution/credentials")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.selfHosted.v1.distributionCredentials.list("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("create (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = {};
+        const rawResponseBody = {
+            member: { member_id: "c7b9b131-73f3-11d9-8665-0b00d2e44b83", email: "email@example.com" },
+            distribution_credentials: {
+                distribution_credentials_id: "82c32c10-53b2-4d23-993f-864b3d44502a",
+                provider: "quay",
+                comment: "My Self-Hosted Distribution Credentials",
+                scopes: ["self-hosted:product:api", "self-hosted:product:engine"],
+                created: "2023-06-28T15:36:59Z",
+            },
+        };
+        server
+            .mockEndpoint()
+            .post("/v1/projects/123456-7890-1234-5678-901234/self-hosted/distribution/credentials")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.selfHosted.v1.distributionCredentials.create("123456-7890-1234-5678-901234", {
+            provider: "quay",
+        });
+        expect(response).toEqual({
+            member: {
+                member_id: "c7b9b131-73f3-11d9-8665-0b00d2e44b83",
+                email: "email@example.com",
+            },
+            distribution_credentials: {
+                distribution_credentials_id: "82c32c10-53b2-4d23-993f-864b3d44502a",
+                provider: "quay",
+                comment: "My Self-Hosted Distribution Credentials",
+                scopes: ["self-hosted:product:api", "self-hosted:product:engine"],
+                created: "2023-06-28T15:36:59Z",
+            },
+        });
+    });
+
+    test("create (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+        const rawRequestBody = {};
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .post("/v1/projects/project_id/self-hosted/distribution/credentials")
+            .jsonBody(rawRequestBody)
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.selfHosted.v1.distributionCredentials.create("project_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("get (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            member: { member_id: "c7b9b131-73f3-11d9-8665-0b00d2e44b83", email: "email@example.com" },
+            distribution_credentials: {
+                distribution_credentials_id: "82c32c10-53b2-4d23-993f-864b3d44502a",
+                provider: "quay",
+                comment: "My Self-Hosted Distribution Credentials",
+                scopes: ["self-hosted:product:api", "self-hosted:product:engine"],
+                created: "2023-06-28T15:36:59Z",
+            },
+        };
+        server
+            .mockEndpoint()
+            .get(
+                "/v1/projects/123456-7890-1234-5678-901234/self-hosted/distribution/credentials/8b36cfd0-472f-4a21-833f-2d6343c3a2f3",
+            )
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.selfHosted.v1.distributionCredentials.get(
+            "123456-7890-1234-5678-901234",
+            "8b36cfd0-472f-4a21-833f-2d6343c3a2f3",
+        );
+        expect(response).toEqual({
+            member: {
+                member_id: "c7b9b131-73f3-11d9-8665-0b00d2e44b83",
+                email: "email@example.com",
+            },
+            distribution_credentials: {
+                distribution_credentials_id: "82c32c10-53b2-4d23-993f-864b3d44502a",
+                provider: "quay",
+                comment: "My Self-Hosted Distribution Credentials",
+                scopes: ["self-hosted:product:api", "self-hosted:product:engine"],
+                created: "2023-06-28T15:36:59Z",
+            },
+        });
+    });
+
+    test("get (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .get("/v1/projects/project_id/self-hosted/distribution/credentials/distribution_credentials_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.selfHosted.v1.distributionCredentials.get("project_id", "distribution_credentials_id");
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+
+    test("delete (1)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = {
+            member: { member_id: "c7b9b131-73f3-11d9-8665-0b00d2e44b83", email: "email@example.com" },
+            distribution_credentials: {
+                distribution_credentials_id: "82c32c10-53b2-4d23-993f-864b3d44502a",
+                provider: "quay",
+                comment: "My Self-Hosted Distribution Credentials",
+                scopes: ["self-hosted:product:api", "self-hosted:product:engine"],
+                created: "2023-06-28T15:36:59Z",
+            },
+        };
+        server
+            .mockEndpoint()
+            .delete(
+                "/v1/projects/123456-7890-1234-5678-901234/self-hosted/distribution/credentials/8b36cfd0-472f-4a21-833f-2d6343c3a2f3",
+            )
+            .respondWith()
+            .statusCode(200)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        const response = await client.selfHosted.v1.distributionCredentials.delete(
+            "123456-7890-1234-5678-901234",
+            "8b36cfd0-472f-4a21-833f-2d6343c3a2f3",
+        );
+        expect(response).toEqual({
+            member: {
+                member_id: "c7b9b131-73f3-11d9-8665-0b00d2e44b83",
+                email: "email@example.com",
+            },
+            distribution_credentials: {
+                distribution_credentials_id: "82c32c10-53b2-4d23-993f-864b3d44502a",
+                provider: "quay",
+                comment: "My Self-Hosted Distribution Credentials",
+                scopes: ["self-hosted:product:api", "self-hosted:product:engine"],
+                created: "2023-06-28T15:36:59Z",
+            },
+        });
+    });
+
+    test("delete (2)", async () => {
+        const server = mockServerPool.createServer();
+        const client = new DeepgramClient({
+            maxRetries: 0,
+            apiKey: "test",
+            environment: { base: server.baseUrl, agent: server.baseUrl, production: server.baseUrl },
+        });
+
+        const rawResponseBody = { key: "value" };
+        server
+            .mockEndpoint()
+            .delete("/v1/projects/project_id/self-hosted/distribution/credentials/distribution_credentials_id")
+            .respondWith()
+            .statusCode(400)
+            .jsonBody(rawResponseBody)
+            .build();
+
+        await expect(async () => {
+            return await client.selfHosted.v1.distributionCredentials.delete(
+                "project_id",
+                "distribution_credentials_id",
+            );
+        }).rejects.toThrow(Deepgram.BadRequestError);
+    });
+});
diff --git a/tsconfig.base.json b/tsconfig.base.json
new file mode 100644
index 00000000..d7627675
--- /dev/null
+++ b/tsconfig.base.json
@@ -0,0 +1,18 @@
+{
+    "compilerOptions": {
+        "extendedDiagnostics": true,
+        "strict": true,
+        "target": "ES6",
+        "moduleResolution": "node",
+        "esModuleInterop": true,
+        "skipLibCheck": true,
+        "declaration": true,
+        "outDir": "dist",
+        "rootDir": "src",
+        "baseUrl": "src",
+        "isolatedModules": true,
+        "isolatedDeclarations": true
+    },
+    "include": ["src"],
+    "exclude": []
+}
diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json
new file mode 100644
index 00000000..5c11446f
--- /dev/null
+++ b/tsconfig.cjs.json
@@ -0,0 +1,9 @@
+{
+    "extends": "./tsconfig.base.json",
+    "compilerOptions": {
+        "module": "CommonJS",
+        "outDir": "dist/cjs"
+    },
+    "include": ["src"],
+    "exclude": []
+}
diff --git a/tsconfig.esm.json b/tsconfig.esm.json
new file mode 100644
index 00000000..6ce90974
--- /dev/null
+++ b/tsconfig.esm.json
@@ -0,0 +1,10 @@
+{
+    "extends": "./tsconfig.base.json",
+    "compilerOptions": {
+        "module": "esnext",
+        "outDir": "dist/esm",
+        "verbatimModuleSyntax": true
+    },
+    "include": ["src"],
+    "exclude": []
+}
diff --git a/tsconfig.json b/tsconfig.json
index c48bfd9b..d77fdf00 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,22 +1,3 @@
 {
-  "include": ["src", "tests/types"],
-  "exclude": ["node_modules/**/*.ts"],
-  "compilerOptions": {
-    "declaration": true,
-    "declarationMap": true,
-    "module": "CommonJS",
-    "outDir": "dist/main",
-    "rootDir": "src",
-    "sourceMap": true,
-    "target": "ES2015",
-
-    "strict": true,
-
-    "esModuleInterop": true,
-    "moduleResolution": "Node",
-
-    "forceConsistentCasingInFileNames": true,
-    "stripInternal": true,
-    "allowSyntheticDefaultImports": true
-  }
+    "extends": "./tsconfig.cjs.json"
 }
diff --git a/tsconfig.module.json b/tsconfig.module.json
deleted file mode 100644
index 8726ca43..00000000
--- a/tsconfig.module.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "extends": "./tsconfig",
-  "compilerOptions": {
-    "module": "ES2020",
-    "outDir": "dist/module"
-  }
-}
diff --git a/vitest.config.mts b/vitest.config.mts
new file mode 100644
index 00000000..ba2ec4f9
--- /dev/null
+++ b/vitest.config.mts
@@ -0,0 +1,28 @@
+import { defineConfig } from "vitest/config";
+export default defineConfig({
+    test: {
+        projects: [
+            {
+                test: {
+                    globals: true,
+                    name: "unit",
+                    environment: "node",
+                    root: "./tests",
+                    include: ["**/*.test.{js,ts,jsx,tsx}"],
+                    exclude: ["wire/**"],
+                    setupFiles: ["./setup.ts"],
+                },
+            },
+            {
+                test: {
+                    globals: true,
+                    name: "wire",
+                    environment: "node",
+                    root: "./tests/wire",
+                    setupFiles: ["../setup.ts", "../mock-server/setup.ts"],
+                },
+            },
+        ],
+        passWithNoTests: true,
+    },
+});
diff --git a/webpack.config.js b/webpack.config.js
deleted file mode 100644
index 503c9582..00000000
--- a/webpack.config.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* eslint-env node */
-/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */
-
-const path = require("path");
-
-module.exports = {
-  entry: "./src/index.ts",
-  output: {
-    path: path.resolve(__dirname, "dist/umd"),
-    filename: "deepgram.js",
-    library: {
-      type: "umd",
-      name: "deepgram",
-    },
-  },
-  module: {
-    rules: [
-      {
-        test: /\.ts$/,
-        loader: "ts-loader",
-        options: {
-          transpileOnly: true,
-        },
-      },
-    ],
-  },
-  resolve: {
-    extensions: [".ts", ".js", ".json"],
-    fallback: {
-      stream: require.resolve("stream-browserify"),
-      buffer: require.resolve("buffer"),
-      util: require.resolve("util"),
-      url: require.resolve("url"),
-    },
-  },
-};